📄 efi.c
字号:
#include "efi/efi.h"#include "etherboot.h"#include "elf.h"#include "sal.h"#include "pal.h"#warning "Place a declaration of lookup_efi_nic somewhere useful"EFI_NETWORK_INTERFACE_IDENTIFIER_INTERFACE *lookup_efi_nic(int index);#warning "Place the declaraction of __call someplace more appropriate\n"extern EFI_STATUS __call(void *,...);/* Keep 16M free in case EFI needs to allocate some memory. * In the worst case this is only 1/8 the memory on an Itanium. */#define EFI_RESERVE_LOW_PAGES ((8*1024*1024)/EFI_PAGE_SIZE)#define EFI_RESERVE_HIGH_PAGES ((8*1024*1024)/EFI_PAGE_SIZE)struct console_info { uint16_t num_cols; uint16_t num_rows; uint16_t orig_x; uint16_t orig_y;};struct efi_mem_map { uint64_t map_size; uint64_t map_key; uint64_t descriptor_size; uint32_t descriptor_version; uint32_t pad; EFI_MEMORY_DESCRIPTOR map[64];};struct efi_info { int flags;#define READ_SYSTAB 1#define READ_FPSWA 2#define READ_MEMMAP 4 #define READ_CONINFO 8 EFI_SYSTEM_TABLE *systab; void *fpswa; struct efi_mem_map mem_map; struct console_info coninfo;};unsigned long io_base;/* local globals */static struct efi_info efi_info;static EFI_HANDLE etherboot_handle;static EFI_BOOT_SERVICES *boot_services;static SIMPLE_TEXT_OUTPUT_INTERFACE *conout;static SIMPLE_INPUT_INTERFACE *conin;static void *mps_table;static void *acpi20_table;static void *smbios_table;static void *nii_table;/* local functions */static EFI_STATUS efi_locate_handle( EFI_LOCATE_SEARCH_TYPE search_type, EFI_GUID *protocol, void *search_key, UINTN *buffer_size, EFI_HANDLE *buffer){ if (!boot_services) return EFI_NOT_FOUND; return __call(boot_services->LocateHandle, search_type, protocol, search_key, buffer_size, buffer);}static EFI_STATUS efi_handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface){ if (!boot_services) return EFI_UNSUPPORTED; return __call(boot_services->HandleProtocol, handle, protocol, interface);}static EFI_STATUS efi_locate_device_path(EFI_GUID *protocol, EFI_DEVICE_PATH **device_path, EFI_HANDLE *device){ if (!boot_services) return EFI_NOT_FOUND; return __call(boot_services->LocateDevicePath, protocol, device_path, device);}static EFI_STATUS efi_allocate_pages(EFI_ALLOCATE_TYPE type, EFI_MEMORY_TYPE memory_type, UINTN pages, EFI_PHYSICAL_ADDRESS *memory){ if (!boot_services) return EFI_OUT_OF_RESOURCES; return __call(boot_services->AllocatePages, type, memory_type, pages, memory);}static EFI_STATUS efi_free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN pages){ if(pages == 0) return EFI_SUCCESS; if (!boot_services) return EFI_INVALID_PARAMETER; return __call(boot_services->FreePages, memory, pages);}static EFI_STATUS efi_get_memory_map(UINTN *map_size, EFI_MEMORY_DESCRIPTOR *map, UINTN *map_key, UINTN *descriptor_size, UINT32 *descriptor_version){ if (!boot_services) return EFI_INVALID_PARAMETER; return __call(boot_services->GetMemoryMap, map_size, map, map_key, descriptor_size, descriptor_version);}static EFI_STATUS efi_free_pool(void *buffer){ if (!boot_services) return EFI_INVALID_PARAMETER; return __call(boot_services->FreePool, buffer);}static EFI_STATUS efi_stall(UINTN microseconds){ if (!boot_services) return EFI_UNSUPPORTED; return __call(boot_services->Stall, microseconds);}static EFI_STATUS efi_set_watchdog_timer( UINTN timeout, UINT64 watchdog_code, UINTN data_size, CHAR16 *watchdog_data){ if (!boot_services) return EFI_UNSUPPORTED; return __call(boot_services->SetWatchdogTimer, timeout, watchdog_code, data_size, watchdog_data);}static void efi_exit_boot_services(struct efi_mem_map *map){ EFI_STATUS status; if (!boot_services) return; status = __call(boot_services->ExitBootServices, etherboot_handle, map->map_key); if (status != EFI_SUCCESS) { printf("ExitBootServices failed: %lx\n", status); } conout = 0; conin = 0; boot_services = 0;}static void efi_free_memory(struct efi_mem_map *map){ EFI_MEMORY_DESCRIPTOR *desc, *tail;#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size))) tail = next_desc(map->map, map->map_size); for(desc = map->map; desc < tail; desc = next_desc(desc, map->descriptor_size)) { EFI_STATUS status; EFI_PHYSICAL_ADDRESS start, end; UINTN pages; int may_free; start = desc->PhysicalStart; pages = desc->NumberOfPages; end = start + pages * EFI_PAGE_SIZE; may_free = 0; /* The only canidates are Loader Code and Data */ if ((desc->Type == EfiLoaderData) || (desc->Type == EfiLoaderCode)) may_free = 1; /* Don't free anything etherboot lives in */ if ((may_free) && (start < virt_to_phys(_end)) && (end > virt_to_phys(_text))) may_free = 0; /* Continue if it is not memory we want to free */ if (!may_free) continue; status = efi_free_pages(start, pages); if (status != EFI_SUCCESS) { printf("free_pages: %lx\n", status); } }#undef next_desc}static void read_efi_mem_map(struct efi_mem_map *map){ EFI_STATUS status; map->map_size = sizeof(map->map); status = efi_get_memory_map( &map->map_size, map->map, &map->map_key, &map->descriptor_size, &map->descriptor_version); if (status != EFI_SUCCESS) { printf("read_efi_mem_map failed: %lx\n", status); map->map_size = 0; } /* map->descriptor_size should only grow larger */ /* map->descriptor_version should only increase and retain * a backward compatible format. */}#if 0static const char *efi_mem_type_name(uint32_t type){ const char *type_name; if (type == EfiReservedMemoryType) type_name = "EfiReservedMemoryType "; else if (type == EfiLoaderCode) type_name = "EfiLoaderCode "; else if (type == EfiLoaderData) type_name = "EfiLoaderData "; else if (type == EfiBootServicesCode) type_name = "EfiBootServicesCode "; else if (type == EfiBootServicesData) type_name = "EfiBootServicesData "; else if (type == EfiRuntimeServicesCode) type_name = "EfiRuntimeServicesCode "; else if (type == EfiRuntimeServicesData) type_name = "EfiRuntimeServicesData "; else if (type == EfiConventionalMemory) type_name = "EfiConventionalMemory "; else if (type == EfiUnusableMemory) type_name = "EfiUnusableMemory "; else if (type == EfiACPIReclaimMemory) type_name = "EfiACPIReclaimMemory "; else if (type == EfiACPIMemoryNVS) type_name = "EfiACPIMemoryNVS "; else if (type == EfiMemoryMappedIO) type_name = "EfiMemoryMappedIO "; else if (type == EfiMemoryMappedIOPortSpace) type_name = "EfiMemoryMappedIOPortSpace"; else if (type == EfiPalCode) type_name = "EfiPalCode "; else type_name = "???? "; return type_name;}static void print_efi_mem_map(struct efi_mem_map *map){ EFI_MEMORY_DESCRIPTOR *desc, *end;#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size))) end = next_desc(map->map, map->map_size); for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) { const char *mem_type; unsigned long start, end, virt, virt_end; uint64_t attr; mem_type = efi_mem_type_name(desc->Type); start = desc->PhysicalStart; end = start + desc->NumberOfPages*EFI_PAGE_SIZE; virt = desc->VirtualStart; virt_end = virt + desc->NumberOfPages*EFI_PAGE_SIZE; attr = desc->Attribute; printf( "mem: %hhx %s @ %#lx-%#lx", desc->Type, mem_type, start, end); if (attr & EFI_MEMORY_UC) printf("UC "); if (attr & EFI_MEMORY_WC) printf("WC "); if (attr & EFI_MEMORY_WT) printf("WT "); if (attr & EFI_MEMORY_WB) printf("WB "); if (attr & EFI_MEMORY_UCE) printf("UCE "); if (attr & EFI_MEMORY_WP) printf("WP "); if (attr & EFI_MEMORY_RP) printf("RP "); if (attr & EFI_MEMORY_XP) printf("XP "); if (attr & EFI_MEMORY_RUNTIME) printf("RUNTIME "); printf("\n"); }#undef next_desc}#endifstatic void efi_allocate_memory(struct efi_mem_map *map){ EFI_MEMORY_DESCRIPTOR *desc, *end; unsigned long low_free, high_free;#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size))) end = next_desc(map->map, map->map_size); /* Find out how much memory is free */ low_free = high_free = 0; for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) { unsigned long start, middle, end; if (desc->Type != EfiConventionalMemory) continue; start = desc->PhysicalStart; end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE); if (start < 0x100000000UL) { if (end > 0x100000000UL) { middle = 0x10000000UL; } else { middle = end; } } else { middle = start; } low_free += (middle - start)/EFI_PAGE_SIZE; high_free += (end - middle)/EFI_PAGE_SIZE; } /* O.k. Now allocate all of the conventional memory, reserving only a tiny * fraction for efi. */ for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) { EFI_STATUS status; EFI_PHYSICAL_ADDRESS address; UINTN pages; unsigned long start, middle, end; unsigned long low_pages, high_pages; if (desc->Type != EfiConventionalMemory) continue; start = desc->PhysicalStart; end = desc->PhysicalStart + (desc->NumberOfPages*EFI_PAGE_SIZE); if (start < 0x100000000UL) { if (end > 0x100000000UL) { middle = 0x10000000UL; } else { middle = end; } } else { middle = start; } low_pages = (middle - start)/EFI_PAGE_SIZE; high_pages = (end - middle)/EFI_PAGE_SIZE; if (low_pages && (low_free > EFI_RESERVE_LOW_PAGES)) { address = start; pages = low_pages; if ((low_free - pages) < EFI_RESERVE_LOW_PAGES) { pages = low_free - EFI_RESERVE_LOW_PAGES; } status = efi_allocate_pages( AllocateAddress, EfiLoaderData, pages, &address); if (status != EFI_SUCCESS) { printf("allocate_pages @%lx for %ld pages failed: %ld\n", desc->PhysicalStart, pages, status); } low_free -= pages; } if (high_pages && (high_free > EFI_RESERVE_HIGH_PAGES)) { address = middle; pages = high_pages; if ((high_free - pages) < EFI_RESERVE_HIGH_PAGES) { pages = high_free - EFI_RESERVE_HIGH_PAGES; } status = efi_allocate_pages( AllocateAddress, EfiLoaderData, pages, &address); if (status != EFI_SUCCESS) { printf("allocate_pages @%lx for %ld pages failed: %ld\n", desc->PhysicalStart, pages, status); } high_free -= pages; } }#undef next_desc}static void set_io_base(struct efi_mem_map *map){ EFI_MEMORY_DESCRIPTOR *desc, *end; io_base = ia64_get_kr0(); /* Default to ar.kr0 */#define next_desc(desc, size) ((EFI_MEMORY_DESCRIPTOR *)(((char *)(desc)) + (size))) end = next_desc(map->map, map->map_size); for(desc = map->map; desc < end ; desc = next_desc(desc, map->descriptor_size)) { if (desc->Type == EfiMemoryMappedIOPortSpace) { io_base = desc->PhysicalStart; break; } }#undef next_desc}#define MAX_EFI_DEVICES 32static void efi_stop_nics(void){ static EFI_GUID simple_net_protocol = EFI_SIMPLE_NETWORK_PROTOCOL; EFI_SIMPLE_NETWORK *simple; EFI_STATUS status; EFI_HANDLE handles[MAX_EFI_DEVICES]; EFI_HANDLE handle; UINTN devices; unsigned i; if (!boot_services) return; devices = sizeof(handles); status = efi_locate_handle( ByProtocol, &simple_net_protocol, 0, &devices, handles); if (status != EFI_SUCCESS) return; devices /= sizeof(handles[0]); for(i = 0; i < devices; i++) { void *that; handle = handles[i]; status = efi_handle_protocol(handle, &simple_net_protocol, &that); if (status != EFI_SUCCESS) continue; simple = that; if ((simple->Mode->State == EfiSimpleNetworkInitialized)) { status = __call(simple->Shutdown, simple); status = __call(simple->Stop, simple); } else if (simple->Mode->State == EfiSimpleNetworkStarted) { status = __call(simple->Stop, simple); } }}static void efi_get_coninfo(struct console_info *info){ EFI_STATUS status; UINTN cols, rows; /* Initialize with some silly safe values */ info->num_cols = 80; info->num_rows = 24; info->orig_x = 0; info->orig_y = 0; status = EFI_UNSUPPORTED; if (conout) { status = __call(conout->QueryMode, conout, conout->Mode->Mode, &cols, &rows); if (status) { printf("QueryMode Failed cannout get console parameters: %ld\n", status); } else { info->num_cols = cols; info->num_rows = rows; info->orig_x = conout->Mode->CursorColumn; info->orig_y = conout->Mode->CursorRow; } }}static void *efi_get_fpswa(void){ static EFI_GUID fpswa_protocol = FPSWA_PROTOCOL; EFI_STATUS status; EFI_HANDLE fpswa_handle; UINTN devices; void *result; /* The FPSWA is the Floating Point Software Assist driver, * to some extent it makes sense but it has one large flaw. * It fails to install an EFI Configuration table, so the * OS does not need assistance from the bootloader to find it. */ devices = sizeof(fpswa_handle); status = efi_locate_handle( ByProtocol, &fpswa_protocol, 0, &devices, &fpswa_handle); if (status != EFI_SUCCESS) return 0; status = efi_handle_protocol( fpswa_handle, &fpswa_protocol, &result); if (status != EFI_SUCCESS) return 0; return result;}/* Exported functions */void arch_main(struct Elf_Bhdr *bhdr){ EFI_STATUS status; unsigned char *note, *end; memset(&efi_info, 0, sizeof(efi_info)); note = ((char *)bhdr) + sizeof(*bhdr); end = ((char *)bhdr) + bhdr->b_size; if (bhdr->b_signature != 0x0E1FB007) { printf("Bad bhdr(%lx) signature(%x)!\n", (unsigned long) bhdr, bhdr->b_signature); note = end = 0; } while(note < end) { Elf_Nhdr *hdr; unsigned char *n_name, *n_desc, *next; hdr = (Elf_Nhdr *)note; n_name = note + sizeof(*hdr); n_desc = n_name + ((hdr->n_namesz + 3) & ~3); next = n_desc + ((hdr->n_descsz + 3) & ~3); if (next > end) break;#if 0 printf("n_type: %x n_name(%d): n_desc(%d): \n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -