Compare commits
29 Commits
v5.x-branc
...
v1.0-branc
Author | SHA1 | Date | |
---|---|---|---|
|
49b6c1e472 | ||
|
2cfa5b281a | ||
|
7c4f71e532 | ||
|
d62e9a49a5 | ||
|
361fb431a5 | ||
|
611914b138 | ||
|
9504dc6da7 | ||
|
767be2c09c | ||
|
33058217fa | ||
|
5ed2c2203a | ||
|
8c76a0f406 | ||
|
0c12e2f4da | ||
|
6db8694d7f | ||
|
af31ba949b | ||
|
07887dcc4c | ||
|
02ef011f8e | ||
|
beb688d8ca | ||
|
c91e96f3e5 | ||
|
94c56a030b | ||
|
fbdd709ba6 | ||
|
cde4a592f3 | ||
|
638e7bf867 | ||
|
63ea645359 | ||
|
fdc89f7631 | ||
|
0c6baf3591 | ||
|
721bedbcc9 | ||
|
f527896a2b | ||
|
996f2d60bf | ||
|
406477acaa |
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@
|
||||
!/limine.bin
|
||||
!/limine-pxe.bin
|
||||
!/stage2.map
|
||||
/stivale
|
||||
|
9
Makefile
9
Makefile
@ -14,7 +14,7 @@ limine-install: limine-install.c limine.o
|
||||
$(CC) $(CFLAGS) -std=c11 limine.o limine-install.c -o limine-install
|
||||
|
||||
limine.o: limine.bin
|
||||
$(OBJCOPY) -I binary -O default limine.bin limine.o
|
||||
$(OBJCOPY) -B i8086 -I binary -O default limine.bin limine.o
|
||||
|
||||
clean:
|
||||
rm -f limine.o limine-install
|
||||
@ -33,8 +33,13 @@ bootloader-clean: stage2-clean decompressor-clean test-clean
|
||||
rm -f stage2/stage2.bin.gz test/stage2.map test.hdd
|
||||
|
||||
distclean: clean bootloader-clean
|
||||
rm -rf stivale
|
||||
|
||||
stage2:
|
||||
stivale:
|
||||
git clone https://github.com/stivale/stivale.git
|
||||
cd stivale && git checkout d0a7ca5642d89654f8d688c2481c2771a8653c99
|
||||
|
||||
stage2: stivale
|
||||
$(MAKE) -C stage2 all
|
||||
|
||||
stage2-clean:
|
||||
|
14
README.md
14
README.md
@ -32,13 +32,21 @@ you have a *very* good reason to.
|
||||
The `unstable` branch is unstable, and non-backwards compatible changes are made to it
|
||||
routinely.
|
||||
|
||||
Use instead a [release](https://github.com/limine-bootloader/limine/releases).
|
||||
Use instead a [release](https://github.com/limine-bootloader/limine/releases), or a [release branch](https://github.com/limine-bootloader/limine/branches) (like v1.0-branch).
|
||||
|
||||
Following a release offers a fixed point, immutable snapshot of Limine, while following a release branch tracks the latest changes made to that major release's branch which do not break compatibility (but could break in other, non-obvious ways).
|
||||
|
||||
One can clone a release directly using
|
||||
```bash
|
||||
git clone https://github.com/limine-bootloader/limine.git --branch=v0.7.2
|
||||
git clone https://github.com/limine-bootloader/limine.git --branch=v1.0
|
||||
```
|
||||
(replace `v0.7.2` with the chosen release)
|
||||
(replace `v1.0` with the chosen release)
|
||||
|
||||
or a release branch with
|
||||
```bash
|
||||
git clone https://github.com/limine-bootloader/limine.git --branch=v1.0-branch
|
||||
```
|
||||
(replace `v1.0-branch` with the chosen release branch)
|
||||
|
||||
Also note that the documentation contained in `unstable` does not reflect the
|
||||
documentation for the specific releases, and one should refer to the releases'
|
||||
|
249
STIVALE.md
249
STIVALE.md
@ -1,248 +1 @@
|
||||
# stivale boot protocol specification
|
||||
|
||||
The stivale boot protocol aims to be a *simple* to implement protocol which
|
||||
provides the kernel with most of the features one may need in a *modern*
|
||||
x86_64 context (although 32-bit x86 is also supported).
|
||||
|
||||
## General information
|
||||
|
||||
In order to have a stivale compliant kernel, one must have a kernel executable
|
||||
in the `elf64` or `elf32` format and have a `.stivalehdr` section (described below).
|
||||
Other executable formats are not supported.
|
||||
|
||||
stivale will recognise whether the ELF file is 32-bit or 64-bit and load the kernel
|
||||
into the appropriate CPU mode.
|
||||
|
||||
stivale natively supports (only for 64-bit kernels) and encourages higher half kernels.
|
||||
The kernel can load itself at `0xffffffff80000000` (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, the bootloader will not perform the
|
||||
higher half relocation.
|
||||
|
||||
*Note: In order to maintain compatibility with Limine and other stivale-compliant*
|
||||
*bootloaders it is strongly advised never to load the kernel or any of its*
|
||||
*sections below the 1 MiB physical memory mark. This may work with some stivale*
|
||||
*loaders, but it WILL NOT work with Limine and it's explicitly discouraged.*
|
||||
|
||||
## Kernel entry machine state
|
||||
|
||||
### 64-bit kernel
|
||||
|
||||
`rip` will be the entry point as defined in the ELF file, unless the `entry_point`
|
||||
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 mappings as such:
|
||||
|
||||
```
|
||||
Base Physical Address - Size -> Virtual address
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0x0000000000000000
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0xffff800000000000 (4-level paging only)
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0xff00000000000000 (5-level paging only)
|
||||
0x0000000000000000 - 0x80000000 -> 0xffffffff80000000
|
||||
```
|
||||
|
||||
If the kernel is dynamic and not statically linked, the bootloader will relocate it,
|
||||
potentially performing KASLR (as specified by the config).
|
||||
|
||||
The kernel should NOT modify the bootloader page tables, and it should only use them
|
||||
to bootstrap its own virtual memory manager and its own page tables.
|
||||
|
||||
At entry all segment registers are loaded as 64 bit code/data segments, limits and
|
||||
bases are ignored since this is Long Mode.
|
||||
|
||||
DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load
|
||||
its own GDT as soon as possible and not rely on the bootloader's.
|
||||
|
||||
The IDT is in an undefined state. Kernel must load its own.
|
||||
|
||||
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`).
|
||||
|
||||
The A20 gate is enabled.
|
||||
|
||||
PIC/APIC IRQs are all masked.
|
||||
|
||||
`rsp` is set to the requested stack as per stivale header. If the requested value is
|
||||
non-null, an invalid return address of 0 is pushed to the stack before jumping
|
||||
to the kernel.
|
||||
|
||||
`rdi` will point to the stivale structure (described below).
|
||||
|
||||
All other general purpose registers are set to 0.
|
||||
|
||||
### 32-bit kernel
|
||||
|
||||
`eip` will be the entry point as defined in the ELF file, unless the `entry_point`
|
||||
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 all segment registers are loaded as 32 bit code/data segments.
|
||||
All segment bases are `0x00000000` and all limits are `0xffffffff`.
|
||||
|
||||
DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load
|
||||
its own GDT as soon as possible and not rely on the bootloader's.
|
||||
|
||||
The IDT is in an undefined state. Kernel must load its own.
|
||||
|
||||
IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined.
|
||||
|
||||
PE is enabled (`cr0`).
|
||||
|
||||
The A20 gate is enabled.
|
||||
|
||||
PIC/APIC IRQs are all masked.
|
||||
|
||||
`esp` is set to the requested stack as per stivale header. An invalid return address
|
||||
of 0 is pushed to the stack before jumping to the kernel.
|
||||
|
||||
A pointer to the stivale structure (described below) is pushed onto this stack
|
||||
before the entry point is called.
|
||||
|
||||
All other general purpose registers are set to 0.
|
||||
|
||||
## Bootloader-reserved memory
|
||||
|
||||
In order for stivale to function, it needs to reserve memory areas for either internal
|
||||
usage (such as page tables, GDT), or for kernel interfacing (such as returned
|
||||
structures).
|
||||
|
||||
stivale ensures that none of these areas are found in any of the sections
|
||||
marked as "usable" or "kernel/modules" in the memory map.
|
||||
|
||||
The location of these areas may vary and it is implementation specific;
|
||||
these areas may be in any non-usable memory map section (except kernel/modules),
|
||||
or in unmarked memory.
|
||||
|
||||
The OS must make sure to be done consuming bootloader information and services
|
||||
before switching to its own address space, as unmarked memory areas in use by
|
||||
the bootloader may become unavailable.
|
||||
|
||||
Once the OS is done needing the bootloader, memory map areas marked as "bootloader
|
||||
reclaimable" may be used as usable memory. These areas are guaranteed to be
|
||||
4096-byte aligned (both base and length), and they are guaranteed to not overlap
|
||||
other sections of the memory map.
|
||||
|
||||
## stivale header (.stivalehdr)
|
||||
|
||||
The kernel executable shall have a section `.stivalehdr` which will contain
|
||||
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 ESP/RSP
|
||||
// when the kernel is loaded.
|
||||
// It can only be set to NULL for 64-bit kernels. 32-bit
|
||||
// kernels are mandated to provide a vaild stack.
|
||||
// 64-bit and 32-bit valid stacks must be at least 256 bytes
|
||||
// in usable space and must be 16 byte aligned addresses.
|
||||
|
||||
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 Formerly used to indicate whether to enable KASLR,
|
||||
// this flag is now reserved as KASLR is enabled in the
|
||||
// bootloader configuration instead. Presently
|
||||
// reserved and unused.
|
||||
// All other bits are undefined and must be 0.
|
||||
|
||||
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.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
## 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
|
||||
// bit 1: 1 if extended colour information passed, 0 if not
|
||||
// All other bits are undefined and set to 0.
|
||||
// Extended colour information follows, only access if bit 1 of flags is set.
|
||||
uint8_t fb_memory_model; // Memory model: 1=RGB, all other values undefined
|
||||
uint8_t fb_red_mask_size; // RGB mask sizes and left shifts
|
||||
uint8_t fb_red_mask_shift;
|
||||
uint8_t fb_green_mask_size;
|
||||
uint8_t fb_green_mask_shift;
|
||||
uint8_t fb_blue_mask_size;
|
||||
uint8_t fb_blue_mask_shift;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
## Memory map entry
|
||||
|
||||
```c
|
||||
struct mmap_entry {
|
||||
uint64_t base; // Base of the memory section
|
||||
uint64_t length; // Length of the section
|
||||
uint32_t type; // Type (described below)
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
`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
|
||||
0x1000 - Bootloader Reclaimable
|
||||
```
|
||||
|
||||
All other values are undefined.
|
||||
|
||||
The kernel and modules loaded **are not** marked as usable memory. They are marked
|
||||
as Kernel/Modules (type 10).
|
||||
|
||||
The entries are guaranteed to be sorted by base address, lowest to highest.
|
||||
|
||||
Usable and bootloader reclaimable entries are guaranteed to be 4096 byte aligned for both base and length.
|
||||
|
||||
Usable and bootloader reclaimable entries are guaranteed not to overlap with any other entry.
|
||||
|
||||
To the contrary, all non-usable entries (including kernel/modules) are not guaranteed any alignment, nor
|
||||
is it guaranteed that they do not overlap other entries (except usable and bootloader reclaimable entries).
|
||||
|
||||
## Modules
|
||||
|
||||
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
|
||||
} __attribute__((packed));
|
||||
```
|
||||
stivale documentation has been moved to https://github.com/stivale/stivale/blob/master/STIVALE.md
|
||||
|
523
STIVALE2.md
523
STIVALE2.md
@ -1,522 +1 @@
|
||||
# stivale2 boot protocol specification
|
||||
|
||||
The stivale2 boot protocol is an improved version of the stivale protocol which
|
||||
provides the kernel with most of the features one may need in a *modern*
|
||||
x86_64 context (although 32-bit x86 is also supported).
|
||||
|
||||
## General information
|
||||
|
||||
In order to have a stivale2 compliant kernel, one must have a kernel executable
|
||||
in the `elf64` or `elf32` format and have a `.stivale2hdr` section (described below).
|
||||
Other executable formats are not supported.
|
||||
|
||||
stivale2 will recognise whether the ELF file is 32-bit or 64-bit and load the kernel
|
||||
into the appropriate CPU mode.
|
||||
|
||||
stivale2 natively supports (only for 64-bit kernels) and encourages higher half kernels.
|
||||
The kernel can load itself at `0xffffffff80000000` 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, the bootloader will not perform the
|
||||
higher half relocation.
|
||||
|
||||
*Note: In order to maintain compatibility with Limine and other stivale2-compliant*
|
||||
*bootloaders it is strongly advised never to load the kernel or any of its*
|
||||
*sections below the 1 MiB physical memory mark. This may work with some stivale2*
|
||||
*loaders, but it WILL NOT work with Limine and it's explicitly discouraged.*
|
||||
|
||||
## Kernel entry machine state
|
||||
|
||||
### 64-bit kernel
|
||||
|
||||
`rip` will be the entry point as defined in the ELF file, unless the `entry_point`
|
||||
field in the stivale2 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 mappings as such:
|
||||
|
||||
```
|
||||
Base Physical Address - Size -> Virtual address
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0x0000000000000000
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0xffff800000000000 (4-level paging only)
|
||||
0x0000000000000000 - 4 GiB plus any additional memory map entry -> 0xff00000000000000 (5-level paging only)
|
||||
0x0000000000000000 - 0x80000000 -> 0xffffffff80000000
|
||||
```
|
||||
|
||||
If the kernel is dynamic and not statically linked, the bootloader will relocate it,
|
||||
potentially performing KASLR (as specified by the config).
|
||||
|
||||
The kernel should NOT modify the bootloader page tables, and it should only use them
|
||||
to bootstrap its own virtual memory manager and its own page tables.
|
||||
|
||||
At entry all segment registers are loaded as 64 bit code/data segments, limits and
|
||||
bases are ignored since this is Long Mode.
|
||||
|
||||
DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load
|
||||
its own GDT as soon as possible and not rely on the bootloader's.
|
||||
|
||||
The IDT is in an undefined state. Kernel must load its own.
|
||||
|
||||
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 the stivale2 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.
|
||||
|
||||
PIC/APIC IRQs are all masked.
|
||||
|
||||
`rsp` is set to the requested stack as per stivale2 header. If the requested value is
|
||||
non-null, an invalid return address of 0 is pushed to the stack before jumping
|
||||
to the kernel.
|
||||
|
||||
`rdi` will point to the stivale2 structure (described below).
|
||||
|
||||
All other general purpose registers are set to 0.
|
||||
|
||||
### 32-bit kernel
|
||||
|
||||
`eip` will be the entry point as defined in the ELF file, unless the `entry_point`
|
||||
field in the stivale2 header is set to a non-0 value, in which case, it is set to
|
||||
the value of `entry_point`.
|
||||
|
||||
At entry all segment registers are loaded as 32 bit code/data segments.
|
||||
All segment bases are `0x00000000` and all limits are `0xffffffff`.
|
||||
|
||||
DO NOT reload segment registers or rely on the provided GDT. The kernel MUST load
|
||||
its own GDT as soon as possible and not rely on the bootloader's.
|
||||
|
||||
The IDT is in an undefined state. Kernel must load its own.
|
||||
|
||||
IF flag, VM flag, and direction flag are cleared on entry. Other flags undefined.
|
||||
|
||||
PE is enabled (`cr0`).
|
||||
|
||||
The A20 gate is enabled.
|
||||
|
||||
PIC/APIC IRQs are all masked.
|
||||
|
||||
`esp` is set to the requested stack as per stivale2 header. An invalid return address
|
||||
of 0 is pushed to the stack before jumping to the kernel.
|
||||
|
||||
A pointer to the stivale2 structure (described below) is pushed onto this stack
|
||||
before the entry point is called.
|
||||
|
||||
All other general purpose registers are set to 0.
|
||||
|
||||
## Bootloader-reserved memory
|
||||
|
||||
In order for stivale2 to function, it needs to reserve memory areas for either internal
|
||||
usage (such as page tables, GDT, SMP), or for kernel interfacing (such as returned
|
||||
structures).
|
||||
|
||||
stivale2 ensures that none of these areas are found in any of the sections
|
||||
marked as "usable" or "kernel/modules" in the memory map.
|
||||
|
||||
The location of these areas may vary and it is implementation specific;
|
||||
these areas may be in any non-usable memory map section (except kernel/modules),
|
||||
or in unmarked memory.
|
||||
|
||||
The OS must make sure to be done consuming bootloader information and services
|
||||
before switching to its own address space, as unmarked memory areas in use by
|
||||
the bootloader may become unavailable.
|
||||
|
||||
Once the OS is done needing the bootloader, memory map areas marked as "bootloader
|
||||
reclaimable" may be used as usable memory. These areas are guaranteed to be
|
||||
4096-byte aligned (both base and length), and they are guaranteed to not overlap
|
||||
other sections of the memory map.
|
||||
|
||||
## stivale2 header (.stivale2hdr)
|
||||
|
||||
The kernel executable shall have a section `.stivale2hdr` which will contain
|
||||
the header that the bootloader will parse.
|
||||
|
||||
Said header looks like this:
|
||||
```c
|
||||
struct stivale2_header {
|
||||
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.
|
||||
|
||||
uint64_t stack; // This is the stack address which will be in ESP/RSP
|
||||
// when the kernel is loaded.
|
||||
// It can only be set to NULL for 64-bit kernels. 32-bit
|
||||
// kernels are mandated to provide a vaild stack.
|
||||
// 64-bit and 32-bit valid stacks must be at least 256 bytes
|
||||
// in usable space and must be 16 byte aligned addresses.
|
||||
|
||||
uint64_t flags; // Bit 0: Formerly used to indicate whether to enable
|
||||
// KASLR, this flag is now reserved as KASLR
|
||||
// is enabled in the bootloader configuration
|
||||
// instead. Presently reserved and unused.
|
||||
// All other bits are undefined and must be 0.
|
||||
|
||||
uint64_t tags; // Pointer to the first of the linked list of tags.
|
||||
// see "stivale2 header tags" section.
|
||||
// NULL = no tags.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
### stivale2 header tags
|
||||
|
||||
The stivale2 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 stivale2 header.
|
||||
|
||||
The bootloader is free to ignore kernel tags that it does not recognise.
|
||||
The kernel should make sure that the bootloader has properly interpreted the
|
||||
provided tags, either by checking returned tags or by other means.
|
||||
|
||||
Each tag shall contain these 2 fields:
|
||||
```c
|
||||
struct stivale2_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 stivale2-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 stivale2_header_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));
|
||||
```
|
||||
|
||||
#### Framebuffer MTRR write-combining header tag
|
||||
|
||||
The presence of this tag tells the bootloader to, in case a framebuffer was
|
||||
requested, make that framebuffer's caching type write-combining using x86's
|
||||
MTRR model specific registers. This caching type helps speed up framebuffer writes
|
||||
on real hardware.
|
||||
|
||||
It is recommended to use this tag in conjunction with the SMP tag in order to
|
||||
let the bootloader make the MTRR settings uniform across all CPUs.
|
||||
|
||||
If no framebuffer was requested, this tag has no effect.
|
||||
|
||||
Identifier: `0x4c7bb07731282e00`
|
||||
|
||||
This tag does not have extra members.
|
||||
|
||||
#### 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.
|
||||
|
||||
#### SMP header tag
|
||||
|
||||
The presence of this tag enables support for booting up application processors.
|
||||
|
||||
```c
|
||||
struct stivale2_header_tag_smp {
|
||||
uint64_t identifier; // Identifier: 0x1ab015085f3273df
|
||||
uint64_t next;
|
||||
uint64_t flags; // Flags:
|
||||
// bit 0: 0 = use xAPIC, 1 = use x2APIC (if available)
|
||||
// All other bits are undefined and must be 0.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
## stivale2 structure
|
||||
|
||||
The stivale2 structure returned by the bootloader looks like this:
|
||||
```c
|
||||
struct stivale2_struct {
|
||||
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 "stivale2 structure tags" section.
|
||||
// NULL = no tags.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
### stivale2 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 "stivale2 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 stivale2_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 stivale2_struct_tag_memmap {
|
||||
uint64_t identifier; // Identifier: 0x2187f79e8612de07
|
||||
uint64_t next;
|
||||
uint64_t entries; // Count of memory map entries
|
||||
struct stivale2_mmap_entry memmap[]; // Array of memory map entries
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
###### Memory map entry
|
||||
|
||||
```c
|
||||
struct stivale2_mmap_entry {
|
||||
uint64_t base; // Base of the memory section
|
||||
uint64_t length; // Length of the section
|
||||
enum stivale2_mmap_type type; // Type (described below)
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
`type` is an enumeration that can have the following values:
|
||||
|
||||
```
|
||||
enum stivale2_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 0x1001).
|
||||
|
||||
The entries are guaranteed to be sorted by base address, lowest to highest.
|
||||
|
||||
Usable and bootloader reclaimable entries are guaranteed to be 4096 byte aligned for both base and length.
|
||||
|
||||
Usable and bootloader reclaimable entries are guaranteed not to overlap with any other entry.
|
||||
|
||||
To the contrary, all non-usable entries (including kernel/modules) are not guaranteed any alignment, nor
|
||||
is it guaranteed that they do not overlap other entries (except usable and bootloader reclaimable entries).
|
||||
|
||||
#### Framebuffer structure tag
|
||||
|
||||
This tag reports to the kernel the currently set up framebuffer details, if any.
|
||||
|
||||
```c
|
||||
struct stivale2_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; // Width and height in pixels
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_pitch; // Pitch in bytes
|
||||
uint16_t framebuffer_bpp; // Bits per pixel
|
||||
uint8_t memory_model; // Memory model: 1=RGB, all other values undefined
|
||||
uint8_t red_mask_size; // RGB mask sizes and left shifts
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Framebuffer MTRR write-combining structure tag
|
||||
|
||||
This tag exists if MTRR write-combining for the framebuffer was requested and
|
||||
successfully enabled.
|
||||
|
||||
Identifier: `0x6bc1a78ebe871172`
|
||||
|
||||
This tag does not have extra members.
|
||||
|
||||
#### Modules structure tag
|
||||
|
||||
This tag lists modules that the bootloader loaded alongside the kernel, if any.
|
||||
|
||||
```c
|
||||
struct stivale2_struct_tag_modules {
|
||||
uint64_t identifier; // Identifier: 0x4b6fe466aade04ce
|
||||
uint64_t next;
|
||||
uint64_t module_count; // Count of loaded modules
|
||||
struct stivale2_module modules[]; // Array of module descriptors
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
```c
|
||||
struct stivale2_module {
|
||||
uint64_t begin; // Address where the module is loaded
|
||||
uint64_t end; // End address of the module
|
||||
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 stivale2_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 stivale2_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 stivale2_struct_tag_firmware {
|
||||
uint64_t identifier; // Identifier: 0x359d837855e3858c
|
||||
uint64_t next;
|
||||
uint64_t flags; // Bit 0: 0 = UEFI, 1 = BIOS
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### SMP structure tag
|
||||
|
||||
This tag reports to the kernel info about a multiprocessor environment.
|
||||
|
||||
```c
|
||||
struct stivale2_struct_tag_smp {
|
||||
uint64_t identifier; // Identifier: 0x34d1d96339647025
|
||||
uint64_t next;
|
||||
uint64_t flags; // Flags:
|
||||
// bit 0: Set if x2APIC was requested and it
|
||||
// was supported and enabled.
|
||||
// All other bits are undefined and set to 0.
|
||||
uint32_t bsp_lapic_id; // LAPIC ID of the BSP (bootstrap processor).
|
||||
uint32_t unused; // Reserved for future use.
|
||||
uint64_t cpu_count; // Total number of logical CPUs (including BSP)
|
||||
struct stivale2_smp_info smp_info[]; // Array of smp_info structs, one per
|
||||
// logical processor, including BSP.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
```c
|
||||
struct stivale2_smp_info {
|
||||
uint32_t acpi_processor_uid; // ACPI Processor UID as specified by MADT
|
||||
uint32_t lapic_id; // LAPIC ID as specified by MADT
|
||||
uint64_t target_stack; // The stack that will be loaded in ESP/RSP
|
||||
// once the goto_address field is loaded.
|
||||
// This MUST point to a valid stack of at least
|
||||
// 256 bytes in size, and 16-byte aligned.
|
||||
// target_stack is an unused field for the
|
||||
// struct describing the BSP (lapic_id == 0)
|
||||
uint64_t goto_address; // This address is polled by the started APs
|
||||
// until the kernel on another CPU performs an
|
||||
// atomic write to this field.
|
||||
// When that happens, bootloader code will
|
||||
// load up ESP/RSP with the stack value as
|
||||
// specified in target_stack.
|
||||
// It will then proceed to load a pointer to
|
||||
// this very structure into either register
|
||||
// RDI for 64-bit or on the stack for 32-bit,
|
||||
// then, goto_address is called (a bogus return
|
||||
// address is pushed onto the stack) and execution
|
||||
// is handed off.
|
||||
// The CPU state will be the same as described
|
||||
// in kernel entry machine state, with the exception
|
||||
// of ESP/RSP and RDI/stack arg being set up as
|
||||
// above.
|
||||
// goto_address is an unused field for the
|
||||
// struct describing the BSP.
|
||||
uint64_t extra_argument; // This field is here for the kernel to use
|
||||
// for whatever it wants. Writes here should
|
||||
// be performed before writing to goto_address
|
||||
// so that the receiving processor can safely
|
||||
// retrieve the data.
|
||||
// extra_argument is an unused field for the
|
||||
// struct describing the BSP.
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### PXE server info structure tag
|
||||
|
||||
This tag reports that the kernel has been booted via PXE, and reports the server ip that it was booted from.
|
||||
|
||||
```c
|
||||
struct stivale2_struct_tag_pxe_server_info {
|
||||
struct stivale2_tag tag; // Identifier: 0x29d1e96239247032
|
||||
uint32_t server_ip; // Server ip in network byte order
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### MMIO32 UART tag
|
||||
|
||||
This tag reports that there is a memory mapped UART port and its address. To write to this port, write the character, zero extended to a 32 bit unsigned integer to the address provided.
|
||||
|
||||
```c
|
||||
struct stivale2_struct_tag_mmio32_uart {
|
||||
uint64_t identifier; // Identifier: 0xb813f9b8dbc78797
|
||||
uint64_t next;
|
||||
uint64_t addr; // The address of the UART port
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
#### Device tree blob tag
|
||||
|
||||
This tag describes a device tree blob for the platform.
|
||||
|
||||
```c
|
||||
struct stivale2_struct_tag_dtb {
|
||||
uint64_t identifier; // Identifier: 0xabb29bd49a2833fa
|
||||
uint64_t next;
|
||||
uint64_t addr; // The address of the dtb
|
||||
uint64_t size; // The size of the dtb
|
||||
} __attribute__((packed));
|
||||
```
|
||||
stivale2 documentation has been moved to https://github.com/stivale/stivale/blob/master/STIVALE2.md
|
||||
|
@ -55,7 +55,7 @@ read_sectors:
|
||||
; EBP:EAX address to EAX LBA sector
|
||||
div ebp
|
||||
mov dword [si+8], eax
|
||||
mov dword [si+12], edx
|
||||
mov dword [si+12], 0
|
||||
|
||||
pop dx
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b))
|
||||
|
||||
struct gpt_table_header {
|
||||
// the head
|
||||
char signature[8];
|
||||
@ -273,7 +275,7 @@ int main(int argc, char *argv[]) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (argc > 1 && strstr("limine.bin", argv[1]) != NULL) {
|
||||
if (argc > 1 && strstr(argv[1], "limine.bin") != NULL) {
|
||||
fprintf(stderr,
|
||||
"WARNING: Passing the bootloader binary as a file argument is\n"
|
||||
" deprecated and should be avoided in the future.\n");
|
||||
@ -300,7 +302,7 @@ int main(int argc, char *argv[]) {
|
||||
int gpt = 0;
|
||||
struct gpt_table_header gpt_header;
|
||||
uint64_t lb_guesses[] = { 512, 4096 };
|
||||
uint64_t lb_size;
|
||||
uint64_t lb_size = 0;
|
||||
for (size_t i = 0; i < sizeof(lb_guesses) / sizeof(uint64_t); i++) {
|
||||
device_read(&gpt_header, lb_guesses[i], sizeof(struct gpt_table_header));
|
||||
if (!strncmp(gpt_header.signature, "EFI PART", 8)) {
|
||||
@ -327,19 +329,20 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
size_t stage2_size = bootloader_file_size - 512;
|
||||
uint16_t stage2_size_a = stage2_size / 2 + stage2_size % 2;
|
||||
uint16_t stage2_size_b = stage2_size / 2;
|
||||
|
||||
size_t stage2_sects = DIV_ROUNDUP(stage2_size, 512);
|
||||
|
||||
uint16_t stage2_size_a = (stage2_sects / 2) * 512 + (stage2_sects % 2 ? 512 : 0);
|
||||
uint16_t stage2_size_b = (stage2_sects / 2) * 512;
|
||||
|
||||
// Default split of stage2 for MBR (consecutive in post MBR gap)
|
||||
uint64_t stage2_loc_a = 512;
|
||||
uint64_t stage2_loc_b = stage2_loc_a + stage2_size_a;
|
||||
if (stage2_loc_b & (512 - 1))
|
||||
stage2_loc_b = (stage2_loc_b + 512) & ~(512 - 1);
|
||||
|
||||
if (gpt) {
|
||||
if (argc > 3) {
|
||||
uint32_t partition_num;
|
||||
sscanf(argv[3], "%" SCNu32, &partition_num);
|
||||
sscanf(argv[2], "%" SCNu32, &partition_num);
|
||||
partition_num--;
|
||||
if (partition_num > gpt_header.number_of_partition_entries) {
|
||||
fprintf(stderr, "ERROR: Partition number is too large.\n");
|
||||
@ -457,7 +460,7 @@ int main(int argc, char *argv[]) {
|
||||
// Write the rest of stage 2 to the device
|
||||
device_write(&bootloader_img[512], stage2_loc_a, stage2_size_a);
|
||||
device_write(&bootloader_img[512 + stage2_size_a],
|
||||
stage2_loc_b, stage2_size_b);
|
||||
stage2_loc_b, stage2_size - stage2_size_a);
|
||||
|
||||
// Hardcode in the bootsector the location of stage 2 halves
|
||||
device_write(&stage2_size_a, 0x1a4 + 0, sizeof(uint16_t));
|
||||
|
BIN
limine-pxe.bin
BIN
limine-pxe.bin
Binary file not shown.
BIN
limine.bin
BIN
limine.bin
Binary file not shown.
BIN
stage2.map
BIN
stage2.map
Binary file not shown.
@ -12,6 +12,9 @@
|
||||
|
||||
#define CACHE_INVALID (~((uint64_t)0))
|
||||
|
||||
#define MAX_CACHE 16384
|
||||
|
||||
static int cached_drive = -1;
|
||||
static uint8_t *cache = NULL;
|
||||
static uint64_t cached_block = CACHE_INVALID;
|
||||
|
||||
@ -26,7 +29,7 @@ struct dap {
|
||||
static struct dap *dap = NULL;
|
||||
|
||||
static int cache_block(int drive, uint64_t block, int sector_size) {
|
||||
if (block == cached_block)
|
||||
if (drive == cached_drive && block == cached_block)
|
||||
return 0;
|
||||
|
||||
if (!dap) {
|
||||
@ -36,7 +39,10 @@ static int cache_block(int drive, uint64_t block, int sector_size) {
|
||||
}
|
||||
|
||||
if (!cache)
|
||||
cache = conv_mem_alloc_aligned(BLOCK_SIZE, 16);
|
||||
cache = conv_mem_alloc_aligned(MAX_CACHE, 16);
|
||||
|
||||
if (BLOCK_SIZE > MAX_CACHE)
|
||||
panic("Disk cache overflow");
|
||||
|
||||
dap->segment = rm_seg(cache);
|
||||
dap->offset = rm_off(cache);
|
||||
@ -56,6 +62,7 @@ static int cache_block(int drive, uint64_t block, int sector_size) {
|
||||
}
|
||||
|
||||
cached_block = block;
|
||||
cached_drive = drive;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -95,17 +95,13 @@ static int fat32_init_context(struct fat32_context* context, struct part *part)
|
||||
}
|
||||
|
||||
static int fat32_read_cluster_from_map(struct fat32_context* context, uint32_t cluster, uint32_t* out) {
|
||||
const uint32_t sector = cluster / (FAT32_SECTOR_SIZE / 4);
|
||||
const uint32_t offset = cluster % (FAT32_SECTOR_SIZE / 4);
|
||||
|
||||
uint32_t clusters[FAT32_SECTOR_SIZE / sizeof(uint32_t)];
|
||||
int r = part_read(&context->part, &clusters[0], (context->fat_start_lba + sector) * FAT32_SECTOR_SIZE, sizeof(clusters));
|
||||
int r = part_read(&context->part, out, context->fat_start_lba * FAT32_SECTOR_SIZE + cluster * sizeof(uint32_t), sizeof(uint32_t));
|
||||
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
*out = clusters[offset] & 0x0FFFFFFF;
|
||||
*out &= 0x0fffffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -143,7 +139,7 @@ static bool read_cluster_chain(struct fat32_context *context,
|
||||
if (chunk > block_size - offset)
|
||||
chunk = block_size - offset;
|
||||
|
||||
uint64_t base = (context->data_start_lba + (cluster_chain[block] - 2)) * block_size;
|
||||
uint64_t base = (context->data_start_lba + (cluster_chain[block] - 2) * context->sectors_per_cluster) * FAT32_SECTOR_SIZE;
|
||||
int r = part_read(&context->part, buf + progress, base + offset, chunk);
|
||||
|
||||
if (r)
|
||||
@ -167,6 +163,9 @@ static bool fat32_filename_to_8_3(char *dest, const char *src) {
|
||||
int i = 0, j = 0;
|
||||
bool ext = false;
|
||||
|
||||
for (size_t i = 0; i < 8+3; i++)
|
||||
dest[i] = ' ';
|
||||
|
||||
while (src[i]) {
|
||||
if (src[i] == '.') {
|
||||
if (ext) {
|
||||
@ -174,9 +173,7 @@ static bool fat32_filename_to_8_3(char *dest, const char *src) {
|
||||
return false;
|
||||
}
|
||||
ext = true;
|
||||
// Pad the rest of the base filename with spaces
|
||||
while (j < 8)
|
||||
dest[j++] = ' ';
|
||||
j = 8;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
@ -321,5 +318,5 @@ int fat32_open(struct fat32_file_handle* ret, struct part *part, const char* pat
|
||||
}
|
||||
|
||||
int fat32_read(struct fat32_file_handle* file, void* buf, uint64_t loc, uint64_t count) {
|
||||
return read_cluster_chain(&file->context, file->cluster_chain, buf, loc, count);
|
||||
return !read_cluster_chain(&file->context, file->cluster_chain, buf, loc, count);
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
|
||||
|
||||
void *freadall(struct file_handle *fd, uint32_t type) {
|
||||
if (fd->is_memfile) {
|
||||
memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false);
|
||||
memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true);
|
||||
return fd->fd;
|
||||
} else {
|
||||
void *ret = ext_mem_alloc_aligned_type(fd->size, 4096, type);
|
||||
|
@ -49,7 +49,10 @@ void *acpi_get_table(const char *signature, int index) {
|
||||
else
|
||||
rsdt = (struct rsdt *)rsdp->rsdt_addr;
|
||||
|
||||
for (size_t i = 0; i < rsdt->length - sizeof(struct sdt); i++) {
|
||||
size_t entry_count =
|
||||
(rsdt->length - sizeof(struct sdt)) / (use_xsdt ? 8 : 4);
|
||||
|
||||
for (size_t i = 0; i < entry_count; i++) {
|
||||
struct sdt *ptr;
|
||||
if (use_xsdt)
|
||||
ptr = (struct sdt *)(size_t)((uint64_t *)rsdt->ptrs_start)[i];
|
||||
|
@ -309,7 +309,7 @@ int elf64_load(struct file_handle *fd, uint64_t *entry_point, uint64_t *top, uin
|
||||
if (this_top > *top)
|
||||
*top = this_top;
|
||||
|
||||
memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true);
|
||||
memmap_alloc_range((size_t)load_vaddr, (size_t)phdr.p_memsz, alloc_type, true, true);
|
||||
|
||||
fread(fd, (void *)(uint32_t)load_vaddr, phdr.p_offset, phdr.p_filesz);
|
||||
|
||||
@ -362,7 +362,7 @@ int elf32_load(struct file_handle *fd, uint32_t *entry_point, uint32_t *top, uin
|
||||
if (this_top > *top)
|
||||
*top = this_top;
|
||||
|
||||
memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true);
|
||||
memmap_alloc_range((size_t)phdr.p_paddr, (size_t)phdr.p_memsz, alloc_type, true, true);
|
||||
|
||||
fread(fd, (void *)phdr.p_paddr, phdr.p_offset, phdr.p_filesz);
|
||||
|
||||
|
@ -24,7 +24,6 @@ bool is_valid_guid(const char *s) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void guid_convert_le_cluster(uint8_t *dest, const char *s, int len) {
|
||||
size_t p = 0;
|
||||
for (int i = len - 1; i >= 0; i--) {
|
||||
@ -33,7 +32,6 @@ static void guid_convert_le_cluster(uint8_t *dest, const char *s, int len) {
|
||||
i % 2 ? (dest[p] = val) : (dest[p++] |= val << 4);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static void guid_convert_be_cluster(uint8_t *dest, const char *s, int len) {
|
||||
size_t p = 0;
|
||||
@ -44,7 +42,7 @@ static void guid_convert_be_cluster(uint8_t *dest, const char *s, int len) {
|
||||
}
|
||||
}
|
||||
|
||||
bool string_to_guid(struct guid *guid, const char *s) {
|
||||
bool string_to_guid_be(struct guid *guid, const char *s) {
|
||||
if (!is_valid_guid(s))
|
||||
return false;
|
||||
|
||||
@ -56,3 +54,16 @@ bool string_to_guid(struct guid *guid, const char *s) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string_to_guid_mixed(struct guid *guid, const char *s) {
|
||||
if (!is_valid_guid(s))
|
||||
return false;
|
||||
|
||||
guid_convert_le_cluster((uint8_t *)guid + 0, s + 0, 8);
|
||||
guid_convert_le_cluster((uint8_t *)guid + 4, s + 9, 4);
|
||||
guid_convert_le_cluster((uint8_t *)guid + 6, s + 14, 4);
|
||||
guid_convert_be_cluster((uint8_t *)guid + 8, s + 19, 4);
|
||||
guid_convert_be_cluster((uint8_t *)guid + 10, s + 24, 12);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ struct guid {
|
||||
} __attribute__((packed));
|
||||
|
||||
bool is_valid_guid(const char *s);
|
||||
bool string_to_guid(struct guid *guid, const char *s);
|
||||
bool string_to_guid_be(struct guid *guid, const char *s);
|
||||
bool string_to_guid_mixed(struct guid *guid, const char *s);
|
||||
|
||||
#endif
|
||||
|
@ -232,6 +232,8 @@ static struct part *part_index = NULL;
|
||||
static size_t part_index_i = 0;
|
||||
|
||||
void part_create_index(void) {
|
||||
size_t part_count = 0;
|
||||
|
||||
for (uint8_t drive = 0x80; drive < 0x8f; drive++) {
|
||||
struct rm_regs r = {0};
|
||||
struct bios_drive_params drive_params;
|
||||
@ -252,29 +254,48 @@ void part_create_index(void) {
|
||||
print(" ... %X total %u-byte sectors\n",
|
||||
drive_params.lba_count, drive_params.bytes_per_sect);
|
||||
|
||||
size_t part_count = 0;
|
||||
|
||||
load_up:
|
||||
for (int part = 0; ; part++) {
|
||||
struct part p;
|
||||
int ret = part_get(&p, drive, part);
|
||||
|
||||
if (ret == END_OF_TABLE)
|
||||
if (ret == END_OF_TABLE || ret == INVALID_TABLE)
|
||||
break;
|
||||
if (ret == NO_PARTITION)
|
||||
continue;
|
||||
|
||||
if (part_index)
|
||||
part_index[part_index_i++] = p;
|
||||
else
|
||||
part_count++;
|
||||
part_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (part_index)
|
||||
return;
|
||||
part_index = ext_mem_alloc(sizeof(struct part) * part_count);
|
||||
|
||||
part_index = ext_mem_alloc(sizeof(struct part) * part_count);
|
||||
goto load_up;
|
||||
for (uint8_t drive = 0x80; drive < 0x8f; drive++) {
|
||||
struct rm_regs r = {0};
|
||||
struct bios_drive_params drive_params;
|
||||
|
||||
r.eax = 0x4800;
|
||||
r.edx = drive;
|
||||
r.ds = rm_seg(&drive_params);
|
||||
r.esi = rm_off(&drive_params);
|
||||
|
||||
drive_params.buf_size = sizeof(struct bios_drive_params);
|
||||
|
||||
rm_int(0x13, &r, &r);
|
||||
|
||||
if (r.eflags & EFLAGS_CF)
|
||||
continue;
|
||||
|
||||
for (int part = 0; ; part++) {
|
||||
struct part p;
|
||||
int ret = part_get(&p, drive, part);
|
||||
|
||||
if (ret == END_OF_TABLE || ret == INVALID_TABLE)
|
||||
break;
|
||||
if (ret == NO_PARTITION)
|
||||
continue;
|
||||
|
||||
part_index[part_index_i++] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
section .realmode
|
||||
|
||||
int_08_ticks_counter: dd 0
|
||||
int_08_callback: dd 0
|
||||
|
||||
int_08_isr:
|
||||
bits 16
|
||||
pushf
|
||||
inc dword [cs:int_08_ticks_counter]
|
||||
int 0x80 ; call callback
|
||||
iret
|
||||
popf
|
||||
jmp far [cs:int_08_callback]
|
||||
bits 32
|
||||
|
||||
extern getchar_internal
|
||||
@ -15,7 +17,7 @@ global pit_sleep_and_quit_on_keypress
|
||||
pit_sleep_and_quit_on_keypress:
|
||||
; Hook int 0x08
|
||||
mov edx, dword [0x08*4]
|
||||
mov dword [0x80*4], edx
|
||||
mov dword [int_08_callback], edx
|
||||
mov edx, int_08_isr
|
||||
mov dword [0x08*4], int_08_isr
|
||||
|
||||
@ -100,7 +102,7 @@ pit_sleep_and_quit_on_keypress:
|
||||
pop ebx
|
||||
|
||||
; Dehook int 0x08
|
||||
mov edx, dword [0x80*4]
|
||||
mov edx, dword [int_08_callback]
|
||||
mov dword [0x08*4], edx
|
||||
|
||||
push eax
|
||||
|
@ -109,12 +109,17 @@ static bool uri_bios_dispatch(struct file_handle *fd, char *loc, char *path) {
|
||||
|
||||
static bool uri_guid_dispatch(struct file_handle *fd, char *guid_str, char *path) {
|
||||
struct guid guid;
|
||||
if (!string_to_guid(&guid, guid_str))
|
||||
if (!string_to_guid_be(&guid, guid_str))
|
||||
return false;
|
||||
|
||||
struct part part;
|
||||
if (!part_get_by_guid(&part, &guid))
|
||||
return false;
|
||||
if (!part_get_by_guid(&part, &guid)) {
|
||||
if (!string_to_guid_mixed(&guid, guid_str))
|
||||
return false;
|
||||
|
||||
if (!part_get_by_guid(&part, &guid))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fopen(fd, &part, path))
|
||||
return false;
|
||||
|
@ -237,7 +237,7 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
|
||||
|
||||
// We now reserve the range we need.
|
||||
int64_t aligned_length = entry_top - alloc_base;
|
||||
memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true);
|
||||
memmap_alloc_range((uint64_t)alloc_base, (uint64_t)aligned_length, type, true, true);
|
||||
|
||||
void *ret = (void *)(size_t)alloc_base;
|
||||
|
||||
@ -252,13 +252,17 @@ void *ext_mem_alloc_aligned_type(size_t count, size_t alignment, uint32_t type)
|
||||
panic("High memory allocator: Out of memory");
|
||||
}
|
||||
|
||||
void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only) {
|
||||
bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool do_panic) {
|
||||
uint64_t top = base + length;
|
||||
|
||||
if (base < 0x100000) {
|
||||
// We don't do allocations below 1 MiB
|
||||
panic("Attempt to allocate memory below 1 MiB (%X-%X)",
|
||||
base, base + length);
|
||||
if (do_panic) {
|
||||
// We don't do allocations below 1 MiB
|
||||
panic("Attempt to allocate memory below 1 MiB (%X-%X)",
|
||||
base, base + length);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < memmap_entries; i++) {
|
||||
@ -303,11 +307,14 @@ void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free
|
||||
target->base = base;
|
||||
target->length = length;
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
panic("Out of memory");
|
||||
if (do_panic)
|
||||
panic("Out of memory");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
extern symbol bss_end;
|
||||
|
@ -20,7 +20,7 @@ extern size_t memmap_entries;
|
||||
void init_memmap(void);
|
||||
struct e820_entry_t *get_memmap(size_t *entries);
|
||||
void print_memmap(struct e820_entry_t *mm, size_t size);
|
||||
void memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only);
|
||||
bool memmap_alloc_range(uint64_t base, uint64_t length, uint32_t type, bool free_only, bool panic);
|
||||
|
||||
void *ext_mem_alloc(size_t count);
|
||||
void *ext_mem_alloc_type(size_t count, uint32_t type);
|
||||
|
@ -13,10 +13,11 @@
|
||||
#include <mm/mtrr.h>
|
||||
|
||||
#define KERNEL_LOAD_ADDR ((size_t)0x100000)
|
||||
#define INITRD_LOAD_ADDR ((size_t)0x1000000)
|
||||
#define KERNEL_HEAP_SIZE ((size_t)0x6000)
|
||||
|
||||
__attribute__((section(".realmode"), used))
|
||||
static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
|
||||
static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg,
|
||||
uint16_t stack_pointer) {
|
||||
asm volatile (
|
||||
"cld\n\t"
|
||||
|
||||
@ -38,30 +39,22 @@ static void spinup(uint16_t real_mode_code_seg, uint16_t kernel_entry_seg) {
|
||||
"mov fs, bx\n\t"
|
||||
"mov gs, bx\n\t"
|
||||
"mov ss, bx\n\t"
|
||||
"mov esp, 0xfdf0\n\t"
|
||||
|
||||
"sti\n\t"
|
||||
"mov esp, edx\n\t"
|
||||
|
||||
"push cx\n\t"
|
||||
"push 0\n\t"
|
||||
|
||||
"retf\n\t"
|
||||
|
||||
".code32\n\t"
|
||||
:
|
||||
: "b" (real_mode_code_seg), "c" (kernel_entry_seg)
|
||||
: "b" (real_mode_code_seg), "c" (kernel_entry_seg),
|
||||
"d" (stack_pointer)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
void linux_load(char *config, char *cmdline) {
|
||||
// The command line needs to be before address 0xa0000, we can use
|
||||
// a conv_mem_alloc() allocated buffer for that.
|
||||
// Allocate the relocation buffer for the command line early so it's allocated
|
||||
// before the real mode code.
|
||||
size_t cmdline_len = strlen(cmdline);
|
||||
char *cmdline_reloc = conv_mem_alloc(cmdline_len + 1);
|
||||
strcpy(cmdline_reloc, cmdline);
|
||||
|
||||
struct file_handle *kernel = ext_mem_alloc(sizeof(struct file_handle));
|
||||
|
||||
char *kernel_path = config_get_value(config, 0, "KERNEL_PATH");
|
||||
@ -87,28 +80,33 @@ void linux_load(char *config, char *cmdline) {
|
||||
|
||||
setup_code_size *= 512;
|
||||
|
||||
print("linux: Setup code size: %x\n", setup_code_size);
|
||||
|
||||
size_t real_mode_code_size = 512 + setup_code_size;
|
||||
|
||||
print("linux: Real Mode code size: %x\n", real_mode_code_size);
|
||||
size_t real_mode_and_heap_size = 0x8000 + KERNEL_HEAP_SIZE;
|
||||
|
||||
void *real_mode_code = conv_mem_alloc_aligned(real_mode_code_size, 0x1000);
|
||||
void *real_mode_code = conv_mem_alloc_aligned(0x10000, 0x1000);
|
||||
|
||||
fread(kernel, real_mode_code, 0, real_mode_code_size);
|
||||
|
||||
size_t heap_end_ptr = ((real_mode_code_size & 0x0f) + 0x10) - 0x200;
|
||||
*((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
|
||||
|
||||
// vid_mode. 0xffff means "normal"
|
||||
*((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
|
||||
|
||||
uint16_t boot_protocol_ver;
|
||||
boot_protocol_ver = *((uint16_t *)(real_mode_code + 0x206));
|
||||
|
||||
print("linux: Boot protocol: %u.%u\n",
|
||||
boot_protocol_ver >> 8, boot_protocol_ver & 0xff);
|
||||
|
||||
if (boot_protocol_ver < 0x203) {
|
||||
panic("Linux protocols < 2.03 are not supported");
|
||||
}
|
||||
|
||||
size_t heap_end_ptr = real_mode_and_heap_size - 0x200;
|
||||
*((uint16_t *)(real_mode_code + 0x224)) = (uint16_t)heap_end_ptr;
|
||||
|
||||
char *cmdline_reloc = real_mode_code + real_mode_and_heap_size;
|
||||
strcpy(cmdline_reloc, cmdline);
|
||||
|
||||
// vid_mode. 0xffff means "normal"
|
||||
*((uint16_t *)(real_mode_code + 0x1fa)) = 0xffff;
|
||||
|
||||
char *kernel_version;
|
||||
kernel_version = real_mode_code + *((uint16_t *)(real_mode_code + 0x20e)) + 0x200;
|
||||
|
||||
@ -122,7 +120,10 @@ void linux_load(char *config, char *cmdline) {
|
||||
uint8_t loadflags;
|
||||
loadflags = *((uint8_t *)(real_mode_code + 0x211));
|
||||
|
||||
loadflags |= (1 << 0); // kernel is loaded at 0x100000
|
||||
if (!(loadflags & (1 << 0))) {
|
||||
panic("Linux kernels that load at 0x10000 are not supported");
|
||||
}
|
||||
|
||||
loadflags &= ~(1 << 5); // print early messages
|
||||
loadflags |= (1 << 7); // can use heap
|
||||
|
||||
@ -131,11 +132,16 @@ void linux_load(char *config, char *cmdline) {
|
||||
*((uint32_t *)(real_mode_code + 0x228)) = (uint32_t)cmdline_reloc;
|
||||
|
||||
// load kernel
|
||||
print("Loading kernel...\n");
|
||||
memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true);
|
||||
print("linux: Loading kernel...\n");
|
||||
memmap_alloc_range(KERNEL_LOAD_ADDR, kernel->size - real_mode_code_size, 0, true, true);
|
||||
fread(kernel, (void *)KERNEL_LOAD_ADDR, real_mode_code_size, kernel->size - real_mode_code_size);
|
||||
|
||||
size_t modules_mem_base = INITRD_LOAD_ADDR;
|
||||
uint32_t modules_mem_base = *((uint32_t *)(real_mode_code + 0x22c)) + 1;
|
||||
if (modules_mem_base == 0)
|
||||
modules_mem_base = 0x38000000;
|
||||
|
||||
size_t size_of_all_modules = 0;
|
||||
|
||||
for (size_t i = 0; ; i++) {
|
||||
char *module_path = config_get_value(config, i, "MODULE_PATH");
|
||||
if (module_path == NULL)
|
||||
@ -145,17 +151,38 @@ void linux_load(char *config, char *cmdline) {
|
||||
if (!uri_open(&module, module_path))
|
||||
panic("Could not open `%s`", module_path);
|
||||
|
||||
print("Loading module `%s`...\n", module_path);
|
||||
|
||||
memmap_alloc_range(modules_mem_base, module.size, 0, true);
|
||||
fread(&module, (void *)modules_mem_base, 0, module.size);
|
||||
|
||||
modules_mem_base += module.size;
|
||||
size_of_all_modules += module.size;
|
||||
}
|
||||
|
||||
if (modules_mem_base != INITRD_LOAD_ADDR) {
|
||||
*((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)INITRD_LOAD_ADDR;
|
||||
*((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)(modules_mem_base - INITRD_LOAD_ADDR);
|
||||
modules_mem_base -= size_of_all_modules;
|
||||
modules_mem_base = ALIGN_DOWN(modules_mem_base, 4096);
|
||||
|
||||
for (;;) {
|
||||
if (memmap_alloc_range(modules_mem_base, size_of_all_modules, 0, true, false))
|
||||
break;
|
||||
modules_mem_base -= 4096;
|
||||
}
|
||||
|
||||
size_t _modules_mem_base = modules_mem_base;
|
||||
for (size_t i = 0; ; i++) {
|
||||
char *module_path = config_get_value(config, i, "MODULE_PATH");
|
||||
if (module_path == NULL)
|
||||
break;
|
||||
|
||||
struct file_handle module;
|
||||
if (!uri_open(&module, module_path))
|
||||
panic("Could not open `%s`", module_path);
|
||||
|
||||
print("linux: Loading module `%s`...\n", module_path);
|
||||
|
||||
fread(&module, (void *)_modules_mem_base, 0, module.size);
|
||||
|
||||
_modules_mem_base += module.size;
|
||||
}
|
||||
|
||||
if (size_of_all_modules != 0) {
|
||||
*((uint32_t *)(real_mode_code + 0x218)) = (uint32_t)modules_mem_base;
|
||||
*((uint32_t *)(real_mode_code + 0x21c)) = (uint32_t)size_of_all_modules;
|
||||
}
|
||||
|
||||
uint16_t real_mode_code_seg = rm_seg(real_mode_code);
|
||||
@ -165,5 +192,5 @@ void linux_load(char *config, char *cmdline) {
|
||||
|
||||
mtrr_restore();
|
||||
|
||||
spinup(real_mode_code_seg, kernel_entry_seg);
|
||||
spinup(real_mode_code_seg, kernel_entry_seg, real_mode_and_heap_size);
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
#ifndef __STIVALE__STIVALE_H__
|
||||
#define __STIVALE__STIVALE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* --- Header --------------------------------------------------------------- */
|
||||
/* Information passed from the kernel to the bootloader */
|
||||
|
||||
struct stivale_header {
|
||||
uint64_t stack;
|
||||
uint16_t flags;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_bpp;
|
||||
uint64_t entry_point;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* --- Struct --------------------------------------------------------------- */
|
||||
/* Information passed from the bootloader to the kernel */
|
||||
|
||||
struct stivale_module {
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
char string[128];
|
||||
uint64_t next;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
STIVALE_MMAP_USABLE = 1,
|
||||
STIVALE_MMAP_RESERVED = 2,
|
||||
STIVALE_MMAP_ACPI_RECLAIMABLE = 3,
|
||||
STIVALE_MMAP_ACPI_NVS = 4,
|
||||
STIVALE_MMAP_BAD_MEMORY = 5,
|
||||
STIVALE_MMAP_KERNEL_AND_MODULES = 10,
|
||||
STIVALE_MMAP_BOOTLOADER_RECLAIMABLE = 0x1000
|
||||
};
|
||||
|
||||
struct stivale_mmap_entry {
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint32_t type;
|
||||
uint32_t unused;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum {
|
||||
STIVALE_FBUF_MMODEL_RGB = 1
|
||||
};
|
||||
|
||||
struct stivale_struct {
|
||||
uint64_t cmdline;
|
||||
uint64_t memory_map_addr;
|
||||
uint64_t memory_map_entries;
|
||||
uint64_t framebuffer_addr;
|
||||
uint16_t framebuffer_pitch;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_bpp;
|
||||
uint64_t rsdp;
|
||||
uint64_t module_count;
|
||||
uint64_t modules;
|
||||
uint64_t epoch;
|
||||
uint64_t flags; // bit 0: 1 if booted with BIOS, 0 if booted with UEFI
|
||||
// bit 1: 1 if extended colour information passed, 0 if not
|
||||
uint8_t fb_memory_model;
|
||||
uint8_t fb_red_mask_size;
|
||||
uint8_t fb_red_mask_shift;
|
||||
uint8_t fb_green_mask_size;
|
||||
uint8_t fb_green_mask_shift;
|
||||
uint8_t fb_blue_mask_size;
|
||||
uint8_t fb_blue_mask_shift;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
@ -1,173 +0,0 @@
|
||||
#ifndef __STIVALE__STIVALE2_H__
|
||||
#define __STIVALE__STIVALE2_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct stivale2_tag {
|
||||
uint64_t identifier;
|
||||
uint64_t next;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* --- Header --------------------------------------------------------------- */
|
||||
/* Information passed from the kernel to the bootloader */
|
||||
|
||||
struct stivale2_header {
|
||||
uint64_t entry_point;
|
||||
uint64_t stack;
|
||||
uint64_t flags;
|
||||
uint64_t tags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_HEADER_TAG_FRAMEBUFFER_ID 0x3ecc1bc43d0f7971
|
||||
|
||||
#define STIVALE2_HEADER_TAG_FB_MTRR_ID 0x4c7bb07731282e00
|
||||
|
||||
struct stivale2_header_tag_framebuffer {
|
||||
struct stivale2_tag tag;
|
||||
uint16_t framebuffer_width;
|
||||
uint16_t framebuffer_height;
|
||||
uint16_t framebuffer_bpp;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_HEADER_TAG_SMP_ID 0x1ab015085f3273df
|
||||
|
||||
struct stivale2_header_tag_smp {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_HEADER_TAG_5LV_PAGING_ID 0x932f477032007e8f
|
||||
|
||||
/* --- Struct --------------------------------------------------------------- */
|
||||
/* Information passed from the bootloader to the kernel */
|
||||
|
||||
struct stivale2_struct {
|
||||
#define STIVALE2_BOOTLOADER_BRAND_SIZE 64
|
||||
char bootloader_brand[STIVALE2_BOOTLOADER_BRAND_SIZE];
|
||||
|
||||
#define STIVALE2_BOOTLOADER_VERSION_SIZE 64
|
||||
char bootloader_version[STIVALE2_BOOTLOADER_VERSION_SIZE];
|
||||
|
||||
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
|
||||
|
||||
enum {
|
||||
STIVALE2_MMAP_USABLE = 1,
|
||||
STIVALE2_MMAP_RESERVED = 2,
|
||||
STIVALE2_MMAP_ACPI_RECLAIMABLE = 3,
|
||||
STIVALE2_MMAP_ACPI_NVS = 4,
|
||||
STIVALE2_MMAP_BAD_MEMORY = 5,
|
||||
STIVALE2_MMAP_BOOTLOADER_RECLAIMABLE = 0x1000,
|
||||
STIVALE2_MMAP_KERNEL_AND_MODULES = 0x1001
|
||||
};
|
||||
|
||||
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;
|
||||
struct stivale2_mmap_entry memmap[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID 0x506461d2950408fa
|
||||
|
||||
enum {
|
||||
STIVALE2_FBUF_MMODEL_RGB = 1
|
||||
};
|
||||
|
||||
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;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_FB_MTRR_ID 0x6bc1a78ebe871172
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_MODULES_ID 0x4b6fe466aade04ce
|
||||
|
||||
struct stivale2_module {
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
|
||||
#define STIVALE2_MODULE_STRING_SIZE 128
|
||||
char string[STIVALE2_MODULE_STRING_SIZE];
|
||||
} __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 STIVALE2_STRUCT_TAG_SMP_ID 0x34d1d96339647025
|
||||
|
||||
struct stivale2_smp_info {
|
||||
uint32_t processor_id;
|
||||
uint32_t lapic_id;
|
||||
uint64_t target_stack;
|
||||
uint64_t goto_address;
|
||||
uint64_t extra_argument;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct stivale2_struct_tag_smp {
|
||||
struct stivale2_tag tag;
|
||||
uint64_t flags;
|
||||
uint32_t bsp_lapic_id;
|
||||
uint32_t unused;
|
||||
uint64_t cpu_count;
|
||||
struct stivale2_smp_info smp_info[];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define STIVALE2_STRUCT_TAG_PXE_SERVER_INFO 0x29d1e96239247032
|
||||
|
||||
struct stivale2_struct_tag_pxe_server_info {
|
||||
struct stivale2_tag tag;
|
||||
uint32_t server_ip;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@ set -x
|
||||
|
||||
PREFIX="$(pwd)"
|
||||
TARGET=i386-elf
|
||||
BINUTILSVERSION=2.35.1
|
||||
BINUTILSVERSION=2.36
|
||||
GCCVERSION=10.2.0
|
||||
NASMVERSION=2.15.05
|
||||
GZIPVERSION=1.10
|
||||
|
Loading…
Reference in New Issue
Block a user