Skip to content

Commit d9ee778

Browse files
committed
Base environment
0 parents  commit d9ee778

30 files changed

+1924
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build
2+
fs

Makefile

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
CC = x86_64-w64-mingw32-gcc
2+
CFLAGS = -Wall -Wextra
3+
CFLAGS += -nostdinc -nostdlib -fno-builtin -fno-common
4+
# https://forum.osdev.org/viewtopic.php?f=1&t=28307
5+
CFLAGS += -fno-stack-check -fno-stack-protector -mno-stack-arg-probe
6+
CFLAGS += -Wl,--subsystem,10
7+
8+
all: build/OVMF.fd fs/EFI/BOOT/BOOTX64.EFI
9+
10+
build/BOOTX64.EFI: build/bootloader.o build/efi.o build/file.o build/hardware_info.o build/memory.o build/util.o
11+
mkdir -p build
12+
$(CC) $(CFLAGS) -e efi_main -o $@ $^
13+
14+
build/%.o: %.c
15+
mkdir -p build
16+
$(CC) $(CFLAGS) -Iinclude -c -o $@ $<
17+
18+
build/OVMF.fd:
19+
mkdir -p build
20+
wget -O build/OVMF.zip http://downloads.sourceforge.net/project/edk2/OVMF/OVMF-X64-r15214.zip
21+
unzip build/OVMF.zip -d build
22+
23+
fs/EFI/BOOT/BOOTX64.EFI: build/BOOTX64.EFI
24+
mkdir -p fs/EFI/BOOT
25+
cp $< $@
26+
27+
clean:
28+
rm -Rf build/* fs/*
29+
30+
.PHONY: all clean

bootloader.c

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include <efi.h>
2+
#include <file.h>
3+
#include <hardware_info.h>
4+
#include <memory.h>
5+
#include <util.h>
6+
7+
#define MB 1048576 // 1024 * 1024
8+
#define KERNEL_NAME_LEN 6
9+
static const CHAR16 AppleFirmwareVendor[6] = L"Apple";
10+
static CHAR16 KERNEL_NAME[KERNEL_NAME_LEN] = L"kernel";
11+
static CHAR16 APP1_NAME[] = L"app1";
12+
static CHAR16 APP2_NAME[] = L"app2";
13+
static CHAR16 APP3_NAME[] = L"app3";
14+
static const unsigned long long KERNEL_START = 0x100000000;
15+
static const unsigned long long APP1_START = 0x104000000;
16+
static const unsigned long long APP2_START = 0x105000000;
17+
static const unsigned long long APP3_START = 0x106000000;
18+
19+
void check_pixel_format() {
20+
// TODO: Support other pixel formats
21+
if (get_pixel_format() == PixelBlueGreenRedReserved8BitPerColor) {
22+
puts(L"Pixel format `PixelRedGreenBlueReversed8BitPerColor is supported\r\n`");
23+
} else {
24+
puts(L"Unsupported pixel format: ");
25+
puth(get_pixel_format(), 8);
26+
while(1);
27+
}
28+
}
29+
30+
void apple_support() {
31+
EFI_STATUS status;
32+
33+
// Thanks to the rEFIt 0.14 project for having figured this out long ago.
34+
// ConsoleControlProtocol is needed to switch Mac boot graphics to text mode.
35+
if (compare(SystemTable->FirmwareVendor, AppleFirmwareVendor, 6)) {
36+
status = SystemTable->BootServices->LocateProtocol(&ccp_guid, NULL, (void **)&CCP);
37+
if (EFI_ERROR(status)) CCP = NULL;
38+
if (CCP != NULL) {
39+
EFI_CONSOLE_CONTROL_SCREEN_MODE mode;
40+
CCP->GetMode(CCP, &mode, NULL, NULL);
41+
if (mode != EfiConsoleControlScreenText) {
42+
CCP->SetMode(CCP, EfiConsoleControlScreenText);
43+
}
44+
}
45+
}
46+
}
47+
48+
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, struct EFI_SYSTEM_TABLE *st) {
49+
EFI_STATUS status;
50+
51+
efi_init(st);
52+
get_hardware_info();
53+
SystemTable->ConOut->ClearScreen(SystemTable->ConOut);
54+
check_pixel_format();
55+
apple_support();
56+
57+
puts(L"Loading kernel image...\r\n");
58+
59+
// Assuming UEFI firmware recognizes multiple volumes, find the volume where kernel is located
60+
struct EFI_FILE_PROTOCOL *kernel_file = NULL;
61+
struct EFI_FILE_PROTOCOL *app1_file = NULL;
62+
struct EFI_FILE_PROTOCOL *app2_file = NULL;
63+
struct EFI_FILE_PROTOCOL *app3_file = NULL;
64+
{
65+
UINTN handle_cnt;
66+
EFI_HANDLE *handle_buffer;
67+
status = SystemTable->BootServices->LocateHandleBuffer(ByProtocol, &sfsp_guid, NULL, &handle_cnt, &handle_buffer);
68+
assert(status, L"BootServices#LocateHandleBuffer error");
69+
70+
struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
71+
for (UINTN i = 0; i < handle_cnt; i++) {
72+
status = SystemTable->BootServices->HandleProtocol(handle_buffer[i], &sfsp_guid, (void **)&fs);
73+
assert(status, L"BootServices#HandleProtocol error");
74+
75+
struct EFI_FILE_PROTOCOL *root;
76+
status = fs->OpenVolume(fs, &root);
77+
assert(status, L"OpenVolume error");
78+
79+
char kernel_found = 0;
80+
while (1) {
81+
UINTN buffer_size = 256; // Arbitrary size
82+
unsigned char buffer[buffer_size];
83+
status = root->Read(root, &buffer_size, (void *)buffer);
84+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
85+
if (buffer_size == 0) break;
86+
87+
struct EFI_FILE_INFO *file_info = (struct EFI_FILE_INFO *)buffer;
88+
if (compare(file_info->FileName, KERNEL_NAME, KERNEL_NAME_LEN)) kernel_found = 1;
89+
}
90+
91+
if (kernel_found) {
92+
status = root->Open(root, &kernel_file, KERNEL_NAME, EFI_FILE_MODE_READ, 0);
93+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
94+
95+
status = root->Open(root, &app1_file, APP1_NAME, EFI_FILE_MODE_READ, 0);
96+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
97+
98+
status = root->Open(root, &app2_file, APP2_NAME, EFI_FILE_MODE_READ, 0);
99+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
100+
101+
status = root->Open(root, &app3_file, APP3_NAME, EFI_FILE_MODE_READ, 0);
102+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
103+
}
104+
105+
root->Close(root);
106+
}
107+
}
108+
109+
if (!kernel_file) {
110+
puts(L"kernel file not found\r\n");
111+
while (1);
112+
}
113+
114+
struct header {
115+
void *bss_start;
116+
UINTN bss_size;
117+
} head;
118+
unsigned long long head_size = sizeof(head);
119+
120+
{
121+
unsigned long long kernel_size = file_size(kernel_file);
122+
load_file(kernel_file, (void *)&head, head_size);
123+
kernel_size -= head_size;
124+
load_file(kernel_file, (void *)KERNEL_START, kernel_size);
125+
}
126+
127+
{
128+
unsigned long long app1_size = file_size(app1_file);
129+
load_file(app1_file, (void *)&head, head_size);
130+
app1_size -= head_size;
131+
load_file(app1_file, (void *)APP1_START, app1_size);
132+
}
133+
134+
{
135+
unsigned long long app2_size = file_size(app2_file);
136+
load_file(app2_file, (void *)&head, head_size);
137+
app2_size -= head_size;
138+
load_file(app2_file, (void *)APP2_START, app2_size);
139+
}
140+
141+
{
142+
unsigned long long app3_size = file_size(app3_file);
143+
load_file(app3_file, (void *)&head, head_size);
144+
app3_size -= head_size;
145+
load_file(app3_file, (void *)APP3_START, app3_size);
146+
}
147+
148+
kernel_file->Close(kernel_file);
149+
app1_file->Close(app1_file);
150+
app2_file->Close(app2_file);
151+
app3_file->Close(app3_file);
152+
SystemTable->BootServices->SetMem(head.bss_start, head.bss_size, 0);
153+
154+
unsigned long long arg1 = (unsigned long long)SystemTable;
155+
unsigned long long arg2 = (unsigned long long)&hardware_info;
156+
unsigned long long stack_base = KERNEL_START + (16 * MB);
157+
158+
// On success, this loader owns all available memory in the system.
159+
puts(L"Exiting boot service...\r\n");
160+
exit_boot_services(ImageHandle);
161+
162+
asm ("mov %0, %%rdi\n"
163+
"mov %1, %%rsi\n"
164+
"mov %2, %%rsp\n"
165+
"jmp *%3\n"
166+
::"m"(arg1), "m"(arg2), "m"(stack_base), "m"(KERNEL_START));
167+
168+
puts(L"Not reached here\r\n");
169+
while (1);
170+
}

efi.c

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <efi.h>
2+
#include <util.h>
3+
4+
struct EFI_SYSTEM_TABLE *SystemTable;
5+
struct EFI_CONSOLE_CONTROL_PROTOCOL *CCP;
6+
struct EFI_GRAPHICS_OUTPUT_PROTOCOL *GOP;
7+
struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SFSP;
8+
9+
struct EFI_GUID ccp_guid = { 0xf42f7782, 0x12e, 0x4c12, {0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21} };
10+
struct EFI_GUID gop_guid = {0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a}};
11+
struct EFI_GUID sfsp_guid = {0x0964e5b22,0x6459,0x11d2, {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}};
12+
13+
// EFI_FILE_INFO_ID
14+
struct EFI_GUID fi_guid = {0x09576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
15+
16+
// EFI_ACPI_TABLE_GUID
17+
struct EFI_GUID acpi_table_guid = {0x8868e871,0xe4f1,0x11d3, {0xbc,0x22,0x00,0x80,0xc7,0x3c,0x88,0x81}};
18+
19+
void efi_init(struct EFI_SYSTEM_TABLE *st) {
20+
SystemTable = st;
21+
SystemTable->BootServices->LocateProtocol(&gop_guid, NULL, (void **)&GOP);
22+
SystemTable->BootServices->LocateProtocol(&sfsp_guid, NULL, (void **)&SFSP);
23+
}
24+
25+
void *find_acpi_table() {
26+
for (UINTN i = 0; i < SystemTable->NumberOfTableEntries; i++) {
27+
struct EFI_GUID *guid = &SystemTable->ConfigurationTable[i].VendorGuid;
28+
if (compare_guid(guid, &acpi_table_guid)) return SystemTable->ConfigurationTable[i].VendorTable;
29+
}
30+
return NULL;
31+
}

file.c

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <efi.h>
2+
#include <file.h>
3+
#include <util.h>
4+
5+
#define READ_UNIT 16384 // 16KiB
6+
7+
void load_file(struct EFI_FILE_PROTOCOL *src, void *dst, unsigned long long size) {
8+
while (size > READ_UNIT) {
9+
UINTN unit = READ_UNIT;
10+
EFI_STATUS status = src->Read(src, &unit, dst);
11+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
12+
size -= unit;
13+
dst += unit;
14+
}
15+
16+
while (size > 0) {
17+
unsigned long long sz = size;
18+
EFI_STATUS status = src->Read(src, &sz, dst);
19+
assert(status, L"EFI_FILE_PROTOCOL#Read error");
20+
size -= sz;
21+
dst += sz;
22+
}
23+
}
24+
25+
unsigned long long file_size(struct EFI_FILE_PROTOCOL *file) {
26+
struct EFI_FILE_INFO file_info;
27+
UINTN buffer_size = sizeof(file_info);
28+
EFI_STATUS status = file->GetInfo(file, &fi_guid, &buffer_size, (void *)&file_info);
29+
assert(status, L"EFI_FILE_PROTOCOL#GetInfo error");
30+
return file_info.FileSize;
31+
}

hardware_info.c

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <efi.h>
2+
#include <hardware_info.h>
3+
4+
struct HardwareInfo hardware_info;
5+
6+
void get_hardware_info() {
7+
hardware_info.fb.base = (struct Pixel *)GOP->Mode->FrameBufferBase;
8+
hardware_info.fb.width = GOP->Mode->Info->HorizontalResolution;
9+
hardware_info.fb.height = GOP->Mode->Info->VerticalResolution;
10+
hardware_info.fb.total_size = GOP->Mode->FrameBufferSize;
11+
12+
hardware_info.rsdp = find_acpi_table();
13+
}
14+
15+
EFI_GRAPHICS_PIXEL_FORMAT get_pixel_format() {
16+
return GOP->Mode->Info->PixelFormat;
17+
}

0 commit comments

Comments
 (0)