ref: 6f3dfb57eba2eb9ab21e4a0d06c8415cccf45fb1
parent: 0a6439a1f564de17bfad7a327178e47483a86e1a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Oct 17 22:13:02 EDT 2014
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.
--- /dev/null
+++ b/sys/src/boot/efi/efi.c
@@ -1,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;
+ }
+}
--- /dev/null
+++ b/sys/src/boot/efi/efi.h
@@ -1,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;
--- /dev/null
+++ b/sys/src/boot/efi/fns.h
@@ -1,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);
--- /dev/null
+++ b/sys/src/boot/efi/mem.h
@@ -1,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) */
--- /dev/null
+++ b/sys/src/boot/efi/mkfile
@@ -1,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
--- /dev/null
+++ b/sys/src/boot/efi/pe32.s
@@ -1,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
--- /dev/null
+++ b/sys/src/boot/efi/pe64.s
@@ -1,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
--- /dev/null
+++ b/sys/src/boot/efi/sub.c
@@ -1,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";
+}