Some work on ACPI and use EBDA start as end of usable conventional memory
diff --git a/bootsect/gdt.inc b/bootsect/gdt.inc
index b6a63439..1fe6c22e 100644
--- a/bootsect/gdt.inc
+++ b/bootsect/gdt.inc
@@ -1,85 +1,90 @@
+%define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b))
+%define ALIGN_UP(x, a) (DIV_ROUNDUP((x), (a)) * (a))
+
+; The GDT is copied to <start of EBDA> - gdt.size, which will also serve
+; as the upper limit for balloc()
load_gdt:
pusha
push es
push ds
- push 0x7ff0
- pop es
+ mov ax, word [0x40e] ; 0x40e contains the value of a segment pointing to the EBDA
+ sub ax, ALIGN_UP(gdt.size, 16) / 16
+ mov es, ax
+ mov word [gdt.ptr], ax
+ shl dword [gdt.ptr], 4
xor di, di
- push 0
- pop ds
- mov si, GDT.GDTStart
- mov cx, GDT.GDTEnd - GDT.GDTStart
+ mov ds, di
+ mov si, gdt.start
+ mov cx, gdt.size
rep movsb
- lgdt [GDT]
pop ds
+ lgdt [gdt]
pop es
popa
ret
-GDT:
-
-dw .GDTEnd - .GDTStart - 1 ; GDT size
-dd 0x7ff00 ; GDT start
-
-.GDTStart:
-
-; Null descriptor (required)
+gdt:
+ dw .size - 1 ; GDT size
+ .ptr:
+ dd 0 ; GDT start address (calculated at runtime)
-.NullDescriptor:
+ .start:
+ ; Null descriptor (required)
+ dw 0x0000 ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 00000000b ; Access
+ db 00000000b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-dw 0x0000 ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 00000000b ; Access
-db 00000000b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 16-bit code
+ dw 0xffff ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10011010b ; Access
+ db 00000000b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 16-bit code
-dw 0xffff ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10011010b ; Access
-db 00000000b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 16-bit data
+ dw 0xffff ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10010010b ; Access
+ db 00000000b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 16-bit data
-dw 0xffff ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10010010b ; Access
-db 00000000b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 32-bit code
+ dw 0xffff ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10011010b ; Access
+ db 11001111b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 32-bit code
-dw 0xFFFF ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10011010b ; Access
-db 11001111b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 32-bit data
+ dw 0xffff ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10010010b ; Access
+ db 11001111b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 32-bit data
-dw 0xFFFF ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10010010b ; Access
-db 11001111b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 64-bit code
+ dw 0x0000 ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10011010b ; Access
+ db 00100000b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 64 bit code
-dw 0x0000 ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10011010b ; Access
-db 00100000b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ ; 64-bit data
+ dw 0x0000 ; Limit
+ dw 0x0000 ; Base (low 16 bits)
+ db 0x00 ; Base (mid 8 bits)
+ db 10010010b ; Access
+ db 00000000b ; Granularity
+ db 0x00 ; Base (high 8 bits)
-; 64 bit data
-dw 0x0000 ; Limit
-dw 0x0000 ; Base (low 16 bits)
-db 0x00 ; Base (mid 8 bits)
-db 10010010b ; Access
-db 00000000b ; Granularity
-db 0x00 ; Base (high 8 bits)
+ .end:
-.GDTEnd:
+ .size: equ .end - .start
diff --git a/limine.bin b/limine.bin
index 220dc3c5..d3b7b5c3 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2/lib/acpi.c b/stage2/lib/acpi.c
index cdd2f03c..661182c7 100644
--- a/stage2/lib/acpi.c
+++ b/stage2/lib/acpi.c
@@ -4,14 +4,24 @@
#include <lib/libc.h>
#include <lib/print.h>
-void *get_rsdp(void) {
- for (size_t i = 0x80000; i < 0x100000; i += 16) {
- if (i == 0xa0000) {
- /* skip video mem and mapped hardware */
- i = 0xe0000 - 16;
- continue;
+// Following function based on https://github.com/qword-os/lai/blob/master/helpers/pc-bios.c's function lai_bios_calc_checksum()
+uint8_t acpi_checksum(void *ptr, size_t size) {
+ uint8_t sum = 0, *_ptr = ptr;
+ for (size_t i = 0; i < size; i++)
+ sum += _ptr[i];
+ return sum;
+}
+
+void *acpi_get_rsdp(void) {
+ size_t ebda = EBDA;
+
+ for (size_t i = ebda; i < 0x100000; i += 16) {
+ if (i == ebda + 1024) {
+ // We probed the 1st KiB of the EBDA as per spec, move onto 0xe0000
+ i = 0xe0000;
}
- if (!strncmp((char *)i, "RSD PTR ", 8)) {
+ if (!memcmp((char *)i, "RSD PTR ", 8)
+ && !acpi_checksum((void *)i, sizeof(struct rsdp))) {
print("acpi: Found RSDP at %x\n", i);
return (void *)i;
}
diff --git a/stage2/lib/acpi.h b/stage2/lib/acpi.h
index 4f45423c..ddbf7f1b 100644
--- a/stage2/lib/acpi.h
+++ b/stage2/lib/acpi.h
@@ -1,6 +1,46 @@
#ifndef __LIB__ACPI_H__
#define __LIB__ACPI_H__
-void *get_rsdp(void);
+#include <stdint.h>
+#include <stddef.h>
+
+#define EBDA ((size_t)(*((uint16_t *)0x40e)) * 16)
+
+struct sdt {
+ char signature[4];
+ uint32_t length;
+ uint8_t rev;
+ uint8_t checksum;
+ char oem_id[6];
+ char oem_table_id[8];
+ uint32_t oem_rev;
+ uint32_t creator_id;
+ uint32_t creator_rev;
+} __attribute__((packed));
+
+struct rsdp {
+ char signature[8];
+ uint8_t checksum;
+ char oem_id[6];
+ uint8_t rev;
+ uint32_t rsdt_addr;
+} __attribute__((packed));
+
+struct rsdp_rev2 {
+ struct rsdp rsdp;
+ uint32_t length;
+ uint64_t xsdt_addr;
+ uint8_t ext_checksum;
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+struct rsdt {
+ struct sdt sdt;
+ char ptrs_start[];
+} __attribute__((packed));
+
+uint8_t acpi_checksum(void *ptr, size_t size);
+void *acpi_get_rsdp(void);
+void *acpi_get_table(const char *signature);
#endif
diff --git a/stage2/lib/blib.c b/stage2/lib/blib.c
index 62f5eacd..c347ea1b 100644
--- a/stage2/lib/blib.c
+++ b/stage2/lib/blib.c
@@ -48,7 +48,7 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) {
extern symbol bss_end;
static size_t bump_allocator_base = (size_t)bss_end;
-#define BUMP_ALLOCATOR_LIMIT ((size_t)0x7ff00)
+static size_t bump_allocator_limit = 0;
void brewind(size_t count) {
bump_allocator_base -= count;
@@ -58,12 +58,21 @@ void *balloc(size_t count) {
return balloc_aligned(count, 4);
}
-// Only power of 2 alignments
void *balloc_aligned(size_t count, size_t alignment) {
+ if (!bump_allocator_limit) {
+ // The balloc limit is the beginning of the GDT
+ struct {
+ uint16_t limit;
+ uint32_t ptr;
+ } __attribute__((packed)) gdtr;
+ asm volatile ("sgdt %0" :: "m"(gdtr));
+ bump_allocator_limit = gdtr.ptr;
+ }
+
size_t new_base = ALIGN_UP(bump_allocator_base, alignment);
void *ret = (void *)new_base;
new_base += count;
- if (new_base >= BUMP_ALLOCATOR_LIMIT)
+ if (new_base >= bump_allocator_limit)
panic("Memory allocation failed");
bump_allocator_base = new_base;
diff --git a/stage2/lib/blib.h b/stage2/lib/blib.h
index f68f12cd..a3045a94 100644
--- a/stage2/lib/blib.h
+++ b/stage2/lib/blib.h
@@ -4,25 +4,6 @@
#include <stddef.h>
#include <stdint.h>
-#define ALIGN_UP(x, a) ({ \
- typeof(x) value = x; \
- typeof(a) align = a; \
- if ((value & (align - 1)) != 0) { \
- value &= ~(align - 1); \
- value += align; \
- } \
- value; \
-})
-
-#define ALIGN_DOWN(x, a) ({ \
- typeof(x) value = x; \
- typeof(a) align = a; \
- if ((value & (align - 1)) != 0) { \
- value &= ~(align - 1); \
- } \
- value; \
-})
-
uint8_t bcd_to_int(uint8_t val);
int cpuid(uint32_t leaf, uint32_t subleaf,
@@ -48,8 +29,22 @@ uint64_t strtoui(const char *s);
#define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b))
-typedef void *symbol[];
+#define ALIGN_UP(x, a) ({ \
+ typeof(x) value = x; \
+ typeof(a) align = a; \
+ value = DIV_ROUNDUP(value, align) * align; \
+ value; \
+})
+
+#define ALIGN_DOWN(x, a) ({ \
+ typeof(x) value = x; \
+ typeof(a) align = a; \
+ value = (value / align) * align; \
+ value; \
+})
#define SIZEOF_ARRAY(array) (sizeof(array) / sizeof(array[0]))
+typedef void *symbol[];
+
#endif
diff --git a/stage2/protos/stivale.c b/stage2/protos/stivale.c
index 0f07ed7f..2f3e3595 100644
--- a/stage2/protos/stivale.c
+++ b/stage2/protos/stivale.c
@@ -213,7 +213,7 @@ void stivale_load(char *cmdline, int boot_drive) {
print(" End: %X\n", m->end);
}
- stivale_struct.rsdp = (uint64_t)(size_t)get_rsdp();
+ stivale_struct.rsdp = (uint64_t)(size_t)acpi_get_rsdp();
stivale_struct.cmdline = (uint64_t)(size_t)cmdline;
@@ -326,6 +326,14 @@ __attribute__((noreturn)) void stivale_spinup(int bits, bool level5pg,
"mov gs, ax\n\t"
"mov ss, ax\n\t"
+ // Since we don't really know what is now present in the upper
+ // 32 bits of the 64 bit registers, clear up the upper bits
+ // of the registers we use to store stack pointer and instruction
+ // pointer
+ "mov esi, esi\n\t"
+ "mov ebx, ebx\n\t"
+ "mov edi, edi\n\t"
+
"push 0x30\n\t"
"push [rsi]\n\t"
"pushfq\n\t"
diff --git a/stage2/protos/stivale2.c b/stage2/protos/stivale2.c
index e4d91c5a..8f8efb39 100644
--- a/stage2/protos/stivale2.c
+++ b/stage2/protos/stivale2.c
@@ -328,7 +328,7 @@ void stivale2_load(char *cmdline, int boot_drive) {
struct stivale2_struct_tag_rsdp *tag = balloc(sizeof(struct stivale2_struct_tag_rsdp));
tag->tag.identifier = STIVALE2_STRUCT_TAG_RSDP_ID;
- tag->rsdp = (uint64_t)(size_t)get_rsdp();
+ tag->rsdp = (uint64_t)(size_t)acpi_get_rsdp();
append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
}
