From cf7cd8be60c254b44b444c97dcb238d7cf3afd4c Mon Sep 17 00:00:00 2001 From: Brett Weiland Date: Tue, 21 Sep 2021 10:50:33 -0500 Subject: palloc smp safe (testing required, NOT pfree) --- src/kernel/heap.c | 6 ++- src/kernel/kernel.c | 23 ++++++++-- src/kernel/libc.c | 8 ++++ src/kernel/page.c | 97 ++++++++++++++++++++++++++++++++++++------- src/kernel/random.c | 7 ++-- src/kernel/smp.c | 30 ++++++++++++- src/kernel/smp_racetest.c | 52 +++++++++++++++++++++++ src/kernel/smp_trampoline.asm | 1 + src/kernel/testmalloc.c | 35 ---------------- 9 files changed, 198 insertions(+), 61 deletions(-) create mode 100644 src/kernel/smp_racetest.c delete mode 100644 src/kernel/testmalloc.c (limited to 'src/kernel') diff --git a/src/kernel/heap.c b/src/kernel/heap.c index db6392f..e2dcbc7 100644 --- a/src/kernel/heap.c +++ b/src/kernel/heap.c @@ -26,10 +26,11 @@ 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; + unsigned int free:1; + unsigned int mutex:1; + unsigned long reserved:54; struct heap_chunk *fd; struct heap_chunk *bk; } chunk; @@ -203,6 +204,7 @@ void *malloc(size_t size) { 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)); diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index ab60f18..0aa394e 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -18,15 +18,24 @@ #include //testing headers -//#include +#include void kmain() { + printf("Kernal started on core %i\n", get_coreid()); + sync_malloc(); PANIC(KERNEL_PANIC_KERNEL_RETURNED); } +static bool smp_unlocked = false; void smp_kinit() { - printf("Kernal started on core <<<<< \n"); + + asm(".wait_for_release:\n" + "mov al, [%0]\n" + "test al, al\n" + "jz .wait_for_release\n" + ::"m"(smp_unlocked)); + smp_load_idt(); kmain(); } @@ -39,7 +48,8 @@ void kernel_init() { pmap_size = map_complete_physical(); init_klog(); init_pmap(pmap_size); - printf("\nKernal started on CPU 1!\n"); + printf("\nKernal started on core 1!\n"); + //test_malloc(100); find_root_sdp(); @@ -52,7 +62,12 @@ void kernel_init() { clear_screen(); debug_pzone(); - smp_boot(); + smp_prepare(); + + //the rest of this needs to get done before the cores start executing + init_pmap_smp(); + smp_unlocked = true; + fix_stack(); unmap_lowmem(); kmain(); diff --git a/src/kernel/libc.c b/src/kernel/libc.c index 4278281..f46c59f 100644 --- a/src/kernel/libc.c +++ b/src/kernel/libc.c @@ -1,5 +1,6 @@ #include #include +#include // TODO clean up variable names int strncmp(const char *s1, const char *s2, unsigned int n) { int i; @@ -18,6 +19,13 @@ size_t strlen(const char *s) { return(len); } +bool is_empty(const char *s, size_t size) { + for(size_t i = 0; i < size; i++) { + if(s[i]) return false; + } + return true; +} + int strcmp(const char *s1, const char *s2) { int i; for(i = 0; ((s1[i] != '\0') && (s2[i] != '\0')); i++) { diff --git a/src/kernel/page.c b/src/kernel/page.c index dea3941..0b286a4 100644 --- a/src/kernel/page.c +++ b/src/kernel/page.c @@ -7,11 +7,15 @@ #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; - +//expects core_id +#define waitlist_i(y) (((core_id) * sizeof(uintptr_t)) + (y)) // PAGE MAPPING #define PAGEMAP_LOCATION 0x10000 @@ -22,12 +26,21 @@ extern char _kernel_shared_zone_begin; typedef struct phys_map { struct phys_map *next; unsigned int max_buddy; + + //has to be a 16 bit variable + uint16_t mutex; //we might improve the speed of this later + uint64_t bsize[MAX_BUDDY_ORDER]; uint64_t *buddy[MAX_BUDDY_ORDER]; } pmap_t; static pmap_t *first_pmap; +//I'd like to find out a way to get rid of this... we only use it once +static unsigned int pmap_count = 0; + +static pmap_t **waiting_pmaps; + #define MEM_AVAILABLE 1 #define MEM_RESERVED 2 #define MEM_APCI_RECLAIMABLE 3 @@ -161,10 +174,10 @@ void debug_pmap() { //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 + uint64_t *onbyte; + uint64_t page_bitloc; + int bbitlen; + int lshift; pmap_t *pmap = first_pmap; /* note: there's no security check to see if the page is actually allocated, @@ -176,7 +189,7 @@ void pfree(void *addr, size_t size) { if(((uintptr_t)addr & 4095) || (size & 4095)) { PANIC(KERNEL_PANIC_INVALID_PFREE); - return; //TODO [minor] some more specificity, not a huge deal + return; } size /= 0x1000; for(; pmap != 0; pmap = pmap->next) { @@ -221,7 +234,7 @@ void pfree(void *addr, size_t size) { if(bbitlen <= 1) { *onbyte |= ((uint64_t)1 << lshift); break; - } else if(bbitlen & 1) { //check me + } else if(bbitlen & 1) { size -= (1 << blevel); *onbyte |= ((uint64_t)1 << (bbitlen + lshift)); } @@ -232,12 +245,16 @@ void pfree(void *addr, size_t size) { void *palloc(size_t size) { + uint8_t core_id = get_coreid(); bool self_alloc; int min_blevel, blevel; - uint64_t bbit, unshifted_entry, threshold, bloc; //TODO move when you've confirmed casting stuff + uint64_t bbit, unshifted_entry, threshold, bloc; uint64_t buddy_i, *ret, *bentry; int itercount; + bool unlocked_pmaps_searched = false; pmap_t *pmap = first_pmap; + unsigned int waitingp_i = 0; + unsigned int searchingp_i; if(size == 0) return 0; @@ -263,7 +280,19 @@ void *palloc(size_t size) { } for(blevel = min_blevel; blevel < MAX_BUDDY_ORDER; blevel++) { - for(pmap = first_pmap; pmap != 0; pmap = pmap->next) { + //for(pmap = first_pmap; pmap != 0; pmap = pmap->next) { + //while(!unlocked_pmaps_searched || + // is_empty(waiting_pmaps[core_id], sizeof(&pmap) * pmap_count)) { + pmap = first_pmap; + while(pmap) { + + if(get_set_mutex(&pmap->mutex)) { + if(!unlocked_pmaps_searched) waiting_pmaps[waitlist_i(waitingp_i++)] = pmap; + goto get_next_pmap; + } + + + if(unlocked_pmaps_searched) waiting_pmaps[waitlist_i(waitingp_i)] = 0; for(buddy_i = 0; buddy_i < pmap->bsize[blevel]; buddy_i++) { if(pmap->buddy[blevel][buddy_i] > (uint64_t)0) { @@ -295,11 +324,42 @@ void *palloc(size_t size) { } *bentry |= (unshifted_entry << bloc); } - if(!self_alloc) bzero(ret, size * 0x1000); + pmap->mutex = 0; + if(!self_alloc) bzero(ret, size * 0x1000); //TODO do we really need to bezero here? return ret; } } +get_next_pmap: + pmap->mutex = 0; + if(unlocked_pmaps_searched) { + pmap = 0; + for(searchingp_i = waitingp_i + 1; searchingp_i < pmap_count; searchingp_i++) { + if(waiting_pmaps[waitlist_i(searchingp_i)]) { + pmap = waiting_pmaps[waitlist_i(searchingp_i)]; + break; + } + } + if(!pmap) { + for(searchingp_i = 0; searchingp_i <= waitingp_i; searchingp_i++) { + if(waiting_pmaps[waitlist_i(searchingp_i)]) { + pmap = waiting_pmaps[waitlist_i(searchingp_i)]; + break; + } + } + } + } + else { + if(!pmap->next) { + pmap = waiting_pmaps ? waiting_pmaps[waitlist_i(0)] : 0; + unlocked_pmaps_searched = true; + } + else { + pmap = pmap->next; + } + } } + unlocked_pmaps_searched = false; + waitingp_i = 0; } return 0; } @@ -374,12 +434,19 @@ size_t map_complete_physical() { } } -pmap_t *init_pmap(size_t pagetable_size) { +void init_pmap_smp() { + size_t pmap_arrsize = corecount * pmap_count * sizeof(waiting_pmaps); + waiting_pmaps = malloc(pmap_arrsize); + bzero(waiting_pmaps, pmap_arrsize); +} + +void *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; + @@ -387,6 +454,7 @@ pmap_t *init_pmap(size_t pagetable_size) { 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); + pmap_count++; 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); @@ -396,7 +464,6 @@ pmap_t *init_pmap(size_t pagetable_size) { zone_size = zones[zone_i].length; pmap = PHYS_TO_VIRT(zones[zone_i].base); } - if(first_pmap_i) { pmap->next = NULL; first_pmap_i = false; @@ -405,6 +472,8 @@ pmap_t *init_pmap(size_t pagetable_size) { pmap->next = last_pmap; } + pmap->mutex = 0; + for(budorder = 0; budorder < MAX_BUDDY_ORDER; budorder++) { pmap_bbitsize = zone_size / (0x1000 << budorder); pmap->bsize[budorder] = DIV_ROUND_UP(pmap_bbitsize , 64); @@ -440,8 +509,8 @@ pmap_t *init_pmap(size_t pagetable_size) { } 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); //TODO (MAJOR BUG) something isn't right, I don't think + first_pmap = pmap; + palloc(pmap_size); } } return pmap; diff --git a/src/kernel/random.c b/src/kernel/random.c index 404223a..c959f6c 100644 --- a/src/kernel/random.c +++ b/src/kernel/random.c @@ -7,10 +7,9 @@ static bool hw_random = false; static unsigned long int seed = -1; void randinit() { - unsigned int unused, eax, ecx; - eax = 0; + unsigned int unused, ecx; ecx = 0; - __get_cpuid(1, &eax, &unused, &ecx, &unused); + __get_cpuid(1, &unused, &unused, &ecx, &unused); hw_random = (ecx >> 30) & 1; printf("Kernel random source: %s.\n", (hw_random) ? "rdrand" : "pseudo"); } @@ -31,6 +30,6 @@ unsigned int randint() { seed = 1103515245 * seed + 12345; return(unsigned int)(seed / 65536) % 32768; } - return 0; + return random_long; } diff --git a/src/kernel/smp.c b/src/kernel/smp.c index ff08f93..a55fe49 100644 --- a/src/kernel/smp.c +++ b/src/kernel/smp.c @@ -53,11 +53,30 @@ struct cpu_info { static struct gdt_descriptor gdtr; +struct cores_info cores; -void smp_boot() { +struct apicid_to_coreid_deleteme { //WILL BE DELETED AFTER THREADING EXISTS TODO + uint8_t apic_id; + uint8_t core_id; +}; + +static struct apicid_to_coreid_deleteme *apicid_to_coreid; + + +uint8_t get_coreid() { //WILL BE DELETED AFTER THREADING EXISTS TODO + uint32_t ebx, unused_cpuid; + uint8_t apic_id; + __get_cpuid(1, &unused_cpuid, &ebx, &unused_cpuid, &unused_cpuid); + apic_id = ebx >> 24; + for(uint8_t core = 0; core < corecount; core++) { + if(apicid_to_coreid[core].apic_id == apic_id) return apicid_to_coreid[core].core_id; + } + return 0; +} + +void smp_prepare() { uint8_t cores_active = 1; uint8_t stack_i = 0, core_i; - struct cores_info cores; struct icr_reg icr; struct cpu_info *stackarray; get_coreinfo(&cores); @@ -72,11 +91,18 @@ void smp_boot() { corecount = cores.corecount; stackarray = malloc(sizeof(struct cpu_info) * (cores.corecount - 1)); + apicid_to_coreid = malloc(sizeof(struct apicid_to_coreid_deleteme) * (cores.corecount - 1)); for(core_i = 0; core_i < cores.corecount; core_i++) { + + //WILL BE DELETED AFTER THREADING EXISTS TODO + apicid_to_coreid[core_i].apic_id = cores.apic_id[core_i]; + apicid_to_coreid[core_i].core_id = core_i; + if(cores.apic_id[core_i] == cores.bsp) continue; stackarray[stack_i].apic_id = cores.apic_id[core_i]; stackarray[stack_i].stack = palloc(0x1000); stackarray[stack_i].secondary_bsp = (stack_i)? false : true; + stack_i++; } for(stack_i = 0; stack_i < (cores.corecount - 1); stack_i++) { diff --git a/src/kernel/smp_racetest.c b/src/kernel/smp_racetest.c new file mode 100644 index 0000000..f86e030 --- /dev/null +++ b/src/kernel/smp_racetest.c @@ -0,0 +1,52 @@ +#define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + 5))) + +#include +#include +#include +#include +#include +#include + +//will delete later + +static uint8_t lockeroni = 0; + +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"); + unlock(&lockeroni); +} +uint8_t cores_waiting = 4; +void sync_malloc() { + void *mtest; + asm("lock decb [%0]\n" + "spinlock:\n" + "cmpb [%0], 0\n" + "jnz spinlock\n" + ::"m"(cores_waiting)); + mtest = palloc(0x1000); + printf("Make sure none of these match -> %lx\n", mtest); +} diff --git a/src/kernel/smp_trampoline.asm b/src/kernel/smp_trampoline.asm index 20c971e..cc91c3a 100644 --- a/src/kernel/smp_trampoline.asm +++ b/src/kernel/smp_trampoline.asm @@ -185,6 +185,7 @@ pause jnz .wait_for_gdt lgdt [final_gdt_descriptor] + mov rax, smp_kinit jmp rax diff --git a/src/kernel/testmalloc.c b/src/kernel/testmalloc.c deleted file mode 100644 index 5733c7c..0000000 --- a/src/kernel/testmalloc.c +++ /dev/null @@ -1,35 +0,0 @@ -#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"); - -} -- cgit v1.2.3