shithub: riscv

Download patch

ref: 1ae5fc01a6e9c6fb1a1befd4c60653a6af10a9e0
parent: 5f4e2670b4d8eb3cd1faed9808c3d0747284a288
author: Keegan Saunders <keegan@undefinedbehaviour.org>
date: Mon Sep 18 21:40:56 EDT 2023

boot/efi: add arm64

This means we can now boot kernels on arm64 EFI platforms.
As well, porting additional architectures to our EFI boot
should now be much simpler.

Due to the nature of EFI relocations, this is a peculiar
code environment for 7l and requires extra care. See
rebase for more information.

--- /dev/null
+++ b/sys/src/boot/efi/aa64.s
@@ -1,0 +1,95 @@
+#define	SYSREG(op0,op1,Cn,Cm,op2)	SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
+#define	SCTLR_EL1			SYSREG(3,0,1,0,0)
+
+#define NSH	(1<<2 | 3)
+#define NSHST	(1<<2 | 2)
+#define	SY	(3<<2 | 3)
+
+TEXT start(SB), 1, $-4
+_base:
+	MOV	R0, R3
+	MOV	R1, R4
+
+	MOV	$setSB(SB), R0
+	BL	rebase(SB)
+	MOV	R0, R28
+
+	MOV	$argsbuf<>(SB), R0
+	MOV	R0, confaddr(SB)
+
+	MOV	R3, R0
+	MOV	R4, 0x08(FP)
+	B	efimain(SB)
+
+TEXT rebase(SB), 1, $-4
+	ADR	_base, R1
+	SUB	$0x8200, R0
+	ADD	R1, R0
+	RETURN
+
+TEXT eficall(SB), 1, $-4
+	MOV	R0, R8
+	MOV	0x08(FP), R0
+	MOV	0x10(FP), R1
+	MOV	0x18(FP), R2
+	MOV	0x20(FP), R3
+	MOV	0x28(FP), R4
+	MOV	0x30(FP), R5
+	MOV	0x38(FP), R6
+	MOV	0x40(FP), R7
+	B	(R8)
+
+TEXT mmudisable<>(SB), 1, $-4
+#define SCTLRCLR \
+	/* RES0 */	( 3<<30 \
+	/* RES0 */	| 1<<27 \
+	/* UCI */	| 1<<26 \
+	/* EE */	| 1<<25 \
+	/* RES0 */	| 1<<21 \
+	/* E0E */	| 1<<24 \
+	/* WXN */	| 1<<19 \
+	/* nTWE */	| 1<<18 \
+	/* RES0 */	| 1<<17 \
+	/* nTWI */	| 1<<16 \
+	/* UCT */	| 1<<15 \
+	/* DZE */	| 1<<14 \
+	/* RES0 */	| 1<<13 \
+	/* RES0 */	| 1<<10 \
+	/* UMA */	| 1<<9 \
+	/* SA0 */	| 1<<4 \
+	/* SA */	| 1<<3 \
+	/* A */		| 1<<1 )
+#define SCTLRSET \
+	/* RES1 */	( 3<<28 \
+	/* RES1 */	| 3<<22 \
+	/* RES1 */	| 1<<20 \
+	/* RES1 */	| 1<<11 )
+#define SCTLRMMU \
+	/* I */		( 1<<12 \
+	/* C */		| 1<<2 \
+	/* M */		| 1<<0 )
+
+	/* initialise SCTLR, MMU and caches off */
+	ISB	$SY
+	MRS	SCTLR_EL1, R0
+	BIC	$(SCTLRCLR | SCTLRMMU), R0
+	ORR	$SCTLRSET, R0
+	ISB	$SY
+	MSR	R0, SCTLR_EL1
+	ISB	$SY
+
+	DSB	$NSHST
+	TLBI	R0, 0,8,7,0	/* VMALLE1 */
+	DSB	$NSH
+	ISB	$SY
+	RETURN
+
+TEXT jump(SB), 1, $-4
+	MOV	R0, R3
+	MOV	R1, R4
+	BL	mmudisable<>(SB)
+	MOV	R4, R0
+	B	(R3)
+
+GLOBL	confaddr(SB), $8
+GLOBL	argsbuf<>(SB), $0x1000
--- a/sys/src/boot/efi/efi.c
+++ b/sys/src/boot/efi/efi.c
@@ -10,6 +10,16 @@
 int (*read)(void *f, void *data, int len);
 void (*close)(void *f);
 
+/*
+ * on ia32 and amd64, we use IMAGE_FILE_RELOCS_STRIPPED which
+ * disables relocations, so this is a no-op.
+ *
+ * on arm64, the EFI loader can move our code, so we need to
+ * update some of our stored addresses (such as callbacks)
+ * which assume we are loaded at our requested base address.
+ */
+extern void *rebase(void *addr);
+
 void
 putc(int c)
 {
@@ -297,6 +307,10 @@
 	f = nil;
 	if(pxeinit(&f) && isoinit(&f) && fsinit(&f))
 		print("no boot devices\n");
+
+	read = rebase(read);
+	close = rebase(close);
+	open = rebase(open);
 
 	for(;;){
 		kern = configure(f, path);
--- a/sys/src/boot/efi/fns.h
+++ b/sys/src/boot/efi/fns.h
@@ -5,7 +5,7 @@
 extern char hex[];
 
 void usleep(int t);
-void jump(void *pc);
+void jump(void *pc, void *arg);
 
 int pxeinit(void **pf);
 int isoinit(void **pf);
--- /dev/null
+++ b/sys/src/boot/efi/ia32.s
@@ -1,0 +1,47 @@
+#include "mem.h"
+
+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 $efimain(SB), DI
+	MOVL DI, (SP)
+	RET
+
+TEXT jump(SB), $0
+	CLI
+	MOVL 4(SP), AX
+	JMP *AX
+
+TEXT eficall(SB), 1, $0
+	MOVL SP, SI
+	MOVL SP, DI
+	MOVL $(4*16), CX
+	SUBL CX, DI
+	ANDL $~15ULL, DI
+	SUBL $8, DI
+
+	MOVL 4(SI), AX
+	LEAL 8(DI), SP
+
+	CLD
+	REP; MOVSB
+	SUBL $(4*16), SI
+
+	CALL AX
+
+	MOVL SI, SP
+	RET
+
+TEXT rebase(SB), 1, $0
+	MOVL 4(SP), AX
+	RET
+
+GLOBL	confaddr(SB), $4
+DATA	confaddr(SB)/4, $CONFADDR
--- a/sys/src/boot/efi/iso.c
+++ b/sys/src/boot/efi/iso.c
@@ -24,8 +24,10 @@
 	uchar dirlen;
 	uchar extlen;
 
-	uchar lba[8];
-	uchar len[8];
+	ulong lba;
+	ulong lbabe;
+	ulong len;
+	ulong lenbe;
 
 	uchar date[7];
 
@@ -133,8 +135,24 @@
 			break;
 		if(d.dirlen == 0)
 			continue;	/* zero padding to next sector */
-		if(read(ex, &d.dirlen + 1, Dirsz-1) != Dirsz-1)
+		if(read(ex, &d.extlen, 1) != 1)
 			break;
+		if(read(ex, &d.lba, 4) != 4)
+			break;
+		if(read(ex, &d.lbabe, 4) != 4)
+			break;
+		if(read(ex, &d.len, 4) != 4)
+			break;
+		if(read(ex, &d.lenbe, 4) != 4)
+			break;
+		if(read(ex, d.date, 7) != 7)
+			break;
+		if(read(ex, d.flags, 3) != 3)
+			break;
+		if(read(ex, d.seq, 4) != 4)
+			break;
+		if(read(ex, &d.namelen, 1) != 1)
+			break;
 		if(read(ex, name, d.namelen) != d.namelen)
 			break;
 		i = d.dirlen - (Dirsz + d.namelen);
@@ -158,8 +176,8 @@
 		i = end - path;
 		if(d.namelen == i && memcmp(name, path, i) == 0){
 			ex->rp = ex->ep;
-			ex->lba = *((ulong*)d.lba);
-			ex->len = *((ulong*)d.len);
+			ex->lba = d.lba;
+			ex->len = d.len;
 			if(*end == 0)
 				return 0;
 			else if(d.flags[0] & 2){
--- a/sys/src/boot/efi/mkfile
+++ b/sys/src/boot/efi/mkfile
@@ -1,4 +1,4 @@
-TARG=bootia32.efi bootx64.efi efiboot.fat
+TARG=bootia32.efi bootx64.efi bootaa64.efi efiboot.fat
 HFILES=fns.h mem.h
 IMAGEBASE=0x8000
 CFLAGS=-FTVw
@@ -9,55 +9,37 @@
 install:V: $TARG
 	cp $prereq /386
 
-bootia32.efi:	pe32.8 efi.8 fs.8 pxe.8 iso.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
-
-fs.8:	fs.c efi.h
-	8c $CFLAGS fs.c
-
-pxe.8:	pxe.c efi.h
-	8c $CFLAGS pxe.c
-
-iso.8:	iso.c efi.h
-	8c $CFLAGS iso.c
-
-sub.8:	sub.c
-	8c $CFLAGS sub.c
-
+%.8:	%.s
+	8a $PEFLAGS $stem.s
+%.8:	%.c
+	8c $CFLAGS $stem.c
+bootia32.efi:	ia32.8 efi.8 fs.8 pxe.8 iso.8 sub.8
+	8l -l -s -R1 -T0x8200 -o bootia32.out $prereq
+	aux/aout2efi -Z$IMAGEBASE -o $target bootia32.out
 %.8:	$HFILES
 
 
-bootx64.efi:	pe64.6 efi.6 fs.6 pxe.6 iso.6 sub.6
-	6l -l -s -R1 -T$IMAGEBASE -o bootx64.out $prereq
-	dd -if bootx64.out -bs 1 -iseek 40 >$target
+%.6:	%.s
+	6a $PEFLAGS $stem.s
+%.6:	%.c
+	6c $CFLAGS $stem.c
+bootx64.efi:	x64.6 efi.6 fs.6 pxe.6 iso.6 sub.6
+	6l -l -s -R1 -T0x8200 -o bootx64.out $prereq
+	aux/aout2efi -Z$IMAGEBASE -o $target bootx64.out
+%.6:	$HFILES
 
-pe64.6:	pe64.s
-	6a $PEFLAGS pe64.s
 
-efi.6:	efi.c efi.h
-	6c $CFLAGS efi.c
+%.7:	%.s
+	7a $PEFLAGS $stem.s
+%.7:	%.c
+	7c $CFLAGS $stem.c
+bootaa64.efi:	aa64.7 efi.7 fs.7 pxe.7 iso.7 sub.7
+	7l -l -s -R1 -T0x8200 -o bootaa64.out $prereq
+	aux/aout2efi -Z$IMAGEBASE -o $target bootaa64.out
+%.7:	$HFILES
 
-fs.6:	fs.c efi.h
-	6c $CFLAGS fs.c
 
-pxe.6:	pxe.c efi.h
-	6c $CFLAGS pxe.c
-
-iso.6:	iso.c efi.h
-	6c $CFLAGS iso.c
-
-sub.6:	sub.c
-	6c $CFLAGS sub.c
-
-%.6:	$HFILES
-
-efiboot.fat:D:	bootia32.efi bootx64.efi
+efiboot.fat:D:	bootia32.efi bootx64.efi bootaa64.efi
 	s = $target.$pid
 	rm -f $target
 	dd -if /dev/zero -of $target -bs 1024 -count 1024
@@ -68,6 +50,7 @@
 	mkdir /n/esp/efi/boot
 	cp bootia32.efi /n/esp/efi/boot
 	cp bootx64.efi /n/esp/efi/boot
+	cp bootaa64.efi /n/esp/efi/boot
 	unmount /n/esp
 	rm /srv/$s
 
@@ -84,7 +67,7 @@
 	disk/mk9660 -B 386/9bootiso -E 386/efiboot.fat -p <{echo +} -s tmp $target
 	rm -r tmp
 
-test.fat:D:	bootia32.efi bootx64.efi
+test.fat:D:	bootia32.efi bootx64.efi bootaa64.efi
 	s = $target.$pid
 	rm -f $target
 	dd -if /dev/zero -of $target -bs 65536 -count 128
@@ -95,6 +78,7 @@
 	mkdir /n/esp/efi/boot
 	cp bootia32.efi /n/esp/efi/boot
 	cp bootx64.efi /n/esp/efi/boot
+	cp bootaa64.efi /n/esp/efi/boot
 	cp /386/9pc /n/esp
 	echo 'bootfile=9pc' >/n/esp/plan9.ini
 	unmount /n/esp
@@ -102,4 +86,4 @@
 
 
 clean:V:
-	rm -f *.[68] *.out $TARG test.* 
+	rm -f *.[678] *.out $TARG test.* 
--- a/sys/src/boot/efi/pe32.s
+++ /dev/null
@@ -1,159 +1,0 @@
-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 $efimain(SB), DI
-	MOVL DI, (SP)
-	RET
-
-TEXT jump(SB), $0
-	CLI
-	MOVL 4(SP), AX
-	JMP *AX
-
-TEXT eficall(SB), 1, $0
-	MOVL SP, SI
-	MOVL SP, DI
-	MOVL $(4*16), CX
-	SUBL CX, DI
-	ANDL $~15ULL, DI
-	SUBL $8, DI
-
-	MOVL 4(SI), AX
-	LEAL 8(DI), SP
-
-	CLD
-	REP; MOVSB
-	SUBL $(4*16), SI
-
-	CALL AX
-
-	MOVL SI, SP
-	RET
--- a/sys/src/boot/efi/pe64.s
+++ /dev/null
@@ -1,237 +1,0 @@
-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 $efimain(SB), DI
-	MOVQ DI, (SP)
-	RET
-
-TEXT eficall(SB), 1, $-4
-	MOVQ SP, SI
-	MOVQ SP, DI
-	MOVL $(8*16), CX
-	SUBQ CX, DI
-	ANDQ $~15ULL, DI
-	LEAQ 16(DI), SP
-	CLD
-	REP; MOVSB
-	SUBQ $(8*16), SI
-
-	MOVQ 0(SP), CX
-	MOVQ 8(SP), DX
-	MOVQ 16(SP), R8
-	MOVQ 24(SP), R9
-	CALL BP
-
-	MOVQ SI, 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
--- a/sys/src/boot/efi/sub.c
+++ b/sys/src/boot/efi/sub.c
@@ -149,11 +149,12 @@
 	return 0;
 }
 
-#define BOOTLINE	((char*)CONFADDR)
+#define BOOTLINE	confaddr
 #define BOOTLINELEN	64
-#define BOOTARGS	((char*)(CONFADDR+BOOTLINELEN))
+#define BOOTARGS	(confaddr+BOOTLINELEN)
 #define	BOOTARGSLEN	(4096-0x200-BOOTLINELEN)
 
+extern char *confaddr;
 static char *confend;
 
 static char*
@@ -329,6 +330,13 @@
 	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
 }
 
+static uvlong
+beswall(uvlong l)
+{
+	uchar *p = (uchar*)&l;
+	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40) | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24) | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8) | (uvlong)p[7];
+}
+
 char*
 bootkern(void *f)
 {
@@ -342,8 +350,12 @@
 	e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
 	switch(beswal(ex.magic)){
 	case S_MAGIC:
-		if(readn(f, e, 8) != 8)
+	case R_MAGIC:
+		if(readn(f, &e, 8) != 8)
 			goto Error;
+		/* load low address */
+		e = (uchar*)(beswall((uvlong)e) & 0x0FFFFFFFUL);
+		break;
 	case I_MAGIC:
 		break;
 	default:
@@ -371,7 +383,7 @@
 	memconf(findconf("*e820=")?nil:&confend);
 	unload();
 
-	jump(e);
+	jump(e, BOOTARGS);
 
 Error:		
 	return "i/o error";
--- /dev/null
+++ b/sys/src/boot/efi/x64.s
@@ -1,0 +1,124 @@
+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 $efimain(SB), DI
+	MOVQ DI, (SP)
+	RET
+
+TEXT eficall(SB), 1, $-4
+	MOVQ SP, SI
+	MOVQ SP, DI
+	MOVL $(8*16), CX
+	SUBQ CX, DI
+	ANDQ $~15ULL, DI
+	LEAQ 16(DI), SP
+	CLD
+	REP; MOVSB
+	SUBQ $(8*16), SI
+
+	MOVQ 0(SP), CX
+	MOVQ 8(SP), DX
+	MOVQ 16(SP), R8
+	MOVQ 24(SP), R9
+	CALL BP
+
+	MOVQ SI, SP
+	RET
+
+TEXT rebase(SB), 1, $-4
+	MOVQ BP, AX
+	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
+
+GLOBL	confaddr(SB), $8
+DATA	confaddr(SB)/8, $CONFADDR