:: commit a909fd821cb2affdea7c3ac8ab8f078367554ba9

mintsuki <mintsuki@protonmail.com> — 2020-09-17 10:06

parents: a7980f3dc4

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);
     }
tab: 248 wrap: offon