Some work on ACPI and use EBDA start as end of usable conventional memory

This commit is contained in:
mintsuki 2020-09-17 12:06:35 +02:00
parent a7980f3dc4
commit a909fd821c
8 changed files with 165 additions and 98 deletions

View File

@ -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: load_gdt:
pusha pusha
push es push es
push ds push ds
push 0x7ff0 mov ax, word [0x40e] ; 0x40e contains the value of a segment pointing to the EBDA
pop es sub ax, ALIGN_UP(gdt.size, 16) / 16
mov es, ax
mov word [gdt.ptr], ax
shl dword [gdt.ptr], 4
xor di, di xor di, di
push 0 mov ds, di
pop ds mov si, gdt.start
mov si, GDT.GDTStart mov cx, gdt.size
mov cx, GDT.GDTEnd - GDT.GDTStart
rep movsb rep movsb
lgdt [GDT]
pop ds pop ds
lgdt [gdt]
pop es pop es
popa popa
ret ret
GDT: gdt:
dw .size - 1 ; GDT size
.ptr:
dd 0 ; GDT start address (calculated at runtime)
dw .GDTEnd - .GDTStart - 1 ; GDT size .start:
dd 0x7ff00 ; GDT 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)
.GDTStart: ; 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)
; Null descriptor (required) ; 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)
.NullDescriptor: ; 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)
dw 0x0000 ; Limit ; 32-bit data
dw 0x0000 ; Base (low 16 bits) dw 0xffff ; Limit
db 0x00 ; Base (mid 8 bits) dw 0x0000 ; Base (low 16 bits)
db 00000000b ; Access db 0x00 ; Base (mid 8 bits)
db 00000000b ; Granularity db 10010010b ; Access
db 0x00 ; Base (high 8 bits) db 11001111b ; Granularity
db 0x00 ; Base (high 8 bits)
; 16-bit code ; 64-bit code
dw 0xffff ; Limit dw 0x0000 ; Limit
dw 0x0000 ; Base (low 16 bits) dw 0x0000 ; Base (low 16 bits)
db 0x00 ; Base (mid 8 bits) db 0x00 ; Base (mid 8 bits)
db 10011010b ; Access db 10011010b ; Access
db 00000000b ; Granularity db 00100000b ; Granularity
db 0x00 ; Base (high 8 bits) db 0x00 ; Base (high 8 bits)
; 16-bit data ; 64-bit data
dw 0xffff ; Limit dw 0x0000 ; Limit
dw 0x0000 ; Base (low 16 bits) dw 0x0000 ; Base (low 16 bits)
db 0x00 ; Base (mid 8 bits) db 0x00 ; Base (mid 8 bits)
db 10010010b ; Access db 10010010b ; Access
db 00000000b ; Granularity db 00000000b ; Granularity
db 0x00 ; Base (high 8 bits) db 0x00 ; Base (high 8 bits)
; 32-bit code .end:
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 .size: equ .end - .start
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 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)
.GDTEnd:

Binary file not shown.

View File

@ -4,14 +4,24 @@
#include <lib/libc.h> #include <lib/libc.h>
#include <lib/print.h> #include <lib/print.h>
void *get_rsdp(void) { // Following function based on https://github.com/qword-os/lai/blob/master/helpers/pc-bios.c's function lai_bios_calc_checksum()
for (size_t i = 0x80000; i < 0x100000; i += 16) { uint8_t acpi_checksum(void *ptr, size_t size) {
if (i == 0xa0000) { uint8_t sum = 0, *_ptr = ptr;
/* skip video mem and mapped hardware */ for (size_t i = 0; i < size; i++)
i = 0xe0000 - 16; sum += _ptr[i];
continue; 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); print("acpi: Found RSDP at %x\n", i);
return (void *)i; return (void *)i;
} }

View File

@ -1,6 +1,46 @@
#ifndef __LIB__ACPI_H__ #ifndef __LIB__ACPI_H__
#define __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 #endif

View File

@ -48,7 +48,7 @@ __attribute__((noreturn)) void panic(const char *fmt, ...) {
extern symbol bss_end; extern symbol bss_end;
static size_t bump_allocator_base = (size_t)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) { void brewind(size_t count) {
bump_allocator_base -= count; bump_allocator_base -= count;
@ -58,12 +58,21 @@ void *balloc(size_t count) {
return balloc_aligned(count, 4); return balloc_aligned(count, 4);
} }
// Only power of 2 alignments
void *balloc_aligned(size_t count, size_t alignment) { 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); size_t new_base = ALIGN_UP(bump_allocator_base, alignment);
void *ret = (void *)new_base; void *ret = (void *)new_base;
new_base += count; new_base += count;
if (new_base >= BUMP_ALLOCATOR_LIMIT) if (new_base >= bump_allocator_limit)
panic("Memory allocation failed"); panic("Memory allocation failed");
bump_allocator_base = new_base; bump_allocator_base = new_base;

View File

@ -4,25 +4,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.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); uint8_t bcd_to_int(uint8_t val);
int cpuid(uint32_t leaf, uint32_t subleaf, 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)) #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])) #define SIZEOF_ARRAY(array) (sizeof(array) / sizeof(array[0]))
typedef void *symbol[];
#endif #endif

View File

@ -213,7 +213,7 @@ void stivale_load(char *cmdline, int boot_drive) {
print(" End: %X\n", m->end); 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; 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 gs, ax\n\t"
"mov ss, 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 0x30\n\t"
"push [rsi]\n\t" "push [rsi]\n\t"
"pushfq\n\t" "pushfq\n\t"

View File

@ -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)); struct stivale2_struct_tag_rsdp *tag = balloc(sizeof(struct stivale2_struct_tag_rsdp));
tag->tag.identifier = STIVALE2_STRUCT_TAG_RSDP_ID; 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); append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
} }