major backup 8.24.21
This commit is contained in:
		
							parent
							
								
									bad4b0e9bd
								
							
						
					
					
						commit
						9b22a69655
					
				
							
								
								
									
										454
									
								
								src/.gdb_history
									
									
									
									
									
								
							
							
						
						
									
										454
									
								
								src/.gdb_history
									
									
									
									
									
								
							| @ -1,256 +1,256 @@ | ||||
| next | ||||
| print buddy_size | ||||
| print pmap->next | ||||
| print pmap | ||||
| print *pmap | ||||
| print *pmap | ||||
| print pmap | ||||
| c | ||||
| info threads | ||||
| quit | ||||
| quit | ||||
| quit | ||||
| break page.c:198 | ||||
| c | ||||
| watch pmap | ||||
| c | ||||
| print pmap | ||||
| next | ||||
| print buddy_size | ||||
| next | ||||
| c | ||||
| print *pmap | ||||
| quitquit | ||||
| quit | ||||
| break page.c | ||||
| c | ||||
| quit | ||||
| break init_pmap | ||||
| c | ||||
| next | ||||
| watch pmap_i | ||||
| c | ||||
| print pmap_i | ||||
| next | ||||
| quit | ||||
| break page.c:220 | ||||
| c | ||||
| quit | ||||
| break init_pmap | ||||
| c | ||||
| next | ||||
| watch pmap_i | ||||
| c | ||||
| print pmap_i | ||||
| c | ||||
| print pmap_i | ||||
| next | ||||
| print zones[zone_i] | ||||
| next | ||||
| break page.c:137 | ||||
| c | ||||
| next | ||||
| info b | ||||
| c | ||||
| print pmap_i | ||||
| c | ||||
| print pmap_i | ||||
| c | ||||
| print pmap_i | ||||
| next | ||||
| print *pmap | ||||
| print pmap | ||||
| quit | ||||
| break page.c:220 | ||||
| c | ||||
| print pmap | ||||
| print *pmap | ||||
| quit | ||||
| break debug_pmap | ||||
| c | ||||
| c | ||||
| quit | ||||
| break page.c:179 | ||||
| c | ||||
| next | ||||
| print buddy_bit | ||||
| print budorder | ||||
| c | ||||
| quit | ||||
| quit | ||||
| break page.c:147 | ||||
| c | ||||
| next | ||||
| print threshold_bitsize  | ||||
| print (uint64_t)threshold_bitsize | ||||
| print pmap_i | ||||
| print *pmap | ||||
| print threshold_bitsize  | ||||
| print buddy_bitsize | ||||
| next | ||||
| print buddy_bit | ||||
| print buddy_bit | ||||
| print buddy_bitlen | ||||
| print buddy_bitlen[0][7] | ||||
| print buddy_bitlen[0][7] | ||||
| next | ||||
| quit | ||||
| break panic | ||||
| c | ||||
| next | ||||
| x ebp | ||||
| print $ebp | ||||
| info reg ebp | ||||
| x 0x1ffff8 | ||||
| stack 50 | ||||
| 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 | ||||
| quit | ||||
| quit | ||||
| break panic | ||||
| c | ||||
| next | ||||
| info stack | ||||
| stack | ||||
| next | ||||
| info rsp | ||||
| x 0x1fff28 | ||||
| x *0x1fff28 | ||||
| stack 50 | ||||
| quit | ||||
| break panic | ||||
| 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 | ||||
| info threads | ||||
| 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 | ||||
| c | ||||
| print cores | ||||
| print cores_active | ||||
| info threads | ||||
| c | ||||
| info threads | ||||
| quit | ||||
| break panic.c:27 | ||||
| c | ||||
| info threads | ||||
| c | ||||
| info threads | ||||
| quit | ||||
| b smp_boot | ||||
| c | ||||
| qit | ||||
| quit | ||||
| b smp.c:59 | ||||
| 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 | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| info threads | ||||
| info threads | ||||
| quit | ||||
| break panic.c:29 | ||||
| b smp.c:65 | ||||
| c | ||||
| print *frame | ||||
| next | ||||
| info threads | ||||
| info thread 2 | ||||
| quit | ||||
| b timer.c:57 | ||||
| c | ||||
| quit | ||||
| break page.c:30 | ||||
| b timer.c:57 | ||||
| c | ||||
| quit | ||||
| break panic.c:30 | ||||
| b smp.c:57 | ||||
| c | ||||
| print *(uint32_t *)&icr | ||||
| print/x *(uint32_t *)&icr | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| next | ||||
| 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 | ||||
| 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 | ||||
| pirnt *frame | ||||
| print *frame | ||||
| d  | ||||
| d | ||||
| hb smp_trampoline | ||||
| c | ||||
| print *frame | ||||
| c | ||||
| print *frame | ||||
| c | ||||
| print *frame | ||||
| c | ||||
| print *frame | ||||
| x 0x1ffff8 | ||||
| info reg rip | ||||
| quit | ||||
| hb smp_trampoline | ||||
| 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 | ||||
| quit | ||||
| break 0x831e | ||||
| hb smp_trampoline | ||||
| c | ||||
| info threads | ||||
| hexdump 0 | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| cc | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| d | ||||
| c | ||||
| quit | ||||
| b *0x831e | ||||
| 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 | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| c | ||||
| quit | ||||
| c | ||||
| info threads | ||||
| quit | ||||
| c | ||||
| print *frame | ||||
| print *frame | ||||
| x *frame | ||||
| x/1 *frame | ||||
|  *frame | ||||
| info threads | ||||
| quit | ||||
| break main.c | ||||
| 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 | ||||
| break main | ||||
| c | ||||
| stack | ||||
| c | ||||
| 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 | ||||
| next | ||||
| info threads | ||||
| next | ||||
| info threads | ||||
| quit | ||||
| 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 | ||||
| b memcpy | ||||
| c | ||||
| print dest | ||||
| hexdump 0xffff800000008000 | ||||
| b 64 | ||||
| c | ||||
| hexdump 0xffff800000008000 | ||||
| print __load_start_smp_bootloader | ||||
| hexdump 0xffff800000000800 | ||||
| quit | ||||
| info reg rsp | ||||
| quit | ||||
|  | ||||
							
								
								
									
										437
									
								
								src/backup
									
									
									
									
									
								
							
							
						
						
									
										437
									
								
								src/backup
									
									
									
									
									
								
							| @ -1,437 +0,0 @@ | ||||
| #include <printf.h> | ||||
| #include <paging.h> | ||||
| #include <stdint.h> | ||||
| #include <libc.h>  | ||||
| #include <limits.h> | ||||
| #include <kernel.h> | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										149
									
								
								src/bootloader/bios_disk.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								src/bootloader/bios_disk.asm
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| 
 | ||||
| @ -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 | ||||
| @ -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 | ||||
| @ -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 | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
| @ -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 eax, 0 | ||||
| mov ecx, 0x1800     ; bzero 6 pages | ||||
| rep stosd | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 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, cr4          | ||||
| or eax, 0x620 | ||||
| ; 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 | ||||
| or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)! | ||||
| mov cr0, eax | ||||
| 
 | ||||
| 
 | ||||
| mov ecx, 0xc0000080 | ||||
| rdmsr | ||||
| or eax, 1 << 8 | ||||
| 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 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										21
									
								
								src/bootloader/print.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/bootloader/print.asm
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -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 $ | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										28
									
								
								src/debug/gdbinit.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										28
									
								
								src/debug/gdbinit.py
									
									
									
									
									
										Executable file
									
								
							| @ -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() | ||||
							
								
								
									
										113
									
								
								src/debug/i8086.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/debug/i8086.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | ||||
| <?xml version="1.0"?> | ||||
| <!-- Copyright (C) 2010-2017 Free Software Foundation, Inc. | ||||
| 
 | ||||
|      Copying and distribution of this file, with or without modification, | ||||
|      are permitted in any medium without royalty provided the copyright | ||||
|      notice and this notice are preserved.  --> | ||||
| 
 | ||||
| <!DOCTYPE target SYSTEM "gdb-target.dtd"> | ||||
| <target> | ||||
|     <architecture>i8086</architecture> | ||||
|     <feature name="org.gnu.gdb.i386.core"> | ||||
|         <flags id="i386_eflags" size="4"> | ||||
|             <field name="CF" start="0" end="0"/> | ||||
|             <field name="" start="1" end="1"/> | ||||
|             <field name="PF" start="2" end="2"/> | ||||
|             <field name="AF" start="4" end="4"/> | ||||
|             <field name="ZF" start="6" end="6"/> | ||||
|             <field name="SF" start="7" end="7"/> | ||||
|             <field name="TF" start="8" end="8"/> | ||||
|             <field name="IF" start="9" end="9"/> | ||||
|             <field name="DF" start="10" end="10"/> | ||||
|             <field name="OF" start="11" end="11"/> | ||||
|             <field name="NT" start="14" end="14"/> | ||||
|             <field name="RF" start="16" end="16"/> | ||||
|             <field name="VM" start="17" end="17"/> | ||||
|             <field name="AC" start="18" end="18"/> | ||||
|             <field name="VIF" start="19" end="19"/> | ||||
|             <field name="VIP" start="20" end="20"/> | ||||
|             <field name="ID" start="21" end="21"/> | ||||
|         </flags> | ||||
| 
 | ||||
|         <reg name="eax" bitsize="32" type="int32"/> | ||||
|         <reg name="ecx" bitsize="32" type="int32"/> | ||||
|         <reg name="edx" bitsize="32" type="int32"/> | ||||
|         <reg name="ebx" bitsize="32" type="int32"/> | ||||
|         <reg name="esp" bitsize="32" type="data_ptr"/> | ||||
|         <reg name="ebp" bitsize="32" type="data_ptr"/> | ||||
|         <reg name="esi" bitsize="32" type="int32"/> | ||||
|         <reg name="edi" bitsize="32" type="int32"/> | ||||
| 
 | ||||
|         <reg name="eip" bitsize="32" type="code_ptr"/> | ||||
|         <reg name="eflags" bitsize="32" type="i386_eflags"/> | ||||
|         <reg name="cs" bitsize="32" type="int32"/> | ||||
|         <reg name="ss" bitsize="32" type="int32"/> | ||||
|         <reg name="ds" bitsize="32" type="int32"/> | ||||
|         <reg name="es" bitsize="32" type="int32"/> | ||||
|         <reg name="fs" bitsize="32" type="int32"/> | ||||
|         <reg name="gs" bitsize="32" type="int32"/> | ||||
| 
 | ||||
|         <reg name="st0" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st1" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st2" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st3" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st4" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st5" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st6" bitsize="80" type="i387_ext"/> | ||||
|         <reg name="st7" bitsize="80" type="i387_ext"/> | ||||
| 
 | ||||
|         <reg name="fctrl" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="fstat" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="ftag" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="fiseg" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="fioff" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="foseg" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="fooff" bitsize="32" type="int" group="float"/> | ||||
|         <reg name="fop" bitsize="32" type="int" group="float"/> | ||||
|     </feature> | ||||
|     <feature name="org.gnu.gdb.i386.32bit.sse"> | ||||
|         <vector id="v4f" type="ieee_single" count="4"/> | ||||
|         <vector id="v2d" type="ieee_double" count="2"/> | ||||
|         <vector id="v16i8" type="int8" count="16"/> | ||||
|         <vector id="v8i16" type="int16" count="8"/> | ||||
|         <vector id="v4i32" type="int32" count="4"/> | ||||
|         <vector id="v2i64" type="int64" count="2"/> | ||||
|         <union id="vec128"> | ||||
|             <field name="v4_float" type="v4f"/> | ||||
|             <field name="v2_double" type="v2d"/> | ||||
|             <field name="v16_int8" type="v16i8"/> | ||||
|             <field name="v8_int16" type="v8i16"/> | ||||
|             <field name="v4_int32" type="v4i32"/> | ||||
|             <field name="v2_int64" type="v2i64"/> | ||||
|             <field name="uint128" type="uint128"/> | ||||
|         </union> | ||||
|         <flags id="i386_mxcsr" size="4"> | ||||
|             <field name="IE" start="0" end="0"/> | ||||
|             <field name="DE" start="1" end="1"/> | ||||
|             <field name="ZE" start="2" end="2"/> | ||||
|             <field name="OE" start="3" end="3"/> | ||||
|             <field name="UE" start="4" end="4"/> | ||||
|             <field name="PE" start="5" end="5"/> | ||||
|             <field name="DAZ" start="6" end="6"/> | ||||
|             <field name="IM" start="7" end="7"/> | ||||
|             <field name="DM" start="8" end="8"/> | ||||
|             <field name="ZM" start="9" end="9"/> | ||||
|             <field name="OM" start="10" end="10"/> | ||||
|             <field name="UM" start="11" end="11"/> | ||||
|             <field name="PM" start="12" end="12"/> | ||||
|             <field name="FZ" start="15" end="15"/> | ||||
|         </flags> | ||||
| 
 | ||||
|         <reg name="xmm0" bitsize="128" type="vec128" regnum="32"/> | ||||
|         <reg name="xmm1" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm2" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm3" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm4" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm5" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm6" bitsize="128" type="vec128"/> | ||||
|         <reg name="xmm7" bitsize="128" type="vec128"/> | ||||
| 
 | ||||
|         <reg name="mxcsr" bitsize="32" type="i386_mxcsr" group="vector"/> | ||||
|     </feature> | ||||
| </target> | ||||
| 
 | ||||
| @ -1,30 +1,20 @@ | ||||
| #ifndef acpi_included | ||||
| #define acpi_included | ||||
| #include <stdint.h> | ||||
| #include <libc.h> | ||||
| 
 | ||||
| struct rsdp_v1 { | ||||
|   char sig[8]; | ||||
|   uint8_t checksum; | ||||
|   char OEMID[6]; | ||||
|   uint8_t version; | ||||
|   uint32_t rsdt_addr; | ||||
| 
 | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct rsdp_v2 { | ||||
|   struct rsdp_v1 v1; | ||||
|   uint32_t len; | ||||
|   uint64_t xsdt_addr; | ||||
|   uint8_t extended_checksum; | ||||
|   uint8_t reserved[3];  | ||||
| } __attribute__((packed)); | ||||
| #include <stdbool.h> | ||||
| #include <int.h> | ||||
| 
 | ||||
| 
 | ||||
| typedef union rsdp_t {  | ||||
|   struct rsdp_v1 v1; | ||||
|   struct rsdp_v2 v2; | ||||
| } rsdp_t; | ||||
| //sdt types
 | ||||
| #define SDT_MADT 0 | ||||
| #define SDT_HPET 1 | ||||
| 
 | ||||
| struct acpi_header { | ||||
| 
 | ||||
| void find_root_sdp(); | ||||
| void *find_sdt(int type); | ||||
| void debug_acpi(); | ||||
| 
 | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										5
									
								
								src/include/heap.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/include/heap.h
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
							
								
								
									
										84
									
								
								src/include/int.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/include/int.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| #ifndef int_header | ||||
| #define int_header | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 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 | ||||
							
								
								
									
										38
									
								
								src/include/io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/include/io.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| #ifndef io_header | ||||
| #define io_header | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <printf.h> | ||||
| 
 | ||||
| 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 | ||||
							
								
								
									
										25
									
								
								src/include/isv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/include/isv.h
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -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 | ||||
|  | ||||
| @ -1,13 +1,17 @@ | ||||
| #ifndef _STRING_H_ | ||||
| #define _STRING_H_ | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/include/madt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/include/madt.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| #ifndef madt_header | ||||
| #define madt_header | ||||
| #include <int.h> | ||||
| 
 | ||||
| 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 | ||||
							
								
								
									
										6
									
								
								src/include/math.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/include/math.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #ifndef MATH_INCLUDED | ||||
| #define MATH_INCLUDED | ||||
| 
 | ||||
| #define DIV_ROUND_UP(number, factor) (((number) + ((factor) - 1)) / factor) | ||||
| 
 | ||||
| #endif | ||||
| @ -1,96 +1,23 @@ | ||||
| #include <stdbool.h> | ||||
| //paging errors
 | ||||
| #define PAGEMAP_LOCATION 0x4000 | ||||
| #ifndef _PAGE_H_ | ||||
| #define _PAGE_H_  | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #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]; | ||||
| }; | ||||
| 
 | ||||
| //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))) | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| extern void* _meminfo_loc; | ||||
| extern void* _stage2_pagetable; | ||||
| 
 | ||||
| bool map_page(void *virtual_addr, void *physical_addr, uint8_t PAGE_SIZE); | ||||
| void unmap_lowmem(); | ||||
| size_t map_complete_physical(); | ||||
| 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 | ||||
| 
 | ||||
|  | ||||
| @ -1,27 +1,59 @@ | ||||
| #ifndef PANIC_INCLUDED | ||||
| #define PANIC_INCLUDED | ||||
| 
 | ||||
| #define EASTEREGG_BLOATWARE | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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)); | ||||
| 
 | ||||
| //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 | ||||
| struct registers { | ||||
|   uint64_t rax, rbx, rcx, rdx, rsi, rdi; | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										5
									
								
								src/include/random.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/include/random.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| #ifndef random_header | ||||
| #define random_header | ||||
| void randinit(); | ||||
| unsigned int randint(); | ||||
| #endif | ||||
| @ -3,14 +3,25 @@ | ||||
| #define _SERIAL_H_ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #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 | ||||
|  | ||||
							
								
								
									
										4
									
								
								src/include/smp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/include/smp.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| #ifndef SMP_INCLUDED | ||||
| #define SMP_INCLUDED | ||||
| void smp_boot(); | ||||
| #endif | ||||
							
								
								
									
										6
									
								
								src/include/testmalloc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/include/testmalloc.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| #ifndef testmalloc_header | ||||
| #define testmalloc_header | ||||
| 
 | ||||
| void test_malloc(unsigned int cnt); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										8
									
								
								src/include/timer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/include/timer.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| #ifndef timer | ||||
| #define timer | ||||
| 
 | ||||
| void init_timer(); | ||||
| void usleep(unsigned int us); | ||||
| uint64_t timestamp(); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										
											BIN
										
									
								
								src/indigo_os
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/indigo_os
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -1,58 +1,169 @@ | ||||
| #include <acpi.h> | ||||
| #include <stdint.h> | ||||
| #include <printf.h> | ||||
| #include <kernel.h> | ||||
| #include <stdbool.h> | ||||
| #include <kernel.h> | ||||
| #include <io.h> | ||||
| #include <int.h> | ||||
| #include <libc.h> | ||||
| #include <panic.h> | ||||
| 
 | ||||
| static int RSDP_verify(void *rsdp_pointer) { | ||||
|   printf("Verifying potential RSDP at address 0x%p... ", rsdp_pointer);   | ||||
|   union rsdp_t *rsdp = rsdp_pointer; | ||||
|   uint8_t checksum = 0; | ||||
|   char *rsdp_csm_ptr = rsdp_pointer;  | ||||
|   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]; | ||||
| 
 | ||||
| //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 { | ||||
|     printf("APCI revision 1.\n"); | ||||
|     for(i = 0; i <= 20; i++) { | ||||
|       checksum += rsdp_csm_ptr[i]; | ||||
|     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); | ||||
|     } | ||||
|   } | ||||
|   if(checksum) { | ||||
|     return 0; | ||||
|     printf("Invalid, searching on.\n"); | ||||
|   } | ||||
|   printf("RSDP Verified!\n"); | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| rsdp_t *find_RSDP() {  | ||||
| //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; | ||||
|   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; | ||||
|   uint8_t checksum = 0;  | ||||
|   if(uv_rsdp->revision) { | ||||
|     for(i = 0; i < uv_rsdp->len; i++) { | ||||
|       checksum += rsdp_char_ptr[i]; | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
|     for(i = 0; i <= 20; i++) { | ||||
|       checksum += rsdp_char_ptr[i]; | ||||
|     } | ||||
|   } | ||||
|   if(!checksum) { | ||||
|     printf("Found RSDP revision %i at address %x.\n", uv_rsdp->revision, uv_rsdp); | ||||
|     return uv_rsdp; | ||||
|   } | ||||
|   printf("Skipped over invalid RSDP at 0x%p.\n", uv_rsdp); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,39 +0,0 @@ | ||||
| #include <stdint.h> | ||||
| #include <serial.h> | ||||
| 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); | ||||
| } | ||||
							
								
								
									
										211
									
								
								src/kernel/heap.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								src/kernel/heap.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,211 @@ | ||||
| #include <paging.h> | ||||
| #include <printf.h> | ||||
| #include <libc.h> | ||||
| #include <io.h> | ||||
| 
 | ||||
| /** 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; | ||||
| } | ||||
							
								
								
									
										253
									
								
								src/kernel/int.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								src/kernel/int.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,253 @@ | ||||
| #include <int.h> | ||||
| #include <acpi.h> | ||||
| #include <io.h> | ||||
| #include <paging.h> | ||||
| #include <printf.h> | ||||
| #include <isv.h> | ||||
| #include <kernel.h> | ||||
| #include <libc.h> | ||||
| #include <madt.h> | ||||
| #include <timer.h> | ||||
| #include <panic.h> | ||||
| 
 | ||||
| #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");  | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/kernel/io.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/kernel/io.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #include <io.h> | ||||
| #include <stdint.h> | ||||
| //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"); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										12
									
								
								src/kernel/isv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/kernel/isv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| #include <printf.h> | ||||
| #include <stdint.h> | ||||
| #include <isv.h>  | ||||
| #include <panic.h> | ||||
| 
 | ||||
| 
 | ||||
| __attribute__((interrupt)) void spurrious_int(void *unused) { | ||||
|   printf("Detected spurrious interrupt, doing nothing.\n"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										65
									
								
								src/kernel/isv_asm.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/kernel/isv_asm.asm
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
| @ -1,31 +1,45 @@ | ||||
| #include <stdbool.h> | ||||
| #include <smp.h> | ||||
| #include <serial.h> | ||||
| #include <printf.h> | ||||
| #include <paging.h> | ||||
| #include <video.h> | ||||
| #include <acpi.h> | ||||
| #include <panic.h> | ||||
| #include <kernel.h> | ||||
| #include <stdbool.h> | ||||
| #include <int.h> | ||||
| #include <io.h> | ||||
| #include <cpuid.h> | ||||
| #include <heap.h> | ||||
| #include <random.h> | ||||
| #include <timer.h> | ||||
| #include <libc.h> | ||||
| 
 | ||||
| //testing headers
 | ||||
| #include <testmalloc.h> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void main() { | ||||
|   if(!(init_serial(COM1))) { | ||||
|     printf("\nKernal started on CPU 1!\n"); // will detect cpu later
 | ||||
|   } | ||||
| #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(); | ||||
|   | ||||
|    | ||||
|   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); | ||||
|   } | ||||
|   find_root_sdp(); | ||||
|   debug_acpi(); | ||||
|    | ||||
|   init_interrupts(); | ||||
| 
 | ||||
|    | ||||
|   randinit(); | ||||
| 
 | ||||
|   dump_video(); | ||||
|   debug_print_memory(); | ||||
| 
 | ||||
|   init_pmap(); | ||||
|   debug_pmap(); | ||||
| 
 | ||||
|   panic(KERNEL_PANIC_KERNEL_RETURNED, KERNEL_PANIC_INVOKED); | ||||
|   smp_boot(); | ||||
| 
 | ||||
|   PANIC(KERNEL_PANIC_KERNEL_RETURNED); | ||||
| } | ||||
|  | ||||
							
								
								
									
										100
									
								
								src/kernel/klog.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/kernel/klog.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| #include <stdint.h> | ||||
| #include <serial.h> | ||||
| #include <io.h> | ||||
| #include <printf.h> | ||||
| #include <kernel.h> | ||||
| #include <stdbool.h> | ||||
| #include <libc.h> | ||||
| 
 | ||||
| //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++; | ||||
| } | ||||
| @ -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++) { | ||||
|  | ||||
							
								
								
									
										179
									
								
								src/kernel/madt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								src/kernel/madt.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,179 @@ | ||||
| #include <stdint.h> | ||||
| #include <libc.h> | ||||
| #include <acpi.h> | ||||
| #include <int.h> | ||||
| #include <kernel.h> | ||||
| #include <stddef.h> | ||||
| #include <heap.h> | ||||
| #include <printf.h> | ||||
| #include <smp.h> | ||||
| #include <madt.h> | ||||
| #include <cpuid.h> | ||||
| 
 | ||||
| //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++; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,12 +1,106 @@ | ||||
| #include <printf.h> | ||||
| #include <paging.h> | ||||
| #include <stdint.h> | ||||
| #include <libc.h>  | ||||
| #include <limits.h> | ||||
| #include <panic.h> | ||||
| #include <math.h> | ||||
| #include <kernel.h> | ||||
| #include <stdbool.h> | ||||
| #include <cpuid.h> | ||||
| 
 | ||||
| //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; | ||||
| 
 | ||||
|   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; | ||||
| 
 | ||||
| //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; | ||||
|    | ||||
|   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...
 | ||||
|       //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; | ||||
|       } | ||||
|   /* 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. | ||||
|    */ | ||||
| 
 | ||||
| 
 | ||||
|       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++; | ||||
| 
 | ||||
|       //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; | ||||
|       } | ||||
| 
 | ||||
|     } | ||||
|   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; | ||||
|   } | ||||
|   pmap_size = (void*)(pmap) - (void*)&_stage2_pagetable; | ||||
|   if(pmap_size >= zone_len[0]) panic(); //TODO debugging
 | ||||
| 
 | ||||
|   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; | ||||
| 
 | ||||
|         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; | ||||
| 
 | ||||
|         threshold_longsize = threshold_bitsize / 64; | ||||
|       } | ||||
|       pmap_bit = pmap_bbitsize & 63; | ||||
|       buddy_bit = buddy_bitlen[pmap_i][budorder] & 63; | ||||
|   while(blevel < MAX_BUDDY_ORDER) { | ||||
|     lshift = (page_bitloc / (1 << blevel)) & 63; | ||||
|     onbyte = pmap->buddy[blevel] + ((page_bitloc / 64) / (1 << blevel)); | ||||
|     bbitlen = size / (1 << blevel);  | ||||
| 
 | ||||
| 
 | ||||
|       if((pmap_bbitsize >= BITLEN_FROM_LSIZE(buddy_size)) && (pmap == (void *)&_stage2_pagetable)) { | ||||
|         bzero(pmap->buddy[budorder], buddy_size * 8); | ||||
|       } | ||||
|       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); | ||||
| 
 | ||||
|           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)); | ||||
|           } | ||||
|     //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)
 | ||||
| 
 | ||||
|     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++; | ||||
|     } | ||||
|     pmap_i++; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * 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. | ||||
| **/ | ||||
| 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; | ||||
| 
 | ||||
| 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; | ||||
|   if(size == 0) return 0; | ||||
|   if(size & 4095) { | ||||
|     size = DIV_ROUND_UP(size, 0x1000); | ||||
|   } | ||||
|   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; | ||||
|     size = size / 0x1000; | ||||
|   } | ||||
| error: | ||||
|   printf("Page allocation error!\n"); | ||||
|   return false; | ||||
| 
 | ||||
|   //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; | ||||
|   } | ||||
| 
 | ||||
|   for(blevel = min_blevel; blevel < MAX_BUDDY_ORDER; blevel++) { | ||||
|     for(pmap = first_pmap; pmap != 0; pmap = pmap->next) { | ||||
| 
 | ||||
|       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; | ||||
| 
 | ||||
|           *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; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //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; | ||||
|      | ||||
| 
 | ||||
|   page_table *pml4 = (page_table *)PAGEMAP_LOCATION; | ||||
|   page_table *pdpe = (page_table *)&_kernel_shared_zone_begin; | ||||
|   page_table *pde; | ||||
| 
 | ||||
|   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(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 { | ||||
|         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; | ||||
| 
 | ||||
|       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; | ||||
|       } | ||||
|     } | ||||
|     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; | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
|   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(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; | ||||
|           } | ||||
|         } | ||||
|         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); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       | ||||
|       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); | ||||
|     } | ||||
|   } | ||||
|   return pmap; | ||||
| } | ||||
|  | ||||
| @ -1,13 +1,15 @@ | ||||
| #include <panic.h> | ||||
| #include <stdint.h> | ||||
| #include <printf.h> | ||||
| #include <kernel.h> | ||||
| #include <serial.h> | ||||
| #include <isv.h> | ||||
| 
 | ||||
| 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"); | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -39,10 +39,12 @@ | ||||
| #include <serial.h> | ||||
| 
 | ||||
| //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 | ||||
| 
 | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										36
									
								
								src/kernel/random.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/kernel/random.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| #include <stdbool.h> | ||||
| #include <cpuid.h> | ||||
| #include <printf.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										80
									
								
								src/kernel/smp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/kernel/smp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | ||||
| #include <kernel.h> | ||||
| #include <madt.h> | ||||
| #include <timer.h> | ||||
| #include <cpuid.h> | ||||
| #include <int.h> | ||||
| #include <libc.h> | ||||
| 
 | ||||
| #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); | ||||
|   } | ||||
|   **/ | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										140
									
								
								src/kernel/smp_trampoline.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/kernel/smp_trampoline.asm
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||
							
								
								
									
										35
									
								
								src/kernel/testmalloc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/kernel/testmalloc.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| #define CHUNK_SIZE_FROM_INDEX(i) ((1 << ((i) + 5))) | ||||
| 
 | ||||
| #include <printf.h> | ||||
| #include <heap.h> | ||||
| #include <libc.h> | ||||
| #include <random.h> | ||||
| 
 | ||||
| //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"); | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										296
									
								
								src/kernel/timer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								src/kernel/timer.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,296 @@ | ||||
| #include <acpi.h> | ||||
| #include <stdbool.h> | ||||
| #include <io.h> | ||||
| #include <printf.h> | ||||
| #include <libc.h> | ||||
| #include <kernel.h> | ||||
| #include <cpuid.h> | ||||
| #include <panic.h> | ||||
| #include <int.h> | ||||
| #include <isv.h> | ||||
| 
 | ||||
| 
 | ||||
| #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; | ||||
|   } | ||||
| } | ||||
| @ -5,5 +5,6 @@ | ||||
| 
 | ||||
| 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); | ||||
|   printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n",  | ||||
|       video->width, video->height, video->bpp, video->framebuffer); | ||||
| } | ||||
							
								
								
									
										48
									
								
								src/link.ld
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								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)) | ||||
|   { | ||||
|     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; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										108
									
								
								src/makefile
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								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 | ||||
| endif | ||||
| ifneq ("$(wildcard $(./debug/serial.out))","") | ||||
| 	mkfifo debug/serial.out | ||||
| endif | ||||
| #	rm -f indigo_os.elf
 | ||||
| 	compiledb make --dry-run > /dev/null | ||||
| 
 | ||||
| 
 | ||||
| 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  | ||||
| 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 | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| %.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 | ||||
| 
 | ||||
| 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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Brett Weiland
						Brett Weiland