setos

拙OS
Log | Files | Refs | LICENSE

commit 74f74b5ebc22d4699e3645d66dd9b0b9914d4293
parent d1b06f3b59bca0a6a7ab9ec3fc8748ed05d61bfa
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sat, 30 Mar 2024 14:47:24 +0900

divide directory

Diffstat:
M.gitignore | 1+
Akernel/main.c | 29+++++++++++++++++++++++++++++
Akernel/memmap.ld | 13+++++++++++++
Auefi/uefi.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Auefi/uefi.h | 408+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Auefi/utils.c | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Auefi/utils.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 907 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1,2 @@ include +OVMF.fd diff --git a/kernel/main.c b/kernel/main.c @@ -0,0 +1,28 @@ +#include "../uefi/uefi.h" + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; + +// Argument order is to interface to the MS-ABI +void +kernel_main(void *dummy0, void *dummy1, void *dummy2, + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop) +{ + uint32_t *fb_base = (uint32_t *)gop->Mode->FrameBufferBase; + uint32_t hrez = gop->Mode->Info->HorizontalResolution; + uint32_t vrez = gop->Mode->Info->VerticalResolution; + uint32_t sl = gop->Mode->Info->PixelsPerScanLine; + uint32_t cx = hrez / 2; + uint32_t cy = vrez / 2; + for (int i = 0; i < vrez; i++) { + for (int j = 0; j < hrez; j++) { + if ((cx-j)*(cx-j) + (cy-i)*(cy-i) < (vrez/3) * (vrez/3)) { + fb_base[i * sl + j] = 0xff << 16; + } else { + fb_base[i * sl + j] = 0xffffff; + } + } + } + for(;;); +} +\ No newline at end of file diff --git a/kernel/memmap.ld b/kernel/memmap.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + .text 0x100000 : { + *(.text) + } + .data : { + *(.data) + } + .bss : { + *(.bss) + } +} +\ No newline at end of file diff --git a/uefi/uefi.c b/uefi/uefi.c @@ -0,0 +1,120 @@ +#include "uefi.h" +#include "utils.h" +EFI_SYSTEM_TABLE *SystemTable; + +EFI_STATUS +EfiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *systab) +{ + // init global variable. + SystemTable = systab; + + EFI_STATUS stat; + + // Output firmware bender. + SystemTable->ConOut->ClearScreen(SystemTable->ConOut); + efi_printf("vendor: %w\n", SystemTable->FirmwareVendor); + efi_printf("EfiMain: 0x%x\n", EfiMain); + + // Output memory map information. + UINTN mmsize = 8196; + char mmbuf[8196]; + EFI_MEMORY_DESCRIPTOR *mmap; + UINTN mkey; + UINTN dsize; + UINT32 dver; + mmap = (EFI_MEMORY_DESCRIPTOR *) mmbuf; + stat = SystemTable->BootServices->GetMemoryMap(&mmsize, mmap, &mkey, &dsize, &dver); + if (stat != EFI_SUCCESS) { + efi_printf("get memory map: %d\n", stat); + return stat; + } + + for (; mmap < (EFI_MEMORY_DESCRIPTOR *)(mmbuf + mmsize); + mmap = (EFI_MEMORY_DESCRIPTOR *) (((char *)mmap) + dsize)) { + if (mmap->Type != EfiConventionalMemory) { + continue; + } + efi_printf("%d\t%x\t%x\t%x\t%x\n", mmap->Type, mmap->VirtualStart, + mmap->PhysicalStart, mmap->NumberOfPages, mmap->Attribute); + } + + EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; + stat = open_gop(ImageHandle, &gop); + if (stat != EFI_SUCCESS) { + efi_printf("open_gop: %d\n", stat); + return stat; + } + UINT32 *frame_buffer = (UINT32 *)gop->Mode->FrameBufferBase; + for (UINTN i = 0; i < gop->Mode->FrameBufferSize/4; i++) { + frame_buffer[i] = 0x427f94; + } + efi_printf("frame buffer: base: %x, size: %x\n", frame_buffer, + gop->Mode->FrameBufferSize); + + EFI_FILE_PROTOCOL *root, *kernel; + stat = open_root(ImageHandle, &root); + if (stat != EFI_SUCCESS) { + efi_printf("open_root: %d\n", stat); + return stat; + } + stat = root->Open(root, &kernel, L"setos.elf", + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0); + if (stat != EFI_SUCCESS) { + efi_printf("open file \"kernel.elf\": %d\n", stat); + return stat; + } + ElfHdr kernel_ehdr; + stat = read_ehdr(kernel, &kernel_ehdr); + if (stat != EFI_SUCCESS) { + efi_printf("read ehdr of \"kernel.elf\": %d\n", stat); + return stat; + } + efi_printf("type:\t%x\nphoff:\t%x\nphentsize:\t%x\nphnum:\t%x\n", + kernel_ehdr.type, kernel_ehdr.phoff, + kernel_ehdr.phentsize, kernel_ehdr.phnum); + if (kernel_ehdr.phnum > 32) { + efi_printf("too many phdrs\n"); + return EFI_BUFFER_TOO_SMALL; + } + Phdr kernel_phdr[32]; + stat = read_phdr(kernel, &kernel_ehdr, kernel_phdr); + if (stat != EFI_SUCCESS) { + efi_printf("read phdr of \"kernel.elf\": %d\n", stat); + return stat; + } + for (UINT16 i = 0; i < kernel_ehdr.phnum; i++) { + efi_printf("type: %x, offset: %x, vaddr: %x\n", + kernel_phdr[i].type, kernel_phdr[i].offset, kernel_phdr[i].vaddr); + } + stat = load_elf(kernel, &kernel_ehdr, kernel_phdr); + if (stat != EFI_SUCCESS) { + efi_printf("load \"kernel.elf\": %d\n", stat); + return stat; + } + stat = kernel->Close(kernel); + if (stat != EFI_SUCCESS) { + efi_printf("close file: %d\n", stat); + return stat; + } + + efi_printf("frame buffer: base: %x, %x, size: %x\n", frame_buffer, + gop->Mode->FrameBufferBase, + gop->Mode->FrameBufferSize); + + mmsize = 8196; + stat = SystemTable->BootServices->GetMemoryMap(&mmsize, mmap, &mkey, &dsize, &dver); + if (stat != EFI_SUCCESS) { + efi_printf("get memory map: %d\n", stat); + return stat; + } + stat = SystemTable->BootServices->ExitBootServices(ImageHandle, mkey); + if (stat != EFI_SUCCESS) { + efi_printf("exit boot services: %d\n", stat); + return stat; + } + + typedef void (* Kernel) (EFI_GRAPHICS_OUTPUT_PROTOCOL *); + ((Kernel) kernel_ehdr.entry)(gop); + + return EFI_SUCCESS; +} diff --git a/uefi/uefi.h b/uefi/uefi.h @@ -0,0 +1,408 @@ +#define IN +#define OUT +#define OPTIONAL +#define CONST +#define EFIAPI + +#define NULL 0L + +typedef unsigned short CHAR16; +typedef unsigned long long UINTN; +typedef unsigned char UINT8; +typedef short INT16; +typedef unsigned short UINT16; +typedef unsigned UINT32; +typedef unsigned long long UINT64; +typedef UINTN EFI_STATUS; +typedef void *EFI_HANDLE; +typedef UINT64 EFI_PHYSICAL_ADDRESS; +typedef UINT64 EFI_VIRTUAL_ADDRESS; +typedef void VOID; +typedef struct EFI_GUID { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + +#define EFI_LOADED_IMAGE_PROTOCOL_GUID \ + {0x5b1b31a1, 0x9562, 0x11d2, \ + {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \ + {0x9042a9de, 0x23dc, 0x4a38, \ + {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a}} +#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + {0x964e5b22, 0x6459, 0x11d2, \ + {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} +#define EFI_FILE_INFO_ID \ + {0x9576e92, 0x6d3f, 0x11d2, \ + {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}} + +// EFI_STATUS +enum { + EFI_SUCCESS = 0, + + EFI_INVALID_PARAMETER = 0x8000000000000002, + EFI_BUFFER_TOO_SMALL = 0x8000000000000005, +}; + +typedef struct _EFI_SYSTEM_TABLE EFI_SYSTEM_TABLE; + +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +typedef +EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY)( + IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL { + void *dummy; + EFI_INPUT_READ_KEY ReadKeyStroke; +} EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +typedef +EFI_STATUS (EFIAPI *EFI_TEXT_STRING)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, + IN CHAR16 *String + ); + +typedef +EFI_STATUS (EFIAPI *EFI_TEXT_CLEAR_SCREEN)( + IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This + ); + +struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL { + void *dummy; + EFI_TEXT_STRING OutputString; + void *dummy1[4]; + EFI_TEXT_CLEAR_SCREEN ClearScreen; +}; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiUnacceptedMemoryType, + EfiMaxMemoryType, +} EFI_MEMORY_TYPE; + +typedef struct { + UINT32 Type; + EFI_PHYSICAL_ADDRESS PhysicalStart; + EFI_VIRTUAL_ADDRESS VirtualStart; + UINT64 NumberOfPages; + UINT64 Attribute; +} EFI_MEMORY_DESCRIPTOR; + +typedef struct _EFI_GRAPHICS_OUTPUT_PROTOCOL EFI_GRAPHICS_OUTPUT_PROTOCOL; + +typedef enum { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax, +} EFI_GRAPHICS_PIXEL_FORMAT; + +typedef struct { + UINT32 RedMask; + UINT32 GreenMask; + UINT32 BlueMask; + UINT32 ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef struct { + UINT32 Version; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + EFI_GRAPHICS_PIXEL_FORMAT PixelFromat; // This is not fixed in size. + EFI_PIXEL_BITMASK PixelInformation; + UINT32 PixelsPerScanLine; +} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION; + +typedef struct { + UINT32 MaxMode; + UINT32 Mode; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINTN SizeOfInfo; + EFI_PHYSICAL_ADDRESS FrameBufferBase; + UINTN FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + +typedef +EFI_STATUS (EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE) ( + ); + +typedef +EFI_STATUS (EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE) ( + ); + +typedef +EFI_STATUS (EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT) ( + ); + +struct _EFI_GRAPHICS_OUTPUT_PROTOCOL { + EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE QueryMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE SetMode; + EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +}; + +typedef struct _EFI_FILE_PROTOCOL EFI_FILE_PROTOCOL; + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_OPEN) ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ); + +#define EFI_FILE_MODE_READ 0x0000000000000001 +#define EFI_FILE_MODE_WRITE 0x0000000000000002 +#define EFI_FILE_MODE_CREATE 0x8000000000000000 + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_CLOSE) ( + IN EFI_FILE_PROTOCOL *This + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_DELETE) ( + IN EFI_FILE_PROTOCOL *This + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_READ) ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_WRITE) ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_SET_POSITION) ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_GET_POSITION) ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ); + +typedef +EFI_STATUS (EFIAPI *EFI_FILE_GET_INFO) ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +struct _EFI_FILE_PROTOCOL { + UINT64 Revision; + EFI_FILE_OPEN Open; + EFI_FILE_CLOSE Close; + EFI_FILE_DELETE Delete; + EFI_FILE_READ Read; + EFI_FILE_WRITE Write; + EFI_FILE_GET_POSITION GetPosition; + EFI_FILE_SET_POSITION SetPosition; + EFI_FILE_GET_INFO GetInfo; + void *dummy1[6]; +}; + +typedef struct { + UINT16 Year; + UINT8 Month; + UINT8 Day; + UINT8 Hour; + UINT8 Minute; + UINT8 Second; + UINT8 Pad1; + UINT32 NanoSecond; + INT16 TimeZone; + UINT8 Daylight; + UINT8 Pad2; +} EFI_TIME; + +typedef struct { + UINT64 Size; + UINT64 FileSize; + UINT64 PhysicalSize; + EFI_TIME CreateTime; + EFI_TIME LastAccessTime; + EFI_TIME ModificationTime; + UINT64 Attribute; + CHAR16 FileName[]; +} EFI_FILE_INFO; + +typedef struct _EFI_LOADED_IMAGE_PROTOCOL EFI_LOADED_IMAGE_PROTOCOL; + +struct _EFI_LOADED_IMAGE_PROTOCOL{ + UINT32 Revision; + EFI_HANDLE ParentHandle; + EFI_SYSTEM_TABLE *SystemTable; + + EFI_HANDLE DeviceHandle; + void *dummy[2]; + + UINT32 LoadOptionSize; + VOID *LoadOptions; + + VOID *ImageBase; + UINT64 ImageSize; + char dummy1[4 + 4]; + void *dummy2; +}; + +typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; + +typedef +EFI_STATUS (EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ); + +struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL { + UINT64 Revision; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume; +}; + +typedef enum { + AllocateAnyPages, + AllocateMaxAddress, + AllocateAddress, + MaxAllocateType +} EFI_ALLOCATE_TYPE; + +typedef +EFI_STATUS (EFIAPI *EFI_ALLOCATE_PAGES)( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +typedef +EFI_STATUS (EFIAPI *EFI_GET_MEMORY_MAP)( + IN OUT UINTN *MemoryMapSize, + OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +typedef +EFI_STATUS (EFIAPI *EFI_EXIT_BOOT_SERVICES)( + IN EFI_HANDLE ImageHandle, + IN UINTN MapKey + ); + +typedef +EFI_STATUS (EFIAPI *EFI_OPEN_PROTOCOL)( + IN EFI_HANDLE Handle, + IN EFI_GUID *Protocol, + OUT VOID **Interface OPTIONAL, + IN EFI_HANDLE AgentHandle, + IN EFI_HANDLE ControllerHandle, + IN UINT32 Attributes + ); + +typedef enum { + AllHandles, + ByRegisterNotify, + ByProtocol +} EFI_LOCATE_SEARCH_TYPE; + +typedef +EFI_STATUS (EFIAPI *EFI_LOCATE_HANDLE_BUFFER)( + IN EFI_LOCATE_SEARCH_TYPE SearchType, + IN EFI_GUID *Protocol OPTIONAL, + IN VOID *SearchKey OPTIONAL, + OUT UINTN *NoHandles, + OUT EFI_HANDLE **Buffer + ); + +#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x1 + +typedef struct { +} EFI_RUNTIME_SERVICES; + +typedef struct { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + +typedef struct { + EFI_TABLE_HEADER Hdr; + // task priority services + void *task_priority_services[2]; + // memory services + EFI_ALLOCATE_PAGES AllocatePages; + void *memory_services0[1]; + EFI_GET_MEMORY_MAP GetMemoryMap; + void *memory_services1[2]; + // event timer services + void *event_timer_services[6]; + // protocol handler services + void *protocol_handler_services[9]; + // image services + void *image_services0[4]; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + void *miscellaneus_services[3]; + void *driversupport_services[2]; + EFI_OPEN_PROTOCOL OpenProtocol; + void *open_and_close_protocol_services[2]; + void *library_servies0[1]; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + void *library_servies1[3]; + void *crc_services[1]; + void *miscellaneus_services1[3]; +} EFI_BOOT_SERVICES; + +struct _EFI_SYSTEM_TABLE { + EFI_TABLE_HEADER Hdr; + CHAR16 *FirmwareVendor; + char dummy1[4]; + EFI_HANDLE ConsoleInHandle; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; + EFI_HANDLE ConsoleOutHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut; + EFI_HANDLE StandardErrorHandle; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; + EFI_RUNTIME_SERVICES *RuntimeServices; + EFI_BOOT_SERVICES *BootServices; + char dummy2[16]; +}; diff --git a/uefi/utils.c b/uefi/utils.c @@ -0,0 +1,265 @@ +#include <stdarg.h> // TODO: implement stdarg.h by my self + +#include "uefi.h" +#include "utils.h" + +CHAR16 * +sprinth(UINT64 n, CHAR16 s[19]) +{ + int i; + int d; + s[0] = L'0'; + s[1] = L'x'; + for (i = 0; i < 16; i++) { + d = (n >> (64 - (i + 1) * 4)) & 0xf; + if (d <= 9) + s[i + 2] = L'0' + d; + else + s[i + 2] = L'a' + d - 10; + } + s[19] = L'\0'; + return s; +} + +char * +wstr2str(CHAR16 *s16, char *s8) +{ + char *s = s8; + for (;*s16;) { + *s8++ = (char) (*s16++ & 0xff); + } + *s8 = '\0'; + return s; +} + +int +efi_printf(char *fmt, ...) +{ + va_list ap; + CHAR16 _buf[1024], *buf = _buf; + EFI_STATUS stat; + + char *s; + CHAR16 *w; + long long d, e; + unsigned long long f, g, h; + + va_start(ap, fmt); + for (;*fmt;) { + if (*fmt != '%') { + if (*fmt == '\n') { + *buf++ = (CHAR16) '\n'; + *buf++ = (CHAR16) '\r'; + fmt++; + continue; + } else { + *buf++ = (CHAR16) *fmt++; + continue; + } + } + fmt++; + switch (*fmt++) { + case '%': + *buf++ = L'%'; + break; + case 's': + s = va_arg(ap, char *); + for (;*s;) { + *buf++ = (CHAR16) *s++; + } + break; + case 'w': + w = va_arg(ap, CHAR16 *); + for (;*w;) { + *buf++ = *w++; + } + break; + case 'd': + d = va_arg(ap, int); + if (d == 0) { + *buf++ = '0'; + break; + } else if (d < 0) { + *buf++ = '-'; + d = -d; + } + for (e = 1; e <= d; e *= 10) { + if (e > e * 10) { // integer too big; + return -1; + } + } + for (e /= 10; e >= 1; e /= 10) { + *buf++ = (CHAR16) ('0' + ((d / e) % 10)); + } + break; + case 'x': + f = va_arg(ap, unsigned int); + if (f == 0) { + *buf++ = '0'; + break; + } + for (g = 1; g <= f; g *= 0x10) { + if (g > g * 0x10) { // integer too big. + return -1; + } + } + for (g /= 0x10; g >= 1; g /= 0x10) { + h = ((f / g) % 0x10); + if (h < 0xa) { + *buf++ = (CHAR16) ('0' + h); + } else { + *buf++ = (CHAR16) ('a' + h - 0xa); + } + } + break; + } + } + va_end(ap); + *buf = L'\0'; + + stat = SystemTable->ConOut->OutputString(SystemTable->ConOut, _buf); + if (stat != EFI_SUCCESS) { + return -1; + } + return (int) (buf - _buf); +} + +EFI_STATUS +open_root(EFI_HANDLE ImageHandle, EFI_FILE_PROTOCOL **root) +{ + EFI_STATUS stat; + EFI_LOADED_IMAGE_PROTOCOL *li; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + + stat = SystemTable->BootServices->OpenProtocol( + ImageHandle, &(EFI_GUID)EFI_LOADED_IMAGE_PROTOCOL_GUID, + (VOID **) &li, ImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + if (stat != EFI_SUCCESS) { + return stat; + } + + stat = SystemTable->BootServices->OpenProtocol( + li->DeviceHandle, &(EFI_GUID)EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, + (VOID **) &fs, ImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + if (stat != EFI_SUCCESS) { + return stat; + } + + stat = fs->OpenVolume(fs, root); + return stat; +} + +EFI_STATUS +open_gop(EFI_HANDLE ImageHandle, EFI_GRAPHICS_OUTPUT_PROTOCOL **gop) +{ + EFI_STATUS stat; + UINTN n = 0; + EFI_HANDLE *_gop; + stat = SystemTable->BootServices->LocateHandleBuffer( + ByProtocol, &(EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, NULL, + &n, &_gop + ); + if (stat != EFI_SUCCESS) { + efi_printf("locate handle buffer: %d\n", stat); + return stat; + } + stat = SystemTable->BootServices->OpenProtocol( + _gop[0], &(EFI_GUID)EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, + (VOID **) gop, ImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + if (stat != EFI_SUCCESS) { + efi_printf("open protocol: %d\n", stat); + return stat; + } + return EFI_SUCCESS; +} + +EFI_STATUS +read_ehdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr) +{ + EFI_STATUS stat; + UINTN ehdr_size = sizeof(ElfHdr); + + stat = elf->SetPosition(elf, 0); + if (stat != EFI_SUCCESS) { + efi_printf("set position: %d\n", stat); + return stat; + } + stat = elf->Read(elf, &ehdr_size, (VOID *) ehdr); + if (stat != EFI_SUCCESS) { + efi_printf("read: %d\n", stat); + return stat; + } + // TODO: check file format. + // for now, it assumes that elf is 2's complement, 64-bit little endian, + // System V ABI... + if (ehdr->ident[0] != 0x7f || ehdr->ident[1] != 'E' || + ehdr->ident[2] != 'L' || ehdr->ident[3] != 'F') { + efi_printf("not an elf file\n"); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +read_phdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]) +{ + EFI_STATUS stat; + UINTN n; + + stat = elf->SetPosition(elf, ehdr->phoff); + if (stat != EFI_SUCCESS) { + efi_printf("set position: %d\n", stat); + return stat; + } + // TODO: need overflow check?? + n = ehdr->phentsize * ehdr->phnum; + stat = elf->Read(elf, &n, (VOID *) phdr); + if (stat != EFI_SUCCESS) { + efi_printf("read phdr: %d\n", stat); + return stat; + } + return EFI_SUCCESS; +} + +EFI_STATUS +load_elf(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]) +{ + EFI_STATUS stat; + EFI_PHYSICAL_ADDRESS addr; + UINT64 size; + for (UINT16 i = 0; i < ehdr->phnum; i++) { + if (phdr[i].type != PT_LOAD) { + continue; + } + efi_printf("load_elf: allocate %d at %x\n", + phdr[i].memsz, phdr[i].vaddr + ); + stat = SystemTable->BootServices->AllocatePages( + AllocateAddress, EfiLoaderData, + (phdr[i].memsz + 0xfff) / 0x1000, &phdr[i].vaddr + ); + if (stat != EFI_SUCCESS) { + efi_printf("allocate pages: %d\n", stat); + return stat; + } + efi_printf("load_elf: phdr[i].vaddr: %x\n", phdr[i].vaddr); + stat = elf->SetPosition(elf, phdr[i].offset); + if (stat != EFI_SUCCESS) { + efi_printf("set position: %d\n", stat); + return stat; + } + addr = (EFI_PHYSICAL_ADDRESS) phdr[i].vaddr; + efi_printf("load_elf: read to %x\n", addr); + size = phdr[i].filesz; + stat = elf->Read(elf, &size, (VOID *)addr); + if (stat != EFI_SUCCESS) { + efi_printf("read to memory: %d\n", stat); + return stat; + } + } + return EFI_SUCCESS; +} diff --git a/uefi/utils.h b/uefi/utils.h @@ -0,0 +1,70 @@ +// #include "uefi.h" + +extern EFI_SYSTEM_TABLE *SystemTable; + +// Printh converts the integer into a string of hex representation. +// It returns the second argument. +// The second argument should have length of 19 ("0x" + "0123456789abcdef" + "\0"). +CHAR16 *sprinth(UINT64, CHAR16[19]); + +// Wstr2str converts UTF16-encoded string s16 to string. +// It ignores the high byte. +// caller must ensure that s has enough space. +// It returns s. +char *wstr2str(CHAR16 *s16, char *s8); + +// Efi_printf prints formatted string to ConOut. +// Can't format a string longer than 1024 CHAR16s. +// It returns number of CHAR16s written excluding the final NULL. +int efi_printf(char *fmt, ...); + +// Open_gop opens the graphics output protocol. +EFI_STATUS open_gop(EFI_HANDLE, EFI_GRAPHICS_OUTPUT_PROTOCOL **); + +// Open_root opens the root directory of the efi image. +EFI_STATUS open_root(EFI_HANDLE, EFI_FILE_PROTOCOL **); + +// ELF header. +typedef struct { + unsigned char ident[16]; + UINT16 type; + UINT16 machine; + UINT32 version; + UINTN entry; + UINTN phoff; + UINTN shoff; + UINT32 flags; + UINT16 ehsize; // ELF header's size. + UINT16 phentsize; + UINT16 phnum; + UINT16 shentsize; + UINT16 shnum; + UINT16 shstrndx; +} ElfHdr; + +typedef struct { + UINT32 type; + UINT32 flags; + UINTN offset; + UINTN vaddr; + UINTN paddr; + UINT64 filesz; + UINT64 memsz; + UINT64 align; +} Phdr; + +#define PT_LOAD 1 + +// Read_ehdr reads elf header and populates ehdr. +// It modifies elf's offset. +EFI_STATUS read_ehdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr); + +// Read_phdr reads elf's program headers and populates phdr. +// It uses ehdr to read phdr. +// It modifies elf's offset. +// Caller should allocate enough space in phdr. +EFI_STATUS read_phdr(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]); + +// Load_elf copies loadable segments of elf to the memory specified by the +// vaddr field of each Phdr. +EFI_STATUS load_elf(EFI_FILE_PROTOCOL *elf, ElfHdr *ehdr, Phdr phdr[]); +\ No newline at end of file