Create a kernel data area for passing information

This commit is contained in:
Justin C. Miller
2018-03-27 10:40:38 -07:00
parent 561686abd3
commit 2b9a0ca15e
6 changed files with 218 additions and 68 deletions

View File

@@ -4,11 +4,14 @@
static CHAR16 kernel_name[] = KERNEL_FILENAME; static CHAR16 kernel_name[] = KERNEL_FILENAME;
EFI_STATUS EFI_STATUS
loader_load_kernel(void **kernel_image, uint64_t *length) loader_load_kernel(void **kernel_image, uint64_t *kernel_length, void **kernel_data, uint64_t *data_length)
{ {
if (kernel_image == 0 || length == 0) if (kernel_image == 0 || kernel_length == 0)
CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, "NULL kernel_image or length pointer"); CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, "NULL kernel_image or length pointer");
if (kernel_data == 0 || data_length == 0)
CHECK_EFI_STATUS_OR_RETURN(EFI_INVALID_PARAMETER, "NULL kernel_data or length pointer");
EFI_STATUS status; EFI_STATUS status;
EFI_GUID guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; EFI_GUID guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
EFI_HANDLE *handles = NULL; EFI_HANDLE *handles = NULL;
@@ -48,7 +51,7 @@ loader_load_kernel(void **kernel_image, uint64_t *length)
CHECK_EFI_STATUS_OR_RETURN(status, "Freeing kernel file info memory"); CHECK_EFI_STATUS_OR_RETURN(status, "Freeing kernel file info memory");
UINTN page_count = ((buffer_size - 1) / 0x1000) + 1; UINTN page_count = ((buffer_size - 1) / 0x1000) + 1;
EFI_PHYSICAL_ADDRESS addr = KERNEL_PHYS_ADDRESS; // Try to load the kernel in at 1MiB EFI_PHYSICAL_ADDRESS addr = KERNEL_PHYS_ADDRESS;
EFI_MEMORY_TYPE mem_type = KERNEL_MEMTYPE; // Special value to tell the kernel it's here EFI_MEMORY_TYPE mem_type = KERNEL_MEMTYPE; // Special value to tell the kernel it's here
status = ST->BootServices->AllocatePages(AllocateAddress, mem_type, page_count, &addr); status = ST->BootServices->AllocatePages(AllocateAddress, mem_type, page_count, &addr);
if (status == EFI_NOT_FOUND) { if (status == EFI_NOT_FOUND) {
@@ -57,6 +60,7 @@ loader_load_kernel(void **kernel_image, uint64_t *length)
ST->BootServices->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr); ST->BootServices->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr);
} }
CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel pages"); CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel pages");
Print(L"\n Allocating %u pages at 0x%x", page_count, addr);
buffer = (void *)addr; buffer = (void *)addr;
status = file->Read(file, &buffer_size, buffer); status = file->Read(file, &buffer_size, buffer);
@@ -65,8 +69,25 @@ loader_load_kernel(void **kernel_image, uint64_t *length)
status = file->Close(file); status = file->Close(file);
CHECK_EFI_STATUS_OR_RETURN(status, "Closing kernel file handle"); CHECK_EFI_STATUS_OR_RETURN(status, "Closing kernel file handle");
*length = buffer_size; *kernel_length = buffer_size;
*kernel_image = buffer; *kernel_image = buffer;
addr += page_count * 0x1000; // Get the next page after the kernel pages
mem_type = KERNEL_DATA_MEMTYPE; // Special value for kernel data
page_count = ((*data_length - 1) / 0x1000) + 1;
status = ST->BootServices->AllocatePages(AllocateAddress, mem_type, page_count, &addr);
if (status == EFI_NOT_FOUND) {
// couldn't get the address we wanted, try loading anywhere
status =
ST->BootServices->AllocatePages(AllocateAnyPages, mem_type, page_count, &addr);
}
CHECK_EFI_STATUS_OR_RETURN(status, "Allocating kernel data pages");
Print(L"\n Allocating %u pages at 0x%x", page_count, addr);
*data_length = page_count * 0x1000;
*kernel_data = (void *)addr;
ST->BootServices->SetMem(*kernel_data, *data_length, 0);
return EFI_SUCCESS; return EFI_SUCCESS;
} }
} }

View File

@@ -5,16 +5,24 @@
#define KERNEL_PHYS_ADDRESS 0x100000 #define KERNEL_PHYS_ADDRESS 0x100000
#endif #endif
#ifndef KERNEL_VIRT_ADDRESS #ifndef VIRTUAL_OFFSET
#define KERNEL_VIRT_ADDRESS 0xf00000000 #define VIRTUAL_OFFSET 0xf00000000
#endif #endif
#ifndef KERNEL_MEMTYPE #ifndef KERNEL_MEMTYPE
#define KERNEL_MEMTYPE 0x80000000 #define KERNEL_MEMTYPE 0x80000000
#endif #endif
#ifndef KERNEL_DATA_MEMTYPE
#define KERNEL_DATA_MEMTYPE 0x80000001
#endif
#ifndef KERNEL_DATA_PAGES
#define KERNEL_DATA_PAGES 1
#endif
#ifndef KERNEL_FILENAME #ifndef KERNEL_FILENAME
#define KERNEL_FILENAME L"kernel.bin" #define KERNEL_FILENAME L"kernel.bin"
#endif #endif
EFI_STATUS loader_load_kernel(void **kernel_image, UINT64 *length); EFI_STATUS loader_load_kernel(void **kernel_image, uint64_t *kernel_length, void **kernel_data, uint64_t *data_length);

View File

@@ -1,5 +1,7 @@
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include <stdalign.h>
#include <stddef.h>
#include "console.h" #include "console.h"
#include "loader.h" #include "loader.h"
@@ -10,24 +12,57 @@
#define GIT_VERSION L"no version" #define GIT_VERSION L"no version"
#endif #endif
#define KERNEL_MAGIC 0x600db007 #define KERNEL_HEADER_MAGIC 0x600db007
#define KERNEL_HEADER_VERSION 1
#define DATA_HEADER_MAGIC 0x600dda7a
#define DATA_HEADER_VERSION 1
#pragma pack(push, 1) #pragma pack(push, 1)
struct kernel_version { struct kernel_version {
uint32_t magic; uint32_t magic;
uint16_t version;
uint16_t length;
uint8_t major; uint8_t major;
uint8_t minor; uint8_t minor;
uint16_t patch; uint16_t patch;
uint32_t gitsha; uint32_t gitsha;
void *entrypoint; void *entrypoint;
}; };
struct popcorn_data {
uint32_t magic;
uint16_t version;
uint16_t length;
uint16_t data_pages;
uint16_t _reserverd;
uint32_t flags;
EFI_MEMORY_DESCRIPTOR *memory_map;
EFI_RUNTIME_SERVICES *runtime;
}
__attribute__((aligned(_Alignof(EFI_MEMORY_DESCRIPTOR))));
#pragma pack(pop) #pragma pack(pop)
EFI_STATUS EFI_STATUS
efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{ {
EFI_STATUS status; EFI_STATUS status;
UINTN memmap_size = 0;
UINTN memmap_key = 0;
UINTN desc_size = 0;
UINTN newmap_size = 0;
UINTN data_length = 0;
UINT32 desc_version = 0;
InitializeLib(ImageHandle, SystemTable); InitializeLib(ImageHandle, SystemTable);
// When checking the console initialization error, // When checking the console initialization error,
@@ -38,33 +73,63 @@ efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
// From here on out, use CHECK_EFI_STATUS_OR_FAIL instead // From here on out, use CHECK_EFI_STATUS_OR_FAIL instead
// because the console is now set up // because the console is now set up
con_status_begin(L"Computing needed data pages...");
status = memory_get_map_size(&data_length);
size_t header_size = sizeof(struct popcorn_data);
const size_t header_align = alignof(struct popcorn_data);
if (header_size % header_align)
header_size += header_align - (header_size % header_align);
data_length += header_size;
con_status_ok();
con_status_begin(L"Loading kernel into memory..."); con_status_begin(L"Loading kernel into memory...");
void *kernel_image = NULL; void *kernel_image = NULL, *kernel_data = NULL;
uint64_t kernel_length = 0; uint64_t kernel_length = 0;
status = loader_load_kernel(&kernel_image, &kernel_length); status = loader_load_kernel(&kernel_image, &kernel_length, &kernel_data, &data_length);
CHECK_EFI_STATUS_OR_FAIL(status); CHECK_EFI_STATUS_OR_FAIL(status);
Print(L"\n %u bytes at 0x%x", kernel_length, kernel_image); Print(L"\n %u bytes at 0x%x", kernel_length, kernel_image);
Print(L"\n %u data bytes at 0x%x", data_length, kernel_data);
struct kernel_version *version = (struct kernel_version *)kernel_image; struct kernel_version *version = (struct kernel_version *)kernel_image;
if (version->magic != KERNEL_MAGIC) { if (version->magic != KERNEL_HEADER_MAGIC) {
Print(L"\n bad magic %x", version->magic); Print(L"\n bad magic %x", version->magic);
CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR); CHECK_EFI_STATUS_OR_FAIL(EFI_CRC_ERROR);
} }
Print(L"\n Kernel version %d.%d.%d %x%s", version->major, version->minor, version->patch, Print(L"\n Kernel version %d.%d.%d %x%s", version->major, version->minor, version->patch,
version->gitsha & 0x0fffffff, version->gitsha & 0xf0000000 ? "*" : ""); version->gitsha & 0x0fffffff, version->gitsha & 0xf0000000 ? "*" : "");
Print(L"\n Entrypoint %d", version->entrypoint); Print(L"\n Entrypoint 0x%x", version->entrypoint);
void (*kernel_main)() = version->entrypoint; void (*kernel_main)() = version->entrypoint;
con_status_ok(); con_status_ok();
// memory_dump_map(); struct popcorn_data *data_header = (struct popcorn_data *)kernel_data;
data_header->magic = DATA_HEADER_MAGIC;
data_header->version = DATA_HEADER_VERSION;
data_header->length = sizeof(struct popcorn_data);
data_header->data_pages = data_length / 0x1000;
data_header->_reserverd = 0;
data_header->flags = 0;
data_header->memory_map = (EFI_MEMORY_DESCRIPTOR *)(data_header + 1);
data_header->runtime = SystemTable->RuntimeServices;
// Get info about this image
con_status_begin(L"Gathering image information...");
EFI_LOADED_IMAGE *info = 0;
EFI_GUID image_proto = EFI_LOADED_IMAGE_PROTOCOL_GUID;
status = ST->BootServices->HandleProtocol(ImageHandle, &image_proto, (void **)&info);
CHECK_EFI_STATUS_OR_FAIL(status);
con_status_ok();
EFI_MEMORY_DESCRIPTOR *memory_map;
/*
memory_get_map(&memory_map, &memmap_size, &memmap_key, &desc_size, &desc_version);
memory_dump_map(memory_map, memmap_size, desc_size);
*/
con_status_begin(L"Exiting boot services..."); con_status_begin(L"Exiting boot services...");
UINTN memmap_size = 0, memmap_key = 0;
UINTN desc_size = 0;
UINT32 desc_version = 0;
EFI_MEMORY_DESCRIPTOR *memory_map;
status = memory_mark_address_for_update((void **)&ST); status = memory_mark_address_for_update((void **)&ST);
CHECK_EFI_STATUS_OR_FAIL(status); CHECK_EFI_STATUS_OR_FAIL(status);
@@ -75,15 +140,18 @@ efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
status = memory_mark_address_for_update((void **)&kernel_main); status = memory_mark_address_for_update((void **)&kernel_main);
CHECK_EFI_STATUS_OR_FAIL(status); CHECK_EFI_STATUS_OR_FAIL(status);
status = memory_mark_address_for_update((void **)&kernel_data);
CHECK_EFI_STATUS_OR_FAIL(status);
status = memory_get_map(&memory_map, &memmap_size, &memmap_key, &desc_size, &desc_version); status = memory_get_map(&memory_map, &memmap_size, &memmap_key, &desc_size, &desc_version);
CHECK_EFI_STATUS_OR_FAIL(status); CHECK_EFI_STATUS_OR_FAIL(status);
status = memory_copy_map(memory_map, data_header->memory_map, memmap_size, desc_size, info->ImageBase, &newmap_size);
CHECK_EFI_STATUS_OR_FAIL(status);
status = ST->BootServices->ExitBootServices(ImageHandle, memmap_key); status = ST->BootServices->ExitBootServices(ImageHandle, memmap_key);
CHECK_EFI_STATUS_OR_ASSERT(status, 0); CHECK_EFI_STATUS_OR_ASSERT(status, 0);
status = memory_virtualize(memory_map, memmap_size, desc_size, desc_version);
CHECK_EFI_STATUS_OR_ASSERT(status, 0);
kernel_main(); kernel_main();
return EFI_LOAD_ERROR; return EFI_LOAD_ERROR;
} }

View File

@@ -1,11 +1,14 @@
#include <efi.h> #include <efi.h>
#include <efilib.h> #include <efilib.h>
#include <stddef.h>
#include "loader.h" #include "loader.h"
#include "memory.h" #include "memory.h"
#include "utility.h" #include "utility.h"
const UINTN PAGE_SIZE = 4096; #define INCREMENT_DESC(p, b) (EFI_MEMORY_DESCRIPTOR*)(((uint8_t*)(p))+(b))
const size_t PAGE_SIZE = 4096;
const CHAR16 *memory_type_names[] = { const CHAR16 *memory_type_names[] = {
L"EfiReservedMemoryType", L"EfiReservedMemoryType",
@@ -29,8 +32,9 @@ static const CHAR16 *
memory_type_name(UINT32 value) memory_type_name(UINT32 value)
{ {
if (value >= (sizeof(memory_type_names) / sizeof(CHAR16 *))) { if (value >= (sizeof(memory_type_names) / sizeof(CHAR16 *))) {
if (value == KERNEL_MEMTYPE) return L"Kernel Image"; if (value == KERNEL_DATA_MEMTYPE) return L"Kernel Data";
return L"Bad Type Value"; else if (value == KERNEL_MEMTYPE) return L"Kernel Image";
else return L"Bad Type Value";
} }
return memory_type_names[value]; return memory_type_names[value];
} }
@@ -57,36 +61,71 @@ memory_mark_address_for_update(void **pointer)
CHECK_EFI_STATUS_OR_ASSERT(status, pointer); CHECK_EFI_STATUS_OR_ASSERT(status, pointer);
} }
EFI_STATUS void
memory_virtualize(EFI_MEMORY_DESCRIPTOR *memory_map, UINTN memmap_size, UINTN desc_size, copy_desc(EFI_MEMORY_DESCRIPTOR *src, EFI_MEMORY_DESCRIPTOR *dst, size_t len)
UINT32 desc_version)
{ {
uint8_t *srcb = (uint8_t *)src;
EFI_MEMORY_DESCRIPTOR *end = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)memory_map + memmap_size); uint8_t *dstb = (uint8_t *)dst;
EFI_MEMORY_DESCRIPTOR *d = memory_map; uint8_t *endb = srcb + len;
while (d < end) { while (srcb < endb)
if (d->Type == KERNEL_MEMTYPE) { *dstb++ = *srcb++;
// d->VirtualStart = (EFI_VIRTUAL_ADDRESS)KERNEL_VIRT_ADDRESS;
d->VirtualStart = (EFI_VIRTUAL_ADDRESS)d->PhysicalStart;
d->Attribute |= EFI_MEMORY_RUNTIME;
} else /*if (d->Attribute & EFI_MEMORY_RUNTIME)*/ {
d->VirtualStart = (EFI_VIRTUAL_ADDRESS)d->PhysicalStart;
}
d = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)d + desc_size);
}
return ST->RuntimeServices->SetVirtualAddressMap(memmap_size, desc_size, desc_version,
memory_map);
} }
EFI_STATUS EFI_STATUS
memory_get_map(EFI_MEMORY_DESCRIPTOR **buffer, UINTN *buffer_size, UINTN *key, UINTN *desc_size, memory_copy_map(EFI_MEMORY_DESCRIPTOR *oldmap, EFI_MEMORY_DESCRIPTOR *newmap, size_t oldmap_size,
size_t desc_size, void *this_image, size_t *newmap_size)
{
size_t count = 0;
EFI_MEMORY_DESCRIPTOR *s;
EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(oldmap, oldmap_size);
for (s = oldmap; s < end; s = INCREMENT_DESC(s, desc_size)) {
if (this_image != (void *)s->PhysicalStart &&
s->Type == EfiLoaderCode ||
s->Type == EfiLoaderData ||
s->Type == EfiBootServicesCode ||
s->Type == EfiBootServicesData ||
s->Type == EfiConventionalMemory) {
// These are memory types we don't need to keep
continue;
}
s->Attribute |= EFI_MEMORY_RUNTIME;
s->VirtualStart = (EFI_VIRTUAL_ADDRESS)(s->PhysicalStart + VIRTUAL_OFFSET);
EFI_MEMORY_DESCRIPTOR *d = INCREMENT_DESC(newmap, count*desc_size);
copy_desc(s, d, desc_size);
++count;
}
*newmap_size = desc_size * count;
return EFI_SUCCESS;
}
EFI_STATUS
memory_get_map_size(size_t *size)
{
if (size == NULL)
return EFI_INVALID_PARAMETER;
EFI_STATUS status;
size_t key, desc_size;
uint32_t desc_version;
*size = 0;
status = ST->BootServices->GetMemoryMap(size, 0, &key, &desc_size, &desc_version);
if (status != EFI_BUFFER_TOO_SMALL) {
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to get memory map size");
}
return EFI_SUCCESS;
}
EFI_STATUS
memory_get_map(EFI_MEMORY_DESCRIPTOR **buffer, size_t *buffer_size, size_t *key, size_t *desc_size,
UINT32 *desc_version) UINT32 *desc_version)
{ {
EFI_STATUS status; EFI_STATUS status;
UINTN needs_size = 0; size_t needs_size = 0;
status = ST->BootServices->GetMemoryMap(&needs_size, 0, key, desc_size, desc_version); status = ST->BootServices->GetMemoryMap(&needs_size, 0, key, desc_size, desc_version);
if (status != EFI_BUFFER_TOO_SMALL) { if (status != EFI_BUFFER_TOO_SMALL) {
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to load memory map"); CHECK_EFI_STATUS_OR_RETURN(status, "Failed to load memory map");
@@ -103,32 +142,30 @@ memory_get_map(EFI_MEMORY_DESCRIPTOR **buffer, UINTN *buffer_size, UINTN *key, U
} }
EFI_STATUS EFI_STATUS
memory_dump_map() memory_dump_map(EFI_MEMORY_DESCRIPTOR *memory_map, size_t memmap_size, size_t desc_size)
{ {
EFI_MEMORY_DESCRIPTOR *buffer; const size_t count = memmap_size / desc_size;
UINTN buffer_size, desc_size, key;
UINT32 desc_version;
EFI_STATUS status = memory_get_map(&buffer, &buffer_size, &key, &desc_size, &desc_version);
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to get memory map");
const UINTN count = buffer_size / desc_size;
Print(L"Memory map:\n"); Print(L"Memory map:\n");
Print(L"\t Descriptor Count: %d (%d bytes)\n", count, buffer_size); Print(L"\t Descriptor Count: %d (%d bytes)\n", count, memmap_size);
Print(L"\t Version Key: %d\n", key); Print(L"\t Descriptor Size: %d bytes\n", desc_size);
Print(L"\tDescriptor Version: %d (%d bytes)\n\n", desc_version, desc_size); Print(L"\t Type offset: %d\n", offsetof(EFI_MEMORY_DESCRIPTOR, Type));
Print(L"\t Physical offset: %d\n", offsetof(EFI_MEMORY_DESCRIPTOR, PhysicalStart));
Print(L"\t Virtual offset: %d\n", offsetof(EFI_MEMORY_DESCRIPTOR, VirtualStart));
Print(L"\t Pages offset: %d\n", offsetof(EFI_MEMORY_DESCRIPTOR, NumberOfPages));
Print(L"\t Attr offset: %d\n\n", offsetof(EFI_MEMORY_DESCRIPTOR, Attribute));
EFI_MEMORY_DESCRIPTOR *end = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)buffer + buffer_size); EFI_MEMORY_DESCRIPTOR *end = INCREMENT_DESC(memory_map, memmap_size);
EFI_MEMORY_DESCRIPTOR *d = buffer; EFI_MEMORY_DESCRIPTOR *d = memory_map;
while (d < end) { while (d < end) {
int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME; int runtime = (d->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME;
Print(L"%23s%s ", memory_type_name(d->Type), runtime ? L"*" : L" "); Print(L"%23s%s ", memory_type_name(d->Type), runtime ? L"*" : L" ");
Print(L"%016llx (%3d pages)\n", d->PhysicalStart, d->NumberOfPages); Print(L"%016llx ", d->PhysicalStart);
Print(L"%016llx ", d->VirtualStart);
Print(L"[%4d]\n", d->NumberOfPages);
d = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)d + desc_size); d = INCREMENT_DESC(d, desc_size);
} }
ST->BootServices->FreePool(buffer);
return EFI_SUCCESS; return EFI_SUCCESS;
} }

View File

@@ -1,12 +1,26 @@
#pragma once #pragma once
#include <efi.h> #include <efi.h>
struct memory_map {
size_t length;
size_t size;
size_t key;
uint32_t version;
EFI_MEMORY_DESCRIPTOR *entries;
};
EFI_STATUS memory_mark_address_for_update(void **pointer); EFI_STATUS memory_mark_address_for_update(void **pointer);
EFI_STATUS memory_virtualize(EFI_MEMORY_DESCRIPTOR *memory_map, UINTN memmap_size, UINTN desc_size, EFI_STATUS memory_virtualize(EFI_MEMORY_DESCRIPTOR *memory_map, size_t memmap_size, size_t desc_size,
UINT32 desc_version); UINT32 desc_version);
EFI_STATUS memory_get_map(EFI_MEMORY_DESCRIPTOR **buffer, UINTN *buffer_size, UINTN *key, EFI_STATUS memory_get_map_size(size_t *sizsize);
UINTN *desc_size, UINT32 *desc_version);
EFI_STATUS memory_get_map(EFI_MEMORY_DESCRIPTOR **buffer, size_t *buffer_size, size_t *key,
size_t *desc_size, UINT32 *desc_version);
EFI_STATUS memory_copy_map(EFI_MEMORY_DESCRIPTOR *oldmap, EFI_MEMORY_DESCRIPTOR *newmap,
size_t oldmap_size, size_t desc_size, void *this_image,
size_t *newmap_size);
EFI_STATUS memory_dump_map(); EFI_STATUS memory_dump_map();

View File

@@ -4,12 +4,14 @@ section .header
align 4 align 4
global _header global _header
_header: _header:
dd MAGIC dd MAGIC ; Kernel header magic
db VERSION_MAJOR dw 1 ; Header version 1
dw 1 ; Kernel header length
db VERSION_MAJOR ; Kernel version
db VERSION_MINOR db VERSION_MINOR
dw VERSION_PATCH dw VERSION_PATCH
dd VERSION_GITSHA dd VERSION_GITSHA
dq _start dq _start ; Kernel entrypoint
section .text section .text
align 16 align 16