OSDev.org

The Place to Start for Operating System Developers
It is currently Sun Apr 28, 2024 1:18 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI code
PostPosted: Wed Jul 12, 2023 8:50 am 
Offline

Joined: Sat Apr 29, 2023 9:29 am
Posts: 8
Good day, dear colleagues! I am having the following problem.

I'm trying to launch the OS from my own DXE-module through efi-loader. My DXE-module starts at the moment BSD-phase, when READY_TO_BOOT events is occurred. I correctly get the path to the efi-loader (in fact, I manually select this file from the file browser implemented in DXE-module so that the path is exactly correct):

Code:
PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(1,GPT,0DDBB405-D540-4260-90F4-DDB764D58459,0x800,0x64000)/\EFI\Microsoft\Boot\bootmgfw.efi


Then I call the LoadImage() function and get file handler:
Code:
bs->LoadImage(TRUE, imageHandle, path_to_efi_loader, NULL, NULL, &fileHandler);

Then I call the StartImage() function:
Code:
bs->StartImage(fileHandler, &exitSize, &exitData)

However, after launching the efi-loader, an attempt is made to start the Windows OS and an error window is displayed:
Attachment:
File comment: Windows recovery screen
3ed056d5-6bb6-42d5-af98-33e392c93fe6.jpg
3ed056d5-6bb6-42d5-af98-33e392c93fe6.jpg [ 32.75 KiB | Viewed 6897 times ]

Those, the path to the efi-loader is passed correctly, the loading and launch is performed correctly, but is there some error in the launch environment?

I tried first to load the efi-loader into memory by passing the buffer to it in LoadImage(). Also, between LoadImage() and StartImage(), I tried to get EFI_LOADED_IMAGE_PROTOCOL for the efi-loader and reset its ParentHandle.

It didn't help either.

What could be the problem here?

Thank you!


Last edited by DeadBrother on Fri Jul 14, 2023 6:36 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Wed Jul 12, 2023 6:36 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
DeadBrother wrote:
\EFI\Boot\BOOTX64.efi

That's not a complete device path. Where's the device?


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Thu Jul 13, 2023 9:18 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
Exactly like Octacontrabass says, you flattered to yourself a bit, when told, your DXE module file browser (?!!) has chosen Device Path correctly. It apparently hasn't. What you show - efi\boot\bootx64.efi is only a Filesystem part of the Device Path. It's not even a relative one. it's Type 4, Subtype 4 node(s). You need to pass the entire Device Path to LoadImage(). If your DXE module file manager gets a relative paths (those very useful for Load Options ones, that start with 4.1 HD() nodes), then you should resolve it to find the full path. The key here is the HD() node - it is present in both, the relative path starts with it, the absolute DP, enumerated by UEFI ends with it. You enumerate Block IO devices (LocateHandleBuffer()), open Block IO Protocol on them, filter out non-logical partitions (BIOP->Media->LogicalPartition is true for logical partitions), then open Device Path protocol on every handle, that is a logical partition and look for your HD() node in logical partitions' DPs. In case of MBR, you have to match signature and start, in case of GPT only signature (UniquePartitionGUID) is enough. This way, you'll find the full DP enumerated by UEFI, where your Filesystem part does reside.

PS. and as always. The note on the abusing efi\boot\bootXXXX.efi. using the last resort path (this efi\boot\bootXXXX.efi) is an awful idea. for non-removable devices, the firmware isn't even obligated to check it. but even for removable devices, it should be checked if only nothing else in the Load Option list worked out. However, admittedly, there are moronic Boot Managers, breaking both the specification and common sense. they allow one to load from, say USB stick, using only this poor efi\boot\bootXXXX.efi way. Xiaomi laptops are an example. :evil:

_________________
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: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Fri Jul 14, 2023 9:27 am 
Online
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1608
zaval wrote:
PS. and as always. The note on the abusing efi\boot\bootXXXX.efi. using the last resort path (this efi\boot\bootXXXX.efi) is an awful idea. for non-removable devices, the firmware isn't even obligated to check it. but even for removable devices, it should be checked if only nothing else in the Load Option list worked out. However, admittedly, there are moronic Boot Managers, breaking both the specification and common sense. they allow one to load from, say USB stick, using only this poor efi\boot\bootXXXX.efi way. Xiaomi laptops are an example. :evil:
Yeah, unfortunately, a lot of UEFI vendors do what BIOS vendors used to do: If Windows boots, they call wrap-up. So the only names they ever check are bootXXX.efi and the name Windows uses.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Fri Jul 14, 2023 6:32 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
nullplan wrote:
zaval wrote:
PS. and as always. The note on the abusing efi\boot\bootXXXX.efi. using the last resort path (this efi\boot\bootXXXX.efi) is an awful idea. for non-removable devices, the firmware isn't even obligated to check it. but even for removable devices, it should be checked if only nothing else in the Load Option list worked out. However, admittedly, there are moronic Boot Managers, breaking both the specification and common sense. they allow one to load from, say USB stick, using only this poor efi\boot\bootXXXX.efi way. Xiaomi laptops are an example. :evil:
Yeah, unfortunately, a lot of UEFI vendors do what BIOS vendors used to do: If Windows boots, they call wrap-up. So the only names they ever check are bootXXX.efi and the name Windows uses.

For me, it looks more like some extraterrestrial logic of the vendors. Windows, btw, also has to duplicate their loader in the installation medium into \efi\boot\bootXXXX.efi to fit this martian approach. Whereas such a nice option as "load from file" would be as much an effort but so much more convenient, logical and in line with the specification.

But I came to clarify on my previous post. I meant searching for the full Device Path in that unspecified DXE module file browser of the OP. When you say:
Quote:
in fact, I manually select this file from the file browser implemented in DXE-module so that the path is exactly correct): \EFI\Boot\BOOTX64.efi

then this could mean only that you had enumerated all Block IO (or, just Simple File System in case of FAT) partitions and then traversed through their filesystem tree, finding the file path of your interest. Correct? Then, you have to pass to LoadImage() the device path (instance) of the same (BIOP/SFSP) handle with the concatenated to it FilePath part, you've just found in your file browser. concatenation can be done, using EFI_DEVICE_PATH_UTILITIES_PROTOCOL (of course, if it's present :D). 4.4 nodes don't support SFSP/BIOP, 4.1 do. Admittedly, the LoadImage() description is silent on whether it can load, using relative DPs, those, starting with 4.1 nodes - HD()\efi\yourcompany\yourimage.efi that is, you can check it though, but it definitely can load from full paths, which you will have on the BIOP/SFSP devices enumeration inside of your miraculous DXE module.
Hopefully, it's clearer, than the LoadImage() description, :D

_________________
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: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Fri Jul 14, 2023 6:40 pm 
Offline

Joined: Sat Apr 29, 2023 9:29 am
Posts: 8
Octocontrabass wrote:
DeadBrother wrote:
\EFI\Boot\BOOTX64.efi

That's not a complete device path. Where's the device?

Octocontrabass, I apologize for the inaccuracy.

The full path is as follows:
Code:
PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(1,GPT,0DDBB405-D540-4260-90F4-DDB764D58459,0x800,0x64000)/\EFI\Microsoft\Boot\bootmgfw.efi

(I corrected the path in the first post)

The path is obtained using the function FileDevicePath() for volume handler and relative file path.
The string representation of a path is obtained using function ConvertDevicePathToText() for EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.


Last edited by DeadBrother on Fri Jul 14, 2023 6:51 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Fri Jul 14, 2023 6:50 pm 
Offline

Joined: Sat Apr 29, 2023 9:29 am
Posts: 8
zaval wrote:
Exactly like Octacontrabass says, you flattered to yourself a bit, when told, your DXE module file browser (?!!) has chosen Device Path correctly. It apparently hasn't. What you show - efi\boot\bootx64.efi is only a Filesystem part of the Device Path. It's not even a relative one. it's Type 4, Subtype 4 node(s). You need to pass the entire Device Path to LoadImage(). If your DXE module file manager gets a relative paths (those very useful for Load Options ones, that start with 4.1 HD() nodes), then you should resolve it to find the full path. The key here is the HD() node - it is present in both, the relative path starts with it, the absolute DP, enumerated by UEFI ends with it. You enumerate Block IO devices (LocateHandleBuffer()), open Block IO Protocol on them, filter out non-logical partitions (BIOP->Media->LogicalPartition is true for logical partitions), then open Device Path protocol on every handle, that is a logical partition and look for your HD() node in logical partitions' DPs. In case of MBR, you have to match signature and start, in case of GPT only signature (UniquePartitionGUID) is enough. This way, you'll find the full DP enumerated by UEFI, where your Filesystem part does reside.

PS. and as always. The note on the abusing efi\boot\bootXXXX.efi. using the last resort path (this efi\boot\bootXXXX.efi) is an awful idea. for non-removable devices, the firmware isn't even obligated to check it. but even for removable devices, it should be checked if only nothing else in the Load Option list worked out. However, admittedly, there are moronic Boot Managers, breaking both the specification and common sense. they allow one to load from, say USB stick, using only this poor efi\boot\bootXXXX.efi way. Xiaomi laptops are an example. :evil:


zaval, thanks for your comment.

I corrected the inaccuracy and gave the full path to the EFI-application:
Code:
PciRoot(0x0)/Pci(0x17,0x0)/Pci(0x0,0x0)/NVMe(0x2,00-00-00-00-00-00-00-00)/HD(1,GPT,0DDBB405-D540-4260-90F4-DDB764D58459,0x800,0x64000)/\EFI\Microsoft\Boot\bootmgfw.efi

Also, the function LoadImage() for this path does not return a error EFI_NOT_FOUND or other.
And the function StartImage() tried to start this EFI-application.
Thus, if I understand correctly - the EFI-file full path is correct, but an error occurs (see screenshot above) already in the process of execution.

p.s.
By file browser, I mean my own implemented functionality, which allows you to view files in all sections in text mode and select one of them. As a result, the browser returns the volume handle (obtained by the enum for EFI_SIMPLE_FILE_SYSTEM_PROTOCOL) and the relative path to the file.


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Mon Jul 17, 2023 10:09 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
Does it work if you use the firmware's boot manager instead of your DXE driver?


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Mon Jul 17, 2023 10:22 am 
Offline

Joined: Sat Apr 29, 2023 9:29 am
Posts: 8
Octocontrabass wrote:
Does it work if you use the firmware's boot manager instead of your DXE driver?

Yes, sure.
If I exit from the DXE-driver (without call LoadImage() and StartImage(), of course), then the OS boot normally.


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Mon Jul 17, 2023 12:18 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
Huh, I'm not sure what else it could be. You might have to spend some time in a debugger to figure out where the difference is.


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Mon Jul 17, 2023 12:56 pm 
Offline

Joined: Sat Apr 29, 2023 9:29 am
Posts: 8
Octocontrabass wrote:
Huh, I'm not sure what else it could be. You might have to spend some time in a debugger to figure out where the difference is.

Octocontrabass, can you tell me what suitable debugging method can be applied - for VMWare and bootmgfw.efi?

And do I understand correctly that the actions that I am doing (LoadImage, StartImage, manual run bootmgfw.efi app instead standart boot loader usage) are correct and they should lead to OS loading?


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Mon Jul 17, 2023 1:20 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5146
DeadBrother wrote:
Octocontrabass, can you tell me what suitable debugging method can be applied - for VMWare and bootmgfw.efi?

I believe VMWare has a GDB stub, but I've never used it. I have used QEMU with GDB to debug UEFI programs, though.

DeadBrother wrote:
And do I understand correctly that the actions that I am doing (LoadImage, StartImage, manual run bootmgfw.efi app instead standart boot loader usage) are correct and they should lead to OS loading?

Yes, as far as I can tell that's correct. Maybe comparing what you're doing against what EDK2 does will help.


Top
 Profile  
 
 Post subject: Re: Try to load and start 'EFI\Boot\bootx64.efi' from UEFI c
PostPosted: Sun Jul 23, 2023 4:32 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 642
Location: Ukraine, Bachmut
I see. OS Loaders make use information in the associated Load Options (LOs), Windows Boot Manager does so as well. Tell me, when you load it, do you fill in LoadOptions pointer (inside of the ImageHandle's EFI_LOADED_IMAGE_PROTOCOL, LIP, instance) before starting the image?
Quote:
The caller may fill in the image’s “load options” data, or add additional protocol support to the handle before passing control to the newly loaded image by calling StartImage().

Basically, you would need to take BootXXXX variable contents and pass its OptionalData address to bootmgr.efi. Because you load OSL instead of UEFI Boot Manager, you would need to mimick the process as if bootmgr.efi was picked during the Load Option processing, basically, you need to find what BootXXXX is related to the bootmgr.efi. For example, by enumerating BootXXXX and finding among them the one, having the same Device Path in the FilePathList[0], but remember, it almost certainly would be a relative one, thus starting with the 4.1 node, like HD()\<FilePath>. Then you should pass the pointer to OptionalData part of the LO via the LIP->LoadOptions field. Don't forget to fill in LoadOptionsSize field too. Useful quote from the spec (Boot Manager, Load Options):
Quote:
OptionalData
The remaining bytes in the load option descriptor are a binary
data buffer that is passed to the loaded image. If the field is zero
bytes long, a NULL pointer is passed to the loaded image. The
number of bytes in OptionalData can be computed by
subtracting the starting offset of OptionalData from total size
in bytes of the EFI_LOAD_OPTION.

I haven't used LoadImage() and may be wrong, but I think, the sequence should be like this:
1. you call LoadImage.
2. On success, you open EFI_LOADED_IMAGE_PROTOCOL (LIP) on the ImageHandle
3. If its LoadOptions field is NULL and LoadOptionsSize is 0, then we got it right, so you proceed. If its not NULL, print it to see, what's there. have no clue what it can be there. because LoadImage() has nothing to write there.
4. Find Windows bootmgr.efi Load Option (BootXXXX) by enumerating these vars and searching in their FilePathList[0] for HD() node with exactly the same identifiers (UniquePartitionGUID for GPT, DiskId and Start for MBR)
5. On finding this LO and you already have its contents read as a buffer, calculate the address of its OptionalData part and pass it via LIP->LoadOptions, calculate its Size and fill in LIP->LoadOptionsSize as well.

ALSO, you might need to set BootCurrent variable with the index of BootXXXX, that corresponds to bootmgr.efi, since bootmgr.efi could use this mechanism to get its data. As we can see, there are many ways of how OSLs can be started and this complicates for them using persistently stored (in LO) information. Also, there are OSL launch scenarios, where the OS is not installed yet and where it is.
As an example. My loader distinguishes Preinstallation run and Postinstallation one, by reading the BootCurrent and analyzing contents of the corresponding BootXXXX variable. PreInst won't have any info set up by us in it, so we know, we are started not through LO processing, but manually - "Load From File" or via that poor efi\boot\bootxxxx.efi or whatever, but normal way and this is exactly the way of the preinstallation phase. If BootCurrent points to the LO, containing what we expect it to contain, then it's PostInstall, so we safely can read the needed info. I use FilePathList[1] for storing OS BootVolume HD() node (4.1) and System Root Directory (4.4). This is needed for finding where the OS is installed (I don't use my 2-part loader with my own "Boot Manager" as Windows does), but also - it allows to distinguish between PreInst and PostInst phases and serves as a marker of the LO, being ours (set by Installer). It's just an example to demonstrate, OSL needs to handle different scenarios of its launch. It is not brilliant, since, if a user launches our loader via, say, UEFI CLI, our loader would think it is PreInst or Live session and most probably will fail or even worse - would start the OS from the "setup" directory, that might screw up the already installed OS. Unlikely, but not too satisfying...

Windows doesn't use FPL[1], but it makes use OptionalData Load Option container (see the image below), storing there some BCD related stuff, basically, text represented GUID like BCD_OBJECT={<Guid here>}. I don't know, how bootmgr.efi handles this variety in the ways of starting it, but it apparently doesn't fail, when launched manually via UEFI Boot Manager or CLI, so, obviously, it uses some of the above - BootCurrent (may use it in PostInstall), LIP LoadOptions pointer. In the PreInst case, when started from UEFI CLI, LIP->LoadOptions points to the command line, you typed, when picking your .efi file. But bootmgr.efi doesn't fail in this case, doesn't it? Maybe it fails if LoadOptions is NULL?
1. If it's PostInstall, LoadOptions would have the contents of LO->OptionalData, set by the Windows Installer, apparently, it uses it.
2. If it's PreInstall, LoadOptions are not NULL and are filled with something, for example, as said above, for the CLI, it would be command like, so at least the image name would be there, kind of argv[0].
3. If it's a plain LoadImage() call, like you did, LoadOptions is NULL and then bootmgr.efi fails.

Try to pass to bootmgr.efi via LIP->LoadOptions the contents of its BootXXXX OptionalData buffer (1) or, at least its name (2). I feel, it will get healed. :)
You have touched a quite complex thing.

Image

_________________
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  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: SemrushBot [Bot] and 24 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