Tagging stivale (#16)
* Initial tagging system * stivale: Report bootloader brand and version, change structure of memory map tag * Reintroduce legacy stivale protocol and rename tagging stivale to stivale2
This commit is contained in:
parent
32278a690f
commit
9fcb13c2a2
260
STIVALE.md
260
STIVALE.md
@ -14,7 +14,7 @@ stivale will recognise whether the ELF file is 32-bit or 64-bit and load the ker
|
||||
into the appropriate CPU mode.
|
||||
|
||||
stivale natively supports (only for 64-bit kernels) and encourages higher half kernels.
|
||||
The kernel can load itself at `0xffffffff80100000` (as defined in the linker script)
|
||||
The kernel can load itself at `0xffffffff80100000` or higher (as defined in the linker script)
|
||||
and the bootloader will take care of everything, no AT linker script directives needed.
|
||||
|
||||
If the kernel loads itself in the lower half (`0x100000` or higher), the bootloader
|
||||
@ -36,15 +36,17 @@ The kernel MUST NOT request to load itself at an address lower than `0x100000`
|
||||
field in the stivale header is set to a non-0 value, in which case, it is set to
|
||||
the value of `entry_point`.
|
||||
|
||||
At entry, the bootloader will have setup paging such that there is a 4GiB identity
|
||||
mapped block of memory at `0x0000000000000000`, a 2GiB mapped area of memory
|
||||
that maps from `0x0000000000000000` physical to `0x0000000080000000` physical
|
||||
to `0xffffffff80000000` virtual. This area is for the higher half kernels.
|
||||
Further more, a 4GiB area of memory from `0x0000000000000000` physical to
|
||||
`0x0000000100000000` physical to `0xffff800000000000` virtual is mapped.
|
||||
At entry, the bootloader will have setup paging mappings as such:
|
||||
|
||||
```
|
||||
Base Physical Address - Top Physical Address -> Virtual address
|
||||
0x0000000000000000 - 0x0000000100000000 -> 0x0000000000000000
|
||||
0x0000000000000000 - 0x0000000100000000 -> 0xffff800000000000
|
||||
0x0000000000000000 - 0x0000000080000000 -> 0xffffffff80000000
|
||||
```
|
||||
|
||||
If the kernel is dynamic and not statically linked, the bootloader will relocate it.
|
||||
Furthermore if bit 2 of the flags field in the stivale header is set, the bootloader
|
||||
Furthermore if bit 0 of the flags field in the stivale header is set, the bootloader
|
||||
will perform kernel address space layout randomisation (KASLR).
|
||||
|
||||
The kernel should NOT modify the bootloader page tables, and it should only use them
|
||||
@ -62,8 +64,8 @@ IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined
|
||||
|
||||
PG is enabled (`cr0`), PE is enabled (`cr0`), PAE is enabled (`cr4`),
|
||||
LME is enabled (`EFER`).
|
||||
If stivale header flag bit 1 is set, then, if available, 5-level paging is enabled
|
||||
(LA57 bit in `cr4`).
|
||||
If the stivale header tag for 5-level paging is present, then, if available,
|
||||
5-level paging is enabled (LA57 bit in `cr4`).
|
||||
|
||||
The A20 gate is enabled.
|
||||
|
||||
@ -112,57 +114,138 @@ the header that the bootloader will parse.
|
||||
Said header looks like this:
|
||||
```c
|
||||
struct stivale_header {
|
||||
uint64_t stack; // This is the stack address which will be in RSP
|
||||
// when the kernel is loaded.
|
||||
uint64_t entry_point; // If not 0, this address will be jumped to as the
|
||||
// entry point of the kernel.
|
||||
// If set to 0, the ELF entry point will be used
|
||||
// instead.
|
||||
|
||||
uint16_t flags; // Flags
|
||||
// bit 0 0 = text mode, 1 = graphics framebuffer mode
|
||||
// bit 1 0 = 4-level paging, 1 = use 5-level paging (if
|
||||
available)
|
||||
Ignored if booting a 32-bit kernel.
|
||||
// bit 2 0 = Disable KASLR, 1 = enable KASLR (up to 1GB slide)
|
||||
Ignored if booting a 32-bit or non-relocatable kernel
|
||||
// All other bits undefined.
|
||||
uint64_t stack; // This is the stack address which will be in RSP
|
||||
// when the kernel is loaded.
|
||||
// It can be set to a non-valid stack address such as 0
|
||||
// as long as the OS is 64-bit and sets up a stack on its
|
||||
// own.
|
||||
|
||||
uint16_t framebuffer_width; // These 3 values are parsed if a graphics mode
|
||||
uint16_t framebuffer_height; // is requested. If all values are set to 0
|
||||
uint16_t framebuffer_bpp; // then the bootloader will pick the best possible
|
||||
// video mode automatically (recommended).
|
||||
uint64_t entry_point; // If not 0, this field will be jumped to at entry
|
||||
// instead of the ELF entry point.
|
||||
uint64_t flags; // Bit 0: if 1, enable KASLR
|
||||
// All other bits undefined
|
||||
|
||||
uint64_t tags; // Pointer to the first of the linked list of tags.
|
||||
// see "stivale header tags" section.
|
||||
// NULL = no tags.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
### stivale header tags
|
||||
|
||||
The stivale header uses a mechanism to avoid having protocol versioning, but
|
||||
rather, feature-specific support detection.
|
||||
|
||||
The kernel executable provides the bootloader with a linked list of structures,
|
||||
the first of which is pointed to by the `tags` entry of the stivale header.
|
||||
|
||||
Each tag shall contain these 2 fields:
|
||||
```c
|
||||
struct stivale_hdr_tag {
|
||||
uint64_t identifier;
|
||||
uint64_t next;
|
||||
} __attribute__((packed));
|
||||
|
||||
```
|
||||
|
||||
The `identifier` field identifies what feature the tag is requesting from the
|
||||
bootloader.
|
||||
|
||||
The `next` field points to another tag in the linked list. A NULL value determines
|
||||
the end of the linked list.
|
||||
|
||||
Tag structures can have more than just these 2 members, but these 2 members MUST
|
||||
appear at the beginning of any given tag.
|
||||
|
||||
Tags can have no extra members and just serve as "flags" to enable some behaviour
|
||||
that does not require extra parameters.
|
||||
|
||||
#### Framebuffer header tag
|
||||
|
||||
This tag asks the stivale-compliant bootloader to initialise a graphical framebuffer
|
||||
video mode.
|
||||
Omitting this tag will make the bootloader default to a CGA-compatible text mode,
|
||||
if supported.
|
||||
|
||||
```c
|
||||
struct stivale_hdr_tag_framebuffer {
|
||||
uint64_t identifier; // Identifier: 0x3ecc1bc43d0f7971
|
||||
uint64_t next;
|
||||
uint16_t framebuffer_width; // If all values are set to 0
|
||||
uint16_t framebuffer_height; // then the bootloader will pick the best possible
|
||||
uint16_t framebuffer_bpp; // video mode automatically.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### 5-level paging header tag
|
||||
|
||||
The presence of this tag enables support for 5-level paging, if available.
|
||||
|
||||
Identifier: `0x932f477032007e8f`
|
||||
|
||||
This tag does not have extra members.
|
||||
|
||||
## stivale structure
|
||||
|
||||
The stivale structure returned by the bootloader looks like this:
|
||||
```c
|
||||
struct stivale_struct {
|
||||
uint64_t cmdline; // Pointer to a null-terminated cmdline
|
||||
uint64_t memory_map_addr; // Pointer to the memory map (entries described below)
|
||||
uint64_t memory_map_entries; // Count of memory map entries
|
||||
uint64_t framebuffer_addr; // Address of the framebuffer and related info
|
||||
uint16_t framebuffer_pitch;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_bpp;
|
||||
uint64_t rsdp; // Pointer to the ACPI RSDP structure
|
||||
uint64_t module_count; // Count of modules that stivale loaded according to config
|
||||
uint64_t modules; // Pointer to the first entry in the linked list of modules (described below)
|
||||
uint64_t epoch; // UNIX epoch at boot, read from system RTC
|
||||
uint64_t flags; // Flags
|
||||
// bit 0: 1 if booted with BIOS, 0 if booted with UEFI
|
||||
// All other bits undefined.
|
||||
char bootloader_brand[64]; // Bootloader null-terminated brand string
|
||||
char bootloader_version[64]; // Bootloader null-terminated version string
|
||||
|
||||
uint64_t tags; // Pointer to the first of the linked list of tags.
|
||||
// see "stivale structure tags" section.
|
||||
// NULL = no tags.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
## Memory map entry
|
||||
### stivale structure tags
|
||||
|
||||
These tags work *very* similarly to the header tags, with the main difference being
|
||||
that these tags are returned to the kernel by the bootloader, instead.
|
||||
|
||||
See "stivale header tags".
|
||||
|
||||
The kernel is responsible for parsing the tags and the identifiers, and interpreting
|
||||
the tags that it supports, while handling in a graceful manner the tags it does not
|
||||
recognise.
|
||||
|
||||
#### Command line structure tag
|
||||
|
||||
This tag reports to the kernel the command line string that was passed to it by
|
||||
the bootloader.
|
||||
|
||||
```c
|
||||
struct mmap_entry {
|
||||
struct stivale_struct_tag_cmdline {
|
||||
uint64_t identifier; // Identifier: 0xe5e76a1b4597a781
|
||||
uint64_t next;
|
||||
uint64_t cmdline; // Pointer to a null-terminated cmdline
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Memory map structure tag
|
||||
|
||||
This tag reports to the kernel the memory map built by the bootloader.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_memmap {
|
||||
uint64_t identifier; // Identifier: 0x2187f79e8612de07
|
||||
uint64_t next;
|
||||
uint64_t entries; // Count of memory map entries
|
||||
struct stivale_mmap_entry memmap[]; // Array of memory map entries
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
###### Memory map entry
|
||||
|
||||
```c
|
||||
struct stivale_mmap_entry {
|
||||
uint64_t base; // Base of the memory section
|
||||
uint64_t length; // Length of the section
|
||||
uint32_t type; // Type (described below)
|
||||
enum stivale_mmap_type type; // Type (described below)
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
@ -170,18 +253,21 @@ struct mmap_entry {
|
||||
`type` is an enumeration that can have the following values:
|
||||
|
||||
```
|
||||
1 - Usable RAM
|
||||
2 - Reserved
|
||||
3 - ACPI reclaimable
|
||||
4 - ACPI NVS
|
||||
5 - Bad memory
|
||||
10 - Kernel/Modules
|
||||
enum stivale_mmap_type : uint32_t {
|
||||
USABLE = 1,
|
||||
RESERVED = 2,
|
||||
ACPI_RECLAIMABLE = 3,
|
||||
ACPI_NVS = 4,
|
||||
BAD_MEMORY = 5,
|
||||
BOOTLOADER_RECLAIMABLE = 0x1000,
|
||||
KERNEL_AND_MODULES = 0x1001
|
||||
};
|
||||
```
|
||||
|
||||
All other values are undefined.
|
||||
|
||||
The kernel and modules loaded **are not** marked as usable memory. They are marked
|
||||
as Kernel/Modules (type 10).
|
||||
as Kernel/Modules (type 0x1001).
|
||||
|
||||
Usable RAM chunks are guaranteed to be 4096 byte aligned for both base and length.
|
||||
|
||||
@ -192,17 +278,75 @@ Usable RAM chunks are guaranteed not to overlap with any other entry.
|
||||
To the contrary, all non-usable RAM chunks are not guaranteed any alignment, nor
|
||||
is it guaranteed that they do not overlap each other (except usable RAM).
|
||||
|
||||
## Modules
|
||||
#### Framebuffer structure tag
|
||||
|
||||
This tag reports to the kernel the currently set up framebuffer details, if any.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_framebuffer {
|
||||
uint64_t identifier; // Identifier: 0x506461d2950408fa
|
||||
uint64_t next;
|
||||
uint64_t framebuffer_addr; // Address of the framebuffer and related info
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_pitch;
|
||||
uint16_t framebuffer_bpp;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Modules structure tag
|
||||
|
||||
This tag lists modules that the bootloader loaded alongside the kernel, if any.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_modules {
|
||||
uint64_t identifier; // Identifier: 0x4b6fe466aade04ce
|
||||
uint64_t next;
|
||||
uint64_t module_count; // Count of loaded modules
|
||||
struct stivale_module modules[]; // Array of module descriptors
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
The `modules` variable points to the first entry of the linked list of module
|
||||
structures.
|
||||
A module structure looks like this:
|
||||
```c
|
||||
struct stivale_module {
|
||||
uint64_t begin; // Address where the module is loaded
|
||||
uint64_t end; // End address of the module
|
||||
char string[128]; // String passed to the module (by config file)
|
||||
uint64_t next; // Pointer to the next module (if any), check module_count
|
||||
// in the stivale_struct
|
||||
char string[128]; // 0-terminated string passed to the module
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### RSDP structure tag
|
||||
|
||||
This tag reports to the kernel the location of the ACPI RSDP structure in memory.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_rsdp {
|
||||
uint64_t identifier; // Identifier: 0x9e1786930a375e78
|
||||
uint64_t next;
|
||||
uint64_t rsdp; // Pointer to the ACPI RSDP structure
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Epoch structure tag
|
||||
|
||||
This tag reports to the kernel the current UNIX epoch, as per RTC.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_epoch {
|
||||
uint64_t identifier; // Identifier: 0x566a7bed888e1407
|
||||
uint64_t next;
|
||||
uint64_t epoch; // UNIX epoch at boot, read from system RTC
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Firmware structure tag
|
||||
|
||||
This tag reports to the kernel info about the firmware.
|
||||
|
||||
```c
|
||||
struct stivale_struct_tag_firmware {
|
||||
uint64_t identifier; // Identifier: 0x359d837855e3858c
|
||||
uint64_t next;
|
||||
uint64_t flags; // Bit 0: 0 = UEFI, 1 = BIOS
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
BIN
qloader2.bin
BIN
qloader2.bin
Binary file not shown.
@ -103,7 +103,10 @@ stage2:
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
jmp 0x8000
|
||||
and edx, 0xff
|
||||
push edx
|
||||
|
||||
call 0x8000
|
||||
|
||||
bits 16
|
||||
%include 'a20_enabler.inc'
|
||||
|
@ -271,8 +271,6 @@ int elf32_load_section(struct file_handle *fd, void *buffer, const char *name, s
|
||||
return 2;
|
||||
}
|
||||
|
||||
#define FIXED_HIGHER_HALF_OFFSET_64 ((uint64_t)0xffffffff80000000)
|
||||
|
||||
int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uint64_t slide) {
|
||||
struct elf64_hdr hdr;
|
||||
fread(fd, &hdr, 0, sizeof(struct elf64_hdr));
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <stdint.h>
|
||||
#include <fs/file.h>
|
||||
|
||||
#define FIXED_HIGHER_HALF_OFFSET_64 ((uint64_t)0xffffffff80000000)
|
||||
|
||||
int elf_bits(struct file_handle *fd);
|
||||
|
||||
int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uint64_t slide);
|
||||
|
@ -10,22 +10,32 @@
|
||||
#define MEMMAP_BASE ((size_t)0x100000)
|
||||
#define MEMMAP_MAX_ENTRIES 256
|
||||
|
||||
#define MEMMAP_USABLE 1
|
||||
#define MEMMAP_RESERVED 2
|
||||
#define MEMMAP_ACPI_RECLAIMABLE 3
|
||||
#define MEMMAP_ACPI_NVS 4
|
||||
#define MEMMAP_BAD_MEMORY 5
|
||||
#define MEMMAP_BOOTLOADER_RECLAIMABLE 0x1000
|
||||
#define MEMMAP_KERNEL_AND_MODULES 0x1001
|
||||
|
||||
static struct e820_entry_t memmap[MEMMAP_MAX_ENTRIES];
|
||||
static size_t memmap_entries = 0;
|
||||
|
||||
static const char *memmap_type(uint32_t type) {
|
||||
switch (type) {
|
||||
case 1:
|
||||
case MEMMAP_USABLE:
|
||||
return "Usable RAM";
|
||||
case 2:
|
||||
case MEMMAP_RESERVED:
|
||||
return "Reserved";
|
||||
case 3:
|
||||
case MEMMAP_ACPI_RECLAIMABLE:
|
||||
return "ACPI reclaimable";
|
||||
case 4:
|
||||
case MEMMAP_ACPI_NVS:
|
||||
return "ACPI NVS";
|
||||
case 5:
|
||||
case MEMMAP_BAD_MEMORY:
|
||||
return "Bad memory";
|
||||
case 10:
|
||||
case MEMMAP_BOOTLOADER_RECLAIMABLE:
|
||||
return "Bootloader reclaimable";
|
||||
case MEMMAP_KERNEL_AND_MODULES:
|
||||
return "Kernel/Modules";
|
||||
default:
|
||||
return "???";
|
||||
@ -196,7 +206,7 @@ void memmap_alloc_range(uint64_t base, uint64_t length) {
|
||||
}
|
||||
target = &memmap[memmap_entries++];
|
||||
|
||||
target->type = 10;
|
||||
target->type = MEMMAP_KERNEL_AND_MODULES;
|
||||
target->base = base;
|
||||
target->length = length;
|
||||
|
||||
|
17
src/main.c
17
src/main.c
@ -1,19 +1,17 @@
|
||||
asm (
|
||||
".section .entry\n\t"
|
||||
"xor dh, dh\n\t"
|
||||
"push edx\n\t"
|
||||
|
||||
// Zero out .bss
|
||||
"xor al, al\n\t"
|
||||
"lea edi, bss_begin\n\t"
|
||||
"lea ecx, bss_end\n\t"
|
||||
"lea edx, bss_begin\n\t"
|
||||
"sub ecx, edx\n\t"
|
||||
"mov edi, OFFSET bss_begin\n\t"
|
||||
"mov ecx, OFFSET bss_end\n\t"
|
||||
"sub ecx, OFFSET bss_begin\n\t"
|
||||
"rep stosb\n\t"
|
||||
|
||||
"call main\n\t"
|
||||
"jmp main\n\t"
|
||||
);
|
||||
|
||||
#include <qloader2.h>
|
||||
#include <drivers/vga_textmode.h>
|
||||
#include <lib/real.h>
|
||||
#include <lib/blib.h>
|
||||
@ -26,6 +24,7 @@ asm (
|
||||
#include <fs/file.h>
|
||||
#include <lib/elf.h>
|
||||
#include <protos/stivale.h>
|
||||
#include <protos/stivale2.h>
|
||||
#include <protos/linux.h>
|
||||
#include <protos/templeos.h>
|
||||
#include <protos/chainload.h>
|
||||
@ -35,7 +34,7 @@ void main(int boot_drive) {
|
||||
// Initial prompt.
|
||||
init_vga_textmode();
|
||||
|
||||
print("qloader2\n\n");
|
||||
print("qloader2 " QLOADER2_VERSION "\n\n");
|
||||
|
||||
print("Boot drive: %x\n", boot_drive);
|
||||
|
||||
@ -73,6 +72,8 @@ void main(int boot_drive) {
|
||||
|
||||
if (!strcmp(proto, "stivale")) {
|
||||
stivale_load(cmdline, boot_drive);
|
||||
} else if (!strcmp(proto, "stivale2")) {
|
||||
stivale2_load(cmdline, boot_drive);
|
||||
} else if (!strcmp(proto, "linux")) {
|
||||
linux_load(cmdline, boot_drive);
|
||||
} else if (!strcmp(proto, "templeos")) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <qloader2.h>
|
||||
#include <menu.h>
|
||||
#include <lib/print.h>
|
||||
#include <lib/blib.h>
|
||||
@ -31,11 +32,7 @@ char *menu(void) {
|
||||
|
||||
refresh:
|
||||
text_clear();
|
||||
print("\n");
|
||||
print(" \e[44m \e[40m\n");
|
||||
print(" \e[44m qloader\e[33m2\e[37m \e[40m\n");
|
||||
print(" \e[44m \e[40m\n");
|
||||
print("\n");
|
||||
print("\n\n \e[44m qloader\e[33m2\e[37m " QLOADER2_VERSION " \e[40m\n\n\n");
|
||||
|
||||
print("Select an entry:\n\n");
|
||||
|
||||
|
575
src/protos/stivale2.c
Normal file
575
src/protos/stivale2.c
Normal file
@ -0,0 +1,575 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <qloader2.h>
|
||||
#include <protos/stivale2.h>
|
||||
#include <lib/elf.h>
|
||||
#include <lib/blib.h>
|
||||
#include <lib/acpi.h>
|
||||
#include <lib/memmap.h>
|
||||
#include <lib/config.h>
|
||||
#include <lib/time.h>
|
||||
#include <lib/print.h>
|
||||
#include <lib/rand.h>
|
||||
#include <lib/real.h>
|
||||
#include <lib/libc.h>
|
||||
#include <drivers/vbe.h>
|
||||
#include <drivers/vga_textmode.h>
|
||||
#include <fs/file.h>
|
||||
|
||||
struct stivale2_tag {
|
||||
uint64_t identifier;
|
||||
uint64_t next;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stivale2_header {
|
||||
uint64_t entry_point;
|
||||
uint64_t stack;
|
||||
uint64_t flags;
|
||||
uint64_t tags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_HDR_TAG_FRAMEBUFFER_ID 0x3ecc1bc43d0f7971
|
||||
|
||||
struct stivale2_hdr_tag_framebuffer {
|
||||
struct stivale2_tag tag;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_bpp;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_HDR_TAG_5LV_PAGING_ID 0x932f477032007e8f
|
||||
|
||||
struct stivale2_struct {
|
||||
char bootloader_brand[64];
|
||||
char bootloader_version[64];
|
||||
uint64_t tags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_CMDLINE_ID 0xe5e76a1b4597a781
|
||||
|
||||
struct stivale2_struct_tag_cmdline {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t cmdline;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_MEMMAP_ID 0x2187f79e8612de07
|
||||
|
||||
struct stivale2_mmap_entry {
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint32_t type;
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stivale2_struct_tag_memmap {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t entries;
|
||||
uint64_t memmap;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID 0x506461d2950408fa
|
||||
|
||||
struct stivale2_struct_tag_framebuffer {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t framebuffer_addr;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_pitch;
|
||||
uint16_t framebuffer_bpp;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_MODULES_ID 0x4b6fe466aade04ce
|
||||
|
||||
struct stivale2_module {
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
char string[128];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stivale2_struct_tag_modules {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t module_count;
|
||||
struct stivale2_module modules[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_RSDP_ID 0x9e1786930a375e78
|
||||
|
||||
struct stivale2_struct_tag_rsdp {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t rsdp;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_EPOCH_ID 0x566a7bed888e1407
|
||||
|
||||
struct stivale2_struct_tag_epoch {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t epoch;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_FIRMWARE_ID 0x359d837855e3858c
|
||||
|
||||
struct stivale2_struct_tag_firmware {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define KASLR_SLIDE_BITMASK 0x03FFFF000u
|
||||
|
||||
struct stivale2_struct stivale2_struct = {0};
|
||||
|
||||
inline static size_t get_phys_addr(uint64_t addr) {
|
||||
if (addr & ((uint64_t)1 << 63))
|
||||
return addr - FIXED_HIGHER_HALF_OFFSET_64;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void *get_tag(struct stivale2_header *s, uint64_t id) {
|
||||
struct stivale2_tag *tag = (void*)get_phys_addr(s->tags);
|
||||
for (;;) {
|
||||
if (tag == NULL)
|
||||
return NULL;
|
||||
if (tag->identifier == id)
|
||||
return tag;
|
||||
tag = (void*)get_phys_addr(tag->next);
|
||||
}
|
||||
}
|
||||
|
||||
static void append_tag(struct stivale2_struct *s, struct stivale2_tag *tag) {
|
||||
tag->next = s->tags;
|
||||
s->tags = (uint64_t)(size_t)tag;
|
||||
}
|
||||
|
||||
void stivale2_load(char *cmdline, int boot_drive) {
|
||||
int kernel_drive; {
|
||||
char buf[32];
|
||||
if (!config_get_value(buf, 0, 32, "KERNEL_DRIVE")) {
|
||||
kernel_drive = boot_drive;
|
||||
} else {
|
||||
kernel_drive = (int)strtoui(buf);
|
||||
}
|
||||
}
|
||||
|
||||
int kernel_part; {
|
||||
char buf[32];
|
||||
if (!config_get_value(buf, 0, 32, "KERNEL_PARTITION")) {
|
||||
panic("KERNEL_PARTITION not specified");
|
||||
} else {
|
||||
kernel_part = (int)strtoui(buf);
|
||||
}
|
||||
}
|
||||
|
||||
char *kernel_path = balloc(128);
|
||||
if (!config_get_value(kernel_path, 0, 128, "KERNEL_PATH")) {
|
||||
panic("KERNEL_PATH not specified");
|
||||
}
|
||||
|
||||
struct file_handle *fd = balloc(sizeof(struct file_handle));
|
||||
if (fopen(fd, kernel_drive, kernel_part, kernel_path)) {
|
||||
panic("Could not open kernel file");
|
||||
}
|
||||
|
||||
struct stivale2_header stivale2_hdr;
|
||||
|
||||
int bits = elf_bits(fd);
|
||||
|
||||
int ret;
|
||||
|
||||
uint64_t slide = 0;
|
||||
|
||||
bool level5pg = false;
|
||||
switch (bits) {
|
||||
case 64: {
|
||||
// Check if 64 bit CPU
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
cpuid(0x80000001, 0, &eax, &ebx, &ecx, &edx);
|
||||
if (!(edx & (1 << 29))) {
|
||||
panic("stivale2: This CPU does not support 64-bit mode.");
|
||||
}
|
||||
// Check if 5-level paging is available
|
||||
cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx);
|
||||
if (ecx & (1 << 16)) {
|
||||
print("stivale2: CPU has 5-level paging support\n");
|
||||
level5pg = true;
|
||||
}
|
||||
|
||||
ret = elf64_load_section(fd, &stivale2_hdr, ".stivale2hdr", sizeof(struct stivale2_header), slide);
|
||||
|
||||
if (!ret && (stivale2_hdr.flags & 1)) {
|
||||
// KASLR is enabled, set the slide
|
||||
slide = rand64() & KASLR_SLIDE_BITMASK;
|
||||
|
||||
// Re-read the .stivale2hdr with slid relocations
|
||||
ret = elf64_load_section(fd, &stivale2_hdr, ".stivale2hdr", sizeof(struct stivale2_header), slide);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
ret = elf32_load_section(fd, &stivale2_hdr, ".stivale2hdr", sizeof(struct stivale2_header));
|
||||
break;
|
||||
default:
|
||||
panic("stivale2: Not 32 nor 64 bit x86 ELF file.");
|
||||
}
|
||||
|
||||
print("stivale2: %u-bit ELF file detected\n", bits);
|
||||
|
||||
switch (ret) {
|
||||
case 1:
|
||||
panic("stivale2: File is not a valid ELF.");
|
||||
case 2:
|
||||
panic("stivale2: Section .stivale2hdr not found.");
|
||||
case 3:
|
||||
panic("stivale2: Section .stivale2hdr exceeds the size of the struct.");
|
||||
case 4:
|
||||
panic("stivale2: Section .stivale2hdr is smaller than size of the struct.");
|
||||
}
|
||||
|
||||
print("stivale2: Requested stack at %X\n", stivale2_hdr.stack);
|
||||
|
||||
uint64_t entry_point = 0;
|
||||
uint64_t top_used_addr = 0;
|
||||
|
||||
switch (bits) {
|
||||
case 64:
|
||||
elf64_load(fd, &entry_point, &top_used_addr, slide);
|
||||
break;
|
||||
case 32:
|
||||
elf32_load(fd, (uint32_t *)&entry_point, (uint32_t *)&top_used_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
if (stivale2_hdr.entry_point != 0)
|
||||
entry_point = stivale2_hdr.entry_point;
|
||||
|
||||
print("stivale2: Kernel slide: %X\n", slide);
|
||||
|
||||
print("stivale2: Top used address in ELF: %X\n", top_used_addr);
|
||||
|
||||
strcpy(stivale2_struct.bootloader_brand, "qloader2");
|
||||
strcpy(stivale2_struct.bootloader_version, QLOADER2_VERSION);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create firmware struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_firmware *tag = balloc(sizeof(struct stivale2_struct_tag_firmware));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_FIRMWARE_ID;
|
||||
|
||||
tag->flags = 1 << 0; // bit 0 = BIOS boot
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create modules struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_modules *tag = balloc(sizeof(struct stivale2_struct_tag_modules));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_MODULES_ID;
|
||||
|
||||
tag->module_count = 0;
|
||||
|
||||
for (int i = 0; ; i++) {
|
||||
char module_file[64];
|
||||
if (!config_get_value(module_file, i, 64, "MODULE_PATH"))
|
||||
break;
|
||||
|
||||
tag->module_count++;
|
||||
|
||||
struct stivale2_module *m = balloc(sizeof(struct stivale2_module));
|
||||
|
||||
if (!config_get_value(m->string, i, 128, "MODULE_STRING")) {
|
||||
m->string[0] = '\0';
|
||||
}
|
||||
|
||||
int part; {
|
||||
char buf[32];
|
||||
if (!config_get_value(buf, i, 32, "MODULE_PARTITION")) {
|
||||
part = kernel_part;
|
||||
} else {
|
||||
part = (int)strtoui(buf);
|
||||
}
|
||||
}
|
||||
|
||||
struct file_handle f;
|
||||
if (fopen(&f, fd->disk, part, module_file)) {
|
||||
panic("Requested module with path \"%s\" not found!\n", module_file);
|
||||
}
|
||||
|
||||
void *module_addr = (void *)(((uint32_t)top_used_addr & 0xfff) ?
|
||||
((uint32_t)top_used_addr & ~((uint32_t)0xfff)) + 0x1000 :
|
||||
(uint32_t)top_used_addr);
|
||||
|
||||
memmap_alloc_range((size_t)module_addr, f.size);
|
||||
fread(&f, module_addr, 0, f.size);
|
||||
|
||||
m->begin = (uint64_t)(size_t)module_addr;
|
||||
m->end = m->begin + f.size;
|
||||
|
||||
top_used_addr = (uint64_t)(size_t)m->end;
|
||||
|
||||
print("stivale2: Requested module %u:\n", i);
|
||||
print(" Path: %s\n", module_file);
|
||||
print(" String: %s\n", m->string);
|
||||
print(" Begin: %X\n", m->begin);
|
||||
print(" End: %X\n", m->end);
|
||||
}
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create RSDP struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_rsdp *tag = balloc(sizeof(struct stivale2_struct_tag_rsdp));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_RSDP_ID;
|
||||
|
||||
tag->rsdp = (uint64_t)(size_t)get_rsdp();
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create cmdline struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_cmdline *tag = balloc(sizeof(struct stivale2_struct_tag_cmdline));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_CMDLINE_ID;
|
||||
|
||||
tag->cmdline = (uint64_t)(size_t)cmdline;
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create epoch struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_epoch *tag = balloc(sizeof(struct stivale2_struct_tag_epoch));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_EPOCH_ID;
|
||||
|
||||
tag->epoch = time();
|
||||
print("stivale2: Current epoch: %U\n", tag->epoch);
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create framebuffer struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_hdr_tag_framebuffer *hdrtag = get_tag(&stivale2_hdr, STIVALE2_HDR_TAG_FRAMEBUFFER_ID);
|
||||
|
||||
if (hdrtag == NULL) {
|
||||
deinit_vga_textmode();
|
||||
} else {
|
||||
struct stivale2_struct_tag_framebuffer *tag = balloc(sizeof(struct stivale2_struct_tag_framebuffer));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID;
|
||||
|
||||
tag->framebuffer_width = hdrtag->framebuffer_width;
|
||||
tag->framebuffer_height = hdrtag->framebuffer_height;
|
||||
tag->framebuffer_bpp = hdrtag->framebuffer_bpp;
|
||||
|
||||
init_vbe(&tag->framebuffer_addr,
|
||||
&tag->framebuffer_pitch,
|
||||
&tag->framebuffer_width,
|
||||
&tag->framebuffer_height,
|
||||
&tag->framebuffer_bpp);
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Create memmap struct tag
|
||||
//////////////////////////////////////////////
|
||||
{
|
||||
struct stivale2_struct_tag_memmap *tag = balloc(sizeof(struct stivale2_struct_tag_memmap));
|
||||
tag->tag.identifier = STIVALE2_STRUCT_TAG_MEMMAP_ID;
|
||||
|
||||
size_t memmap_entries;
|
||||
struct e820_entry_t *memmap = get_memmap(&memmap_entries);
|
||||
|
||||
tag->entries = (uint64_t)memmap_entries;
|
||||
|
||||
void *tag_memmap = balloc(sizeof(struct e820_entry_t) * memmap_entries);
|
||||
memcpy(tag_memmap, memmap, sizeof(struct e820_entry_t) * memmap_entries);
|
||||
|
||||
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
|
||||
}
|
||||
|
||||
// Check if 5-level paging tag is requesting support
|
||||
bool level5pg_requested = get_tag(&stivale2_hdr, STIVALE2_HDR_TAG_5LV_PAGING_ID) ? true : false;
|
||||
|
||||
if (bits == 64) {
|
||||
// If we're going 64, we might as well call this BIOS interrupt
|
||||
// to tell the BIOS that we are entering Long Mode, since it is in
|
||||
// the specification.
|
||||
struct rm_regs r = {0};
|
||||
r.eax = 0xec00;
|
||||
r.ebx = 0x02; // Long mode only
|
||||
rm_int(0x15, &r, &r);
|
||||
}
|
||||
|
||||
rm_flush_irqs();
|
||||
|
||||
if (bits == 64) {
|
||||
void *pagemap_ptr;
|
||||
if (level5pg && level5pg_requested) {
|
||||
// Enable CR4.LA57
|
||||
asm volatile (
|
||||
"mov eax, cr4\n\t"
|
||||
"bts eax, 12\n\t"
|
||||
"mov cr4, eax\n\t"
|
||||
:
|
||||
:
|
||||
: "eax", "memory"
|
||||
);
|
||||
|
||||
struct pagemap {
|
||||
uint64_t pml5[512];
|
||||
uint64_t pml4_lo[512];
|
||||
uint64_t pml4_hi[512];
|
||||
uint64_t pml3_lo[512];
|
||||
uint64_t pml3_hi[512];
|
||||
uint64_t pml2_0gb[512];
|
||||
uint64_t pml2_1gb[512];
|
||||
uint64_t pml2_2gb[512];
|
||||
uint64_t pml2_3gb[512];
|
||||
};
|
||||
struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
|
||||
pagemap_ptr = (void *)pagemap;
|
||||
|
||||
// zero out the pagemap
|
||||
for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
|
||||
*p = 0;
|
||||
|
||||
pagemap->pml5[511] = (uint64_t)(size_t)pagemap->pml4_hi | 0x03;
|
||||
pagemap->pml5[0] = (uint64_t)(size_t)pagemap->pml4_lo | 0x03;
|
||||
pagemap->pml4_hi[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
|
||||
pagemap->pml4_hi[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
|
||||
pagemap->pml4_lo[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
|
||||
pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
|
||||
pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
|
||||
pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
|
||||
pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
|
||||
pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
|
||||
pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
|
||||
|
||||
// populate the page directories
|
||||
for (size_t i = 0; i < 512 * 4; i++)
|
||||
(&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
|
||||
} else {
|
||||
struct pagemap {
|
||||
uint64_t pml4[512];
|
||||
uint64_t pml3_lo[512];
|
||||
uint64_t pml3_hi[512];
|
||||
uint64_t pml2_0gb[512];
|
||||
uint64_t pml2_1gb[512];
|
||||
uint64_t pml2_2gb[512];
|
||||
uint64_t pml2_3gb[512];
|
||||
};
|
||||
struct pagemap *pagemap = balloc_aligned(sizeof(struct pagemap), 0x1000);
|
||||
pagemap_ptr = (void *)pagemap;
|
||||
|
||||
// zero out the pagemap
|
||||
for (uint64_t *p = (uint64_t *)pagemap; p < &pagemap->pml3_hi[512]; p++)
|
||||
*p = 0;
|
||||
|
||||
pagemap->pml4[511] = (uint64_t)(size_t)pagemap->pml3_hi | 0x03;
|
||||
pagemap->pml4[256] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
|
||||
pagemap->pml4[0] = (uint64_t)(size_t)pagemap->pml3_lo | 0x03;
|
||||
pagemap->pml3_hi[510] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
|
||||
pagemap->pml3_hi[511] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
|
||||
pagemap->pml3_lo[0] = (uint64_t)(size_t)pagemap->pml2_0gb | 0x03;
|
||||
pagemap->pml3_lo[1] = (uint64_t)(size_t)pagemap->pml2_1gb | 0x03;
|
||||
pagemap->pml3_lo[2] = (uint64_t)(size_t)pagemap->pml2_2gb | 0x03;
|
||||
pagemap->pml3_lo[3] = (uint64_t)(size_t)pagemap->pml2_3gb | 0x03;
|
||||
|
||||
// populate the page directories
|
||||
for (size_t i = 0; i < 512 * 4; i++)
|
||||
(&pagemap->pml2_0gb[0])[i] = (i * 0x200000) | 0x03 | (1 << 7);
|
||||
}
|
||||
|
||||
asm volatile (
|
||||
"cli\n\t"
|
||||
"cld\n\t"
|
||||
"mov cr3, eax\n\t"
|
||||
"mov eax, cr4\n\t"
|
||||
"or eax, 1 << 5\n\t"
|
||||
"mov cr4, eax\n\t"
|
||||
"mov ecx, 0xc0000080\n\t"
|
||||
"rdmsr\n\t"
|
||||
"or eax, 1 << 8\n\t"
|
||||
"wrmsr\n\t"
|
||||
"mov eax, cr0\n\t"
|
||||
"or eax, 1 << 31\n\t"
|
||||
"mov cr0, eax\n\t"
|
||||
"jmp 0x28:1f\n\t"
|
||||
"1: .code64\n\t"
|
||||
"mov ax, 0x30\n\t"
|
||||
"mov ds, ax\n\t"
|
||||
"mov es, ax\n\t"
|
||||
"mov fs, ax\n\t"
|
||||
"mov gs, ax\n\t"
|
||||
"mov ss, ax\n\t"
|
||||
|
||||
"push 0x30\n\t"
|
||||
"push [rsi]\n\t"
|
||||
"pushfq\n\t"
|
||||
"push 0x28\n\t"
|
||||
"push [rbx]\n\t"
|
||||
|
||||
"xor rax, rax\n\t"
|
||||
"xor rbx, rbx\n\t"
|
||||
"xor rcx, rcx\n\t"
|
||||
"xor rdx, rdx\n\t"
|
||||
"xor rsi, rsi\n\t"
|
||||
"xor rbp, rbp\n\t"
|
||||
"xor r8, r8\n\t"
|
||||
"xor r9, r9\n\t"
|
||||
"xor r10, r10\n\t"
|
||||
"xor r11, r11\n\t"
|
||||
"xor r12, r12\n\t"
|
||||
"xor r13, r13\n\t"
|
||||
"xor r14, r14\n\t"
|
||||
"xor r15, r15\n\t"
|
||||
|
||||
"iretq\n\t"
|
||||
".code32\n\t"
|
||||
:
|
||||
: "a" (pagemap_ptr), "b" (&entry_point),
|
||||
"D" (&stivale2_struct), "S" (&stivale2_hdr.stack)
|
||||
: "memory"
|
||||
);
|
||||
} else if (bits == 32) {
|
||||
asm volatile (
|
||||
"cli\n\t"
|
||||
"cld\n\t"
|
||||
|
||||
"sub esp, 4\n\t"
|
||||
"mov [esp], edi\n\t"
|
||||
|
||||
"push 0x20\n\t"
|
||||
"push [esi]\n\t"
|
||||
"pushfd\n\t"
|
||||
"push 0x18\n\t"
|
||||
"push [ebx]\n\t"
|
||||
|
||||
"xor eax, eax\n\t"
|
||||
"xor ebx, ebx\n\t"
|
||||
"xor ecx, ecx\n\t"
|
||||
"xor edx, edx\n\t"
|
||||
"xor esi, esi\n\t"
|
||||
"xor edi, edi\n\t"
|
||||
"xor ebp, ebp\n\t"
|
||||
|
||||
"iret\n\t"
|
||||
:
|
||||
: "b" (&entry_point), "D" (&stivale2_struct), "S" (&stivale2_hdr.stack)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
}
|
6
src/protos/stivale2.h
Normal file
6
src/protos/stivale2.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __PROTOS__STIVALE2_H__
|
||||
#define __PROTOS__STIVALE2_H__
|
||||
|
||||
void stivale2_load(char *cmdline, int boot_drive);
|
||||
|
||||
#endif
|
6
src/qloader2.h
Normal file
6
src/qloader2.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __QLOADER2_H__
|
||||
#define __QLOADER2_H__
|
||||
|
||||
#define QLOADER2_VERSION "0.4"
|
||||
|
||||
#endif
|
@ -2,7 +2,7 @@ TIMEOUT=3
|
||||
|
||||
:Test kernel
|
||||
|
||||
PROTOCOL=stivale
|
||||
PROTOCOL=stivale2
|
||||
|
||||
KERNEL_PARTITION=0
|
||||
KERNEL_PATH=boot/test.elf
|
||||
|
@ -1,15 +1,13 @@
|
||||
; This is a compliant "kernel" meant for testing purposes.
|
||||
|
||||
; Header
|
||||
section .stivalehdr
|
||||
section .stivale2hdr
|
||||
|
||||
stivale_header:
|
||||
dq stack.top ; rsp
|
||||
dw 0 ; video mode
|
||||
dw 0 ; fb_width
|
||||
dw 0 ; fb_height
|
||||
dw 0 ; fb_bpp
|
||||
dq 0
|
||||
dq 0 ; entry point
|
||||
dq stack.top ; rsp
|
||||
dq 0 ; flags
|
||||
dq 0 ; tags
|
||||
|
||||
section .bss
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user