Message ID | acaf651389c3f407a9d6d0a2e943daf0a85bb5fc.1625704981.git.isaku.yamahata@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | TDX support | expand |
Hi, > + /* > + * If TDVF temp memory describe in TDVF metadata lays in RAM, reserve > + * the region property. > + */ > + if (entry->address >= 4 * GiB + x86ms->above_4g_mem_size || > + entry->address + entry->size >= 4 * GiB + x86ms->above_4g_mem_size) { > + error_report("TDVF type %u address 0x%" PRIx64 " size 0x%" PRIx64 > + " above high memory", > + entry->type, entry->address, entry->size); > + exit(1); > + } I think you can simply use dma_memory_map() API, then just work with guest physical addresses and drop the messy and error-prone memory region offset calculations. > + entry->mem_ptr = memory_region_get_ram_ptr(entry->mr); > + if (entry->data_len) { > + /* > + * The memory_region api doesn't allow partial file mapping, create > + * ram and copy the contents > + */ > + if (lseek(fd, entry->data_offset, SEEK_SET) != entry->data_offset) { > + error_report("can't seek to 0x%x %s", entry->data_offset, filename); > + exit(1); > + } > + if (read(fd, entry->mem_ptr, entry->data_len) != entry->data_len) { > + error_report("can't read 0x%x %s", entry->data_len, filename); > + exit(1); > + } > + } Wouldn't a simple rom_add_blob work here? > +int load_tdvf(const char *filename) > +{ > + for_each_fw_entry(fw, entry) { > + if (entry->address < x86ms->below_4g_mem_size || > + entry->address > 4 * GiB) { > + tdvf_init_ram_memory(ms, entry); > + } else { > + tdvf_init_bios_memory(fd, filename, entry); > + } > + } Why there are two different ways to load the firmware? Also: why is all this firmware volume parsing needed? The normal ovmf firmware can simply be mapped just below 4G, why can't tdvf work the same way? thanks, Gerd
On 8/26/2021 7:18 PM, Gerd Hoffmann wrote: >> +int load_tdvf(const char *filename) >> +{ > >> + for_each_fw_entry(fw, entry) { >> + if (entry->address < x86ms->below_4g_mem_size || >> + entry->address > 4 * GiB) { >> + tdvf_init_ram_memory(ms, entry); >> + } else { >> + tdvf_init_bios_memory(fd, filename, entry); >> + } >> + } > > Why there are two different ways to load the firmware? because there are two different parts in TDVF: a) one is firmware volume (BFV and CFV, i.e., OVMF_CODE.fd and OVMF_VAR.fd). Those are ROMs; b) the other is some RAM regions, e.g., temp memory for BFV early running and TD HOB to pass info to TDVF; Those are RAMs which is already added to TDX VM; > Also: why is all this firmware volume parsing needed? The normal ovmf > firmware can simply be mapped just below 4G, why can't tdvf work the > same way? Ideally, the firmware (part a above) can be mapped just below 4G like what we do for OVMF. But it needs additional when map part a) to parse the metadata and get location of part b) and initialize the RAM of part b). Yes, the additional work can be added in existing OVMF laoding flow as pflash. + Laszlo, Regarding laoding TDVF as pflash, I have some questions: - pflash requires KVM to support readonly mmeory. However, for TDX, it doesn't support readonly memory. Is it a must? or we can make an exception for TDX? - I saw from https://lists.gnu.org/archive/html/qemu-discuss/2018-04/msg00045.html, you said when load OVMF as pflash, it's MMIO. But for TDVF, it's treated as private memory. I'm not sure whether it will cause some potential problem if loading TDVF with pflash. Anyway I tried changing the existing pflash approach to load TDVF. It can boot a TDX VM and no issue. > thanks, > Gerd >
On 01/04/22 14:08, Xiaoyao Li wrote: > + Laszlo, > > Regarding laoding TDVF as pflash, I have some questions: > > - pflash requires KVM to support readonly mmeory. However, for TDX, it > doesn't support readonly memory. Is it a must? or we can make an > exception for TDX? > > - I saw from > https://lists.gnu.org/archive/html/qemu-discuss/2018-04/msg00045.html, > you said when load OVMF as pflash, it's MMIO. But for TDVF, it's treated > as private memory. I'm not sure whether it will cause some potential > problem if loading TDVF with pflash. > > Anyway I tried changing the existing pflash approach to load TDVF. It > can boot a TDX VM and no issue. I have no comments on whether TDX should or should not use pflash. If you go without pflash, then you likely will not have a standards-conformant UEFI variable store. (Unless you reimplement the variable arch protocols in edk2 on top of something else than the Fault Tolerant Write and Firmware Volume Block protocols.) Whether a conformant UEFI varstore matters to you (or to TDX in general) is something I can't comment on. (I've generally stopped commenting on confidential computing topics, but this message allows for comments on just pflash, and how it impacts OVMF.) Regarding pflash itself, the read-only KVM memslot is required for it. Otherwise pflash cannot work as a "ROMD device" (= you can't flip it back and forth between ROM mode and programming (MMIO) mode). Thanks Laszlo
On 1/7/2022 12:06 AM, Laszlo Ersek wrote: > On 01/04/22 14:08, Xiaoyao Li wrote: > >> + Laszlo, >> >> Regarding laoding TDVF as pflash, I have some questions: >> >> - pflash requires KVM to support readonly mmeory. However, for TDX, it >> doesn't support readonly memory. Is it a must? or we can make an >> exception for TDX? >> >> - I saw from >> https://lists.gnu.org/archive/html/qemu-discuss/2018-04/msg00045.html, >> you said when load OVMF as pflash, it's MMIO. But for TDVF, it's treated >> as private memory. I'm not sure whether it will cause some potential >> problem if loading TDVF with pflash. >> >> Anyway I tried changing the existing pflash approach to load TDVF. It >> can boot a TDX VM and no issue. > > I have no comments on whether TDX should or should not use pflash. > > If you go without pflash, then you likely will not have a > standards-conformant UEFI variable store. (Unless you reimplement the > variable arch protocols in edk2 on top of something else than the Fault > Tolerant Write and Firmware Volume Block protocols.) Whether a > conformant UEFI varstore matters to you (or to TDX in general) is > something I can't comment on. Thanks for your reply! Laszlo regarding "standards-conformant UEFI variable store", I guess you mean the change to UEFI non-volatile variables needs to be synced back to the OVMF_VARS.fd file. right? If so, I need to sync with internal folks who are upstreaming TDVF support into OVMF. > (I've generally stopped commenting on confidential computing topics, but > this message allows for comments on just pflash, and how it impacts OVMF.) > > Regarding pflash itself, the read-only KVM memslot is required for it. > Otherwise pflash cannot work as a "ROMD device" (= you can't flip it > back and forth between ROM mode and programming (MMIO) mode). We don't need Read-only mode for TDVF so far. If for this purpose, is it acceptable that allowing a pflash without KVM readonly memslot support if read-only is not required for the specific pflash device? We are trying to follow the existing usage of OVMF for TDX, since TDVF support will be landed in OVMF instead of a new separate binary. > Thanks > Laszlo >
> > If you go without pflash, then you likely will not have a > > standards-conformant UEFI variable store. (Unless you reimplement the > > variable arch protocols in edk2 on top of something else than the Fault > > Tolerant Write and Firmware Volume Block protocols.) Whether a > > conformant UEFI varstore matters to you (or to TDX in general) is > > something I can't comment on. > > Thanks for your reply! Laszlo > > regarding "standards-conformant UEFI variable store", I guess you mean the > change to UEFI non-volatile variables needs to be synced back to the > OVMF_VARS.fd file. right? Yes. UEFI variables are expected to be persistent, and syncing to OVMF_VARS.fd handles that. Not fully sure whenever that expectation holds up in the CC world. At least the AmdSev variant has just OVMF.fd, i.e. no CODE/VARS split. > > Regarding pflash itself, the read-only KVM memslot is required for it. > > Otherwise pflash cannot work as a "ROMD device" (= you can't flip it > > back and forth between ROM mode and programming (MMIO) mode). > > We don't need Read-only mode for TDVF so far. If for this purpose, is it > acceptable that allowing a pflash without KVM readonly memslot support if > read-only is not required for the specific pflash device? In case you don't want/need persistent VARS (which strictly speaking is a UEFI spec violation) you should be able to go for a simple "-bios OVMF.fd". take care, Gerd
On 1/10/2022 7:01 PM, Gerd Hoffmann wrote: >>> If you go without pflash, then you likely will not have a >>> standards-conformant UEFI variable store. (Unless you reimplement the >>> variable arch protocols in edk2 on top of something else than the Fault >>> Tolerant Write and Firmware Volume Block protocols.) Whether a >>> conformant UEFI varstore matters to you (or to TDX in general) is >>> something I can't comment on. >> >> Thanks for your reply! Laszlo >> >> regarding "standards-conformant UEFI variable store", I guess you mean the >> change to UEFI non-volatile variables needs to be synced back to the >> OVMF_VARS.fd file. right? > > Yes. UEFI variables are expected to be persistent, and syncing to > OVMF_VARS.fd handles that. Further question. Is it achieved via read-only memslot that when UEFI variable gets changed, it exits to QEMU with KVM_EXIT_MMIO due to read-only memslot so QEMU can sync the change to OVMF_VAR.fd? > Not fully sure whenever that expectation holds up in the CC world. At > least the AmdSev variant has just OVMF.fd, i.e. no CODE/VARS split. > >>> Regarding pflash itself, the read-only KVM memslot is required for it. >>> Otherwise pflash cannot work as a "ROMD device" (= you can't flip it >>> back and forth between ROM mode and programming (MMIO) mode). >> >> We don't need Read-only mode for TDVF so far. If for this purpose, is it >> acceptable that allowing a pflash without KVM readonly memslot support if >> read-only is not required for the specific pflash device? > > In case you don't want/need persistent VARS (which strictly speaking is > a UEFI spec violation) you should be able to go for a simple "-bios > OVMF.fd". > > take care, > Gerd >
On 01/10/22 13:09, Xiaoyao Li wrote: > On 1/10/2022 7:01 PM, Gerd Hoffmann wrote: >>>> If you go without pflash, then you likely will not have a >>>> standards-conformant UEFI variable store. (Unless you reimplement >>>> the variable arch protocols in edk2 on top of something else than >>>> the Fault Tolerant Write and Firmware Volume Block protocols.) >>>> Whether a conformant UEFI varstore matters to you (or to TDX in >>>> general) is something I can't comment on. >>> >>> Thanks for your reply! Laszlo >>> >>> regarding "standards-conformant UEFI variable store", I guess you >>> mean the >>> change to UEFI non-volatile variables needs to be synced back to the >>> OVMF_VARS.fd file. right? >> >> Yes. UEFI variables are expected to be persistent, and syncing to >> OVMF_VARS.fd handles that. > > Further question. > > Is it achieved via read-only memslot that when UEFI variable gets > changed, it exits to QEMU with KVM_EXIT_MMIO due to read-only memslot > so QEMU can sync the change to OVMF_VAR.fd? Yes. When the flash device is in "romd_mode", that's when a readonly KVM memslot is used. In this case, the guest can read and execute from the memory region in question, only writes trap to QEMU. Such a write (WRITE_BYTE_CMD) is what the guest's flash driver uses to flip the flash device out of "romd_mode". When the flash device is not in "romd_mode", then no KVM memslot is used at all, and both reads and writes trap to QEMU. Once the flash programming is done, the guest's flash driver issues a particular write command (READ_ARRAY_CMD) that flips the device back to "romd_mode" (and then the readonly KVM memslot is re-established). Here's a rough call tree (for the non-SMM case, updating a non-authenticated non-volatile variable): VariableServiceSetVariable() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] UpdateVariable() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] UpdateVariableStore() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] FvbProtocolWrite() [OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c] QemuFlashWrite() [OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c] QemuFlashPtrWrite (WRITE_BYTE_CMD /* 0x10 */) QEMU: pflash_write() [hw/block/pflash_cfi01.c] (wcycle == 0) memory_region_rom_device_set_romd(false) [softmmu/memory.c] ... kvm_region_del() [accel/kvm/kvm-all.c] kvm_set_phys_mem(false) [accel/kvm/kvm-all.c] /* unregister the slot */ /* Single Byte Program */ wcycle++ QemuFlashPtrWrite (Buffer[Loop]) QEMU: pflash_write() [hw/block/pflash_cfi01.c] (wcycle == 1) /* Single Byte Program */ pflash_data_write() [hw/block/pflash_cfi01.c] pflash_update() [hw/block/pflash_cfi01.c] blk_pwrite() [block/block-backend.c] wcycle = 0 QemuFlashPtrWrite (READ_ARRAY_CMD /* 0xff */) QEMU: pflash_write() [hw/block/pflash_cfi01.c] (wcycle == 0) memory_region_rom_device_set_romd(false) [softmmu/memory.c] /* no actual change */ /* Read Array */ memory_region_rom_device_set_romd(true) [softmmu/memory.c] kvm_region_add() [accel/kvm/kvm-all.c] kvm_set_phys_mem(true) [accel/kvm/kvm-all.c] /* register the new slot */ kvm_mem_flags() [accel/kvm/kvm-all.c] ... memory_region_is_romd() ... [include/exec/memory.h] flags |= KVM_MEM_READONLY Thanks Laszlo
On 01/11/22 09:19, Laszlo Ersek wrote: > Here's a rough call tree (for the non-SMM case, updating a > non-authenticated non-volatile variable): > > VariableServiceSetVariable() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] > UpdateVariable() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] > UpdateVariableStore() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] > FvbProtocolWrite() [OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c] > QemuFlashWrite() [OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c] > > QemuFlashPtrWrite (WRITE_BYTE_CMD /* 0x10 */) > QEMU: > pflash_write() [hw/block/pflash_cfi01.c] > (wcycle == 0) > memory_region_rom_device_set_romd(false) [softmmu/memory.c] > ... > kvm_region_del() [accel/kvm/kvm-all.c] > kvm_set_phys_mem(false) [accel/kvm/kvm-all.c] > /* unregister the slot */ > > /* Single Byte Program */ > wcycle++ > > QemuFlashPtrWrite (Buffer[Loop]) > QEMU: > pflash_write() [hw/block/pflash_cfi01.c] > (wcycle == 1) > /* Single Byte Program */ > pflash_data_write() [hw/block/pflash_cfi01.c] > pflash_update() [hw/block/pflash_cfi01.c] > blk_pwrite() [block/block-backend.c] > wcycle = 0 > > QemuFlashPtrWrite (READ_ARRAY_CMD /* 0xff */) > QEMU: > pflash_write() [hw/block/pflash_cfi01.c] > (wcycle == 0) > memory_region_rom_device_set_romd(false) [softmmu/memory.c] > /* no actual change */ > /* Read Array */ > memory_region_rom_device_set_romd(true) [softmmu/memory.c] > kvm_region_add() [accel/kvm/kvm-all.c] > kvm_set_phys_mem(true) [accel/kvm/kvm-all.c] > /* register the new slot */ > kvm_mem_flags() [accel/kvm/kvm-all.c] > ... memory_region_is_romd() ... [include/exec/memory.h] > flags |= KVM_MEM_READONLY In that call tree, I ignored Reclaim() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c]; Reclaim() is called from more places than just from UpdateVariable(). In Reclaim(), we (roughly) have Reclaim() [MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c] FtwVariableSpace() [MdeModulePkg/Universal/Variable/RuntimeDxe/Reclaim.c] FtwWrite() [MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c] QemuFlashWrite() [OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c] For a bit more info on the internals of FtwWrite(), see the attached message (I'd provide a URL, but Intel had killed the edk2-devel archives on lists.01.org, and the other archives don't go back to 2014...) Thanks Laszlo On 04/18/14 21:32, Kirkendall, Garrett wrote: > Is there any good documentation for how the Fault Tolerant Write is > supposed to work? > > I understand that NV storage, FTW working space and FTW spare space are > supposed to be in the same Firmware Volume. > > I’m having trouble deciphering how big the FTW working and spare areas > should be in relation to the NV storage space. > > Also, in a bunch of places, it looks like the code was written such that > the working space must fit within one block size. What happens if need > space spanning multiple blocks? Below are parts from two functions that > end in an ASSERT because only one block gets read and returns an error > when the requested FVB->Read input size is larger than one block of data. If it's any help, here's a diagram I derived last December, while I was hunting down <https://github.com/tianocore/edk2/commit/06f1982a>: On 12/17/13 07:16, Laszlo Ersek wrote: > During reclaim, the following data movements take place (I'm skipping > the erasures and the in-memory buffer manipulations): > > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ L: event log > LIVE | varstore |L|W| W: working block > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ > > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ > SPARE | | > +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ > > (1) copy LIVE to MyBuffer > (2) copy SPARE to SpareBuffer > (3) copy MyBuffer to SPARE > (4) copy SPARE to Buffer > (5) copy Buffer to LIVE > (6) copy SpareBuffer to SPARE (MyBuffer, SpareBuffer, and Buffer are temporary memory buffers.) In OVMF, the block size is 4K. The varstore is 14 blocks (56K), plus we got one block (4K) for the event log and one block (4K) for the working block. In total, 64K in the live half. The spare half is the same size, giving 128K total for the firmware volume. I'm also attaching the debug patch I wrote at that time for the FTW and auth variable services, plus its output (which I annotated during analysis) that helped me understand what was happening. Maybe you can reuse something from them. Laszlo Reclaim: enter, VariableBase=0xFFE00048, IsVolatile=0, NewVariableSize=0x0, ReclaimPubKeyStore=0 FtwVariableSpace:/home/lacos/src/upstream/edk2-git-svn/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c: enter FvbProtocolGetAttributes: enter FvbGetVolumeAttributes: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetVolumeAttributes: exit @ 320, Status=Success, Attributes=0x4FEFF FvbProtocolGetAttributes: exit @ 704, Status=Success FvbProtocolGetPhysicalAddress: enter FvbGetPhysicalAddress: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetPhysicalAddress: exit @ 275, Status=Success, Address=0xFFE00000 FvbProtocolGetPhysicalAddress: exit @ 620, Status=Success FvbProtocolGetAttributes: enter FvbGetVolumeAttributes: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetVolumeAttributes: exit @ 320, Status=Success, Attributes=0x4FEFF FvbProtocolGetAttributes: exit @ 704, Status=Success FvbProtocolGetPhysicalAddress: enter FvbGetPhysicalAddress: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetPhysicalAddress: exit @ 275, Status=Success, Address=0xFFE00000 FvbProtocolGetPhysicalAddress: exit @ 620, Status=Success FvbProtocolGetPhysicalAddress: enter FvbGetPhysicalAddress: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetPhysicalAddress: exit @ 275, Status=Success, Address=0xFFE00000 FvbProtocolGetPhysicalAddress: exit @ 620, Status=Success FtwWrite: enter, Lba=0x0 Offset=0x48 Length=0xDFB8 PrivateData=0 FvBlockHandle=9F58E798 Buffer=9F7BE060 WorkSpaceRefresh: enter FvbProtocolRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9EBEF0E0 QemuFlashRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9EBEF0E0 QemuFlashPtr: enter, Lba=0xF Offset=0x0 QemuFlashPtr: exit, Ret=FFE0F000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FtwGetLastWriteHeader: enter, FtwWorkSpaceSize=0x1000 FtwGetLastWriteHeader: exit @ 881, Status=Success Ftw: Remaining work space size - 590 FtwGetLastWriteRecord: enter FtwGetLastWriteRecord: exit @ 924, Status=Success WorkSpaceRefresh: exit 6 IsErasedFlashBuffer: enter, Buffer=9EBEFB50 BufferSize=0x28 IsErasedFlashBuffer: exit, IsEmpty=1 FtwAllocate: enter, CallerId=FE5CEA76-4F72-49E8-986F-2CD899DFFE5D, PrivateDataSize=0x0, NumberOfWrites=0x1 WorkSpaceRefresh: enter FvbProtocolRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9EBEF0E0 QemuFlashRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9EBEF0E0 QemuFlashPtr: enter, Lba=0xF Offset=0x0 QemuFlashPtr: exit, Ret=FFE0F000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FtwGetLastWriteHeader: enter, FtwWorkSpaceSize=0x1000 FtwGetLastWriteHeader: exit @ 881, Status=Success Ftw: Remaining work space size - 590 FtwGetLastWriteRecord: enter FtwGetLastWriteRecord: exit @ 924, Status=Success WorkSpaceRefresh: exit 6 FvbProtocolWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x28 Buffer=9EBEFB50 QemuFlashWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x28 Buffer=9EBEFB50 QemuFlashPtr: enter, Lba=0xF Offset=0xA70 QemuFlashPtr: exit, Ret=FFE0FA70 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x28 FtwUpdateFvState: enter, Lba=0xF Offset=0xA70 NewBit=2 FvbProtocolRead: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852647 QemuFlashRead: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852647 QemuFlashPtr: enter, Lba=0xF Offset=0xA70 QemuFlashPtr: exit, Ret=FFE0FA70 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852647 QemuFlashWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852647 QemuFlashPtr: enter, Lba=0xF Offset=0xA70 QemuFlashPtr: exit, Ret=FFE0FA70 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success Ftw: Allocate() success, Caller:FE5CEA76-4F72-49E8-986F-2CD899DFFE5D, # 1 FtwAllocate: exit 7 FtwGetFvbByHandle: enter FtwGetFvbByHandle: exit: Success FvbProtocolGetPhysicalAddress: enter FvbGetPhysicalAddress: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success FvbGetPhysicalAddress: exit @ 275, Status=Success, Address=0xFFE00000 FvbProtocolGetPhysicalAddress: exit @ 620, Status=Success IsBootBlock: enter, Lba=0x0 FtwGetSarProtocol: enter FtwGetSarProtocol: exit: Not Found IsBootBlock: exit 2: Not Found FvbProtocolWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x28 Buffer=9EBEFB78 QemuFlashWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x28 Buffer=9EBEFB78 QemuFlashPtr: enter, Lba=0xF Offset=0xA98 QemuFlashPtr: exit, Ret=FFE0FA98 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x28 // // Read all original data from target block to memory buffer // FvbProtocolRead: enter, Lba=0x0 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashRead: enter, Lba=0x0 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashPtr: enter, Lba=0x0 Offset=0x0 QemuFlashPtr: exit, Ret=FFE00000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashRead: enter, Lba=0x1 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashPtr: enter, Lba=0x1 Offset=0x0 QemuFlashPtr: exit, Ret=FFE01000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x2 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashRead: enter, Lba=0x2 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashPtr: enter, Lba=0x2 Offset=0x0 QemuFlashPtr: exit, Ret=FFE02000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x3 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashRead: enter, Lba=0x3 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashPtr: enter, Lba=0x3 Offset=0x0 QemuFlashPtr: exit, Ret=FFE03000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x4 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashRead: enter, Lba=0x4 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashPtr: enter, Lba=0x4 Offset=0x0 QemuFlashPtr: exit, Ret=FFE04000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x5 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashRead: enter, Lba=0x5 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashPtr: enter, Lba=0x5 Offset=0x0 QemuFlashPtr: exit, Ret=FFE05000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x6 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashRead: enter, Lba=0x6 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashPtr: enter, Lba=0x6 Offset=0x0 QemuFlashPtr: exit, Ret=FFE06000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x7 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashRead: enter, Lba=0x7 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashPtr: enter, Lba=0x7 Offset=0x0 QemuFlashPtr: exit, Ret=FFE07000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x8 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashRead: enter, Lba=0x8 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashPtr: enter, Lba=0x8 Offset=0x0 QemuFlashPtr: exit, Ret=FFE08000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x9 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashRead: enter, Lba=0x9 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashPtr: enter, Lba=0x9 Offset=0x0 QemuFlashPtr: exit, Ret=FFE09000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xA Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashRead: enter, Lba=0xA Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashPtr: enter, Lba=0xA Offset=0x0 QemuFlashPtr: exit, Ret=FFE0A000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xB Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashRead: enter, Lba=0xB Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashPtr: enter, Lba=0xB Offset=0x0 QemuFlashPtr: exit, Ret=FFE0B000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xC Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashRead: enter, Lba=0xC Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashPtr: enter, Lba=0xC Offset=0x0 QemuFlashPtr: exit, Ret=FFE0C000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xD Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashRead: enter, Lba=0xD Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashPtr: enter, Lba=0xD Offset=0x0 QemuFlashPtr: exit, Ret=FFE0D000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xE Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashRead: enter, Lba=0xE Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashPtr: enter, Lba=0xE Offset=0x0 QemuFlashPtr: exit, Ret=FFE0E000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashRead: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashPtr: enter, Lba=0xF Offset=0x0 QemuFlashPtr: exit, Ret=FFE0F000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 // // Try to keep the content of spare block // Save spare block into a spare backup memory buffer (Sparebuffer) // FvbProtocolRead: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C7F5018 QemuFlashRead: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C7F5018 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C7F6018 QemuFlashRead: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C7F6018 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C7F7018 QemuFlashRead: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C7F7018 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C7F8018 QemuFlashRead: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C7F8018 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C7F9018 QemuFlashRead: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C7F9018 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C7FA018 QemuFlashRead: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C7FA018 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C7FB018 QemuFlashRead: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C7FB018 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C7FC018 QemuFlashRead: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C7FC018 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C7FD018 QemuFlashRead: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C7FD018 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C7FE018 QemuFlashRead: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C7FE018 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C7FF018 QemuFlashRead: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C7FF018 QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C800018 QemuFlashRead: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C800018 QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C801018 QemuFlashRead: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C801018 QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C802018 QemuFlashRead: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C802018 QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C803018 QemuFlashRead: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C803018 QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C804018 QemuFlashRead: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C804018 QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 // // Write the memory buffer to spare block // FtwEraseSpareBlock: enter FvbProtocolEraseBlocks: enter GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success QemuFlashEraseBlock: enter, Lba=0x10 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x11 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x12 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x13 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x14 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x15 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x16 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x17 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x18 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x19 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1A QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1B QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1C QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1D QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1E QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1F QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashEraseBlock: exit 2 FvbProtocolEraseBlocks: exit @ 839, Status=Success FtwEraseSpareBlock: exit: Success FvbProtocolWrite: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashWrite: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashWrite: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashWrite: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashWrite: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashWrite: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashWrite: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashWrite: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashWrite: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashWrite: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashWrite: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashWrite: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashWrite: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashWrite: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashWrite: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashWrite: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 !!! out-of-varstore write !!! FvbProtocolWrite: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashWrite: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 // // Set the SpareComplete in the FTW record, // FtwUpdateFvState: enter, Lba=0xF Offset=0xA98 NewBit=2 FvbProtocolRead: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F8526C7 QemuFlashRead: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F8526C7 QemuFlashPtr: enter, Lba=0xF Offset=0xA98 QemuFlashPtr: exit, Ret=FFE0FA98 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F8526C7 QemuFlashWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F8526C7 QemuFlashPtr: enter, Lba=0xF Offset=0xA98 QemuFlashPtr: exit, Ret=FFE0FA98 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success // // Since the content has already backuped in spare block, the write is // guaranteed to be completed with fault tolerant manner. // FtwWriteRecord: enter // // IF target block is working block, THEN Flush Spare Block To Working Block; // ELSE flush spare block to target block, which may be boot block after all. // IsWorkingBlock: enter, Lba=0x0 IsWorkingBlock: exit: 1 FtwUpdateFvState: enter, Lba=0x1F Offset=0xA98 NewBit=2 FvbProtocolRead: enter, Lba=0x1F Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashRead: enter, Lba=0x1F Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0x1F Offset=0xA98 QemuFlashPtr: exit, Ret=FFE1FA98 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0x1F Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashWrite: enter, Lba=0x1F Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0x1F Offset=0xA98 QemuFlashPtr: exit, Ret=FFE1FA98 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success FlushSpareBlockToWorkingBlock: enter FtwUpdateFvState: enter, Lba=0x1F Offset=0x14 NewBit=1 FvbProtocolRead: enter, Lba=0x1F Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashRead: enter, Lba=0x1F Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0x1F Offset=0x14 QemuFlashPtr: exit, Ret=FFE1F014 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0x1F Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashWrite: enter, Lba=0x1F Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0x1F Offset=0x14 QemuFlashPtr: exit, Ret=FFE1F014 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success // // Read from spare block to memory buffer // FvbProtocolRead: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashRead: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashRead: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashRead: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashRead: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashRead: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashRead: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashRead: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashRead: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashRead: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashRead: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashRead: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashRead: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashRead: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashRead: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashRead: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 FvbProtocolRead: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashRead: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1000 // // Clear the CRC and STATE, copy data from spare to working block. // InitWorkSpaceHeader: enter InitWorkSpaceHeader: exit 2 // // target block is working block, then // Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER // before erase the working block. // FtwUpdateFvState: enter, Lba=0xF Offset=0x14 NewBit=2 FvbProtocolRead: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashRead: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0xF Offset=0x14 QemuFlashPtr: exit, Ret=FFE0F014 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashWrite: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0xF Offset=0x14 QemuFlashPtr: exit, Ret=FFE0F014 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success // // Erase the working block // FtwEraseBlock: enter, Lba=0x0 FvbProtocolEraseBlocks: enter GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success QemuFlashEraseBlock: enter, Lba=0x0 QemuFlashPtr: enter, Lba=0x0 Offset=0x0 QemuFlashPtr: exit, Ret=FFE00000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1 QemuFlashPtr: enter, Lba=0x1 Offset=0x0 QemuFlashPtr: exit, Ret=FFE01000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x2 QemuFlashPtr: enter, Lba=0x2 Offset=0x0 QemuFlashPtr: exit, Ret=FFE02000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x3 QemuFlashPtr: enter, Lba=0x3 Offset=0x0 QemuFlashPtr: exit, Ret=FFE03000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x4 QemuFlashPtr: enter, Lba=0x4 Offset=0x0 QemuFlashPtr: exit, Ret=FFE04000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x5 QemuFlashPtr: enter, Lba=0x5 Offset=0x0 QemuFlashPtr: exit, Ret=FFE05000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x6 QemuFlashPtr: enter, Lba=0x6 Offset=0x0 QemuFlashPtr: exit, Ret=FFE06000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x7 QemuFlashPtr: enter, Lba=0x7 Offset=0x0 QemuFlashPtr: exit, Ret=FFE07000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x8 QemuFlashPtr: enter, Lba=0x8 Offset=0x0 QemuFlashPtr: exit, Ret=FFE08000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x9 QemuFlashPtr: enter, Lba=0x9 Offset=0x0 QemuFlashPtr: exit, Ret=FFE09000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xA QemuFlashPtr: enter, Lba=0xA Offset=0x0 QemuFlashPtr: exit, Ret=FFE0A000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xB QemuFlashPtr: enter, Lba=0xB Offset=0x0 QemuFlashPtr: exit, Ret=FFE0B000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xC QemuFlashPtr: enter, Lba=0xC Offset=0x0 QemuFlashPtr: exit, Ret=FFE0C000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xD QemuFlashPtr: enter, Lba=0xD Offset=0x0 QemuFlashPtr: exit, Ret=FFE0D000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xE QemuFlashPtr: enter, Lba=0xE Offset=0x0 QemuFlashPtr: exit, Ret=FFE0E000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0xF QemuFlashPtr: enter, Lba=0xF Offset=0x0 QemuFlashPtr: exit, Ret=FFE0F000 QemuFlashEraseBlock: exit 2 FvbProtocolEraseBlocks: exit @ 839, Status=Success FtwEraseBlock: exit: Success // // Write memory buffer to working block, using the FvbBlock protocol interface // FvbProtocolWrite: enter, Lba=0x0 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashWrite: enter, Lba=0x0 Offset=0x0 NumBytes=0x1000 Buffer=9C806018 QemuFlashPtr: enter, Lba=0x0 Offset=0x0 QemuFlashPtr: exit, Ret=FFE00000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashWrite: enter, Lba=0x1 Offset=0x0 NumBytes=0x1000 Buffer=9C807018 QemuFlashPtr: enter, Lba=0x1 Offset=0x0 QemuFlashPtr: exit, Ret=FFE01000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x2 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashWrite: enter, Lba=0x2 Offset=0x0 NumBytes=0x1000 Buffer=9C808018 QemuFlashPtr: enter, Lba=0x2 Offset=0x0 QemuFlashPtr: exit, Ret=FFE02000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x3 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashWrite: enter, Lba=0x3 Offset=0x0 NumBytes=0x1000 Buffer=9C809018 QemuFlashPtr: enter, Lba=0x3 Offset=0x0 QemuFlashPtr: exit, Ret=FFE03000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x4 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashWrite: enter, Lba=0x4 Offset=0x0 NumBytes=0x1000 Buffer=9C80A018 QemuFlashPtr: enter, Lba=0x4 Offset=0x0 QemuFlashPtr: exit, Ret=FFE04000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x5 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashWrite: enter, Lba=0x5 Offset=0x0 NumBytes=0x1000 Buffer=9C80B018 QemuFlashPtr: enter, Lba=0x5 Offset=0x0 QemuFlashPtr: exit, Ret=FFE05000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x6 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashWrite: enter, Lba=0x6 Offset=0x0 NumBytes=0x1000 Buffer=9C80C018 QemuFlashPtr: enter, Lba=0x6 Offset=0x0 QemuFlashPtr: exit, Ret=FFE06000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x7 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashWrite: enter, Lba=0x7 Offset=0x0 NumBytes=0x1000 Buffer=9C80D018 QemuFlashPtr: enter, Lba=0x7 Offset=0x0 QemuFlashPtr: exit, Ret=FFE07000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x8 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashWrite: enter, Lba=0x8 Offset=0x0 NumBytes=0x1000 Buffer=9C80E018 QemuFlashPtr: enter, Lba=0x8 Offset=0x0 QemuFlashPtr: exit, Ret=FFE08000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x9 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashWrite: enter, Lba=0x9 Offset=0x0 NumBytes=0x1000 Buffer=9C80F018 QemuFlashPtr: enter, Lba=0x9 Offset=0x0 QemuFlashPtr: exit, Ret=FFE09000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xA Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashWrite: enter, Lba=0xA Offset=0x0 NumBytes=0x1000 Buffer=9C810018 QemuFlashPtr: enter, Lba=0xA Offset=0x0 QemuFlashPtr: exit, Ret=FFE0A000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xB Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashWrite: enter, Lba=0xB Offset=0x0 NumBytes=0x1000 Buffer=9C811018 QemuFlashPtr: enter, Lba=0xB Offset=0x0 QemuFlashPtr: exit, Ret=FFE0B000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xC Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashWrite: enter, Lba=0xC Offset=0x0 NumBytes=0x1000 Buffer=9C812018 QemuFlashPtr: enter, Lba=0xC Offset=0x0 QemuFlashPtr: exit, Ret=FFE0C000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xD Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashWrite: enter, Lba=0xD Offset=0x0 NumBytes=0x1000 Buffer=9C813018 QemuFlashPtr: enter, Lba=0xD Offset=0x0 QemuFlashPtr: exit, Ret=FFE0D000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xE Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashWrite: enter, Lba=0xE Offset=0x0 NumBytes=0x1000 Buffer=9C814018 QemuFlashPtr: enter, Lba=0xE Offset=0x0 QemuFlashPtr: exit, Ret=FFE0E000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashWrite: enter, Lba=0xF Offset=0x0 NumBytes=0x1000 Buffer=9C815018 QemuFlashPtr: enter, Lba=0xF Offset=0x0 QemuFlashPtr: exit, Ret=FFE0F000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 // // Update the VALID of the working block // FtwUpdateFvState: enter, Lba=0xF Offset=0x14 NewBit=1 FvbProtocolRead: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashRead: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0xF Offset=0x14 QemuFlashPtr: exit, Ret=FFE0F014 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashWrite: enter, Lba=0xF Offset=0x14 NumBytes=0x1 Buffer=9F8525D7 QemuFlashPtr: enter, Lba=0xF Offset=0x14 QemuFlashPtr: exit, Ret=FFE0F014 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success FlushSpareBlockToWorkingBlock: exit @ 765, Status=Success // // Record the DestionationComplete in record // FtwUpdateFvState: enter, Lba=0xF Offset=0xA98 NewBit=4 FvbProtocolRead: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashRead: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0xF Offset=0xA98 QemuFlashPtr: exit, Ret=FFE0FA98 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashWrite: enter, Lba=0xF Offset=0xA98 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0xF Offset=0xA98 QemuFlashPtr: exit, Ret=FFE0FA98 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success // // If this is the last Write in these write sequence, // set the complete flag of write header. // IsLastRecordOfWrites: enter IsLastRecordOfWrites: exit: 1 FtwUpdateFvState: enter, Lba=0xF Offset=0xA70 NewBit=4 FvbProtocolRead: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852657 QemuFlashRead: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0xF Offset=0xA70 QemuFlashPtr: exit, Ret=FFE0FA70 QemuFlashRead: exit 2 FvbProtocolRead: exit @ 944, Status=Success, NumBytes=0x1 FvbProtocolWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852657 QemuFlashWrite: enter, Lba=0xF Offset=0xA70 NumBytes=0x1 Buffer=9F852657 QemuFlashPtr: enter, Lba=0xF Offset=0xA70 QemuFlashPtr: exit, Ret=FFE0FA70 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1 FtwUpdateFvState: exit @ 824, Status=Success FtwWriteRecord: exit 5 // // Restore spare backup buffer into spare block , if no failure happened during FtwWrite. // FtwEraseSpareBlock: enter FvbProtocolEraseBlocks: enter GetFvbInstance: enter, Instance=0x0, Global=9F7DAF18, Virtual=0 GetFvbInstance: exit @ 229, Status=Success QemuFlashEraseBlock: enter, Lba=0x10 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x11 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x12 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x13 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x14 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x15 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x16 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x17 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x18 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x19 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1A QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1B QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1C QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1D QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1E QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashEraseBlock: exit 2 QemuFlashEraseBlock: enter, Lba=0x1F QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashEraseBlock: exit 2 FvbProtocolEraseBlocks: exit @ 839, Status=Success FtwEraseSpareBlock: exit: Success FvbProtocolWrite: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C7F5018 QemuFlashWrite: enter, Lba=0x10 Offset=0x0 NumBytes=0x1000 Buffer=9C7F5018 QemuFlashPtr: enter, Lba=0x10 Offset=0x0 QemuFlashPtr: exit, Ret=FFE10000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C7F6018 QemuFlashWrite: enter, Lba=0x11 Offset=0x0 NumBytes=0x1000 Buffer=9C7F6018 QemuFlashPtr: enter, Lba=0x11 Offset=0x0 QemuFlashPtr: exit, Ret=FFE11000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C7F7018 QemuFlashWrite: enter, Lba=0x12 Offset=0x0 NumBytes=0x1000 Buffer=9C7F7018 QemuFlashPtr: enter, Lba=0x12 Offset=0x0 QemuFlashPtr: exit, Ret=FFE12000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C7F8018 QemuFlashWrite: enter, Lba=0x13 Offset=0x0 NumBytes=0x1000 Buffer=9C7F8018 QemuFlashPtr: enter, Lba=0x13 Offset=0x0 QemuFlashPtr: exit, Ret=FFE13000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C7F9018 QemuFlashWrite: enter, Lba=0x14 Offset=0x0 NumBytes=0x1000 Buffer=9C7F9018 QemuFlashPtr: enter, Lba=0x14 Offset=0x0 QemuFlashPtr: exit, Ret=FFE14000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C7FA018 QemuFlashWrite: enter, Lba=0x15 Offset=0x0 NumBytes=0x1000 Buffer=9C7FA018 QemuFlashPtr: enter, Lba=0x15 Offset=0x0 QemuFlashPtr: exit, Ret=FFE15000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C7FB018 QemuFlashWrite: enter, Lba=0x16 Offset=0x0 NumBytes=0x1000 Buffer=9C7FB018 QemuFlashPtr: enter, Lba=0x16 Offset=0x0 QemuFlashPtr: exit, Ret=FFE16000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C7FC018 QemuFlashWrite: enter, Lba=0x17 Offset=0x0 NumBytes=0x1000 Buffer=9C7FC018 QemuFlashPtr: enter, Lba=0x17 Offset=0x0 QemuFlashPtr: exit, Ret=FFE17000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C7FD018 QemuFlashWrite: enter, Lba=0x18 Offset=0x0 NumBytes=0x1000 Buffer=9C7FD018 QemuFlashPtr: enter, Lba=0x18 Offset=0x0 QemuFlashPtr: exit, Ret=FFE18000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C7FE018 QemuFlashWrite: enter, Lba=0x19 Offset=0x0 NumBytes=0x1000 Buffer=9C7FE018 QemuFlashPtr: enter, Lba=0x19 Offset=0x0 QemuFlashPtr: exit, Ret=FFE19000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C7FF018 QemuFlashWrite: enter, Lba=0x1A Offset=0x0 NumBytes=0x1000 Buffer=9C7FF018 QemuFlashPtr: enter, Lba=0x1A Offset=0x0 QemuFlashPtr: exit, Ret=FFE1A000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C800018 QemuFlashWrite: enter, Lba=0x1B Offset=0x0 NumBytes=0x1000 Buffer=9C800018 QemuFlashPtr: enter, Lba=0x1B Offset=0x0 QemuFlashPtr: exit, Ret=FFE1B000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C801018 QemuFlashWrite: enter, Lba=0x1C Offset=0x0 NumBytes=0x1000 Buffer=9C801018 QemuFlashPtr: enter, Lba=0x1C Offset=0x0 QemuFlashPtr: exit, Ret=FFE1C000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C802018 QemuFlashWrite: enter, Lba=0x1D Offset=0x0 NumBytes=0x1000 Buffer=9C802018 QemuFlashPtr: enter, Lba=0x1D Offset=0x0 QemuFlashPtr: exit, Ret=FFE1D000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 FvbProtocolWrite: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C803018 QemuFlashWrite: enter, Lba=0x1E Offset=0x0 NumBytes=0x1000 Buffer=9C803018 QemuFlashPtr: enter, Lba=0x1E Offset=0x0 QemuFlashPtr: exit, Ret=FFE1E000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 !!! out-of-varstore write !!! FvbProtocolWrite: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C804018 QemuFlashWrite: enter, Lba=0x1F Offset=0x0 NumBytes=0x1000 Buffer=9C804018 QemuFlashPtr: enter, Lba=0x1F Offset=0x0 QemuFlashPtr: exit, Ret=FFE1F000 QemuFlashWrite: exit 2 FvbProtocolWrite: exit @ 891, Status=Success, NumBytes=0x1000 // // All success. // Ftw: Write() success, (Lba:Offset)=(0:0x48), Length: 0xDFB8 FtwWrite: exit 20 FtwVariableSpace: exit @ 167, Status=Success
On 1/10/2022 7:01 PM, Gerd Hoffmann wrote: >>> Regarding pflash itself, the read-only KVM memslot is required for it. >>> Otherwise pflash cannot work as a "ROMD device" (= you can't flip it >>> back and forth between ROM mode and programming (MMIO) mode). >> >> We don't need Read-only mode for TDVF so far. If for this purpose, is it >> acceptable that allowing a pflash without KVM readonly memslot support if >> read-only is not required for the specific pflash device? > > In case you don't want/need persistent VARS (which strictly speaking is > a UEFI spec violation) you should be able to go for a simple "-bios > OVMF.fd". > Gerd and Laszlo, First, thank you for your patient explanation of how pflash works in QEMU and the clarification of usage of pflash with OVMF. Below I want to share current situation of loading TDVF. Restrictions from TDX architecture: - Current TDX doesn't support read-only memory, i.e., cannot trap write. - Current TDVF spec states that "In order to simplify the design, TDVF does not support non-volatile variables" in chapter 8.3.3 Regarding what interface should be used to load TDVF, there are three options: 1) pflash: the same as how we load OVMF. Suppose TDVF support will finally get into OVMF, using this interface, it's full compatible with normal VMs. No change required to QEMU command line and TDVF binary is mapped to the GPA address right below 4G, but they are actually mapped as RAM. Of course, we need several hacks (special handling) in QEMU. Of course, they don't work as flash, the change made to it doesn't persist. 2) -bios exploit "-bios" parameter to load TDVF. But again, read-only is not supported. TDVF is mapped as RAM. 3) generic loader Just like what this series does. Implement specific parser in generic loader to load and parse TDVF as private RAM. I'm nor sure if 1) is acceptable from your side. If not, we will go with option 3, since 2) doesn't make too much sense.
> Regarding what interface should be used to load TDVF, there are three > options: > > 1) pflash: the same as how we load OVMF. > > Suppose TDVF support will finally get into OVMF, using this > interface, it's full compatible with normal VMs. No change required > to QEMU command line and TDVF binary is mapped to the GPA address > right below 4G, but they are actually mapped as RAM. > > Of course, we need several hacks (special handling) in QEMU. What kind if "hack"? > Of course, they don't work as flash, the change made to it doesn't > persist. > > 2) -bios > > exploit "-bios" parameter to load TDVF. But again, read-only is not > supported. TDVF is mapped as RAM. > > 3) generic loader > > Just like what this series does. Implement specific parser in generic > loader to load and parse TDVF as private RAM. > > I'm nor sure if 1) is acceptable from your side. If not, we will go with > option 3, since 2) doesn't make too much sense. Yep, Daniel (Cc'ed) tried (2) recently for SEV. Didn't work due to differences in -bios and -pflash reset handling. So that option is out I guess. SEV uses (1), and there is some support code which you should be able to reuse (walker for the list of guid-sections with meta-data in the ovmf reset vector for example). So TDX going for (1) too is probably the best option. take care, Gerd
On 1/25/2022 3:42 PM, Gerd Hoffmann wrote: >> Regarding what interface should be used to load TDVF, there are three >> options: >> >> 1) pflash: the same as how we load OVMF. >> >> Suppose TDVF support will finally get into OVMF, using this >> interface, it's full compatible with normal VMs. No change required >> to QEMU command line and TDVF binary is mapped to the GPA address >> right below 4G, but they are actually mapped as RAM. >> >> Of course, we need several hacks (special handling) in QEMU. > > What kind if "hack"? For example, several pflash codes require the support of read-only memslot from KVM. We need to absolve it for TDX guest. And the pflash won't work as a flash device that no write induced KVM_EXIT_MMIO will go to its callback. >> Of course, they don't work as flash, the change made to it doesn't >> persist. >> >> 2) -bios >> >> exploit "-bios" parameter to load TDVF. But again, read-only is not >> supported. TDVF is mapped as RAM. >> >> 3) generic loader >> >> Just like what this series does. Implement specific parser in generic >> loader to load and parse TDVF as private RAM. >> >> I'm nor sure if 1) is acceptable from your side. If not, we will go with >> option 3, since 2) doesn't make too much sense. > > Yep, Daniel (Cc'ed) tried (2) recently for SEV. Didn't work due to > differences in -bios and -pflash reset handling. So that option is > out I guess. > > SEV uses (1), and there is some support code which you should be able to > reuse (walker for the list of guid-sections with meta-data in the ovmf > reset vector for example). > > So TDX going for (1) too is probably the best option. Yes. With option 1), it's friendly to user that no command change. And also compatible for future TDX/TDVF when non-volatile variable is supported. Next version of this series will go with option 1). Let's wait and see if the real implementation is acceptable or not. > take care, > Gerd >
diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index d14f932eea..ee2f49b47a 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -34,6 +34,7 @@ #include "hw/core/cpu.h" #include "sysemu/dma.h" #include "sysemu/reset.h" +#include "sysemu/tdvf.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/qdev-properties.h" @@ -147,6 +148,10 @@ static void generic_loader_realize(DeviceState *dev, Error **errp) as); } + if (size < 0) { + size = load_tdvf(s->file); + } + if (size < 0) { size = load_targphys_hex_as(s->file, &entry, as); } diff --git a/hw/core/meson.build b/hw/core/meson.build index 18f44fb7c2..ec943debf1 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -24,6 +24,9 @@ common_ss.add(when: 'CONFIG_REGISTER', if_true: files('register.c')) common_ss.add(when: 'CONFIG_SPLIT_IRQ', if_true: files('split-irq.c')) common_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) +common_ss.add(when: 'CONFIG_TDX', if_false: files('tdvf-stub.c')) +common_ss.add(when: 'CONFIG_ALL', if_true: files('tdvf-stub.c')) + softmmu_ss.add(files( 'cpu-sysemu.c', 'fw-path-provider.c', diff --git a/hw/core/tdvf-stub.c b/hw/core/tdvf-stub.c new file mode 100644 index 0000000000..5f2586dd70 --- /dev/null +++ b/hw/core/tdvf-stub.c @@ -0,0 +1,6 @@ +#include "sysemu/tdvf.h" + +int load_tdvf(const char *filename) +{ + return -1; +} diff --git a/hw/i386/meson.build b/hw/i386/meson.build index e5d109f5c6..945e805525 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -24,6 +24,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files( 'pc_sysfw.c', 'acpi-build.c', 'port92.c')) +i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c')) subdir('kvm') subdir('xen') diff --git a/hw/i386/tdvf.c b/hw/i386/tdvf.c new file mode 100644 index 0000000000..9b0065d656 --- /dev/null +++ b/hw/i386/tdvf.c @@ -0,0 +1,312 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + + * Copyright (c) 2020 Intel Corporation + * Author: Isaku Yamahata <isaku.yamahata at gmail.com> + * <isaku.yamahata at intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/units.h" +#include "cpu.h" +#include "exec/hwaddr.h" +#include "hw/boards.h" +#include "hw/i386/e820_memory_layout.h" +#include "hw/i386/tdvf.h" +#include "hw/i386/x86.h" +#include "hw/loader.h" +#include "sysemu/tdx.h" +#include "sysemu/tdvf.h" +#include "target/i386/kvm/tdx.h" + +static void tdvf_init_ram_memory(MachineState *ms, TdxFirmwareEntry *entry) +{ + void *ram_ptr = memory_region_get_ram_ptr(ms->ram); + X86MachineState *x86ms = X86_MACHINE(ms); + + if (entry->type == TDVF_SECTION_TYPE_BFV || + entry->type == TDVF_SECTION_TYPE_CFV) { + error_report("TDVF type %u addr 0x%" PRIx64 " in RAM (disallowed)", + entry->type, entry->address); + exit(1); + } + + if (entry->address < 4 * GiB) { + entry->mem_ptr = ram_ptr + entry->address; + } else { + /* + * If TDVF temp memory describe in TDVF metadata lays in RAM, reserve + * the region property. + */ + if (entry->address >= 4 * GiB + x86ms->above_4g_mem_size || + entry->address + entry->size >= 4 * GiB + x86ms->above_4g_mem_size) { + error_report("TDVF type %u address 0x%" PRIx64 " size 0x%" PRIx64 + " above high memory", + entry->type, entry->address, entry->size); + exit(1); + } + entry->mem_ptr = ram_ptr + x86ms->below_4g_mem_size + + entry->address - 4 * GiB; + } + e820_change_type(entry->address, entry->size, E820_RESERVED); +} + +static void tdvf_init_bios_memory(int fd, const char *filename, + TdxFirmwareEntry *entry) +{ + static unsigned int nr_cfv; + static unsigned int nr_tmp; + + MemoryRegion *system_memory = get_system_memory(); + Error *err = NULL; + const char *name; + + /* Error out if the section might overlap other structures. */ + if (entry->address < 4 * GiB - 16 * MiB) { + error_report("TDVF type %u address 0x%" PRIx64 " in PCI hole", + entry->type, entry->address); + exit(1); + } + + if (entry->type == TDVF_SECTION_TYPE_BFV) { + name = g_strdup("tdvf.bfv"); + } else if (entry->type == TDVF_SECTION_TYPE_CFV) { + name = g_strdup_printf("tdvf.cfv%u", nr_cfv++); + } else if (entry->type == TDVF_SECTION_TYPE_TD_HOB) { + name = g_strdup("tdvf.hob"); + } else if (entry->type == TDVF_SECTION_TYPE_TEMP_MEM) { + name = g_strdup_printf("tdvf.tmp%u", nr_tmp++); + } else { + error_report("TDVF type %u unknown/unsupported", entry->type); + exit(1); + } + entry->mr = g_malloc(sizeof(*entry->mr)); + + memory_region_init_ram(entry->mr, NULL, name, entry->size, &err); + if (err) { + error_report_err(err); + exit(1); + } + + entry->mem_ptr = memory_region_get_ram_ptr(entry->mr); + if (entry->data_len) { + /* + * The memory_region api doesn't allow partial file mapping, create + * ram and copy the contents + */ + if (lseek(fd, entry->data_offset, SEEK_SET) != entry->data_offset) { + error_report("can't seek to 0x%x %s", entry->data_offset, filename); + exit(1); + } + if (read(fd, entry->mem_ptr, entry->data_len) != entry->data_len) { + error_report("can't read 0x%x %s", entry->data_len, filename); + exit(1); + } + } + + memory_region_add_subregion(system_memory, entry->address, entry->mr); + + if (entry->type == TDVF_SECTION_TYPE_TEMP_MEM) { + e820_add_entry(entry->address, entry->size, E820_RESERVED); + } +} + +static void tdvf_parse_section_entry(TdxFirmwareEntry *entry, + const TdvfSectionEntry *src, + uint64_t file_size) +{ + entry->data_offset = le32_to_cpu(src->DataOffset); + entry->data_len = le32_to_cpu(src->RawDataSize); + entry->address = le64_to_cpu(src->MemoryAddress); + entry->size = le64_to_cpu(src->MemoryDataSize); + entry->type = le32_to_cpu(src->Type); + entry->attributes = le32_to_cpu(src->Attributes); + + /* sanity check */ + if (entry->data_offset + entry->data_len > file_size) { + error_report("too large section: DataOffset 0x%x RawDataSize 0x%x", + entry->data_offset, entry->data_len); + exit(1); + } + if (entry->size < entry->data_len) { + error_report("broken metadata RawDataSize 0x%x MemoryDataSize 0x%lx", + entry->data_len, entry->size); + exit(1); + } + if (!QEMU_IS_ALIGNED(entry->address, TARGET_PAGE_SIZE)) { + error_report("MemoryAddress 0x%lx not page aligned", entry->address); + exit(1); + } + if (!QEMU_IS_ALIGNED(entry->size, TARGET_PAGE_SIZE)) { + error_report("MemoryDataSize 0x%lx not page aligned", entry->size); + exit(1); + } + if (entry->type == TDVF_SECTION_TYPE_TD_HOB || + entry->type == TDVF_SECTION_TYPE_TEMP_MEM) { + if (entry->data_len > 0) { + error_report("%d section with RawDataSize 0x%x > 0", + entry->type, entry->data_len); + exit(1); + } + } +} + +static void tdvf_parse_metadata_entries(int fd, TdxFirmware *fw, + TdvfMetadata *metadata) +{ + + TdvfSectionEntry *sections; + ssize_t entries_size; + uint32_t len, i; + + fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries); + if (fw->nr_entries < 2) { + error_report("Invalid number of entries (%u) in TDVF", fw->nr_entries); + exit(1); + } + + len = le32_to_cpu(metadata->Length); + entries_size = fw->nr_entries * sizeof(TdvfSectionEntry); + if (len != sizeof(*metadata) + entries_size) { + error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)", + len, (uint32_t)(sizeof(*metadata) + entries_size)); + exit(1); + } + + fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries); + sections = g_new(TdvfSectionEntry, fw->nr_entries); + + if (read(fd, sections, entries_size) != entries_size) { + error_report("Failed to read TDVF section entries"); + exit(1); + } + + for (i = 0; i < fw->nr_entries; i++) { + tdvf_parse_section_entry(&fw->entries[i], §ions[i], fw->file_size); + } + g_free(sections); +} + +static int tdvf_parse_metadata_header(int fd, TdvfMetadata *metadata) +{ + uint32_t offset; + int64_t size; + + size = lseek(fd, 0, SEEK_END); + if (size < TDVF_METDATA_OFFSET_FROM_END || (uint32_t)size != size) { + return -1; + } + + /* Chase the metadata pointer to get to the actual metadata. */ + offset = size - TDVF_METDATA_OFFSET_FROM_END; + if (lseek(fd, offset, SEEK_SET) != offset) { + return -1; + } + if (read(fd, &offset, sizeof(offset)) != sizeof(offset)) { + return -1; + } + + offset = le32_to_cpu(offset); + if (offset > size - sizeof(*metadata)) { + return -1; + } + + /* Pointer to the metadata has been resolved, read the actual metadata. */ + if (lseek(fd, offset, SEEK_SET) != offset) { + return -1; + } + if (read(fd, metadata, sizeof(*metadata)) != sizeof(*metadata)) { + return -1; + } + + /* Finally, verify the signature to determine if this is a TDVF image. */ + if (metadata->Signature[0] != 'T' || metadata->Signature[1] != 'D' || + metadata->Signature[2] != 'V' || metadata->Signature[3] != 'F') { + return -1; + } + + /* Sanity check that the TDVF doesn't overlap its own metadata. */ + metadata->Length = le32_to_cpu(metadata->Length); + if (metadata->Length > size - offset) { + return -1; + } + + /* Only version 1 is supported/defined. */ + metadata->Version = le32_to_cpu(metadata->Version); + if (metadata->Version != 1) { + return -1; + } + + return size; +} + +int load_tdvf(const char *filename) +{ + MachineState *ms = MACHINE(qdev_get_machine()); + X86MachineState *x86ms = X86_MACHINE(ms); + TdxFirmwareEntry *entry; + TdvfMetadata metadata; + TdxGuest *tdx; + TdxFirmware *fw; + int64_t size; + int fd; + + if (!kvm_enabled()) { + return -1; + } + + tdx = (void *)object_dynamic_cast(OBJECT(ms->cgs), TYPE_TDX_GUEST); + if (!tdx) { + return -1; + } + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + return -1; + } + + size = tdvf_parse_metadata_header(fd, &metadata); + if (size < 0) { + close(fd); + return -1; + } + + /* Error out if the user is attempting to load multiple TDVFs. */ + fw = &tdx->fw; + if (fw->file_name) { + error_report("tdvf can only be specified once."); + exit(1); + } + + fw->file_size = size; + fw->file_name = g_strdup(filename); + + tdvf_parse_metadata_entries(fd, fw, &metadata); + + for_each_fw_entry(fw, entry) { + if (entry->address < x86ms->below_4g_mem_size || + entry->address > 4 * GiB) { + tdvf_init_ram_memory(ms, entry); + } else { + tdvf_init_bios_memory(fd, filename, entry); + } + } + + close(fd); + return 0; +} diff --git a/include/sysemu/tdvf.h b/include/sysemu/tdvf.h new file mode 100644 index 0000000000..0cf085e3ae --- /dev/null +++ b/include/sysemu/tdvf.h @@ -0,0 +1,6 @@ +#ifndef QEMU_TDVF_H +#define QEMU_TDVF_H + +int load_tdvf(const char *filename); + +#endif diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index 844d24aade..2fed27b3fb 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -5,6 +5,30 @@ #include "qapi/error.h" #include "exec/confidential-guest-support.h" +typedef struct TdxFirmwareEntry { + uint32_t data_offset; + uint32_t data_len; + uint64_t address; + uint64_t size; + uint32_t type; + uint32_t attributes; + + MemoryRegion *mr; + void *mem_ptr; +} TdxFirmwareEntry; + +typedef struct TdxFirmware { + const char *file_name; + uint64_t file_size; + + /* metadata */ + uint32_t nr_entries; + TdxFirmwareEntry *entries; +} TdxFirmware; + +#define for_each_fw_entry(fw, e) \ + for (e = (fw)->entries; e != (fw)->entries + (fw)->nr_entries; e++) + #define TYPE_TDX_GUEST "tdx-guest" #define TDX_GUEST(obj) \ OBJECT_CHECK(TdxGuest, (obj), TYPE_TDX_GUEST) @@ -20,6 +44,8 @@ typedef struct TdxGuest { bool initialized; bool debug; + + TdxFirmware fw; } TdxGuest; int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp);