[Build/Dev Blog] Christmas Workstation Build (EFI RAM Disk Fun)

Work has resumed lol

So I’ve just realized why I haven’t been able to get any of the EFI System Table BootServices functions to work in my own code -

image

I didn’t really understand the underlying framework all that well until today, but most of the applications provided with the TianoCore EFI Toolkit are written using some kind of C Std Lib compatibility layer to allow things like passing argc and argv to main(), which is not a standard part of the EFI specification.

To do so, the MAKE files specify the entry point to the linker as _LIBC_Start_A which I’m guessing is defined way down in the C libraries. Don’t know much else about it because I don’t really care to know - to write a pure EFI application, the entry point here needs changed to your main() function so that you can receive the EFI ImageHandle and SystemTable parameters as described in the EFI specification instead of the _LIBC stepping on them.


So, to be fair to the developers, some of the complaints above are ‘correct’ in that they’re written with the assumption that this abstraction layer providing the C Std Lib will always be available. That said, the code is still written like garbage and this C library blows the binary size up seven times larger than just following the EFI implementation and using the standardized EFI system calls.


That too, but my goal here is that once I get this working I’ll have an EFI partition that can be portable to any system, to boot an arbitrary image in RAM from anything that can be detected as a storage device. No Linux kernel, etc.

3 Likes

Crap, wait a minute.

…Sapphire Rapids is going to be on DDR5 only, isn’t it? And probably Storm Peak too.

I do not want to pay for 512GB of DDR5.

Anyone at L1T want to hit up Micron and make a video out of this thing? :rofl: /s

Did I mention the Cheap 16GB DDR3 ECC sticks? $10 each.

1 Like

where?

eBay of course 16GB Samsung PC3-14900R DDR3 1866 2Rx4 Server Memory RAM M393B2G70QH0-CMA LOT | eBay

2 Likes

And that’s some fast registered 2R DDR3 too. If they’re still there tomorrow night when I get paid I’mma buy eight sticks of that for the old server board.

Unfortunately I’d need 32 sticks of it for this system and going from Rocket Lake to Ivy Bridge would be a bit rough lol

1 Like

image

I won’t stop you lol
image

Note to self for later

https://www.ipcstore.com/intel-xeon-w-2275-processor-3-3-ghz-19-25-mb-cd8069504393300

Buckle up, there ain’t no strings where we’re going.

No argc/*argv[] either, the EFI shell gives you a null-terminated string of the command line that was used to call the program and it’s yours from there.

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Populates args, argc, and argv with arguments extracted from command line.                                         //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EFI_STATUS parseCommandLine(
   CHAR16 * command,
   UINTN  commandSize, 
   CHAR16 ** args,
   UINTN  * argc, 
   CHAR16 *** argv)
{
   UINTN  position;
   
   position = 0;
   *argc = 0;
   
   if (*args != NULL)
   {
      FreePool(*args);
   }
   
   if (*argv != NULL)
   {
      FreePool(*argv);
   }
   
   // Absorb leading whitespace.
   while (command[position] == L' ')
   {
      position = position + 1;
   }
   
   // Check for no arguments.
   if (command[position] == L'\0')
   {
      return EFI_INVALID_PARAMETER;
   }

   *args = AllocateZeroPool(commandSize);      
   if (*args == NULL)
   {
      return EFI_OUT_OF_RESOURCES;
   }

   // Copy command line to string buffer.
   StrCpy(*args, command);

   // Parse arguments until NULL terminator is reached.
   while ((*args)[position] != L'\0')
   {
      // Absorb whitespace.
      while ((*args)[position] == L' ')
      {
         position = position + 1;
      }
      
      // Check for end of command line string.
      if ((*args)[position] != L'\0')
      {
         // Allocate new pointer for argument.
         if (*argc == 0)
         {
            *argv = AllocateZeroPool(sizeof(CHAR16*));
         }
         else
         {
            ReallocatePool(*argv, *argc * sizeof(CHAR16*), (*argc + 1) * sizeof(CHAR16*));
         }
         
         if (argv == NULL)
         {
            FreePool(*args);
            return EFI_OUT_OF_RESOURCES;
         }

         // Update pointer, increment count.
         (*argv)[*argc] = *args + position;
         *argc = *argc + 1;

         // Absorb argument.
         while (((*args)[position] != L' ') && ((*args)[position] != L'\0'))
         {
            position = position + 1;
         }
         
         // Null terminate argument, move to next.
         if ((*args)[position] != L'\0')
         {
            (*args)[position] = L'\0';
            position = position + 1;
         }
      }
   }
   
   // Done, return.
   return EFI_SUCCESS;
}

image

If I had any idea what I was doing when I got into this, it wouldn’t have taken a month, but at this point I’m pretty confident in writing basically anything I could ever need to run in the EFI environment pre-boot.

4 Likes

I’m excited to see this working :metal:

1 Like

Same lol, 90% of the actual work is done now and I just need to script it all together now.

I predict I’m going to have a whole new issue if I can’t get Windows to recognize the EFI disk driver, but we’ll deal with that when we come to it. :neutral_face:

Honestly wouldn’t still be plugging away at this a month later if I’d just used the C Std Library that came with the TianoCore toolkit, but I’d just end up not really understanding how the standard EFI protocols work anyway if I just abstract it away like that. It’s a learning experience.

1 Like

Now port a game to run without an OS lol
Seriously though, Doom running on UEFI.

3 Likes

I think we’re late to that party!

2 Likes

neet

I mean, it’s probably launching DOS or something and just going straight to the game.

I remember back in the day they had a uefi web browser, probably chrome

Would be super useful for downloading a bios update

2 Likes

I was surprised, UEFI networking is surprisingly easy to do with the amount of built-in protocol support that already exists. I wouldn’t want to be the one tasked with making a graphical browser that does CSS rendering/etc, but to just fetch a BIOS file from an address actually isn’t all that tough at least.

1 Like

Oh
Oh no

Welp, time to rewrite part of this. A thought occurred, I wrote this tool to use the EFI shell device name mapping (BLK0, BLK1, FS0, etc) to identify the source/destination. Each of these is stored in an environment variable with the corresponding hardware device path.

Well, I wasn’t thinking about these not being static, and when you boot this thing with a USB drive that wasn’t in there before, BLK4 might become BLK5 and you’ve just accidentally nuked one random storage device with another. Woops.

Sooo it’s a pain in the ass to type out but it’s using the device GUID now which is guarenteed to be static and unique.

4 Likes

I assumed some self identifying code to determine BLK/FS number or something.