Date
1 - 3 of 3
Flash memory mapped region protection
Konstantin Aladyshev
Hello!
Can someone explain to me how flash memory mapping works in Ovmf?
I've added a new DATA region to the `OvmfPkg/OvmfPkgX64.fdf`,
initialized it with data and created a PCD for the region base:
```
<...>|<...>
gUefiOvmfPkgTokenSpaceGuid.PcdMyRegionBase
DATA = {
0xDE, 0xAD, 0xBE, 0xEF
}
```
I've also created simple UEFI_APPLICATION that uses this PCD and
reads/writes this region:
```
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
return EFI_SUCCESS;
}
```
I launch my QEMU with this command:
```
qemu-system-x86_64 -drive
if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic \
-net none
```
The region is created correctly and the PCD is assigned to the correct
value, but I'm a little bit confused by the application output:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
```
Can someone explain to me, why does it look that way?
My current theory is that it is impossible to write data to the memory
mapped flash via pointer, and the second output is just a compiler
optimization. Am I correct? In this case how is this region protected?
Is it an OVMF feature, or is it simply a QEMU feature?
Best regards,
Konstantin Aladyshev
Can someone explain to me how flash memory mapping works in Ovmf?
I've added a new DATA region to the `OvmfPkg/OvmfPkgX64.fdf`,
initialized it with data and created a PCD for the region base:
```
<...>|<...>
gUefiOvmfPkgTokenSpaceGuid.PcdMyRegionBase
DATA = {
0xDE, 0xAD, 0xBE, 0xEF
}
```
I've also created simple UEFI_APPLICATION that uses this PCD and
reads/writes this region:
```
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
return EFI_SUCCESS;
}
```
I launch my QEMU with this command:
```
qemu-system-x86_64 -drive
if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic \
-net none
```
The region is created correctly and the PCD is assigned to the correct
value, but I'm a little bit confused by the application output:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
```
Can someone explain to me, why does it look that way?
My current theory is that it is impossible to write data to the memory
mapped flash via pointer, and the second output is just a compiler
optimization. Am I correct? In this case how is this region protected?
Is it an OVMF feature, or is it simply a QEMU feature?
Best regards,
Konstantin Aladyshev
Andrew Fish
Konstantin,
In general devices supporting UEFI use NOR FLASH. You can’t just write to NOR FLASH it is not a memory. If I’m remembering the right polarity you can set a 1 to 0 in NOR FLASH, but to set a 0 to 1 you need to erase the entire block. I think QEMU works the same way.
The 2nd issue is for secure boot the NOR FLASH is secured and it can only be written to from SMM mode. This feature is a build option in OVMF [1].
If you don’t have the SMM security setup then this is the FvbServicesRuntimeDxe driver manages writing to the NOR FLASH, and it publishes a gEfiFirmwareVolumeBlockProtocolGuid to abstract this service from the generic variable stack. I think the FvbServicesRuntimeDxe only manages writes to the NVRAM store.
There is some QEMU special magic in that the NVRAM region is part of the VM. I seem to remember the size of the ROM implies the location of the NVRAM store in QEMU. This is why in some cases you need to use OVMF_CODE.fd vs OVM.fd. Please see [3]
[1] https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf#L384
[2] https://github.com/tianocore/edk2/tree/master/OvmfPkg/QemuFlashFvbServicesRuntimeDxe
[3] https://github.com/tianocore/edk2/blob/master/OvmfPkg/README
Thanks,
Andrew Fish
toggle quoted message
Show quoted text
In general devices supporting UEFI use NOR FLASH. You can’t just write to NOR FLASH it is not a memory. If I’m remembering the right polarity you can set a 1 to 0 in NOR FLASH, but to set a 0 to 1 you need to erase the entire block. I think QEMU works the same way.
The 2nd issue is for secure boot the NOR FLASH is secured and it can only be written to from SMM mode. This feature is a build option in OVMF [1].
If you don’t have the SMM security setup then this is the FvbServicesRuntimeDxe driver manages writing to the NOR FLASH, and it publishes a gEfiFirmwareVolumeBlockProtocolGuid to abstract this service from the generic variable stack. I think the FvbServicesRuntimeDxe only manages writes to the NVRAM store.
There is some QEMU special magic in that the NVRAM region is part of the VM. I seem to remember the size of the ROM implies the location of the NVRAM store in QEMU. This is why in some cases you need to use OVMF_CODE.fd vs OVM.fd. Please see [3]
[1] https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf#L384
[2] https://github.com/tianocore/edk2/tree/master/OvmfPkg/QemuFlashFvbServicesRuntimeDxe
[3] https://github.com/tianocore/edk2/blob/master/OvmfPkg/README
Thanks,
Andrew Fish
On Jul 26, 2022, at 8:15 AM, Konstantin Aladyshev <aladyshev22@...> wrote:
Hello!
Can someone explain to me how flash memory mapping works in Ovmf?
I've added a new DATA region to the `OvmfPkg/OvmfPkgX64.fdf`,
initialized it with data and created a PCD for the region base:
```
<...>|<...>
gUefiOvmfPkgTokenSpaceGuid.PcdMyRegionBase
DATA = {
0xDE, 0xAD, 0xBE, 0xEF
}
```
I've also created simple UEFI_APPLICATION that uses this PCD and
reads/writes this region:
```
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
return EFI_SUCCESS;
}
```
I launch my QEMU with this command:
```
qemu-system-x86_64 -drive
if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic \
-net none
```
The region is created correctly and the PCD is assigned to the correct
value, but I'm a little bit confused by the application output:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
```
Can someone explain to me, why does it look that way?
My current theory is that it is impossible to write data to the memory
mapped flash via pointer, and the second output is just a compiler
optimization. Am I correct? In this case how is this region protected?
Is it an OVMF feature, or is it simply a QEMU feature?
Best regards,
Konstantin Aladyshev
Konstantin Aladyshev
Thanks for the answer! I'll investigate the mentioned modules.
As for my example I completely forgot that I can declare variable as
'volatile' like this:
```
volatile UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
```
This way compiler doesn't perform any optimizations and it is clearly
seen that the variable is read-only:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xEFBEADDE
```
Best regards,
Konstantin Aladyshev
toggle quoted message
Show quoted text
As for my example I completely forgot that I can declare variable as
'volatile' like this:
```
volatile UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
```
This way compiler doesn't perform any optimizations and it is clearly
seen that the variable is read-only:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xEFBEADDE
```
Best regards,
Konstantin Aladyshev
On Tue, Jul 26, 2022 at 8:09 PM Andrew Fish <afish@...> wrote:
Konstantin,
In general devices supporting UEFI use NOR FLASH. You can’t just write to NOR FLASH it is not a memory. If I’m remembering the right polarity you can set a 1 to 0 in NOR FLASH, but to set a 0 to 1 you need to erase the entire block. I think QEMU works the same way.
The 2nd issue is for secure boot the NOR FLASH is secured and it can only be written to from SMM mode. This feature is a build option in OVMF [1].
If you don’t have the SMM security setup then this is the FvbServicesRuntimeDxe driver manages writing to the NOR FLASH, and it publishes a gEfiFirmwareVolumeBlockProtocolGuid to abstract this service from the generic variable stack. I think the FvbServicesRuntimeDxe only manages writes to the NVRAM store.
There is some QEMU special magic in that the NVRAM region is part of the VM. I seem to remember the size of the ROM implies the location of the NVRAM store in QEMU. This is why in some cases you need to use OVMF_CODE.fd vs OVM.fd. Please see [3]
[1] https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf#L384
[2] https://github.com/tianocore/edk2/tree/master/OvmfPkg/QemuFlashFvbServicesRuntimeDxe
[3] https://github.com/tianocore/edk2/blob/master/OvmfPkg/README
Thanks,
Andrew Fish
On Jul 26, 2022, at 8:15 AM, Konstantin Aladyshev <aladyshev22@...> wrote:
Hello!
Can someone explain to me how flash memory mapping works in Ovmf?
I've added a new DATA region to the `OvmfPkg/OvmfPkgX64.fdf`,
initialized it with data and created a PCD for the region base:
```
<...>|<...>
gUefiOvmfPkgTokenSpaceGuid.PcdMyRegionBase
DATA = {
0xDE, 0xAD, 0xBE, 0xEF
}
```
I've also created simple UEFI_APPLICATION that uses this PCD and
reads/writes this region:
```
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINT32* Val = (UINT32*)(FixedPcdGet32(PcdMyRegionBase));
Print(L"Val = 0x%08x\n", *Val);
*Val = 0xCAFECAFE;
Print(L"Val = 0x%08x\n", *Val);
return EFI_SUCCESS;
}
```
I launch my QEMU with this command:
```
qemu-system-x86_64 -drive
if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:~/UEFI_disk \
-nographic \
-net none
```
The region is created correctly and the PCD is assigned to the correct
value, but I'm a little bit confused by the application output:
```
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
FS0:\> FlashAccessRaw.efi
Val = 0xEFBEADDE
Val = 0xCAFECAFE
```
Can someone explain to me, why does it look that way?
My current theory is that it is impossible to write data to the memory
mapped flash via pointer, and the second output is just a compiler
optimization. Am I correct? In this case how is this region protected?
Is it an OVMF feature, or is it simply a QEMU feature?
Best regards,
Konstantin Aladyshev