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.
This commit is contained in:
cinap_lenrek 2014-10-18 02:13:02 +02:00
parent 0a6439a1f5
commit 6f3dfb57eb
8 changed files with 1426 additions and 0 deletions

272
sys/src/boot/efi/efi.c Normal file
View file

@ -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;
}
}

270
sys/src/boot/efi/efi.h Normal file
View file

@ -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;

29
sys/src/boot/efi/fns.h Normal file
View file

@ -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);

47
sys/src/boot/efi/mem.h Normal file
View file

@ -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) */

43
sys/src/boot/efi/mkfile Normal file
View file

@ -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

149
sys/src/boot/efi/pe32.s Normal file
View file

@ -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

234
sys/src/boot/efi/pe64.s Normal file
View file

@ -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

382
sys/src/boot/efi/sub.c Normal file
View file

@ -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";
}