From 9b22a6965579ea1867aea291d910c96f386b518b Mon Sep 17 00:00:00 2001 From: Brett Weiland Date: Tue, 24 Aug 2021 14:09:29 -0500 Subject: major backup 8.24.21 --- src/kernel/acpi.c | 179 ++++++++++--- src/kernel/drivers/serial.c | 39 --- src/kernel/drivers/video.c | 9 - src/kernel/heap.c | 211 ++++++++++++++++ src/kernel/int.c | 253 +++++++++++++++++++ src/kernel/io.c | 24 ++ src/kernel/isv.c | 12 + src/kernel/isv_asm.asm | 65 +++++ src/kernel/kernel.c | 46 ++-- src/kernel/klog.c | 100 ++++++++ src/kernel/libc.c | 19 +- src/kernel/madt.c | 179 +++++++++++++ src/kernel/page.c | 573 +++++++++++++++++++++++++++--------------- src/kernel/panic.c | 80 ++++-- src/kernel/printf.c | 6 + src/kernel/random.c | 36 +++ src/kernel/smp.c | 80 ++++++ src/kernel/smp_trampoline.asm | 140 +++++++++++ src/kernel/testmalloc.c | 35 +++ src/kernel/timer.c | 296 ++++++++++++++++++++++ src/kernel/video.c | 10 + 21 files changed, 2059 insertions(+), 333 deletions(-) delete mode 100644 src/kernel/drivers/serial.c delete mode 100644 src/kernel/drivers/video.c create mode 100644 src/kernel/heap.c create mode 100644 src/kernel/int.c create mode 100644 src/kernel/io.c create mode 100644 src/kernel/isv.c create mode 100644 src/kernel/isv_asm.asm create mode 100644 src/kernel/klog.c create mode 100644 src/kernel/madt.c create mode 100644 src/kernel/random.c create mode 100644 src/kernel/smp.c create mode 100644 src/kernel/smp_trampoline.asm create mode 100644 src/kernel/testmalloc.c create mode 100644 src/kernel/timer.c create mode 100644 src/kernel/video.c (limited to 'src/kernel') diff --git a/src/kernel/acpi.c b/src/kernel/acpi.c index 0c22fe4..e5a6e4d 100644 --- a/src/kernel/acpi.c +++ b/src/kernel/acpi.c @@ -1,58 +1,169 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include -static int RSDP_verify(void *rsdp_pointer) { - printf("Verifying potential RSDP at address 0x%p... ", rsdp_pointer); - union rsdp_t *rsdp = rsdp_pointer; + +//finding rsdp +typedef struct rsdp { + char sig[8]; + uint8_t checksum; + char OEMID[6]; + uint8_t revision; + uint32_t rsdt; + + //these only exist on REV > 1 + uint32_t len; + uint64_t xsdt; + uint8_t extended_checksum; + uint8_t reserved[3]; + +} __attribute__((packed)) root_sdp; + + +//root descriptor SDTs +struct rsdt { + sdt_head header; + uint32_t sdt_pointers[]; +} __attribute__((packed)); + +struct xsdt { + sdt_head header; + uint64_t sdt_pointers[]; +} __attribute__((packed)); + +root_sdp *rsdp; + + + +void debug_acpi() { + sdt_head *sdt; + int sdt_i, sdt_cnt; + + if(rsdp->revision) { + struct xsdt *root = PHYS_TO_VIRT(rsdp->xsdt); + sdt_cnt = (root->header.length - sizeof(root->header)) / 8; + printf("sdts found in apic headers: %i\n", sdt_cnt); + for(sdt_i = 0; sdt_i < sdt_cnt; sdt_i++) { + sdt = PHYS_TO_VIRT(root->sdt_pointers[sdt_i]); + printf("ACPI debug:%.4s\n", sdt->sig); + } + } + else { + struct rsdt *root = PHYS_TO_VIRT((uint64_t)rsdp->rsdt); + sdt_cnt = (root->header.length - sizeof(root->header)) / 4; + printf("sdts found in apic headers: %i\n", sdt_cnt); + for(sdt_i = 0; sdt_i < sdt_cnt; sdt_i++) { + sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]); + printf("ACPI debug:%.4s\n", sdt->sig); + } + } +} + +//TODO clean up confusing variable name rsdt +void *find_sdt(int type) { + char sig[4]; + sdt_head *sdt; + int sdt_i, sdt_cnt; + + //If we never need to expand this, then you can clean it up. + switch(type) { + case SDT_MADT: + strcpy(sig, "APIC"); + break; + case SDT_HPET: + strcpy(sig, "HPET"); + break; + } + + if(rsdp->revision) { + struct xsdt *root = PHYS_TO_VIRT(rsdp->xsdt); + sdt_cnt = (root->header.length - sizeof(root->header)) / 8; + for(sdt_i = 0; sdt_i < sdt_cnt - 1; sdt_i++) { + sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]); + if(!(strncmp(sdt->sig, sig, 4))) { + return sdt; + } + } + } + else { + struct rsdt *root = PHYS_TO_VIRT((uint64_t)rsdp->rsdt); + sdt_cnt = (root->header.length - sizeof(root->header)) / 4; + for(sdt_i = 0; sdt_i < sdt_cnt - 1; sdt_i++) { + sdt = PHYS_TO_VIRT((uint64_t)root->sdt_pointers[sdt_i]); + if(!(strncmp(sdt->sig, sig, 4))) { + return sdt; + } + } + } + return 0; +} + +bool verify_sdt(sdt_head *sdt) { uint8_t checksum = 0; - char *rsdp_csm_ptr = rsdp_pointer; + for(int i = 0; i < sdt->length; i++) checksum += ((uint8_t *)sdt)[i]; + return checksum == 0; +} + +static root_sdp *verify_sdp(root_sdp *uv_rsdp) { + char *rsdp_char_ptr = (char *)uv_rsdp; int i; - if(checksum) return 0; - if(rsdp->v1.version) { - printf("APCI revision > 2.\n"); - checksum = 0; - printf("len : %i\n", rsdp->v2.len); - for(i = 0; i < rsdp->v2.len; i++) { - checksum += rsdp_csm_ptr[i]; + uint8_t checksum = 0; + if(uv_rsdp->revision) { + for(i = 0; i < uv_rsdp->len; i++) { + checksum += rsdp_char_ptr[i]; } } else { - printf("APCI revision 1.\n"); for(i = 0; i <= 20; i++) { - checksum += rsdp_csm_ptr[i]; + checksum += rsdp_char_ptr[i]; } } - if(checksum) { - return 0; - printf("Invalid, searching on.\n"); + if(!checksum) { + printf("Found RSDP revision %i at address %x.\n", uv_rsdp->revision, uv_rsdp); + return uv_rsdp; } - printf("RSDP Verified!\n"); - return 1; + printf("Skipped over invalid RSDP at 0x%p.\n", uv_rsdp); + return 0; } -rsdp_t *find_RSDP() { + +void find_root_sdp() { const char sig[9] = "RSD PTR "; uintptr_t *p = (void *)0x040e; uintptr_t *ebda_unshifted = (void *)p; + bool rsdt_verified; - void *ebda = (void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff); + void *ebda = PHYS_TO_VIRT((void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff)); - for(void *i = ebda; i <= ebda + 64000; i += 16) { - if(!(memcmp(sig, i, 8))) { - if(RSDP_verify(i)) { - return(i); - } - } + + + for(void *i = ebda; i <= ebda + 64000; i += 16) + if(!(memcmp(sig, i, 8)) && ((rsdp = verify_sdp(i)))) break; + + + for(void *i = PHYS_TO_VIRT(0xe0000); i <= PHYS_TO_VIRT(0xfffff); i += 16) + if(!(memcmp(sig, i, 8)) && ((rsdp = verify_sdp(i)))) break; + + if(!(rsdp)) { + printf("Couldn't find the RSDP... not sure what to do now.\n"); + PANIC(KERNEL_PANIC_RSDP_UNFOUND); + } + + if(rsdp->revision) { + rsdt_verified = verify_sdt(PHYS_TO_VIRT(rsdp->xsdt)); + } + else { + rsdt_verified = verify_sdt(PHYS_TO_VIRT((uint64_t)rsdp->rsdt)); } - for(void *i = (void *)0xe0000; i <= (void *)0xfffff; i += 16) { - if(!(memcmp(sig, i, 8))) { - if(RSDP_verify(i)) { - return(i); - } - } + if(!(rsdt_verified)) { + PANIC(KERNEL_PANIC_INVALID_RSDT); } } - - diff --git a/src/kernel/drivers/serial.c b/src/kernel/drivers/serial.c deleted file mode 100644 index 25f89ad..0000000 --- a/src/kernel/drivers/serial.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -static inline void outb(uint16_t port, uint8_t value) { - asm volatile( - "outb %0, %1" :: "a"(value), "Nd"(port) - ); -} - -static inline uint8_t inb(uint16_t port) { - uint8_t ret; - asm volatile( - "inb %1, %0" : "=a"(ret) : "Nd"(port) - ); - return(ret); -} - -int init_serial(uint16_t port) { - outb(port + 1, 0x00); - outb(port + 3, 0x80); - outb(port + 0, 0x06); - outb(port + 1, 0x00); - outb(port + 3, 0x03); - outb(port + 2, 0xc7); - outb(port + 4, 0x0b); - outb(port + 4, 0x1e); - - outb(port + 0, 0xae); // test char - - if(inb(port + 0) != 0xae) - return 1; - - outb(port + 4, 0x0f); // dissable interupts - return 0; -} - -void _putchar_serial(uint16_t port, char msg) { - while(!(inb(port + 5) & 0x20)); //wait for transmit to be done - outb(port, msg); -} diff --git a/src/kernel/drivers/video.c b/src/kernel/drivers/video.c deleted file mode 100644 index ab73bb0..0000000 --- a/src/kernel/drivers/video.c +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -//to be implimented when paging is set up - -void dump_video() { - struct mode_info *video = (struct mode_info *)0x600; - printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n", video->width, video->height, video->bpp, video->framebuffer); -} diff --git a/src/kernel/heap.c b/src/kernel/heap.c new file mode 100644 index 0000000..db6392f --- /dev/null +++ b/src/kernel/heap.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +/** a disclaimer- + * I've never made an OS, so I don't know what kind of structures I'll have. + * Because of this, I'm not YET using a slab allocator. + * This allocator allocates sizes of 2^n, starting at 32, which can waste lots of space. + * In other places, you'll see me reallocating when it's not nessesary, + * as if my allocator doesn't over-allocate. + * + * Later in development, I will create a slab allocator, making it so that this isn't an issue. +**/ + + + +#define MIN_CHUNK_ORDER 5 //equal to 32 bytes for heap_chunk struct. Keeping away from 24 for easy division. +#define MAX_CHUNK_I 6 +#define CHUNK_LIST_LEN MAX_CHUNK_I + 1 +#define LOG_SUB 63 - MIN_CHUNK_ORDER +#define PAGE_SIZE 0x1000 //TODO [minor] maybe move this to some header somewhere + +#define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + MIN_CHUNK_ORDER))) +#define CHUNK_INDEX_FROM_SIZE(s) ((63 - MIN_CHUNK_ORDER - __builtin_clzl((s)))) + + +typedef struct __attribute__((packed)) heap_chunk { + unsigned int free:1; + unsigned int size:4; //will use with flags later if needed + unsigned int lsize:4; + unsigned long reserved:55; + struct heap_chunk *fd; + struct heap_chunk *bk; +} chunk; + +struct heap_chunk_roots { + void *fd; +}; + + +//TODO this wastes some memory +chunk arena[CHUNK_LIST_LEN]; + + +void debug_heap() { + chunk *on_chunk, *last_chunk; + size_t chunk_expected_size; + size_t chunk_actual_size; + for(unsigned int l = 0; l < CHUNK_LIST_LEN; l++) { + chunk_expected_size = CHUNK_SIZE_FROM_INDEX(l); + printf("\n%i sized chunks:\n", chunk_expected_size); + for(on_chunk = arena[l].fd; on_chunk != 0; on_chunk = on_chunk->fd) { + chunk_actual_size = CHUNK_SIZE_FROM_INDEX(on_chunk->size); + printf("\t%p", on_chunk); + if(chunk_expected_size != chunk_actual_size) { + printf("\nFound chunk of size %i in %i sized freebin!!!!\n", chunk_actual_size, chunk_expected_size); + hlt(); + } + if(!on_chunk->free) { + printf("\nChunk found in freebin isn't free!\n"); + hlt(); + } + //may take a while + if((uintptr_t)on_chunk & (0x1000 - 1)) { + last_chunk = (void *)on_chunk - CHUNK_SIZE_FROM_INDEX(on_chunk->lsize); + if(last_chunk->size != on_chunk->lsize) { + printf("\nChunk before this one is a different size then lsize!"); + hlt(); + } + } + } + } + printf("\n\n"); +} + + + +void malloc_init() { + bzero(&arena, sizeof(arena)); +} + +void free(void *addr) { + chunk *on_chunk, *buddy_chunk, *next_chunk, *chunk_iter; + on_chunk = addr - 24; + + + for(;;) { + if(on_chunk->size == (MAX_CHUNK_I + 1)) { + pfree(on_chunk, 0x1000); + printf("freeing page %p\n", on_chunk); + return; + } + unsigned int chunk_size = CHUNK_SIZE_FROM_INDEX(on_chunk->size); + if((uintptr_t)on_chunk & ((chunk_size * 2) - 1)) { + + buddy_chunk = (void *)on_chunk - CHUNK_SIZE_FROM_INDEX(on_chunk->lsize); + if((buddy_chunk->size != on_chunk->size) || !(buddy_chunk->free)) { + next_chunk = (void *)on_chunk + chunk_size; + break; + } + chunk_iter = buddy_chunk; + + } + else { + + buddy_chunk = (void *)on_chunk + chunk_size; + if((buddy_chunk->size != on_chunk->size) || !(buddy_chunk->free)) { + next_chunk = buddy_chunk; + break; + }; + chunk_iter = on_chunk; + + } + + if(buddy_chunk->fd) (buddy_chunk->fd)->bk = buddy_chunk->bk; + (buddy_chunk->bk)->fd = buddy_chunk->fd; + on_chunk = chunk_iter; + on_chunk->size++; + + } + + + next_chunk->lsize = on_chunk->size; + on_chunk->free = 1; + + on_chunk->bk = (chunk *)&arena[on_chunk->size]; + on_chunk->fd = arena[on_chunk->size].fd; + if(arena[on_chunk->size].fd) (arena[on_chunk->size].fd)->bk = on_chunk; + arena[on_chunk->size].fd = on_chunk; + + + +} + + +static void split_chunk(chunk *full_chunk, unsigned int full_size, unsigned int req_size) { + chunk *on_chunk; + + full_chunk->size = req_size; + full_chunk->free = 0; + + //chunk isn't newly allocated page + //our free funciton won't check lsize if addr is divisible by 0x1000 + if(full_chunk->bk) { + if(full_chunk->fd) (full_chunk->fd)->bk = (chunk *)&arena[full_size]; + arena[full_size].fd = full_chunk->fd; + on_chunk = (void *)full_chunk + CHUNK_SIZE_FROM_INDEX(full_size); + if((uintptr_t)on_chunk & (0x1000 - 1)) on_chunk->lsize = full_size - 1; + } + + on_chunk = (void *)full_chunk + CHUNK_SIZE_FROM_INDEX(req_size); + + for(unsigned int sz = req_size; sz < full_size; sz++) { + on_chunk->lsize = (sz == req_size) ? req_size : sz - 1; + on_chunk->fd = arena[sz].fd; + on_chunk->bk = (chunk *)&arena[sz]; + on_chunk->size = sz; + on_chunk->free = 1; + + arena[sz].fd = on_chunk; + on_chunk = (void *)on_chunk + CHUNK_SIZE_FROM_INDEX(sz); + } +} + + +void *malloc(size_t size) { + size += sizeof(chunk); + chunk *on_chunk; + unsigned int chunk_sz_i; //desired chunk size index + unsigned int chunk_ck_i; //backup chunk size index in case we need to count up + //rounding size to nearest 2^n to find which size it fits into + + if(size < 32) size = 32; + + chunk_sz_i = CHUNK_INDEX_FROM_SIZE(size); + if(size & (size - 1)) chunk_sz_i++; + + if(chunk_sz_i > MAX_CHUNK_I) return(void *)0; + + //search for direct hits + if(arena[chunk_sz_i].fd) { + on_chunk = arena[chunk_sz_i].fd; + if(on_chunk->fd) (on_chunk->fd)->bk = (chunk *)&arena[chunk_sz_i]; + arena[chunk_sz_i].fd = on_chunk->fd; + on_chunk->free = 0; + return (void *)on_chunk + sizeof(chunk); + } + + //search for chunks above our size + for(chunk_ck_i = chunk_sz_i + 1; chunk_ck_i < CHUNK_LIST_LEN; chunk_ck_i++) { + if(arena[chunk_ck_i].fd) { + on_chunk = arena[chunk_ck_i].fd; + split_chunk(on_chunk, chunk_ck_i, chunk_sz_i); + return (void *)on_chunk + sizeof(chunk); + } + } + + on_chunk = (void *)palloc(0x1000); + printf("allocating page %p\n", on_chunk); + + split_chunk(on_chunk, 7, chunk_sz_i); + return (void *)on_chunk + sizeof(chunk); + +} +void *realloc(void *old_chunk, size_t size) { + void *new_chunk = malloc(size); + memcpy(new_chunk, old_chunk, CHUNK_SIZE_FROM_INDEX(((chunk *)(old_chunk-24))->size)); + free(old_chunk); + return new_chunk; +} diff --git a/src/kernel/int.c b/src/kernel/int.c new file mode 100644 index 0000000..34f1c78 --- /dev/null +++ b/src/kernel/int.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SEGMENT_GDT 0 +#define SEGMENT_LDT 1 + + + +//io commands +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +#define ICW4_8086 0x01 + + +// PIC +#define PICM_COMMAND 0x20 +#define PICM_DATA 0x21 + +#define PICS_COMMAND 0xa0 +#define PICS_DATA 0xa1 + +#define KERNEL_IDT_DESC_GATE(addr) \ + ((struct idt_descriptor) { \ + .offset_1 = (uint16_t)((uint64_t)addr & 0xffff), \ + .offset_2 = (uint16_t)((uint64_t)addr >> 16), \ + .offset_3 = (uint32_t)((uint64_t)addr >> 32), \ + .segment = 0x8, \ + .ist = 0, \ + .type = INT_GATE_64, \ + .priv = 0, \ + .reserved = 0, \ + .reserved_1 = 0, \ + .reserved_2 = 0, \ + .present = 1 \ +}) + +#define GDT_ADDR (uint64_t)PHYS_TO_VIRT(0x7e22) + +#define IOAPICR_VER 1 + +struct idt_descriptor { + uint16_t offset_1; + uint16_t segment; + unsigned int ist:3; //interupt stack table offset + unsigned int reserved:5; + unsigned int type:4; + unsigned int reserved_1:1; + unsigned int priv:2; + unsigned int present:1; + uint16_t offset_2; + uint32_t offset_3; + uint32_t reserved_2; +} __attribute__((packed)); + + +struct segment_descriptor { + unsigned int priv:2; + unsigned int type:1; + unsigned int index:13; +} __attribute__((packed)); + +struct idt_reg { + uint16_t size; + uint64_t offset; +} __attribute__((packed)); + +struct gdt_reg { + uint16_t size; + uint64_t offset; +} __attribute__((packed)); + +struct idt_descriptor *idt; + +static struct idt_reg idtr; +struct gdt_reg gdtr = { + .size = 0x17, + .offset = GDT_ADDR +}; + + +lapic_t lapic; //would make this static but it's needed by timer.c +static struct ioapic_fixedlen ioapic; +static uint64_t isr_bitmap[4]; //first 32 is for exceptions; + + +void disable_pic() { + //remapping PIC + outb_wait(PICM_COMMAND, ICW1_INIT | ICW1_ICW4); //initilizing + outb_wait(PICS_COMMAND, ICW1_INIT | ICW1_ICW4); + + outb_wait(PICM_DATA, 32); //IRQ offsets + outb_wait(PICS_DATA, 40); + + outb_wait(PICM_DATA, 4); //notify master of slave + outb_wait(PICS_DATA, 2); //nofity slave of mediocore social ethical standards + + outb_wait(PICM_DATA, ICW4_8086); + outb_wait(PICS_DATA, ICW4_8086); + + + //masking. + outb_wait(PICS_DATA, 0xff); + outb_wait(PICM_DATA, 0xff); +} + +void write_ioapic(void *ioapic_addr, uint32_t reg, uint32_t value) { + uint32_t *ioapic_r = ioapic_addr; + ioapic_r[0] = reg & 0xff; + ioapic_r[4] = value; +} + +uint32_t read_ioapic(void *ioapic_addr, uint32_t reg) { + uint32_t *ioapic_r = ioapic_addr; + ioapic_r[0] = reg & 0xff; + return ioapic_r[4]; +} + +void create_fixed_interrupt(unsigned int irq, struct apic_vt *redirect) { + irq = irq_to_gsi(irq); //make sure there's no redirection entries. + + struct ioapic_t *ioapic_smi = (void *)0; + for(unsigned int i = 0; i < ioapic.count; i++) { + if((irq >= ioapic.ioapic[i].gsi_base) && + (irq < (ioapic.ioapic[i].gsi_base + ioapic.ioapic[i].gsi_count))) { + ioapic_smi = ioapic.ioapic[i].address; + break; + } + } + if(!ioapic_smi) PANIC(KERNEL_PANIC_INVALID_IOAPIC_VEC); + + + write_ioapic(ioapic_smi, (0x10 + (irq * 2)), *(uint32_t *)redirect); + write_ioapic(ioapic_smi, ((0x10 + (irq * 2)) + 1), *(uint64_t *)redirect >> 32); +} + +unsigned int alloc_idt(struct idt_entry *entry) { + unsigned int b, i; + for(b = 0; b < (sizeof(isr_bitmap) / 8); b++) { + for(i = 0; i < 64; i++) { + if(!((isr_bitmap[b] >> i) & 1)) { + isr_bitmap[b] |= (uint64_t)1 << i; + idt[(b * 64) + i] = (struct idt_descriptor) { + .offset_1 = (uint16_t)((uint64_t)entry->addr & 0xffff), + .offset_2 = (uint16_t)((uint64_t)entry->addr >> 16), + .offset_3 = (uint32_t)((uint64_t)entry->addr >> 32), + .segment = 0x8, + .ist = entry->ist, + .type = entry->type, + .priv = entry->priv, + .reserved = 0, + .reserved_1 = 0, + .reserved_2 = 0, + .present = 1 + }; + return i; + } + } + } + return 0; +} + +void modify_idt(struct idt_entry *entry, unsigned int vector) { + idt[vector] = (struct idt_descriptor) { + .offset_1 = (uint16_t)((uint64_t)entry->addr & 0xffff), + .offset_2 = (uint16_t)((uint64_t)entry->addr >> 16), + .offset_3 = (uint32_t)((uint64_t)entry->addr >> 32), + .segment = 0x8, + .ist = entry->ist, + .type = entry->type, + .priv = entry->priv, + .reserved = 0, + .reserved_1 = 0, + .reserved_2 = 0, + .present = 1 + }; +} + +void free_idt(unsigned int entry) { + isr_bitmap[entry / 64] ^= ((uint64_t)1 << (entry & 63)); + idt[entry].present = 0; +} + +inline void clear_int() { + lapic[44] = 0; +} + + +void init_exceptions() { + //for idt index explainations, see include/panic.h + //TODO maybe utalize add_idt_entry? + unsigned int e; + idt[0] = KERNEL_IDT_DESC_GATE(fatal_hwexception); + idt[8] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode); + idt[16] = KERNEL_IDT_DESC_GATE(fatal_hwexception); + idt[17] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode); + idt[30] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode); + for(e = 5; e < 8; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception); + for(e = 10; e < 15; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception_errcode); + for(e = 18; e < 21; e++) idt[e] = KERNEL_IDT_DESC_GATE(fatal_hwexception); +} +//void new_idt + + +void init_interrupts() { + init_madt(); + debug_madt(); + lapic = get_lapic(); + + get_ioapic(&ioapic); + for(unsigned int i = 0; i < ioapic.count; i++) { + ioapic.ioapic[i].gsi_count = ((read_ioapic(ioapic.ioapic[i].address, IOAPICR_VER) >> 16) & 0xff); + printf("Found ioapic %i at addr %p, gsi %i to %i\n", i, ioapic.ioapic[i].address, + ioapic.ioapic[0].gsi_base, ioapic.ioapic[0].gsi_base + ioapic.ioapic[0].gsi_count); + } + + disable_pic(); + + idt = palloc(0x1000); + idtr.size = 0x1000; + idtr.offset = (uint64_t)idt; + + bzero(&isr_bitmap, sizeof(isr_bitmap)); + isr_bitmap[0] = (((uint64_t)1 << 32) - 1); + + //set idt and new gdt + asm("lgdt [%0]\n" + "lidt [%1]\n":: "m"(gdtr), "m"(idtr)); + + + //Spurrious Interrupt (permanent, required for APIC) + idt[SPURRIOUS_VECTOR] = KERNEL_IDT_DESC_GATE(spurrious_int); + + //Spurrious interrupt on IDT + lapic[60] = 0x1ff; //page 395 + + //initlize exceptions + init_exceptions(); + + + //initilize the timers + init_timer(); + asm("sti\n"); +} diff --git a/src/kernel/io.c b/src/kernel/io.c new file mode 100644 index 0000000..1974c35 --- /dev/null +++ b/src/kernel/io.c @@ -0,0 +1,24 @@ +#include +#include +//these functions are assumed not to be time-sensitive. +void outb_wait(uint16_t port, uint8_t value) { + outb(port, value); + io_wait(); +} + +void read_msr(uint32_t addr, uint64_t *value) { + uint32_t low, high; + asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); + *value = low | ((uint64_t)high << 32); +} + +void write_msr(uint32_t addr, uint64_t value) { + uint32_t low = value & UINT32_MAX; + uint32_t high = value >> 32; + asm volatile("wrmsr"::"a"(low), "d"(high), "c"(addr)); +} + +void hlt() { + asm("cli\nhlt"); +} + diff --git a/src/kernel/isv.c b/src/kernel/isv.c new file mode 100644 index 0000000..fbc60c0 --- /dev/null +++ b/src/kernel/isv.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + + +__attribute__((interrupt)) void spurrious_int(void *unused) { + printf("Detected spurrious interrupt, doing nothing.\n"); +} + + + diff --git a/src/kernel/isv_asm.asm b/src/kernel/isv_asm.asm new file mode 100644 index 0000000..b770aaa --- /dev/null +++ b/src/kernel/isv_asm.asm @@ -0,0 +1,65 @@ +global timer_init_pit +global kernel_block +global fatal_hwexception +global fatal_hwexception_errcode +global lapic_timer_racefixer + +extern clear_int +extern panic +extern calibrate_lapic_waiting + +;I need to get my timing right and consistently boot smp, +;_then_ I'll work on cleaning this up. + +timer_init_pit: +cli +mov ecx, DWORD [rbx + 0x390] +mov DWORD [rbx + 0x380], 0 +in al, 0x61 +and al, 0xfe +out 0x61, al +mov DWORD [rbx + 0xb0], 0 +iretq + + +kernel_block: +call clear_int +iretq + + +fatal_hwexception: +push qword rdi +push qword rsi +push qword rdx +push qword rcx +push qword rbx +push qword rax +mov rdi, 0 +mov rdx, rsp +mov rsi, rdx +add rsi, 48 +call panic + +; rdi: reason +; rsi: frame +; rdx: regs + +; 0xffff80000010af70 +fatal_hwexception_errcode: +push qword rdi +push qword rsi +push qword rdx +push qword rcx +push qword rbx +push qword rax +mov rdi, 1 +mov rdx, rsp +mov rsi, rdx +add rsi, 48 +call panic + +lapic_timer_racefixer: ;in case the lapic makes it to zero, impliment me +inc rbx +call clear_int +mov QWORD [rsp], calibrate_lapic_waiting +iretq diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 50e0578..50b8359 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -1,31 +1,45 @@ #include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//testing headers +#include -void main() { - if(!(init_serial(COM1))) { - printf("\nKernal started on CPU 1!\n"); // will detect cpu later - } - - rsdp_t *rsdp; - rsdp = find_RSDP(); - if(!(rsdp)) { - printf("Couldn't find the RSDP... not sure what to do now.\n"); - panic(KERNEL_PANIC_RSDP_UNFOUND, KERNEL_PANIC_INVOKED); - } - dump_video(); - debug_print_memory(); +void main() { +#ifndef SCREEN_OUTPUT + if(init_serial(COM1)) printf("\nKernal started on CPU 1!\n"); +#endif + get_mem_capabilities(); + init_pmap(map_complete_physical()); + unmap_lowmem(); + + + find_root_sdp(); + debug_acpi(); + + init_interrupts(); - init_pmap(); - debug_pmap(); + + randinit(); - panic(KERNEL_PANIC_KERNEL_RETURNED, KERNEL_PANIC_INVOKED); + smp_boot(); + PANIC(KERNEL_PANIC_KERNEL_RETURNED); } diff --git a/src/kernel/klog.c b/src/kernel/klog.c new file mode 100644 index 0000000..52444b1 --- /dev/null +++ b/src/kernel/klog.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include + +//README +//this file has some temporary workarounds until I get further into development +//this isn't going to be the serial driver I end up keeping + +#define VIDEO_BUFFER PHYS_TO_VIRT(0xb8000) +#define MAX_LOOPBACK_ATTEMPTS 20 + +//later we'll set it up for interrupting instead of polling +bool init_serial(uint16_t port) { + outb_wait(port + 1, 0x00); + outb_wait(port + 2, 0x00); + outb_wait(port + 3, 0x80); + outb_wait(port + 0, 0x01); //here + outb_wait(port + 1, 0x00); + outb_wait(port + 3, 0x03); + outb_wait(port + 2, 0xc7); + outb_wait(port + 4, 0x0b); + outb_wait(port + 4, 0x1e); + + + //we shouldn't accept this as a loopback success. + //I'm making an exception because my dell desktop has a faulty serial port + //that requires some extra effort. + + uint8_t loopback_byte; + for(int attempts = 0; attempts < MAX_LOOPBACK_ATTEMPTS; attempts++) { + outb_wait(port + 0, 0xae); // test char + loopback_byte = inb(port); + if(loopback_byte == 0xae) break; + } + + if(loopback_byte != 0xae) { + //I'm sorry if these next few lines give you a stroke. They gave me one. + + //My old Dell test desktop has disfunctional serial hardware that only works after a reboot. + //Seeing we don't have ACPI set up yet, we can't reboot without crashing. + //IM GOING TO REMOVE THIS ONCE I DEVELOP THE "REAL" SERIAL DRIVER!!!! + asm("mov rax, 0\n" + "div rax\n"); + return false; + } + + outb_wait(port + 4, 0x0f); + return true; +} + +void _putchar_serial(uint16_t port, char msg) { + while(!(inb(port + 5) & 0x20)); //wait for transmit to be done + outb_wait(port, msg); +} + +static unsigned int on_char = 0; +static unsigned int on_line = 0; + + +void clear_screen() { + char *screen_buffer = (void *)VIDEO_BUFFER; + for(unsigned int i = 0; i <= (80 * 25); i++) screen_buffer[i * 2] = ' '; + on_char = 0; + on_line = 0; +} + +void next_line() { + if(on_line >= 25) { + on_line = 0; + clear_screen(); + } + else { + on_line++; + } + on_char = 0; +} + +void move_cursor(unsigned int x, unsigned int y) { + //yeah yeah yeah, it doens't test for overflows... I'm gonna delete this once i get serial working + //on my second desktop + on_char = x; + on_line = y; +} + +//until we get serial working on hp +void _putchar_screen(char msg) { + if(on_char >= 80) { + next_line(); + } else if(msg == '\n') { + next_line(); + return; + } + char *screen_buffer = (void *)((uint64_t)VIDEO_BUFFER + ((on_line * 160) + (on_char * 2))); + *screen_buffer = msg; + on_char++; +} diff --git a/src/kernel/libc.c b/src/kernel/libc.c index c786cd0..4278281 100644 --- a/src/kernel/libc.c +++ b/src/kernel/libc.c @@ -3,7 +3,7 @@ // TODO clean up variable names int strncmp(const char *s1, const char *s2, unsigned int n) { int i; - for(i = 0; ((i <= n) && (s1[i] != '\0') && (s2[i] != '\0')); i++) { + for(i = 0; ((i < (n - 1)) && (s1[i] != '\0') && (s2[i] != '\0')); i++) { if(s1[i] != s2[i]) { return(s1[i] - s2[i]); } @@ -11,6 +11,13 @@ int strncmp(const char *s1, const char *s2, unsigned int n) { return(s1[i] - s2[i]); } +//this one hasn't been tested +size_t strlen(const char *s) { + size_t len = 0; + while(s[len + 1] != '\0') len++; + return(len); +} + int strcmp(const char *s1, const char *s2) { int i; for(i = 0; ((s1[i] != '\0') && (s2[i] != '\0')); i++) { @@ -25,7 +32,7 @@ int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *p1 = s1; const unsigned char *p2 = s2; int i; - for(i = 0; i < n; i++) { + for(i = 0; i < n - 1; i++) { if(p1[i] != p2[i]) { return(p1[i] - p2[i]); } @@ -41,7 +48,7 @@ void strcpy(char *dest, char *src) { void *memcpy(void *dest, char *src, size_t n) { char *p = dest; - for(unsigned int i = 0; i <= n; i++) { + for(unsigned int i = 0; i < n; i++) { p[i] = src[i]; } return(dest); @@ -56,12 +63,16 @@ void *bzero(void *dest, size_t size) { } //TODO move this function to a seperate math library -unsigned int ceil(double n) { +int ceil(double n) { int low_n = (int)n; if(n == (double)low_n) return(low_n); return(low_n + 1); } +int round(double n) { + return(int)(n + 0.5); +} + void *memset(void *s, char c, size_t n) { char *p = s; for(size_t i = 0; i < n; i++) { diff --git a/src/kernel/madt.c b/src/kernel/madt.c new file mode 100644 index 0000000..62e0535 --- /dev/null +++ b/src/kernel/madt.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//madt entry types. there's more, we don't need em yet +#define LOCAL_APIC 0 +#define IO_APIC 1 +#define IO_INT_OVERRIDE 2 +#define IO_APIC_NMI_SOURCE 3 +#define IO_APIC_NMI 4 +#define MADT_LOCAL_APIC_ADDR_OVERRIDE 5 + +struct madt_sdt { + sdt_head header; + uint32_t apic_base; + uint32_t flags; +} __attribute__((packed)); + +struct madt_entry { + uint8_t type; + uint8_t length; +} __attribute__((packed)); + +struct madt_local_apic { + uint8_t processor_id; + uint8_t apic_id; + uint32_t flags; +} __attribute__((packed)); + +struct madt_local_apic_override { + uint16_t reserved; + void *apic_base; +} __attribute__((packed)); + +struct madt_ioapic { + uint8_t apic_id; + uint8_t reserved; + uint32_t addr; + uint32_t gsi_base; +} __attribute__((packed)); + +struct madt_io_int_override { + uint8_t bus_src; //not sure what this is used for. + uint8_t irq; + uint32_t global_vector; + uint16_t flags; +} __attribute__((packed)); + +static struct madt_sdt *madt; + + +void init_madt() { + madt = find_sdt(SDT_MADT); +} + +void debug_madt() { + struct madt_entry *entry; + for( + entry = (void *)madt + sizeof(*madt); + (void *)entry < (void *)madt + madt->header.length; + entry = (void *)entry + entry->length) { + printf("MADT debug: "); + switch(entry->type) { + case LOCAL_APIC: + printf("local APIC\n"); + break; + case IO_APIC: + printf("IOAPIC\n"); + break; + case IO_INT_OVERRIDE: + printf("IOAPIC interupt override\n"); + break; + case IO_APIC_NMI_SOURCE: + printf("IOAPIC NMI\n"); + break; + case IO_APIC_NMI: + printf("Local APIC NMI\n"); + break; + case MADT_LOCAL_APIC_ADDR_OVERRIDE: + printf("APIC addr override\n"); + break; + default: + printf("other\n"); + break; + } + } +} + +unsigned int irq_to_gsi(unsigned int irq) { + struct madt_io_int_override *irq_override; + struct madt_entry *entry; + + for( + entry = (void *)madt + sizeof(*madt); + (void *)entry < (void *)madt + madt->header.length; + entry = (void *)entry + entry->length) { + + if(entry->type == IO_INT_OVERRIDE) { + irq_override = (void *)entry + 2; + if(irq_override->irq == irq) return irq_override->global_vector; + } + } + return (uint32_t)irq; //no entry found +} + +void get_ioapic(struct ioapic_fixedlen *ret) { + struct madt_entry *entry; + struct madt_ioapic *mpio_entry; + + ret->count = 0; + + for( + entry = (void *)madt + sizeof(*madt); + (void *)entry < (void *)madt + madt->header.length; + entry = (void *)entry + entry->length) { + if(entry->type == IO_APIC) { + mpio_entry = (void *)entry + 2; + if(ret->count) { + ret->ioapic = realloc(ret->ioapic, ++ret->count * sizeof(struct ioapic_t)); + } + else { + ret->ioapic = malloc(++ret->count * sizeof(struct ioapic_t)); + } + ret->ioapic[ret->count - 1].address = PHYS_TO_VIRT((uintptr_t)mpio_entry->addr); + ret->ioapic[ret->count - 1].gsi_base = mpio_entry->gsi_base; + } + } +} + +lapic_t get_lapic() { + struct madt_local_apic_override *ap_override; + struct madt_entry *entry; + + for( + entry = (void *)madt + sizeof(*madt); + (void *)entry < (void *)madt + madt->header.length; + entry = (void *)entry + entry->length) { + + if(entry->type == MADT_LOCAL_APIC_ADDR_OVERRIDE) { + ap_override = (void *)entry + 2; + + return (lapic_t)PHYS_TO_VIRT(ap_override->apic_base); + } + } + return (lapic_t)PHYS_TO_VIRT((uint64_t)madt->apic_base); +} + +void get_coreinfo(struct cores_info *cores) { + struct madt_local_apic *ap_info; + struct madt_entry *entry; + uint32_t unused_cpuid, ebx; + + __get_cpuid(1, &unused_cpuid, &ebx, &unused_cpuid, &unused_cpuid); + cores->bsp = ebx << 24; + + bzero(cores, sizeof(*cores)); + + for( + entry = (void *)madt + sizeof(*madt); + (void *)entry < (void *)madt + madt->header.length; + entry = (void *)entry + entry->length) { + + if(entry->type == LOCAL_APIC) { + ap_info = (void *)entry + 2; + if(ap_info->flags & 1) { + cores->apic_id[cores->corecount] = ap_info->processor_id; + cores->corecount++; + } + } + } +} diff --git a/src/kernel/page.c b/src/kernel/page.c index de4f557..9db8660 100644 --- a/src/kernel/page.c +++ b/src/kernel/page.c @@ -1,12 +1,106 @@ #include -#include #include #include #include +#include +#include #include +#include +#include + +//just using char because c is a lil bitch and won't let us use void +extern char _kernel_shared_zone_begin; + + + +// PAGE MAPPING +#define PAGEMAP_LOCATION 0x10000 + +#define MAX_BUDDY_ORDER 8 +#define PALLOC_AUTO_BLEVEL MAX_BUDDY_ORDER + +typedef struct phys_map { + struct phys_map *next; + unsigned int max_buddy; + uint64_t bsize[MAX_BUDDY_ORDER]; + uint64_t *buddy[MAX_BUDDY_ORDER]; +} pmap_t; + +static pmap_t *first_pmap; + +#define MEM_AVAILABLE 1 +#define MEM_RESERVED 2 +#define MEM_APCI_RECLAIMABLE 3 +#define MEM_APCI_NVS 4 +#define MEM_BAD 5 + +// ZONES +#define ZONE_MAP_PLOC 0x7000 +#define ZONE_MAP PHYS_TO_VIRT(ZONE_MAP_PLOC) + + + +//reorganized (moved) from header +typedef struct __attribute__((packed)) { + unsigned int present : 1; // present, must be one when accessed. + unsigned int read_write : 1; // if set to one, read and write is set + unsigned int user : 1; // For seperating CPL 0-2 and 3+ + unsigned int writethrough_cache : 1; // honestly maybe I should look into caching + unsigned int cachable : 1; // hardware chaching. 0 is enabled, whats the worst that could happen? + unsigned int accessed : 1; // we'll never use any of these! + unsigned int zg0 : 1; // needs to be (and will be) zero'd + unsigned int size : 1; // if set to 1, this entry points to physical memory + unsigned int zg1 : 1; // needs to be (and will be) zero'd + unsigned int software_marks : 3; // available for our own use, I doubt we'll use it in such a simple thing + + uintptr_t base_ptr : 40; + unsigned int avail:11; + unsigned int no_exec:1; +} page_table; + + +struct memory_table { + void *base; + uint64_t length; + uint32_t type; + uint32_t ACPI; +} __attribute__((packed)); + +static bool NX_capable; +static bool huge_page_capable; + + +void get_mem_capabilities() { + uint32_t unused, edx; + __get_cpuid(0x80000001, &unused, &unused, &unused, &edx); + huge_page_capable = (edx >> 26) & 1; + NX_capable = (edx >> 20) & 1; +} + + +void unmap_lowmem() { + struct stack_frame *frame; + + asm("addq rsp, %0\n" + "addq rbp, %0\n" + "mov %0, rbp" + :"=r"(frame) + :"r"(PA_OFFSET)); + + while(frame->next != 0) { + printf("%p\n", frame->function_base); + frame->next = PHYS_TO_VIRT((void *)frame->next); + frame = frame->next; + } + + //[future] + //eventually, you should use the function that unmaps pages when you write it + page_table *entry = (page_table *)PAGEMAP_LOCATION; + entry[0].present = 0; +} void debug_print_memory() { - struct memory_table *memtable = (struct memory_table *)&_meminfo_loc; + struct memory_table *memtable = (void *)ZONE_MAP; printf(" __________________________________________________________________________\n"); printf("| type\tstart\t\t\tend\t\t\tsize\t\t |\n"); printf("|--------------------------------------------------------------------------|\n"); @@ -16,32 +110,39 @@ void debug_print_memory() { printf("----------------------------------------------------------------------------\n"); } +void ram_stresser() { + struct memory_table *memtable = (void *)ZONE_MAP - PA_OFFSET; + memtable[6].length = 0x10000; +} + void debug_pmap() { - struct phys_map* pmap; + pmap_t *pmap = first_pmap; int pmap_i = 0, order; - uint64_t buddy_size, blong_i, bbit_i, buddy_chunksize, omit_cnt; - printf("Maximum buddy order: %u (up to %#x sized chunks)\n", MAX_BUDDY_ORDER, (0x1000 << MAX_BUDDY_ORDER - 1)); - for(pmap = (struct phys_map*)&_stage2_pagetable; pmap != 0; pmap = pmap->next) { + uint64_t blong_i, bbit_i, buddy_chunksize, omit_cnt; + printf("Maximum buddy order: %u (up to %#x sized chunks)\n", MAX_BUDDY_ORDER, ((0x1000 << MAX_BUDDY_ORDER) - 1)); + for(; pmap != 0; pmap = pmap->next) { printf("Table %u:\n" - "\tPhysical Start:\t%#p\n" - "\tTable location:\t%#p\n", pmap_i, pmap->zone_paddr, pmap); + "\tPhysical/pmap start:\t%#p\n" + "\tTable Size:\t%u\n", pmap_i, pmap, + (uint64_t)(pmap->buddy[MAX_BUDDY_ORDER - 1] + pmap->bsize[MAX_BUDDY_ORDER - 1]) - (uint64_t)pmap); + for(order = 0; order <= MAX_BUDDY_ORDER - 1; order++) { buddy_chunksize = (0x1000 << order); //TODO just put it in the for loop - buddy_size = (((order == MAX_BUDDY_ORDER - 1) - ? (uint64_t *)pmap->next : pmap->buddy[order + 1]) - pmap->buddy[order]); printf("\tbuddy[%u]:\n" - "\t\tAddress:\t%#x\n" + "\t\tAddress:\t%#p\n" "\t\tSize:\t\t%u\n" - "\t\tBuddies:\t\t\n", order, pmap->buddy[order], buddy_size); + "\t\tBuddies:\t\t\n", order, pmap->buddy[order], pmap->bsize[order]); omit_cnt = 0; - for(blong_i = 0; blong_i < buddy_size; blong_i++) { + for(blong_i = 0; blong_i < pmap->bsize[order]; blong_i++) { for(bbit_i = 0; bbit_i < 64; bbit_i++) { - if(*(pmap->buddy[order] + blong_i) & ((uint64_t)1 << bbit_i)) { - if((omit_cnt < 20) || (blong_i == buddy_size - 1)) { - printf("address %#x\tbit %u: %p\t is free\n", - pmap->buddy[order] + blong_i, bbit_i, (uint64_t)pmap->zone_paddr + (((blong_i * 64) + bbit_i) * buddy_chunksize)); + if((pmap->buddy[order][blong_i]) & ((uint64_t)1 << bbit_i)) { + if((omit_cnt < 20) || (blong_i == pmap->bsize[order] - 1)) { + printf("address %#p\tbit %u: %p\t is free\n", + pmap->buddy[order] + blong_i, + bbit_i, + ((uint64_t)pmap - PA_OFFSET) + ((((blong_i * 64) + bbit_i) * buddy_chunksize))); } omit_cnt++; if(omit_cnt == 20) { @@ -55,237 +156,291 @@ void debug_pmap() { } } -void init_pmap() { - struct memory_table *zones = (struct memory_table *)&_meminfo_loc; - struct phys_map *pmap = (struct phys_map*)&_stage2_pagetable; +//TODO I know you don't want to, but you need to thoroughly check this. +void pfree(void *addr, size_t size) { + int blevel = 0; + uint64_t *onbyte; //the byte out buddy resides on in the current level + uint64_t page_bitloc; // how many bits we are away from buddy[0]. Helps calculate bitshifts + int bbitlen; //length of free'd area in current level + int lshift; //lshift is how many bits we shift over, rightbit is what it sounds like dumbass + pmap_t *pmap = first_pmap; + + /* note: there's no security check to see if the page is actually allocated, + * or if we are freeing the table itself. + * This should be okay, as only the kernel will be calling it. + * If it gets too messy we can always come back. + */ - unsigned int zone_i, pmap_i = 0; - int budorder; - //we keep this info out of the struct because we won't need it after setting up - uint64_t zone_len[MAX_ZONE_CNT], buddy_bitlen[MAX_ZONE_CNT][MAX_BUDDY_ORDER], *buddy_end; - uint64_t pmap_size, pmap_bbitsize, pmap_blongsize, buddy_size, buddy_bit, pmap_bit; - uint64_t threshold_bitsize, threshold_longsize = 0; + if(((uintptr_t)addr & 4095) || (size & 4095)) { + PANIC(KERNEL_PANIC_INVALID_PFREE); + return; //TODO [minor] some more specificity, not a huge deal + } + size /= 0x1000; + for(; pmap != 0; pmap = pmap->next) { + page_bitloc = (addr - (void *)pmap) / 0x1000; + onbyte = pmap->buddy[0] + (page_bitloc / 64); + if((addr >= (void *)pmap) && onbyte < pmap->buddy[1]) break; + } - - void *paged_mem = (void *)&_stage2_pagetable + 0x200000; - map_page(&_stage2_pagetable, &_stage2_pagetable, PAGE_SIZE_2M); + while(blevel < MAX_BUDDY_ORDER) { + lshift = (page_bitloc / (1 << blevel)) & 63; + onbyte = pmap->buddy[blevel] + ((page_bitloc / 64) / (1 << blevel)); + bbitlen = size / (1 << blevel); - for(zone_i = 0; zones[zone_i].length > 0; zone_i++) { - if((zones[zone_i].type == MEM_AVAILABLE) && (zones[zone_i].ACPI & 1)) { + //TODO clean up this part ------------------------------------------------------------- (below) + if(bbitlen <= 1) { + if(lshift & 1) { + if((*onbyte >> (lshift - 1)) & 1) { + *onbyte &= ~(((uint64_t)1 << (lshift - 1)) | ((uint64_t)1 << lshift)); + size += (1 << blevel); + page_bitloc -= (1 << blevel); + bbitlen = size / (1 << blevel); + } + } + else if((*onbyte >> (lshift + 1)) & 1) { + *onbyte &= ~(((uint64_t)1 << (lshift + 1)) | ((uint64_t)1 << lshift)); + size += (1 << blevel); + bbitlen = size / (1 << blevel); + } + } + else if(((lshift + bbitlen) & 1) && ((*onbyte >> (lshift + bbitlen)) & 1)) { + *onbyte ^= ((uint64_t)1 << (lshift + bbitlen)); + size += (1 << blevel); + bbitlen = size / (1 << blevel); + } + //TODO clean up this part ------------------------------------------------------------- (above) - //hopefully this should never happen... - //I should dig into the docs to check before removing this. - //We also could forget about MAX_ZONE_CNT if we did. - - if(zone_i >= MAX_ZONE_CNT) { - printf("Only %u zones can be used! Modify MAX_ZONE_CNT in paging.h to use all memory.\n", MAX_ZONE_CNT); + if((!((size - 1) & size)) && (bbitlen != 1)) { + blevel = 63 - __builtin_clzl(size); + } + else { + if(bbitlen <= 1) { + *onbyte |= ((uint64_t)1 << lshift); break; + } else if(bbitlen & 1) { //check me + size -= (1 << blevel); + *onbyte |= ((uint64_t)1 << (bbitlen + lshift)); } + blevel++; + } + } +} - if((zones[zone_i].base <= (void*)&_stage2_pagetable) && - (zones[zone_i].base + zones[zone_i].length >= (void *)&_stage2_pagetable)) { - pmap->zone_paddr = &_stage2_pagetable; - zone_len[pmap_i] = zones[zone_i].length - (pmap->zone_paddr - zones[zone_i].base); - } - else { - pmap->zone_paddr = zones[zone_i].base; - zone_len[pmap_i] = zones[zone_i].length; - } +void *palloc(size_t size) { + bool self_alloc; + int min_blevel, blevel; + uint64_t bbit, unshifted_entry, threshold, bloc; //TODO move when you've confirmed casting stuff + uint64_t buddy_i, *ret, *bentry; + int itercount; + pmap_t *pmap = first_pmap; - pmap->buddy[0] = (void *)pmap + sizeof(*pmap); - for(budorder = 1; budorder < MAX_BUDDY_ORDER; budorder++) { - buddy_bitlen[pmap_i][budorder - 1] = GET_BUDDY_BITLEN(zone_len[pmap_i], budorder - 1); - pmap->buddy[budorder] = (uint64_t *)pmap->buddy[budorder - 1] + - LSIZE_FROM_BITLEN(buddy_bitlen[pmap_i][budorder - 1]); - } + if(size == 0) return 0; + if(size & 4095) { + size = DIV_ROUND_UP(size, 0x1000); + } + else { + size = size / 0x1000; + } + + //checking if pmap has been initilized; if not we've been called to self allocate + //the first buddy should never be allocated; that's where our pmap lives + if(pmap->buddy[pmap->max_buddy][0] & 1) { + self_alloc = true; + min_blevel = pmap->max_buddy; + } + else { + //log(size, 2) + self_alloc = false; + min_blevel = 63 - __builtin_clzl(size); + if(size & (size - 1)) min_blevel++; + if(min_blevel > MAX_BUDDY_ORDER - 1) return 0; + } - buddy_bitlen[pmap_i][MAX_BUDDY_ORDER - 1] = GET_BUDDY_BITLEN(zone_len[pmap_i], MAX_BUDDY_ORDER - 1); - pmap->next = (void *)pmap->buddy[MAX_BUDDY_ORDER - 1] + - (LSIZE_FROM_BITLEN(buddy_bitlen[pmap_i][MAX_BUDDY_ORDER - 1]) * 8); + for(blevel = min_blevel; blevel < MAX_BUDDY_ORDER; blevel++) { + for(pmap = first_pmap; pmap != 0; pmap = pmap->next) { - pmap = pmap->next; - pmap_i++; + for(buddy_i = 0; buddy_i < pmap->bsize[blevel]; buddy_i++) { + if(pmap->buddy[blevel][buddy_i] > (uint64_t)0) { + bentry = &pmap->buddy[blevel][buddy_i]; + bbit = __builtin_ctzl(*bentry); + bloc = bbit; - //allocates by an extra sizeof(struct phys_map), - //but were about to discard anyway - while((void *)pmap + sizeof(*pmap) >= paged_mem) { - map_page(paged_mem, paged_mem, PAGE_SIZE_2M); - paged_mem += 0x200000; - } + *bentry ^= (uint64_t)1 << bbit; + + ret = (((buddy_i * 64) + bbit) * (0x1000 << blevel)) + (void *)pmap; + + threshold = 0b11; + + itercount = 1; + for(blevel--; blevel >= 0; blevel--) { + bentry = pmap->buddy[blevel] + ((bentry - pmap->buddy[blevel + 1]) * 2); + itercount++; + if(bloc >= 32) bentry += 1; + bloc = (bloc * 2) & 63; // will be the amount we need to shift + bbit = ceil((float)size / (1 << blevel)); + + unshifted_entry = ((uint64_t)1 << bbit) & threshold; + if(unshifted_entry) { + threshold = ((uint64_t)1 << (bbit * 2)) - 1; + } + else { + threshold = (threshold << 2) | threshold; + } + *bentry |= (unshifted_entry << bloc); + } + if(!self_alloc) bzero(ret, size * 0x1000); + return ret; + } + } } } - pmap_size = (void*)(pmap) - (void*)&_stage2_pagetable; - if(pmap_size >= zone_len[0]) panic(); //TODO debugging + return 0; +} - pmap_i = 0; - for(pmap = (struct phys_map*)&_stage2_pagetable; pmap->next != 0; pmap = pmap->next) { - for(budorder = MAX_BUDDY_ORDER - 1; budorder >= 0; budorder--) { - pmap_bbitsize = ceil((float)pmap_size / ((uint64_t)0x1000 << budorder)); - pmap_blongsize = pmap_bbitsize / 64; - if(budorder == MAX_BUDDY_ORDER - 1) { - buddy_size = (uint64_t *)pmap->next - pmap->buddy[budorder]; - buddy_end = (uint64_t *)pmap->next - 1; +//returns size of pages needed +size_t map_complete_physical() { + uint64_t total_mem; + unsigned int pdpe_cnt, pde_cnt, pde_max_i; + int zone_i, entry_i; + struct memory_table *zones = (void *)ZONE_MAP_PLOC; + - threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2; - } - else { - buddy_size = pmap->buddy[budorder + 1] - pmap->buddy[budorder]; - buddy_end = pmap->buddy[budorder + 1] - 1; + page_table *pml4 = (page_table *)PAGEMAP_LOCATION; + page_table *pdpe = (page_table *)&_kernel_shared_zone_begin; + page_table *pde; - threshold_longsize = threshold_bitsize / 64; - } - pmap_bit = pmap_bbitsize & 63; - buddy_bit = buddy_bitlen[pmap_i][budorder] & 63; + for(zone_i = 0; zones[zone_i].length > 0; zone_i++); + total_mem = (uint64_t)zones[zone_i - 1].base + zones[zone_i - 1].length; + + pdpe_cnt = (total_mem + (0x40000000 - 1)) / 0x40000000; + + entry_i = (PA_OFFSET >> 39) & 0x1ff; + pml4[entry_i].base_ptr = (uintptr_t)&_kernel_shared_zone_begin >> 12; + pml4[entry_i].read_write = 1; + pml4[entry_i].user = 0; + pml4[entry_i].size = 0; + pml4[entry_i].no_exec = 1; + pml4[entry_i].present = 1; - if((pmap_bbitsize >= BITLEN_FROM_LSIZE(buddy_size)) && (pmap == (void *)&_stage2_pagetable)) { - bzero(pmap->buddy[budorder], buddy_size * 8); + if(huge_page_capable) { + for(int pdpe_i = 0; pdpe_i < pdpe_cnt; pdpe_i++) { + pdpe[pdpe_i].base_ptr = pdpe_i << 18; + pdpe[pdpe_i].read_write = 1; + pdpe[pdpe_i].user = 0; + pdpe[pdpe_i].size = 1; + pdpe[pdpe_i].no_exec = NX_capable; + pdpe[pdpe_i].present = 1; + } + return pdpe_cnt * 0x1000; + } + else { + pde_cnt = (total_mem + 0x100000) / 0x200000; + for(int pdpe_i = 0; pdpe_i < pdpe_cnt; pdpe_i++) { + pde = (page_table *)(&_kernel_shared_zone_begin + (pdpe_cnt * 0x1000) + (pdpe_i * 0x1000)); + + if((pdpe_i < pdpe_cnt - 1) || (!(pde_cnt & 511))) { + pde_max_i = 512; } else { - if(budorder == MAX_BUDDY_ORDER - 1) { - if(pmap == (void*)&_stage2_pagetable) { - if(pmap_blongsize) bzero(pmap->buddy[budorder], (pmap_blongsize - 1) * 8); - if(pmap_bit) { - *(pmap->buddy[budorder] + pmap_blongsize) = ~(((uint64_t)1 << pmap_bit) - 1); - } - else { - *(pmap->buddy[budorder] + pmap_blongsize) = UINT64_MAX; - } - if(pmap_blongsize + 1 == buddy_size) { - *buddy_end &= ((uint64_t)1 << buddy_bit) - 1; - } - else { - memset(pmap->buddy[budorder] + pmap_blongsize + 1, UINT8_MAX, (buddy_size - 1) * 8); - if(buddy_bit) { - *buddy_end = ((uint64_t)1 << buddy_bit) - 1; - } - else { - *buddy_end = UINT64_MAX; - } - } - threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2; - } - else { - memset(pmap->buddy[budorder], UINT8_MAX, (buddy_size - 1) * 8); - if(buddy_bit) { - *buddy_end = ((uint64_t)1 << buddy_bit) - 1; - } - else { - *buddy_end = UINT64_MAX; - } - } - } - else if(pmap == (void *)&_stage2_pagetable) { - if(threshold_longsize) bzero(pmap->buddy[budorder], (threshold_longsize - 1) * 8); + pde_max_i = pde_cnt & 511; + } + + pdpe[pdpe_i].base_ptr = (uintptr_t)pde >> 12; + pdpe[pdpe_i].read_write = 1; + pdpe[pdpe_i].user = 0; + pdpe[pdpe_i].size = 0; + pdpe[pdpe_i].no_exec = NX_capable; + pdpe[pdpe_i].present = 1; - if(threshold_bitsize > pmap_bbitsize) - *(pmap->buddy[budorder] + threshold_longsize) = ((uint64_t)1 << ((threshold_bitsize - 1) & 63)); - - if(buddy_size - threshold_longsize) - bzero(pmap->buddy[budorder] + threshold_longsize + 1, buddy_size - threshold_longsize); - if(buddy_bit & 1) { - *buddy_end = ((uint64_t)1 << (buddy_bit - 1)); - } - threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2; - } - else { - bzero(pmap->buddy[budorder], buddy_size); - if(buddy_bit & 1) { - *buddy_end = ((uint64_t)1 << ((buddy_bit) - 1)); - } - } + for(int pde_i = 0; pde_i < pde_max_i; pde_i++) { + pde[pde_i].base_ptr = ((pdpe_i << 9) + pde_i) << 9; + pde[pde_i].read_write = 1; + pde[pde_i].user = 0; + pde[pde_i].size = 1; + pde[pde_i].no_exec = NX_capable; + pde[pde_i].present = 1; } } - pmap_i++; + return (pdpe_cnt * 2) * 0x1000; } } +pmap_t *init_pmap(size_t pagetable_size) { + pmap_t *pmap, *last_pmap; + struct memory_table *zones = (void *)ZONE_MAP; + int budorder, zone_i; + uint64_t pmap_size, pmap_bbitsize, zone_size; + bool first_pmap_i = true; -/** - * BIG TODO: - * Paging turned out to be simpler then I thought. I've temporarily fixed the code, but needs to be rewritten/simplified. - * Let's get rid of those nasty GOTOs if we can. - * Also, once we get physical memory allocator up and running, impliment that in this function. -**/ + -bool map_page(void *virtual_addr, void *physical_addr, uint8_t size) { - //printf("map page called\n"); - uintptr_t va_ptr = (uintptr_t)virtual_addr; - uintptr_t pa_ptr = (uintptr_t)physical_addr; - if((va_ptr % (1 << size)) || (pa_ptr % (1 << size))) { - return 0; - } - page_table *table = (page_table *)PAGEMAP_LOCATION; - int pte_i = (va_ptr >> 12) & 0x1ff; - int pde_i = (va_ptr >> 21) & 0x1ff; - int pdpe_i = (va_ptr >> 30) & 0x1ff; - int pml4e_i = (va_ptr >> 39) & 0x1ff; - - if(table->pml4e[pml4e_i].present) { - if(table->pml4e[pml4e_i].base_ptr != (uintptr_t)&table->pdpe[pdpe_i] >> 12) goto error; - if(table->pdpe[pdpe_i].present) { - if(size == PAGE_SIZE_1G) { - if(table->pdpe[pdpe_i].base_ptr == ((uintptr_t)pa_ptr >> 30 & 0x1ff)) - return true; - goto error; + for(zone_i = 0; zones[zone_i].length > 0; zone_i++) { + if((zones[zone_i].type == MEM_AVAILABLE) && (zones[zone_i].ACPI & 1) && + zones[zone_i].length >= (0x2000)) { + printf("found allocatable map at %p\n", zones[zone_i].base); + last_pmap = pmap; + if(zones[zone_i].base == (void *)0x100000) { + zone_size = zones[zone_i].length - (((uint64_t)&_kernel_shared_zone_begin - 0x100000) + pagetable_size); + pmap = PHYS_TO_VIRT((void *)&_kernel_shared_zone_begin + pagetable_size); + } + else { + zone_size = zones[zone_i].length; + pmap = PHYS_TO_VIRT(zones[zone_i].base); } - if(table->pdpe[pdpe_i].base_ptr != (uintptr_t)&table->pde[pde_i] >> 12) goto error; - if(table->pde[pde_i].present) { - if(size == PAGE_SIZE_2M) { - if(table->pde[pde_i].base_ptr == ((uintptr_t)pa_ptr >> 21 & 0x1ff)) - return true; - goto error; + if(first_pmap_i) { + pmap->next = NULL; + first_pmap_i = false; + } + else { + pmap->next = last_pmap; + } + + for(budorder = 0; budorder < MAX_BUDDY_ORDER; budorder++) { + pmap_bbitsize = zone_size / (0x1000 << budorder); + pmap->bsize[budorder] = DIV_ROUND_UP(pmap_bbitsize , 64); + if(budorder) { + pmap->buddy[budorder] = pmap->buddy[budorder - 1] + pmap->bsize[budorder - 1]; + } + else { + pmap->buddy[0] = (void *)pmap + sizeof(*pmap); + } + if(budorder < MAX_BUDDY_ORDER - 1) { + bzero(pmap->buddy[budorder], pmap->bsize[budorder] * 8); + if(pmap_bbitsize & 1) { + pmap->buddy[budorder][pmap->bsize[budorder] - 1] = + ((uint64_t)1 << ((pmap_bbitsize - 1) & 63)); + } + if(pmap_bbitsize == 1) { + pmap->max_buddy = budorder; + for(budorder++; budorder < MAX_BUDDY_ORDER; budorder++) { + pmap->buddy[budorder] = 0; + pmap->bsize[budorder] = 0; + } + break; + } } - if(table->pde[pde_i].base_ptr != (uintptr_t)&table->pte[pte_i] >> 12) goto error; - if(table->pte[pte_i].present) { - if(table->pte[pte_i].base_ptr != ((pa_ptr >> 12) & 0x1ff)) goto error; - return true; + else { + pmap->max_buddy = MAX_BUDDY_ORDER - 1; + memset(pmap->buddy[budorder], UINT8_MAX, pmap->bsize[budorder] * 8); + if((pmap_bbitsize / 64) != (pmap->bsize[budorder])) { + pmap->buddy[budorder][pmap->bsize[budorder] - 1] = + (((uint64_t)1 << (pmap_bbitsize & 63)) - 1); + } } - else goto mod_page_pte; } - else goto mod_page_pde; - } - else goto mod_page_pdpe; - } - else { - table->pml4e[pml4e_i].base_ptr = (uintptr_t)&table->pdpe[pdpe_i] >> 12; - table->pdpe[pml4e_i].read_write = 1; - table->pml4e[pml4e_i].present = 1; -mod_page_pdpe: - table->pdpe[pdpe_i].read_write = 1; - //TODO you just found out things are a lot more simple then you thought! - if(size == PAGE_SIZE_1G) { - table->pdpe[pdpe_i].size = 1; - table->pdpe[pdpe_i].base_ptr = pa_ptr >> 12; - table->pdpe[pdpe_i].present = 1; - return true; - } - table->pdpe[pdpe_i].base_ptr = (uintptr_t)&table->pde[pde_i] >> 12; - table->pdpe[pdpe_i].present = 1; -mod_page_pde: - table->pde[pde_i].read_write = 1; - if(size == PAGE_SIZE_2M) { - table->pde[pde_i].size = 1; - table->pde[pde_i].base_ptr = pa_ptr >> 12; - table->pde[pde_i].present = 1; - return true; + + pmap_size = (uint64_t)(pmap->buddy[pmap->max_buddy] + pmap->bsize[pmap->max_buddy]) - (uint64_t)pmap; + first_pmap = pmap; //we spoof palloc into allocating from the specific required pmap. + palloc(pmap_size); } - table->pde[pde_i].base_ptr = (uintptr_t)&table->pte[pte_i] >> 12; - table->pde[pde_i].present = 1; -mod_page_pte: - table->pte[pte_i].base_ptr = pa_ptr >> 12; - table->pte[pte_i].read_write = 1; - table->pte[pte_i].present = 1; - return true; } -error: - printf("Page allocation error!\n"); - return false; + return pmap; } diff --git a/src/kernel/panic.c b/src/kernel/panic.c index 851684a..82a761f 100644 --- a/src/kernel/panic.c +++ b/src/kernel/panic.c @@ -1,13 +1,15 @@ #include #include #include +#include +#include +#include -void panic(int reason, int type) { // will fill with debugging info latter +void panic(int reason, void *eframe_p, struct registers *regs) { // will fill with debugging info latter + - struct stack_frame *frame; - #ifdef EASTEREGG_BLOATWARE - printf("Kernel PANIC!!!!!!!\n"); + printf("\nKernel PANIC!!!!!!!\n"); printf( " _.-^^---....,,-- \n" " _-- --_ \n" @@ -24,31 +26,65 @@ void panic(int reason, int type) { // will fill with debugging info latter printf("Kernel Panic!\n"); #endif - printf("Reason:\n"); - switch(reason) { - case KERNEL_PANIC_PMAPSIZE : - printf("\tThe physical map can't fit in the first memory zone.\n" - "\tNote: If you have this issue, please contact me.\n" - "\tIt's a fixable bug caused by an unlikely scenario.\n"); - break; - case KERNEL_PANIC_RSDP_UNFOUND: - printf("\tRSDP unfound!\n"); - break; - case KERNEL_PANIC_KERNEL_RETURNED: - printf("\tThe kernel (almost) reached its return!\n"); - break; + case KERNEL_PANIC_HW_EXCEPTION: + case KERNEL_PANIC_HW_EXCEPTION_ERR: + printf("\nHardware exception in kernel space!\n"); + break; + + case KERNEL_PANIC_RSDP_UNFOUND: + printf("\nRSDP unfound!\n"); + break; + case KERNEL_PANIC_KERNEL_RETURNED: + printf("\nThe kernel (almost) reached its return!\n"); + break; + case KERNEL_PANIC_INVALID_PFREE: + printf("\npfree was called with invalid paramaters.\n"); + break; + case KERNEL_PANIC_INVALID_RSDT: + printf("\nInvalid RSDT or XSDT after RSDP verification.\nIf this happens, go buy some lottery tickets.\n"); + break; + case KERNEL_PANIC_INVALID_IOAPIC_VEC: + printf("\nThe kernel tried to make a vector that was too high for the IOAPIC to handle.\n"); + break; + case KERNEL_PANIC_HPET_REQUIRED: + printf("\nHPET is required. \nIf you get this error, let know;\nif enough people share this issue, I'll impliment PIT usage.\n"); + default: + printf("\nUnknown panic code %i\n.", reason); + break; } - printf("\nStack trace:\n"); + struct stack_frame *frame; - asm("mov %%rbp,%0" : "=r"(frame) ::); + char reg_str[156]; + if((reason == KERNEL_PANIC_HW_EXCEPTION) || (reason == KERNEL_PANIC_HW_EXCEPTION_ERR)) { + sprintf(reg_str, "rax:\t0x%lx\n" + "rbx:\t0x%lx\n" + "rcx:\t0x%lx\n" + "rdx:\t0x%lx\n" + "rsi:\t0x%lx\n" + "rdi:\t0x%lx\n", regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi); + } + if(reason == KERNEL_PANIC_HW_EXCEPTION) { + struct int_frame *ex_frame = eframe_p; + printf("Offending instruction:\t0x%p\n", ex_frame->rip); + printf(reg_str); + } + else if (reason == KERNEL_PANIC_HW_EXCEPTION_ERR) { + struct exception_frame *ex_frame = eframe_p; + printf("Offending instruction: 0x%p\nError value: %x\n", ex_frame->frame.rip, ex_frame->err); + printf(reg_str); + } + asm("mov %0, rbp" : "=r"(frame) ::); + printf("\nCall trace:\n"); + for(; frame->next != 0; frame = frame->next) { - printf("\t%x\n", frame->function_base); + printf("\t0x%p\n", frame->function_base); } + - //It's not public yet, but it will be + //It's not public yet, but if I ever get somewhere it will be printf("\nAfter ensuring your computer meets the requirements specified, if you think this is a bug, please open an issue on the git repo or email me at %s.\n", DEV_EMAIL); - for(;;); + asm("cli\nhlt"); } diff --git a/src/kernel/printf.c b/src/kernel/printf.c index 14c897d..8267755 100644 --- a/src/kernel/printf.c +++ b/src/kernel/printf.c @@ -39,10 +39,12 @@ #include //and my options +/** #define PRINTF_DISABLE_SUPPORT_FLOAT #define PRINTF_DISABLE_SUPPORT_EXPONENTIAL #define PRINTF_DISABLE_SUPPORT_LONG_LONG #define PRINTF_DISABLE_SUPPORT_PTRDIFF_T +**/ // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the @@ -159,7 +161,11 @@ static inline void _out_char(char character, void* buffer, size_t idx, size_t ma { (void)buffer; (void)idx; (void)maxlen; if (character) { +#ifdef SCREEN_OUTPUT + _putchar_screen(character); +#else _putchar_serial(COM1, character); // later we should figure out a way to not specifify exclusively com1 +#endif } } diff --git a/src/kernel/random.c b/src/kernel/random.c new file mode 100644 index 0000000..404223a --- /dev/null +++ b/src/kernel/random.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +static bool hw_random = false; +static unsigned long int seed = -1; + +void randinit() { + unsigned int unused, eax, ecx; + eax = 0; + ecx = 0; + __get_cpuid(1, &eax, &unused, &ecx, &unused); + hw_random = (ecx >> 30) & 1; + printf("Kernel random source: %s.\n", (hw_random) ? "rdrand" : "pseudo"); +} + +//As of now, this function isn't nessesarily meant to be fast. +unsigned int randint() { + uint64_t random_long = 0; + if(hw_random) { + asm("rand:\n" + "rdrand %0\n" + "jc finished\n" + "pause\n" + "jmp rand\n" + "finished:" :"=r"(random_long)::"rax" ); + } + else { + //TODO FUCKING ENTROPY!!!!!!!111 + seed = 1103515245 * seed + 12345; + return(unsigned int)(seed / 65536) % 32768; + } + return 0; +} + diff --git a/src/kernel/smp.c b/src/kernel/smp.c new file mode 100644 index 0000000..d3c74fe --- /dev/null +++ b/src/kernel/smp.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +#define LAPIC_ICR_LOW 192 +#define LAPIC_ICR_HIGH 196 + +extern lapic_t lapic; +extern char __load_start_smp_bootloader, __load_stop_smp_bootloader; +extern uint8_t *smp_bootstrap_corecount; + +struct icr_reg { + uint8_t vector; + unsigned int deliv_mode:3; + unsigned int dest_mode:1; + unsigned int deliv_status:1; + unsigned int reserved:1; + unsigned int level:1; //0 = de-assert + unsigned int trig_mode:1; + unsigned int reserved_1:2; + unsigned int dest_shorthand:2; + unsigned int reserved_2:12; +}__attribute__((packed)); + +//1: get bsp number 2 +//2: get list of lapics 3 +//3: copy code 1 +//4: + + +static inline void write_icr(uint8_t dest, uint32_t message) { + lapic[LAPIC_ICR_HIGH] = (uint32_t)dest << 24; + lapic[LAPIC_ICR_LOW] = message; +} + +void smp_boot() { + uint8_t cores_active = 0; //TODO change in asm + struct cores_info cores; + unsigned int ci; + + struct icr_reg icr; + bzero(&icr, sizeof(icr)); + + memcpy(PHYS_TO_VIRT((void *)0x8000), PHYS_TO_VIRT(&__load_start_smp_bootloader), + &__load_stop_smp_bootloader - &__load_start_smp_bootloader); + *(uint8_t **)PHYS_TO_VIRT(&smp_bootstrap_corecount) = &cores_active; + + + get_coreinfo(&cores); + + icr.deliv_mode = 0b101; + icr.dest_shorthand = 0b11; + icr.level = 1; + write_icr(0, *(uint32_t *)&icr); + usleep(10000); + + icr.deliv_mode = 0b110; + icr.vector = 8; + write_icr(0, *(uint32_t *)&icr); + usleep(200); + write_icr(0, *(uint32_t *)&icr); + + /** + if(cores_active != cores.corecount) { + write_icr(0, *(uint32_t *)&icr); + usleep(200); + } + **/ + /** + for(ci = 0; ci < cores.corecount; ci++) { + if(ci == cores.bsp) continue; + //send init sipi + write_icr(ci, *(uint32_t *)&icr); + } + **/ + +} diff --git a/src/kernel/smp_trampoline.asm b/src/kernel/smp_trampoline.asm new file mode 100644 index 0000000..f723aa6 --- /dev/null +++ b/src/kernel/smp_trampoline.asm @@ -0,0 +1,140 @@ +global smp_bootstrap_corecount; + +[bits 16] +smp_trampoline: +cli +hlt +hlt + +xor ax, ax +mov ds, ax +lgdt [.gdt_descriptor_p] +mov eax, cr0 +or eax, 0x1 +mov cr0, eax ; now in long mode + +jmp 0x8:.smp_protected + + +;________________________________________________________________________________________ + +;TODO find how to use old gdt +.gdt_start_p: ; we need to start with a null gdt +dd 0 +dd 0 + +.gdt_code_p: +dw 0xffff +dw 0x0000 +db 0x00 +db 10011010b +db 11001111b +db 0x0000 + +.gdt_data_p: +dw 0xffff +dw 0x0000 +db 0x00 +db 10010010b +db 11001111b +db 0x0000 + +.gdt_end_p: + +.gdt_descriptor_p: + dw .gdt_end_p - .gdt_start_p - 1 +dq .gdt_start_p + +SMP_PROTECTED_CODE_SEGMENT equ .gdt_code_p - .gdt_start_p +SMP_PROTECTED_DATA_SEGMENT equ .gdt_data_p - .gdt_start_p + +;________________________________________________________________________________________ + +.smp_protected + +[bits 32] +mov ax, SMP_PROTECTED_DATA_SEGMENT +mov ds, ax +mov ss, ax +mov es, ax +mov fs, ax +mov gs, ax + +mov eax, 0x10000 ;TODO clarify _why_ this is a thing +mov cr3, eax + +;setting up misc features +mov eax, cr4 +; PAE, OSFXSR, OSXMMEXCPT +or eax, 1 << 5 | 1 << 9 | 1 << 10 +mov cr4, eax + + +;set NX and LME +mov eax, 0x80000001 +cpuid +and edx, 1 << 20 +shr edx, 9 + +mov ecx, 0xc0000080 +rdmsr +or eax, 1 << 8 | 1 << 11 +or eax, edx +wrmsr + +;enable paging +mov eax, cr0 +or eax, 1 << 31 | 1 << 0; +and ax, ~(1 << 2) +mov cr0, eax + +jmp SMP_LONG_CODE_SEGMENT:.counter + +;________________________________________________________________________________________ + +[bits 64] +;TODO do we really need all this? +.gdt_start_l: +;and now we set up a temporary GDT creating a 1:1 mapping +dw 0xffff +dw 0 +db 0 ;this is the invalid GDT +db 0 +db 1 +db 0 + +;now for the code GDT: +.gdt_code_l: +dw 0 ; segment limit 15:00 (I don't think this matters in 64 bit mode!) +dw 0 ; base address 15:00 +db 0 ; base address 23:16 +db 10011010b +db 00100000b +db 0 + +.gdt_data_l: +dw 0 +dw 0 +db 0 +db 10010010b +db 00100000b +db 0 + +.gdt_end_l: ; later calculates offset in defs below + + +.descriptor_l: + dw .gdt_end_l - .gdt_start_l - 1 +dq .gdt_start_l + +SMP_LONG_CODE_SEGMENT equ .gdt_code_l - .gdt_start_l +SMP_LONG_DATA_SEGMENT equ .gdt_data_l - .gdt_start_l + +.counter: +mov rax, [smp_bootstrap_corecount] +inc QWORD [rax] +cli +hlt +;TODO set up stack; enter kernel + +smp_bootstrap_corecount: db 0 diff --git a/src/kernel/testmalloc.c b/src/kernel/testmalloc.c new file mode 100644 index 0000000..5733c7c --- /dev/null +++ b/src/kernel/testmalloc.c @@ -0,0 +1,35 @@ +#define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + 5))) + +#include +#include +#include +#include + +//will delete later + +void test_malloc(unsigned int cnt) { + void *testchunks[cnt]; + unsigned int rindex[cnt], testchunk_size, i, x; + + bzero(rindex, cnt * sizeof(unsigned int)); + for(x = 0; x < cnt; x++) { + testchunk_size = (CHUNK_SIZE_FROM_INDEX(randint() % 7) - 24); + testchunks[x] = malloc(testchunk_size); + //printf("ALLOCATING CHUNK %p SIZE %i\n", (void *)testchunks[x] - 24, testchunk_size); + } + for(x = 0; x < cnt;) { + i = randint() % cnt; + if(rindex[i]) continue; + rindex[i] = x; + x++; + } + for(x = 0; x < cnt; x++) { + //printf("FREEING CHUNK %p\n", (void *)testchunks[rindex[x]]); + free(testchunks[rindex[x]]); + } + printf("\nmalloc tester:\n"); + printf("THIS NEEDS TO BE EMPTY______________\n"); + debug_heap(); + printf("____________________________________\n"); + +} diff --git a/src/kernel/timer.c b/src/kernel/timer.c new file mode 100644 index 0000000..aed42ba --- /dev/null +++ b/src/kernel/timer.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PIT_COMMAND 0x43 +#define PIT_FREQ 1193182 + +#define PIT_CHANNEL_0 0x40 +#define PIT_CHANNEL_2 0x42 +#define PIT_INPUT_2 0x61 +//you can move these if it makes more sense to put them in a lapic.h +#define LAPIC_TIMER_LVT 200 +#define LAPIC_TIMER_INIT_COUNT 224 +#define LAPIC_TIMER_CURRENT_COUNT 228 +#define LAPIC_TIMER_DIVIDE 248 + +#define LAPIC_TIMER_MODE_ONESHOT 0b00 +#define LAPIC_TIMER_MODE_PERIODIC 0b01 +#define LAPIC_TIMER_MODE_TSC_DEADLINE 0b10 + +#define IA32_TSC_DEADLINE 0x6E0 + + +struct acpi_addr_fmt { + uint8_t addr_space; //0 is system memory, 1 is system io + uint8_t reg_bit_width; + uint8_t reg_bit_offset; + uint8_t resrved; + uint64_t addr; +} __attribute__((packed)); + +struct hpet_sdt { + sdt_head header; + uint8_t hw_rev_id; + unsigned int comparator_cnt:5; + unsigned int counter_size_64bit:1; + unsigned int reserved:1; + unsigned int legacy_capable:1; + uint16_t vendor_id; + struct acpi_addr_fmt acpi_addr; + uint8_t hpet_number; + uint16_t min_tick; + unsigned int protection:4; //0 = no protection, 1 = 4kb, 2 = 64kb + unsigned int oem_attribute:4; +} __attribute__((packed)); + +struct hpet_info_struct { + uint64_t *hpet_reg; + unsigned int hpet_period; + double hpet_freq_mhz; //improves speed with us quantum + unsigned int timer_cnt; + unsigned int irqs; + bool long_mode; +} hpet_info; + + +struct lapic_lvt { + uint8_t vector; + unsigned int reserved:4; + unsigned int delivery_status:1; + unsigned int reserved_1:3; + unsigned int mask:1; + unsigned int timer_mode:2; + unsigned int reserved_2:13; +} __attribute__((packed)); + +extern lapic_t lapic; + +#define TSC_TIME_TSC_EVENT 0 +#define TSC_TIME_LAPIC_EVENT 1 +#define LAPIC_TIME_HPET_EVENT 2 + +static int clock_mode; + +//time quantum is 1us +static double tsc_freq; +static double apic_freq; + +static unsigned int early_event_vector; + +static struct lapic_lvt lapic_timer_lvt; + +uint64_t timestamp() { + if((clock_mode == TSC_TIME_TSC_EVENT) || (clock_mode == TSC_TIME_LAPIC_EVENT)) { + return read_tsc() / tsc_freq; + } + else { + return UINT32_MAX - (lapic[LAPIC_TIMER_CURRENT_COUNT] / apic_freq); + } + return 0; +} + +//timer test code +//there is a race condition here. +//I'm leaving it unattended, as I'm only expecting this to be used for SMP booting. +void usleep(unsigned int us) { + if(clock_mode == TSC_TIME_TSC_EVENT) { + write_msr(IA32_TSC_DEADLINE, ((uint64_t)((us * (double)tsc_freq) + 0.5)) + read_tsc()); + } + else if(clock_mode == TSC_TIME_LAPIC_EVENT) { + lapic[LAPIC_TIMER_INIT_COUNT] = (uint32_t)((us * (double)apic_freq) + 0.5); + } + else { + hpet_info.hpet_reg[33] = hpet_info.hpet_reg[30] + + (uint32_t)((us * hpet_info.hpet_freq_mhz) + 0.5); + } + asm("hlt\n"); +} + +/** +we either use: +1: tsc +2: tsc + +1: tsc +2: lapic (no tsc deadline) + +1: lapic +2: hpet + +PIT not implimented, I've yet to find a computer that doesn't have HPET +**/ + +void calibrate_lapic() { + unsigned int timer_idt = alloc_idt(&KERNEL_IDT_GATE(lapic_timer_racefixer)); + uint32_t lapic_ticks; + uint64_t hpet_ticks = (100000000000000 * (1 / (double)hpet_info.hpet_period)) + 0.5; + uint64_t timer_loops = 0; + struct lapic_lvt timer_lvt = { + .vector = timer_idt, + .delivery_status = 0, + .mask = 0, + .timer_mode = LAPIC_TIMER_MODE_PERIODIC + }; + printf("Starting LAPIC timer calibration...\n"); + + lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&timer_lvt; + lapic[LAPIC_TIMER_DIVIDE] = 0b1011; + asm(".global calibrate_lapic_waiting\n" + "xor rbx, rbx\n" + "mov rax, %2\n" + "add rax, %3\n" + "mov [%4], rax\n" //hpet timer + "mov [%5], 0xffffffff\n" //lapic timer + "calibrate_lapic_waiting:\n" + "hlt\n" + "mov %0, %6\n" //save lapic time + "mov [%5], 0\n" + "mov %1, rbx\n" + :"=r"(lapic_ticks), "=r"(timer_loops) + :"r"(hpet_ticks), "m"(hpet_info.hpet_reg[30]), "m"(hpet_info.hpet_reg[33]), + "m"(lapic[LAPIC_TIMER_INIT_COUNT]), "m"(lapic[LAPIC_TIMER_CURRENT_COUNT]) + :"rax","rbx" ); + apic_freq = ((UINT32_MAX * timer_loops) + (UINT32_MAX - lapic_ticks)) / (double)100000; + + printf("LAPIC timer frequency: %f MHz\n", apic_freq); + free_idt(timer_idt); +} + + +void init_timer() { + struct hpet_sdt *hpet_desc = find_sdt(SDT_HPET); + early_event_vector = alloc_idt(&KERNEL_IDT_GATE(kernel_block)); + if(!hpet_desc) PANIC(KERNEL_PANIC_HPET_REQUIRED); + + unsigned int first_irq; + + struct apic_vt hpet_redirect; + bzero(&hpet_redirect, sizeof(hpet_redirect)); + hpet_redirect.vector = early_event_vector; + hpet_redirect.polarity = 1; + + + hpet_info.hpet_reg = PHYS_TO_VIRT(hpet_desc->acpi_addr.addr); + hpet_info.hpet_period = (hpet_info.hpet_reg[0] >> 32) & UINT32_MAX; + hpet_info.long_mode = (hpet_info.hpet_reg[0] >> 13) & 1; + hpet_info.irqs = (hpet_info.hpet_reg[32] >> 32) & UINT32_MAX; + hpet_info.hpet_freq_mhz = (1 / (double)hpet_info.hpet_period) * 1000000000; + //get first irq available + first_irq = __builtin_ctzl(hpet_info.irqs) + 1; + + printf("hpet frequency: %f MHz\n", hpet_info.hpet_freq_mhz); + + //do we need to worry about bypassing irq remappings? + create_fixed_interrupt(first_irq, &hpet_redirect); + + //set irq, enable triggering of interrupts + hpet_info.hpet_reg[32] = (first_irq << 9) | (1 << 2) | 1; + + //enable main counter + hpet_info.hpet_reg[2] = 1; + + asm("sti\n"); + + //detect consistent TSC + uint32_t unused, cpuid_reg; + __get_cpuid(0x80000007, &unused, &unused, &unused, &cpuid_reg); + + //goto debug_tsc; + if((cpuid_reg >> 8) & 1) { + printf("Detected invariant TSC\n"); + //.1 second to calibrate, TODO do we need to check if the register is big enough? + uint64_t hpet_ticks = (100000000000000 * (1 / (double)hpet_info.hpet_period)) + 0.5; + printf("Starting TSC calibration...\n"); + uint64_t volatile start_tsc, end_tsc; + //this may not be the fastest, but I'll improve if needed further into development + asm volatile( + "xor rax, rax\n" + "rdtsc\n" + "shl rdx, 32\n" + "or rax, rdx\n" + "mov %0, rax\n" + "mov rbx, %4\n" + "add rbx, [%3]\n" + "mov [%2], rbx\n" + //if you're worried about a single instruction being a race condition, it's time for an upgrade + "xor rax, rax\n" + "hlt\n" + "rdtsc\n" + "shl rdx, 32\n" + "or rax, rdx\n" + "mov %1, rax\n" + :"=&r"(start_tsc), "=&r"(end_tsc) + :"m"(hpet_info.hpet_reg[33]), "m"(hpet_info.hpet_reg[30]),"r"(hpet_ticks) + :"rax","rbx","rdx"); + tsc_freq = (end_tsc - start_tsc) / (double)100000; + printf("TSC: Detected frequency is %f MHz\n", tsc_freq); + __get_cpuid(0x1, &unused, &unused, &cpuid_reg, &unused); + if((cpuid_reg >> 24) & 1) { + clock_mode = TSC_TIME_TSC_EVENT; + + lapic_timer_lvt.vector = early_event_vector; + lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_TSC_DEADLINE; + lapic_timer_lvt.delivery_status = 0; + lapic_timer_lvt.mask = 0; + } + else { + clock_mode = TSC_TIME_LAPIC_EVENT; + calibrate_lapic(); + + lapic_timer_lvt.vector = early_event_vector; + lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_ONESHOT; + lapic_timer_lvt.delivery_status = 0; + lapic_timer_lvt.mask = 0; + } + lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&lapic_timer_lvt; + } + else { + uint32_t apic_div; + clock_mode = LAPIC_TIME_HPET_EVENT; + calibrate_lapic(); + + //because lapic is used as scheduler, we want to cause as little interrupts as possible + //while retaining 1 mhz accuracy + + apic_div = __builtin_clz((uint32_t)apic_freq); + if(!apic_div) { + apic_div = 0b1011; + } + else if(apic_div >= 7) { + apic_div = 0b1010; + apic_freq /= 128; + } + else { + apic_freq /= (1 << --apic_div); + apic_div = (((apic_div & 0b100) << 1) | (apic_div * 0b1011)); + } + + lapic_timer_lvt.vector = SPURRIOUS_VECTOR; //TODO CHANGE ME + lapic_timer_lvt.timer_mode = LAPIC_TIMER_MODE_PERIODIC; + lapic_timer_lvt.delivery_status = 0; + lapic_timer_lvt.mask = 1; + lapic[LAPIC_TIMER_DIVIDE] = apic_div; + lapic[LAPIC_TIMER_LVT] = *(uint32_t *)&lapic_timer_lvt; + lapic[LAPIC_TIMER_INIT_COUNT] = UINT32_MAX; + } + switch(clock_mode) { + case TSC_TIME_TSC_EVENT: + printf("Clock source: tsc\nEvent source: tsc-deadline\n"); + break; + case TSC_TIME_LAPIC_EVENT: + printf("Clock source: tsc\nEvent source: lapic\n"); + break; + case LAPIC_TIME_HPET_EVENT: + printf("Clock source: lapic\nEvent source: hpet\n"); + break; + } +} diff --git a/src/kernel/video.c b/src/kernel/video.c new file mode 100644 index 0000000..0433ce2 --- /dev/null +++ b/src/kernel/video.c @@ -0,0 +1,10 @@ +#include +#include + +//to be implimented when paging is set up + +void dump_video() { + struct mode_info *video = (struct mode_info *)0x600; + printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n", + video->width, video->height, video->bpp, video->framebuffer); +} -- cgit v1.2.3