git: 9front

ref: 267e3cc41aa9aed63f2b9f7e9b69ef0b49f3c7c7
dir: /sys/src/boot/efi/efi.c/

View raw version
#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 int
topbit(ulong mask)
{
	int bit;

	for(bit=1; bit < 32 && (mask >> bit) != 0; bit++)
		;
	return bit;
}

static int
lowbit(ulong mask)
{
	int bit;

	for(bit=0; bit < 32 && (mask & (1<<bit)) == 0; bit++)
		;
	return bit;
}

static char*
modeinfostr(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info, char *s)
{
	ulong mr, mg, mb, mx, mc;
	int n, depth;

	switch(info->PixelFormat){
	default:
		return nil;	/* unsupported */

	case PixelRedGreenBlueReserved8BitPerColor:
		mr = 0x000000ff;
		mg = 0x0000ff00;
		mb = 0x00ff0000;
		mx = 0xff000000;
		break;
	case PixelBlueGreenRedReserved8BitPerColor:
		mb = 0x000000ff;
		mg = 0x0000ff00;
		mr = 0x00ff0000;
		mx = 0xff000000;
		break;
	case PixelBitMask:
		mr = info->PixelInformation.RedMask;
		mg = info->PixelInformation.GreenMask;
		mb = info->PixelInformation.BlueMask;
		mx = info->PixelInformation.ReservedMask;
		break;
	}

	depth = topbit(mr | mg | mb | mx);

	s = decfmt(s, 0, info->PixelsPerScanLine), *s++ = 'x';
	s = decfmt(s, 0, info->VerticalResolution), *s++ = 'x';
	s = decfmt(s, 0, depth), *s++ = ' ';

	while(depth > 0){
		if(depth == topbit(mr)){
			mc = mr;
			*s++ = 'r';
		} else if(depth == topbit(mg)){
			mc = mg;
			*s++ = 'g';
		} else if(depth == topbit(mb)){
			mc = mb;
			*s++ = 'b';
		} else if(depth == topbit(mx)){
			mc = mx;
			*s++ = 'x';
		} else {
			break;
		}
		n = depth - lowbit(mc);
		s = decfmt(s, 0, n);
		depth -= n;
	}
	*s = '\0';

	return 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;
	if((s = modeinfostr(gop->Mode->Info, s)) == nil){
		**cfg = '\0';
		return;
	}
	*s++ = ' ';
	*s++ = '0', *s++ = 'x';
	s = hexfmt(s, 0, gop->Mode->FrameBufferBase), *s++ = '\n';
	*s = '\0';

	print(*cfg);
	*cfg = s;
}

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