VirtualBox

Changeset 81250 in vbox for trunk


Ignore:
Timestamp:
Oct 14, 2019 11:41:24 AM (5 years ago)
Author:
vboxsync
Message:

Devices/EFI: Split the flash device emulation out of DevFlash so it can be embedded into other device emulations, bugref:6940

Location:
trunk/src/VBox/Devices
Files:
2 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/EFI/DevFlash.cpp

    r80704 r81250  
    3535
    3636#include "VBoxDD.h"
     37#include "FlashCore.h"
    3738
    3839
     
    4041*   Defined Constants And Macros                                                                                                 *
    4142*********************************************************************************************************************************/
    42 /** The current version of the saved state. */
    43 #define FLASH_SAVED_STATE_VERSION           1
    44 
    45 
    46 /** @name CUI (Command User Interface) Commands.
    47  *  @{ */
    48 #define FLASH_CMD_ALT_WRITE             0x10
    49 #define FLASH_CMD_ERASE_SETUP           0x20
    50 #define FLASH_CMD_WRITE                 0x40
    51 #define FLASH_CMD_STS_CLEAR             0x50
    52 #define FLASH_CMD_STS_READ              0x70
    53 #define FLASH_CMD_READ_ID               0x90
    54 #define FLASH_CMD_ERASE_SUS_RES         0xB0
    55 #define FLASH_CMD_ERASE_CONFIRM         0xD0
    56 #define FLASH_CMD_ARRAY_READ            0xFF
    57 /** @} */
    58 
    59 /** @name Status register bits.
    60  *  @{ */
    61 #define FLASH_STATUS_WSMS               0x80    /* Write State Machine Status, 1=Ready */
    62 #define FLASH_STATUS_ESS                0x40    /* Erase Suspend Status, 1=Suspended */
    63 #define FLASH_STATUS_ES                 0x20    /* Erase Status, 1=Error */
    64 #define FLASH_STATUS_BWS                0x10    /* Byte Write Status, 1=Error */
    65 #define FLASH_STATUS_VPPS               0x08    /* Vpp Status, 1=Low Vpp */
    66 /* The remaining bits 0-2 are reserved/unused */
    67 /** @} */
    6843
    6944
     
    7651typedef struct DEVFLASH
    7752{
    78     /** The current command. */
    79     uint8_t             bCmd;
    80     /** The status register. */
    81     uint8_t             bStatus;
    82     /** Current bus cycle. */
    83     uint8_t             cBusCycle;
    84 
    85     uint8_t             uPadding0;
    86 
    87     /* The following state does not change at runtime.*/
    88     /** Manufacturer (high byte) and device (low byte) ID. */
    89     uint16_t            u16FlashId;
    90     /** The configured block size of the device. */
    91     uint16_t            cbBlockSize;
     53    /** The flash core device instance.*/
     54    FLASHCORE           Core;
    9255    /** The guest physical memory base address. */
    9356    RTGCPHYS            GCPhysFlashBase;
    94     /** The flash memory region size.  */
    95     uint32_t            cbFlashSize;
    96     /** The actual flash memory data.  */
    97     uint8_t             *pbFlash;
    9857    /** When set, indicates the state was saved. */
    9958    bool                fStateSaved;
    100     /** The backing file. */
    101     RTFILE              hFlashFile;
     59    /** The file conaining the flash content. */
    10260    char                *pszFlashFile;
    10361} DEVFLASH;
     
    11169#ifdef IN_RING3 /* for now */
    11270
    113 static int flashMemWriteByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t bCmd)
    114 {
    115     int rc = VINF_SUCCESS;
    116     unsigned uOffset;
    117 
    118     /* NB: Older datasheets (e.g. 28F008SA) suggest that for two-cycle commands like byte write or
    119      * erase setup, the address is significant in both cycles, but do not explain what happens
    120      * should the addresses not match. Newer datasheets (e.g. 28F008B3) clearly say that the address
    121      * in the first byte cycle never matters. We prefer the latter interpretation.
    122      */
    123 
    124     if (pThis->cBusCycle == 0)
    125     {
    126         /* First bus write cycle, start processing a new command. Address is ignored. */
    127         switch (bCmd)
    128         {
    129         case FLASH_CMD_ARRAY_READ:
    130         case FLASH_CMD_STS_READ:
    131         case FLASH_CMD_ERASE_SUS_RES:
    132         case FLASH_CMD_READ_ID:
    133             /* Single-cycle write commands, only change the current command. */
    134             pThis->bCmd = bCmd;
    135             break;
    136         case FLASH_CMD_STS_CLEAR:
    137             /* Status clear continues in read mode. */
    138             pThis->bStatus = 0;
    139             pThis->bCmd = FLASH_CMD_ARRAY_READ;
    140             break;
    141         case FLASH_CMD_WRITE:
    142         case FLASH_CMD_ALT_WRITE:
    143         case FLASH_CMD_ERASE_SETUP:
    144             /* Two-cycle commands, advance the bus write cycle. */
    145             pThis->bCmd = bCmd;
    146             pThis->cBusCycle++;
    147             break;
    148         default:
    149             LogFunc(("1st cycle command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    150             break;
    151         }
    152     }
    153     else
    154     {
    155         /* Second write of a two-cycle command. */
    156         Assert(pThis->cBusCycle == 1);
    157         switch (pThis->bCmd)
    158         {
    159         case FLASH_CMD_WRITE:
    160         case FLASH_CMD_ALT_WRITE:
    161             uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    162             if (uOffset < pThis->cbFlashSize)
    163             {
    164                 pThis->pbFlash[uOffset] = bCmd;
    165                 /* NB: Writes are instant and never fail. */
    166                 LogFunc(("wrote byte to flash at %08RGp: %02X\n", GCPhysAddr, bCmd));
    167             }
    168             else
    169                 LogFunc(("ignoring write at %08RGp: %02X\n", GCPhysAddr, bCmd));
    170             break;
    171         case FLASH_CMD_ERASE_SETUP:
    172             if (bCmd == FLASH_CMD_ERASE_CONFIRM)
    173             {
    174                 /* The current address determines the block to erase. */
    175                 uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    176                 uOffset = uOffset & ~(pThis->cbBlockSize - 1);
    177                 memset(pThis->pbFlash + uOffset, 0xff, pThis->cbBlockSize);
    178                 LogFunc(("Erasing block at offset %u\n", uOffset));
    179             }
    180             else
    181             {
    182                 /* Anything else is a command erorr. Transition to status read mode. */
    183                 LogFunc(("2st cycle erase command is %02X, should be confirm (%02X)\n", bCmd, FLASH_CMD_ERASE_CONFIRM));
    184                 pThis->bCmd = FLASH_CMD_STS_READ;
    185                 pThis->bStatus |= FLASH_STATUS_BWS | FLASH_STATUS_ES;
    186             }
    187             break;
    188         default:
    189             LogFunc(("2st cycle bad command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    190             break;
    191         }
    192         pThis->cBusCycle = 0;
    193     }
    194     LogFlow(("flashMemWriteByte: write access at %08RGp: %#x rc=%Rrc\n", GCPhysAddr, bCmd, rc));
    195 //LogRel(("flashMemWriteByte: write access at %08RGp: %#x (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bCmd, pThis->bCmd, rc));
    196     return rc;
    197 }
    198 
    199 
    200 static int flashMemReadByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t *pbData)
    201 {
    202     uint8_t bValue;
    203     unsigned uOffset;
    204     int rc = VINF_SUCCESS;
    205 
    206     /* Reads are only defined in three states: Array read, status register read,
    207      * and ID read.
    208      */
    209     switch (pThis->bCmd)
    210     {
    211     case FLASH_CMD_ARRAY_READ:
    212         uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    213         bValue = pThis->pbFlash[uOffset];
    214         LogFunc(("read byte at %08RGp: %02X\n", GCPhysAddr, bValue));
    215         break;
    216     case FLASH_CMD_STS_READ:
    217         bValue = pThis->bStatus;
    218         break;
    219     case FLASH_CMD_READ_ID:
    220         bValue = GCPhysAddr & 1 ?  RT_HI_U8(pThis->u16FlashId) : RT_LO_U8(pThis->u16FlashId);
    221         break;
    222     default:
    223         bValue = 0xff;
    224         break;
    225     }
    226     *pbData = bValue;
    227 
    228     LogFlow(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    229 //LogRel(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    230     return rc;
    231 }
    232 
    23371/** @callback_method_impl{FNIOMMIWRITE, Flash memory write} */
    23472PDMBOTHCBDECL(int) flashMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
    23573{
    23674    PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    237     int rc = VINF_SUCCESS;
    238     const uint8_t *pu8Mem = (const uint8_t *)pv;
    239     unsigned uOffset;
    24075    RT_NOREF1(pvUser);
    24176
    242     /* Writes may need to go back to R3. If more than one byte is being written (not likely!),
    243      * just suck it up and take the trip to R3 immediately.
    244      */
    245     /** @todo Idea: We could buffer all writes in R0 and flush them out on a
    246      *        timer. Probably not worth it.
    247      */
    248 #ifndef IN_RING3
    249     if (cb > 1)
    250         return VINF_IOM_R3_IOPORT_WRITE;
    251 #endif
    252 
    253     for (uOffset = 0; uOffset < cb; ++uOffset)
    254     {
    255         rc = flashMemWriteByte(pThis, GCPhysAddr + uOffset, pu8Mem[uOffset]);
    256         if (!RT_SUCCESS(rc))
    257             break;
    258     }
    259 
    260     LogFlow(("FlashMMIOWrite: completed write at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
    261     return rc;
     77    return flashWrite(&pThis->Core, GCPhysAddr - pThis->GCPhysFlashBase, pv, cb);
    26278}
    26379
     
    26783{
    26884    PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    269     int rc = VINF_SUCCESS;
    270     unsigned uOffset;
    271     uint8_t *pu8Mem;
    27285    RT_NOREF1(pvUser);
    27386
    274     /* Reading can always be done witout going back to R3. Reads do not
    275      * change the device state and we always have the data.
    276      */
    277     pu8Mem = (uint8_t *)pv;
    278     for (uOffset = 0; uOffset < cb; ++uOffset, ++pu8Mem)
    279     {
    280         rc = flashMemReadByte(pThis, GCPhysAddr + uOffset, pu8Mem);
    281         if (!RT_SUCCESS(rc))
    282             break;
    283     }
    284 
    285     LogFlow(("flashMMIORead: completed read at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
    286     return rc;
     87    return flashRead(&pThis->Core, GCPhysAddr - pThis->GCPhysFlashBase, pv, cb);
    28788}
    28889
     
    29697    PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    29798
    298     /* Save the device state. */
    299     SSMR3PutU8(pSSM, pThis->bCmd);
    300     SSMR3PutU8(pSSM, pThis->bStatus);
    301     SSMR3PutU8(pSSM, pThis->cBusCycle);
    302 
    303     /* Save the current configuration for validation purposes. */
    304     SSMR3PutU16(pSSM, pThis->cbBlockSize);
    305     SSMR3PutU16(pSSM, pThis->u16FlashId);
    306 
    307     /* Save the current flash contents. */
    308     SSMR3PutU32(pSSM, pThis->cbFlashSize);
    309     SSMR3PutMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    310 
    311     pThis->fStateSaved = true;
    312 
    313     return VINF_SUCCESS;
     99    int rc = flashR3SsmSaveExec(&pThis->Core, pSSM);
     100    if (RT_SUCCESS(rc))
     101        pThis->fStateSaved = true;
     102
     103    return rc;
    314104}
    315105
     
    325115        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    326116
    327     /*
    328      * Do the actual restoring.
    329      */
    330     if (uVersion == FLASH_SAVED_STATE_VERSION)
    331     {
    332         uint16_t    u16Val;
    333         uint32_t    u32Val;
    334 
    335         SSMR3GetU8(pSSM, &pThis->bCmd);
    336         SSMR3GetU8(pSSM, &pThis->bStatus);
    337         SSMR3GetU8(pSSM, &pThis->cBusCycle);
    338 
    339         /* Make sure configuration didn't change behind our back. */
    340         SSMR3GetU16(pSSM, &u16Val);
    341         if (u16Val != pThis->cbBlockSize)
    342             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    343         SSMR3GetU16(pSSM, &u16Val);
    344         if (u16Val != pThis->u16FlashId)
    345             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    346         SSMR3GetU32(pSSM, &u32Val);
    347         if (u16Val != pThis->cbFlashSize)
    348             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    349 
    350         /* Suck in the flash contents. */
    351         SSMR3GetMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    352     }
    353 
    354     return VINF_SUCCESS;
     117    return flashR3SsmLoadExec(&pThis->Core, pSSM);
    355118}
    356119
     
    362125    PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    363126
    364     /*
    365      * Initialize the device state.
    366      */
    367     pThis->bCmd      = FLASH_CMD_ARRAY_READ;
    368     pThis->bStatus   = 0;
    369     pThis->cBusCycle = 0;
     127    flashR3Reset(&pThis->Core);
    370128}
    371129
     
    380138    if (!pThis->fStateSaved)
    381139    {
    382         rc = RTFileSeek(pThis->hFlashFile, 0, RTFILE_SEEK_BEGIN, NULL);
    383         rc = RTFileWrite(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
     140        rc = flashR3SaveToFile(&pThis->Core, pThis->pszFlashFile);
    384141        if (RT_FAILURE(rc))
    385             LogRel(("flash: Failed to save flash file"));
    386     }
    387 
    388     if (pThis->pbFlash)
    389     {
    390         PDMDevHlpMMHeapFree(pDevIns, pThis->pbFlash);
    391         pThis->pbFlash = NULL;
     142            LogRel(("Flash: Failed to save flash file"));
    392143    }
    393144
     
    398149    }
    399150
     151    flashR3Destruct(&pThis->Core);
    400152    return VINF_SUCCESS;
    401153}
    402 
    403 /** @todo this does not really belong here; workaround for EFI failing to init empty flash. */
    404 static const uint8_t aHdrBegin[] = {
    405     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    406     0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
    407     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x46, 0x56, 0x48, 0xFF, 0xFE, 0x04, 0x00,
    408     0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    409     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x36, 0xCF, 0xDD, 0x75, 0x32, 0x64, 0x41,
    410     0x98, 0xB6, 0xFE, 0x85, 0x70, 0x7F, 0xFE, 0x7D, 0xB8, 0xDF, 0x00, 0x00, 0x5A, 0xFE, 0x00, 0x00,
    411     0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
    412 };
    413154
    414155/**
     
    432173
    433174    /* The default device ID is Intel 28F800SA. */
    434     int rc = CFGMR3QueryU16Def(pCfg, "DeviceId", &pThis->u16FlashId, 0xA289);
     175    uint16_t u16FlashId = 0;
     176    int rc = CFGMR3QueryU16Def(pCfg, "DeviceId", &u16FlashId, 0xA289);
    435177    if (RT_FAILURE(rc))
    436178        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    444186
    445187    /* The default flash device size is 128K. */
    446     rc = CFGMR3QueryU32Def(pCfg, "Size", &pThis->cbFlashSize, 128 * _1K);
     188    uint32_t cbFlash = 0;
     189    rc = CFGMR3QueryU32Def(pCfg, "Size", &cbFlash, 128 * _1K);
    447190    if (RT_FAILURE(rc))
    448191        return PDMDEV_SET_ERROR(pDevIns, rc,
     
    450193
    451194    /* The default flash device block size is 4K. */
    452     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
     195    uint16_t cbBlock = 0;
     196    rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &cbBlock, _4K);
    453197    if (RT_FAILURE(rc))
    454198        return PDMDEV_SET_ERROR(pDevIns, rc,
    455199                                N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    456200
    457     /* The default flash device block size is 4K. */
    458     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
    459     if (RT_FAILURE(rc))
    460         return PDMDEV_SET_ERROR(pDevIns, rc,
    461                                 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    462 
    463201    rc = CFGMR3QueryStringAlloc(pCfg, "FlashFile", &pThis->pszFlashFile);
    464202    if (RT_FAILURE(rc))
     
    466204                                N_("Configuration error: Querying \"FlashFile\" as a string failed"));
    467205
    468     /* Try opening the backing file. */
    469     rc = RTFileOpen(&pThis->hFlashFile, pThis->pszFlashFile, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    470     if (RT_FAILURE(rc))
    471         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
    472 
    473     /* Set up the static state, immutable at run-time. */
    474     pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
    475     if (!pThis->pbFlash)
    476         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate heap memory"));
    477 
    478     size_t cbRead = 0;
    479     rc = RTFileRead(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
    480     if (RT_FAILURE(rc))
    481         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to read flash file"));
    482     Log(("Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize));
    483 
    484     /* If the file didn't exist, or someone truncated it, we'll initialize
    485      * the storage with default contents.
    486      */
    487     if (cbRead != pThis->cbFlashSize)
    488     {
    489         memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
    490         memcpy(pThis->pbFlash, aHdrBegin, sizeof(aHdrBegin));
    491         LogRel(("Only read %zu bytes from flash file (asked for %u). Initializing with defaults.\n", cbRead, pThis->cbFlashSize));
    492     }
    493 
    494     /* Reset the dynamic state.*/
    495     flashReset(pDevIns);
     206    rc = flashR3Init(&pThis->Core, pDevIns, u16FlashId, cbFlash, cbBlock);
     207    if (RT_FAILURE(rc))
     208        return PDMDEV_SET_ERROR(pDevIns, rc,
     209                                N_("Flash: Failed to initialize core flash device"));
     210
     211    /* Try to load the flash content from file. */
     212    rc = flashR3LoadFromFile(&pThis->Core, pThis->pszFlashFile);
     213    if (RT_FAILURE(rc))
     214        return PDMDEV_SET_ERROR(pDevIns, rc,
     215                                N_("Flash: Failed to load flash content from given file"));
    496216
    497217    /*
    498218     * Register MMIO region.
    499219     */
    500     rc = PDMDevHlpMMIORegister(pDevIns, pThis->GCPhysFlashBase, pThis->cbFlashSize, NULL /*pvUser*/,
     220    rc = PDMDevHlpMMIORegister(pDevIns, pThis->GCPhysFlashBase, cbFlash, NULL /*pvUser*/,
    501221                               IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
    502222                               flashMMIOWrite, flashMMIORead,
    503223                               "Flash Memory");
    504224    AssertRCReturn(rc, rc);
    505     LogRel(("Registered %uKB flash at %RGp\n", pThis->cbFlashSize / _1K, pThis->GCPhysFlashBase));
     225    LogRel(("Registered %uKB flash at %RGp\n", pThis->Core.cbFlashSize / _1K, pThis->GCPhysFlashBase));
    506226
    507227    /*
  • trunk/src/VBox/Devices/EFI/FlashCore.cpp

    r81236 r81250  
    3535
    3636#include "VBoxDD.h"
     37#include "FlashCore.h"
    3738
    3839
     
    4041*   Defined Constants And Macros                                                                                                 *
    4142*********************************************************************************************************************************/
    42 /** The current version of the saved state. */
    43 #define FLASH_SAVED_STATE_VERSION           1
    44 
    45 
    4643/** @name CUI (Command User Interface) Commands.
    4744 *  @{ */
     
    7168*   Structures and Typedefs                                                                                                      *
    7269*********************************************************************************************************************************/
    73 /**
    74  * The flash device
    75  */
    76 typedef struct DEVFLASH
    77 {
    78     /** The current command. */
    79     uint8_t             bCmd;
    80     /** The status register. */
    81     uint8_t             bStatus;
    82     /** Current bus cycle. */
    83     uint8_t             cBusCycle;
    84 
    85     uint8_t             uPadding0;
    86 
    87     /* The following state does not change at runtime.*/
    88     /** Manufacturer (high byte) and device (low byte) ID. */
    89     uint16_t            u16FlashId;
    90     /** The configured block size of the device. */
    91     uint16_t            cbBlockSize;
    92     /** The guest physical memory base address. */
    93     RTGCPHYS            GCPhysFlashBase;
    94     /** The flash memory region size.  */
    95     uint32_t            cbFlashSize;
    96     /** The actual flash memory data.  */
    97     uint8_t             *pbFlash;
    98     /** When set, indicates the state was saved. */
    99     bool                fStateSaved;
    100     /** The backing file. */
    101     RTFILE              hFlashFile;
    102     char                *pszFlashFile;
    103 } DEVFLASH;
    104 
    105 /** Pointer to the Flash device state. */
    106 typedef DEVFLASH *PDEVFLASH;
    107 
    10870#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    10971
     
    11173#ifdef IN_RING3 /* for now */
    11274
    113 static int flashMemWriteByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t bCmd)
     75static int flashMemWriteByte(PFLASHCORE pThis, uint32_t off, uint8_t bCmd)
    11476{
    11577    int rc = VINF_SUCCESS;
     
    12789        switch (bCmd)
    12890        {
    129         case FLASH_CMD_ARRAY_READ:
    130         case FLASH_CMD_STS_READ:
    131         case FLASH_CMD_ERASE_SUS_RES:
    132         case FLASH_CMD_READ_ID:
    133             /* Single-cycle write commands, only change the current command. */
    134             pThis->bCmd = bCmd;
    135             break;
    136         case FLASH_CMD_STS_CLEAR:
    137             /* Status clear continues in read mode. */
    138             pThis->bStatus = 0;
    139             pThis->bCmd = FLASH_CMD_ARRAY_READ;
    140             break;
    141         case FLASH_CMD_WRITE:
    142         case FLASH_CMD_ALT_WRITE:
    143         case FLASH_CMD_ERASE_SETUP:
    144             /* Two-cycle commands, advance the bus write cycle. */
    145             pThis->bCmd = bCmd;
    146             pThis->cBusCycle++;
    147             break;
    148         default:
    149             LogFunc(("1st cycle command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    150             break;
     91            case FLASH_CMD_ARRAY_READ:
     92            case FLASH_CMD_STS_READ:
     93            case FLASH_CMD_ERASE_SUS_RES:
     94            case FLASH_CMD_READ_ID:
     95                /* Single-cycle write commands, only change the current command. */
     96                pThis->bCmd = bCmd;
     97                break;
     98            case FLASH_CMD_STS_CLEAR:
     99                /* Status clear continues in read mode. */
     100                pThis->bStatus = 0;
     101                pThis->bCmd = FLASH_CMD_ARRAY_READ;
     102                break;
     103            case FLASH_CMD_WRITE:
     104            case FLASH_CMD_ALT_WRITE:
     105            case FLASH_CMD_ERASE_SETUP:
     106                /* Two-cycle commands, advance the bus write cycle. */
     107                pThis->bCmd = bCmd;
     108                pThis->cBusCycle++;
     109                break;
     110            default:
     111                LogFunc(("1st cycle command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
     112                break;
    151113        }
    152114    }
     
    157119        switch (pThis->bCmd)
    158120        {
    159         case FLASH_CMD_WRITE:
    160         case FLASH_CMD_ALT_WRITE:
    161             uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    162             if (uOffset < pThis->cbFlashSize)
    163             {
    164                 pThis->pbFlash[uOffset] = bCmd;
    165                 /* NB: Writes are instant and never fail. */
    166                 LogFunc(("wrote byte to flash at %08RGp: %02X\n", GCPhysAddr, bCmd));
    167             }
    168             else
    169                 LogFunc(("ignoring write at %08RGp: %02X\n", GCPhysAddr, bCmd));
    170             break;
    171         case FLASH_CMD_ERASE_SETUP:
    172             if (bCmd == FLASH_CMD_ERASE_CONFIRM)
    173             {
    174                 /* The current address determines the block to erase. */
    175                 uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    176                 uOffset = uOffset & ~(pThis->cbBlockSize - 1);
    177                 memset(pThis->pbFlash + uOffset, 0xff, pThis->cbBlockSize);
    178                 LogFunc(("Erasing block at offset %u\n", uOffset));
    179             }
    180             else
    181             {
    182                 /* Anything else is a command erorr. Transition to status read mode. */
    183                 LogFunc(("2st cycle erase command is %02X, should be confirm (%02X)\n", bCmd, FLASH_CMD_ERASE_CONFIRM));
    184                 pThis->bCmd = FLASH_CMD_STS_READ;
    185                 pThis->bStatus |= FLASH_STATUS_BWS | FLASH_STATUS_ES;
    186             }
    187             break;
    188         default:
    189             LogFunc(("2st cycle bad command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    190             break;
     121            case FLASH_CMD_WRITE:
     122            case FLASH_CMD_ALT_WRITE:
     123                uOffset = off & (pThis->cbFlashSize - 1);
     124                if (uOffset < pThis->cbFlashSize)
     125                {
     126                    pThis->pbFlash[uOffset] = bCmd;
     127                    /* NB: Writes are instant and never fail. */
     128                    LogFunc(("wrote byte to flash at %08RX32: %02X\n", off, bCmd));
     129                }
     130                else
     131                    LogFunc(("ignoring write at %08RX32: %02X\n", off, bCmd));
     132                break;
     133            case FLASH_CMD_ERASE_SETUP:
     134                if (bCmd == FLASH_CMD_ERASE_CONFIRM)
     135                {
     136                    /* The current address determines the block to erase. */
     137                    uOffset = off & (pThis->cbFlashSize - 1);
     138                    uOffset = uOffset & ~(pThis->cbBlockSize - 1);
     139                    memset(pThis->pbFlash + uOffset, 0xff, pThis->cbBlockSize);
     140                    LogFunc(("Erasing block at offset %u\n", uOffset));
     141                }
     142                else
     143                {
     144                    /* Anything else is a command erorr. Transition to status read mode. */
     145                    LogFunc(("2st cycle erase command is %02X, should be confirm (%02X)\n", bCmd, FLASH_CMD_ERASE_CONFIRM));
     146                    pThis->bCmd = FLASH_CMD_STS_READ;
     147                    pThis->bStatus |= FLASH_STATUS_BWS | FLASH_STATUS_ES;
     148                }
     149                break;
     150            default:
     151                LogFunc(("2st cycle bad command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
     152                break;
    191153        }
    192154        pThis->cBusCycle = 0;
    193155    }
    194     LogFlow(("flashMemWriteByte: write access at %08RGp: %#x rc=%Rrc\n", GCPhysAddr, bCmd, rc));
    195 //LogRel(("flashMemWriteByte: write access at %08RGp: %#x (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bCmd, pThis->bCmd, rc));
    196     return rc;
    197 }
    198 
    199 
    200 static int flashMemReadByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t *pbData)
     156    LogFlow(("flashMemWriteByte: write access at %08RX32: %#x rc=%Rrc\n", off, bCmd, rc));
     157    return rc;
     158}
     159
     160
     161static int flashMemReadByte(PFLASHCORE pThis, uint32_t off, uint8_t *pbData)
    201162{
    202163    uint8_t bValue;
     
    204165    int rc = VINF_SUCCESS;
    205166
    206     /* Reads are only defined in three states: Array read, status register read,
     167    /*
     168     * Reads are only defined in three states: Array read, status register read,
    207169     * and ID read.
    208170     */
    209171    switch (pThis->bCmd)
    210172    {
    211     case FLASH_CMD_ARRAY_READ:
    212         uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    213         bValue = pThis->pbFlash[uOffset];
    214         LogFunc(("read byte at %08RGp: %02X\n", GCPhysAddr, bValue));
    215         break;
    216     case FLASH_CMD_STS_READ:
    217         bValue = pThis->bStatus;
    218         break;
    219     case FLASH_CMD_READ_ID:
    220         bValue = GCPhysAddr & 1 ?  RT_HI_U8(pThis->u16FlashId) : RT_LO_U8(pThis->u16FlashId);
    221         break;
    222     default:
    223         bValue = 0xff;
    224         break;
     173        case FLASH_CMD_ARRAY_READ:
     174            uOffset = off & (pThis->cbFlashSize - 1);
     175            bValue = pThis->pbFlash[uOffset];
     176            LogFunc(("read byte at %08RX32: %02X\n", off, bValue));
     177            break;
     178        case FLASH_CMD_STS_READ:
     179            bValue = pThis->bStatus;
     180            break;
     181        case FLASH_CMD_READ_ID:
     182            bValue = off & 1 ?  RT_HI_U8(pThis->u16FlashId) : RT_LO_U8(pThis->u16FlashId);
     183            break;
     184        default:
     185            bValue = 0xff;
     186            break;
    225187    }
    226188    *pbData = bValue;
    227189
    228     LogFlow(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    229 //LogRel(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    230     return rc;
    231 }
    232 
    233 /** @callback_method_impl{FNIOMMIWRITE, Flash memory write} */
    234 PDMBOTHCBDECL(int) flashMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
    235 {
    236     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
     190    LogFlow(("flashMemReadByte: read access at %08RX: %02X (cmd=%02X) rc=%Rrc\n", bValue, pThis->bCmd, rc));
     191    return rc;
     192}
     193
     194DECLHIDDEN(int) flashWrite(PFLASHCORE pThis, uint32_t off, const void *pv, size_t cb)
     195{
    237196    int rc = VINF_SUCCESS;
    238197    const uint8_t *pu8Mem = (const uint8_t *)pv;
    239     unsigned uOffset;
    240     RT_NOREF1(pvUser);
    241 
    242     /* Writes may need to go back to R3. If more than one byte is being written (not likely!),
    243      * just suck it up and take the trip to R3 immediately.
    244      */
    245     /** @todo Idea: We could buffer all writes in R0 and flush them out on a
    246      *        timer. Probably not worth it.
    247      */
     198
    248199#ifndef IN_RING3
    249200    if (cb > 1)
     
    251202#endif
    252203
    253     for (uOffset = 0; uOffset < cb; ++uOffset)
    254     {
    255         rc = flashMemWriteByte(pThis, GCPhysAddr + uOffset, pu8Mem[uOffset]);
     204    for (uint32_t uOffset = 0; uOffset < cb; ++uOffset)
     205    {
     206        rc = flashMemWriteByte(pThis, off + uOffset, pu8Mem[uOffset]);
    256207        if (!RT_SUCCESS(rc))
    257208            break;
    258209    }
    259210
    260     LogFlow(("FlashMMIOWrite: completed write at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
    261     return rc;
    262 }
    263 
    264 
    265 /** @callback_method_impl{FNIOMMIOREAD, Flash memory read} */
    266 PDMBOTHCBDECL(int) flashMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
    267 {
    268     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
     211    LogFlow(("flashWrite: completed write at %08RX32 (LB %u): rc=%Rrc\n", off, cb, rc));
     212    return rc;
     213}
     214
     215DECLHIDDEN(int) flashRead(PFLASHCORE pThis, uint32_t off, void *pv, size_t cb)
     216{
    269217    int rc = VINF_SUCCESS;
    270     unsigned uOffset;
    271     uint8_t *pu8Mem;
    272     RT_NOREF1(pvUser);
    273 
    274     /* Reading can always be done witout going back to R3. Reads do not
     218    uint8_t *pu8Mem = (uint8_t *)pv;
     219
     220    /*
     221     * Reading can always be done witout going back to R3. Reads do not
    275222     * change the device state and we always have the data.
    276223     */
    277     pu8Mem = (uint8_t *)pv;
    278     for (uOffset = 0; uOffset < cb; ++uOffset, ++pu8Mem)
    279     {
    280         rc = flashMemReadByte(pThis, GCPhysAddr + uOffset, pu8Mem);
     224    for (uint32_t uOffset = 0; uOffset < cb; ++uOffset, ++pu8Mem)
     225    {
     226        rc = flashMemReadByte(pThis, off + uOffset, pu8Mem);
    281227        if (!RT_SUCCESS(rc))
    282228            break;
    283229    }
    284230
    285     LogFlow(("flashMMIORead: completed read at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
     231    LogFlow(("flashRead: completed read at %08RX32 (LB %u): rc=%Rrc\n", off, cb, rc));
    286232    return rc;
    287233}
     
    291237#ifdef IN_RING3
    292238
    293 /** @callback_method_impl{FNSSMDEVSAVEEXEC} */
    294 static DECLCALLBACK(int) flashSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    295 {
    296     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
     239DECLHIDDEN(int) flashR3Init(PFLASHCORE pThis, PPDMDEVINS pDevIns, uint16_t idFlashDev, uint32_t cbFlash, uint16_t cbBlock)
     240{
     241    pThis->pDevIns     = pDevIns;
     242    pThis->u16FlashId  = idFlashDev;
     243    pThis->cbBlockSize = cbBlock;
     244    pThis->cbFlashSize = cbFlash;
     245
     246    /* Set up the flash data. */
     247    pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
     248    if (!pThis->pbFlash)
     249        return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Failed to allocate heap memory"));
     250
     251    /* Default value for empty flash. */
     252    memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
     253
     254    /* Reset the dynamic state.*/
     255    flashR3Reset(pThis);
     256    return VINF_SUCCESS;
     257}
     258
     259DECLHIDDEN(void) flashR3Destruct(PFLASHCORE pThis)
     260{
     261    if (pThis->pbFlash)
     262    {
     263        PDMDevHlpMMHeapFree(pThis->pDevIns, pThis->pbFlash);
     264        pThis->pbFlash = NULL;
     265    }
     266}
     267
     268DECLHIDDEN(int) flashR3LoadFromFile(PFLASHCORE pThis, const char *pszFilename)
     269{
     270    RTFILE hFlashFile = NIL_RTFILE;
     271
     272    int rc = RTFileOpen(&hFlashFile, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     273    if (RT_FAILURE(rc))
     274        return PDMDEV_SET_ERROR(pThis->pDevIns, rc, N_("Failed to open flash file"));
     275
     276    size_t cbRead = 0;
     277    rc = RTFileRead(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
     278    if (RT_FAILURE(rc))
     279        return PDMDEV_SET_ERROR(pThis->pDevIns, rc, N_("Failed to read flash file"));
     280    Log(("Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize));
     281
     282    RTFileClose(hFlashFile);
     283    return VINF_SUCCESS;
     284}
     285
     286DECLHIDDEN(int) flashR3LoadFromBuf(PFLASHCORE pThis, void *pvBuf, size_t cbBuf)
     287{
     288    AssertReturn(pThis->cbFlashSize >= cbBuf, VERR_BUFFER_OVERFLOW);
     289
     290    memcpy(pThis->pbFlash, pvBuf, RT_MIN(cbBuf, pThis->cbFlashSize));
     291    return VINF_SUCCESS;
     292}
     293
     294DECLHIDDEN(int) flashR3SaveToFile(PFLASHCORE pThis, const char *pszFilename)
     295{
     296    RTFILE hFlashFile = NIL_RTFILE;
     297
     298    int rc = RTFileOpen(&hFlashFile, pszFilename, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
     299    if (RT_FAILURE(rc))
     300        return PDMDEV_SET_ERROR(pThis->pDevIns, rc, N_("Failed to open flash file"));
     301
     302    rc = RTFileWrite(hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
     303    if (RT_FAILURE(rc))
     304        return PDMDEV_SET_ERROR(pThis->pDevIns, rc, N_("Failed to write flash file"));
     305
     306    RTFileClose(hFlashFile);
     307    return VINF_SUCCESS;
     308}
     309
     310DECLHIDDEN(int) flashR3SaveToBuf(PFLASHCORE pThis, void *pvBuf, size_t cbBuf)
     311{
     312    AssertReturn(pThis->cbFlashSize <= cbBuf, VERR_BUFFER_OVERFLOW);
     313
     314    memcpy(pvBuf, pThis->pbFlash, RT_MIN(cbBuf, pThis->cbFlashSize));
     315    return VINF_SUCCESS;
     316}
     317
     318DECLHIDDEN(void) flashR3Reset(PFLASHCORE pThis)
     319{
     320    /*
     321     * Initialize the device state.
     322     */
     323    pThis->bCmd      = FLASH_CMD_ARRAY_READ;
     324    pThis->bStatus   = 0;
     325    pThis->cBusCycle = 0;
     326}
     327
     328DECLHIDDEN(int) flashR3SsmSaveExec(PFLASHCORE pThis, PSSMHANDLE pSSM)
     329{
     330    SSMR3PutU32(pSSM, FLASH_SAVED_STATE_VERSION);
    297331
    298332    /* Save the device state. */
     
    309343    SSMR3PutMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    310344
    311     pThis->fStateSaved = true;
    312 
    313     return VINF_SUCCESS;
    314 }
    315 
    316 
    317 /** @callback_method_impl{FNSSMDEVLOADEXEC} */
    318 static DECLCALLBACK(int) flashLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    319 {
    320     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    321     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
    322 
    323     /* Fend off unsupported versions. */
    324     if (uVersion != FLASH_SAVED_STATE_VERSION)
    325         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     345    return VINF_SUCCESS;
     346}
     347
     348DECLHIDDEN(int) flashR3SsmLoadExec(PFLASHCORE pThis, PSSMHANDLE pSSM)
     349{
     350    uint32_t uVersion = FLASH_SAVED_STATE_VERSION;
     351    int rc = SSMR3GetU32(pSSM, &uVersion);
     352    AssertRCReturn(rc, rc);
    326353
    327354    /*
     
    351378        SSMR3GetMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    352379    }
    353 
    354     return VINF_SUCCESS;
    355 }
    356 
    357 /**
    358  * @interface_method_impl{PDMDEVREG,pfnReset}
    359  */
    360 static DECLCALLBACK(void) flashReset(PPDMDEVINS pDevIns)
    361 {
    362     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    363 
    364     /*
    365      * Initialize the device state.
    366      */
    367     pThis->bCmd      = FLASH_CMD_ARRAY_READ;
    368     pThis->bStatus   = 0;
    369     pThis->cBusCycle = 0;
    370 }
    371 
    372 /**
    373  * @interface_method_impl{PDMDEVREG,pfnDestruct}
    374  */
    375 static DECLCALLBACK(int) flashDestruct(PPDMDEVINS pDevIns)
    376 {
    377     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    378     int rc;
    379 
    380     if (!pThis->fStateSaved)
    381     {
    382         rc = RTFileSeek(pThis->hFlashFile, 0, RTFILE_SEEK_BEGIN, NULL);
    383         rc = RTFileWrite(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
    384         if (RT_FAILURE(rc))
    385             LogRel(("flash: Failed to save flash file"));
    386     }
    387 
    388     if (pThis->pbFlash)
    389     {
    390         PDMDevHlpMMHeapFree(pDevIns, pThis->pbFlash);
    391         pThis->pbFlash = NULL;
    392     }
    393 
    394     if (pThis->pszFlashFile)
    395     {
    396         PDMDevHlpMMHeapFree(pDevIns, pThis->pszFlashFile);
    397         pThis->pszFlashFile = NULL;
    398     }
    399 
    400     return VINF_SUCCESS;
    401 }
    402 
    403 /** @todo this does not really belong here; workaround for EFI failing to init empty flash. */
    404 static const uint8_t aHdrBegin[] = {
    405     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    406     0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
    407     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x46, 0x56, 0x48, 0xFF, 0xFE, 0x04, 0x00,
    408     0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    409     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x36, 0xCF, 0xDD, 0x75, 0x32, 0x64, 0x41,
    410     0x98, 0xB6, 0xFE, 0x85, 0x70, 0x7F, 0xFE, 0x7D, 0xB8, 0xDF, 0x00, 0x00, 0x5A, 0xFE, 0x00, 0x00,
    411     0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
    412 };
    413 
    414 /**
    415  * @interface_method_impl{PDMDEVREG,pfnConstruct}
    416  */
    417 static DECLCALLBACK(int) flashConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    418 {
    419     RT_NOREF1(iInstance);
    420     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
    421     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    422     Assert(iInstance == 0);
    423 
    424     /*
    425      * Validate configuration.
    426      */
    427     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceId|BaseAddress|Size|BlockSize|FlashFile", "");
    428 
    429     /*
    430      * Read configuration.
    431      */
    432 
    433     /* The default device ID is Intel 28F800SA. */
    434     int rc = CFGMR3QueryU16Def(pCfg, "DeviceId", &pThis->u16FlashId, 0xA289);
    435     if (RT_FAILURE(rc))
    436         return PDMDEV_SET_ERROR(pDevIns, rc,
    437                                 N_("Configuration error: Querying \"DeviceId\" as an integer failed"));
    438 
    439     /* The default base address is 2MB below 4GB. */
    440     rc = CFGMR3QueryU64Def(pCfg, "BaseAddress", &pThis->GCPhysFlashBase, 0xFFE00000);
    441     if (RT_FAILURE(rc))
    442         return PDMDEV_SET_ERROR(pDevIns, rc,
    443                                 N_("Configuration error: Querying \"BaseAddress\" as an integer failed"));
    444 
    445     /* The default flash device size is 128K. */
    446     rc = CFGMR3QueryU32Def(pCfg, "Size", &pThis->cbFlashSize, 128 * _1K);
    447     if (RT_FAILURE(rc))
    448         return PDMDEV_SET_ERROR(pDevIns, rc,
    449                                 N_("Configuration error: Querying \"Size\" as an integer failed"));
    450 
    451     /* The default flash device block size is 4K. */
    452     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
    453     if (RT_FAILURE(rc))
    454         return PDMDEV_SET_ERROR(pDevIns, rc,
    455                                 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    456 
    457     /* The default flash device block size is 4K. */
    458     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
    459     if (RT_FAILURE(rc))
    460         return PDMDEV_SET_ERROR(pDevIns, rc,
    461                                 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    462 
    463     rc = CFGMR3QueryStringAlloc(pCfg, "FlashFile", &pThis->pszFlashFile);
    464     if (RT_FAILURE(rc))
    465         return PDMDEV_SET_ERROR(pDevIns, rc,
    466                                 N_("Configuration error: Querying \"FlashFile\" as a string failed"));
    467 
    468     /* Try opening the backing file. */
    469     rc = RTFileOpen(&pThis->hFlashFile, pThis->pszFlashFile, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    470     if (RT_FAILURE(rc))
    471         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
    472 
    473     /* Set up the static state, immutable at run-time. */
    474     pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
    475     if (!pThis->pbFlash)
    476         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate heap memory"));
    477 
    478     size_t cbRead = 0;
    479     rc = RTFileRead(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
    480     if (RT_FAILURE(rc))
    481         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to read flash file"));
    482     Log(("Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize));
    483 
    484     /* If the file didn't exist, or someone truncated it, we'll initialize
    485      * the storage with default contents.
    486      */
    487     if (cbRead != pThis->cbFlashSize)
    488     {
    489         memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
    490         memcpy(pThis->pbFlash, aHdrBegin, sizeof(aHdrBegin));
    491         LogRel(("Only read %zu bytes from flash file (asked for %u). Initializing with defaults.\n", cbRead, pThis->cbFlashSize));
    492     }
    493 
    494     /* Reset the dynamic state.*/
    495     flashReset(pDevIns);
    496 
    497     /*
    498      * Register MMIO region.
    499      */
    500     rc = PDMDevHlpMMIORegister(pDevIns, pThis->GCPhysFlashBase, pThis->cbFlashSize, NULL /*pvUser*/,
    501                                IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
    502                                flashMMIOWrite, flashMMIORead,
    503                                "Flash Memory");
    504     AssertRCReturn(rc, rc);
    505     LogRel(("Registered %uKB flash at %RGp\n", pThis->cbFlashSize / _1K, pThis->GCPhysFlashBase));
    506 
    507     /*
    508      * Register saved state.
    509      */
    510     rc = PDMDevHlpSSMRegister(pDevIns, FLASH_SAVED_STATE_VERSION, sizeof(*pThis), flashSaveExec, flashLoadExec);
    511     if (RT_FAILURE(rc))
    512         return rc;
    513 
    514     return VINF_SUCCESS;
     380    else
     381        rc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     382
     383    return rc;
    515384}
    516385
    517386#endif /* IN_RING3 */
    518387
    519 /**
    520  * The device registration structure.
    521  */
    522 const PDMDEVREG g_DeviceFlash =
    523 {
    524     /* .u32Version = */             PDM_DEVREG_VERSION,
    525     /* .uReserved0 = */             0,
    526     /* .szName = */                 "flash",
    527     /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS,
    528     /* .fClass = */                 PDM_DEVREG_CLASS_ARCH,
    529     /* .cMaxInstances = */          1,
    530     /* .uSharedVersion = */         42,
    531     /* .cbInstanceShared = */       sizeof(DEVFLASH),
    532     /* .cbInstanceCC = */           0,
    533     /* .cbInstanceRC = */           0,
    534     /* .cMaxPciDevices = */         0,
    535     /* .cMaxMsixVectors = */        0,
    536     /* .pszDescription = */         "Flash Memory Device",
    537 #if defined(IN_RING3)
    538     /* .pszRCMod = */               "",
    539     /* .pszR0Mod = */               "",
    540     /* .pfnConstruct = */           flashConstruct,
    541     /* .pfnDestruct = */            flashDestruct,
    542     /* .pfnRelocate = */            NULL,
    543     /* .pfnMemSetup = */            NULL,
    544     /* .pfnPowerOn = */             NULL,
    545     /* .pfnReset = */               flashReset,
    546     /* .pfnSuspend = */             NULL,
    547     /* .pfnResume = */              NULL,
    548     /* .pfnAttach = */              NULL,
    549     /* .pfnDetach = */              NULL,
    550     /* .pfnQueryInterface = */      NULL,
    551     /* .pfnInitComplete = */        NULL,
    552     /* .pfnPowerOff = */            NULL,
    553     /* .pfnSoftReset = */           NULL,
    554     /* .pfnReserved0 = */           NULL,
    555     /* .pfnReserved1 = */           NULL,
    556     /* .pfnReserved2 = */           NULL,
    557     /* .pfnReserved3 = */           NULL,
    558     /* .pfnReserved4 = */           NULL,
    559     /* .pfnReserved5 = */           NULL,
    560     /* .pfnReserved6 = */           NULL,
    561     /* .pfnReserved7 = */           NULL,
    562 #elif defined(IN_RING0)
    563     /* .pfnEarlyConstruct = */      NULL,
    564     /* .pfnConstruct = */           NULL,
    565     /* .pfnDestruct = */            NULL,
    566     /* .pfnFinalDestruct = */       NULL,
    567     /* .pfnRequest = */             NULL,
    568     /* .pfnReserved0 = */           NULL,
    569     /* .pfnReserved1 = */           NULL,
    570     /* .pfnReserved2 = */           NULL,
    571     /* .pfnReserved3 = */           NULL,
    572     /* .pfnReserved4 = */           NULL,
    573     /* .pfnReserved5 = */           NULL,
    574     /* .pfnReserved6 = */           NULL,
    575     /* .pfnReserved7 = */           NULL,
    576 #elif defined(IN_RC)
    577     /* .pfnConstruct = */           NULL,
    578     /* .pfnReserved0 = */           NULL,
    579     /* .pfnReserved1 = */           NULL,
    580     /* .pfnReserved2 = */           NULL,
    581     /* .pfnReserved3 = */           NULL,
    582     /* .pfnReserved4 = */           NULL,
    583     /* .pfnReserved5 = */           NULL,
    584     /* .pfnReserved6 = */           NULL,
    585     /* .pfnReserved7 = */           NULL,
    586 #else
    587 # error "Not in IN_RING3, IN_RING0 or IN_RC!"
    588 #endif
    589     /* .u32VersionEnd = */          PDM_DEVREG_VERSION
    590 };
    591 
    592388#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
  • trunk/src/VBox/Devices/EFI/FlashCore.h

    r81236 r81250  
    11/* $Id$ */
    22/** @file
    3  * DevFlash - A simple Flash device
     3 * A simple Flash device
    44 *
    55 * A simple non-volatile byte-wide (x8) memory device modeled after Intel 28F008
     
    2222 */
    2323
     24#ifndef VBOX_INCLUDED_SRC_EFI_FlashCore_h
     25#define VBOX_INCLUDED_SRC_EFI_FlashCore_h
     26#ifndef RT_WITHOUT_PRAGMA_ONCE
     27# pragma once
     28#endif
    2429
    2530/*********************************************************************************************************************************
    2631*   Header Files                                                                                                                 *
    2732*********************************************************************************************************************************/
    28 #define LOG_GROUP LOG_GROUP_DEV_FLASH
    2933#include <VBox/vmm/pdmdev.h>
    3034#include <VBox/log.h>
     
    3640#include "VBoxDD.h"
    3741
     42RT_C_DECLS_BEGIN
    3843
    3944/*********************************************************************************************************************************
     
    4449
    4550
    46 /** @name CUI (Command User Interface) Commands.
    47  *  @{ */
    48 #define FLASH_CMD_ALT_WRITE             0x10
    49 #define FLASH_CMD_ERASE_SETUP           0x20
    50 #define FLASH_CMD_WRITE                 0x40
    51 #define FLASH_CMD_STS_CLEAR             0x50
    52 #define FLASH_CMD_STS_READ              0x70
    53 #define FLASH_CMD_READ_ID               0x90
    54 #define FLASH_CMD_ERASE_SUS_RES         0xB0
    55 #define FLASH_CMD_ERASE_CONFIRM         0xD0
    56 #define FLASH_CMD_ARRAY_READ            0xFF
    57 /** @} */
    58 
    59 /** @name Status register bits.
    60  *  @{ */
    61 #define FLASH_STATUS_WSMS               0x80    /* Write State Machine Status, 1=Ready */
    62 #define FLASH_STATUS_ESS                0x40    /* Erase Suspend Status, 1=Suspended */
    63 #define FLASH_STATUS_ES                 0x20    /* Erase Status, 1=Error */
    64 #define FLASH_STATUS_BWS                0x10    /* Byte Write Status, 1=Error */
    65 #define FLASH_STATUS_VPPS               0x08    /* Vpp Status, 1=Low Vpp */
    66 /* The remaining bits 0-2 are reserved/unused */
    67 /** @} */
    68 
    69 
    7051/*********************************************************************************************************************************
    7152*   Structures and Typedefs                                                                                                      *
    7253*********************************************************************************************************************************/
    7354/**
    74  * The flash device
    75  */
    76 typedef struct DEVFLASH
     55 * The flash device core structure.
     56 */
     57typedef struct FLASHCORE
    7758{
     59    /** Owning device instance. */
     60    PPDMDEVINS          pDevIns;
    7861    /** The current command. */
    7962    uint8_t             bCmd;
     
    9073    /** The configured block size of the device. */
    9174    uint16_t            cbBlockSize;
    92     /** The guest physical memory base address. */
    93     RTGCPHYS            GCPhysFlashBase;
    9475    /** The flash memory region size.  */
    9576    uint32_t            cbFlashSize;
     
    9879    /** When set, indicates the state was saved. */
    9980    bool                fStateSaved;
    100     /** The backing file. */
    101     RTFILE              hFlashFile;
    102     char                *pszFlashFile;
    103 } DEVFLASH;
     81} FLASHCORE;
    10482
    10583/** Pointer to the Flash device state. */
    106 typedef DEVFLASH *PDEVFLASH;
     84typedef FLASHCORE *PFLASHCORE;
    10785
    10886#ifndef VBOX_DEVICE_STRUCT_TESTCASE
    10987
    110 
    111 #ifdef IN_RING3 /* for now */
    112 
    113 static int flashMemWriteByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t bCmd)
    114 {
    115     int rc = VINF_SUCCESS;
    116     unsigned uOffset;
    117 
    118     /* NB: Older datasheets (e.g. 28F008SA) suggest that for two-cycle commands like byte write or
    119      * erase setup, the address is significant in both cycles, but do not explain what happens
    120      * should the addresses not match. Newer datasheets (e.g. 28F008B3) clearly say that the address
    121      * in the first byte cycle never matters. We prefer the latter interpretation.
    122      */
    123 
    124     if (pThis->cBusCycle == 0)
    125     {
    126         /* First bus write cycle, start processing a new command. Address is ignored. */
    127         switch (bCmd)
    128         {
    129         case FLASH_CMD_ARRAY_READ:
    130         case FLASH_CMD_STS_READ:
    131         case FLASH_CMD_ERASE_SUS_RES:
    132         case FLASH_CMD_READ_ID:
    133             /* Single-cycle write commands, only change the current command. */
    134             pThis->bCmd = bCmd;
    135             break;
    136         case FLASH_CMD_STS_CLEAR:
    137             /* Status clear continues in read mode. */
    138             pThis->bStatus = 0;
    139             pThis->bCmd = FLASH_CMD_ARRAY_READ;
    140             break;
    141         case FLASH_CMD_WRITE:
    142         case FLASH_CMD_ALT_WRITE:
    143         case FLASH_CMD_ERASE_SETUP:
    144             /* Two-cycle commands, advance the bus write cycle. */
    145             pThis->bCmd = bCmd;
    146             pThis->cBusCycle++;
    147             break;
    148         default:
    149             LogFunc(("1st cycle command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    150             break;
    151         }
    152     }
    153     else
    154     {
    155         /* Second write of a two-cycle command. */
    156         Assert(pThis->cBusCycle == 1);
    157         switch (pThis->bCmd)
    158         {
    159         case FLASH_CMD_WRITE:
    160         case FLASH_CMD_ALT_WRITE:
    161             uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    162             if (uOffset < pThis->cbFlashSize)
    163             {
    164                 pThis->pbFlash[uOffset] = bCmd;
    165                 /* NB: Writes are instant and never fail. */
    166                 LogFunc(("wrote byte to flash at %08RGp: %02X\n", GCPhysAddr, bCmd));
    167             }
    168             else
    169                 LogFunc(("ignoring write at %08RGp: %02X\n", GCPhysAddr, bCmd));
    170             break;
    171         case FLASH_CMD_ERASE_SETUP:
    172             if (bCmd == FLASH_CMD_ERASE_CONFIRM)
    173             {
    174                 /* The current address determines the block to erase. */
    175                 uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    176                 uOffset = uOffset & ~(pThis->cbBlockSize - 1);
    177                 memset(pThis->pbFlash + uOffset, 0xff, pThis->cbBlockSize);
    178                 LogFunc(("Erasing block at offset %u\n", uOffset));
    179             }
    180             else
    181             {
    182                 /* Anything else is a command erorr. Transition to status read mode. */
    183                 LogFunc(("2st cycle erase command is %02X, should be confirm (%02X)\n", bCmd, FLASH_CMD_ERASE_CONFIRM));
    184                 pThis->bCmd = FLASH_CMD_STS_READ;
    185                 pThis->bStatus |= FLASH_STATUS_BWS | FLASH_STATUS_ES;
    186             }
    187             break;
    188         default:
    189             LogFunc(("2st cycle bad command %02X, current cmd %02X\n", bCmd, pThis->bCmd));
    190             break;
    191         }
    192         pThis->cBusCycle = 0;
    193     }
    194     LogFlow(("flashMemWriteByte: write access at %08RGp: %#x rc=%Rrc\n", GCPhysAddr, bCmd, rc));
    195 //LogRel(("flashMemWriteByte: write access at %08RGp: %#x (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bCmd, pThis->bCmd, rc));
    196     return rc;
    197 }
    198 
    199 
    200 static int flashMemReadByte(PDEVFLASH pThis, RTGCPHYS GCPhysAddr, uint8_t *pbData)
    201 {
    202     uint8_t bValue;
    203     unsigned uOffset;
    204     int rc = VINF_SUCCESS;
    205 
    206     /* Reads are only defined in three states: Array read, status register read,
    207      * and ID read.
    208      */
    209     switch (pThis->bCmd)
    210     {
    211     case FLASH_CMD_ARRAY_READ:
    212         uOffset = GCPhysAddr & (pThis->cbFlashSize - 1);
    213         bValue = pThis->pbFlash[uOffset];
    214         LogFunc(("read byte at %08RGp: %02X\n", GCPhysAddr, bValue));
    215         break;
    216     case FLASH_CMD_STS_READ:
    217         bValue = pThis->bStatus;
    218         break;
    219     case FLASH_CMD_READ_ID:
    220         bValue = GCPhysAddr & 1 ?  RT_HI_U8(pThis->u16FlashId) : RT_LO_U8(pThis->u16FlashId);
    221         break;
    222     default:
    223         bValue = 0xff;
    224         break;
    225     }
    226     *pbData = bValue;
    227 
    228     LogFlow(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    229 //LogRel(("flashMemReadByte: read access at %08RGp: %02X (cmd=%02X) rc=%Rrc\n", GCPhysAddr, bValue, pThis->bCmd, rc));
    230     return rc;
    231 }
    232 
    233 /** @callback_method_impl{FNIOMMIWRITE, Flash memory write} */
    234 PDMBOTHCBDECL(int) flashMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
    235 {
    236     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    237     int rc = VINF_SUCCESS;
    238     const uint8_t *pu8Mem = (const uint8_t *)pv;
    239     unsigned uOffset;
    240     RT_NOREF1(pvUser);
    241 
    242     /* Writes may need to go back to R3. If more than one byte is being written (not likely!),
    243      * just suck it up and take the trip to R3 immediately.
    244      */
    245     /** @todo Idea: We could buffer all writes in R0 and flush them out on a
    246      *        timer. Probably not worth it.
    247      */
    248 #ifndef IN_RING3
    249     if (cb > 1)
    250         return VINF_IOM_R3_IOPORT_WRITE;
    251 #endif
    252 
    253     for (uOffset = 0; uOffset < cb; ++uOffset)
    254     {
    255         rc = flashMemWriteByte(pThis, GCPhysAddr + uOffset, pu8Mem[uOffset]);
    256         if (!RT_SUCCESS(rc))
    257             break;
    258     }
    259 
    260     LogFlow(("FlashMMIOWrite: completed write at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
    261     return rc;
    262 }
    263 
    264 
    265 /** @callback_method_impl{FNIOMMIOREAD, Flash memory read} */
    266 PDMBOTHCBDECL(int) flashMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
    267 {
    268     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    269     int rc = VINF_SUCCESS;
    270     unsigned uOffset;
    271     uint8_t *pu8Mem;
    272     RT_NOREF1(pvUser);
    273 
    274     /* Reading can always be done witout going back to R3. Reads do not
    275      * change the device state and we always have the data.
    276      */
    277     pu8Mem = (uint8_t *)pv;
    278     for (uOffset = 0; uOffset < cb; ++uOffset, ++pu8Mem)
    279     {
    280         rc = flashMemReadByte(pThis, GCPhysAddr + uOffset, pu8Mem);
    281         if (!RT_SUCCESS(rc))
    282             break;
    283     }
    284 
    285     LogFlow(("flashMMIORead: completed read at %08RGp (LB %u): rc=%Rrc\n", GCPhysAddr, cb, rc));
    286     return rc;
    287 }
    288 
    289 #endif /* IN_RING3 for now */
    290 
    291 #ifdef IN_RING3
    292 
    293 /** @callback_method_impl{FNSSMDEVSAVEEXEC} */
    294 static DECLCALLBACK(int) flashSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    295 {
    296     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    297 
    298     /* Save the device state. */
    299     SSMR3PutU8(pSSM, pThis->bCmd);
    300     SSMR3PutU8(pSSM, pThis->bStatus);
    301     SSMR3PutU8(pSSM, pThis->cBusCycle);
    302 
    303     /* Save the current configuration for validation purposes. */
    304     SSMR3PutU16(pSSM, pThis->cbBlockSize);
    305     SSMR3PutU16(pSSM, pThis->u16FlashId);
    306 
    307     /* Save the current flash contents. */
    308     SSMR3PutU32(pSSM, pThis->cbFlashSize);
    309     SSMR3PutMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    310 
    311     pThis->fStateSaved = true;
    312 
    313     return VINF_SUCCESS;
    314 }
    315 
    316 
    317 /** @callback_method_impl{FNSSMDEVLOADEXEC} */
    318 static DECLCALLBACK(int) flashLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    319 {
    320     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    321     Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
    322 
    323     /* Fend off unsupported versions. */
    324     if (uVersion != FLASH_SAVED_STATE_VERSION)
    325         return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
    326 
    327     /*
    328      * Do the actual restoring.
    329      */
    330     if (uVersion == FLASH_SAVED_STATE_VERSION)
    331     {
    332         uint16_t    u16Val;
    333         uint32_t    u32Val;
    334 
    335         SSMR3GetU8(pSSM, &pThis->bCmd);
    336         SSMR3GetU8(pSSM, &pThis->bStatus);
    337         SSMR3GetU8(pSSM, &pThis->cBusCycle);
    338 
    339         /* Make sure configuration didn't change behind our back. */
    340         SSMR3GetU16(pSSM, &u16Val);
    341         if (u16Val != pThis->cbBlockSize)
    342             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    343         SSMR3GetU16(pSSM, &u16Val);
    344         if (u16Val != pThis->u16FlashId)
    345             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    346         SSMR3GetU32(pSSM, &u32Val);
    347         if (u16Val != pThis->cbFlashSize)
    348             return VERR_SSM_LOAD_CONFIG_MISMATCH;
    349 
    350         /* Suck in the flash contents. */
    351         SSMR3GetMem(pSSM, pThis->pbFlash, pThis->cbFlashSize);
    352     }
    353 
    354     return VINF_SUCCESS;
    355 }
    356 
    357 /**
    358  * @interface_method_impl{PDMDEVREG,pfnReset}
    359  */
    360 static DECLCALLBACK(void) flashReset(PPDMDEVINS pDevIns)
    361 {
    362     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    363 
    364     /*
    365      * Initialize the device state.
    366      */
    367     pThis->bCmd      = FLASH_CMD_ARRAY_READ;
    368     pThis->bStatus   = 0;
    369     pThis->cBusCycle = 0;
    370 }
    371 
    372 /**
    373  * @interface_method_impl{PDMDEVREG,pfnDestruct}
    374  */
    375 static DECLCALLBACK(int) flashDestruct(PPDMDEVINS pDevIns)
    376 {
    377     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    378     int rc;
    379 
    380     if (!pThis->fStateSaved)
    381     {
    382         rc = RTFileSeek(pThis->hFlashFile, 0, RTFILE_SEEK_BEGIN, NULL);
    383         rc = RTFileWrite(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, NULL);
    384         if (RT_FAILURE(rc))
    385             LogRel(("flash: Failed to save flash file"));
    386     }
    387 
    388     if (pThis->pbFlash)
    389     {
    390         PDMDevHlpMMHeapFree(pDevIns, pThis->pbFlash);
    391         pThis->pbFlash = NULL;
    392     }
    393 
    394     if (pThis->pszFlashFile)
    395     {
    396         PDMDevHlpMMHeapFree(pDevIns, pThis->pszFlashFile);
    397         pThis->pszFlashFile = NULL;
    398     }
    399 
    400     return VINF_SUCCESS;
    401 }
    402 
    403 /** @todo this does not really belong here; workaround for EFI failing to init empty flash. */
    404 static const uint8_t aHdrBegin[] = {
    405     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    406     0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
    407     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, 0x46, 0x56, 0x48, 0xFF, 0xFE, 0x04, 0x00,
    408     0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
    409     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x36, 0xCF, 0xDD, 0x75, 0x32, 0x64, 0x41,
    410     0x98, 0xB6, 0xFE, 0x85, 0x70, 0x7F, 0xFE, 0x7D, 0xB8, 0xDF, 0x00, 0x00, 0x5A, 0xFE, 0x00, 0x00,
    411     0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
    412 };
    413 
    414 /**
    415  * @interface_method_impl{PDMDEVREG,pfnConstruct}
    416  */
    417 static DECLCALLBACK(int) flashConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
    418 {
    419     RT_NOREF1(iInstance);
    420     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
    421     PDEVFLASH pThis = PDMINS_2_DATA(pDevIns, PDEVFLASH);
    422     Assert(iInstance == 0);
    423 
    424     /*
    425      * Validate configuration.
    426      */
    427     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "DeviceId|BaseAddress|Size|BlockSize|FlashFile", "");
    428 
    429     /*
    430      * Read configuration.
    431      */
    432 
    433     /* The default device ID is Intel 28F800SA. */
    434     int rc = CFGMR3QueryU16Def(pCfg, "DeviceId", &pThis->u16FlashId, 0xA289);
    435     if (RT_FAILURE(rc))
    436         return PDMDEV_SET_ERROR(pDevIns, rc,
    437                                 N_("Configuration error: Querying \"DeviceId\" as an integer failed"));
    438 
    439     /* The default base address is 2MB below 4GB. */
    440     rc = CFGMR3QueryU64Def(pCfg, "BaseAddress", &pThis->GCPhysFlashBase, 0xFFE00000);
    441     if (RT_FAILURE(rc))
    442         return PDMDEV_SET_ERROR(pDevIns, rc,
    443                                 N_("Configuration error: Querying \"BaseAddress\" as an integer failed"));
    444 
    445     /* The default flash device size is 128K. */
    446     rc = CFGMR3QueryU32Def(pCfg, "Size", &pThis->cbFlashSize, 128 * _1K);
    447     if (RT_FAILURE(rc))
    448         return PDMDEV_SET_ERROR(pDevIns, rc,
    449                                 N_("Configuration error: Querying \"Size\" as an integer failed"));
    450 
    451     /* The default flash device block size is 4K. */
    452     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
    453     if (RT_FAILURE(rc))
    454         return PDMDEV_SET_ERROR(pDevIns, rc,
    455                                 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    456 
    457     /* The default flash device block size is 4K. */
    458     rc = CFGMR3QueryU16Def(pCfg, "BlockSize", &pThis->cbBlockSize, 4 * _1K);
    459     if (RT_FAILURE(rc))
    460         return PDMDEV_SET_ERROR(pDevIns, rc,
    461                                 N_("Configuration error: Querying \"BlockSize\" as an integer failed"));
    462 
    463     rc = CFGMR3QueryStringAlloc(pCfg, "FlashFile", &pThis->pszFlashFile);
    464     if (RT_FAILURE(rc))
    465         return PDMDEV_SET_ERROR(pDevIns, rc,
    466                                 N_("Configuration error: Querying \"FlashFile\" as a string failed"));
    467 
    468     /* Try opening the backing file. */
    469     rc = RTFileOpen(&pThis->hFlashFile, pThis->pszFlashFile, RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    470     if (RT_FAILURE(rc))
    471         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to open flash file"));
    472 
    473     /* Set up the static state, immutable at run-time. */
    474     pThis->pbFlash = (uint8_t *)PDMDevHlpMMHeapAlloc(pDevIns, pThis->cbFlashSize);
    475     if (!pThis->pbFlash)
    476         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to allocate heap memory"));
    477 
    478     size_t cbRead = 0;
    479     rc = RTFileRead(pThis->hFlashFile, pThis->pbFlash, pThis->cbFlashSize, &cbRead);
    480     if (RT_FAILURE(rc))
    481         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to read flash file"));
    482     Log(("Read %zu bytes from file (asked for %u)\n.", cbRead, pThis->cbFlashSize));
    483 
    484     /* If the file didn't exist, or someone truncated it, we'll initialize
    485      * the storage with default contents.
    486      */
    487     if (cbRead != pThis->cbFlashSize)
    488     {
    489         memset(pThis->pbFlash, 0xff, pThis->cbFlashSize);
    490         memcpy(pThis->pbFlash, aHdrBegin, sizeof(aHdrBegin));
    491         LogRel(("Only read %zu bytes from flash file (asked for %u). Initializing with defaults.\n", cbRead, pThis->cbFlashSize));
    492     }
    493 
    494     /* Reset the dynamic state.*/
    495     flashReset(pDevIns);
    496 
    497     /*
    498      * Register MMIO region.
    499      */
    500     rc = PDMDevHlpMMIORegister(pDevIns, pThis->GCPhysFlashBase, pThis->cbFlashSize, NULL /*pvUser*/,
    501                                IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
    502                                flashMMIOWrite, flashMMIORead,
    503                                "Flash Memory");
    504     AssertRCReturn(rc, rc);
    505     LogRel(("Registered %uKB flash at %RGp\n", pThis->cbFlashSize / _1K, pThis->GCPhysFlashBase));
    506 
    507     /*
    508      * Register saved state.
    509      */
    510     rc = PDMDevHlpSSMRegister(pDevIns, FLASH_SAVED_STATE_VERSION, sizeof(*pThis), flashSaveExec, flashLoadExec);
    511     if (RT_FAILURE(rc))
    512         return rc;
    513 
    514     return VINF_SUCCESS;
    515 }
    516 
    517 #endif /* IN_RING3 */
    518 
    519 /**
    520  * The device registration structure.
    521  */
    522 const PDMDEVREG g_DeviceFlash =
    523 {
    524     /* .u32Version = */             PDM_DEVREG_VERSION,
    525     /* .uReserved0 = */             0,
    526     /* .szName = */                 "flash",
    527     /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS,
    528     /* .fClass = */                 PDM_DEVREG_CLASS_ARCH,
    529     /* .cMaxInstances = */          1,
    530     /* .uSharedVersion = */         42,
    531     /* .cbInstanceShared = */       sizeof(DEVFLASH),
    532     /* .cbInstanceCC = */           0,
    533     /* .cbInstanceRC = */           0,
    534     /* .cMaxPciDevices = */         0,
    535     /* .cMaxMsixVectors = */        0,
    536     /* .pszDescription = */         "Flash Memory Device",
    537 #if defined(IN_RING3)
    538     /* .pszRCMod = */               "",
    539     /* .pszR0Mod = */               "",
    540     /* .pfnConstruct = */           flashConstruct,
    541     /* .pfnDestruct = */            flashDestruct,
    542     /* .pfnRelocate = */            NULL,
    543     /* .pfnMemSetup = */            NULL,
    544     /* .pfnPowerOn = */             NULL,
    545     /* .pfnReset = */               flashReset,
    546     /* .pfnSuspend = */             NULL,
    547     /* .pfnResume = */              NULL,
    548     /* .pfnAttach = */              NULL,
    549     /* .pfnDetach = */              NULL,
    550     /* .pfnQueryInterface = */      NULL,
    551     /* .pfnInitComplete = */        NULL,
    552     /* .pfnPowerOff = */            NULL,
    553     /* .pfnSoftReset = */           NULL,
    554     /* .pfnReserved0 = */           NULL,
    555     /* .pfnReserved1 = */           NULL,
    556     /* .pfnReserved2 = */           NULL,
    557     /* .pfnReserved3 = */           NULL,
    558     /* .pfnReserved4 = */           NULL,
    559     /* .pfnReserved5 = */           NULL,
    560     /* .pfnReserved6 = */           NULL,
    561     /* .pfnReserved7 = */           NULL,
    562 #elif defined(IN_RING0)
    563     /* .pfnEarlyConstruct = */      NULL,
    564     /* .pfnConstruct = */           NULL,
    565     /* .pfnDestruct = */            NULL,
    566     /* .pfnFinalDestruct = */       NULL,
    567     /* .pfnRequest = */             NULL,
    568     /* .pfnReserved0 = */           NULL,
    569     /* .pfnReserved1 = */           NULL,
    570     /* .pfnReserved2 = */           NULL,
    571     /* .pfnReserved3 = */           NULL,
    572     /* .pfnReserved4 = */           NULL,
    573     /* .pfnReserved5 = */           NULL,
    574     /* .pfnReserved6 = */           NULL,
    575     /* .pfnReserved7 = */           NULL,
    576 #elif defined(IN_RC)
    577     /* .pfnConstruct = */           NULL,
    578     /* .pfnReserved0 = */           NULL,
    579     /* .pfnReserved1 = */           NULL,
    580     /* .pfnReserved2 = */           NULL,
    581     /* .pfnReserved3 = */           NULL,
    582     /* .pfnReserved4 = */           NULL,
    583     /* .pfnReserved5 = */           NULL,
    584     /* .pfnReserved6 = */           NULL,
    585     /* .pfnReserved7 = */           NULL,
    586 #else
    587 # error "Not in IN_RING3, IN_RING0 or IN_RC!"
    588 #endif
    589     /* .u32VersionEnd = */          PDM_DEVREG_VERSION
    590 };
     88/**
     89 * Performs a write to the given flash offset.
     90 *
     91 * @returns VBox status code.
     92 * @param   pThis               The UART core instance.
     93 * @param   off                 Offset to start writing to.
     94 * @param   pv                  The value to write.
     95 * @param   cb                  Number of bytes to write.
     96 */
     97DECLHIDDEN(int) flashWrite(PFLASHCORE pThis, uint32_t off, const void *pv, size_t cb);
     98
     99/**
     100 * Performs a read from the given flash offset.
     101 *
     102 * @returns VBox status code.
     103 * @param   pThis               The UART core instance.
     104 * @param   off                 Offset to start reading from.
     105 * @param   pv                  Where to store the read data.
     106 * @param   cb                  Number of bytes to read.
     107 */
     108DECLHIDDEN(int) flashRead(PFLASHCORE pThis, uint32_t off, void *pv, size_t cb);
     109
     110# ifdef IN_RING3
     111
     112/**
     113 * Initialiizes the given flash device instance.
     114 *
     115 * @returns VBox status code.
     116 * @param   pThis               The flash device core instance.
     117 * @param   pDevIns             Pointer to the owning device instance.
     118 * @param   idFlashDev          The flash device ID.
     119 * @param   GCPhysFlashBase     Base MMIO address where the flash is located.
     120 * @param   cbFlash             Size of the flash device in bytes.
     121 * @param   cbBlock             Size of a flash block.
     122 */
     123DECLHIDDEN(int) flashR3Init(PFLASHCORE pThis, PPDMDEVINS pDevIns, uint16_t idFlashDev, uint32_t cbFlash, uint16_t cbBlock);
     124
     125/**
     126 * Destroys the given flash device instance.
     127 *
     128 * @returns nothing.
     129 * @param   pThis               The flash device core instance.
     130 */
     131DECLHIDDEN(void) flashR3Destruct(PFLASHCORE pThis);
     132
     133/**
     134 * Loads the flash content from the given file.
     135 *
     136 * @returns VBox status code.
     137 * @param   pThis               The flash device core instance.
     138 * @param   pszFilename         The file to load the flash content from.
     139 */
     140DECLHIDDEN(int) flashR3LoadFromFile(PFLASHCORE pThis, const char *pszFilename);
     141
     142/**
     143 * Loads the flash content from the given buffer.
     144 *
     145 * @returns VBox status code.
     146 * @param   pThis               The flash device core instance.
     147 * @param   pvBuf               The buffer to load the content from.
     148 * @param   cbBuf               Size of the buffer in bytes.
     149 */
     150DECLHIDDEN(int) flashR3LoadFromBuf(PFLASHCORE pThis, void *pvBuf, size_t cbBuf);
     151
     152/**
     153 * Saves the flash content to the given file.
     154 *
     155 * @returns VBox status code.
     156 * @param   pThis               The flash device core instance.
     157 * @param   pszFilename         The file to save the flash content to.
     158 */
     159DECLHIDDEN(int) flashR3SaveToFile(PFLASHCORE pThis, const char *pszFilename);
     160
     161/**
     162 * Saves the flash content to the given buffer.
     163 *
     164 * @returns VBox status code.
     165 * @param   pThis               The flash device core instance.
     166 * @param   pvBuf               The buffer to save the content to.
     167 * @param   cbBuf               Size of the buffer in bytes.
     168 */
     169DECLHIDDEN(int) flashR3SaveToBuf(PFLASHCORE pThis, void *pvBuf, size_t cbBuf);
     170
     171/**
     172 * Resets the dynamic part of the flash device state.
     173 *
     174 * @returns nothing.
     175 * @param   pThis               The flash device core instance.
     176 */
     177DECLHIDDEN(void) flashR3Reset(PFLASHCORE pThis);
     178
     179/**
     180 * Saves the flash device state to the given SSM handle.
     181 *
     182 * @returns VBox status code.
     183 * @param   pThis               The flash device core instance.
     184 * @param   pSSM                The SSM handle to save to.
     185 */
     186DECLHIDDEN(int) flashR3SsmSaveExec(PFLASHCORE pThis, PSSMHANDLE pSSM);
     187
     188/**
     189 * Loads the flash device state from the given SSM handle.
     190 *
     191 * @returns VBox status code.
     192 * @param   pThis               The flash device core instance.
     193 * @param   pSSM                The SSM handle to load from.
     194 */
     195DECLHIDDEN(int) flashR3SsmLoadExec(PFLASHCORE pThis, PSSMHANDLE pSSM);
     196
     197# endif /* IN_RING3 */
    591198
    592199#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
     200
     201RT_C_DECLS_END
     202
     203#endif /* !VBOX_INCLUDED_SRC_EFI_FlashCore_h */
     204
  • trunk/src/VBox/Devices/Makefile.kmk

    r81016 r81250  
    156156        EFI/DevSmc.cpp \
    157157        EFI/DevFlash.cpp \
     158        EFI/FlashCore.cpp \
    158159        Graphics/DevVGA.cpp \
    159160        Storage/DevATA.cpp \
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette