PatchworkOS  966e257
A non-POSIX operating system.
Loading...
Searching...
No Matches
kernel.c
Go to the documentation of this file.
1#include "kernel.h"
2
3#include <boot/boot_info.h>
4#include <stdint.h>
5#include <sys/elf.h>
6#include <sys/math.h>
7#include <sys/proc.h>
8
9EFI_STATUS kernel_load(boot_kernel_t* kernel, EFI_FILE* rootHandle)
10{
11 if (kernel == NULL)
12 {
13 return EFI_INVALID_PARAMETER;
14 }
15
16 Print(L"Loading kernel... ");
17
18 EFI_FILE* kernelDir = NULL;
19 EFI_FILE* file = NULL;
20 EFI_STATUS status = EFI_SUCCESS;
21 void* physStart = 0;
22
23 status = uefi_call_wrapper(rootHandle->Open, 5, rootHandle, &kernelDir, L"kernel", EFI_FILE_MODE_READ, 0);
24 if (EFI_ERROR(status))
25 {
26 Print(L"failed to open boot directory (0x%x)!\n", status);
27 goto cleanup;
28 }
29
30 status = uefi_call_wrapper(kernelDir->Open, 5, kernelDir, &file, L"kernel", EFI_FILE_MODE_READ, 0);
31 if (EFI_ERROR(status))
32 {
33 Print(L"failed to open kernel file (0x%x)!\n", status);
34 goto cleanup;
35 }
36
37 EFI_FILE_INFO* fileInfo = LibFileInfo(file);
38 if (fileInfo == NULL)
39 {
40 Print(L"failed to get kernel file info (0x%x)!\n", status);
41 status = EFI_LOAD_ERROR;
42 goto cleanup;
43 }
44 uint64_t fileSize = fileInfo->FileSize;
45 FreePool(fileInfo);
46
47 void* fileData = AllocatePool(fileSize);
48 if (fileData == NULL)
49 {
50 Print(L"failed to allocate memory for kernel file (0x%x)!\n", status);
51 status = EFI_OUT_OF_RESOURCES;
52 goto cleanup;
53 }
54
55 uint64_t readSize = fileSize;
56 status = uefi_call_wrapper(file->Read, 3, file, &readSize, fileData);
57 if (EFI_ERROR(status) || readSize != fileSize)
58 {
59 Print(L"failed to read kernel file (0x%x)!\n", status);
60 FreePool(fileData);
61 goto cleanup;
62 }
63
64 uint64_t result = elf64_validate(&kernel->elf, fileData, fileSize);
65 if (result != 0)
66 {
67 Print(L"invalid kernel ELF file %d!\n", result);
68 FreePool(fileData);
69 status = EFI_LOAD_ERROR;
70 goto cleanup;
71 }
72
73 Elf64_Addr minVaddr = 0;
74 Elf64_Addr maxVaddr = 0;
75 elf64_get_loadable_bounds(&kernel->elf, &minVaddr, &maxVaddr);
76 uint64_t kernelPageAmount = BYTES_TO_PAGES(maxVaddr - minVaddr);
77
78 Print(L"allocating %llu pages... ", kernelPageAmount);
79 status =
80 uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiReservedMemoryType, kernelPageAmount, &physStart);
81 if (EFI_ERROR(status))
82 {
83 Print(L"failed to allocate pages for kernel (0x%x)!\n", status);
84 goto cleanup;
85 }
86
87 Print(L"loading segments to 0x%p... ", physStart);
88 elf64_load_segments(&kernel->elf, (Elf64_Addr)physStart, minVaddr);
89 kernel->physAddr = physStart;
90
91 Print(L"done!\n");
92 status = EFI_SUCCESS;
93
94cleanup:
95 if (EFI_ERROR(status) && physStart != NULL)
96 {
97 uefi_call_wrapper(BS->FreePages, 2, (EFI_PHYSICAL_ADDRESS)(uintptr_t)physStart,
98 BYTES_TO_PAGES(maxVaddr - minVaddr));
99 physStart = NULL;
100 }
101 if (file != NULL)
102 {
103 uefi_call_wrapper(file->Close, 1, file);
104 }
105 if (kernelDir != NULL)
106 {
107 uefi_call_wrapper(kernelDir->Close, 1, kernelDir);
108 }
109
110 return status;
111}
void elf64_load_segments(const Elf64_File *elf, Elf64_Addr base, Elf64_Off offset)
Load all loadable segments of an ELF file into memory.
uint64_t elf64_validate(Elf64_File *elf, void *data, uint64_t size)
Validate a files content and initalize a ELF64_File structure using it.
void elf64_get_loadable_bounds(const Elf64_File *elf, Elf64_Addr *minAddr, Elf64_Addr *maxAddr)
Get the loadable virtual memory bounds of an ELF file.
uint64_t Elf64_Addr
ELF64 Unsigned program address.
Definition elf.h:30
#define BYTES_TO_PAGES(amount)
Convert a size in bytes to pages.
Definition proc.h:114
#define NULL
Pointer error value.
Definition NULL.h:23
EFI_STATUS kernel_load(boot_kernel_t *kernel, EFI_FILE *rootHandle)
Definition kernel.c:9
static dentry_t * file
Definition log_file.c:22
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
void * physAddr
Definition boot_info.h:90
Elf64_File elf
Definition boot_info.h:89