Creating a HTTP EFI handle

This commit is contained in:
Thomas Oltmann 2025-06-04 21:43:26 +02:00
parent 3fd0ea1b79
commit c1f7148f30
2 changed files with 28 additions and 222 deletions

View file

@ -1,4 +1,5 @@
/*
/* vim: et:sw=4:ts=4
*
* x86_64-efi/bootboot.c
*
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
@ -1453,17 +1454,11 @@ EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
EFI_LOADED_IMAGE *loaded_image = NULL;
EFI_GUID lipGuid = LOADED_IMAGE_PROTOCOL;
EFI_GUID RomTableGuid = EFI_PCI_OPTION_ROM_TABLE_GUID;
EFI_PCI_OPTION_ROM_TABLE *RomTable;
EFI_GUID bioGuid = BLOCK_IO_PROTOCOL;
EFI_BLOCK_IO *bio;
EFI_HANDLE *handles = NULL;
EFI_STATUS status=EFI_SUCCESS;
EFI_MEMORY_DESCRIPTOR *memory_map = NULL, *mement;
EFI_PARTITION_TABLE_HEADER *gptHdr;
EFI_PARTITION_ENTRY *gptEnt;
EFI_INPUT_KEY key;
EFI_GUID http_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
EFI_SERVICE_BINDING *http_binding;
EFI_HANDLE http_handle;
#if USE_MP_SERVICES
EFI_EVENT Event;
EFI_GUID mpspGuid = EFI_MP_SERVICES_PROTOCOL_GUID;
@ -1474,16 +1469,14 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
UINT64 ncycles = 0, currtime, endtime;
UINTN bad_madt=0;
#endif
EFI_GUID SerIoGuid = EFI_SERIAL_IO_PROTOCOL_GUID;
EFI_SERIAL_IO_PROTOCOL *ser = NULL;
UINTN bsp_num=0, i, j=0, x,y, handle_size=0,memory_map_size=0, map_key=0, desc_size=0;
UINTN bsp_num=0, i, j=0, x,y, memory_map_size=0, map_key=0, desc_size=0;
UINT32 desc_version=0, a, b;
UINT64 lba_s=0,lba_e=0,sysptr;
MMapEnt *mmapent, *last=NULL, *sort;
file_t ret={NULL,0};
CHAR16 **argv, *initrdfile, *configfile, *help=
CHAR16 **argv, *configfile, *help=
L"SYNOPSIS\n BOOTBOOT.EFI [ -h | -? | /h | /? | -s ] [ INITRDFILE [ ENVIRONFILE [...] ] ]\n\nDESCRIPTION\n Bootstraps an operating system via the BOOTBOOT Protocol.\n If arguments not given, defaults to\n FS0:\\BOOTBOOT\\INITRD as ramdisk image and\n FS0:\\BOOTBOOT\\CONFIG for boot environment.\n Additional \"key=value\" command line arguments will be appended to the\n environment. If INITRD not found, it will use the first bootable partition\n in GPT. If CONFIG not found, it will look for /sys/config inside the\n INITRD (or partition). With -s it will scan the memory for an initrd ROM.\n\n As this is a loader, it is not supposed to return control to the shell.\n\n";
INTN argc, scanmemory=0;
INTN argc;
// Initialize UEFI Library
InitializeLib(image, systab);
@ -1498,16 +1491,8 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
Print(L"BOOTBOOT LOADER (build %s)\n\n%s",a2u(__DATE__),help);
return EFI_SUCCESS;
}
if(argv[1][0]=='-'||argv[1][0]=='s') {
argc--; argv++; scanmemory = 1;
}
}
if(argc>1) {
initrdfile=argv[1];
} else {
initrdfile=L"\\BOOTBOOT\\INITRD";
}
if(argc>2) {
configfile=argv[2];
} else {
configfile=L"\\BOOTBOOT\\CONFIG";
@ -1562,205 +1547,28 @@ efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
} while(0)
#endif
// locate InitRD in ROM
DBG(L" * Locate initrd in Option ROMs%s\n",L"");
RomTable = NULL; initrd.ptr = NULL; initrd.size = 0;
status=EFI_LOAD_ERROR;
// first, try RomTable
LibGetSystemConfigurationTable(&RomTableGuid,(void *)&(RomTable));
if(RomTable!=NULL) {
for (i=0;i<RomTable->PciOptionRomCount;i++) {
ret.ptr=(UINT8*)RomTable->PciOptionRomDescriptors[i].RomAddress;
if(ret.ptr[0]==0x55 && ret.ptr[1]==0xAA && !CompareMem(ret.ptr+8,(const CHAR8 *)"INITRD",6)) {
CopyMem(&initrd.size,ret.ptr+16,4);
initrd.ptr=ret.ptr+32;
status=EFI_SUCCESS;
break;
}
}
}
//if not found, scan memory
if(scanmemory && (EFI_ERROR(status) || initrd.ptr==NULL)){
status = uefi_call_wrapper(BS->GetMemoryMap, 5,
&memory_map_size, memory_map, NULL, &desc_size, NULL);
if (status!=EFI_BUFFER_TOO_SMALL || memory_map_size==0) {
return report(EFI_OUT_OF_RESOURCES,L"GetMemoryMap getSize");
}
memory_map_size+=2*desc_size;
memory_map = NULL;
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2,
(memory_map_size+PAGESIZE-1)/PAGESIZE,
(EFI_PHYSICAL_ADDRESS*)&memory_map);
if (EFI_ERROR(status) || memory_map == NULL) {
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages");
}
status = uefi_call_wrapper(BS->GetMemoryMap, 5,
&memory_map_size, memory_map, &map_key, &desc_size, &desc_version);
status=EFI_LOAD_ERROR;
for(mement=memory_map;
mement<memory_map+memory_map_size;
mement=NextMemoryDescriptor(mement,desc_size)) {
if(mement==NULL || (mement->PhysicalStart==0 && mement->NumberOfPages==0))
break;
// skip free and ACPI memory
if(mement->Type==7||(mement->Type>=9&&mement->Type<=13))
continue;
// according to spec, EFI Option ROMs must start on 512 bytes boundary, not 2048
for(ret.ptr=(UINT8*)mement->PhysicalStart;
ret.ptr+512<(UINT8*)mement->PhysicalStart+mement->NumberOfPages*PAGESIZE;
ret.ptr+=512) {
if(ret.ptr[0]==0x55 && ret.ptr[1]==0xAA && !CompareMem(ret.ptr+8,(const CHAR8 *)"INITRD",6)) {
CopyMem(&initrd.size,ret.ptr+16,4);
initrd.ptr=ret.ptr+32;
status=EFI_SUCCESS;
goto foundinrom;
}
}
}
foundinrom:
uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)memory_map, (memory_map_size+PAGESIZE-1)/PAGESIZE);
}
// try reading the initrd from serial line
if(EFI_ERROR(status) || initrd.ptr==NULL){
status = uefi_call_wrapper(BS->LocateProtocol, 3, &SerIoGuid, NULL, (void**)&ser);
if(!EFI_ERROR(status) && ser) {
// 1000 microsec timeout, mode 115200,8,n,1
status = uefi_call_wrapper(ser->SetAttributes, 7, ser, 115200, 0, 1000, NoParity, 8, OneStopBit);
if(!EFI_ERROR(status)) {
i = 3;
uefi_call_wrapper(ser->Write, 3, ser, &i, "\003\003\003");
i = 4; initrd.size = 0;
status = uefi_call_wrapper(ser->Read, 3, ser, &i, (VOID*)&initrd.size);
if(!EFI_ERROR(status) && i == 4) {
i = 2;
if(initrd.size < 32 || initrd.size >= INITRD_MAXSIZE*1024*1024) {
uefi_call_wrapper(ser->Write, 3, ser, &i, "SE");
initrd.size = 0;
status = EFI_LOAD_ERROR;
} else {
initrd.ptr = NULL;
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, (initrd.size+PAGESIZE-1)/PAGESIZE,
(EFI_PHYSICAL_ADDRESS*)&initrd.ptr);
if (EFI_ERROR(status) || initrd.ptr == NULL) {
uefi_call_wrapper(ser->Write, 3, ser, &i, "SE");
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages");
}
uefi_call_wrapper(ser->Write, 3, ser, &i, "OK");
i = initrd.size;
status = uefi_call_wrapper(ser->Read, 3, ser, &i, (VOID*)initrd.ptr);
if(EFI_ERROR(status) || i != initrd.size) {
uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)initrd.ptr,
(initrd.size+PAGESIZE-1)/PAGESIZE);
initrd.ptr = NULL;
initrd.size = 0;
status = EFI_LOAD_ERROR;
}
}
}
}
}
}
// fall back to INITRD on filesystem
if(EFI_ERROR(status) || initrd.ptr==NULL){
// if the user presses any key now, we fallback to backup initrd
for(i=0;i<500;i++) {
if(!uefi_call_wrapper(BS->CheckEvent, 1, CI->WaitForKey)) {
uefi_call_wrapper(CI->ReadKeyStroke, 2, CI, &key);
Print(L" * Backup initrd\n");
initrdfile=L"\\BOOTBOOT\\INITRD.BAK";
break;
}
// delay 1ms
uefi_call_wrapper(BS->Stall, 1, 1000);
}
DBG(L" * Locate initrd in %s\n",initrdfile);
// Initialize FS with the DeviceHandler from loaded image protocol
status = uefi_call_wrapper(BS->HandleProtocol,
3,
image,
&lipGuid,
(void **) &loaded_image);
if (!EFI_ERROR(status) && loaded_image!=NULL) {
status=EFI_LOAD_ERROR;
RootDir = LibOpenRoot(loaded_image->DeviceHandle);
// load ramdisk
status=LoadFile(initrdfile,&initrd.ptr, &initrd.size);
}
}
// if not found, try architecture specific initrd file
if(EFI_ERROR(status) || initrd.ptr==NULL){
initrdfile=L"\\BOOTBOOT\\X86_64";
DBG(L" * Locate initrd in %s\n",initrdfile);
status=LoadFile(initrdfile,&initrd.ptr, &initrd.size);
}
// if even that failed, look for a partition
if(status!=EFI_SUCCESS || initrd.size==0){
DBG(L" * Locate initrd in GPT%s\n",L"");
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);
if (status!=EFI_BUFFER_TOO_SMALL || handle_size==0) {
return report(EFI_OUT_OF_RESOURCES,L"LocateHandle getSize");
}
handles = NULL;
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, (handle_size+PAGESIZE-1)/PAGESIZE,
(EFI_PHYSICAL_ADDRESS*)&handles);
if(EFI_ERROR(status) || handles == NULL)
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages\n");
initrd.ptr = NULL;
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, 1, (EFI_PHYSICAL_ADDRESS*)&initrd.ptr);
if (EFI_ERROR(status) || initrd.ptr == NULL)
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages");
lba_s=lba_e=0;
status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &bioGuid, NULL, &handle_size, handles);
for(i=0;i<handle_size/sizeof(EFI_HANDLE);i++) {
// we have to do it the hard way. HARDDRIVE_DEVICE_PATH does not return partition type or attribs...
status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &bioGuid, (void **) &bio);
if(status!=EFI_SUCCESS || bio==NULL || bio->Media->BlockSize==0)
continue;
status = uefi_call_wrapper(bio->ReadBlocks, 5, bio, bio->Media->MediaId, 1, PAGESIZE, initrd.ptr);
if(status!=EFI_SUCCESS || CompareMem(initrd.ptr,EFI_PTAB_HEADER_ID,8))
continue;
gptHdr = (EFI_PARTITION_TABLE_HEADER*)initrd.ptr;
if(gptHdr->NumberOfPartitionEntries>127) gptHdr->NumberOfPartitionEntries=127;
// first, look for a partition with bootable flag
ret.ptr= (UINT8*)(initrd.ptr + (gptHdr->PartitionEntryLBA-1) * bio->Media->BlockSize);
for(j=0;j<gptHdr->NumberOfPartitionEntries;j++) {
gptEnt=(EFI_PARTITION_ENTRY*)ret.ptr;
if((ret.ptr[0]==0 && ret.ptr[1]==0 && ret.ptr[2]==0 && ret.ptr[3]==0) || gptEnt->StartingLBA==0)
break;
// use first partition with bootable flag as INITRD
if((gptEnt->Attributes & EFI_PART_USED_BY_OS)) goto partfound;
ret.ptr+=gptHdr->SizeOfPartitionEntry;
}
// if none, look for specific partition types
ret.ptr= (UINT8*)(initrd.ptr + (gptHdr->PartitionEntryLBA-1) * bio->Media->BlockSize);
for(j=0;j<gptHdr->NumberOfPartitionEntries;j++) {
gptEnt=(EFI_PARTITION_ENTRY*)ret.ptr;
if((ret.ptr[0]==0 && ret.ptr[1]==0 && ret.ptr[2]==0 && ret.ptr[3]==0) || gptEnt->StartingLBA==0)
break;
// use the first OS/Z root partition for this architecture
if(!CompareMem(&gptEnt->PartitionTypeGUID.Data1,"OS/Z",4) &&
gptEnt->PartitionTypeGUID.Data2==0x8664 &&
!CompareMem(&gptEnt->PartitionTypeGUID.Data4[4],"root",4)) {
partfound: lba_s=gptEnt->StartingLBA; lba_e=gptEnt->EndingLBA;
initrd.size = (((lba_e-lba_s)*bio->Media->BlockSize + PAGESIZE-1)/PAGESIZE)*PAGESIZE;
status=EFI_SUCCESS;
goto partok;
}
ret.ptr+=gptHdr->SizeOfPartitionEntry;
}
}
return report(EFI_LOAD_ERROR,L"No boot partition");
partok:
uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)initrd.ptr, 1);
if(initrd.size>0 && bio!=NULL) {
initrd.ptr = NULL;
status = uefi_call_wrapper(BS->AllocatePages, 4, 0, 2, initrd.size/PAGESIZE, (EFI_PHYSICAL_ADDRESS*)&initrd.ptr);
if (EFI_ERROR(status) || initrd.ptr == NULL)
return report(EFI_OUT_OF_RESOURCES,L"AllocatePages");
status = uefi_call_wrapper(bio->ReadBlocks, 5, bio, bio->Media->MediaId, lba_s, initrd.size, initrd.ptr);
} else
// Try to locate HTTP service binding protocol
DBG(L" * Locating HTTP service binding protocol%s\n", L"");
status = uefi_call_wrapper(BS->LocateProtocol, 3, &http_binding_guid, NULL, (void **)&http_binding);
if (EFI_ERROR(status)) {
return report(status, L"LocateProtocol");
}
// Create a HTTP protocol handle
DBG(L" * Creating HTTP protocol handle%s\n", L"");
http_handle=NULL;
status = uefi_call_wrapper(http_binding->CreateChild, 2, http_binding, &http_handle);
if (EFI_ERROR(status)) {
return report(status, L"CreateChild");
}
status=EFI_LOAD_ERROR;
// Retrieve InitRD from external HTTP server
{
for (;;) {}
}
if(status==EFI_SUCCESS && initrd.size>0){
//check if initrd is gzipped
if(initrd.ptr[0]==0x1f && initrd.ptr[1]==0x8b){

View file

@ -17,8 +17,6 @@
{0x7A59B29B, 0x910B, 0x4171,\
{0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B}}
INTERFACE_DECL(_EFI_HTTP);
typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL;
//*******************************************