diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-10-18 02:13:02 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-10-18 02:13:02 +0200 |
commit | 6f3dfb57eba2eb9ab21e4a0d06c8415cccf45fb1 (patch) | |
tree | 871ec1925cc8500c081000d2d3050fcfff4d1d4a /sys/src/boot | |
parent | 0a6439a1f564de17bfad7a327178e47483a86e1a (diff) |
efi: add experimental efi bootloader
this is basically a port of 9boot to EFI. theres
support for IA32 (386) and X64 (amd64).
has been tested only under qemu with OVMF so far.
Diffstat (limited to 'sys/src/boot')
-rw-r--r-- | sys/src/boot/efi/efi.c | 272 | ||||
-rw-r--r-- | sys/src/boot/efi/efi.h | 270 | ||||
-rw-r--r-- | sys/src/boot/efi/fns.h | 29 | ||||
-rw-r--r-- | sys/src/boot/efi/mem.h | 47 | ||||
-rw-r--r-- | sys/src/boot/efi/mkfile | 43 | ||||
-rw-r--r-- | sys/src/boot/efi/pe32.s | 149 | ||||
-rw-r--r-- | sys/src/boot/efi/pe64.s | 234 | ||||
-rw-r--r-- | sys/src/boot/efi/sub.c | 382 |
8 files changed, 1426 insertions, 0 deletions
diff --git a/sys/src/boot/efi/efi.c b/sys/src/boot/efi/efi.c new file mode 100644 index 000000000..b317a2b94 --- /dev/null +++ b/sys/src/boot/efi/efi.c @@ -0,0 +1,272 @@ +#include <u.h> +#include "fns.h" +#include "efi.h" + +enum { + MAXPATH = 128, +}; + +UINTN MK; +EFI_HANDLE *IH; +EFI_SYSTEM_TABLE *ST; + +EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; +EFI_FILE_PROTOCOL *root; + +void +putc(int c) +{ + CHAR16 w[2]; + + w[0] = c; + w[1] = 0; + eficall(2, ST->ConOut->OutputString, ST->ConOut, w); +} + +int +getc(void) +{ + EFI_INPUT_KEY k; + + if(eficall(2, ST->ConIn->ReadKeyStroke, ST->ConIn, &k)) + return 0; + return k.UnicodeChar; +} + +void +usleep(int us) +{ + eficall(1, ST->BootServices->Stall, (UINTN)us); +} + +void +unload(void) +{ + eficall(2, ST->BootServices->ExitBootServices, IH, MK); +} + +EFI_STATUS +LocateProtocol(EFI_GUID *guid, void *reg, void **pif) +{ + return eficall(3, ST->BootServices->LocateProtocol, guid, reg, pif); +} + +void +fsinit(void) +{ + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + + fs = nil; + root = nil; + if(LocateProtocol(&EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID, nil, &fs)) + return; + if(eficall(2, fs->OpenVolume, fs, &root)){ + root = nil; + return; + } +} + +static void +towpath(CHAR16 *w, int nw, char *s) +{ + int i; + + for(i=0; *s && i<nw-1; i++){ + *w = *s++; + if(*w == '/') + *w = '\\'; + w++; + } + *w = 0; +} + +EFI_FILE_PROTOCOL* +fswalk(EFI_FILE_PROTOCOL *dir, char *name) +{ + CHAR16 wname[MAXPATH]; + EFI_FILE_PROTOCOL *fp; + + towpath(wname, MAXPATH, name); + + fp = nil; + if(eficall(5, dir->Open, dir, &fp, wname, (UINT64)1, (UINT64)1)) + return nil; + return fp; +} + + +int +read(void *f, void *data, int len) +{ + UINTN size; + + size = len; + if(eficall(3, ((EFI_FILE_PROTOCOL*)f)->Read, f, &size, data)) + return 0; + return (int)size; +} + +void +close(void *f) +{ + eficall(1, ((EFI_FILE_PROTOCOL*)f)->Close, f); +} + + +static void +memconf(char **cfg) +{ + static uchar memtype[EfiMaxMemoryType] = { + [EfiReservedMemoryType] 2, + [EfiLoaderCode] 1, + [EfiLoaderData] 1, + [EfiBootServicesCode] 1, + [EfiBootServicesData] 1, + [EfiRuntimeServicesCode] 1, + [EfiRuntimeServicesData] 1, + [EfiConventionalMemory] 1, + [EfiUnusableMemory] 2, + [EfiACPIReclaimMemory] 3, + [EfiACPIMemoryNVS] 4, + [EfiMemoryMappedIO] 2, + [EfiMemoryMappedIOPortSpace] 2, + [EfiPalCode] 2, + }; + UINTN mapsize, entsize; + EFI_MEMORY_DESCRIPTOR *t; + uchar mapbuf[96*1024], *p, m; + UINT32 entvers; + char *s; + + mapsize = sizeof(mapbuf); + entsize = sizeof(EFI_MEMORY_DESCRIPTOR); + entvers = 1; + if(eficall(5, ST->BootServices->GetMemoryMap, &mapsize, mapbuf, &MK, &entsize, &entvers)) + return; + + s = *cfg; + for(p = mapbuf; mapsize >= entsize; p += entsize, mapsize -= entsize){ + t = (EFI_MEMORY_DESCRIPTOR*)p; + + m = 0; + if(t->Type < EfiMaxMemoryType) + m = memtype[t->Type]; + + if(m == 0) + continue; + + if(s == *cfg) + memmove(s, "*e820=", 6), s += 6; + s = hexfmt(s, 1, m), *s++ = ' '; + s = hexfmt(s, 16, t->PhysicalStart), *s++ = ' '; + s = hexfmt(s, 16, t->PhysicalStart + t->NumberOfPages * 4096ULL), *s++ = ' '; + } + *s = '\0'; + if(s > *cfg){ + s[-1] = '\n'; + print(*cfg); + *cfg = s; + } +} + +static void +acpiconf(char **cfg) +{ + EFI_CONFIGURATION_TABLE *t; + uintptr pa; + char *s; + int n; + + pa = 0; + t = ST->ConfigurationTable; + n = ST->NumberOfTableEntries; + while(--n >= 0){ + if(memcmp(&t->VendorGuid, &ACPI_10_TABLE_GUID, sizeof(EFI_GUID)) == 0){ + if(pa == 0) + pa = (uintptr)t->VendorTable; + } else if(memcmp(&t->VendorGuid, &ACPI_20_TABLE_GUID, sizeof(EFI_GUID)) == 0) + pa = (uintptr)t->VendorTable; + t++; + } + + if(pa){ + s = *cfg; + memmove(s, "*acpi=0x", 8), s += 8; + s = hexfmt(s, 0, pa), *s++ = '\n'; + *s = '\0'; + print(*cfg); + *cfg = s; + } +} + +static void +screenconf(char **cfg) +{ + char *s; + + gop = nil; + if(LocateProtocol(&EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, nil, &gop) || gop == nil) + return; + + s = *cfg; + memmove(s, "*bootscreen=", 12), s += 12; + + s = decfmt(s, 0, gop->Mode->Info->PixelsPerScanLine), *s++ = 'x'; + s = decfmt(s, 0, gop->Mode->Info->VerticalResolution), *s++ = 'x'; + s = decfmt(s, 0, 32), *s++ = ' '; + + memmove(s, "x8r8g8b8", 8), s += 8; + *s++ = ' '; + + *s++ = '0', *s++ = 'x'; + s = hexfmt(s, 0, gop->Mode->FrameBufferBase), *s++ = '\n'; + *s = '\0'; + + print(*cfg); + *cfg = s; + +/* + Print(" Width="), Printi(gop->Mode->Info->HorizontalResolution), Print("\r\n"); + Print(" Height="), Printi(gop->Mode->Info->VerticalResolution), Print("\r\n"); + Print(" Stride="), Printi(gop->Mode->Info->PixelsPerScanLine), Print("\r\n"); + Print(" PixelFormat="), Printi(gop->Mode->Info->PixelFormat), Print("\r\n"); + Print(" RedMask="), Printi(gop->Mode->Info->PixelInformation.RedMask), Print("\r\n"); + Print(" GreenMask="), Printi(gop->Mode->Info->PixelInformation.GreenMask), Print("\r\n"); + Print(" BlueMask="), Printi(gop->Mode->Info->PixelInformation.BlueMask), Print("\r\n"); + Print(" FrameBufferBase="), Printi(gop->Mode->FrameBufferBase), Print("\r\n"); + Print(" FrameBufferSize="), Printi(gop->Mode->FrameBufferSize), Print("\r\n"); +*/ +} + +void +eficonfig(char **cfg) +{ + screenconf(cfg); + acpiconf(cfg); + memconf(cfg); +} + +EFI_STATUS +main(EFI_HANDLE ih, EFI_SYSTEM_TABLE *st) +{ + char path[MAXPATH], *kern; + void *f; + + IH = ih; + ST = st; + + fsinit(); + + f = fswalk(root, "/plan9.ini"); + for(;;){ + kern = configure(f, path); + f = fswalk(root, kern); + if(f == nil){ + print("not found\n"); + continue; + } + print(bootkern(f)); + print("\n"); + f = nil; + } +} diff --git a/sys/src/boot/efi/efi.h b/sys/src/boot/efi/efi.h new file mode 100644 index 000000000..60ba31c3b --- /dev/null +++ b/sys/src/boot/efi/efi.h @@ -0,0 +1,270 @@ +typedef ushort CHAR16; + +typedef uchar UINT8; +typedef ushort UINT16; +typedef ulong UINT32; +typedef uvlong UINT64; + +typedef uintptr UINTN; + +typedef void* EFI_HANDLE; +typedef UINT32 EFI_STATUS; + +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} EFI_GUID; + +typedef struct { + UINT16 ScanCode; + CHAR16 UnicodeChar; +} EFI_INPUT_KEY; + +typedef struct { + void *Reset; + void *ReadKeyStroke; + void *WaitForKey; +} EFI_SIMPLE_TEXT_INPUT_PROTOCOL; + +typedef struct { + void *Reset; + void *OutputString; + void *TestString; + void *QueryMode; + void *SetMode; + void *SetAttribute; + void *ClearScreen; + void *SetCursorPosition; + void *EnableCursor; + void *Mode; +} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL; + +typedef struct { + UINT32 RedMask; + UINT32 GreenMask; + UINT32 BlueMask; + UINT32 ReservedMask; +} EFI_PIXEL_BITMASK; + +typedef struct { + UINT32 Version; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 PixelFormat; + 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; + UINT64 FrameBufferBase; + UINTN FrameBufferSize; +} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE; + +typedef struct { + void *QueryMode; + void *SetMode; + void *Blt; + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode; +} EFI_GRAPHICS_OUTPUT_PROTOCOL; + +EFI_GUID EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID = { + 0x9042a9de, 0x23dc, 0x4a38, + 0x96, 0xfb, 0x7a, 0xde, + 0xd0, 0x80, 0x51, 0x6a, +}; + +typedef struct { + UINT64 Revision; + void *Open; + void *Close; + void *Delete; + void *Read; + void *Write; + void *GetPosition; + void *SetPosition; + void *GetInfo; + void *SetInfo; + void *Flush; + void *OpenEx; + void *ReadEx; + void *WriteEx; + void *FlushEx; +} EFI_FILE_PROTOCOL; + +typedef struct { + UINT64 Revision; + void *OpenVolume; +} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL; + +EFI_GUID EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID = { + 0x0964e5b22, 0x6459, 0x11d2, + 0x8e, 0x39, 0x00, 0xa0, + 0xc9, 0x69, 0x72, 0x3b, +}; + +enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiMaxMemoryType, +}; + +typedef struct { + UINT32 Type; + UINT32 Reserved; + UINT64 PhysicalStart; + UINT64 VirtualStart; + UINT64 NumberOfPages; + UINT64 Attribute; +} EFI_MEMORY_DESCRIPTOR; + + +typedef struct { + UINT64 Signature; + UINT32 Revision; + UINT32 HeaderSize; + UINT32 CRC32; + UINT32 Reserved; +} EFI_TABLE_HEADER; + +typedef struct { + EFI_TABLE_HEADER; + + void *RaiseTPL; + void *RestoreTPL; + void *AllocatePages; + void *FreePages; + void *GetMemoryMap; + void *AllocatePool; + void *FreePool; + + void *CreateEvent; + void *SetTimer; + void *WaitForEvent; + void *SignalEvent; + void *CloseEvent; + void *CheckEvent; + + void **InstallProtocolInterface; + void **ReinstallProtocolInterface; + void **UninstallProtocolInterface; + + void *HandleProtocol; + void *Reserved; + void *RegisterProtocolNotify; + + void *LocateHandle; + void *LocateDevicePath; + void *InstallConfigurationTable; + + void *LoadImage; + void *StartImage; + void *Exit; + void *UnloadImage; + void *ExitBootServices; + + void *GetNextMonotonicCount; + void *Stall; + void *SetWatchdogTimer; + + void *ConnectController; + void *DisconnectController; + + void *OpenProtocol; + void *CloseProtocol; + + void *OpenProtocolInformation; + void *ProtocolsPerHandle; + void *LocateHandleBuffer; + void *LocateProtocol; + + void *InstallMultipleProtocolInterfaces; + void *UninstallMultipleProtocolInterfaces; + + void *CalculateCrc32; + + void *CopyMem; + void *SetMem; + void *CreateEventEx; +} EFI_BOOT_SERVICES; + +typedef struct { + EFI_TABLE_HEADER; + + void *GetTime; + void *SetTime; + void *GetWakeupTime; + void *SetWakeupTime; + + void *SetVirtualAddressMap; + void *ConvertPointer; + + void *GetVariable; + void *GetNextVariableName; + void *SetVariable; + + void *GetNextHighMonotonicCount; + void *ResetSystem; + + void *UpdateCapsule; + void *QueryCapsuleCapabilities; + + void *QueryVariableInfo; +} EFI_RUNTIME_SERVICES; + + +EFI_GUID ACPI_20_TABLE_GUID = { + 0x8868e871, 0xe4f1, 0x11d3, + 0xbc, 0x22, 0x00, 0x80, + 0xc7, 0x3c, 0x88, 0x81, +}; + +EFI_GUID ACPI_10_TABLE_GUID = { + 0xeb9d2d30, 0x2d88, 0x11d3, + 0x9a, 0x16, 0x00, 0x90, + 0x27, 0x3f, 0xc1, 0x4d, +}; + +typedef struct { + EFI_GUID VendorGuid; + void *VendorTable; +} EFI_CONFIGURATION_TABLE; + +typedef struct { + EFI_TABLE_HEADER; + + CHAR16 *FirmwareVendor; + UINT32 FirmwareRevision; + + 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; + + UINTN NumberOfTableEntries; + EFI_CONFIGURATION_TABLE *ConfigurationTable; +} EFI_SYSTEM_TABLE; diff --git a/sys/src/boot/efi/fns.h b/sys/src/boot/efi/fns.h new file mode 100644 index 000000000..3d1770562 --- /dev/null +++ b/sys/src/boot/efi/fns.h @@ -0,0 +1,29 @@ +extern char hex[]; + +void usleep(int t); +void jump(void *pc); + +int read(void *f, void *data, int len); +int readn(void *f, void *data, int len); +void close(void *f); +void unload(void); + +int getc(void); +void putc(int c); + +void memset(void *p, int v, int n); +void memmove(void *dst, void *src, int n); +int memcmp(void *src, void *dst, int n); +int strlen(char *s); +char *strchr(char *s, int c); +char *strrchr(char *s, int c); +void print(char *s); + +char *configure(void *f, char *path); +char *bootkern(void *f); + +char *hexfmt(char *s, int i, uvlong a); +char *decfmt(char *s, int i, ulong a); + +long eficall(long narg, void *proc, ...); +void eficonfig(char **cfg); diff --git a/sys/src/boot/efi/mem.h b/sys/src/boot/efi/mem.h new file mode 100644 index 000000000..18819590d --- /dev/null +++ b/sys/src/boot/efi/mem.h @@ -0,0 +1,47 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1)) + +/* + * Fundamental addresses + */ +#define CONFADDR 0x1200 /* info passed from boot loader */ +#define BIOSXCHG 0x6000 /* To exchange data with the BIOS */ + +#define SELGDT (0<<3) /* selector is in gdt */ +#define SELLDT (1<<3) /* selector is in ldt */ + +#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) + +/* + * fields in segment descriptors + */ +#define SEGDATA (0x10<<8) /* data/stack segment */ +#define SEGEXEC (0x18<<8) /* executable segment */ +#define SEGTSS (0x9<<8) /* TSS segment */ +#define SEGCG (0x0C<<8) /* call gate */ +#define SEGIG (0x0E<<8) /* interrupt gate */ +#define SEGTG (0x0F<<8) /* trap gate */ +#define SEGLDT (0x02<<8) /* local descriptor table */ +#define SEGTYPE (0x1F<<8) + +#define SEGP (1<<15) /* segment present */ +#define SEGPL(x) ((x)<<13) /* priority level */ +#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ +#define SEGD (1<<22) /* default 1==32bit (for code) */ +#define SEGE (1<<10) /* expand down */ +#define SEGW (1<<9) /* writable (for data/stack) */ +#define SEGR (1<<9) /* readable (for code) */ +#define SEGL (1<<21) /* 64 bit */ +#define SEGG (1<<23) /* granularity 1==4k (for other) */ diff --git a/sys/src/boot/efi/mkfile b/sys/src/boot/efi/mkfile new file mode 100644 index 000000000..699f21867 --- /dev/null +++ b/sys/src/boot/efi/mkfile @@ -0,0 +1,43 @@ +TARG=bootia32.efi bootx64.efi +HFILES=fns.h mem.h +IMAGEBASE=0x8000 +PEFLAGS=$CFLAGS '-DIMAGEBASE='$IMAGEBASE + +all:V: $TARG + +install:V: $TARG + cp bootia32.efi /386 + cp bootx64.efi /386 + +bootia32.efi: pe32.8 efi.8 sub.8 + 8l -l -H3 -T$IMAGEBASE -o $target $prereq + +pe32.8: pe32.s + 8a $PEFLAGS pe32.s + +efi.8: efi.c efi.h + 8c $CFLAGS efi.c + +sub.8: sub.c + 8c $CFLAGS sub.c + +%.8: $HFILES + + +bootx64.efi: pe64.6 efi.6 sub.6 + 6l -l -s -R1 -T$IMAGEBASE -o bootx64.out $prereq + dd -if bootx64.out -bs 1 -iseek 40 >$target + +pe64.6: pe64.s + 6a $PEFLAGS pe64.s + +efi.6: efi.c efi.h + 6c $CFLAGS efi.c + +sub.6: sub.c + 6c $CFLAGS sub.c + +%.6: $HFILES + +clean: + rm -f *.[68] *.out $TARG diff --git a/sys/src/boot/efi/pe32.s b/sys/src/boot/efi/pe32.s new file mode 100644 index 000000000..46abc0009 --- /dev/null +++ b/sys/src/boot/efi/pe32.s @@ -0,0 +1,149 @@ +TEXT mzhdr(SB), 1, $0 + BYTE $'M'; BYTE $'Z' + + WORD $0 /* e_cblp UNUSED */ + WORD $0 /* e_cp UNUSED */ + WORD $0 /* e_crlc UNUSED */ + WORD $0 /* e_cparhdr UNUSED */ + WORD $0 /* e_minalloc UNUSED */ + WORD $0 /* e_maxalloc UNUSED */ + WORD $0 /* e_ss UNUSED */ + WORD $0 /* e_sp UNUSED */ + WORD $0 /* e_csum UNUSED */ + WORD $0 /* e_ip UNUSED */ + WORD $0 /* e_cs UNUSED */ + WORD $0 /* e_lsarlc UNUSED */ + WORD $0 /* e_ovno UNUSED */ + + WORD $0 /* e_res UNUSED */ + WORD $0 + WORD $0 + WORD $0 + WORD $0 + + WORD $0 /* e_oemid UNUSED */ + + WORD $0 /* e_res2 UNUSED */ + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + + LONG $pehdr-IMAGEBASE(SB) /* offset to pe header */ + +TEXT pehdr(SB), 1, $0 + BYTE $'P'; BYTE $'E'; BYTE $0; BYTE $0 + + WORD $0x014C /* Machine (Intel 386) */ + WORD $1 /* NumberOfSections */ + LONG $0 /* TimeDateStamp UNUSED */ + LONG $0 /* PointerToSymbolTable UNUSED */ + LONG $0 /* NumberOfSymbols UNUSED */ + WORD $0xE0 /* SizeOfOptionalHeader */ + WORD $2103 /* Characteristics (no relocations, executable, 32 bit) */ + + WORD $0x10B /* Magic (PE32) */ + BYTE $9 /* MajorLinkerVersion UNUSED */ + BYTE $0 /* MinorLinkerVersion UNUSED */ + LONG $0 /* SizeOfCode UNUSED */ + LONG $0 /* SizeOfInitializedData UNUSED */ + LONG $0 /* SizeOfUninitializedData UNUSED */ + LONG $start-IMAGEBASE(SB)/* AddressOfEntryPoint */ + LONG $0 /* BaseOfCode UNUSED */ + LONG $0 /* BaseOfData UNUSED */ + LONG $IMAGEBASE /* ImageBase */ + LONG $0x200 /* SectionAlignment */ + LONG $0x200 /* FileAlignment */ + WORD $4 /* MajorOperatingSystemVersion UNUSED */ + WORD $0 /* MinorOperatingSystemVersion UNUSED */ + WORD $0 /* MajorImageVersion UNUSED */ + WORD $0 /* MinorImageVersion UNUSED */ + WORD $4 /* MajorSubsystemVersion */ + WORD $0 /* MinorSubsystemVersion UNUSED */ + LONG $0 /* Win32VersionValue UNUSED */ + LONG $end-IMAGEBASE(SB) /* SizeOfImage */ + LONG $start-IMAGEBASE(SB)/* SizeOfHeaders */ + LONG $0 /* CheckSum UNUSED */ + WORD $10 /* Subsystem (10 = efi application) */ + WORD $0 /* DllCharacteristics UNUSED */ + LONG $0 /* SizeOfStackReserve UNUSED */ + LONG $0 /* SizeOfStackCommit UNUSED */ + LONG $0 /* SizeOfHeapReserve UNUSED */ + LONG $0 /* SizeOfHeapCommit UNUSED */ + LONG $0 /* LoaderFlags UNUSED */ + LONG $16 /* NumberOfRvaAndSizes UNUSED */ + + LONG $0; LONG $0 + LONG $0; LONG $0 + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + + BYTE $'.'; BYTE $'t'; BYTE $'e'; BYTE $'x' + BYTE $'t'; BYTE $0; BYTE $0; BYTE $0 + LONG $edata-(IMAGEBASE+0x200)(SB) /* VirtualSize */ + LONG $start-IMAGEBASE(SB) /* VirtualAddress */ + LONG $edata-(IMAGEBASE+0x200)(SB) /* SizeOfData */ + LONG $start-IMAGEBASE(SB) /* PointerToRawData */ + LONG $0 /* PointerToRelocations UNUSED */ + LONG $0 /* PointerToLinenumbers UNUSED */ + WORD $0 /* NumberOfRelocations UNUSED */ + WORD $0 /* NumberOfLinenumbers UNUSED */ + LONG $0x86000020 /* Characteristics (code, execute, read, write) */ + + /* padding to get start(SB) at IMAGEBASE+0x200 */ + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + +TEXT start(SB), 1, $0 + CALL reloc(SP) + +TEXT reloc(SB), 1, $0 + MOVL 0(SP), SI + SUBL $reloc-IMAGEBASE(SB), SI + MOVL $IMAGEBASE, DI + MOVL $edata-IMAGEBASE(SB), CX + CLD + REP; MOVSB + MOVL $main(SB), DI + MOVL DI, (SP) + RET + +TEXT jump(SB), $0 + CLI + MOVL 4(SP), AX + JMP *AX + + +TEXT eficall(SB), 1, $0 + MOVL 0(SP), DI /* saved by callee */ + MOVL 8(SP), AX + ADDL $12, SP + CALL AX + SUBL $12, SP + MOVL DI, 0(SP) + RET diff --git a/sys/src/boot/efi/pe64.s b/sys/src/boot/efi/pe64.s new file mode 100644 index 000000000..a9c00aa39 --- /dev/null +++ b/sys/src/boot/efi/pe64.s @@ -0,0 +1,234 @@ +TEXT mzhdr(SB), 1, $0 + BYTE $'M'; BYTE $'Z' + + WORD $0 /* e_cblp UNUSED */ + WORD $0 /* e_cp UNUSED */ + WORD $0 /* e_crlc UNUSED */ + WORD $0 /* e_cparhdr UNUSED */ + WORD $0 /* e_minalloc UNUSED */ + WORD $0 /* e_maxalloc UNUSED */ + WORD $0 /* e_ss UNUSED */ + WORD $0 /* e_sp UNUSED */ + WORD $0 /* e_csum UNUSED */ + WORD $0 /* e_ip UNUSED */ + WORD $0 /* e_cs UNUSED */ + WORD $0 /* e_lsarlc UNUSED */ + WORD $0 /* e_ovno UNUSED */ + + WORD $0 /* e_res UNUSED */ + WORD $0 + WORD $0 + WORD $0 + WORD $0 + + WORD $0 /* e_oemid UNUSED */ + + WORD $0 /* e_res2 UNUSED */ + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + WORD $0 + + LONG $pehdr-IMAGEBASE(SB) /* offset to pe header */ + +TEXT pehdr(SB), 1, $0 + BYTE $'P'; BYTE $'E'; BYTE $0; BYTE $0 + + WORD $0x8664 /* Machine (AMD64) */ + WORD $1 /* NumberOfSections */ + LONG $0 /* TimeDateStamp UNUSED */ + LONG $0 /* PointerToSymbolTable UNUSED */ + LONG $0 /* NumberOfSymbols UNUSED */ + WORD $0xF0 /* SizeOfOptionalHeader */ + WORD $2223 /* Characteristics */ + + WORD $0x20B /* Magic (PE32+) */ + BYTE $9 /* MajorLinkerVersion UNUSED */ + BYTE $0 /* MinorLinkerVersion UNUSED */ + LONG $0 /* SizeOfCode UNUSED */ + LONG $0 /* SizeOfInitializedData UNUSED */ + LONG $0 /* SizeOfUninitializedData UNUSED */ + LONG $start-IMAGEBASE(SB)/* AddressOfEntryPoint */ + LONG $0 /* BaseOfCode UNUSED */ + + QUAD $IMAGEBASE /* ImageBase */ + LONG $0x200 /* SectionAlignment */ + LONG $0x200 /* FileAlignment */ + WORD $4 /* MajorOperatingSystemVersion UNUSED */ + WORD $0 /* MinorOperatingSystemVersion UNUSED */ + WORD $0 /* MajorImageVersion UNUSED */ + WORD $0 /* MinorImageVersion UNUSED */ + WORD $4 /* MajorSubsystemVersion */ + WORD $0 /* MinorSubsystemVersion UNUSED */ + LONG $0 /* Win32VersionValue UNUSED */ + LONG $end-IMAGEBASE(SB) /* SizeOfImage */ + LONG $start-IMAGEBASE(SB)/* SizeOfHeaders */ + LONG $0 /* CheckSum UNUSED */ + WORD $10 /* Subsystem (10 = efi application) */ + WORD $0 /* DllCharacteristics UNUSED */ + QUAD $0 /* SizeOfStackReserve UNUSED */ + QUAD $0 /* SizeOfStackCommit UNUSED */ + QUAD $0 /* SizeOfHeapReserve UNUSED */ + QUAD $0 /* SizeOfHeapCommit UNUSED */ + LONG $0 /* LoaderFlags UNUSED */ + LONG $16 /* NumberOfRvaAndSizes UNUSED */ + + LONG $0; LONG $0 + LONG $0; LONG $0 + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + LONG $0; LONG $0 /* RVA */ + + BYTE $'.'; BYTE $'t'; BYTE $'e'; BYTE $'x' + BYTE $'t'; BYTE $0; BYTE $0; BYTE $0 + LONG $edata-(IMAGEBASE+0x200)(SB) /* VirtualSize */ + LONG $start-IMAGEBASE(SB) /* VirtualAddress */ + LONG $edata-(IMAGEBASE+0x200)(SB) /* SizeOfData */ + LONG $start-IMAGEBASE(SB) /* PointerToRawData */ + LONG $0 /* PointerToRelocations UNUSED */ + LONG $0 /* PointerToLinenumbers UNUSED */ + WORD $0 /* NumberOfRelocations UNUSED */ + WORD $0 /* NumberOfLinenumbers UNUSED */ + LONG $0x86000020 /* Characteristics (code, execute, read, write) */ + + /* padding to get start(SB) at IMAGEBASE+0x200 */ + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0; + LONG $0; LONG $0; LONG $0; LONG $0 + +MODE $64 + +TEXT start(SB), 1, $-4 + /* spill arguments */ + MOVQ CX, 8(SP) + MOVQ DX, 16(SP) + + CALL reloc(SP) + +TEXT reloc(SB), 1, $-4 + MOVQ 0(SP), SI + SUBQ $reloc-IMAGEBASE(SB), SI + MOVQ $IMAGEBASE, DI + MOVQ $edata-IMAGEBASE(SB), CX + CLD + REP; MOVSB + + MOVQ 16(SP), BP + MOVQ $main(SB), DI + MOVQ DI, (SP) + RET + +TEXT eficall(SB), 1, $-4 + MOVQ 0(SP), DI /* saved by callee */ + MOVQ 16(SP), AX + ADDQ $24, SP + + /* arguments in regisyers */ + MOVQ 0(SP), CX + MOVQ 8(SP), DX + MOVQ 16(SP), R8 + MOVQ 24(SP), R9 + + CALL AX + + SUBQ $24, SP + MOVQ DI, 0(SP) + RET + +#include "mem.h" + +TEXT jump(SB), 1, $-4 + CLI + + /* load zero length idt */ + MOVL $_idtptr64p<>(SB), AX + MOVL (AX), IDTR + + /* load temporary gdt */ + MOVL $_gdtptr64p<>(SB), AX + MOVL (AX), GDTR + + /* load CS with 32bit code segment */ + PUSHQ $SELECTOR(3, SELGDT, 0) + PUSHQ $_warp32<>(SB) + RETFQ + +MODE $32 + +TEXT _warp32<>(SB), 1, $-4 + + /* load 32bit data segments */ + MOVL $SELECTOR(2, SELGDT, 0), AX + MOVW AX, DS + MOVW AX, ES + MOVW AX, FS + MOVW AX, GS + MOVW AX, SS + + /* turn off paging */ + MOVL CR0, AX + ANDL $0x7fffffff, AX /* ~(PG) */ + MOVL AX, CR0 + + MOVL $0, AX + MOVL AX, CR3 + + /* disable long mode */ + MOVL $0xc0000080, CX /* Extended Feature Enable */ + RDMSR + ANDL $0xfffffeff, AX /* Long Mode Disable */ + WRMSR + + /* diable pae */ + MOVL CR4, AX + ANDL $0xffffff5f, AX /* ~(PAE|PGE) */ + MOVL AX, CR4 + + JMP *BP + +TEXT _gdt<>(SB), 1, $-4 + /* null descriptor */ + LONG $0 + LONG $0 + + /* (KESEG) 64 bit long mode exec segment */ + LONG $(0xFFFF) + LONG $(SEGL|SEGG|SEGP|(0xF<<16)|SEGPL(0)|SEGEXEC|SEGR) + + /* 32 bit data segment descriptor for 4 gigabytes (PL 0) */ + LONG $(0xFFFF) + LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW) + + /* 32 bit exec segment descriptor for 4 gigabytes (PL 0) */ + LONG $(0xFFFF) + LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR) + +TEXT _gdtptr64p<>(SB), 1, $-4 + WORD $(4*8-1) + QUAD $_gdt<>(SB) + +TEXT _idtptr64p<>(SB), 1, $-4 + WORD $0 + QUAD $0 diff --git a/sys/src/boot/efi/sub.c b/sys/src/boot/efi/sub.c new file mode 100644 index 000000000..ee951bd9f --- /dev/null +++ b/sys/src/boot/efi/sub.c @@ -0,0 +1,382 @@ +#include <u.h> +#include <a.out.h> +#include "fns.h" +#include "mem.h" + +char hex[] = "0123456789abcdef"; + +void +print(char *s) +{ + while(*s != 0){ + if(*s == '\n') + putc('\r'); + putc(*s++); + } +} + +int +readn(void *f, void *data, int len) +{ + uchar *p, *e; + + putc(' '); + p = data; + e = p + len; + while(p < e){ + if(((ulong)p & 0xF000) == 0){ + putc('\b'); + putc(hex[((ulong)p>>16)&0xF]); + } + if((len = read(f, p, e - p)) <= 0) + break; + p += len; + } + putc('\b'); + + return p - (uchar*)data; +} + +void +memmove(void *dst, void *src, int n) +{ + uchar *d = dst; + uchar *s = src; + + if(d < s){ + while(n-- > 0) + *d++ = *s++; + } else if(d > s){ + s += n; + d += n; + while(n-- > 0) + *--d = *--s; + } +} + +int +memcmp(void *src, void *dst, int n) +{ + uchar *d = dst; + uchar *s = src; + int r = 0; + + while(n-- > 0){ + r = *d++ - *s++; + if(r != 0) + break; + } + + return r; +} + +int +strlen(char *s) +{ + char *p = s; + + while(*p != '\0') + p++; + + return p - s; +} + +char* +strchr(char *s, int c) +{ + for(; *s != 0; s++) + if(*s == c) + return s; + + return nil; +} + +void +memset(void *dst, int v, int n) +{ + uchar *d = dst; + + while(n > 0){ + *d++ = v; + n--; + } +} + +static int +readline(void *f, char buf[64]) +{ + static char white[] = "\t "; + char *p; + + p = buf; + do{ + if(f == nil) + putc('>'); + for(;;){ + if(f == nil){ + while((*p = getc()) == 0) + ; + putc(*p); + if(*p == '\r') + putc('\n'); + else if(*p == '\b' && p > buf){ + p--; + continue; + } + }else if(read(f, p, 1) <= 0) + return 0; + if(strchr("\r\n", *p) != nil) + break; + if(p == buf && strchr(white, *p) != nil) + continue; /* whitespace on start of line */ + if(p >= buf + 64-1){ + if(f == nil){ + putc('\b'); + putc(' '); + putc('\b'); + } + continue; /* line full do not advance */ + } + p++; + } + while(p > buf && strchr(white, p[-1])) + p--; + }while(p == buf); + *p = 0; + + return p - buf; +} + +static int +timeout(int ms) +{ + while(ms > 0){ + if(getc() != 0) + return 1; + usleep(100000); + ms -= 100; + } + return 0; +} + +#define BOOTLINE ((char*)CONFADDR) +#define BOOTLINELEN 64 +#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN)) +#define BOOTARGSLEN (4096-0x200-BOOTLINELEN) + +char *confend; + +static char* +getconf(char *s, char *buf) +{ + char *p, *e; + int n; + + n = strlen(s); + for(p = BOOTARGS; p < confend; p = e+1){ + for(e = p+1; e < confend; e++) + if(*e == '\n') + break; + if(memcmp(p, s, n) == 0){ + p += n; + n = e - p; + buf[n] = 0; + memmove(buf, p, n); + return buf; + } + } + return nil; +} + +static int +delconf(char *s) +{ + char *p, *e; + + for(p = BOOTARGS; p < confend; p = e){ + for(e = p+1; e < confend; e++){ + if(*e == '\n'){ + e++; + break; + } + } + if(memcmp(p, s, strlen(s)) == 0){ + memmove(p, e, confend - e); + confend -= e - p; + *confend = 0; + return 1; + } + } + return 0; +} + +char* +configure(void *f, char *path) +{ + char line[64], *kern, *s, *p; + int inblock, nowait, n; + static int once = 1; + + if(once){ + once = 0; +Clear: + memset(BOOTLINE, 0, BOOTLINELEN); + + confend = BOOTARGS; + memset(confend, 0, BOOTARGSLEN); + eficonfig(&confend); + } + nowait = 1; + inblock = 0; +Loop: + while(readline(f, line) > 0){ + if(*line == 0 || strchr("#;=", *line) != nil) + continue; + if(*line == '['){ + inblock = memcmp("[common]", line, 8) != 0; + continue; + } + if(memcmp("boot", line, 5) == 0){ + nowait=1; + break; + } + if(memcmp("wait", line, 5) == 0){ + nowait=0; + continue; + } + if(memcmp("show", line, 5) == 0){ + print(BOOTARGS); + continue; + } + if(memcmp("clear", line, 5) == 0){ + if(line[5] == '\0'){ + print("ok\n"); + goto Clear; + } else if(line[5] == ' ' && delconf(line+6)) + print("ok\n"); + continue; + } + if(inblock != 0 || (p = strchr(line, '=')) == nil) + continue; + *p++ = 0; + delconf(line); + s = confend; + memmove(confend, line, n = strlen(line)); confend += n; + *confend++ = '='; + memmove(confend, p, n = strlen(p)); confend += n; + *confend++ = '\n'; + *confend = 0; + print(s); + } + kern = getconf("bootfile=", path); + + if(f != nil){ + close(f); + f = nil; + + if(kern != nil && (nowait==0 || timeout(1000))) + goto Loop; + } + + if(kern == nil){ + print("no bootfile\n"); + goto Loop; + } + while((p = strchr(kern, '!')) != nil) + kern = p+1; + + return kern; +} + +static char* +numfmt(char *s, ulong b, ulong i, ulong a) +{ + char *r; + + if(i == 0){ + ulong v = a; + while(v != 0){ + v /= b; + i++; + } + if(i == 0) + i = 1; + } + + s += i; + r = s; + while(i > 0){ + *--s = hex[a % b]; + a /= b; + i--; + } + return r; +} + +char* +hexfmt(char *s, int i, uvlong a) +{ + if(i > 8){ + s = numfmt(s, 16, i-8, a>>32); + i = 8; + } + return numfmt(s, 16, i, a); +} + +char* +decfmt(char *s, int i, ulong a) +{ + return numfmt(s, 10, i, a); +} + +static ulong +beswal(ulong l) +{ + uchar *p = (uchar*)&l; + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +} + +char* +bootkern(void *f) +{ + uchar *e, *d, *t; + ulong n; + Exec ex; + + if(readn(f, &ex, sizeof(ex)) != sizeof(ex)) + return "bad header"; + + e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL); + switch(beswal(ex.magic)){ + case S_MAGIC: + if(readn(f, e, 8) != 8) + goto Error; + case I_MAGIC: + break; + default: + return "bad magic"; + } + + t = e; + n = beswal(ex.text); + if(readn(f, t, n) != n) + goto Error; + t += n; + d = (uchar*)PGROUND((ulong)t); + memset(t, 0, d - t); + n = beswal(ex.data); + if(readn(f, d, n) != n) + goto Error; + d += n; + t = (uchar*)PGROUND((ulong)d); + t += PGROUND(beswal(ex.bss)); + memset(d, 0, t - d); + + close(f); + unload(); + + jump(e); + +Error: + return "i/o error"; +} |