diff --git a/emul b/emul index 95626fd..5becde2 100755 --- a/emul +++ b/emul @@ -58,7 +58,7 @@ function main() { make all || exit 1 util/build_iso.sh || exit 1 echo > serial.log - emulator="qemu-system-x86_64 -cdrom mittos64.iso -serial file:serial.log ${EMULPARAM[@]}" + emulator="qemu-system-x86_64 -cdrom mittos64.iso -serial file:serial.log -smp 4 ${EMULPARAM[@]}" debugger=$(which x86_64-elf-linux-gdb) if [[ (-n ${EMULVNC}) ]]; then diff --git a/kernel/arch/acpi.c b/kernel/arch/acpi.c new file mode 100644 index 0000000..441fb57 --- /dev/null +++ b/kernel/arch/acpi.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include + +RSDP_st *find_rsdp() +{ + // The Root System Description Pointer (RSDP) should be found either + // - in the first 1 KB of the EBDA + // - between 0xE0000 and 0xFFFFF + // We'll only try the second alternative for now + + uintptr_t start = KERNEL_OFFSET + 0xE0000; + uintptr_t end = KERNEL_OFFSET + 0xFFFFF; + + uint8_t *p = (void *)start; + while((uintptr_t)p < end) + { + // The RSDP is identified by a signature string + if(!(memcmp(p, "RSD PTR ", 8))) + { + // Make sure we got it right by calculating the checksum + uint8_t checksum = 0; + for(int i = 0; i < 20; i++) + checksum += p[i]; + if(!checksum) + break; + } + // The RSDP must be 16-byte aligned + p = incptr(p, 16); + } + if((uintptr_t)p >= end) + return 0; + return (void *)p; +} + +SDT_header *find_SDT(RSDP_st *rsdp, char *signature) +{ + // Scan through the RSDT or XSDT for a header with the wanted signature + + // Read RSDT if revision <= 1.0 + // else read XSDT + unsigned int bpp = (!rsdp->revision)?4:8; + SDT_header *rsdt = (bpp == 4) ? P2V(rsdp->RSDT_p) : P2V(rsdp->XSDT_p); + + int entries = (rsdt->length - sizeof(SDT_header))/bpp; + for(int i = 0; i < entries; i++) + { + // 32 bit pointers if revision <= 1.0 + // otherwise 64 bit pointers + SDT_header *h = (bpp == 4) ? + P2V(*(uint32_t*)&rsdt->data[i*bpp]) : + P2V(*(uint64_t*)&rsdt->data[i*bpp]); + + // Return pointer if signature is correct + if(!memcmp(h->signature, signature, 4)) + return h; + } + return 0; +} + +void parse_MADT(SDT_header *header) +{ + MADT_header *madt = (MADT_header *)header->data; + // Save the memory mapping of the local APIC + + // TODO: In bochs, there are MADT entries with 0 length. I assume parsing should stop here. + // TODO: Look this up + for(MADT_field *f = (void*)madt->fields; + (uintptr_t)f < (uintptr_t)madt + header->length && f->length; + f = incptr(f, f->length)) + { + switch(f->type) + { + case 0: // Processor Local APIC entry + debug_info("ACPI - Processor id:%x LAPIC:%x", f->proc.proc_ID, f->proc.APIC_ID); + if(f->proc.flags & 0x1) + { + debug(" enabled"); + } + debug("\n"); + break; + case 1: // I/O APIC entry + debug_info("ACPI - IOAPIC id:%x address:%x\n", f->IOAPIC.APIC_ID, f->IOAPIC.address); + break; + case 2: // Interrupt Source Override + debug_info("ACPI - Interrupt source override %x->%x\n", f->ISO.irq, f->ISO.interrupt); + break; + default: + break; + } + } +} + +void acpi_init() +{ + RSDP_st *rsdp; + if(!(rsdp = mboot_data.rsdp)) + { + if(!(rsdp = find_rsdp())) + { + debug_error("PANIC: ACPI - No RSDP found!"); + for(;;); + } + } + + debug_info("ACPI - ACPI version %s\n", (rsdp->revision)?"2.0":"1.0"); + + // Scan for MADT + SDT_header *madt = find_SDT(rsdp, "APIC"); + // Read processor info from MADT + parse_MADT(madt); + // Ignore all other tables for now + +} diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index e3eb89e..68605ac 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -7,6 +7,7 @@ #include #include #include +#include void thread_function() { @@ -31,11 +32,8 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) gdt_init(); scheduler_init(); pic_init(); + acpi_init(); - debug_info("CPUID - max function number: Normal:%x, Extended:%x\n", cpuid_max, cpuid_maxx); - debug_info("CPUID - has MSR:%d\n", CPUID_FEATURE_MSR); - debug_info("CPUID - has APIC:%d\n", CPUID_FEATURE_APIC); - debug_info("CPUID - has SYSCALL:%d\n", CPUID_FEATURE_SYSCALL); process_t *p1 = process_spawn(0); process_t *p2 = process_spawn(p1); diff --git a/kernel/boot/multiboot.c b/kernel/boot/multiboot.c index 0279de5..3d67200 100644 --- a/kernel/boot/multiboot.c +++ b/kernel/boot/multiboot.c @@ -70,6 +70,11 @@ void parse_multiboot2() mboot_data.mmap = tag->data; debug_ok("MBOOT2 - handle "); break; + case MBOOT2_ACPI_V1: + case MBOOT2_ACPI_V2: + mboot_data.rsdp = &tag->data; + debug_ok("[MBOOT2] %x handle ", mboot_data.rsdp); + break; default: debug_warning("MBOOT2 - ignore "); break; @@ -129,6 +134,8 @@ int multiboot_page_used(uintptr_t addr) mboot2_tags_head *data = mboot_data.data; if(overlapsz(addr, PAGE_SIZE, V2P(data), data->total_size)) return 1; + if(mboot_data.rsdp && overlapsz(addr, PAGE_SIZE, mboot_data.rsdp, 1)) + return 1; } return 0; } diff --git a/kernel/include/acpi.h b/kernel/include/acpi.h new file mode 100644 index 0000000..d29b680 --- /dev/null +++ b/kernel/include/acpi.h @@ -0,0 +1,63 @@ +#pragma once +#include + +typedef struct RSDP_st +{ + unsigned char signature[8]; + uint8_t checksum; + unsigned char OEMID[6]; + uint8_t revision; + uint32_t RSDT_p; + // The following are only available if revision != 0 + uint32_t length; + uint64_t XSDT_p; + uint8_t checksum2; + uint8_t reserved[3]; +}__attribute__ ((packed)) RSDP_st; + +typedef struct SDT_header +{ + unsigned char signature[4]; + uint32_t length; + uint8_t revision; + uint8_t checksum; + unsigned char OEMID[6]; + unsigned char OEMtable[8]; + uint32_t OEMrevision; + uint32_t CreatorID; + uint32_t CreatorRevision; + uint8_t data[]; +}__attribute__ ((packed)) SDT_header; + +typedef struct MADT_header +{ + uint32_t LCA; + uint32_t flags; + uint8_t fields[]; +}__attribute__((packed)) MADT_header; +typedef struct MADT_field +{ + uint8_t type; + uint8_t length; + union{ + struct{ + uint8_t proc_ID; + uint8_t APIC_ID; + uint32_t flags; + }__attribute__((packed)) proc; + struct { + uint8_t APIC_ID; + uint8_t reserved; + uint32_t address; + uint32_t base; + }__attribute__((packed)) IOAPIC; + struct { + uint8_t bus; + uint8_t irq; + uint32_t interrupt; + uint16_t flags; + }__attribute__((packed)) ISO; + }; +}__attribute__((packed)) MADT_field; + +void acpi_init(); diff --git a/kernel/include/multiboot.h b/kernel/include/multiboot.h index 9b953a5..c311bf4 100644 --- a/kernel/include/multiboot.h +++ b/kernel/include/multiboot.h @@ -80,6 +80,8 @@ typedef struct { #define MBOOT2_CMDLINE 1 #define MBOOT2_BOOTLOADER 2 #define MBOOT2_MMAP 6 + #define MBOOT2_ACPI_V1 14 + #define MBOOT2_ACPI_V2 15 // Multiboot tags are padded to a multiple of 8 bytes #define next_tag(tag) ((void *)((((uintptr_t)tag) + tag->size + 7) & ~0x7)) @@ -92,6 +94,7 @@ typedef struct { char *bootloader; void *mmap; uint32_t mmap_size; + void *rsdp; }; extern struct mboot_data_st mboot_data;