Compare commits

...

29 Commits

Author SHA1 Message Date
mintsuki
49b6c1e472 misc: Update binary images 2021-03-10 02:29:46 +01:00
mintsuki
2cfa5b281a acpi: Fix length of RSDP calculation 2021-03-10 02:28:11 +01:00
mintsuki
7c4f71e532 fat32: Fix base calculation for cluster sizes of more than 1 sector 2021-03-07 03:15:45 +01:00
mintsuki
d62e9a49a5 limine-install: Fix buffer overflow bug with new stage 2 alignments 2021-03-06 04:02:13 +01:00
mintsuki
361fb431a5 limine-install: Make sure stage 2 chunks are sector aligned 2021-03-04 12:29:59 +01:00
mintsuki
611914b138 disk: Add sanity checks to cache 2021-03-04 11:05:28 +01:00
mintsuki
9504dc6da7 limine-install: Fix bug where wrong command line argument is parsed 2021-02-20 23:06:03 +01:00
JlXip
767be2c09c limine-install: Initialize lb_size so GCC doesn't warn 2021-02-11 21:13:42 +01:00
mintsuki
33058217fa fat32: Fix bug with conversion to 8+3 filename 2021-02-08 19:06:10 +01:00
mintsuki
5ed2c2203a part: Fix bug where an improper buffer size was allocated when indexing all partitions 2021-02-08 18:52:57 +01:00
mintsuki
8c76a0f406 Revert "volume: Replace concept of partition handle with that of volumes, fix bug in indexing volumes along the way"
This reverts commit af31ba949b.
2021-02-08 18:47:52 +01:00
mintsuki
0c12e2f4da Revert "ext2: Change line endings of source files to UNIX"
This reverts commit 6db8694d7f.
2021-02-08 18:47:41 +01:00
mintsuki
6db8694d7f ext2: Change line endings of source files to UNIX 2021-02-06 15:11:14 +01:00
mintsuki
af31ba949b volume: Replace concept of partition handle with that of volumes, fix bug in indexing volumes along the way 2021-02-06 15:10:41 +01:00
mintsuki
07887dcc4c linux: Misc protocol bug fixes 2021-01-27 17:31:57 +01:00
mintsuki
02ef011f8e linux: Misc protocol bug fixes 2021-01-27 17:30:58 +01:00
mintsuki
beb688d8ca misc: Bump binutils to 2.36 2021-01-27 17:29:46 +01:00
mintsuki
c91e96f3e5 sleep: Do not clobber int 0x80 for PIT IRQ handler callback 2021-01-17 16:47:15 +01:00
mintsuki
94c56a030b guid: Add handling of mixed endianness GUIDs 2021-01-17 16:46:38 +01:00
mintsuki
fbdd709ba6 misc: Bump stivale commit 2021-01-15 10:20:12 +01:00
mintsuki
cde4a592f3 misc: Make build system download stivale headers from stivale repository and delete local copies 2021-01-15 06:27:30 +01:00
mintsuki
638e7bf867 misc: Update warning about unstable branch in README 2021-01-15 06:27:30 +01:00
mintsuki
63ea645359 misc: stivale specifications moved to stivale/stivale 2021-01-15 06:27:30 +01:00
mintsuki
fdc89f7631 misc: Add binary architecture flag to objcopy to avoid limine-install build failures on older host toolchains. Fixes #63 2021-01-15 06:27:30 +01:00
mintsuki
0c6baf3591 misc: Update example version of limine in readme 2021-01-04 00:49:39 +01:00
mintsuki
721bedbcc9 fat32: Fix wrong return type issue 2021-01-03 23:33:03 +01:00
mintsuki
f527896a2b limine-install: Fix argument order for strstr() call 2021-01-03 19:40:04 +01:00
mintsuki
996f2d60bf misc: Update binary images 2021-01-03 03:01:21 +01:00
mintsuki
406477acaa misc: Bump version 2021-01-03 02:56:48 +01:00
26 changed files with 201 additions and 1117 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@
!/limine.bin
!/limine-pxe.bin
!/stage2.map
/stivale

View File

@ -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:

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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));

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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