summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarvin Borner2021-07-05 23:22:24 +0200
committerMarvin Borner2021-07-05 23:27:40 +0200
commit23aa6f84539ba320a91235fb81681d0754178f62 (patch)
tree972b0a4abc41900538bda23f4ac2145abf94e369
parentd1476974cd612412eefc40c6dc72ba66191136fd (diff)
ACPI and config parsing
-rw-r--r--example/segelboot.cfg7
-rw-r--r--makefile1
-rwxr-xr-xrun11
-rw-r--r--src/loader/acpi.c92
-rw-r--r--src/loader/cfg.c173
-rw-r--r--src/loader/dev.c10
-rw-r--r--src/loader/fs/ext2.c2
-rw-r--r--src/loader/impl/mb1.c9
-rw-r--r--src/loader/inc/acpi.h168
-rw-r--r--src/loader/inc/cfg.h22
-rw-r--r--src/loader/inc/def.h1
-rw-r--r--src/loader/inc/dev.h1
-rw-r--r--src/loader/inc/impl/mb1.h13
-rw-r--r--src/loader/inc/lib.h4
-rw-r--r--src/loader/lib.c36
-rw-r--r--src/loader/main.c6
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
diff --git a/makefile b/makefile
index 288f029..3c52077 100644
--- a/makefile
+++ b/makefile
@@ -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 $@
diff --git a/run b/run
index 4142232..31287fc 100755
--- a/run
+++ b/run
@@ -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");