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/.gdb_history | 386 +++++++++---------- src/backup | 437 --------------------- src/bootloader/bios_disk.asm | 149 ++++++++ src/bootloader/bios_functions/bios_disk.asm | 40 -- src/bootloader/bios_functions/print.asm | 58 --- src/bootloader/bootloader.asm | 95 ++--- src/bootloader/cpu_check.asm | 28 +- src/bootloader/enter_kernel.asm | 72 ++-- src/bootloader/gdt.asm | 6 +- src/bootloader/print.asm | 21 + src/bootloader/video.asm | 4 - src/debug/gdbinit.gdb | 9 +- src/debug/gdbinit.py | 28 ++ src/debug/i8086.xml | 113 ++++++ src/include/acpi.h | 37 +- src/include/heap.h | 5 + src/include/int.h | 84 ++++ src/include/io.h | 38 ++ src/include/isv.h | 25 ++ src/include/kernel.h | 16 +- src/include/libc.h | 4 + src/include/madt.h | 20 + src/include/math.h | 6 + src/include/paging.h | 95 +---- src/include/panic.h | 60 ++- src/include/random.h | 5 + src/include/serial.h | 13 +- src/include/smp.h | 4 + src/include/testmalloc.h | 6 + src/include/timer.h | 8 + src/indigo_os | Bin 19512 -> 41152 bytes 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 + src/link.ld | 48 ++- src/makefile | 104 +++-- 54 files changed, 3061 insertions(+), 1355 deletions(-) delete mode 100644 src/backup create mode 100644 src/bootloader/bios_disk.asm delete mode 100644 src/bootloader/bios_functions/bios_disk.asm delete mode 100644 src/bootloader/bios_functions/print.asm create mode 100644 src/bootloader/print.asm create mode 100755 src/debug/gdbinit.py create mode 100644 src/debug/i8086.xml create mode 100644 src/include/heap.h create mode 100644 src/include/int.h create mode 100644 src/include/io.h create mode 100644 src/include/isv.h create mode 100644 src/include/madt.h create mode 100644 src/include/math.h create mode 100644 src/include/random.h create mode 100644 src/include/smp.h create mode 100644 src/include/testmalloc.h create mode 100644 src/include/timer.h 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') diff --git a/src/.gdb_history b/src/.gdb_history index 41118ac..edbca99 100644 --- a/src/.gdb_history +++ b/src/.gdb_history @@ -1,256 +1,256 @@ -next -print buddy_size -print pmap->next -print pmap -print *pmap -print *pmap -print pmap -quit -quit +c +info threads quit -break page.c:198 c -watch pmap +info threads +step c -print pmap -next -print buddy_size -next +print cores +print cores_active +info threads c -print *pmap -quitquit +info threads quit -break page.c c -quit -break init_pmap +info threads c -next -watch pmap_i -c -print pmap_i -next +info threads quit -break page.c:220 +b smp_boot c +qit quit -break init_pmap +b smp.c:59 c next -watch pmap_i -c -print pmap_i -c -print pmap_i -next -print zones[zone_i] +info threads next -break page.c:137 -c +info threads next -info b -c -print pmap_i -c -print pmap_i +info threads +info threads +info threads +quit +b smp.c:65 c -print pmap_i next -print *pmap -print pmap +info threads +info thread 2 quit -break page.c:220 +b timer.c:57 c -print pmap -print *pmap quit -break debug_pmap -c +b timer.c:57 c quit -break page.c:179 +b smp.c:57 c +print *(uint32_t *)&icr +print/x *(uint32_t *)&icr +info threads next -print buddy_bit -print budorder -c -quit -quit -break page.c:147 -c +info threads next -print threshold_bitsize -print (uint64_t)threshold_bitsize -print pmap_i -print *pmap -print threshold_bitsize -print buddy_bitsize +info threads next -print buddy_bit -print buddy_bit -print buddy_bitlen -print buddy_bitlen[0][7] -print buddy_bitlen[0][7] +info threads next -quit -break panic -c +info threads +next +info threads next -x ebp -print $ebp -info reg ebp -x 0x1ffff8 -stack 50 +info threads +print/x *(uint32_t *)&icr +pirnt (void *)0x8000 +prit (void *)0x8000 +print (void *)0x8000 +print *(void *)0x8000 +print __load_start_smp_bootloader +print &__load_start_smp_bootloader +print (void *)&__load_start_smp_bootloader +print (void *)&__load_stop_smp_bootloader quit -break debug_pmap -c -info reg rbp -info reg rbp -x 0x1fffe8 -print (void*)&debug_pmap -next -stack -stack 50 -info reg rbp -x 0x1fffe8 -x/20 0x1fffe8 +print &__load_start_smp_bootloader +print &__load_stop_smp_bootloader +print &__load_stop_smp_bootloader +print smp_bootstrap +print smp_bootloader +print &__load_stop_smp_bootloader +print __load_stop_smp_bootloader +print &__load_stop_smp_bootloader +print smp_bootstrap_corecount +b smp_trampoline +hb smp_trampoline +c +d +d +hb smp_trampoline +c +info reg rip quit +hb smp_trampoline +c quit -break panic c -next -info stack -stack -next -info rsp -x 0x1fff28 -x *0x1fff28 -stack 50 quit -break panic +hb smp_trampoline +c +info threads +hexdump 0 +c +c +c +c c c -stack -stack 50 c -stack 50 -info reg rbp -quit -break panic -c -next -print stack -stack 50 -stack --help -stack 0x20 -stack 100 0x20 -info reg rbp -info reg rbp + 1 -info reg rbp -x 0x1fff58+8 -x 0x1fff58-8 -x 0x1fff58+1 -quit -break main c -next -stepi -next -stepi -x 0x1fffe8 - 8 -x 0x1fffe8 + 8 -x 0x1fffe8 -x 0x1fffc8-8 -x 0x1fffe8-8 -next -step -print rsp -stack -x $rbp-8 -next -x $rbp-8 -x $rbp+8 -stack 50 -stack 100 -stack 90 -stack 90 90 -stack 90 -x $ebp -x $ebp-8x $eb -x $ebp-8 -x $ebp+8 -quit -break panic.c:27 c -next -print *Frame -print frame -print *frame -print frame->function_base -print/x frame->function_base -x 0x103ef2 -x frame->function_base -x frame->lastframe->function_base -quit -break panic.c:29 c -print *frame c -quit -break page.c:30 +c +c +c +c +cc +c +c +c +c +c +c +c +d c quit -break panic.c:30 +b smp_trampoline +c +hb smp_trampoline +d 2 +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c +c c c -pirnt *frame -print *frame c -print *frame c -print *frame c -print *frame c -print *frame -x 0x1ffff8 c quit c -x 831e -x 0x831e -x 0x103f58 -x/i 0x831e -x/i 0x831e-8 -x/i 0x831e-16 -x/10i 0x831e -x/10i 0x831e-16 -x/10i 0x831e-1 -x/10i 0x831e- -x/10i 0x831e -x/10i 0x831e-8 -x/10i 0x831e+8 -x/10i 0x831e +info threads quit -break 0x831e c +info threads quit -b *0x831e +info threads +next +next +print 0x8000 / 0x1000 +next +quit +quit +next +info threads +next +info threads +next +info threads +quit +next +info threads +next +info threads +next +info threads +next +info threads +next +info threads +next +info threads +quit +hb 0 c quit +next +next +next +print icr +next +next +info threads +quit +next +info threads +next +info threads +next +info threads +next +info threads quit +b smp.c:60 c -print *frame -print *frame -x *frame -x/1 *frame - *frame +next +info threads +next +info threads quit -break main.c +b memcpy c +print dest +x 0xffff800000008000 +print 0xffff800000008000 +print/x 0xffff800000008000 +print n +b 54 +c +next +info reg +info reg rax +info reg rbx +inf reg rdi +x/i 0xffff800000000000 +x/i 0xffff800000008000 + smp_trampoline +hexdump 0xffff800000008000 quit -break main +b memcpy c -stack +print dest +hexdump 0xffff800000008000 +b 64 c +hexdump 0xffff800000008000 +print __load_start_smp_bootloader +hexdump 0xffff800000000800 +quit +info reg rsp quit diff --git a/src/backup b/src/backup deleted file mode 100644 index 9191304..0000000 --- a/src/backup +++ /dev/null @@ -1,437 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void debug_print_memory() { - struct memory_table *memtable = (struct memory_table *)&_meminfo_loc; - printf(" __________________________________________________________________________\n"); - printf("| type\tstart\t\t\tend\t\t\tsize\t\t |\n"); - printf("|--------------------------------------------------------------------------|\n"); - for(unsigned int i = 0; memtable[i].length > 0; i++) { - printf("| %u %u\t0x%p\t0x%p\t0x%p |\n", memtable[i].type, memtable[i].ACPI, memtable[i].base, (memtable[i].base + memtable[i].length), memtable[i].length); - } - printf("----------------------------------------------------------------------------\n"); -} - -void debug_pmap() { - struct phys_map* 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) { - printf("Table %u:\n" - "\tPhysical Start:\t%#p\n" - "\tTable location:\t%#p\n", pmap_i, pmap->zone_paddr, 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\tSize:\t\t%u\n" - "\t\tBuddies:\t\t\n", order, pmap->buddy[order], buddy_size); - - omit_cnt = 0; - - for(blong_i = 0; blong_i < buddy_size; 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: %x\t is free\n", - pmap->buddy[order] + blong_i, bbit_i, pmap->zone_paddr + ((blong_i * 64) + bbit_i) * buddy_chunksize); - } - omit_cnt++; - if(omit_cnt == 20) { - printf("\t\t\t[more entries ommited]\n"); - } - } - } - } -print_next_buddy: ; - } - pmap_i++; - } -} - -/* - * part 1: - * init tables (complete) - * - * part 2: setting the actual entires - * if entry contains table, set 0, set threshold - * else: - * if entry: - */ - -// init_memory revision -// rules: - /** -void init_pmap() { - struct memory_table *memtable = (struct memory_table *)&_meminfo_loc; - struct phys_map *pmap = (struct phys_map*)&_stage2_pagetable; - struct phys_map *last_pmap; - unsigned int i, x; - uint64_t budentry_len, pmap_chunksize, total_pmap_len = 0; - void *y; - void *paged_mem = &_stage2_pagetable + 0x200000; - map_page(&_stage2_pagetable, &_stage2_pagetable, PAGE_SIZE_2M); - for(i = 0; memtable[i].length > 0; i++) { - if((memtable[i].type == MEM_AVAILABLE) && (memtable[i].ACPI & 1)) { - total_pmap_len += 88; //it'd be nice to find a cleaner way - - //make sure we don't overwrite what we have so far of the kernel - if((memtable[i].base <= (void*)&_stage2_pagetable) && (memtable[i].base + memtable[i].length >= (void *)&_stage2_pagetable)) { - pmap->chunk_start = &_stage2_pagetable; - pmap->chunk_size = memtable[i].length - (pmap->chunk_start - memtable[i].base); - } - else { - pmap->chunk_start = memtable[i].base; - pmap->chunk_size = memtable[i].length; - } - - for(x = 0; x < 8; x++) { - pmap->bsize[x] = ceil((pmap->chunk_size / (0x1000 * (1 << x))) / (double)64); - total_pmap_len += pmap->bsize[x] * 8; - } - - pmap->next = (void*)&_stage2_pagetable + total_pmap_len; - - while((void*)pmap->next + sizeof(struct phys_map) >= paged_mem) { - //do check here if nessesary - map_page(paged_mem, paged_mem, PAGE_SIZE_2M); - paged_mem += 0x200000; - } - - last_pmap = pmap; - pmap = pmap->next; - } - } - last_pmap->next = 0; //I wonder if there's a better way to do this - pmap = (struct phys_map*)&_stage2_pagetable; - -} -**/ - -void init_pmap() { - struct memory_table *zones = (struct memory_table *)&_meminfo_loc; - struct phys_map *pmap = (struct phys_map*)&_stage2_pagetable; - struct phys_map *last_pmap = (struct phys_map*)&_stage2_pagetable; - - 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]; - uint64_t *buddy_end; - - uint64_t pmap_size, pmap_bbitsize, pmap_blongsize, buddy_size, pmap_bit; - uint64_t threshold_longsize = 0, threshold_bit, threshold_end, threshold_bitsize; - uint64_t deleteme_last_p_bits; - - - void *paged_mem = (void *)&_stage2_pagetable + 0x200000; - map_page(&_stage2_pagetable, &_stage2_pagetable, PAGE_SIZE_2M); - - for(zone_i = 0; zones[zone_i].length > 0; zone_i++) { - - if((zones[zone_i].type == MEM_AVAILABLE) && (zones[zone_i].ACPI & 1)) { - - //hopefully this should never happen... but x86 is routy. - //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); - break; - } - - - 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; - } - - 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]); - } - - 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); - - pmap = pmap->next; - pmap_i++; - last_pmap = pmap; - - //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; - } - - } - } - pmap_size = (void*)(pmap) - (void*)&_stage2_pagetable; - if(pmap_size >= zone_len[0]) panic(); //TODO debugging - - pmap = (struct phys_map*)&_stage2_pagetable; - - // Honestly, this section makes me feel like Yandere Dev. It's ugly. - // I've been rewriting this function forever, so I'm deciding to slam it out start to finish. - // I know there's a lot of repeated if statements. I know it hurts. - // But fear not. - // I'll come back and rewrite this part when I've gotten a break from memory management. - for(pmap = (struct phys_map*)&_stage2_pagetable; pmap != 0; pmap++) { - 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_end = (uint64_t *)pmap->next - 1; - threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2; - threshold_bitsize = UINT64_MAX; - } - else { - buddy_end = pmap->buddy[budorder + 1] - 1; - threshold_longsize = threshold_bitsize / 64; - threshold_end = threshold_longsize + 1; - } - pmap_bit = pmap_bbitsize & 63; - buddy_size = buddy_end - pmap->buddy[budorder]; - - - if(pmap_bbitsize >= BITLEN_FROM_LSIZE(buddy_size)) { - //is this nessesary? - bzero(pmap->buddy[budorder], buddy_size * 8); - } - else { - if(budorder == MAX_BUDDY_ORDER - 1) { - 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) { - //TODO why did I have this conditional? Do I need it later? Check on desktop before removing - if(buddy_bitlen[0][budorder]) { - *(pmap->buddy[budorder] + pmap_blongsize) &= - ((uint64_t)1 << (buddy_bitlen[0][budorder] & 63)) - 1; - } - } - else { - memset(pmap->buddy[budorder] + pmap_blongsize + 1, UINT8_MAX, - (void *)buddy_end - (void *)pmap->buddy[budorder] - 8); - *buddy_end = ((uint64_t)1 << (buddy_bitlen[0][budorder] & 63)) - 1; - } - } - else { - if(threshold_longsize) bzero(pmap->buddy[budorder], (threshold_longsize - 1) * 8); - - 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); - *buddy_end = ((uint64_t)1 << ((buddy_bitlen[0][budorder] & 63) - 1)); - } - threshold_bitsize = ((pmap_blongsize * 64) + pmap_bbitsize) * 2; - } - } - } -// for(pmap = pmap->next; pmap != 0; pmap++) { -// } -} - - -// for(budlong_ptr = pmap->buddy[budorder]; budlong_ptr < (uint64_t *)pmap->next - 1; budlong_ptr++) { - -/** -//uses buddy system allocation -void init_memory() { - struct memory_table *memtable = (struct memory_table *)&_meminfo_loc; - struct phys_map *map = (struct phys_map*)&_stage2_pagetable; - struct phys_map *lasttable; - unsigned int i, buddy_chunksize; - uint64_t buddy_bitsize, prev_buddy_bsize, ppt_size; - uint64_t *buddy_ptr, *budentry_end, *threshold; - uint64_t buddy_size64; - - map_page((void*)&_stage2_pagetable, (void*)&_stage2_pagetable, PAGE_SIZE_2M); - void *next_page = (void *)0x400000; - // at this point, we are declaring our header and kernel itself as free (so don't forget to fix that!) - - //TODO all these for loops are unsanitary. - //We hae a lot of branches in the for loops, - //And we re-do work to allocate the page-table. - //I'll clean this up when I'm certain my buddy system works. - for(i = 0; memtable[i].length > 0; i++) { - if((memtable[i].type == MEM_AVAILABLE) && (memtable[i].ACPI & 1)) { - map->chunk_start = (void*)memtable[i].base; - map->chunk_size = memtable[i].length; - buddy_ptr = (void*)&map->buddies; - - for(buddy_chunksize = 0x1000; buddy_chunksize < 0x100000; buddy_chunksize *= 2) { - buddy_bitsize = memtable[i].length / buddy_chunksize; - buddy_size64 = ceil(buddy_bitsize / (double)64); - - if((void*)&buddy_ptr[buddy_size64] + 24 >= next_page) { - map_page(next_page, next_page, PAGE_SIZE_2M); - next_page += 0x200000; - } - - printf("buddy\t%x\theader bitsize\t%u\theader longsize\t%u\tbuddy start\t%p",\ - buddy_chunksize, buddy_bitsize, buddy_size64, buddy_ptr); - if(((buddy_bitsize * 2) != prev_buddy_bsize) && (buddy_chunksize != 0x1000)) { - buddy_ptr[-1] |= ((uint64_t)1 << ((prev_buddy_bsize & 63) - 1)); - printf("\tlast:\t%lx", buddy_ptr[-1]); - } - printf("\n"); - - if(buddy_chunksize < 0x80000) { - bzero(buddy_ptr, buddy_size64 * 8); - prev_buddy_bsize = buddy_bitsize; - } - - else if(buddy_size64 % buddy_bitsize) { - memset(buddy_ptr, 0xff, (buddy_size64 - 1) * 8); - buddy_ptr[buddy_size64] |= 1 << buddy_bitsize; - } - - else memset(buddy_ptr, 0xff, buddy_size64); - - buddy_ptr += buddy_size64; - } - - //this feels kind of gross - lasttable = map; - map->next = (struct phys_map*)buddy_ptr; - map = (struct phys_map*)buddy_ptr; - } - } - lasttable->next = (void*)0; - map = (struct phys_map*)&_stage2_pagetable; - //now we will allocate the table out of itself so we don't mess things up. - //We can't just call palloc(), we need to allocate out of the first available pages (where the pages are) - //we should clean this whole gross function - /** - ppt_size = (uint64_t)((void *)buddy_ptr - (void *)&_stage2_pagetable); - threshold = (void*)UINT64_MAX; - int buddy_bit; - for(buddy_chunksize = 0x80000; buddy_chunksize >= 0x1000; buddy_chunksize /= 2) { - //this means that our table must fit into the first page table. Fixme later, low priotrity - buddy_size64 = ceil((map->chunk_size / buddy_chunksize) / (double)64); - budentry_end = buddy_ptr; - for(buddy_ptr -= buddy_size64; buddy_ptr <= budentry_end; buddy_ptr++) { - if(buddy_ptr > threshold) { - buddy_ptr = budentry_end; - continue; - } - if( - } - } -} - **/ - -//TODO this function was deleted due to it being wrong. -//I'll create it once I have the physical paging prerequisite set up. -void create_pagetable_stage2(uint64_t free_mem) { -} - - -/** - * 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; - } - 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(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 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; - } - 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; -} diff --git a/src/bootloader/bios_disk.asm b/src/bootloader/bios_disk.asm new file mode 100644 index 0000000..5992920 --- /dev/null +++ b/src/bootloader/bios_disk.asm @@ -0,0 +1,149 @@ +bios_disk: +.init: +mov [boot_device], dl +mov ah, 0x8 +int 0x13 +;TODO defaults + +jc .init_use_defaults + +mov [max_head], dh +mov [max_sector], cl +and WORD [max_sector], 0x3f + +mov [max_cylinder], cl +shl WORD [max_cylinder], 8 +or [max_cylinder], ch +and WORD [max_cylinder], 0x3ff + +ret + +.init_use_defaults: +mov BYTE [max_sector], 63 +mov WORD [max_head], 15 +mov BYTE [max_cylinder], 1023 + +ret + +; Return: +; CH = low eight bits of maximum cylinder number +; CL = maximum sector number (bits 5-0), high two bits of maximum cylinder number (bits 7-6) +; DH = maximum head number + +.load_sectors_v2: +;AH = 02h +;AL = number of sectors to read (must be nonzero) +;CH = low eight bits of cylinder number +;CL = sector number 1-63 (bits 0-5) high two bits of cylinder (bits 6-7) +;DH = head number +;DL = drive number (bit 7 set for hard disk) +;ES:BX -> data buffer + +; I don't understand i8086. The base pointer needs to be above the stack pointer, +; yet the stack grows down, +; and we can't address using sp, or by subtraction. +; it's like it's forcing us to use the whole push/pop thing. + +sub sp, 16 +mov bp, sp + +; sector: rbp + 0 (uint8_t) +; head: rbp + 1 (uint8_t) +; cylinder: rbp + 2 (uint16_t) +; sector_cnt: rbp + 4 (uint16_t) +; destination: rbp + 6 (uint32_t) + +; set up variables ______________________________________________ + +;destination to stack +mov [bp + 6], edi + +; find init chs ________________________________________________ + +; divide sector_start / max_sectors +; TODO test for overflow +mov ax, si +shr esi, 16 +mov dx, si + +;find sector +div DWORD [max_sector] +inc dx +mov [bp], edx ; remainder is sector variable + +;find head and cylinder +mov dx, 0 +div DWORD [max_head] +mov [bp + 1], dx ; head +mov [bp + 2], ax ; cylinder + +.sector_for_loop: +mov [bp + 4], cx + +; do bios call ___________________________________________________ +mov ah, 2 +mov al, 1 +; sets up ch and cl +mov cx, [bp + 2] +xchg ch, cl +shl cl, 6 +or cl, [bp] + +mov dh, [bp + 1] +mov dl, [boot_device] +mov bx, 0x500 ; where we store the sector temporarily + +int 0x13 +jc .read_failed + +; mempcy __________________________________________________________ + +; we move it to the place at edi, which I don't think changes +mov esi, 0x500 +mov ecx, 512 +a32 rep movsb + +; recalc chs ______________________________________________________ + +; need to test for more overflows I think +inc WORD [bp] +mov al, [bp]; increase the sector we're on +cmp al, [max_sector] +jbe .continue_loop +mov WORD [bp], 1 + +inc WORD [bp + 1] +mov al, [bp + 1] +cmp al, [max_head] +jbe .continue_loop +mov WORD [bp + 1], 0 +inc DWORD [bp + 2] + +; loopin back ____________________________________________________ +.continue_loop: +mov cx, [bp + 4] + + +loop .sector_for_loop +add bp, 16 +mov sp, bp + + +ret + + + + +.read_failed: +mov bx, .loadsectors_error +call bios_print +cli +hlt + +.loadsectors_error: db "Error loading required sector!", 0 + +boot_device: db 0 +max_sector: db 0 +max_cylinder: dw 0 +max_head: db 0 + diff --git a/src/bootloader/bios_functions/bios_disk.asm b/src/bootloader/bios_functions/bios_disk.asm deleted file mode 100644 index 195057a..0000000 --- a/src/bootloader/bios_functions/bios_disk.asm +++ /dev/null @@ -1,40 +0,0 @@ -bios_disk: -.load_sectors: -pusha -mov es, dx - -; TODO when our kernel gets to big to fit in one track, we need to just switch over to LHS with extended bios functions. - -mov ah, 0x02 ; read disc sectors -mov ch, 0x00 ; track 0 -mov dh, 0x00 ; head 0 -mov dl, [stage0.boot_device] - -int 0x13 - -jc .failed - -mov ah, 0 -popa -ret - -.failed: -debug: -mov bx, .loadsectors_error -mov cx, 0 -call bios_print - -push 0 -mov al, ah -mov ah, 0 ; you need to clean up the bios print function! -push ax -mov cx, 1 -mov bx, sp -call bios_print - - -mov ah, 1 -popa -ret - -.loadsectors_error: db "Error loading sectors: ", 0 diff --git a/src/bootloader/bios_functions/print.asm b/src/bootloader/bios_functions/print.asm deleted file mode 100644 index 303fa8f..0000000 --- a/src/bootloader/bios_functions/print.asm +++ /dev/null @@ -1,58 +0,0 @@ -;TODO fix null problem, allow passing value insted of pointer -bios_print: -pusha -mov ah, 0x0e - -.print_loop: -mov al, [bx] -cmp al, 0 -je .fini - -test cx, cx ; if cx is zero, ascii, otherwise hex string -jne .print_hex -int 0x10 -.print_hex_ret: -inc bx -jmp .print_loop - -.fini: -mov al, 0xd -int 0x10 -mov al, 0xa -int 0x10 -popa -ret - - -.print_hex: -mov al, '0' -int 0x10 - -mov al, 'x' -int 0x10 - -mov al, [bx] -shr al, 4 -call .bios_print_nibble - -mov al, [bx] -and al, 0x0f -call .bios_print_nibble - -mov al, ' ' -int 0x10 - -jmp .print_hex_ret - - -.bios_print_nibble: -cmp al, 9 -ja .print_hex_letter -add al, 0x30 -int 0x10 -ret - -.print_hex_letter: -add al, 0x57 -int 0x10 -ret diff --git a/src/bootloader/bootloader.asm b/src/bootloader/bootloader.asm index 3ac10f3..f912e49 100644 --- a/src/bootloader/bootloader.asm +++ b/src/bootloader/bootloader.asm @@ -1,11 +1,11 @@ [bits 16] -[extern _kernel_size] +[extern _kernel_sector_size] [extern _bootloader_stage1_size] -[extern _kernel_loc] +[extern _kernel_s1_loc] jmp stage0 -times 3-($-$$) db 0x90 ; a temporary dirty fix to emulate a floppy disk insted of a hard risk -times 59 db 0 ; (TODO support hard disks) +times 3-($-$$) db 0x90 +times 59 db 0 stage0: @@ -13,44 +13,49 @@ jmp 0:.entry .entry: mov ax, 0 -mov ds, ax -mov bp, ax - mov ds, ax mov es, ax -mov ax, 0x8fc0 +;stack segments +mov ax, 0x7000 mov ss, ax -mov ax, 0xfffe +mov ax, 0xfff0 mov sp, ax +mov bp, 0 mov al, 0x92 or al, 2 out 0x92, al -mov [.boot_device], dl + +call bios_disk.init + mov bx, .loadstage2_msg -mov cx, 0 call bios_print -; TODO put in an error message and a maximum fail count .load_stage1: -mov al, _bootloader_stage1_size -mov cl, 0x2 ; read sector 2 -mov dx, 0x0 ; dest segment 0 -mov bx, 0x7e00 ; dest offst 0 -call bios_disk.load_sectors +;TODO LOAD STAGE ONE HERE + +; we start on 0x100000 +; esi: sector start +; cx: sector count +; edi: memory desination + +mov esi, 1 ; 2nt sector +mov ecx, _bootloader_stage1_size +mov edi, 0x7e00 ; desination +call bios_disk.load_sectors_v2 + jmp mbr_end.entry -.boot_device: db 0 .loadstage2_msg: db "Loading (stage 2) bootloader...", 0 -%include "bootloader/bios_functions/bios_disk.asm" -%include "bootloader/bios_functions/print.asm" +%include "bootloader/bios_disk.asm" +%include "bootloader/print.asm" times 510 - ($-$$) db 0 dw 0xaa55 @@ -66,15 +71,12 @@ boot_msg: mbr_end: .entry: +cli ; entering unreal mode mov bx, boot_msg.stage2_loaded -mov cx, 0 call bios_print -cli -push ds - lgdt [protected_gdt.descriptor] mov eax, cr0 @@ -83,52 +85,29 @@ mov cr0, eax jmp $+2 -mov bx, 0x10 ; descriptor 2, the data descriptor -mov ds, bx ; put it into the segment register -mov es, bx ; +mov bx, 0x10 +mov ds, bx +mov es, bx and al, 0xfe mov cr0, eax -pop ds +mov bx, 0 +mov ds, bx +mov es, bx sti -;we are now in unreal mode - -mov cl, 5 -mov edi, _kernel_loc -.loop: -mov al, 0x1 ; sector count -mov dx, 0x0 ; dest addr segment -mov bx, 0x500 ; dest addr offset -call bios_disk.load_sectors - - -inc cl - -push cx - -mov esi, 0x500 -mov ecx, 512 -a32 rep movsb -nop - -pop cx - -cmp cl, _kernel_size+2 -je .loop_end - -jmp .loop - -.loop_end: +mov esi, _bootloader_stage1_size +mov edi, 0x100000 +mov ecx, _kernel_sector_size +call bios_disk.load_sectors_v2 mov bx, boot_msg.kernel_loaded -mov cx, 0 call bios_print call detect_arch -call vbe_init +;call vbe_init done: call enter_longmode diff --git a/src/bootloader/cpu_check.asm b/src/bootloader/cpu_check.asm index 0fa6ddf..ec5ee7b 100644 --- a/src/bootloader/cpu_check.asm +++ b/src/bootloader/cpu_check.asm @@ -1,4 +1,4 @@ -[extern _meminfo_loc] +[extern _meminfo] detect_arch: ; detect CPUID @@ -19,6 +19,7 @@ cpuid and edx, 0x0020000000 jz .print_long_error + ; APIC mov eax, 0x00000001 cpuid @@ -31,14 +32,13 @@ jz .print_sse_error mov bx, .no_error -mov cx, 0 call bios_print ; get memory mappings mov ax, 0 mov es, ax -mov ax, _meminfo_loc +mov ax, _meminfo mov di, ax mov eax, 0xe820 @@ -64,50 +64,50 @@ je .mem_detected jmp .mem_detect_loop .mem_detected: +add di,24 +mov ecx, 24 +mov al, 0 +rep stosb + ret .print_cpuid_error: mov bx, .cpuid_error -mov cx, 0 call bios_print jmp $ .print_long_error: mov bx, .arch_error -mov cx, 0 call bios_print jmp $ .print_apic_error: mov bx, .apic_error -mov cx, 0 call bios_print jmp $ .print_mem_error: mov bx, .mem_error -mov cx, 0 call bios_print jmp $ .print_sse_error: mov bx, .sse_error -mov cx, 0 call bios_print jmp $ .cpuid_error: - db "No CPUID capabilitity", 0x0 + db "Somehow, your CPU doesn't even support the ability to detect its abilities. I'm gonna go out on a limb and say your cpu is too old to run this OS.", 0x0 .arch_error: - db "This operating system was compiled to run in 64 bit mode!", 0x0 + db "This operating system requires a x64 processor.", 0x0 .apic_error: - db "No apic support", 0x0 + db "No APIC support.", 0x0 .mem_error: - db "Could not get information on memory!", 0x0 + db "Couldn't obtain memory map.", 0x0 .sse_error: - db "This OS requires SSE", 0x0 + db "This OS requires the SSE instruction set.", 0x0 .no_error: - db "CPU info gathered!", 0x0 + db "CPU meets requirements to boot!", 0x0 diff --git a/src/bootloader/enter_kernel.asm b/src/bootloader/enter_kernel.asm index d3933cf..ef2cd71 100644 --- a/src/bootloader/enter_kernel.asm +++ b/src/bootloader/enter_kernel.asm @@ -1,14 +1,14 @@ [extern main] [extern _kernel_stack_loc] -[extern _stage1_pagetable] +[extern _kernel_page_size] enter_longmode: cli -; TODO check if a20 is already set mov al, 0x92 or al, 2 out 0x92, al +;enter 32 bit mode lgdt [protected_gdt.descriptor] mov eax, cr0 or eax, 0x1 @@ -30,44 +30,56 @@ mov es, ax mov fs, ax mov gs, ax -mov edi, _stage1_pagetable ; 0x3000 -mov cr3, edi -mov eax, 0 -mov ecx, 0xc00 ; 0x1000 -rep stosd -mov edi, cr3 +mov edi, 0x10000 +mov cr3, edi -mov DWORD [edi], _stage1_pagetable + 0x1003 ; pml4e[0] = pdpe -add edi, 0x1000 -mov DWORD [edi], _stage1_pagetable + 0x2003 ; pdpe[0] = pde -add edi, 0x1000 -mov DWORD [edi], 0x83 ; pde[0] = pte +mov eax, 0 +mov ecx, 0x1800 ; bzero 6 pages +rep stosd -mov eax, cr4 -or eax, 0x620 -mov cr4, eax +mov DWORD [0x10000], 0x11003 ; pml4e[0] = pdpe +mov DWORD [0x11000], 0x12003 ; pdpe[0] = pde +mov DWORD [0x12000], 0x83 ; pde[0] = pte + +mov DWORD [0x10ff8], 0x13003 +mov DWORD [0x13ff0], 0x14003 +mov DWORD [0x14000], 0x15003 + +mov eax, 0x100003 +mov ebx, 0 +mov ecx, _kernel_page_size +.kernel_load_loop: +mov DWORD [0x15000 + ebx], eax +add ebx, 8 +add eax, 0x1000 +loop .kernel_load_loop -;end of setting up pages -mov ecx, 0xc0000080 -rdmsr -or eax, 1 << 8 -wrmsr -mov eax, cr0 -or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)! -mov cr0, eax +mov eax, cr4 +; PAE, OSFXSR, OSXMMEXCPT +or eax, 1 << 5 | 1 << 9 | 1 << 10 +mov cr4, eax +;end of setting up pages +;testing to see if NX bit is available. +;If it's not and we enable it, it will cause pagefaults on read +mov eax, 0x80000001 +cpuid +and edx, 1 << 20 +shr edx, 9 + mov ecx, 0xc0000080 rdmsr -or eax, 1 << 8 +or eax, 1 << 8 | 1 << 11 +or eax, edx wrmsr mov eax, cr0 -and ax, 0xfffb -or eax, 0x80000002 +or eax, 1 << 31 | 1 << 0; +and ax, ~(1 << 2) mov cr0, eax @@ -76,8 +88,10 @@ lgdt [long_gdt.descriptor] jmp LONG_CODE_SEGMENT:enter_kernel enter_kernel: bits 64 -mov rbp, _kernel_stack_loc +mov rbp, 0 mov rsp, _kernel_stack_loc -call main ; where we actually call the kernel +mov rax, QWORD main +;push QWORD 0 +jmp rax jmp $ ret diff --git a/src/bootloader/gdt.asm b/src/bootloader/gdt.asm index 0ba0a44..0e6d89b 100644 --- a/src/bootloader/gdt.asm +++ b/src/bootloader/gdt.asm @@ -45,8 +45,8 @@ db 0 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 ;1st flags and type. The first four bits (1010) are type, and the last are flags. See https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf -db 10101111b ;1111 is segment limit continued. 0: available, 0: 64 bit (change?), 1: 32 bit segment, 1: granularity (shifts 3 hex didgets to get all of memory) +db 10011010b +db 00100000b db 0 .gdt_data: @@ -54,7 +54,7 @@ dw 0 dw 0 db 0 db 10010010b -db 00000000b +db 00100000b db 0 .gdt_end: ; later calculates offset in defs below diff --git a/src/bootloader/print.asm b/src/bootloader/print.asm new file mode 100644 index 0000000..29769f5 --- /dev/null +++ b/src/bootloader/print.asm @@ -0,0 +1,21 @@ +;TODO fix null problem, allow passing value insted of pointer +bios_print: +pusha +mov ah, 0x0e + +.print_loop: +mov al, [bx] +cmp al, 0 +je .fini + +int 0x10 +inc bx +jmp .print_loop + +.fini: +mov al, 0xd +int 0x10 +mov al, 0xa +int 0x10 +popa +ret diff --git a/src/bootloader/video.asm b/src/bootloader/video.asm index 5b292c2..e47c1dc 100644 --- a/src/bootloader/video.asm +++ b/src/bootloader/video.asm @@ -151,25 +151,21 @@ ret .vbe_unsupported: mov bx, .unsupported_msg -mov cx, 0 call bios_print jmp $ .vbe_generic_error: mov bx, .lazyerror_msg -mov cx, 0 call bios_print jmp $ .edid_error: mov bx, .ediderror_msg -mov cx, 0 call bios_print jmp $ .res_unsupported: mov bx, .res_unsupported_msg -mov cx, 0 call bios_print jmp $ diff --git a/src/debug/gdbinit.gdb b/src/debug/gdbinit.gdb index 6c0cc28..c890f8d 100644 --- a/src/debug/gdbinit.gdb +++ b/src/debug/gdbinit.gdb @@ -1,4 +1,11 @@ target remote localhost:1234 symbol-file debug/debug_syms.o -break *0x7c00 +hb smp_boot + + + +define cs2bs + print (1 << (5 + $arg0)) +end continue + diff --git a/src/debug/gdbinit.py b/src/debug/gdbinit.py new file mode 100755 index 0000000..75ab5ca --- /dev/null +++ b/src/debug/gdbinit.py @@ -0,0 +1,28 @@ +class NextInstructionAddress(gdb.Command): + """ +Run until Next Instruction address. + +Usage: nia + +Put a temporary breakpoint at the address of the next instruction, and continue. + +Useful to step over int interrupts. + +See also: http://stackoverflow.com/questions/24491516/how-to-step-over-interrupt-calls-when-debugging-a-bootloader-bios-with-gdb-and-q +""" + def __init__(self): + super().__init__( + 'nia', + gdb.COMMAND_BREAKPOINTS, + gdb.COMPLETE_NONE, + False + ) + def invoke(self, arg, from_tty): + frame = gdb.selected_frame() + arch = frame.architecture() + pc = gdb.selected_frame().pc() + length = arch.disassemble(pc)[0]['length'] + gdb.Breakpoint('*' + str(pc + length), temporary = True) + gdb.execute('continue') + +NextInstructionAddress() diff --git a/src/debug/i8086.xml b/src/debug/i8086.xml new file mode 100644 index 0000000..0c91287 --- /dev/null +++ b/src/debug/i8086.xml @@ -0,0 +1,113 @@ + + + + + + i8086 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/include/acpi.h b/src/include/acpi.h index c15e044..f06bc9b 100644 --- a/src/include/acpi.h +++ b/src/include/acpi.h @@ -1,30 +1,20 @@ +#ifndef acpi_included +#define acpi_included #include -#include +#include +#include -struct rsdp_v1 { - char sig[8]; - uint8_t checksum; - char OEMID[6]; - uint8_t version; - uint32_t rsdt_addr; -} __attribute__((packed)); +//sdt types +#define SDT_MADT 0 +#define SDT_HPET 1 -struct rsdp_v2 { - struct rsdp_v1 v1; - uint32_t len; - uint64_t xsdt_addr; - uint8_t extended_checksum; - uint8_t reserved[3]; -} __attribute__((packed)); +void find_root_sdp(); +void *find_sdt(int type); +void debug_acpi(); -typedef union rsdp_t { - struct rsdp_v1 v1; - struct rsdp_v2 v2; -} rsdp_t; - -struct acpi_header { +typedef struct sdt { char sig[4]; uint32_t length; uint8_t revision; @@ -34,6 +24,7 @@ struct acpi_header { uint32_t OEMRevision; uint32_t creator_id; uint32_t creator_revision; -} __attribute__((packed)); +} __attribute__((packed)) sdt_head; + -rsdp_t *find_RSDP(); +#endif diff --git a/src/include/heap.h b/src/include/heap.h new file mode 100644 index 0000000..b1d7d6a --- /dev/null +++ b/src/include/heap.h @@ -0,0 +1,5 @@ +void *malloc(size_t size); +void *realloc(void *old_chunk, size_t size); +void malloc_init(); +void debug_heap(); +void free(void *size); diff --git a/src/include/int.h b/src/include/int.h new file mode 100644 index 0000000..8cc6a88 --- /dev/null +++ b/src/include/int.h @@ -0,0 +1,84 @@ +#ifndef int_header +#define int_header + +#include +#include + + + +void usleep(unsigned int us); +void init_interrupts(); + +typedef uint32_t *lapic_t; + +//this is only for madt; do we really need it here? +struct ioapic_t { + void *address; + unsigned int gsi_base; + unsigned int gsi_count; +}; + +//future: if we start to do things like this more then once, +struct ioapic_fixedlen { + size_t count; + struct ioapic_t *ioapic; +}; + +//TODO change name +struct apic_vt { + uint8_t vector; + unsigned int delivery_mode:3; + unsigned int dest_mode:1; + unsigned int delivery_status:1; + unsigned int polarity:1; //0 = high, 1 = low. + unsigned int remote_irr:1; + unsigned int trigger_mode:1; + unsigned int mask:1; + unsigned long int reserved:40; + unsigned int destination:7; +} __attribute__((packed)); + + +//simplified idt_descriptor makes things easier +struct idt_entry { + void *addr; + unsigned int ist:3; + unsigned int type:4; + unsigned int priv:2; +}; + +#define IOAPIC_REDIRECT_FIXED(vector, destination) \ + ((struct apic_vt) { \ + .vector = vector, \ + .delivery_mode = 0, \ + .dest_mode = 0, \ + .polarity = 0, \ + .remote_irr = 0, \ + .trigger_mode = 0, \ + .mask = 0, \ + .destination = destination \ +}) + +#define KERNEL_IDT_GATE(isr) \ + ((struct idt_entry) { \ + .addr = isr, \ + .ist = 0, \ + .type = INT_GATE_64, \ + .priv = 0 \ +}) + +#define TASK_GATE_64 0x5 +#define INT_GATE_64 0xe +#define TRAP_GATE_64 0xf + +#define SPURRIOUS_VECTOR 255 + + +void create_fixed_interrupt(unsigned int irq, struct apic_vt *redirect); +void clear_int(); +unsigned int alloc_idt(struct idt_entry *entry); +void free_idt(unsigned int entry); +void modify_idt(struct idt_entry *entry, unsigned int vector); + + +#endif diff --git a/src/include/io.h b/src/include/io.h new file mode 100644 index 0000000..fb19bdc --- /dev/null +++ b/src/include/io.h @@ -0,0 +1,38 @@ +#ifndef io_header +#define io_header + +#include +#include + +static inline void outb(uint16_t port, uint8_t value) { + asm volatile("outb %1, %0" :: "a"(value), "Nd"(port)); +} + +static inline uint8_t inb(uint16_t port) { + uint8_t ret; + asm volatile("inb %0, %1" : "=a"(ret) : "Nd"(port)); + return(ret); +} + +static inline void io_wait() { + asm volatile("outb 0x80, %%al"::"a"(0)); +} + +static inline uint64_t read_tsc() { + uint64_t time; + asm volatile("xor rax, rax\n" + "rdtsc\n" + "shl rdx, 32\n" + "or rax, rdx\n" + "mov %0, rax\n" + :"=r"(time):); + return time; + +} + +void outb_wait(uint16_t port, uint8_t value); +void read_msr(uint32_t addr, uint64_t *value); +void write_msr(uint32_t addr, uint64_t value); +void hlt(); +uint64_t get_rip(); +#endif diff --git a/src/include/isv.h b/src/include/isv.h new file mode 100644 index 0000000..d9dfa1b --- /dev/null +++ b/src/include/isv.h @@ -0,0 +1,25 @@ +#ifndef isv_defined +#define isv_defined + +//TODO move to int.h + +struct int_frame { + void *rip; + uint64_t segment_selector; + uint64_t rflags; + void *rsp; + uint64_t stack_segment; +} __attribute__((packed)); + +struct exception_frame { + uint64_t err; + struct int_frame frame; +} __attribute__((packed)); + +__attribute__((interrupt)) void spurrious_int(void *unused); +__attribute__((interrupt)) void kernel_block(void *unused); +__attribute__((interrupt)) void fatal_hwexception(struct int_frame *frame); +__attribute__((interrupt)) void fatal_hwexception_errcode(struct exception_frame *frame); +__attribute__((interrupt)) void lapic_timer_racefixer(void *unused); + +#endif diff --git a/src/include/kernel.h b/src/include/kernel.h index 2a87f5e..4d8ea22 100644 --- a/src/include/kernel.h +++ b/src/include/kernel.h @@ -1,5 +1,13 @@ -#define EASTEREGG_BLOATWARE //TODO move to some kind of global config file -void panic(); +#ifndef KERNEL +#define KERNEL -#define KERNEL_PANIC_INVOKED 0 -//more to come + +#define PA_OFFSET 0xffff800000000000 +#define TXT_OFFSET 0xffffffff80000000 + +#define PHYS_TO_VIRT(addr) ((void *)(addr) + PA_OFFSET) + +#define DEV_EMAIL "brett_weiland@bpcspace.com" + + +#endif diff --git a/src/include/libc.h b/src/include/libc.h index c7ccda7..d0789cf 100644 --- a/src/include/libc.h +++ b/src/include/libc.h @@ -1,13 +1,17 @@ #ifndef _STRING_H_ #define _STRING_H_ #include +#include void *strcpy(char *dest, char *src); void *memcpy(void *dest, void *src, size_t n); //TODO void *bzero(const void *dest, size_t size); void *memset(void *s, char c, size_t n); +size_t strlen(const char *s); int strcmp(const char *str1, const char *str2); int strncmp(const char *str1, const char *str2, size_t n); int memcmp(const void *s1, const void *s2, size_t n); int ceil(double n1); +int round(double n1); + #endif diff --git a/src/include/madt.h b/src/include/madt.h new file mode 100644 index 0000000..84bfa5d --- /dev/null +++ b/src/include/madt.h @@ -0,0 +1,20 @@ +#ifndef madt_header +#define madt_header +#include + +struct cores_info { + unsigned int corecount; + uint8_t apic_id[256]; + uint8_t bsp; +}; + +void init_madt(); +void get_ioapic(struct ioapic_fixedlen *ret); +void get_coreinfo(struct cores_info *cores); +void debug_madt(); +unsigned int irq_to_gsi(unsigned int irq); +lapic_t get_lapic(); +void boot_multicore(); + + +#endif diff --git a/src/include/math.h b/src/include/math.h new file mode 100644 index 0000000..10b0521 --- /dev/null +++ b/src/include/math.h @@ -0,0 +1,6 @@ +#ifndef MATH_INCLUDED +#define MATH_INCLUDED + +#define DIV_ROUND_UP(number, factor) (((number) + ((factor) - 1)) / factor) + +#endif diff --git a/src/include/paging.h b/src/include/paging.h index 3d31ef2..16afae2 100644 --- a/src/include/paging.h +++ b/src/include/paging.h @@ -1,96 +1,23 @@ -#include -//paging errors -#define PAGEMAP_LOCATION 0x4000 #ifndef _PAGE_H_ #define _PAGE_H_ -#include - -#define PAGE_VIRT_UNALIGNED 0x01 -#define PAGE_PHYS_UNALIGNED 0x02 -#define PAGE_PHYS_INVALID 0x03 -#define PAGE_VIRT_INVALID 0x04 - -//* -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; // another bit we'll never use, 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; - 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 sign:11; -} page_entry; - - -typedef struct __attribute__((packed)) { - page_entry pml4e[512]; - page_entry pdpe[512]; - page_entry pde[512]; - page_entry pte[512]; -} page_table; - -#define MEM_AVAILABLE 1 -#define MEM_RESERVED 2 -#define MEM_APCI_RECLAIMABLE 3 -#define MEM_APCI_NVS 4 -#define MEM_BAD 5 - -#define PAGE_SIZE_4K 12 -#define PAGE_SIZE_2M 21 -#define PAGE_SIZE_1G 30 -#define MAX_BUDDY_ORDER 8 - -#define MAX_ZONE_CNT 16 //should cover all cases - -struct memory_table { - void *base; - uint64_t length; - uint32_t type; - uint32_t ACPI; -} __attribute__((packed)); - -/** - * the bsizes are there so we don't have to calculate it every time. - * - * Keep in mind that at if the allocator reaches the last buddy, - * it _will_ have to calculate the bitwidth, even if it's a multiple of 64. - * This scenario hopefully won't happen much during time sensitive areas, - * and (I think) linux calculates the buddy size every single time anyway. -**/ -struct phys_map { - struct phys_map *next; - void *zone_paddr; - uint64_t extra_bits; - uint64_t *buddy[MAX_BUDDY_ORDER]; -}; +#include +#include +#include -//clean up doing extra work some other time -#define LSIZE_FROM_BITLEN(bitlen) (((bitlen) + 63) / 64) -#define BITLEN_FROM_LSIZE(lsize) ((lsize) * 64) -#define GET_BUDDY_BITLEN(zone_len, order) ((zone_len) / (0x1000 << (order))) -#define GET_ORDER_CHUNKSIZE(order) (0x1000 << ((order))) +void unmap_lowmem(); +size_t map_complete_physical(); +void debug_print_memory(); -extern void* _meminfo_loc; -extern void* _stage2_pagetable; -bool map_page(void *virtual_addr, void *physical_addr, uint8_t PAGE_SIZE); -void debug_print_memory(); -void create_pagetable_stage2(uint64_t free_mem); -void init_memory(); //TODO removeme -void init_pmap(); -void *palloc(); -void *pfree(); +struct phys_map *init_pmap(size_t pagetable_size); +void *palloc(size_t size); +void pfree(void *addr, size_t size); void debug_pmap(); +void get_mem_capabilities(); +void ram_stresser(); #endif - diff --git a/src/include/panic.h b/src/include/panic.h index 1386348..6a987f4 100644 --- a/src/include/panic.h +++ b/src/include/panic.h @@ -1,27 +1,59 @@ #ifndef PANIC_INCLUDED #define PANIC_INCLUDED -#define EASTEREGG_BLOATWARE - #include -void panic(int reason, int type); +#define EASTEREGG_BLOATWARE + +//TODO this needs to be moved once we find somehwere better struct stack_frame { - struct stack_frame *next; - uint64_t function_base; + struct stack_frame *next; //rbp + void *function_base; //rip +} __attribute__((packed)); + +struct registers { + uint64_t rax, rbx, rcx, rdx, rsi, rdi; } __attribute__((packed)); -//kernel panic reasons, likely to grow at an extremely fast rate -#define KERNEL_PANIC_PMAPSIZE 0 -#define KERNEL_PANIC_RSDP_UNFOUND 1 -#define KERNEL_PANIC_KERNEL_RETURNED 2 +void panic(int reason, void *frame_p, struct registers *regs); + + +#define PANIC(reason) panic(reason, 0, 0) + +//hardware exceptions/faults +//kernel panic reasons 0-31 reserved for these +//later on, we can make an ugly function to find our vector. +//I did a lot of work assuming it was pushed onto the stack, +//so if I choose not to impliment that these defs will be deleted. +/** +#define KERNEL_PANIC_HWE_DE 0 +#define KERNEL_PANIC_HWE_BR 5 +#define KERNEL_PANIC_HWE_UD 6 +#define KERNEL_PANIC_HWE_NM 7 +#define KERNEL_PANIC_HWE_DF 8 +#define KERNEL_PANIC_HWE_TS 10 +#define KERNEL_PANIC_HWE_NP 11 +#define KERNEL_PANIC_HWE_SS 12 +#define KERNEL_PANIC_HWE_GP 13 +#define KERNEL_PANIC_HWE_PF 14 +#define KERNEL_PANIC_HWE_MF 16 +#define KERNEL_PANIC_HWE_AC 17 +#define KERNEL_PANIC_HWE_MC 18 +#define KERNEL_PANIC_HWE_XM 19 +#define KERNEL_PANIC_HWE_VE 20 +#define KERNEL_PANIC_HWE_SE 30 +**/ +#define KERNEL_PANIC_HW_EXCEPTION 0 +#define KERNEL_PANIC_HW_EXCEPTION_ERR 1 //exception with error code +//kernel generated exceptions +#define KERNEL_PANIC_RSDP_UNFOUND 32 +#define KERNEL_PANIC_KERNEL_RETURNED 33 +#define KERNEL_PANIC_INVALID_PFREE 34 +#define KERNEL_PANIC_INVALID_RSDT 35 +#define KERNEL_PANIC_INVALID_IOAPIC_VEC 36 +#define KERNEL_PANIC_HPET_REQUIRED 37 -//kernel panic types, may or may not expand once I get further in development -#define KERNEL_PANIC_INVOKED 0 -#define KERNEL_PANIC_ERROR 1 //i'll change this once I see what happends -//TODO move this to some kind of global more accesable header -#define DEV_EMAIL "brett_weiland@bpcspace.com" #endif diff --git a/src/include/random.h b/src/include/random.h new file mode 100644 index 0000000..6f35278 --- /dev/null +++ b/src/include/random.h @@ -0,0 +1,5 @@ +#ifndef random_header +#define random_header +void randinit(); +unsigned int randint(); +#endif diff --git a/src/include/serial.h b/src/include/serial.h index 824e245..ef5eecf 100644 --- a/src/include/serial.h +++ b/src/include/serial.h @@ -3,14 +3,25 @@ #define _SERIAL_H_ #include +#include + #define COM1 0x3f8 #define COM2 0x2f8 #define COM3 0x3e8 #define COM4 0x2e8 -int init_serial(uint16_t port); + +bool init_serial(uint16_t port); void serial_out(uint16_t port, char *string); void _putchar_serial(uint16_t port, char character); +void move_cursor(unsigned int x, unsigned int y); + + +//TODO fix shitty header +void _putchar_screen(char character); + +void clear_screen(); + #endif diff --git a/src/include/smp.h b/src/include/smp.h new file mode 100644 index 0000000..c4a675a --- /dev/null +++ b/src/include/smp.h @@ -0,0 +1,4 @@ +#ifndef SMP_INCLUDED +#define SMP_INCLUDED +void smp_boot(); +#endif diff --git a/src/include/testmalloc.h b/src/include/testmalloc.h new file mode 100644 index 0000000..25ab7f3 --- /dev/null +++ b/src/include/testmalloc.h @@ -0,0 +1,6 @@ +#ifndef testmalloc_header +#define testmalloc_header + +void test_malloc(unsigned int cnt); + +#endif diff --git a/src/include/timer.h b/src/include/timer.h new file mode 100644 index 0000000..0277e87 --- /dev/null +++ b/src/include/timer.h @@ -0,0 +1,8 @@ +#ifndef timer +#define timer + +void init_timer(); +void usleep(unsigned int us); +uint64_t timestamp(); + +#endif diff --git a/src/indigo_os b/src/indigo_os index 3df46fd..0a9c1af 100755 Binary files a/src/indigo_os and b/src/indigo_os differ 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); +} diff --git a/src/link.ld b/src/link.ld index f45ddec..529d43f 100644 --- a/src/link.ld +++ b/src/link.ld @@ -1,38 +1,34 @@ SEARCH_DIR(objects) -INPUT( -bootloader.o -libc.o -serial.o -video.o -printf.o -page.o -acpi.o -kernel.o -panic.o -) - -_kernel_stack_loc = 0x200000 - 8; -_kernel_loc = 0x100000; -_meminfo_loc = 0x7000; +_kernel_s1_loc = 0xffffffff80000000; +_meminfo = 0x7000; _vbe_infoblock = 0x500; -_stage2_pagetable = 0x200000; -_stage1_pagetable = 0x4000; SECTIONS { - . = 0x0; - bootloader 0x7c00 : + bootloader 0x7c00 : AT(0) { - bootloader.o(.text) + bootloader.o(.text) } - kernel _kernel_loc : - AT (ADDR(bootloader) + SIZEOF(bootloader)) - /*ALIGN(4096)*/ + smp_bootloader 0x8000 : + AT(SIZEOF(bootloader)) { - EXCLUDE_FILE (*bootloader.o) *(.text .data .bss .rodata .comment .eh_frame) + smp_trampoline.o(.text) } + kernel _kernel_s1_loc : + AT (SIZEOF(bootloader)) + { + EXCLUDE_FILE (*bootloader.o) *(.text .data .bss .rodata .comment .eh_frame) + } } -_kernel_size = ((SIZEOF(kernel) / 512) + (SIZEOF(bootloader) / 512)); /* there's a bug here I think!*/ -_bootloader_stage1_size = (SIZEOF(bootloader) / 512); +_kernel_sector_size = ((SIZEOF(kernel) + SIZEOF(smp_bootloader) + 511) / 512); +_kernel_page_size = ((SIZEOF(kernel) + SIZEOF(smp_bootloader) + 0xfff) / 0x1000); +_bootloader_stage1_size = (SIZEOF(bootloader) + 511) / 512; + +__load_start_smp_bootloader = LOADADDR(smp_bootloader); +__load_stop_smp_bootloader = LOADADDR(smp_bootloader) + SIZEOF(smp_bootloader); + +_kernel_stack_loc = (0x100000 + (_kernel_page_size * 0x1000) + 0x2000) - 8; +_kernel_shared_zone_begin = 0x100000 + (_kernel_page_size * 0x1000) + 0x2000; + diff --git a/src/makefile b/src/makefile index 2398509..83876c2 100644 --- a/src/makefile +++ b/src/makefile @@ -4,60 +4,98 @@ OBJCPY=../compiler/indigo_gcc/bin/x86_64-elf-objcopy INC=-I./include EMU_CORES=4 -EMU_RAM=4G +EMU_RAM=5G XRES=1024 YRES=768 -CCFLAGS=-g -ffreestanding -Wall +CFLAGS=-g -ffreestanding -mcmodel=kernel -masm=intel -Wall -O0 -make: - nasm -g -felf64 bootloader/bootloader.asm -o objects/bootloader.o - $(CC) $(INC) $(CCFLAGS) -c kernel/kernel.c -o objects/kernel.o - $(CC) $(INC) $(CCFLAGS) -c kernel/panic.c -o objects/panic.o - $(CC) $(INC) $(CCFLAGS) -c kernel/acpi.c -o objects/acpi.o - $(CC) $(INC) $(CCFLAGS) -c kernel/drivers/serial.c -o objects/serial.o - $(CC) $(INC) $(CCFLAGS) -c kernel/drivers/video.c -o objects/video.o - $(CC) $(INC) $(CCFLAGS) -c kernel/printf.c -o objects/printf.o - $(CC) $(INC) $(CCFLAGS) -c kernel/page.c -o objects/page.o - $(CC) $(INC) $(CCFLAGS) -c kernel/libc.c -o objects/libc.o - $(LD) -o indigo_os.elf --oformat=elf64-x86-64 -T link.ld +C_SRCFILES := $(wildcard kernel/*.c) +C_SRCFILES := $(filter-out kernel/isv.c, $(C_SRCFILES)) +C_OBJFILES := $(patsubst kernel/%.c,%.o,$(C_SRCFILES)) + +ASM_SRCFILES := $(wildcard kernel/*.asm) +ASM_SRCFILES := $(filter-out kernel/smp_trampoline.asm, $(ASM_SRCFILES)) +ASM_OBJFILES := $(patsubst kernel/%.asm,%.o,$(ASM_SRCFILES)) + + +MISC_OBJFILES := isv.o #this will probably expand over time for files that require special treatment +OBJFILES_PATH := $(patsubst %,objects/%,$(C_OBJFILES) $(ASM_OBJFILES) $(MISC_OBJFILES)) + +QEMU_OPTS=-smp $(EMU_CORES) -m $(EMU_RAM) -no-reboot -drive format=raw,file=./indigo_os + +QEMU_CPU=-cpu host,+invtsc,+tsc-deadline + +ifndef disable-kvm + QEMU_OPTS := $(QEMU_OPTS) -enable-kvm $(QEMU_CPU) +endif + +QEMU_PRINTDEBUG=-d int,guest_errors + + + +all: $(ASM_OBJFILES) $(C_OBJFILES) $(MISC_OBJFILES) bootloader.o smp_trampoline.o + $(LD) -o indigo_os.elf --no-check-sections --oformat=elf64-x86-64 -T link.ld $(OBJFILES_PATH) $(OBJCPY) --only-keep-debug indigo_os.elf debug/debug_syms.o $(OBJCPY) -O binary --strip-all indigo_os.elf indigo_os -ifneq ("$(wildcard $(./debug/serial.in))","") - mkfifo debug/serial.in + compiledb make --dry-run > /dev/null + + +isv.o: kernel/isv.c + $(CC) $(CFLAGS) $(INC) -mgeneral-regs-only -MMD -MP -c kernel/isv.c -o objects/$@ + +printf.o: kernel/printf.c +ifdef screen + $(CC) $(CFLAGS) $(INC) -MMD -MP -DSCREEN_OUTPUT -c kernel/printf.c -o objects/$@ +else + $(CC) $(CFLAGS) $(INC) -MMD -MP -c kernel/printf.c -o objects/$@ endif -ifneq ("$(wildcard $(./debug/serial.out))","") - mkfifo debug/serial.out + +kernel.o: kernel/kernel.c +ifdef screen + $(CC) $(CFLAGS) $(INC) -MMD -MP -DSCREEN_OUTPUT -c kernel/kernel.c -o objects/$@ +else + $(CC) $(CFLAGS) $(INC) -MMD -MP -c kernel/kernel.c -o objects/$@ endif -# rm -f indigo_os.elf +%.o: kernel/%.c makefile + $(CC) $(CFLAGS) $(INC) -MMD -MP -c $< -o objects/$@ + +%.o: kernel/%.asm makefile + nasm -g -felf64 $< -o objects/$@ + +bootloader.o: + nasm -g -felf64 bootloader/bootloader.asm -o objects/bootloader.o -preproc_debug: - nasm -g -felf64 bootloader/bootloader.asm - $(CC) $(INC) $(CCFLAGS) -E -c kernel/kernel.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/acpi.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/drivers/serial.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/drivers/video.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/printf.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/page.c - $(CC) $(INC) $(CCFLAGS) -E -c kernel/libc.c +smp_trampoline.o: + nasm -g -felf64 kernel/smp_trampoline.asm -o objects/smp_trampoline.o run: - qemu-system-x86_64 -smp $(EMU_CORES) -m $(EMU_RAM) -nographic -no-reboot -drive format=raw,file=./indigo_os - + qemu-system-x86_64 $(QEMU_OPTS) $(QEMU_PRINTDEBUG) -nographic gdb: indigo_os - tmux new-session -s os_gdb "qemu-system-x86_64 -smp $(EMU_CORES) -nographic -no-reboot -S -s -drive format=raw,file=./indigo_os -m $(EMU_RAM)"\;\ + tmux new-session -s os_gdb "qemu-system-x86_64 -S -s $(QEMU_OPTS) -nographic"\;\ split-window -h "gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64" run-graphical: - qemu-system-x86_64 -S -s -smp $(EMU_CORES) -m $(EMU_RAM) -no-reboot -serial pipe:debug/serial -device VGA,edid=on,xres=$(XRES),yres=$(YRES) -drive format=raw,file=./indigo_os &\ + qemu-system-x86_64 -device VGA,edid=on,xres=$(XRES),yres=$(YRES) -S -s $(QEMU_OPTS) &\ gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64 + +install-sandisk: indigo_os + test -h /dev/disk/by-id/usb-SanDisk_Cruzer_Fit_4C531001351010112404-0:0 && \ + sudo dd if=indigo_os of=/dev/disk/by-id/usb-SanDisk_Cruzer_Fit_4C531001351010112404-0:0 && \ + sync + +install-trav: indigo_os + test -h /dev/disk/by-id/usb-Kingston_DataTraveler_3.0_E0D55EA573F1E3A11963008B-0:0 && \ + sudo dd if=indigo_os of=/dev/disk/by-id/usb-Kingston_DataTraveler_3.0_E0D55EA573F1E3A11963008B-0:0 && \ + sync + + clean: rm -f objects/* rm -f indigo_os + rm -f indigo_os.elf rm -f bin/* rm -f debug/debug_syms.o - rm -f debug/serial.in - rm -f debug/serial.out -- cgit v1.2.3