[SeaBIOS] [PATCH] Add SD card support

Dave Frodin dave.frodin at se-eng.com
Thu Jun 5 18:36:07 CEST 2014


Paul,

I'm resending the patch, supposedly as plain text.
Let me know if you still see a problem.

Thanks,
Dave



>From fa9dc2154278b428af16899e1688b3e1b1aabcf7 Mon Sep 17 00:00:00 2001
From: David Babich <david.babich at se-eng.com>
Date: Thu, 22 May 2014 16:14:29 -0600
Subject: [PATCH] Add SD card support

Updated initial commit of SD card boot support.  This has been tested
with SDHC cards booting Puppy linux.  SDSC and SDXC cards may
not work.  SD cards pre 1.01 of the SD spec are not supported
if they use byte addressing and/or block addressing with
a block size not equal to 512 Bytes.  Also, the drivers are
written to support boot, but not necessarily for optimal
speed.  The driver supports read and not write, and only
implements functions that are required for boot. Some of the
source is refactored FreeBSD code.

Signed-off-by: David Babich <david.babich at se-eng.com>
---
 Makefile              |   3 +-
 src/Kconfig           |  10 +
 src/block.c           |  33 ++-
 src/block.h           |   2 +
 src/config.h          |   1 +
 src/hw/bar.h          |  65 +++++
 src/hw/sd.c           | 613 ++++++++++++++++++++++++++++++++++++++++++++
 src/hw/sd.h           | 275 ++++++++++++++++++++
 src/hw/sd_if.c        | 413 ++++++++++++++++++++++++++++++
 src/hw/sd_if.h        |  49 ++++
 src/hw/sd_utils.c     | 190 ++++++++++++++
 src/hw/sd_utils.h     | 108 ++++++++
 src/hw/sdhc_generic.c | 697 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/hw/sdhc_generic.h |  41 +++
 src/hw/sdhci.h        | 207 +++++++++++++++
 src/post.c            |   3 +
 src/stdbool.h         |  29 +++
 src/stdint.h          |  41 +++
 18 files changed, 2778 insertions(+), 2 deletions(-)
 create mode 100644 src/hw/bar.h
 create mode 100644 src/hw/sd.c
 create mode 100644 src/hw/sd.h
 create mode 100644 src/hw/sd_if.c
 create mode 100644 src/hw/sd_if.h
 create mode 100644 src/hw/sd_utils.c
 create mode 100644 src/hw/sd_utils.h
 create mode 100644 src/hw/sdhc_generic.c
 create mode 100644 src/hw/sdhc_generic.h
 create mode 100644 src/hw/sdhci.h
 create mode 100644 src/stdbool.h
 create mode 100644 src/stdint.h

diff --git a/Makefile b/Makefile
index 78b598e..02266ce 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,8 @@ SRCBOTH=misc.c stacks.c output.c string.c x86.c
block.c cdrom.c mouse.c kbd.c \
     hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
     hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \
     hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \
-    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c
+    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c \
+    hw/sdhc_generic.c hw/sd.c hw/sd_if.c hw/sd_utils.c
 SRC16=$(SRCBOTH) system.c disk.c font.c
 SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c pmm.c romfile.c optionroms.c \
     boot.c bootsplash.c jpeg.c bmp.c \
diff --git a/src/Kconfig b/src/Kconfig
index a863866..432eca5 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -1,4 +1,5 @@
 # Kconfig SeaBIOS configuration
+# Copyright (C) 2013-2014 Sage Electronic Engineering, LLC

 mainmenu "SeaBIOS Configuration"

@@ -207,6 +208,15 @@ menu "Hardware support"
         default y
         help
             Support floppy drive access.
+    config SD
+        depends on DRIVES
+        bool "SD controller"
+        default n
+        help
+            Support SD card boot. This is a development feature.
+            Select this option ONLY if you know that your hardware
+            will support booting from SD card.
+            If unsure, say n.

     config PS2PORT
         depends on KEYBOARD || MOUSE
diff --git a/src/block.c b/src/block.c
index 264f376..615edd1 100644
--- a/src/block.c
+++ b/src/block.c
@@ -2,6 +2,7 @@
 //
 // Copyright (C) 2008,2009  Kevin O'Connor <kevin at koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
+// Copyright (C) 2013 Sage Electronic Engineering, LLC
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.

@@ -13,6 +14,7 @@
 #include "hw/blockcmd.h" // cdb_*
 #include "hw/rtc.h" // rtc_read
 #include "hw/virtio-blk.h" // process_virtio_blk_op
+#include "hw/sd_if.h" // process_sd_op
 #include "malloc.h" // malloc_low
 #include "output.h" // dprintf
 #include "stacks.h" // stack_hop
@@ -20,9 +22,12 @@
 #include "string.h" // checksum
 #include "util.h" // process_floppy_op

+#define MAX_DRIVE_TYPES 4
+
 u8 FloppyCount VARFSEG;
 u8 CDCount;
-struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG;
+
+struct drive_s *IDMap[MAX_DRIVE_TYPES][BUILD_MAX_EXTDRIVE] VARFSEG;
 u8 *bounce_buf_fl VARFSEG;
 struct dpte_s DefaultDPTE VARLOW;

@@ -278,6 +283,27 @@ map_floppy_drive(struct drive_s *drive)
     }
 }

+// Map a SD card
+void
+map_sd_drive(struct drive_s *drive_g)
+{
+    ASSERT32FLAT();
+    struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);
+    int sdid = bda->hdcount;
+    printf("Mapping sd/mmc drive 0x%08x\n", (unsigned int)drive_g);
+    add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);
+
+    // Setup disk geometry translation.
+    setup_translation(drive_g);
+
+    //@NOTE:  This step appears to be unnecessary for booting from
the sd card as the pchs info does not get used...
+    drive_g->pchs.head = drive_g->lchs.head;
+    drive_g->pchs.cylinder = drive_g->lchs.cylinder;
+    drive_g->pchs.sector = drive_g->lchs.sector;
+
+    // Fill "fdpt" structure.
+    fill_fdpt(drive_g, sdid);
+}

 /****************************************************************
  * Return status functions
@@ -395,6 +421,11 @@ process_op(struct disk_op_s *op)
         ret = call32(_cfunc32flat_process_scsi_op
                      , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
         break;
+    case DTYPE_SD: ;
+        extern void _cfunc32flat_process_sd_op(void);
+        ret = call32(_cfunc32flat_process_sd_op
+                      , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);
+    break;
     default:
         ret = DISK_RET_EPARAM;
         break;
diff --git a/src/block.h b/src/block.h
index 5d0afb5..ee20218 100644
--- a/src/block.h
+++ b/src/block.h
@@ -86,6 +86,7 @@ struct drive_s {
 #define DTYPE_ESP_SCSI     0x81
 #define DTYPE_MEGASAS      0x82
 #define DTYPE_PVSCSI       0x83
+#define DTYPE_SD           0x90

 #define MAXDESCSIZE 80

@@ -115,6 +116,7 @@ int getDriveId(u8 exttype, struct drive_s *drive);
 void map_floppy_drive(struct drive_s *drive);
 void map_hd_drive(struct drive_s *drive);
 void map_cd_drive(struct drive_s *drive);
+void map_sd_drive(struct drive_s *drive);
 struct bregs;
 void __disk_ret(struct bregs *regs, u32 linecode, const char *fname);
 void __disk_ret_unimplemented(struct bregs *regs, u32 linecode
diff --git a/src/config.h b/src/config.h
index d705615..73fbffe 100644
--- a/src/config.h
+++ b/src/config.h
@@ -99,6 +99,7 @@
 #define DEBUG_HDL_pmm 1
 #define DEBUG_HDL_pcibios 9
 #define DEBUG_HDL_apm 9
+#define DEBUG_HDL_SD 6

 #define DEBUG_unimplemented 2
 #define DEBUG_invalid 3
diff --git a/src/hw/bar.h b/src/hw/bar.h
new file mode 100644
index 0000000..171525b
--- /dev/null
+++ b/src/hw/bar.h
@@ -0,0 +1,65 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __BAR_H
+#define __BAR_H
+
+#include <stdint.h>
+
+// write functions
+static inline void barWrite8( uint32_t bar, uint32_t offset, uint8_t value )
+{
+    volatile uint8_t* pReg = (volatile uint8_t*)(bar | ( offset & 0xFF ) );
+    *pReg = value;
+}
+
+static inline void barWrite16( uint32_t bar, uint32_t offset, uint16_t value )
+{
+    volatile uint16_t* pReg = (volatile uint16_t*)(bar | ( offset & 0xFF ) );
+    *pReg = value;
+}
+
+static inline void barWrite32( uint32_t bar, uint32_t offset, uint32_t value )
+{
+    volatile uint32_t* pReg = (volatile uint32_t*)(bar | ( offset & 0xFF ) );
+    *pReg = value;
+}
+
+// read functions
+static inline uint8_t barRead8( uint32_t bar, uint32_t offset )
+{
+    volatile uint8_t* pReg = (volatile uint8_t*)(bar | ( offset & 0xFF ) );
+    return( *pReg );
+}
+
+static inline uint16_t barRead16( uint32_t bar, uint32_t offset )
+{
+    volatile uint16_t* pReg = (volatile uint16_t*)(bar | ( offset & 0xFF ) );
+    return( *pReg );
+}
+
+static inline uint32_t barRead32( uint32_t bar, uint32_t offset )
+{
+    volatile uint32_t* pReg = (volatile uint32_t*)(bar | ( offset & 0xFF ) );
+    return( *pReg );
+}
+
+#endif /* __BAR_H */
diff --git a/src/hw/sd.c b/src/hw/sd.c
new file mode 100644
index 0000000..ac4c3b3
--- /dev/null
+++ b/src/hw/sd.c
@@ -0,0 +1,613 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "string.h"
+#include "util.h"
+#include "malloc.h"
+#include "output.h"
+#include "config.h"
+#include "sd.h"
+
+// Host controller access functions cmd/data and acmd
+static bool sdHostXfer( sdHc_t* pHost, sdXfer_t* pXfer );
+static bool sdAppSpecificHostXfer( sdHc_t* pHost, sdXfer_t* pXfer );
+
+// Card control functions
+static bool sdSelectDeselectCard( sdCard_t* pCard );
+
+// Card intialization functions
+static bool sdIdle( sdCard_t* pCard );
+static bool sdSendIfCond( sdCard_t* pCard );
+static bool sdSendOpCond( sdCard_t* pCard );
+static bool sdSendCSD( sdCard_t* pCard );
+static bool sdAllSendCID( sdCard_t* pCard );
+static bool sdSendRelativeAddr( sdCard_t* pCard );
+static bool sdCardIdentificationMode( sdCard_t* pCard );
+
+
+/**
+ * @brief     sdHostXfer - execute the host controller callback to perform
+ *                 a transfer from the host to the card and read responses and
+ *                 data from the card
+ *
+ * @param     sdHc_t* pHost - pointer to the host controller
abstraction structure
+ * @param     sdXfer_t* pXfer - pointer to the host style transfer structure
+ *
+ * @return    bool - true if successful, false otherwise
+ */
+static bool sdHostXfer( sdHc_t* pHost, sdXfer_t* pXfer )
+{
+    bool status = false;
+
+    dprintf( DEBUG_HDL_SD,
+            "SD card: Sending CMD%u with arg1 0x%08x\n",
pXfer->cmdIdx, pXfer->arg1 );
+
+    status = pHost->sdhcCmd( pHost, pXfer );
+    if( status )
+    {
+        switch( pXfer->rspType )
+        {
+            case eRsp136:
+                dprintf( DEBUG_HDL_SD,
+                        "SD card: Response 136: 0x%08x, 0x%08x,
0x%08x, 0x%08x\n",
+                        pXfer->response[0],
+                        pXfer->response[1],
+                        pXfer->response[2],
+                        pXfer->response[3] );
+                break;
+
+            case eRsp48:
+                dprintf( DEBUG_HDL_SD, "SD card: Response 48: 0x%08x\n",
+                        pXfer->response[0] );
+                break;
+
+            case eRsp48_busy:
+                dprintf( DEBUG_HDL_SD, "SD card: Response 48 with
busy signal: 0x%08x\n",
+                        pXfer->response[0] );
+                break;
+
+            case eRspNone:
+            default:
+                break;
+
+        }
+    }
+    else
+    {
+        dprintf( DEBUG_HDL_SD, "SD card:  Failed to respond to
CMD%u\n", pXfer->cmdIdx );
+    }
+
+    return status;
+}
+
+/**
+ * @brief    sdAppSpecificHostXfer - this function performs the
necessary steps to
+ *                 allow the sd card to accept application specific
commands (namely, it
+ *                 sends CMD55 prior to sending the ACMD<XX>.  CMD55
puts the card into
+ *                 application specific mode.
+ *
+ * @param     sdHc_t* pHost - pointer to the host controller
abstraction structure
+ * @param     sdXfer_t* pXfer - pointer to the host style transfer structure
+ *
+ * @return    bool - true if successful, false otherwise
+ */
+static bool sdAppSpecificHostXfer( sdHc_t* pHost, sdXfer_t* pXfer )
+{
+    bool status = false;
+    sdXfer_t xfer;
+
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_APP_CMD55;
+    xfer.arg1 = 0;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+
+    // send CMD55 to place card in APP specific mode
+    status = sdHostXfer( pHost, &xfer );
+    if( status )
+    {
+        // send APP specific cmd
+        status = sdHostXfer( pHost, pXfer );
+    }
+
+    return status;
+}
+
+/**
+ * @brief    sdSelectDeselectCard - this function impelements CMD7
SELECT/DESELECT_CARD
+ *                 to toggle a card between standby and transfer state
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdSelectDeselectCard( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+
+    // set up a transaction structure
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_SELECT_CARD_CMD7;
+    xfer.arg1 = (uint32_t)(pCard->rca) << 16;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48_busy;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+
+    // invoke the host controller callback
+    status = sdHostXfer( pCard->pHost, &xfer );
+
+    if(status)
+    {
+        pCard->isSelected = pCard->isSelected == true ? false : true;
+    }
+
+    return status;
+}
+
+/**
+ * @brief    sdReadSingleBlock - read a single block from the card
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ * @param    uint8_t* pData - pointer to the data buffer to read into
+ * @param    uint32_t addr - logical block address to read
+ *
+ * @return   bool - true on success false otherwise
+ */
+bool sdReadSingleBlock( sdCard_t* pCard, uint8_t* pData, uint32_t addr )
+{
+    bool status = false;
+    sdXfer_t xfer;
+
+    if( !pCard->isSelected )
+    {
+        // select the card (CMD7)
+        sdSelectDeselectCard( pCard );
+    }
+
+    // set up a transaction structure
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_READ_SINGLE_BLOCK_CMD17;
+    xfer.arg1 = addr;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48;
+    xfer.xferType = eRdXfer;
+    xfer.pData = pData;
+    dprintf( DEBUG_HDL_SD, "---- pData address: 0x%08x ----\n",
(uint32_t)pData);
+
+    // invoke the host controller callback
+    status = sdHostXfer( pCard->pHost, &xfer );
+
+    return status;
+}
+
+bool sdReadMultipleBlock( sdCard_t* pCard )
+{
+    bool status = false;
+    // stub
+    return status;
+}
+
+bool sdStopTransmission( sdCard_t* pCard )
+{
+    bool status = false;
+    // stub
+    return status;
+}
+
+/**
+ * @brief    sdIdle - this function implements the CMD0 GO_IDLE_MODE,
+ *                 which resets the sd card and prepares it for intalization
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdIdle( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+
+    // set up a transaction structure
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_GO_IDLE_STATE_CMD0;
+    xfer.arg1 = 0;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRspNone;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+
+    // invoke the host controller callback
+    status = sdHostXfer( pCard->pHost, &xfer );
+
+    return status;
+}
+
+/**
+ * @brief    sdSendIfCond - this function executes CMD8 SEND_IF_COND,
to determine
+ *                 whether or not the host controller is compatible
with the sd card.
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdSendIfCond( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+    uint32_t cycleTries = 1;
+
+    /* Send CMD8 to determine whether or not the host controller's
voltage setting
+     * is correct for the card
+     * NOTE: it should always be correct for SD cards, as there is
really only one
+     * voltage range currently supported as of 2013.  This may change
in the future
+     * though.  If this fails, the card is not an SD, SDCH or SDXC
card and the card
+     * is unusable, or the host controller is not setup correctly for the card.
+     */
+    // set up a transaction structure
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = SD_SEND_IF_COND_CMD8;
+
+    // voltage range 2.7 to 3.6 v and test pattern = 0xAA
+    xfer.arg1 = SD_VOLTAGE_RANGE_270_360 | SD_IF_COND_ECHO;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+
+    // check the echo response
+    while( cycleTries-- )
+    {
+        if( sdHostXfer( pCard->pHost, &xfer ) )
+        {
+            if( xfer.response[0] == xfer.arg1 )
+            {
+                status = true;
+                break;
+            }
+            usleep(100);
+        }
+    }
+    if( !status )
+    {
+        dprintf( 6, "SD: card not present or not supported in the
present operating conditions\n" );
+    }
+    return status;
+}
+
+/**
+ * @brief    sdSendOpCond - this function executes the ACMD41
SEND_OP_COND, this function
+ *                 transitions the card from the idle state to the
ready state.  This transition
+ *                 requires a minimum of one second to complete, and
is required for sdxc and sdhc
+ *                 card enumeration.
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdSendOpCond( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+    uint32_t cycleTries = SD_STATE_CHANGE_ATTEMPTS;
+
+    // Send Application specific command ACMD41 in inquiry mode
+    // (no voltage bits set) to read the OCR
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = SD_APP_SEND_OP_COND_CMD41;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+
+    // setup the voltages based on what is supported by the host
+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 &
SDHCI_CAN_VDD_180 ? VDD_S18A : 0;
+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 &
SDHCI_CAN_VDD_300 ? VDD_RANGE_27_30 : 0;
+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 &
SDHCI_CAN_VDD_330 ? VDD_RANGE_30_33 : 0;
+
+    // normal sd cards ignore the HCS bit, so set it for hcxc types
+    xfer.arg1 |= HCS;
+
+    while( cycleTries-- )
+    {
+        status = sdAppSpecificHostXfer( pCard->pHost, &xfer );
+        if( status )
+        {
+            // initialization takes 1 second to complete, and we
query the busy bit
+            // in the response to know when to stop
+            if( xfer.response[0] & OCR_DONE_BSY_N )
+            {
+                pCard->ocr = xfer.response[0];
+                pCard->xchcCard = (HCS == (pCard->ocr & HCS));
+                break;
+            }
+            else
+            {
+                udelay(100);
+            }
+        }
+    }
+    return status;
+}
+
+/**
+ * @brief    sdSendCSD - request the values from CSD register
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdSendCSD( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+    uint32_t cycleTries = SD_TRY_AGAIN;
+
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_SEND_CSD_CMD9;
+    xfer.arg1 =  (uint32_t)(pCard->rca) << 16;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp136;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+    while( cycleTries-- )
+    {
+        status = sdHostXfer( pCard->pHost, &xfer );
+        if( status )
+        {
+            // The Host Response places bits [127:8] in bits [119:0]
of the response (hence the shift)
+            memmove( xfer.response,
(void*)(((uint8_t*)(xfer.response)) - 1), sizeof(xfer.response ) );
+            pCard->csd[0] = xfer.response[3];
+            pCard->csd[1] = xfer.response[2];
+            pCard->csd[2] = xfer.response[1];
+            pCard->csd[3] = xfer.response[0];
+            decode_csd_sd( pCard->csd, &pCard->decode.csdDecode );
+            break;
+        }
+
+    }
+    return status;
+}
+
+/**
+ * @brief    sdAllSendCID - this function executes CMD2 ALL_SEND_CID,
this transitions
+ *                 the card from the ready state to the
identification state, and allows the
+ *                 card to transmit the contents of the CID register
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdAllSendCID( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+    uint32_t cycleTries = SD_TRY_AGAIN;
+
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_ALL_SEND_CID_CMD2;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp136;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+    while( cycleTries-- )
+    {
+        status = sdHostXfer( pCard->pHost, &xfer );
+        if( status )
+        {
+            // The Host Response places bits [127:8] in bits [119:0]
of the response (hence the shift)
+            memmove( xfer.response,
(void*)(((uint8_t*)(xfer.response)) - 1), sizeof(xfer.response ) );
+
+            // the utility functions swap the result prior to use
+            pCard->cid[0] = xfer.response[3];
+            pCard->cid[1] = xfer.response[2];
+            pCard->cid[2] = xfer.response[1];
+            pCard->cid[3] = xfer.response[0];
+            decode_cid_sd( pCard->cid, &pCard->decode.cidDecode );
+            break;
+        }
+
+    }
+    return status;
+
+}
+
+/**
+ * @brief    sdSendRelativeAddr - this function executes CMD3 -
SEND_RELATIVE_ADDRESS, of the
+ *                 card initialization sequence.  After successful
completion, the relative card
+ *                 address (RCA) of the card is known, and the SD
card enters standby mode from
+ *                 card identification mode
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdSendRelativeAddr( sdCard_t* pCard )
+{
+    bool status = false;
+    sdXfer_t xfer;
+    uint32_t cycleTries = SD_TRY_AGAIN;
+    sdCardState_e currentState = eInvalid;
+
+    memset( &xfer, 0, sizeof( sdXfer_t ) );
+    xfer.cmdIdx = MMC_SET_RELATIVE_ADDR_CMD3;
+    xfer.cmdType = eCmdNormal;
+    xfer.rspType = eRsp48;
+    xfer.xferType = eWrXfer;
+    xfer.pData = NULL;
+    while( cycleTries-- )
+    {
+        status = sdHostXfer( pCard->pHost, &xfer );
+        if( status )
+        {
+            // the response is the R6 response containing the relative card
+            // address, and current status info
+            pCard->rca = (uint16_t)(xfer.response[0] >> 16);
+            if( xfer.response[0] & RCAERROR_MSK )
+            {
+                dprintf( DEBUG_HDL_SD,
+                        "SD card: RCA request responded with error
status: 0x%08x\n",
+                        xfer.response[0] & RCAERROR_MSK );
+                status = false;
+                // here there should probably be a full status check
+            }
+
+            // now the card should be in stby mode (this might not be
reflected until
+            // the next command (the offset is bit 9 : 12 for state info)
+            currentState = (sdCardState_e)((xfer.response[0] &
RCASTATUS_CURRENT_STATE) >> 9);
+            if( currentState == eStby )
+            {
+                dprintf( DEBUG_HDL_SD, "SD card: Current state is
stby: 0x%02x - \n", currentState );
+                break;
+            }
+        }
+    }
+    return status;
+
+}
+
+/**
+ * @brief    sdCardIdentificationMode - this function executes the
call sequence/state
+ *                 machine outlined in section 4.2 of "Physical Layer
Simplified Specification
+ *                 Version 4.10"
+ *
+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure
+ *
+ * @return   bool - true if successful, false otherwise
+ */
+static bool sdCardIdentificationMode( sdCard_t* pCard )
+{
+    bool status = false;
+    uint32_t cycleTries = NUM_INIT_ATTEMPTS;
+
+    ASSERT32FLAT();
+     while( cycleTries-- )
+     {
+        // CMD8 - SEND_IF_COND
+        if( !(status = sdSendIfCond( pCard )) )
+            continue;
+
+        // ACMD41 - SEND_OP_COND to properly initialize SDHC and SDXC cards...
+        if( !(status = sdSendOpCond( pCard )) )
+            continue;
+
+        // If the voltage needs to change based on the response for
ACMD41, change it using CMD11
+        // @TODO: implement CMD11 voltage switch if necessary...
probably don't need to support this
+        // for a while
+
+        // Else Send CMD2 to get the CID, the card should be in
identification state
+        if( !(status = sdAllSendCID( pCard )) )
+            continue;
+
+        // Send CMD3 to get the relative card address (RCA) used for
broad cast commands
+        if( !(status = sdSendRelativeAddr( pCard )) )
+            continue;
+
+        // Send CMD9 to get the CSD register info
+        if( !(status = sdSendCSD( pCard )) )
+            continue;
+
+        // the card will now be in standby state, and is ready for
data transfers
+        if( status == true )
+        {
+            dprintf( DEBUG_HDL_SD, "SD card: Initialization of sd
card is complete:\n" );
+            dprintf( DEBUG_HDL_SD, "  - currrent card state:  standby\n");
+            dprintf( DEBUG_HDL_SD, "  - RCA: 0x%04x\n", pCard->rca );
+            dprintf( DEBUG_HDL_SD, "  - OCR: 0x%08x\n", pCard->ocr );
+            dprintf( DEBUG_HDL_SD,
+                    "  - CID: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+                    pCard->cid[0], pCard->cid[1], pCard->cid[2],
pCard->cid[3] );
+            dprintf( DEBUG_HDL_SD,
+                    "  - CSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+                    pCard->csd[0], pCard->csd[1], pCard->csd[2],
pCard->csd[3] );
+            dprintf( DEBUG_HDL_SD, "  - card type is ");
+            if( pCard->xchcCard )
+            {
+                dprintf( DEBUG_HDL_SD, "SDXC/SDHC\n" );
+            }
+            else
+            {
+                dprintf( DEBUG_HDL_SD, "Normal SD\n" );
+            }
+
+
+            break;
+        }
+     }
+    return status;
+}
+
+/**
+ * @brief    sdCardBusInit - public function to initialize the SD card-bus.
+ *                 This function is called by the host controller
after the host
+ *                 controller has completed its initial "pessimistic"
configuration.
+ *                 This function implements the steps in the sequence
diagram of figure
+ *                 4-1 of the "Physical Layer Simplified
Specification Version 4.10" of the
+ *                 SD card specification documents.
+ *
+ * @param    sdHc_t* hc - pointer to the host controller structure
+ *
+ * @return   bool - status, true = success, false = failure of the
card bus initialization
+ */
+bool sdCardBusInit( sdHc_t* pHc )
+{
+    bool status = false;
+
+    // allocate the card
+    sdCard_t* pCard = malloc_fseg( sizeof( sdCard_t ) );
+    if( !pCard )
+    {
+        dprintf( DEBUG_HDL_SD, "SD: card failed to allocate\n" );
+        return status;
+    }
+    dprintf( DEBUG_HDL_SD, "SD:  pCard address: 0x%08x\n", (uint32_t)pCard);
+
+    // set the host pointer
+    pCard->pHost = pHc;
+
+    // Set Idle Mode with CMD0
+    status = sdIdle( pCard );
+
+    if( status )
+    {
+        // execute the initialization/identification procedure
+        pCard->cardInitialized = sdCardIdentificationMode( pCard );
+    }
+
+    if( !pCard->cardInitialized )
+    {
+        dprintf( DEBUG_HDL_SD, "SD: Card init failed, check card...\n");
+        status = pCard->cardInitialized;
+        free( pCard );
+    }
+    else
+    {
+        // If we get here, the card is in standby mode, so give a
+        // reference to the host controller
+        pHc->pCard = pCard;
+    }
+    return status;
+}
diff --git a/src/hw/sd.h b/src/hw/sd.h
new file mode 100644
index 0000000..bcf4d94
--- /dev/null
+++ b/src/hw/sd.h
@@ -0,0 +1,275 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __SD_H
+#define __SD_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "sd_utils.h"
+
+/** @file sd.h */
+
+#include "sdhci.h"
+
+/** @brief sd host capabilities registers */
+typedef struct
+{
+    uint32_t cap1;
+    uint32_t cap2;
+}capabilities_t;
+
+typedef enum
+{
+    eCmdNormal = SDHCI_CMD_TYPE_NORMAL,
+    eCmdSuspend = SDHCI_CMD_TYPE_SUSPEND,
+    eCmdResume = SDHCI_CMD_TYPE_RESUME,
+    eCmdAbort = SDHCI_CMD_TYPE_ABORT
+}sdCmdType_e;
+
+typedef enum
+{
+    eRspNone = SDHCI_CMD_RESP_NONE,
+    eRsp136 = SDHCI_CMD_RESP_LONG,
+    eRsp48 = SDHCI_CMD_RESP_SHORT,
+    eRsp48_busy = SDHCI_CMD_RESP_SHORT_BUSY
+}sdRspType_e;
+
+typedef enum
+{
+    eSdSpecV_1_00 = 0,
+    eSdSpecV_2_00,
+    eSdSpecV_3_00
+}sdSpecVer_e;
+
+typedef enum
+{
+    eRdXfer = 0,
+    eWrXfer
+}sdXferType_e;
+
+typedef struct
+{
+    bool idxChkEn;
+    bool crcChkEn;
+}sdXferFlags_t;
+
+/** @brief struct used for host to card and card to host transfers */
+typedef struct
+{
+    uint8_t                     cmdIdx;
+    uint32_t                    arg1;
+    sdCmdType_e                 cmdType;
+    sdRspType_e                 rspType;
+    sdXferType_e                xferType;
+    uint32_t                    response[4];
+    bool                        rspValid;
+    void*                       pData;
+}sdXfer_t;
+
+/** @brief struct to hold decoded CID and CSD registers (see SD
Specification) */
+typedef struct
+{
+    sd_cid_t                    cidDecode;
+    sd_csd_t                    csdDecode;
+}sdRegDecode_t;
+
+// resolve forward declarations
+struct sdCard_t;
+typedef struct sdCard_t sdCard_t;
+
+typedef struct sdHc_t
+{
+    uint32_t                 barAddress;
+    capabilities_t           cardCapabilities;
+    uint32_t                 maxClk;
+    uint32_t                 tmoClk;
+    uint32_t                 curClk;
+    uint32_t                 blkSize;
+    uint32_t                 pwrMode;
+    bool                     crcCheckEnable;
+    bool                     indexCheckEnable;
+    bool                     xchcSupported;
+    bool                     isInitialized;
+    uint8_t                  hostVendorId;
+    uint8_t                  hostSpecId;
+    sdCard_t*                pCard;
+
+    // call back to host for sending commands to the card via the
host controller interface
+    bool (*sdhcCmd)( struct sdHc_t* pSdCtrl, sdXfer_t* xfer );
+}sdHc_t;
+
+/**
+ * SD Memory Card Registers
+ */
+typedef struct sdCard_t
+{
+    sdHc_t*                 pHost;
+    uint32_t                cid[4];
+    uint16_t                rca;
+    uint16_t                dsr;
+    uint32_t                csd[4];
+    uint32_t                scr[2];
+    uint32_t                ocr;
+    uint32_t                ssr[16];
+    uint32_t                csr;
+    sdRegDecode_t           decode;
+    bool                    xchcCard;
+    bool                    cardInitialized;
+    bool                    isSelected;
+}sdCard_t;
+
+#define BLOCK_SIZE8      512
+#define MHZ 1000000
+#define KHZ 1000
+#define BLOCK_MASK 0x00000FFF
+
+// MMC Card Commands that mostly overlap with the SD specification,
some have slightly different meaning or results
+#define MMC_GO_IDLE_STATE_CMD0            0
+#define MMC_SEND_OP_COND_CMD1             1
+#define MMC_ALL_SEND_CID_CMD2             2
+#define MMC_SET_RELATIVE_ADDR_CMD3        3
+#define MMC_SET_DSR_CMD4                  4
+#define MMC_SWITCH_CMD6                   6
+#define MMC_SELECT_CARD_CMD7              7
+#define MMC_SEND_EXT_CSD_CMD8             8
+#define MMC_SEND_CSD_CMD9                 9
+#define MMC_SEND_CID_CMD10                10
+#define MMC_STOP_TRANSMISSION_CMD12       12
+#define MMC_SEND_STATUS_CMD13             13
+#define MMC_SET_BLOCKLEN_CMD16            16
+#define MMC_READ_SINGLE_BLOCK_CMD17       17
+#define MMC_READ_MULTIPLE_BLOCK_CMD18     18
+#define MMC_WRITE_SINGLE_BLOCK_CMD24      24
+#define MMC_WRITE_MULTIPLE_BLOCK_CMD25    25
+#define MMC_ERASE_GROUP_START_CMD35       35
+#define MMC_ERASE_GROUP_END_CMD36         36
+#define MMC_ERASE_CMD38                   38
+#define MMC_APP_CMD55                     55
+#define MMC_SPI_READ_OCR_CMD58            58
+#define MMC_SPI_CRC_ON_OFF_CMD59          59
+
+// SD card specific commands
+#define SD_SEND_RELATIVE_ADDR_CMD3        3
+#define SD_SWITCH_FUNC_CMD6               6
+#define SD_SEND_IF_COND_CMD8              8
+#define SD_APP_SET_BUS_WIDTH_CMD6         6
+#define SD_ERASE_WR_BLK_START_CMD32       32
+#define SD_ERASE_WR_BLK_END_CMD33         33
+#define SD_APP_SEND_OP_COND_CMD41         41
+#define SD_APP_SEND_SCR_CMD51             51
+
+// other useful defines
+#define SD_VOLTAGE_RANGE_270_360          0x00000100
+#define SD_IF_COND_ECHO                   0x000000AA
+#define SD_STATE_CHANGE_ATTEMPTS          1000
+#define SD_TRY_AGAIN                      10
+
+
+// ACMD41 bit shifts and masks
+#define OCR_DONE_BSY_N        (1 << 31)
+#define HCS_SHIFT 30
+#define HCS  (1 << HCS_SHIFT)
+#define XPC_SHIFT 28
+#define XPC  (1 << XPC_SHIFT)
+#define S18R_SHIFT 24
+#define S18R (1 << S18R_SHIFT)
+#define OCR_SHIFT 8
+#define OCR  (0xFF << OCR_SHIFT)
+
+// OCR register voltage ranges
+#define VDD_27_28    (1 << 15)
+#define VDD_28_29    (1 << 16)
+#define VDD_29_30    (1 << 17)
+#define VDD_30_31    (1 << 18)
+#define VDD_31_32    (1 << 19)
+#define VDD_32_33    (1 << 20)
+#define VDD 33_34    (1 << 21)
+#define VDD_34_35    (1 << 22)
+#define VDD_35_36    (1 << 23)
+#define VDD_S18A     (1 << 24)
+
+
+#define VDD_MASK        ( VDD_27_28 | VDD_28_29 | VDD_29_30 |
VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD 33_34 | VDD_34_35 | VDD_35_36
)
+#define VDD_RANGE_27_30 ( VDD_27_28 | VDD_28_29 | VDD_29_30 )
+#define VDD_RANGE_30_33 ( VDD_30_31 | VDD_31_32 | VDD_32_33 )
+#define VDD_RANGE_33_36 ( VDD 33_34 | VDD_34_35 | VDD_35_36 )
+
+#define CARD_UHS_II_STATUS          (1 << 29)
+#define CARD_CAPACITY_STATUS        (1 << 30)
+#define CARD_POWER_UP_BUSY          (1 << 31)
+
+//! Physical Layer Simplified Specification Version 4.10 "Card
Status" bits from Table 4-41
+#define SDCARD_OUT_OF_RANGE         (1 << 31)
+#define SDCARD_ADDRESS_ERROR        (1 << 30)
+#define SDCARD_BLOCK_LEN_ERROR      (1 << 29)
+#define SDCARD_ERASE_SEQ_ERROR      (1 << 28)
+#define SDCARD_ERASE_PARAM          (1 << 27)
+#define SDCARD_WP_VIOLATION         (1 << 26)
+#define SDCARD_CARD_IS_LOCKED       (1 << 25)
+#define SDCARD_LOCK_UNLOCK_FAILED   (1 << 24)
+#define SDCARD_COM_CRC_ERROR        (1 << 23)
+#define SDCARD_ILLEGAL_COMMAND      (1 << 22)
+#define SDCARD_CARD_ECC_FAILED      (1 << 21)
+#define SDCARD_CC_ERROR             (1 << 20)
+#define SDCARD_ERROR                (1 << 19)
+#define SDCARD_CSD_OVERWRITE        (1 << 16)
+#define SDCARD_WP_ERASE_SKIP        (1 << 15)
+#define SDCARD_CARD_ECC_DISABLED    (1 << 14)
+#define SDCARD_ERASE_RESET          (1 << 13)
+#define SDCARD_CURRENT_STATE        (0xF << 9)
+#define SDCARD_READY_FOR_DATA       (1 << 8)
+#define SDCARD_APP_CMD              (1 << 5)
+#define SDCARD_AKE_SEQ_ERROR        (1 << 3)
+
+// RCA RESPONSE STATUS BITS
+#define RCASTATUS_COM_CRC_ERROR     (1 << 15)
+#define RCASTATUS_ILLEGAL_COMMAND   (1 << 14)
+#define RCASTATUS_ERROR             (1 << 13)
+#define RCASTATUS_CURRENT_STATE     (SDCARD_CURRENT_STATE)
+#define RCASTATUS_READY_FOR_DATA    (SDCARD_READY_FOR_DATA)
+#define RCASTATUS_APP_CMD           (SDCARD_APP_CMD)
+#define RCASTATUS_AKE_SEQ_ERROR     (SDCARD_AKE_SEQ_ERROR)
+
+#define RCAERROR_MSK    (RCASTATUS_COM_CRC_ERROR |
RCASTATUS_ILLEGAL_COMMAND | RCASTATUS_ERROR)
+
+typedef enum
+{
+    eIdle = 0,
+    eReady,
+    eIdent,
+    eStby,
+    eTran,
+    eData,
+    eRcv,
+    ePrg,
+    eDis,
+    eInvalid
+}sdCardState_e;
+
+#define NUM_INIT_ATTEMPTS 2
+
+bool sdCardBusInit( sdHc_t* pHc );
+bool sdReadSingleBlock( sdCard_t* pCard, uint8_t* pData, uint32_t addr );
+bool sdReadMultipleBlock( sdCard_t* pCard );
+bool sdStopTransmission( sdCard_t* pCard );
+
+#endif // __SD_H
diff --git a/src/hw/sd_if.c b/src/hw/sd_if.c
new file mode 100644
index 0000000..0d00b3c
--- /dev/null
+++ b/src/hw/sd_if.c
@@ -0,0 +1,413 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#include "stacks.h"
+#include "string.h"
+#include "malloc.h"
+#include "util.h"
+#include "output.h"
+#include "biosvar.h"
+#include "pci.h"
+#include "pci_ids.h"
+#include "std/disk.h"
+#include "bar.h"
+#include "sdhci.h"
+#include "sdhc_generic.h"
+#include "sd_if.h"
+
+sdDiskIf_t* g_pDev;
+
+static int sd_disk_read( struct disk_op_s* op );
+static int sd_disk_read_aligned( struct disk_op_s* op );
+
+/**
+ * @brief    sd_disk_init - finalize the SeaBIOS drive initialization
and register the drive
+ *
+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure
+ *
+ * @return   none
+ */
+static void sd_disk_init( sdDiskIf_t* pSdIf )
+{
+    pSdIf->drive.blksize = pSdIf->pHostCtrl->blkSize;
+    pSdIf->drive.type = DTYPE_SD;
+    pSdIf->drive.cntl_id = 0;  // @TODO: Presently only one SD card
is supported at a time!
+    pSdIf->drive.removable = false;
+    pSdIf->drive.translation = TRANSLATION_LBA;
+    // shift by 9 (divide by 512 block size)
+    pSdIf->drive.sectors =
pSdIf->pHostCtrl->pCard->decode.csdDecode.capacity >> 9;
+    dprintf( DEBUG_HDL_SD, "SD: num sectors: %d\n",
(uint32_t)pSdIf->drive.sectors );
+
+    // generate host vendor/spec string
+    pSdIf->desc = znprintf( MAXDESCSIZE,
+                          "SD Card Vendor ID: %d",
+                          pSdIf->pHostCtrl->hostVendorId );
+
+    pSdIf->bootPriority = bootprio_find_pci_device( (struct
pci_device*)pSdIf->pPci );
+    dprintf( DEBUG_HDL_SD, "SD card boot priority: 0x%08x\n",
pSdIf->bootPriority );
+
+    // register the device as a hard disk
+    boot_add_hd(&pSdIf->drive, pSdIf->desc, (int)pSdIf->bootPriority );
+}
+
+/**
+ * @brief    sd_host_setup - setup the host controller driver, if the host
+ *                 is successfully initialized, setup the sd card
initialization
+ *
+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure
+ *
+ * @return   bool true if the card was successfully initialized and
prepared for boot
+ *                  fasle otherwise
+ */
+static bool sd_host_setup( sdDiskIf_t* pSdIf)
+{
+    bool status = false;
+
+    // perform the sd card initialization sequence
+    if( sdhc_init( pSdIf->pHostCtrl ) )
+    {
+        // if the card passes initialization and goes to standby
mode, it is ready for boot, so setup the disk info
+        if( sdCardBusInit( pSdIf->pHostCtrl ) )
+        {
+            sd_disk_init( pSdIf );
+
+            // the card is now enumerated, prepare it for boot
(operational mode)
+            sdhc_prepBoot( pSdIf->pHostCtrl );
+            status = true;
+        }
+    }
+    return status;
+}
+
+/**
+ * @brief    sd_card_detect - check to see if the card detect
indicates that a card is present
+ *                 if there is a card, setup the host and intialize
the underlying card
+ *
+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure
+ *
+ * @return   bool status of the card detect bit
+ */
+static bool sd_card_detect( sdDiskIf_t* pSdIf )
+{
+    bool status = false;
+    uint32_t regVal32 = 0;
+
+    // check to see if the card is present
+    regVal32 = barRead32(pSdIf->pHostCtrl->barAddress, SDHCI_PRESENT_STATE);
+    status = (regVal32 & SDHCI_CARD_PRESENT) == SDHCI_CARD_PRESENT ?
true : false;
+
+    // if the card is present, register it in the boot sequence
+    if( status )
+    {
+        status = sd_host_setup( pSdIf );
+    }
+
+    return status;
+}
+
+
+/**
+ * @brief    sd_config_setup - setup the sd host controller driver
and allocate resources.
+ *
+ * @param    struct pci_device* pci - pointer to the sdhci controller
pci device.
+ *
+ * @return   none
+ */
+static void sd_config_setup(struct pci_device* pci)
+{
+    dprintf(6, "sd_config_setup: 0x%04x\n", pci->bdf );
+
+    // allocate the pci to sd interface structure
+    g_pDev = (sdDiskIf_t*)malloc_fseg( sizeof(*g_pDev) );
+    if( !g_pDev )
+    {
+        warn_noalloc();
+        return;
+    }
+    memset( g_pDev, 0, sizeof( *g_pDev ) );
+
+    // allocate the host controller
+    g_pDev->pHostCtrl = (sdHc_t*)malloc_fseg( sizeof(*g_pDev->pHostCtrl) );
+    if( !(g_pDev->pHostCtrl) )
+    {
+        warn_noalloc();
+        free(g_pDev);
+        return;
+    }
+    memset( g_pDev->pHostCtrl, 0, sizeof( *g_pDev->pHostCtrl) );
+    g_pDev->pHostCtrl->isInitialized = false;
+
+    // assign the pci device and set up the host controller
+    g_pDev->pPci = pci;
+
+    // setup bar0
+    g_pDev->pHostCtrl->barAddress =
pci_config_readl(g_pDev->pPci->bdf, 0x10) & 0xFFFFFF00;
+
+    // check for card detect
+    if( !sd_card_detect(g_pDev) )
+    {
+        dprintf( DEBUG_HDL_SD, "No SD card detected\n");
+        free( g_pDev->pHostCtrl );
+        free( g_pDev );
+    }
+
+    else
+    {
+        dprintf( DEBUG_HDL_SD, "SD card is inserted\n");
+
+        // initialize bounce buffer
+        if( create_bounce_buf() < 0 )
+        {
+            warn_noalloc();
+            free( g_pDev);
+        }
+    }
+}
+
+
+/**
+ * @brief    sd_scan - seabios function to scan for the sd conroller
on the pci bus
+ *
+ * @param    none
+ *
+ * @return   none
+ */
+static void sd_scan(void)
+{
+    struct pci_device *pci = NULL;
+    dprintf(6, "SD: Scanning for SD Host controllers\n" );
+
+    // Scan PCI bus for sd_mmc host controllers
+    foreachpci(pci)
+    {
+        if( pci->class != PCI_CLASS_SYSTEM_SDHCI )
+        {
+            continue;
+        }
+
+        if( pci->prog_if != 1 )
+        {
+            continue;
+        }
+        dprintf(6, "Found PCI SDHCI controller\n");
+
+        // setup the sd host controller hardware
+        sd_config_setup(pci);
+    }
+}
+
+
+
+/**
+ * @brief    sd_setup - seabios function
+ *
+ * @param    none
+ *
+ * @return   none
+ */
+void sd_setup( void )
+{
+    ASSERT32FLAT();
+    if( CONFIG_SD )
+    {
+        dprintf(3, "init SD drives\n");
+        sd_scan();
+    }
+}
+
+/**
+ * @brief    sd_cmd_data - seabios entry point for command/data disk
transactions
+ *
+ * @param    struct disk_op_s *op - pointer to the disk operations structure
+ * @param    uint16_t blocksize - the size of the blocks for the
block device transactions
+ *
+ * @return   int disk operation status
+ */
+int sd_cmd_data( struct disk_op_s *op, void *cdbcmd, uint16_t blocksize )
+{
+    int retVal = DISK_RET_EPARAM;
+    dprintf(3, "sd_cmd_data\n");
+
+    switch( op->command )
+    {
+        case CMD_READ:
+            retVal = sd_disk_read( op );
+            break;
+        case CMD_WRITE:
+            break;
+        case CMD_RESET:
+        case CMD_ISREADY:
+        case CMD_FORMAT:
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            retVal = DISK_RET_SUCCESS;
+            break;
+        default:
+            retVal = DISK_RET_EPARAM;
+            break;
+    }
+    return retVal;
+}
+
+
+/**
+ * @brief    sd_disk_read_aligned - read into an aligned buffer a
block of data from the sd card
+ *
+ * @param    struct disk_op_s* op - pointer to the disk operation request
+ *
+ * @return   int - disk operation status
+ */
+static int sd_disk_read_aligned( struct disk_op_s* op )
+{
+    int retVal = DISK_RET_SUCCESS;
+    sdDiskIf_t* pSdIf = GET_GLOBAL( g_pDev );
+    uint16_t i = 0;
+    uint8_t* curPosition = (uint8_t*)op->buf_fl;
+
+    for( i = 0; i < op->count; i++ )
+    {
+        if( !sdReadSingleBlock( pSdIf->pHostCtrl->pCard, curPosition,
(uint32_t)(op->lba + i)) )
+        {
+            dprintf( DEBUG_HDL_SD, "SD Read Fail\n");
+            retVal = DISK_RET_EPARAM;
+            break;
+        }
+        else
+        {
+            dprintf( DEBUG_HDL_SD, "sd disk %s, lba %6x, count %3x,
buf %p, rc %d\n",
+                           "read", (u32)op->lba + i, op->count - i,
curPosition, retVal);
+            curPosition += BLOCK_SIZE8;
+        }
+    }
+    dprintf( DEBUG_HDL_SD, "return from read retval = %u\n", retVal );
+    return retVal;
+}
+
+/**
+ * @brief    sd_disk_read - if the requested buffer is word aligned,
performs the disk read operation
+ *
+ * @param    struct disk_op_s* op - pointer to the disk operation request
+ *
+ * @return   int - disk operation status
+ */
+static int sd_disk_read( struct disk_op_s* op )
+{
+    int retVal = DISK_RET_EPARAM;
+    struct disk_op_s localOp;
+    uint8_t* alignedBuf = NULL;
+    uint8_t* curPosition = NULL;
+    uint16_t i = 0;
+
+    // check if the callers buffer is word aligned, if so use it directly
+    if( ( (uint32_t)op->buf_fl & 1 ) == 0 )
+    {
+        dprintf( DEBUG_HDL_SD, "sd read: buffer already alligned\n");
+        retVal = sd_disk_read_aligned( op );
+    }
+    else
+    {
+        dprintf( DEBUG_HDL_SD, "sd read: unaligned buffer, performing
realligend read\n");
+        // get access to an aligned buffer for the disk operation
+        localOp = *op;
+        alignedBuf = GET_GLOBAL( bounce_buf_fl );
+        curPosition = op->buf_fl;
+
+        // execute the aligned to unaligned access one operation at a time
+        localOp.buf_fl = alignedBuf;
+        localOp.count = 1;
+
+        for( i = 0; i < op->count; i++ )
+        {
+            retVal = sd_disk_read_aligned( &localOp );
+            if( retVal )
+            {
+                dprintf( DEBUG_HDL_SD, "  - aligned read fail\n");
+                break;
+            }
+            memcpy_fl( curPosition, alignedBuf, BLOCK_SIZE8 );
+            curPosition += BLOCK_SIZE8;
+            localOp.lba++;
+        }
+
+    }
+    return retVal;
+}
+
+/**
+ * @brief    process_sd_op - entry point for disk io operations for sea bios
+ *
+ * @param    struct disk_op_s *op - disk io functions
+ *
+ * @return   int - disk return value from disk.h
+ *
+ * @NOTE:    The macro VISIBLE32FLAT is indicitave of a call to 32
bit mode from 16-bit mode it forces the compiler
+ *             to prepend the <function name> with
<_cfunc32flat_><funciton name>, so in this case if you were to perform
+ *             a search for the caller of process_sd_op, you may not
find it unless you search for _cfunc32flat_process_sd_op
+ */
+
+int VISIBLE32FLAT process_sd_op( struct disk_op_s *op  )
+{
+    int retVal = DISK_RET_EPARAM;
+
+    // ensure the configuration exists
+    if (!CONFIG_SD)
+        return 0;
+
+    dprintf( DEBUG_HDL_SD, "Executing SD disk transaction:  %d\r\n",
op->command );
+    // execute a command
+    switch( op->command )
+    {
+        case CMD_READ:
+            dprintf( DEBUG_HDL_SD,
+                    "SD CMD_READ: lba: 0x%08x%08x\n",
(uint32_t)(op->lba >> 32), (uint32_t)(op->lba) );
+            dprintf( DEBUG_HDL_SD, "  op->count = %d\n", op->count );
+            retVal = sd_disk_read( op );
+            break;
+        case CMD_WRITE:
+            break;
+        case CMD_RESET:
+        case CMD_ISREADY:
+        case CMD_FORMAT:
+        case CMD_VERIFY:
+        case CMD_SEEK:
+            retVal = DISK_RET_SUCCESS;
+            break;
+        default:
+            op->count = 0;
+            retVal = DISK_RET_EPARAM;
+            break;
+
+    }
+    return retVal;
+}
+
+void SD_DEBUG( const char* func, unsigned int line )
+{
+    volatile uint8_t exit = 0;
+    volatile uint32_t i = 0;
+
+    dprintf( DEBUG_HDL_SD, "%s, %d\n", func, line );
+
+    while( !exit )
+    {
+        i++;
+    }
+}
diff --git a/src/hw/sd_if.h b/src/hw/sd_if.h
new file mode 100644
index 0000000..af2e626
--- /dev/null
+++ b/src/hw/sd_if.h
@@ -0,0 +1,49 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __SD_IF_H
+#define __SD_IF_H
+
+#include <stdint.h>
+#include "block.h"
+#include "config.h"
+#include "pci.h"
+#include "sd.h"
+
+/** @file sd_if.h*/
+
+// SeaBIOS to SD driver interface (to allow portability for reuse of sd driver
+
+typedef struct
+{
+    struct drive_s          drive;
+    int32_t                 bootPriority;
+    const char*             desc;
+    struct pci_device*      pPci;
+    sdHc_t*                 pHostCtrl;
+}sdDiskIf_t;
+
+void sd_setup (void );
+int sd_cmd_data( struct disk_op_s *op, void *cdbcmd, uint16_t blocksize );
+int process_sd_op( struct disk_op_s *op );
+void SD_DEBUG(const char* func, unsigned int line);
+#define SD_STOP( ) SD_DEBUG( __FUNCTION__, __LINE__ )
+#endif // __SD_IF_H
diff --git a/src/hw/sd_utils.c b/src/hw/sd_utils.c
new file mode 100644
index 0000000..6920cb1
--- /dev/null
+++ b/src/hw/sd_utils.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2006 Bernd Walter.  All rights reserved.
+ * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
+ * Copyright (C) 2013-2104 Sage Electronic Engineering, LLC
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ */
+
+/*
+ * NOTE:  This is refactored code from FreeBSD modified to be OS agnostic and
+ *           independent for use in bootloading.
+ */
+
+#include "config.h"
+#include "string.h"
+#include "output.h"
+#include "sd_utils.h"
+
+static uint32_t get_bits(uint32_t *bits, int bit_len, int start, int size);
+
+static const int exp[8] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+static const int mant[16] = {
+    0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+
+static const int cur_min[8] = {
+    500, 1000, 5000, 10000, 25000, 35000, 60000, 100000
+};
+
+static const int cur_max[8] = {
+    1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000
+};
+
+static uint32_t get_bits(uint32_t *bits, int bit_len, int start, int size)
+{
+    const int i = (bit_len / 32) - (start / 32) - 1;
+    const int shift = start & 31;
+    uint32_t retval = bits[i] >> shift;
+    if (size + shift > 32)
+        retval |= bits[i - 1] << (32 - shift);
+    return (retval & ((1llu << size) - 1));
+}
+
+void decode_cid_sd(uint32_t *raw_cid, sd_cid_t* cid)
+{
+    int i;
+
+    /* There's no version info, so we take it on faith */
+    memset(cid, 0, sizeof(*cid));
+    cid->mid = get_bits(raw_cid, 128, 120, 8);
+    cid->oid = get_bits(raw_cid, 128, 104, 16);
+    for (i = 0; i < 5; i++)
+        cid->pnm[i] = get_bits(raw_cid, 128, 96 - i * 8, 8);
+    cid->pnm[5] = 0;
+    cid->prv = get_bits(raw_cid, 128, 56, 8);
+    cid->psn = get_bits(raw_cid, 128, 24, 32);
+    cid->mdt_year = get_bits(raw_cid, 128, 12, 8) + 2000;
+    cid->mdt_month = get_bits(raw_cid, 128, 8, 4);
+}
+
+void decode_csd_sd(uint32_t *raw_csd, sd_csd_t* csd)
+{
+    int v;
+    int m;
+    int e;
+    int tst;
+
+    memset(csd, 0, sizeof(*csd));
+    csd->csd_structure = v = get_bits(raw_csd, 128, 126, 2);
+    dprintf( DEBUG_HDL_SD, "CSD Register Info:\n" );
+    if (v == 0) {
+        dprintf( DEBUG_HDL_SD, "  CSD Version 1.0\n");
+        m = get_bits(raw_csd, 128, 115, 4);
+        e = get_bits(raw_csd, 128, 112, 3);
+
+        tst = get_bits(raw_csd, 128, 112, 8 );
+        dprintf( DEBUG_HDL_SD, "  RAW TAAC: 0x%02x\n", (uint8_t)tst );
+
+        csd->tacc = (exp[e] * mant[m] + 9) / 10;
+        csd->nsac = get_bits(raw_csd, 128, 104, 8) * 100;
+        m = get_bits(raw_csd, 128, 99, 4);
+        e = get_bits(raw_csd, 128, 96, 3);
+        csd->tran_speed = exp[e] * 10000 * mant[m];
+        csd->ccc = get_bits(raw_csd, 128, 84, 12);
+        csd->read_bl_len = 1 << get_bits(raw_csd, 128, 80, 4);
+        csd->read_bl_partial = get_bits(raw_csd, 128, 79, 1);
+        csd->write_blk_misalign = get_bits(raw_csd, 128, 78, 1);
+        csd->read_blk_misalign = get_bits(raw_csd, 128, 77, 1);
+        csd->dsr_imp = get_bits(raw_csd, 128, 76, 1);
+        csd->vdd_r_curr_min = cur_min[get_bits(raw_csd, 128, 59, 3)];
+        csd->vdd_r_curr_max = cur_max[get_bits(raw_csd, 128, 56, 3)];
+        csd->vdd_w_curr_min = cur_min[get_bits(raw_csd, 128, 53, 3)];
+        csd->vdd_w_curr_max = cur_max[get_bits(raw_csd, 128, 50, 3)];
+        m = get_bits(raw_csd, 128, 62, 12);
+        e = get_bits(raw_csd, 128, 47, 3);
+        csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;
+        csd->erase_blk_en = get_bits(raw_csd, 128, 46, 1);
+        csd->erase_sector = get_bits(raw_csd, 128, 39, 7) + 1;
+        csd->wp_grp_size = get_bits(raw_csd, 128, 32, 7);
+        csd->wp_grp_enable = get_bits(raw_csd, 128, 31, 1);
+        csd->r2w_factor = 1 << get_bits(raw_csd, 128, 26, 3);
+        csd->write_bl_len = 1 << get_bits(raw_csd, 128, 22, 4);
+        csd->write_bl_partial = get_bits(raw_csd, 128, 21, 1);
+    } else if (v == 1) {
+        dprintf( DEBUG_HDL_SD, "CSD Version 2.0\n");
+        m = get_bits(raw_csd, 128, 115, 4);
+        e = get_bits(raw_csd, 128, 112, 3);
+
+        tst = get_bits(raw_csd, 128, 112, 8 );
+        dprintf( DEBUG_HDL_SD, "  RAW TAAC: 0x%02x\n", (uint8_t)tst );
+
+        csd->tacc = (exp[e] * mant[m] + 9) / 10;
+        csd->nsac = get_bits(raw_csd, 128, 104, 8) * 100;
+        m = get_bits(raw_csd, 128, 99, 4);
+        e = get_bits(raw_csd, 128, 96, 3);
+        csd->tran_speed = exp[e] * 10000 * mant[m];
+        csd->ccc = get_bits(raw_csd, 128, 84, 12);
+        csd->read_bl_len = 1 << get_bits(raw_csd, 128, 80, 4);
+        csd->read_bl_partial = get_bits(raw_csd, 128, 79, 1);
+        csd->write_blk_misalign = get_bits(raw_csd, 128, 78, 1);
+        csd->read_blk_misalign = get_bits(raw_csd, 128, 77, 1);
+        csd->dsr_imp = get_bits(raw_csd, 128, 76, 1);
+        csd->capacity = ((uint64_t)get_bits(raw_csd, 128, 48, 22) + 1) *
+            512 * 1024;
+        dprintf( DEBUG_HDL_SD, " C_SIZE: 0x%08x\n", get_bits(raw_csd,
128, 48, 22) );
+        csd->erase_blk_en = get_bits(raw_csd, 128, 46, 1);
+        csd->erase_sector = get_bits(raw_csd, 128, 39, 7) + 1;
+        csd->wp_grp_size = get_bits(raw_csd, 128, 32, 7);
+        csd->wp_grp_enable = get_bits(raw_csd, 128, 31, 1);
+        csd->r2w_factor = 1 << get_bits(raw_csd, 128, 26, 3);
+        csd->write_bl_len = 1 << get_bits(raw_csd, 128, 22, 4);
+        csd->write_bl_partial = get_bits(raw_csd, 128, 21, 1);
+    } else
+    {
+        dprintf( DEBUG_HDL_SD, "unknown SD CSD version\n");
+    }
+
+    dprintf( DEBUG_HDL_SD, "  READ_BL_LEN: %d\n", csd->read_bl_len );
+
+    dprintf( DEBUG_HDL_SD, "  CAPACITY: 0x%08x%08x\n", (uint32_t)(
csd->capacity >> 32), (uint32_t)(csd->capacity) );
+}
diff --git a/src/hw/sd_utils.h b/src/hw/sd_utils.h
new file mode 100644
index 0000000..56d0d97
--- /dev/null
+++ b/src/hw/sd_utils.h
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2006 Bernd Walter.  All rights reserved.
+ * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
+ * Copyright (C) 2013-2104 Sage Electronic Engineering, LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ */
+
+/*
+ * NOTE:  This is refactored code from FreeBSD modified to be OS agnostic and
+ *           independent for use in bootloading.
+ */
+
+#ifndef __SD_UTILS_H
+#define __SD_UTILS_H
+
+#include <stdint.h>
+
+/* CSD -- decoded structure */
+typedef struct
+{
+    uint32_t mid;
+    char pnm[8];
+    uint32_t psn;
+    uint16_t oid;
+    uint16_t mdt_year;
+    uint8_t mdt_month;
+    uint8_t prv;
+    uint8_t fwrev;
+}sd_cid_t;
+
+typedef struct
+{
+    uint8_t csd_structure;
+    uint8_t spec_vers;
+    uint16_t ccc;
+    uint16_t tacc;
+    uint32_t nsac;
+    uint32_t r2w_factor;
+    uint32_t tran_speed;
+    uint32_t read_bl_len;
+    uint32_t write_bl_len;
+    uint32_t vdd_r_curr_min;
+    uint32_t vdd_r_curr_max;
+    uint32_t vdd_w_curr_min;
+    uint32_t vdd_w_curr_max;
+    uint32_t wp_grp_size;
+    uint32_t erase_sector;
+    uint64_t capacity;
+    unsigned int read_bl_partial:1,
+        read_blk_misalign:1,
+        write_bl_partial:1,
+        write_blk_misalign:1,
+        dsr_imp:1,
+        erase_blk_en:1,
+        wp_grp_enable:1;
+}sd_csd_t;
+
+
+void decode_cid_sd(uint32_t *raw_cid, sd_cid_t* cid);
+void decode_csd_sd(uint32_t *raw_csd, sd_csd_t* csd);
+
+#endif
diff --git a/src/hw/sdhc_generic.c b/src/hw/sdhc_generic.c
new file mode 100644
index 0000000..6c675e1
--- /dev/null
+++ b/src/hw/sdhc_generic.c
@@ -0,0 +1,697 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "string.h"
+#include "malloc.h"
+#include "util.h"
+#include "output.h"
+#include "biosvar.h"
+#include "pci.h"
+#include "pci_ids.h"
+#include "std/disk.h"
+#include "bar.h"
+#include "sdhci.h"
+#include "sd.h"
+#include "sdhc_generic.h"
+
+// host controller functions
+static void sdhc_readResponse( sdHc_t* pSdCtrl, sdXfer_t* pXfer );
+static bool sdhc_pollIntrStatus( sdHc_t* pSdCtrl, sdXfer_t* pXfer,
uint32_t intrNum, uint32_t pollCnt, uint32_t uSecTmo );
+static void sdhc_getVerInfo( sdHc_t* pSdCtrl );
+static void sdhc_setClock( sdHc_t* pSdCtrl, uint32_t clockVal );
+static void sdhc_setPower( sdHc_t* pSdCtrl, uint32_t pwrMode );
+static bool sdhc_reset( sdHc_t* pSdCtrl, uint8_t resetFlags );
+static void sdhc_readBlock( sdHc_t* pSdCtrl, uint8_t* pBuf, uint32_t count );
+
+// callback function for performing command/response transactions
+static bool sdhc_Cmd( sdHc_t* pSdCtrl, sdXfer_t* pXfer );
+
+
+/**
+ * @brief    sdhc_readResponse - helper function to read different
response types
+ *              based on a transfer request
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller
abstraction structure
+ * @param    sdXfer_t* pXfer - pointer to the host style transfer structure
+ *
+ * @return   none
+ */
+static void sdhc_readResponse( sdHc_t* pSdCtrl, sdXfer_t* pXfer )
+{
+    memset( pXfer->response, 0, sizeof( pXfer->response[0] * 4 ) );
+    pXfer->rspValid = false;
+
+    switch( pXfer->rspType )
+    {
+        case eRsp136:
+            pXfer->response[0] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE );
+            pXfer->response[1] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE + 0x04 );
+            pXfer->response[2] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE + 0x08 );
+            pXfer->response[3] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE + 0x0C );
+            pXfer->rspValid = true;
+            break;
+
+        case eRsp48:
+            pXfer->response[0] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE );
+            pXfer->rspValid = true;
+            break;
+
+        case eRsp48_busy:
+            pXfer->response[0] = barRead32(pSdCtrl->barAddress,
SDHCI_RESPONSE + 0x0C );
+            pXfer->rspValid = true;
+            break;
+
+        case eRspNone:
+        default:
+            break;
+    }
+}
+
+/**
+ * @brief    sdhc_pollIntrStatus - interrupt status polling routine
+ *
+ * @param    sdHc_t* pSdCtrll - pointer to the host controller struct
+ * @param    uint32_t intrNum - the requested interrupt number(s) to check
+ * @param    uint32_t pollCnt - the number of iterations to poll
+ * @param    uint32_t uSecTmo - microsecond delay per polling iteration
+ *
+ * @return   bool - true if the requested interrupt was set during this
+ *              request cycle, false otherwise
+ */
+static bool sdhc_pollIntrStatus( sdHc_t* pSdCtrl, sdXfer_t* pXfer,
uint32_t intrNum, uint32_t pollCnt, uint32_t uSecTmo )
+{
+    bool status = false;
+    uint32_t regVal32= 0;
+
+    // check at least once
+    if( !pollCnt )
+    {
+        pollCnt = 1;
+    }
+
+    // check for the interrupt flag
+    while( pollCnt-- )
+    {
+        regVal32 = barRead32(pSdCtrl->barAddress, SDHCI_INT_STATUS );
+        // check that all requested interrupts were set
+        if( ( intrNum & regVal32 ) == intrNum )
+        {
+            // in the case of response to command, save the response
+            if( intrNum == SDHCI_INT_RESPONSE )
+            {
+                sdhc_readResponse( pSdCtrl, pXfer);
+            }
+
+            // clear the interrupt flag(s)
+            // @NOTE: some interrupts will not be cleared by writing them to 0
+            regVal32 &= ~intrNum;
+            barWrite32( pSdCtrl->barAddress, SDHCI_INT_STATUS, regVal32 );
+            status = true;
+            dprintf( DEBUG_HDL_SD, "SD: requested interrupt occured:
%u\n", intrNum );
+            break;
+        }
+        else if( regVal32 & SDHCI_INT_ERROR_MASK )
+        {
+            // notify debug of timeout error
+            if( regVal32 & SDHCI_INT_TIMEOUT )
+            {
+                dprintf( DEBUG_HDL_SD, "SD: ERROR Timeout\n" );
+            }
+            // reset the card on fatal errors
+            else
+            {
+                dprintf( DEBUG_HDL_SD,
+                    "SD: ERROR interrupt occured, clearing interrupt
and resetting card\n" );
+                    sdhc_reset( pSdCtrl, SDHCI_RESET_CMD | SDHCI_RESET_DATA );
+            }
+            barWrite32( pSdCtrl->barAddress, SDHCI_INT_STATUS,
~SDHCI_INT_ERROR_MASK );
+            status = false;
+            break;
+        }
+
+        udelay( uSecTmo );
+    }
+    // in the case of errors, reset the card and clear out the error interrupts
+    dprintf( DEBUG_HDL_SD, "SD: Current interrupt status register:
0x%08x\n", regVal32 );
+
+    return status;
+}
+
+/**
+ * @brief    sdhc_getVerInfo - read the host controller vendor
specific id and host
+ *                 sd specification supported by the controller
+ *
+ * @param    sdHc_t* pSdCtrll - pointer to the host controller struct
+ *
+ * @return   none
+ */
+static void sdhc_getVerInfo( sdHc_t* pSdCtrl )
+{
+    uint16_t regVal16 = 0;
+
+    regVal16 = barRead16( pSdCtrl->barAddress, SDHCI_HOST_VERSION );
+    pSdCtrl->hostVendorId =
+            (uint8_t)( ( regVal16 & SDHCI_VENDOR_VER_MASK ) >>
SDHCI_VENDOR_VER_SHIFT );
+    pSdCtrl->hostSpecId =
+            (uint8_t)( ( regVal16 & SDHCI_SPEC_VER_MASK ) >>
SDHCI_SPEC_VER_SHIFT );
+}
+
+/**
+ * @brief    sdhc_setPower - setup the power state of the host
controller based on its
+ *                 reported capabilities.  The first time this is
called, the power is setup
+ *                 in the highest condition to support all types of
cards.  After card enumeration
+ *                 the voltage can be lowered.
+ *
+ * @param     sdHc_t* pSdCtrll - pointer to the host controller
abstraction structure
+ * @param     uint32_t pwrMode - the requested voltage setting for the power
+ *
+ * @return    none
+ */
+static void sdhc_setPower( sdHc_t* pSdCtrl, uint32_t pwrMode )
+{
+    uint8_t pwr = 0;
+
+    pSdCtrl->pwrMode = pwrMode;
+
+    /* Turn off the POWER. */
+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);
+
+    if (pwrMode == 0)
+        return;
+
+    /* Set voltage. */
+    switch( pwrMode )
+    {
+        case SDHCI_CAN_VDD_180:
+            pwr |= SDHCI_POWER_180;
+            break;
+        case SDHCI_CAN_VDD_300:
+            pwr |= SDHCI_POWER_300;
+            break;
+        case SDHCI_CAN_VDD_330:
+            pwr |= SDHCI_POWER_330;
+            break;
+    }
+
+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);
+    /* Turn on the POWER. */
+    pwr |= SDHCI_POWER_ON;
+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);
+}
+
+/**
+ * @brief    sdhc_setClock - set the clock of the host controller.
This function executes the
+ *                 clock divisor algorithm described in the "SD Host
Controller Simplified
+ *                 Specification Version 3.00" to generate the
highest clock frequency that the
+ *                 card host can handle based on the requested clock.
+ *
+ * @param    sdHc_t* pSdCtrll - pointer to the host controller
abstraction structure
+ * @param    uint32_t clockVal - desired clock frequency
+ *
+ * @return   none.
+ */
+static void sdhc_setClock( sdHc_t* pSdCtrl, uint32_t clockVal )
+{
+    uint32_t res = 0;
+    uint16_t clk = 0;
+    int32_t timeout = 0;
+
+    pSdCtrl->curClk = clockVal;
+
+    // disable the clock
+    barWrite16(pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, 0 );
+
+    // calculate the highest possible frequency <= the maximum clock
frequency reported by the card
+    res = pSdCtrl->maxClk;
+    for (clk = 1; clk < 256; clk <<= 1)
+    {
+        if( res <= clockVal )
+        {
+            break;
+        }
+        res >>= 1;
+    }
+
+    // adjust the Divider, 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ...
+    clk >>= 1;
+    clk <<= SDHCI_DIVIDER_SHIFT;
+    clk |= SDHCI_CLOCK_INT_EN;
+    barWrite16( pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, clk);
+
+    // Wait up to 10 ms until it stabilizes
+    timeout = 10;
+    while( !((clk = barRead16(pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL) )
+            & SDHCI_CLOCK_INT_STABLE) )
+    {
+        if( timeout == 0 )
+        {
+            dprintf( DEBUG_HDL_SD, "SD: card internal clock never
stabilized\n");
+            break;
+        }
+        timeout--;
+        udelay(1000);
+    }
+
+    if( timeout > 0)
+    {
+        // clock is stable so enable the clock signal for the card bus
+        dprintf( DEBUG_HDL_SD, "SD: card internal clock stabilized at
%u Hz\n", pSdCtrl->curClk );
+        clk |= SDHCI_CLOCK_CARD_EN;
+        barWrite16( pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, clk );
+    }
+}
+
+/**
+ * @brief    sdhc_reset - issue the SD reset sequence described in
the SD Host Controller Spec V3.00
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct
+ * @param    uint8_t resetFlags - a logical OR mask of the three
possible reset types:
+ *                                     SDHCI_RESET_ALL - reset entire
host controller
+ *                                     SDHCI_RESET_CMD - reset command circuit
+ *                                     SDHCI_RESET_DATA - reset data
& dma circuit
+ *
+ * @return   bool - true if the request did not timeout, false otherwise
+ */
+static bool sdhc_reset( sdHc_t* pSdCtrl, uint8_t resetFlags )
+{
+    uint8_t resetResult = 0;
+    uint32_t timeout = 0;
+    bool status = false;
+
+    // send the reset command
+    barWrite8( (uint32_t)pSdCtrl->barAddress, SDHCI_SOFTWARE_RESET,
resetFlags );
+
+    // wait for all of the requested reset flags to clear until the
timeout occurs
+    timeout = 10;
+    while( ( resetResult = barRead8( pSdCtrl->barAddress,
SDHCI_SOFTWARE_RESET) & resetFlags ) )
+    {
+        if( timeout == 0 )
+        {
+            dprintf( DEBUG_HDL_SD,
+                    "SDHC Reset Timeout for reset request type:
0x%02x\n", resetFlags );
+        }
+        timeout--;
+        udelay(100);
+    }
+    if( timeout > 0)
+    {
+        dprintf( DEBUG_HDL_SD,
+                    "SDHC Reset Successful for reset request type:
0x%02x\n", resetFlags );
+        status = true;
+    }
+    return status;
+}
+
+/**
+ * @brief    sdhc_Cmd - This is the call-back entry point for the
card bus driver to access
+ *                 the bus via the host controller.  This function
must be registered with the
+ *                 card-bus driver in order for it to be able to
function properly.  It is the
+ *                 entry point for both command and data transfers.
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller abstraction
+ * @param    sdXfer_t* pXfer - pointer to the command/data transfer,
filled out by the
+ *                 card-bus driver.
+ * @return   bool true on success, false otherwise
+ */
+static bool sdhc_Cmd( sdHc_t* pSdCtrl, sdXfer_t* pXfer )
+{
+    uint32_t curState = 0;
+    uint32_t stateMsk = 0;
+    uint8_t regVal8 = 0;
+    uint8_t tmo = 10;
+    uint16_t mode = 0;
+    bool status = false;
+    uint32_t intFlags = 0;
+
+    // setup the state mask for the transfer
+    stateMsk = SDHCI_CMD_INHIBIT;
+    if( pXfer->rspType == eRsp48_busy )
+    {
+        stateMsk |= SDHCI_DAT_INHIBIT;
+    }
+
+    // wait for the state mask to clear
+    while( curState & stateMsk )
+    {
+        if( tmo == 0 )
+        {
+            dprintf( DEBUG_HDL_SD,
+                    "SD: unable to access cmd bus, its always busy\n");
+            break;
+        }
+        tmo--;
+        udelay(1000);
+        curState = barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE );
+    }
+
+    if( tmo > 0 )
+    {
+        //Set command argument
+        barWrite32(pSdCtrl->barAddress, SDHCI_ARGUMENT, pXfer->arg1);
+
+        if( pXfer->pData && pXfer->xferType == eRdXfer )
+        {
+            //Set data transfer mode for reading data
+            mode = barRead16( pSdCtrl->barAddress, SDHCI_TRANSFER_MODE );
+            mode |= ( SDHCI_TRNS_READ );
+            mode &= ~( SDHCI_TRNS_MULTI | SDHCI_TRNS_DMA );
+            barWrite16(pSdCtrl->barAddress, SDHCI_TRANSFER_MODE, mode );
+        }
+        else
+        {
+            //Set data transfer mode for commanding
+            mode = barRead16( pSdCtrl->barAddress, SDHCI_TRANSFER_MODE );
+            mode &= ~( SDHCI_TRNS_READ | SDHCI_TRNS_MULTI | SDHCI_TRNS_DMA );
+            barWrite16(pSdCtrl->barAddress, SDHCI_TRANSFER_MODE, mode );
+        }
+
+        // build the command transaction type
+        regVal8 = (pSdCtrl->crcCheckEnable) ? SDHCI_CMD_CRC : 0;
+        regVal8 |= (pSdCtrl->indexCheckEnable) ? SDHCI_CMD_INDEX : 0;
+        regVal8 |= (pXfer->pData != NULL) ? SDHCI_CMD_DATA : 0;
+        regVal8 |= (uint8_t)(pXfer->cmdType);
+        regVal8 |= (uint8_t)(pXfer->rspType);
+        barWrite8( pSdCtrl->barAddress, SDHCI_COMMAND_FLAGS, regVal8 );
+
+        // initiate the transfer
+        barWrite8(pSdCtrl->barAddress, SDHCI_COMMAND, pXfer->cmdIdx);
+
+        tmo = 10;
+        if( pXfer->rspType != eRspNone )
+        {
+            intFlags = SDHCI_INT_RESPONSE;
+            if( (pXfer->pData) && (pXfer->xferType == eRdXfer) )
+            {
+                // wait for the transfer to be complete in the case
of a read command
+                intFlags |= SDHCI_INT_DATA_AVAIL;
+            }
+
+            while( !sdhc_pollIntrStatus( pSdCtrl, pXfer, intFlags, 100, 1000) )
+            {
+                if( tmo == 0 )
+                {
+                    dprintf( DEBUG_HDL_SD, "SD: failed to receive
response to command\n");
+                    break;
+                }
+                tmo--;
+            }
+
+            // if this is a read block transaction break out here to
get the data
+            if( (pXfer->pData) && (pXfer->xferType == eRdXfer) )
+            {
+                sdhc_readBlock( pSdCtrl, pXfer->pData, BLOCK_SIZE8 );
+            }
+        }
+
+    }
+
+    status = (tmo > 0);
+    return status;
+}
+
+/**
+ * @brief    sdhc_readBlock - read a block from the SD card, this
function is only
+ *                 executed if the data pointer and read flag are set
in the sdhc_Cmd
+ *                 request
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller abstraction
+ * @param    uint8_t* pBuf - buffer to fill in with data (typically a block)
+ * @param    uint32_t count - number of bytes to read in the transaction
+ *
+ * @return   none
+ */
+static void sdhc_readBlock( sdHc_t* pSdCtrl, uint8_t* pBuf, uint32_t count )
+{
+    uint32_t lim = 0;
+    uint32_t dataReg = 0;
+    uint8_t* pBufLocal = NULL;
+
+    pBufLocal = pBuf;
+
+    //lim = min(BLOCK_SIZE8, count);
+    lim = BLOCK_SIZE8;
+
+    // ensure that there is data available
+    //usleep(10000);
+    // @NOTE: This usleep call was to throttle transactions during development,
+    //        it can be commented back in to throttle block read transactions
+    //        while modifying the driver
+    if( barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE ) &
SDHCI_DATA_AVAILABLE )
+    {
+        dprintf( DEBUG_HDL_SD, "SD: reading %d bytes of data\n", lim );
+
+        // calculate the number of 32 bit values to read by
converting the limit to
+        // dwords (additional bytes handled later)
+        lim >>= 2;
+        while( lim > 0 )
+        {
+            dataReg = barRead32(pSdCtrl->barAddress, SDHCI_BUFFER);
+            pBufLocal[0] = (uint8_t)(dataReg);
+            pBufLocal[1] = (uint8_t)(dataReg >> 8);
+            pBufLocal[2] = (uint8_t)(dataReg >> 16);
+            pBufLocal[3] = (uint8_t)(dataReg >> 24);
+            pBufLocal += 4;
+            lim--;
+        }
+
+        // handle the remainder
+        lim = count & 0x03;
+        if( lim > 0 )
+        {
+            dataReg = barRead32(pSdCtrl->barAddress, SDHCI_BUFFER);
+            while( lim > 0 )
+            {
+                *(pBufLocal++) = (uint8_t)dataReg;
+                dataReg >>= 8;
+                lim--;
+            }
+        }
+    }
+#if( CONFIG_DEBUG_LEVEL > 9 )
+    hexdump( pBuf, BLOCK_SIZE8 );
+#endif
+
+}
+
+/**
+ * @brief    sdhc_prepBoot - post initialization function to perform changes
+ *                 to the operating mode of the card prior to boot, and to
+ *                 take it out of enumeration mode.
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct
+ *
+ * @return   none
+ */
+void sdhc_prepBoot( sdHc_t* pSdCtrl )
+{
+    // boost the clock speed for boot
+    //@TODO:  should check if this speed is supported first, (most
newer cards do)
+    sdhc_setClock( pSdCtrl, 25 * MHZ );
+
+    //@TODO: do other changes to card operating mode here
+}
+
+/**
+ * @brief   sdhc_isInitialized - check to see if the host controller
is initialized
+ *
+ * @param   sdHc_t* pSdCtrl - pointerto the host controller sturcture
+ *
+ * @return  bool true if host initialized, false otherwise
+ */
+bool sdhc_isInitialized( sdHc_t* pSdCtrl )
+{
+    return pSdCtrl->isInitialized;
+}
+
+/**
+ * @brief    sdhc_init - performs the minimum necessary steps
outlined in the SD
+ *                 host controller specification to prepare the sd card/host
+ *                 controller for use
+ *
+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct
+ *
+ * @return   bool true if reset succeeded, false otherwise
+ */
+bool sdhc_init( sdHc_t* pSdCtrl )
+{
+    uint32_t regVal32 = 0;
+    uint8_t regVal8 = 0;
+
+    // reset the the host controller
+    if( sdhc_reset( pSdCtrl, SDHCI_RESET_ALL ) )
+    {
+        // read the capabilities register
+        pSdCtrl->cardCapabilities.cap1 =
+                barRead32( pSdCtrl->barAddress, SDHCI_CAPABILITIES );
+        pSdCtrl->cardCapabilities.cap2 =
+                barRead32( pSdCtrl->barAddress, (SDHCI_CAPABILITIES + 4) );
+
+        regVal8 = barRead8(pSdCtrl->barAddress, SDHCI_HOST_CONTROL );
+        dprintf( DEBUG_HDL_SD, "SD: Host Control register: 0x%02x\n",
regVal8 );
+
+        // check the power
+        regVal8 = barRead8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL );
+        if( !(regVal8 & SDHCI_POWER_ON) )
+        {
+            dprintf( DEBUG_HDL_SD, "SD: card currently not powered,
power on to");
+            // setup the power for the card
+            if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_330 )
+            {
+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_330 );
+                dprintf( DEBUG_HDL_SD, ": 3.3V\n");
+            }
+            else if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_300 )
+            {
+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_300 );
+                dprintf( DEBUG_HDL_SD, ": 3.0V\n");
+            }
+            else if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_180 )
+            {
+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_180 );
+                dprintf( DEBUG_HDL_SD, ": 1.8V\n");
+            }
+        }
+        else
+        {
+            dprintf(6, "SD: card bus is powered on\n");
+        }
+
+        // determine the base clock frequency reported by the card
+        pSdCtrl->maxClk =
+                (pSdCtrl->cardCapabilities.cap1 & SDHCI_CLOCK_BASE_MASK)
+                >> SDHCI_CLOCK_BASE_SHIFT;
+        if( pSdCtrl->maxClk == 0 )
+        {
+            dprintf( DEBUG_HDL_SD,
+                    "SD: no base clock frequency specified by card
capabilities\n");
+
+            // @TODO:  If the clock was not set, need to set it ?
+        }
+        else
+        {
+            pSdCtrl->maxClk *= MHZ;
+            dprintf( DEBUG_HDL_SD, "SD: base clock frequency %u
Hz\n", pSdCtrl->maxClk );
+        }
+
+        // setup the cards internal clock to always be normal speed
mode to blanket support all card types
+        // the sd spec defines normal speed mode as 25MHz, and
enumeration at 400KHz
+        sdhc_setClock( pSdCtrl, 400000 );
+
+        // determine the base timeout frequency
+        pSdCtrl->tmoClk = (pSdCtrl->cardCapabilities.cap1 &
SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+        if( pSdCtrl->tmoClk == 0 )
+        {
+            dprintf( DEBUG_HDL_SD, "SD: no timeout clock frequency
specified by card capabilities\n");
+        }
+        else
+        {
+            // if the units are specified in MHz adjust the frequency
to reflect that
+            pSdCtrl->tmoClk =
+                    (pSdCtrl->cardCapabilities.cap1 & SDHCI_TIMEOUT_CLK_UNIT)
+                    ? pSdCtrl->tmoClk * MHZ : pSdCtrl->tmoClk * KHZ;
+            dprintf( DEBUG_HDL_SD, "SD: timeout frequency clock
%u\n", pSdCtrl->tmoClk );
+
+            // test max timeout
+            barWrite8( pSdCtrl->barAddress, SDHCI_TIMEOUT_CONTROL, 0x0E );
+        }
+
+        // the "always supported" block size is 512, so force it
+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_BLOCK_SIZE );
+
+        // mask off the block bits
+        pSdCtrl->blkSize &= BLOCK_MASK;
+        if( pSdCtrl->blkSize == 0 )
+        {
+            dprintf( DEBUG_HDL_SD, "SD: no block size set...\n");
+        }
+        else
+        {
+            dprintf( DEBUG_HDL_SD, "SD: current block size: %u\n",
pSdCtrl->blkSize );
+        }
+
+        // if necessary set the block size to the default
+        if( pSdCtrl->blkSize != BLOCK_SIZE8 )
+        {
+            pSdCtrl->blkSize = BLOCK_SIZE8;
+            dprintf( DEBUG_HDL_SD, "  - setting new block size to 512
bytes\n");
+
+            // clear the current block size bits
+            regVal32 &= ~BLOCK_MASK;
+            regVal32 |= pSdCtrl->blkSize;
+            barWrite32( pSdCtrl->barAddress, SDHCI_BLOCK_SIZE, regVal32 );
+
+            // check that the new value was written
+            regVal32 = barRead32( pSdCtrl->barAddress,
SDHCI_BLOCK_SIZE ) & BLOCK_MASK;
+            if( regVal32 != BLOCK_SIZE8 )
+            {
+                dprintf( DEBUG_HDL_SD, "  - set new block size failed!");
+                //@TODO: Probably should fail now?
+            }
+            else
+            {
+                dprintf( DEBUG_HDL_SD, "  - new block size set to:
%u\n", pSdCtrl->blkSize );
+            }
+        }
+
+        // test reset after config
+        sdhc_reset( pSdCtrl, SDHCI_RESET_CMD | SDHCI_RESET_DATA );
+
+        // setup the interrupts
+        barWrite32( pSdCtrl->barAddress, SDHCI_INT_ENABLE,
SDHCI_INT_BUS_POWER |
+        SDHCI_INT_DATA_END_BIT |
+        SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
+        SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
+        SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
+        SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
+        SDHCI_INT_ACMD12ERR );
+
+        // and signals
+        barWrite32( pSdCtrl->barAddress, SDHCI_SIGNAL_ENABLE,
SDHCI_INT_BUS_POWER |
+        SDHCI_INT_DATA_END_BIT |
+        SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
+        SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
+        SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
+        SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
+        SDHCI_INT_ACMD12ERR );
+
+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_INT_ENABLE );
+        dprintf(6, "SD: interrupts enabled to: 0x%08x\n", regVal32 );
+
+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_INT_STATUS );
+        dprintf(6, "SD: Current interrupt status: 0x%08x\n", regVal32 );
+
+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE );
+        dprintf(6, "SD: Present State: 0x%08x\n", regVal32 );
+
+        // record the vendor and sd spec info of the host controller
+        sdhc_getVerInfo( pSdCtrl );
+
+        // setup the callback(s) for the underlying card bus
+        pSdCtrl->sdhcCmd = &sdhc_Cmd;
+
+        pSdCtrl->isInitialized = true;
+    }
+    return( pSdCtrl->isInitialized );
+}
diff --git a/src/hw/sdhc_generic.h b/src/hw/sdhc_generic.h
new file mode 100644
index 0000000..4797cc6
--- /dev/null
+++ b/src/hw/sdhc_generic.h
@@ -0,0 +1,41 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __SDHC_GENERIC_H
+#define __SDHC_GENERIC_H
+
+/** @file sdhc_generic.h */
+/*
+ * @brief SD PCI host controller driver header file.  This driver is intended
+ *           to be a generic driver for use with booting from SD cards. It
+ *           only supports the minimum controls necessary to boot.
+ */
+#include <stdint.h>
+#include "block.h"
+#include "config.h"
+#include "sd.h"
+
+
+bool sdhc_init( sdHc_t* pSdCtrl );
+void sdhc_prepBoot( sdHc_t* pSdCtrl );
+bool sdhc_isInitialized( sdHc_t* pSdCtrl );
+
+#endif /* __SDHC_GENERIC_H */
diff --git a/src/hw/sdhci.h b/src/hw/sdhci.h
new file mode 100644
index 0000000..93ecd67
--- /dev/null
+++ b/src/hw/sdhci.h
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2008 Alexander Motin <mav at FreeBSD.org>
+ * Copyright (C) 2013-2014 Sage Electronic Engineering, LLC
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * NOTE:  This is from FreeBSD
+ */
+/*
+ * PCI registers
+ */
+
+
+
+
+#define PCI_SDHCI_IFPIO            0x00
+#define PCI_SDHCI_IFDMA            0x01
+#define PCI_SDHCI_IFVENDOR        0x02
+
+#define PCI_SLOT_INFO            0x40    /* 8 bits */
+#define  PCI_SLOT_INFO_SLOTS(x)        (((x >> 4) & 7) + 1)
+#define  PCI_SLOT_INFO_FIRST_BAR(x)    ((x) & 7)
+
+/*
+ * RICOH specific PCI registers
+ */
+#define    SDHC_PCI_MODE_KEY        0xf9
+#define    SDHC_PCI_MODE            0x150
+#define    SDHC_PCI_MODE_SD20        0x10
+#define    SDHC_PCI_BASE_FREQ_KEY        0xfc
+#define    SDHC_PCI_BASE_FREQ        0xe1
+
+/*
+ * Controller registers
+ */
+
+#define SDHCI_DMA_ADDRESS    0x00
+
+#define SDHCI_BLOCK_SIZE    0x04
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
+
+#define SDHCI_BLOCK_COUNT    0x06
+
+#define SDHCI_ARGUMENT        0x08
+
+#define SDHCI_TRANSFER_MODE    0x0C
+#define  SDHCI_TRNS_DMA        0x01
+#define  SDHCI_TRNS_BLK_CNT_EN    0x02
+#define  SDHCI_TRNS_ACMD12    0x04
+#define  SDHCI_TRNS_READ    0x10
+#define  SDHCI_TRNS_MULTI    0x20
+
+#define SDHCI_COMMAND_FLAGS    0x0E
+#define  SDHCI_CMD_RESP_NONE    0x00
+#define  SDHCI_CMD_RESP_LONG    0x01
+#define  SDHCI_CMD_RESP_SHORT    0x02
+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03
+#define  SDHCI_CMD_RESP_MASK    0x03
+#define  SDHCI_CMD_CRC        0x08
+#define  SDHCI_CMD_INDEX    0x10
+#define  SDHCI_CMD_DATA        0x20
+#define  SDHCI_CMD_TYPE_NORMAL    0x00
+#define  SDHCI_CMD_TYPE_SUSPEND    0x40
+#define  SDHCI_CMD_TYPE_RESUME    0x80
+#define  SDHCI_CMD_TYPE_ABORT    0xc0
+#define  SDHCI_CMD_TYPE_MASK    0xc0
+
+#define SDHCI_COMMAND        0x0F
+
+#define SDHCI_RESPONSE        0x10
+
+#define SDHCI_BUFFER        0x20
+
+#define SDHCI_PRESENT_STATE    0x24
+#define  SDHCI_CMD_INHIBIT    0x00000001
+#define  SDHCI_DAT_INHIBIT    0x00000002
+#define  SDHCI_DAT_ACTIVE    0x00000004
+#define  SDHCI_DOING_WRITE    0x00000100
+#define  SDHCI_DOING_READ    0x00000200
+#define  SDHCI_SPACE_AVAILABLE    0x00000400
+#define  SDHCI_DATA_AVAILABLE    0x00000800
+#define  SDHCI_CARD_PRESENT    0x00010000
+#define  SDHCI_CARD_STABLE    0x00020000
+#define  SDHCI_CARD_PIN        0x00040000
+#define  SDHCI_WRITE_PROTECT    0x00080000
+#define  SDHCI_STATE_DAT    0x00700000
+#define  SDHCI_STATE_CMD    0x00800000
+
+#define SDHCI_HOST_CONTROL     0x28
+#define  SDHCI_CTRL_LED        0x01
+#define  SDHCI_CTRL_4BITBUS    0x02
+#define  SDHCI_CTRL_HISPD    0x04
+#define  SDHCI_CTRL_SDMA    0x08
+#define  SDHCI_CTRL_ADMA2    0x10
+#define  SDHCI_CTRL_ADMA264    0x18
+#define  SDHCI_CTRL_CARD_DET    0x40
+#define  SDHCI_CTRL_FORCE_CARD    0x80
+
+#define SDHCI_POWER_CONTROL    0x29
+#define  SDHCI_POWER_ON        0x01
+#define  SDHCI_POWER_180    0x0A
+#define  SDHCI_POWER_300    0x0C
+#define  SDHCI_POWER_330    0x0E
+
+#define SDHCI_BLOCK_GAP_CONTROL    0x2A
+
+#define SDHCI_WAKE_UP_CONTROL    0x2B
+
+
+#define SDHCI_CLOCK_CONTROL    0x2C
+#define  SDHCI_DIVIDER_SHIFT    8
+#define  SDHCI_CLOCK_CARD_EN    0x0004
+#define  SDHCI_CLOCK_INT_STABLE    0x0002
+#define  SDHCI_CLOCK_INT_EN    0x0001
+
+#define SDHCI_TIMEOUT_CONTROL    0x2E
+
+#define SDHCI_SOFTWARE_RESET    0x2F
+#define  SDHCI_RESET_ALL    0x01
+#define  SDHCI_RESET_CMD    0x02
+#define  SDHCI_RESET_DATA    0x04
+
+#define SDHCI_INT_STATUS    0x30
+#define SDHCI_INT_ENABLE    0x34
+#define SDHCI_SIGNAL_ENABLE    0x38
+#define  SDHCI_INT_RESPONSE    0x00000001
+#define  SDHCI_INT_DATA_END    0x00000002
+#define  SDHCI_INT_BLOCK_GAP    0x00000004
+#define  SDHCI_INT_DMA_END    0x00000008
+#define  SDHCI_INT_SPACE_AVAIL    0x00000010
+#define  SDHCI_INT_DATA_AVAIL    0x00000020
+#define  SDHCI_INT_CARD_INSERT    0x00000040
+#define  SDHCI_INT_CARD_REMOVE    0x00000080
+#define  SDHCI_INT_CARD_INT    0x00000100
+#define  SDHCI_INT_ERROR    0x00008000
+#define  SDHCI_INT_TIMEOUT    0x00010000
+#define  SDHCI_INT_CRC        0x00020000
+#define  SDHCI_INT_END_BIT    0x00040000
+#define  SDHCI_INT_INDEX    0x00080000
+#define  SDHCI_INT_DATA_TIMEOUT    0x00100000
+#define  SDHCI_INT_DATA_CRC    0x00200000
+#define  SDHCI_INT_DATA_END_BIT    0x00400000
+#define  SDHCI_INT_BUS_POWER    0x00800000
+#define  SDHCI_INT_ACMD12ERR    0x01000000
+#define  SDHCI_INT_ADMAERR    0x02000000
+
+#define  SDHCI_INT_NORMAL_MASK    0x00007FFF
+#define  SDHCI_INT_ERROR_MASK    0xFFFF8000
+
+#define  SDHCI_INT_CMD_MASK    (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
+        SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
+#define  SDHCI_INT_DATA_MASK    (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
+        SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
+        SDHCI_INT_DATA_END_BIT)
+
+#define SDHCI_ACMD12_ERR    0x3C
+
+#define SDHCI_CAPABILITIES    0x40
+#define  SDHCI_TIMEOUT_CLK_MASK    0x0000003F
+#define  SDHCI_TIMEOUT_CLK_SHIFT 0
+#define  SDHCI_TIMEOUT_CLK_UNIT    0x00000080
+#define  SDHCI_CLOCK_BASE_MASK    0x00003F00
+#define  SDHCI_CLOCK_BASE_SHIFT    8
+#define  SDHCI_MAX_BLOCK_MASK    0x00030000
+#define  SDHCI_MAX_BLOCK_SHIFT  16
+#define  SDHCI_CAN_DO_ADMA2    0x00080000
+#define  SDHCI_CAN_DO_HISPD    0x00200000
+#define  SDHCI_CAN_DO_DMA    0x00400000
+#define  SDHCI_CAN_DO_SUSPEND    0x00800000
+#define  SDHCI_CAN_VDD_330    0x01000000
+#define  SDHCI_CAN_VDD_300    0x02000000
+#define  SDHCI_CAN_VDD_180    0x04000000
+#define  SDHCI_CAN_DO_64BIT    0x10000000
+
+#define SDHCI_MAX_CURRENT    0x48
+
+#define SDHCI_SLOT_INT_STATUS    0xFC
+
+#define SDHCI_HOST_VERSION    0xFE
+#define  SDHCI_VENDOR_VER_MASK    0xFF00
+#define  SDHCI_VENDOR_VER_SHIFT    8
+#define  SDHCI_SPEC_VER_MASK    0x00FF
+#define  SDHCI_SPEC_VER_SHIFT    0
diff --git a/src/post.c b/src/post.c
index 0fdd28e..556ff47 100644
--- a/src/post.c
+++ b/src/post.c
@@ -2,6 +2,7 @@
 //
 // Copyright (C) 2008-2013  Kevin O'Connor <kevin at koconnor.net>
 // Copyright (C) 2002  MandrakeSoft S.A.
+// Copyright (C) 2013-2014 Sage Electronic Engineering, LLC
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.

@@ -14,6 +15,7 @@
 #include "hw/ata.h" // ata_setup
 #include "hw/esp-scsi.h" // esp_scsi_setup
 #include "hw/lsi-scsi.h" // lsi_scsi_setup
+#include "hw/sd_if.h" // sd_setup
 #include "hw/megasas.h" // megasas_setup
 #include "hw/pvscsi.h" // pvscsi_setup
 #include "hw/pic.h" // pic_setup
@@ -143,6 +145,7 @@ device_hardware_setup(void)
     floppy_setup();
     ata_setup();
     ahci_setup();
+    sd_setup();
     cbfs_payload_setup();
     ramdisk_setup();
     virtio_blk_setup();
diff --git a/src/stdbool.h b/src/stdbool.h
new file mode 100644
index 0000000..71f75b0
--- /dev/null
+++ b/src/stdbool.h
@@ -0,0 +1,29 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __SEABIOS_STDBOOL_H
+#define __SEABIOS_STDBOOL_H
+
+typedef int bool;
+#define true 1
+#define false 0
+
+#endif /* __SEABIOS_STDBOOL_H */
diff --git a/src/stdint.h b/src/stdint.h
new file mode 100644
index 0000000..276119b
--- /dev/null
+++ b/src/stdint.h
@@ -0,0 +1,41 @@
+ /*****************************************************************************
+ *
+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.
+ *
+ * Software License Agreement
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *****************************************************************************/
+
+#ifndef __SEABIOS_STDINT_H
+#define __SEABIOS_STDINT_H
+
+#include "types.h"
+
+/* minimal stdint types for seabios non-specific portability */
+
+typedef u8       uint8_t;
+typedef s8       int8_t;
+
+typedef u16      uint16_t;
+typedef s16      int16_t;
+
+typedef u32      uint32_t;
+typedef s32      int32_t;
+
+typedef u64      uint64_t;
+typedef s64      int64_t;
+
+#endif /* __SEABIOS_STDINT_H */
-- 
1.9.1



More information about the SeaBIOS mailing list