shithub: riscv

Download patch

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.

diff: cannot open b/sys/src/boot/efi//null: file does not exist: 'b/sys/src/boot/efi//null'
--- /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";
+}