OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 8:16 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
 Post subject: Non-volatile memory in the UEFI
PostPosted: Sun Jan 02, 2022 10:43 am 
Offline

Joined: Mon Dec 27, 2021 1:33 pm
Posts: 4
Hello, I want to figure out how to save data to non-volatile memory in the UEFI such that data is still there after I reopen QEMU.

So I used to run my bootx64.efi by producing it and then just putting it to app/efi/boot/bootx64.efi and then I did
Code:
qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd -hdd fat:rw:app
and that worked very well.
However, I figured I wouldn't be able to save data in a non-volatile way like this and I would need to instead create a real FAT32 file system image with my /efi/boot/bootx64.efi on that image and then I'd be able to save data to that image. Is that correct?

Well, that aside, so far I know of two ways that should allow me to store data in a non-volatile way:
* Using UEFI variables (in the UEFI shell this can be done with `set`)
* Using the Simple File System Protocol and the File Protocol
* I read that there is a way to read a non-FAT32 file system (e.g. ext2) by using the Block I/O Protocol and parsing the file system myself. The non-FAT32 file system would still have to live on top of the FAT32 one though, right?
Are there other ways?

Well now I'm creating a bootable disk like this: https://wiki.osdev.org/UEFI_App_Bare_Bo ... _FAT_image
Then I run it like this:
Code:
qemu-system-x86_64 -drive file=fat.img,media=disk,format=raw -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=/usr/share/OVMF/OVMF_VARS.fd

It starts the UEFI shell. As a test I did `set a b`, rebooted and the variable was still there. But I figured that saving data specific to my image/application in the user's general `/usr/share/OVMF/OVMF_VARS.fd` wasn't good so I think variables are out of the race for non-volatile data storage. Unless there is a way to save the variables somewhere else?

Simply removing the last `-drive` argument from the above command actually starts the bootx64.efi.

Anyway, so as a start I tried obtaining the Simple File System Protocol and that seems to have worked: `EFI_BOOT_SERVICES.LocateProtocol()` returned `EFI_SUCCESS` for that protocol.
For the File Protocol, which is the necessary counterpart, however, `EFI_BOOT_SERVICES.LocateProtocol()` returns `EFI_NOT_FOUND` for that protocol and I can't figure out why.

What could I be doing wrong? Is my `fat.img` in its current state still read-only? Are my QEMU arguments wrong? Can I not store data in the file system in my FAT32 image?

I hope somebody can teach me how to store non-volatile data within the UEFI.


Top
 Profile  
 
 Post subject: Re: Non-volatile memory in the UEFI
PostPosted: Sun Jan 02, 2022 3:34 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
uefiguy wrote:
However, I figured I wouldn't be able to save data in a non-volatile way like this and I would need to instead create a real FAT32 file system image with my /efi/boot/bootx64.efi on that image and then I'd be able to save data to that image. Is that correct?

Have you tried it? There is some limited support for writing files to the virtual FAT drive. It seems to work well enough for OVMF to store its variables there when there's no NVRAM.

uefiguy wrote:
* I read that there is a way to read a non-FAT32 file system (e.g. ext2) by using the Block I/O Protocol and parsing the file system myself. The non-FAT32 file system would still have to live on top of the FAT32 one though, right?

You don't need a FAT32 partition when you're not booting from the disk.

uefiguy wrote:
Are there other ways?

None come to mind.

uefiguy wrote:
But I figured that saving data specific to my image/application in the user's general `/usr/share/OVMF/OVMF_VARS.fd` wasn't good so I think variables are out of the race for non-volatile data storage. Unless there is a way to save the variables somewhere else?

You're supposed to make a separate copy of OVMF_VARS.fd for each VM. Tools like libvirt do this automatically.

uefiguy wrote:
Simply removing the last `-drive` argument from the above command actually starts the bootx64.efi.

Boot order is controlled by UEFI variables. It sounds like the variables you're using are set to boot the shell.

uefiguy wrote:
For the File Protocol, which is the necessary counterpart, however, `EFI_BOOT_SERVICES.LocateProtocol()` returns `EFI_NOT_FOUND` for that protocol and I can't figure out why.

It means there are no open files or directories.

uefiguy wrote:
What could I be doing wrong?

You're not opening any files or directories. Take a look at EFI_SIMPLE_FILE SYSTEM_PROTOCOL.OpenVolume() in the UEFI specification.


Top
 Profile  
 
 Post subject: Re: Non-volatile memory in the UEFI
PostPosted: Sun Jan 02, 2022 6:06 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 640
Location: Ukraine, Bachmut
Quote:
Hello, I want to figure out how to save data to non-volatile memory in the UEFI such that data is still there after I reopen QEMU.

So I used to run my bootx64.efi by producing it and then just putting it to app/efi/boot/bootx64.efi and then I did

UEFI variables and volumes on secondary storage. do not put into UEFI variables everything, only something small, what is really needed to be there - because they are stored in a very scarce NOR flash devices, your users won't be happy if you thrash those. in most cases, its use is for your installation BootXXXX Load Option variable. for OVMF, that file OVMG_VARS.fd is a representation of such a flash device, you provide it for qemu on a per VM basis, just like Octoconrabas pointed. in other words, when starting your VM, provide its own copy of this file.
accessing volumes on secondary storages allows you to store there what you need. generally, it goes to ESP, but not necessarily, it could be any FAT volume, if you don't want to parse FS structures in your loader. then you just create a FAT volume and put your stuff there \efi\yourorgname\. btw, use this approach for storing your loader as well, and then start it from the shell or Boot Manager. or from a load option even - the latter is the most natural way for a "production ready" phase. don't use the "default" \efi\boot\bootx64.efi approach - it's meant as a last chance and is OPTIONAL for the firmware to check on persistent storage devices. it may clash with other things already sitting there with this name and it may just not be started.

for accessing FAT drives, you first open EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on a handle, representing that device (in case of using the volume from where your loader got started, this handle is the DeviceHandle member of the EFI_LOADED_IMAGE_PROTOCOL instance of your loader, but also, you can enumerate all the devices, supporting SFSP). then you OpenVolume() on it and get an EFI_FILE_PROTOCOL instance of the root directory of that volume. then you can Open() any file or directory on that instance, getting an instance of EFI_FILE_PROTOCOL of that file or directory. then, finally, you can Read() or Write() that file. storing on the volume what you need.

for FS, other, than FAT family (except exFAT), you have to use BLOCK_IO_PROTOCOL and implement FS reading/writing yourself. as you guess, it's way better to use a FAT volume. but don't worry, you will still need to implement the aforementioned non-FAT volume reading (at least) for getting your kernel files. and if, like in Windows, there is journaling capabilities for the configuration database (registry) in your OS, you will need to implement it (for replaying unfinished transactions and making the registry clean). this implies being able to do write on a non-FAT volume, if your OS uses such. but for loader specific data, please, use \efi\yourorgname\ directory on a FAT volume. then at least at the beginning, firmware will save you from the burden of messing around a pretty hard work of getting the data from/to a non-FAT FS.

also, some firmwares materialize SFSP on a non-FAT volumes. like uboot on ext4 for example. UEFI allows that (but not how apple does it - ESP is always a FAT32 volume on a compliant system). it's a nice feature (if wouldn't have nasty bugs) but it's just a non-guaranteed addition.

In a short summary:
1) you use flash based storage only for your variables, and they are small. BootXXXX for your installation mostly. access is through FW services.
2) your loader specific data with the loader itself go into a FAT volume (most naturally ESP, but when developing, just put it into a normal FAT volume, would be easier), you put your data into \efi\yourorgname directory and access it, using an easy to use firmware services. you put here most your stuff. but again, let's not participate in bloating ESP to 1GB, ok? :D
3) your OS resides on your own badass FS and the firmware has no idea about it. you implement your own FS reading code in the loader, that does the job. using EFI_BLOCK_IO_PROTOCOL underneath for accessing the drive. you mostly need a readonly capabilities, but if your OS requires features, like logging for e.g. configuration database, you would need to implement write access to your FS as well.

_________________
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).


Top
 Profile  
 
 Post subject: Re: Non-volatile memory in the UEFI
PostPosted: Mon Jan 03, 2022 12:25 pm 
Offline

Joined: Mon Dec 27, 2021 1:33 pm
Posts: 4
I understand a lot better now. Thanks!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: SemrushBot [Bot] and 57 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group