diff --git a/x86_64-efi/bootnetboot.c b/x86_64-efi/bootnetboot.c index 56ce433..ffcef6e 100644 --- a/x86_64-efi/bootnetboot.c +++ b/x86_64-efi/bootnetboot.c @@ -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; + // 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; - // first, try RomTable - LibGetSystemConfigurationTable(&RomTableGuid,(void *)&(RomTable)); - if(RomTable!=NULL) { - for (i=0;iPciOptionRomCount;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; - mementPhysicalStart==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;iHandleProtocol, 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;jNumberOfPartitionEntries;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;jNumberOfPartitionEntries;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 - 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){ diff --git a/x86_64-efi/efihttp.h b/x86_64-efi/efihttp.h index e38819d..9768342 100644 --- a/x86_64-efi/efihttp.h +++ b/x86_64-efi/efihttp.h @@ -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; //*******************************************