Page 1 of 2

Getting started with UEFI

Posted: Wed Aug 08, 2012 5:16 pm
by blm768
I just recently lost my old BIOS-based code to a partition table corruption, so I decided to start fresh with a UEFI-based kernel. I've gotten QEMU set up with the right firmware and built a GRUB2 EFI image using the instructions in the GRUB page on the wiki (which should really be moved to the GRUB2 page because they don't use legacy GRUB), and everything goes smoothly until I get into GRUB. Instead of displaying a menu, it drops right to the rescue prompt without any indication of what's wrong. Here is my grub.cfg:

Code: Select all

set timeout=30
set default=0
set debug=all

#loadfont /efi/boot/unicode.pf2
#set gfxmode=1024x768
#set gfxmode=auto
#set gfxpayload=keep
#terminal_output gfxterm

#background_image -m normal /efi/boot/background.jpg

menuentry "OSKernel" {
set debug=all
sleep 5 
}
I also have a few other questions:
  • Does GRUB pass the EFI system table to the loaded OS?
  • If not, is there another way to get it?
  • Is GOP available after ExitBootServices()?
Thanks in advance for your help!

Re: Getting started with UEFI

Posted: Wed Aug 08, 2012 6:10 pm
by Brendan
Hi,
blm768 wrote:I just recently lost my old BIOS-based code to a partition table corruption, so I decided to start fresh with a UEFI-based kernel. I've gotten QEMU set up with the right firmware and built a GRUB2 EFI image using the instructions in the GRUB page on the wiki (which should really be moved to the GRUB2 page because they don't use legacy GRUB), and everything goes smoothly until I get into GRUB. Instead of displaying a menu, it drops right to the rescue prompt without any indication of what's wrong. Here is my grub.cfg:
I've got no idea what could be wrong. If you run GRUB2 inside Qemu (with UEFI) you might be able to debug it.
blm768 wrote:I also have a few other questions:
  • Does GRUB pass the EFI system table to the loaded OS?
That depends what the "loaded OS" is. If it uses multi-boot then no, GRUB2 won't pass the EFI system table. If the OS uses Linux' native boot then I don't think the system table is passed. I don't know about the native boot method used by FreeBSD (or other OSs that GRUB2 might support). Finally, if GRUB2 is used to "chainload" a normal UEFI boot loader then it should pass the EFI system table (however, for this case and possibly for UEFI in general, there's no point bothering with GRUB2).
blm768 wrote:
  • If not, is there another way to get it?
No - if you're not passed the address of the EFI system table you can't get it any other way.
blm768 wrote:
  • Is GOP available after ExitBootServices()?
No, but you can get information needed to use the frame buffer before calling ExitBootServices() and use that framebuffer after calling ExitBootServices().


Cheers,

Brendan

Re: Getting started with UEFI

Posted: Wed Aug 08, 2012 10:27 pm
by blm768
Brendan wrote: I've got no idea what could be wrong. If you run GRUB2 inside Qemu (with UEFI) you might be able to debug it.
Maybe. Sounds painful, though...
Brendan wrote: Finally, if GRUB2 is used to "chainload" a normal UEFI boot loader then it should pass the EFI system table (however, for this case and possibly for UEFI in general, there's no point bothering with GRUB2).
I might have to do that. My only real reasons for using GRUB2 were convenience and the ability to dual-boot, but chainloading an EFI loader should work. At least it'll make a higher-half kernel easier.
Brendan wrote: No, but you can get information needed to use the frame buffer before calling ExitBootServices() and use that framebuffer after calling ExitBootServices().
Ouch. I thought UEFI was supposed to make things easier. I guess I'll have to implement a framebuffer driver for each graphics card. (I'm not planning on messing with 2D acceleration; it's not worth the effort when most window managers are switching to OpenGL).

Well, I guess I've got my work cut out for me...

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 12:05 am
by Brendan
Hi,
blm768 wrote:Ouch. I thought UEFI was supposed to make things easier. I guess I'll have to implement a framebuffer driver for each graphics card. (I'm not planning on messing with 2D acceleration; it's not worth the effort when most window managers are switching to OpenGL).
You don't need a frame-buffer driver for each card - you only need one frame-buffer driver.

The frame-buffer driver should only need to know the physical address of the frame buffer, the resolution, the pixel format and how many bytes between horizontal lines (and shouldn't need to know anything else, including what the video card is).

Also note that this also means that the same frame-buffer driver should work regardless of where this information came from (and the same frame buffer driver should work regardless of whether this information originally came from UEFI/GOP, UEFI/UGA, BIOS/VBE or something else).

The disadvantage is that there's no 2D or 3D acceleration, no hardware mouse pointer support, and no way to change video modes after boot. For these things you'd need native drivers for each card (and not a frame-buffer driver).


Cheers,

Brendan

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 12:05 am
by Brendan
Hi,
blm768 wrote:Ouch. I thought UEFI was supposed to make things easier. I guess I'll have to implement a framebuffer driver for each graphics card. (I'm not planning on messing with 2D acceleration; it's not worth the effort when most window managers are switching to OpenGL).
You don't need a frame-buffer driver for each card - you only need one frame-buffer driver.

The frame-buffer driver should only need to know the physical address of the frame buffer, the resolution, the pixel format and how many bytes between horizontal lines (and shouldn't need to know anything else, including what the video card is).

Also note that this also means that the same frame-buffer driver should work regardless of where this information came from (and the same frame buffer driver should work regardless of whether this information originally came from UEFI/GOP, UEFI/UGA, BIOS/VBE or something else).

The disadvantage is that there's no 2D or 3D acceleration, no hardware mouse pointer support, and no way to change video modes after boot. For these things you'd need native drivers for each card (and not a frame-buffer driver).


Cheers,

Brendan

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 12:38 am
by Antti
As far as the hobby OS developing is concerned, I think that playing with GRUB (or similar) is not a good idea. I do not know how to explain this but I feel that it does not belong to the philosophy of doing things from scratch. I would categorize the hobby OS developing to be "doing things from scratch". If you are able to write a kernel, why you do not just take care of the boot procedures also. As an aside, I would find it frustrating to start studying (and debugging!) GRUB because, well, I am doing my own system.

I know that there is a lot of code running (BIOS code, SMM, UEFI firmware, etc.) that is not made by me. I accept that. However, the GRUB goes too far. It goes without saying that this philosophy has disadvantages.

I also want to emphasize that it is just my opinion and I am not saying that it is a universal truth. I am an expert of making offtopic posts.

I have a question: is it standardized that the frame buffer can always be read? If I write something to it, does it always return the same value? My current implementation relies on this behaviour.

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 2:06 am
by gerryg400
Antti wrote:As far as the hobby OS developing is concerned, I think that playing with GRUB (or similar) is not a good idea. I do not know how to explain this but I feel that it does not belong to the philosophy of doing things from scratch. I would categorize the hobby OS developing to be "doing things from scratch". If you are able to write a kernel, why you do not just take care of the boot procedures also. As an aside, I would find it frustrating to start studying (and debugging!) GRUB because, well, I am doing my own system.
I feel the opposite. I use Grub. I have no interest whatsoever in writing a boot loader. It's just some sort of driver thingy that loads my kernel and is nothing at all to do with my operating system design. It's just a distraction.

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 4:22 am
by Antti
gerryg400 wrote:I feel the opposite. I use Grub. I have no interest whatsoever in writing a boot loader. It's just some sort of driver thingy that loads my kernel and is nothing at all to do with my operating system design. It's just a distraction.
I understand your viewpoint and I cannot anyhow have arguments against it.

When I started developing an OS, I did not accept that I would use something like GRUB. The first disk images of my system (did not count as an OS yet) would have actually been mostly the GRUB code. I liked the idea that everything in the system image was made by me.

I know that the general opinion is that the boot loader is not considered to be an integrated part of the OS. For me, it is. I think that my OS starts right after the first instruction of my code is fetched.I do not mind of having a multi-boot compatibility.

My system is always meant to be booted from an external device and it runs fully in RAM. I think that hard drives are obsolete and RAM would be considered "non-volatile" in the future. The idea of completely turning off the computer is discarded.

Re: Getting started with UEFI

Posted: Thu Aug 09, 2012 5:32 pm
by blm768
Brendan wrote: The disadvantage is that there's no 2D or 3D acceleration, no hardware mouse pointer support, and no way to change video modes after boot. For these things you'd need native drivers for each card (and not a frame-buffer driver).
What I was planning to make was a very minimal driver for each card that would support changing video modes and drawing through an unaccelerated framebuffer-like interface. If 2D acceleration isn't hard to implement in a driver, though, I might add it. I just don't want to bother with it if it adds much effort; I'm hoping to get OpenGL drivers anyway (eventually...), so 2D acceleration likely wouldn't even be used much.
Until I start with the GUI, though, the GOP framebuffer should be plenty to emulate a text console.

Re: Getting started with UEFI

Posted: Fri Aug 10, 2012 8:33 am
by Combuster
Modesetting is typically a pain, and I even know a few chipsets where programming the 2D engine is actually easier than getting that very modesetting right.

Re: Getting started with UEFI

Posted: Fri Aug 10, 2012 6:33 pm
by Brendan
Hi,
blm768 wrote:What I was planning to make was a very minimal driver for each card that would support changing video modes and drawing through an unaccelerated framebuffer-like interface. If 2D acceleration isn't hard to implement in a driver, though, I might add it.
My advice is to forget about implementing drivers, and concentrate on writing a specification that defines the video driver interface. For example, your specification might have 8 functions:
  • a function to get a the driver's identification and capabilities (if it supports various optional features or not)
  • a function to get a list of supported video modes
  • a function to get information about a specific video mode
  • a function to set a video mode
  • a function to draw a frame of video
  • a function to determine what "object ID" happens to be at a specific coordinate (that software can use to determine what part of which icon/widget/window the mouse clicked on)
  • a function to set the mouse pointer position
  • a function to set the mouse pointer's appearance
Of course you'd have to describe everything properly - e.g. which capabilities might be supported, how various structures (e.g. the "video mode information structure") are defined, how a frame of video is described to the driver (a list of commands that describe what to draw?, raw pixel data?), etc; and your native video driver interface (and mine) might be completely different to the example above.

Once you've done that you can implement a basic frame-buffer driver. For example, it could return a list of video modes that only has one video mode (the video mode that the boot code setup), and it might not support any optional capabilities/features, and anything it does support would be implemented in software (without hardware acceleration). Then, later on, you (or someone else) could implement video driver/s (based on your specification) that implement more of the optional capabilities and/or allow video mode switching and/or uses hardware acceleration. In the same way, software developers can write GUIs and/or libraries (e.g. OpenGL) and/or applications that rely on your specification, and this software can support things that are defined by the specification that aren't actually supported by any video driver (yet).
blm768 wrote:I just don't want to bother with it if it adds much effort; I'm hoping to get OpenGL drivers anyway (eventually...), so 2D acceleration likely wouldn't even be used much.
OpenGL is not a driver - OpenGL is an "Open Graphics Library" (a library that runs in user space). OpenGL may not have anything to do with the native video driver interface at all.

For example, the OpenGL library might create a "list of commands" in a buffer in RAM, and then send that list of commands to the native video driver (e.g. using a "draw a frame" native video driver function) when the application calls the "glFlush()" or "glFinish()" library function. In this case, the OpenGL specification doesn't describe the format of that "list of commands" being sent to the native video driver (it only describes the functions provided by a library).


Cheers,

Brendan

Re: Getting started with UEFI

Posted: Fri Aug 10, 2012 7:41 pm
by blm768
Brendan wrote: OpenGL is not a driver - OpenGL is an "Open Graphics Library" (a library that runs in user space). OpenGL may not have anything to do with the native video driver interface at all.
Good point.
My thought was that I would end up with two components for each card, a driver and a shared library. Each version of the shared library would be tailored to a specific driver, so the interface between the userspace library and the driver would be implementor-defined. Is that actually the way that most systems work?

The architecture you suggested sounds like a good idea. I'll probably implement something like it eventually, but graphics will definitely come after the userspace. Before that, I still have to make my UEFI bootloader...

For some strange reason, I can't make calls to UEFI "methods" directly; I have to use uefi_call_wrapper(). Strange...
Also, is there a good reference on loading a file with UEFI? I can't figure out how to get the EFI_DEVICE_PATH_PROTOCOL that LoadFile() uses as the file path.

Re: Getting started with UEFI

Posted: Sat Aug 11, 2012 8:22 am
by Brendan
Hi,
blm768 wrote:
Brendan wrote:OpenGL is not a driver - OpenGL is an "Open Graphics Library" (a library that runs in user space). OpenGL may not have anything to do with the native video driver interface at all.
Good point.
My thought was that I would end up with two components for each card, a driver and a shared library. Each version of the shared library would be tailored to a specific driver, so the interface between the userspace library and the driver would be implementor-defined. Is that actually the way that most systems work?
I'm not too sure how most systems do it. :)

Having a different OpenGL library for each different video driver could work, until you start thinking about supporting multiple monitors attached to different video cards and need to dynamically link several different versions of the OpenGL library at the same time.
blm768 wrote:For some strange reason, I can't make calls to UEFI "methods" directly; I have to use uefi_call_wrapper(). Strange...
UEFI uses Microsoft's calling conventions. GNU's tools use System V AMD64 ABI calling conventions. I'd assume the "uefi_call_wrapper()" wrapper exists to hide the differences.
blm768 wrote:Also, is there a good reference on loading a file with UEFI? I can't figure out how to get the EFI_DEVICE_PATH_PROTOCOL that LoadFile() uses as the file path.
The only reference I've seen is the UEFI spec/s (which could be described as "convoluted" rather than "good").

I don't know if what I did is right or if it's the easiest way, but...

When your boot loader is started, EFI passes an "EFI handle" for the loaded image (your boot loader) to your entry point. I use the EFI handle protocol to find the EFI loaded image protocol for this EFI handle. The protocol interface structure for the EFI loaded image protocol has an "EFI_DEVICE_PATH_PROTOCOL *FilePath" field - I think this is what you want (the device path for the device that the boot loader was loaded from).


Cheers,

Brendan

Re: Getting started with UEFI

Posted: Sat Aug 11, 2012 9:32 am
by blm768
Brendan wrote: Having a different OpenGL library for each different video driver could work, until you start thinking about supporting multiple monitors attached to different video cards and need to dynamically link several different versions of the OpenGL library at the same time.
I thought about that as well. If each application renders into an offscreen buffer, it doesn't really matter which card it's using; I can just allocate each one a card based on load. I'd just have to figure out how the window manager will work with the monitors...
By different versions, do you mean versions of the OpenGL specs or revisions of the driver/libraries?
Brendan wrote: UEFI uses Microsoft's calling conventions. GNU's tools use System V AMD64 ABI calling conventions. I'd assume the "uefi_call_wrapper()" wrapper exists to hide the differences.
My program hangs when I make the calls directly, so that's probably it.
Brendan wrote: The only reference I've seen is the UEFI spec/s (which could be described as "convoluted" rather than "good").
Absolutely. The ELF spec is much better, and I even got confused with that (figuring out where string tables are stored).

I think I'll try your method. If I can't figure out how the code works, I'll ask for further help, but I'll see if I can figure it out. Apparently, efilib has a function to locate protocols by GUID, which will make thinks nicer.

Re: Getting started with UEFI

Posted: Sat Aug 11, 2012 7:11 pm
by Brendan
Hi,
blm768 wrote:
Brendan wrote:
blm768 wrote:My thought was that I would end up with two components for each card, a driver and a shared library. Each version of the shared library would be tailored to a specific driver, so the interface between the userspace library and the driver would be implementor-defined. Is that actually the way that most systems work?
Having a different OpenGL library for each different video driver could work, until you start thinking about supporting multiple monitors attached to different video cards and need to dynamically link several different versions of the OpenGL library at the same time.
I thought about that as well. If each application renders into an offscreen buffer, it doesn't really matter which card it's using; I can just allocate each one a card based on load. I'd just have to figure out how the window manager will work with the monitors...
By different versions, do you mean versions of the OpenGL specs or revisions of the driver/libraries?
By different versions of the OpenGL library, I mean "Each version of the shared library would be tailored to a specific driver, so the interface between the userspace library and the driver would be implementor-defined.".
blm768 wrote:If each application renders into an offscreen buffer...
The job of a device driver is to provide an abstraction layer; so that other software doesn't need to care about underlying hardware details. For example, you wouldn't force applications to care about "cylinder, head, sector" for file IO would you?

Now let's imagine an application that wants to show a simple triangle. The triangle's colour is bright cyan, and happens to be a specific hue that can't be represented properly by the sRGB colour space (but can easily be represented by the CMYK colour space). The application's window is spread across 2 different monitors that are using different resolutions and different colour depths. The user will also want to send the application's triangle to the printer (it's a very nice triangle!).

Do you want the application to say "I need a bright cyan triangle" and let each device driver figure out the best way to draw it for their specific device; and end up with video drivers that clip the triangle to the edges of their screen then scale the vertexes to suit the resolution, and convert "bright cyan" into the closest colour their version of RGB can represent before using hardware acceleration to draw the part of the triangle that is visible on that screen (with full anti-aliased edges, etc); and do you want a printer driver that does similar vertex scaling to suit the printer's resolution and converts "bright cyan" into the printer's CMYK and prints the triangle (with dithering) with near perfect colour? This is all relatively easy and the application doesn't really need to care about any of it.

Do you want a leaky abstraction where the application can't figure out what to do and ends up drawing the same triangle (without any hardware acceleration at all) 3 different times for 3 different devices (in 3 different formats); before trying to push many MiB of graphics data around the system (instead of just 3 coords and a colour)?

The job of a device driver is to provide an abstraction layer; and if your abstraction has this much trouble with one simple triangle what hope are you going to have getting good results (and good performance) with multiple windows containing many icons, buttons, menus, pictures, tooltips, fonts, etc? ;)


Cheers,

Brendan