diff options
author | Marvin Borner | 2021-07-05 23:22:24 +0200 |
---|---|---|
committer | Marvin Borner | 2021-07-05 23:27:40 +0200 |
commit | 23aa6f84539ba320a91235fb81681d0754178f62 (patch) | |
tree | 972b0a4abc41900538bda23f4ac2145abf94e369 | |
parent | d1476974cd612412eefc40c6dc72ba66191136fd (diff) |
ACPI and config parsing
-rw-r--r-- | example/segelboot.cfg | 7 | ||||
-rw-r--r-- | makefile | 1 | ||||
-rwxr-xr-x | run | 11 | ||||
-rw-r--r-- | src/loader/acpi.c | 92 | ||||
-rw-r--r-- | src/loader/cfg.c | 173 | ||||
-rw-r--r-- | src/loader/dev.c | 10 | ||||
-rw-r--r-- | src/loader/fs/ext2.c | 2 | ||||
-rw-r--r-- | src/loader/impl/mb1.c | 9 | ||||
-rw-r--r-- | src/loader/inc/acpi.h | 168 | ||||
-rw-r--r-- | src/loader/inc/cfg.h | 22 | ||||
-rw-r--r-- | src/loader/inc/def.h | 1 | ||||
-rw-r--r-- | src/loader/inc/dev.h | 1 | ||||
-rw-r--r-- | src/loader/inc/impl/mb1.h | 13 | ||||
-rw-r--r-- | src/loader/inc/lib.h | 4 | ||||
-rw-r--r-- | src/loader/lib.c | 36 | ||||
-rw-r--r-- | src/loader/main.c | 6 |
16 files changed, 543 insertions, 13 deletions
diff --git a/example/segelboot.cfg b/example/segelboot.cfg new file mode 100644 index 0000000..17a7d14 --- /dev/null +++ b/example/segelboot.cfg @@ -0,0 +1,7 @@ +TIMEOUT=10 + +# Multiboot 1 +PATH=hda0:/boot/mb1.elf + +# Multiboot 2 +PATH=hda0:/boot/mb2.elf @@ -32,6 +32,7 @@ all: dir $(BLD)/boot.bin dir: @mkdir -p $(BLD)/entry/ @mkdir -p $(BLD)/loader/fs/ + @mkdir -p $(BLD)/loader/impl/ $(BLD)/boot.bin: $(BLD)/loader.bin @$(AS) $(ASFLAGS) -f bin $(SRC)/entry/bootsector.asm -o $@ @@ -93,11 +93,12 @@ build() { $SUDO dd if=build/boot.bin of="$DEV" bs=1 skip=510 seek=510 conv=notrunc status=none # Mount disk and copy files - #mkdir -p mnt/ - #$SUDO mount "$DEV$PART" mnt/ - #$SUDO mkdir -p mnt/boot/ - #$SUDO umount mnt/ || (sync && $SUDO umount mnt/) - #rm -rf mnt/ + mkdir -p mnt/ + $SUDO mount "$DEV$PART" mnt/ + $SUDO mkdir -p mnt/boot/ + $SUDO cp example/segelboot.cfg mnt/boot/ + $SUDO umount mnt/ || (sync && $SUDO umount mnt/) + rm -rf mnt/ $SUDO losetup -d "$DEV" } diff --git a/src/loader/acpi.c b/src/loader/acpi.c new file mode 100644 index 0000000..f7e958c --- /dev/null +++ b/src/loader/acpi.c @@ -0,0 +1,92 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <acpi.h> +#include <lib.h> +#include <pnc.h> + +/** + * General SDP + */ + +static u8 acpi_sdp_verify(struct sdp_header *header) +{ + u8 sum = 0; + + for (u32 i = 0; i < sizeof(struct rsdp); i++) + sum += (u8)(((u8 *)header)[i]); + + return sum == 0; +} + +/** + * General SDT + */ + +static u8 acpi_sdt_verify(struct sdt_header *header) +{ + u8 sum = 0; + + for (u32 i = 0; i < header->length; i++) + sum += (u8)(((u8 *)header)[i]); + + return sum == 0; +} + +static void *acpi_sdt_find(struct rsdt *rsdt, const char *signature) +{ + u32 entries = (rsdt->header.length - sizeof(rsdt->header)) / 4; + + for (u32 i = 0; i < entries; i++) { + struct sdt_header *header = (struct sdt_header *)rsdt->sdt_pointer[i]; + if (memcmp(header->signature, signature, 4) == 0) { + if (acpi_sdt_verify(header)) + return header; + else + break; + } + } + + return NULL; +} + +/** + * RSDP - points to RSDT + */ + +static struct rsdp *acpi_rsdp_find(void) +{ + // Main BIOS area + for (u32 i = 0xe0000; i < 0xfffff; i++) + if (memcmp((u32 *)i, RSDP_MAGIC, 8) == 0) + return (struct rsdp *)i; + + // Or first KB of EBDA? + u8 *ebda = (void *)(*((u16 *)0x40e) << 4); + for (u16 i = 0; i < 1024; i += 16) + if (memcmp(ebda + i, RSDP_MAGIC, 8) == 0) + return (struct rsdp *)(ebda + i); + + return NULL; +} + +/** + * Probe + */ + +void acpi_probe(void) +{ + struct rsdp *rsdp = acpi_rsdp_find(); + assert(rsdp && rsdp->header.revision == 0 && acpi_sdp_verify(&rsdp->header)); + struct rsdt *rsdt = rsdp->rsdt; + assert(rsdt && memcmp(rsdt->header.signature, RSDT_MAGIC, 4) == 0 && + acpi_sdt_verify(&rsdt->header)); + + struct madt *madt = acpi_sdt_find(rsdt, MADT_MAGIC); + struct fadt *fadt = acpi_sdt_find(rsdt, FADT_MAGIC); + struct hpet *hpet = acpi_sdt_find(rsdt, HPET_MAGIC); + + // TODO! + UNUSED(madt); + UNUSED(fadt); + UNUSED(hpet); +} diff --git a/src/loader/cfg.c b/src/loader/cfg.c new file mode 100644 index 0000000..37794e6 --- /dev/null +++ b/src/loader/cfg.c @@ -0,0 +1,173 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <cfg.h> +#include <dev.h> +#include <lib.h> +#include <log.h> +#include <pnc.h> + +// Keys +#define TIMEOUT "TIMEOUT" +#define PATH "PATH" + +// Config struct (gettable using cfg_get) +struct { + u32 timeout; + struct { + u8 exists : 1; + char name[64]; + char path[64]; + } elem[16]; // Up to 16 different selections +} cfg = { 0 }; + +// Config file contents (if found) +static char file[1024] = { 0 }; + +// Find config file +static u8 cfg_find(struct dev *dev) +{ + if (!dev->fs.read) + return 0; // No fs found or not readable - continue! + + s32 res = dev->fs.read("/boot/segelboot.cfg", file, 0, sizeof(file), dev); + if (res > 0) + return 1; // Break foreach + + // Continue foreach + return 0; +} + +// Checks if index is appropriate as some key/value need to be in element +static void cfg_in_element(u8 index) +{ + if (index == 0xff) + panic("No element name given\n"); +} + +// Add/overwrite value by key and element index +static void cfg_add(u8 index, enum cfg_key key, const char *value) +{ + cfg.elem[index].exists = 1; + + switch (key) { + case CFG_NAME: + cfg_in_element(index); + strlcpy(cfg.elem[index].name, value, sizeof(cfg.elem[index].name)); + break; + case CFG_TIMEOUT: + cfg.timeout = atoi(value); + break; + case CFG_PATH: + cfg_in_element(index); + strlcpy(cfg.elem[index].path, value, sizeof(cfg.elem[index].path)); + break; + case CFG_NONE: + default: + panic("Invalid config\n"); + } +} + +// TODO: This code is kind of messy +// Structure per line: KEY=VALUE +static void cfg_parse(void) +{ + // Element index + u8 elem = 0xff; + + // Value per key + char value[64] = { 0 }; + u8 value_index = 0; + + // States + enum cfg_key current = CFG_NONE; // Value key type + u8 state = 0; // 0 is key, 1 is value, 2 is elem + + const char *start = file; // Start is at the beginning of the key + for (const char *p = start; *p; p++) { + if (state == 0) { + // We're at key parsing + if (*p == '\n') { // A key can't just end but ok + start = p + 1; + } else if (*p == '#') { + state = 2; // Let's parse the element name + p++; + continue; + } else if (*p != '=') { + continue; + } + + // The key is now at start until p + u8 diff = p - start; + + // Timeout key + if (diff == sizeof(TIMEOUT) - 1 && memcmp(start, TIMEOUT, diff) == 0) { + current = CFG_TIMEOUT; + state = 1; + continue; + } + + // Path key + if (diff == sizeof(PATH) - 1 && memcmp(start, PATH, diff) == 0) { + current = CFG_PATH; + state = 1; + continue; + } + } else if (state == 1) { + // We're at value parsing + assert(value_index + 1 < (u8)sizeof(value)); + if (*p == '\n') { // Finished + value[value_index] = 0; + cfg_add(elem, current, value); + value_index = 0; + state = 0; + p--; // Repeat parse normally + } else { + value[value_index++] = *p; + } + } else if (state == 2) { + // We're at element name parsing + assert(value_index + 1 < (u8)sizeof(value)); + if (*p == '\n') { // Finished + elem = elem == 0xff ? 0 : elem + 1; + value[value_index] = 0; + cfg_add(elem, CFG_NAME, value); + value_index = 0; + state = 0; + p--; // Repeat parse normally + } else { + value[value_index++] = *p; + } + } + } +} + +const void *cfg_get(u8 index, enum cfg_key key) +{ + switch (key) { + case CFG_NAME: + return &cfg.elem[index].path; + case CFG_TIMEOUT: + return &cfg.timeout; + case CFG_PATH: + return &cfg.elem[index].path; + case CFG_NONE: + default: + return NULL; + } +} + +void cfg_print(void) +{ + log("[CFG] Global: %d\n", cfg.timeout); + + for (u8 i = 0; i < COUNT(cfg.elem) && cfg.elem[i].exists; i++) + log("[CFG] Element: %s at %s\n", cfg.elem[i].name, cfg.elem[i].path); +} + +void cfg_exec(void) +{ + dev_foreach(DEV_DISK, &cfg_find); + if (!file[0]) + panic("No config found\n"); + cfg_parse(); +} diff --git a/src/loader/dev.c b/src/loader/dev.c index e529dfa..591d5a2 100644 --- a/src/loader/dev.c +++ b/src/loader/dev.c @@ -25,6 +25,16 @@ struct dev *dev_get(u8 id) return &devices[id]; } +void dev_foreach(enum dev_type type, u8 (*cb)(struct dev *)) +{ + for (u8 i = 0; i < COUNT(devices); i++) { + struct dev *dev = &devices[i]; + if (dev->type == type) + if (cb(dev)) + break; + } +} + u8 dev_register(enum dev_type type, char *name, u32 data, s32 (*read)(void *, u32, u32, struct dev *), s32 (*write)(const void *, u32, u32, struct dev *)) diff --git a/src/loader/fs/ext2.c b/src/loader/fs/ext2.c index fd46ca6..a7d4662 100644 --- a/src/loader/fs/ext2.c +++ b/src/loader/fs/ext2.c @@ -134,7 +134,7 @@ static u32 ext2_find_inode(const char *name, u32 dir_inode, struct dev *dev) } d = (struct ext2_dirent *)((u32)d + d->total_len); - } while (sum < (1024 * i.blocks / 2)); + } while (sum < (BLOCK_SIZE * i.blocks / 2)); return (unsigned)-1; } diff --git a/src/loader/impl/mb1.c b/src/loader/impl/mb1.c new file mode 100644 index 0000000..5265082 --- /dev/null +++ b/src/loader/impl/mb1.c @@ -0,0 +1,9 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <impl/mb1.h> + +u8 mb1_probe(struct dev *dev) +{ + (void)dev; + return 1; +} diff --git a/src/loader/inc/acpi.h b/src/loader/inc/acpi.h new file mode 100644 index 0000000..f7626e9 --- /dev/null +++ b/src/loader/inc/acpi.h @@ -0,0 +1,168 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Many huge structures from ACPI spec + +#ifndef ACPI_H +#define ACPI_H + +#include <def.h> + +#define RSDP_MAGIC "RSD PTR " +#define RSDT_MAGIC "RSDT" +#define MADT_MAGIC "APIC" +#define FADT_MAGIC "FACP" +#define HPET_MAGIC "HPET" + +/** + * General headers + */ + +struct sdt_header { + u8 signature[4]; + u32 length; + u8 revision; + u8 checksum; + u8 oem_id[6]; + u8 oem_table_id[8]; + u32 oem_revision; + u32 creator_id; + u32 creator_revision; +}; + +struct sdp_header { + u8 signature[8]; + u8 checksum; + u8 oem_id[6]; + u8 revision; +}; + +struct generic_address { + u8 address_space; + u8 bit_width; + u8 bit_offset; + u8 access_size; + u32 phys_high; + u32 phys_low; +}; + +/** + * RSDT + */ + +struct rsdt { + struct sdt_header header; + u32 sdt_pointer[]; +}; + +/** + * RSDP - points to RSDT + */ + +struct rsdp { + struct sdp_header header; + struct rsdt *rsdt; +}; + +/** + * MADT + */ + +struct madt_entry_header { + u8 type; + u8 length; +}; + +struct madt { + struct sdt_header header; + u32 local_address; + u32 flags; + struct madt_entry_header entry; +} PACKED; + +/** + * FADT + */ + +struct fadt { + struct sdt_header header; + u32 firmware_ctrl; + u32 dsdt; + u8 reserved; + u8 preferred_power_mgmt; + u16 sci_interrupt; + u32 smi_command_port; + u8 acpi_enable; + u8 acpi_disable; + u8 s4_bios_req; + u8 pstate_control; + u32 pm1a_event_block; + u32 pm1b_event_block; + u32 pm1a_control_block; + u32 pm1b_control_block; + u32 pm2_control_block; + u32 pm_timer_block; + u32 gpe0_block; + u32 gpe1_block; + u8 pm1_event_length; + u8 pm1_control_length; + u8 pm2_control_length; + u8 pm_timer_length; + u8 gpe0_length; + u8 gpe1_length; + u8 gpe1_base; + u8 c_state_control; + u16 worst_c2_latency; + u16 worst_c3_latency; + u16 flush_size; + u16 flush_stride; + u8 duty_offset; + u8 duty_width; + u8 day_alarm; + u8 month_alarm; + u8 century; + + // Used since ACPI 2.0+ + u16 boot_architecture_flags; + + u8 reserved2; + u32 flags; + struct generic_address reset_reg; + u8 reset_value; + u8 reserved3[3]; + + // Available on ACPI 2.0+ + u32 x_firmware_control_high; + u32 x_firmware_control_low; + u32 x_dsdt_high; + u32 x_dsdt_low; + + struct generic_address x_pm1a_event_block; + struct generic_address x_pm1b_event_block; + struct generic_address x_pm1a_control_block; + struct generic_address x_pm1b_control_block; + struct generic_address x_pm2_control_block; + struct generic_address x_pm_timer_block; + struct generic_address x_gpe0_block; + struct generic_address x_gpe1_block; +} PACKED; + +/** + * HPET + */ + +struct hpet { + struct sdt_header header; + u8 hardware_rev_id; + u8 comparator_count : 5; + u8 counter_size : 1; + u8 reserved : 1; + u8 legacy_replacement : 1; + u16 pci_vendor_id; + struct generic_address address; + u8 hpet_number; + u16 minimum_tick; + u8 page_protection; +} PACKED; + +void acpi_probe(void); + +#endif diff --git a/src/loader/inc/cfg.h b/src/loader/inc/cfg.h new file mode 100644 index 0000000..a214db2 --- /dev/null +++ b/src/loader/inc/cfg.h @@ -0,0 +1,22 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef CFG_H +#define CFG_H + +#include <def.h> + +// Global config element index (can actually be anything but wth) +#define CFG_GLOBAL 0 + +enum cfg_key { + CFG_NONE, + CFG_NAME, + CFG_TIMEOUT, + CFG_PATH, +}; + +const void *cfg_get(u8 index, enum cfg_key key); +void cfg_exec(void); +void cfg_print(void); + +#endif diff --git a/src/loader/inc/def.h b/src/loader/inc/def.h index cb41c78..3532bc1 100644 --- a/src/loader/inc/def.h +++ b/src/loader/inc/def.h @@ -23,6 +23,7 @@ typedef __builtin_va_list va_list; #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define ABS(a) (((a) < 0) ? -(a) : (a)) #define COUNT(a) (sizeof(a) / sizeof 0 [a]) +#define UNUSED(a) ((void)a); #define PACKED __attribute__((packed)) diff --git a/src/loader/inc/dev.h b/src/loader/inc/dev.h index 6fcbf25..9d9913e 100644 --- a/src/loader/inc/dev.h +++ b/src/loader/inc/dev.h @@ -25,6 +25,7 @@ struct dev { }; struct dev *dev_get(u8 id); +void dev_foreach(enum dev_type type, u8 (*cb)(struct dev *)); // cb=1 => break u8 dev_register(enum dev_type type, char *name, u32 data, s32 (*read)(void *, u32, u32, struct dev *), s32 (*write)(const void *, u32, u32, struct dev *)); diff --git a/src/loader/inc/impl/mb1.h b/src/loader/inc/impl/mb1.h new file mode 100644 index 0000000..fa0efc1 --- /dev/null +++ b/src/loader/inc/impl/mb1.h @@ -0,0 +1,13 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef MB1_H +#define MB1_H + +#include <def.h> +#include <dev.h> + +#define MB1_MAGIC 0x1badb002 + +u8 mb1_probe(struct dev *dev); + +#endif diff --git a/src/loader/inc/lib.h b/src/loader/inc/lib.h index e811670..2f49007 100644 --- a/src/loader/inc/lib.h +++ b/src/loader/inc/lib.h @@ -12,7 +12,9 @@ s32 strncmp(const char *s1, const char *s2, u32 n); void *memcpy(void *dest, const void *src, u32 n); void *memset(void *dest, u32 val, u32 n); +s32 memcmp(const void *s1, const void *s2, u32 n); -int itoa(s32 value, char *buffer, u32 base); +s32 itoa(s32 value, char *buffer, u32 base); +s32 atoi(const char *inp); #endif diff --git a/src/loader/lib.c b/src/loader/lib.c index 83b1e25..a5a1aee 100644 --- a/src/loader/lib.c +++ b/src/loader/lib.c @@ -49,10 +49,10 @@ s32 strncmp(const char *s1, const char *s2, u32 n) const u8 *c1 = (const u8 *)s1; const u8 *c2 = (const u8 *)s2; u8 ch; - int d = 0; + s32 d = 0; while (n--) { - d = (int)(ch = *c1++) - (int)*c2++; + d = (s32)(ch = *c1++) - (s32)*c2++; if (d || !ch) break; } @@ -107,18 +107,31 @@ void *memset(void *dest, u32 val, u32 n) return dest; } +s32 memcmp(const void *s1, const void *s2, u32 n) +{ + const u8 *a = (const u8 *)s1; + const u8 *b = (const u8 *)s2; + for (u32 i = 0; i < n; i++) { + if (a[i] < b[i]) + return -1; + else if (b[i] < a[i]) + return 1; + } + return 0; +} + /** * Conversion */ -int itoa(s32 value, char *buffer, u32 base) +s32 itoa(s32 value, char *buffer, u32 base) { char tmp[16]; char *tp = tmp; - int i; + s32 i; unsigned v; - int sign = (base == 10 && value < 0); + s32 sign = (base == 10 && value < 0); if (sign) v = -value; else @@ -133,7 +146,7 @@ int itoa(s32 value, char *buffer, u32 base) *tp++ = i + 'a' - 10; } - int len = tp - tmp; + s32 len = tp - tmp; if (sign) { *buffer++ = '-'; @@ -146,3 +159,14 @@ int itoa(s32 value, char *buffer, u32 base) return len; } + +// From stackoverflow +s32 atoi(const char *inp) +{ + s32 ret = 0; + while (*inp) { + ret = (ret << 3) + (ret << 1) + (*inp) - '0'; + inp++; + } + return ret; +} diff --git a/src/loader/main.c b/src/loader/main.c index 7c50e62..f01a93b 100644 --- a/src/loader/main.c +++ b/src/loader/main.c @@ -1,5 +1,7 @@ // MIT License, Copyright (c) 2021 Marvin Borner +#include <acpi.h> +#include <cfg.h> #include <def.h> #include <dev.h> #include <ide.h> @@ -21,9 +23,13 @@ int start(void) pic_install(); idt_install(); + acpi_probe(); pci_probe(); dev_print(); + cfg_exec(); + cfg_print(); + // Sleep and wait for interrupts while (1) __asm__ volatile("hlt"); |