diff --git a/i386/i386/bitops.h b/i386/i386/bitops.h new file mode 100644 index 0000000..877b3ad --- /dev/null +++ b/i386/i386/bitops.h @@ -0,0 +1,50 @@ +#ifndef _MACH_I386_BITOPS_H_ +#define _MACH_I386_BITOPS_H_ + +#include + +void set_bit(unsigned long nr, volatile vm_offset_t addr) +{ + test_and_set_bit(nr,addr); +} + +void clear_bit(unsigned long nr, volatile vm_offset_t addr) +{ + test_and_clear_bit(nr,addr); +} + +int test_and_set_bit(unsigned long nr, volatile vm_offset_t addr) +{ + + int oldbit; + + __asm__ __volatile__( + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (*(void volatile *)addr) + :"Ir" (nr) : "memory"); + return oldbit; +} + + +int test_and_clear_bit(unsigned long nr, volatile vm_offset_t addr) +{ + + int oldbit; + __asm__ __volatile__( + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (*(void volatile *)addr) + :"Ir" (nr) : "memory"); + return oldbit; +} + + +int test_bit(int nr, unsigned long * addr) +{ + int mask; + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + + return ((mask & (*addr)) != 0); +} + +#endif diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c index ca00078..6afb213 100644 --- a/i386/i386at/model_dep.c +++ b/i386/i386at/model_dep.c @@ -32,10 +32,9 @@ * Basic initialization for I386 - ISA bus machines. */ +#include #include - #include - #include #include #include @@ -74,6 +73,7 @@ #include #endif /* MACH_XEN */ + /* Location of the kernel's symbol table. Both of these are 0 if none is available. */ #if MACH_KDB @@ -104,8 +104,11 @@ unsigned long la_shift = VM_MIN_KERNEL_ADDRESS; struct multiboot_info boot_info; #endif /* MACH_XEN */ +/* To make sure that the boot memory allocator is initialized */ +int boot_allocator_initialized= 0; /* Command line supplied to kernel. */ char *kernel_cmdline = ""; +int kernel_cmdline_len = 0; /* This is used for memory initialization: it gets bumped up through physical memory @@ -334,43 +337,54 @@ i386at_init(void) */ mem_size_init(); + init_boot_allocator(); + #ifdef MACH_XEN kernel_cmdline = (char*) boot_info.cmd_line; #else /* MACH_XEN */ /* Copy content pointed by boot_info before losing access to it when it * is too far in physical memory. */ + if (boot_info.flags & MULTIBOOT_CMDLINE) { vm_offset_t addr; - int len = strlen ((char*)phystokv(boot_info.cmdline)) + 1; - assert(init_alloc_aligned(round_page(len), &addr)); + assert(init_alloc_aligned(kernel_cmdline_len, &addr)); kernel_cmdline = (char*) phystokv(addr); - memcpy(kernel_cmdline, (char*)phystokv(boot_info.cmdline), len); + memcpy(kernel_cmdline, (char*)phystokv(boot_info.cmdline), kernel_cmdline_len); + bootmap_free(atop(boot_info.cmdline - phys_first_addr), atop(round_page(kernel_cmdline_len))); boot_info.cmdline = addr; } + + if (boot_info.flags & MULTIBOOT_MODS) { struct multiboot_module *m; vm_offset_t addr; - int i; - - assert(init_alloc_aligned(round_page(boot_info.mods_count * sizeof(*m)), &addr)); - m = (void*) phystokv(addr); - memcpy(m, (void*) phystokv(boot_info.mods_addr), boot_info.mods_count * sizeof(*m)); + int i,size; + + size = boot_info.mods_count * sizeof(*m); + assert(init_alloc_aligned(size, &addr)); + m = (struct multiboot_module *) phystokv(addr); + memcpy(m, (void*) phystokv(boot_info.mods_addr), size); + bootmap_free(atop(round_page(boot_info.mods_addr)), atop(round_page(size) )); boot_info.mods_addr = addr; + for (i = 0; i < boot_info.mods_count; i++) { - vm_size_t size = m[i].mod_end - m[i].mod_start; - assert(init_alloc_aligned(round_page(size), &addr)); + vm_size_t size = m[i].mod_end - m[i].mod_start + 1; + assert(init_alloc_aligned(size, &addr)); memcpy((void*) phystokv(addr), (void*) phystokv(m[i].mod_start), size); + bootmap_free(atop(m[i].mod_start),atop(round_page(size))); m[i].mod_start = addr; - m[i].mod_end = addr + size; - + m[i].mod_end = addr + size - 1; size = strlen((char*) phystokv(m[i].string)) + 1; - assert(init_alloc_aligned(round_page(size), &addr)); + assert(init_alloc_aligned(size, &addr)); memcpy((void*) phystokv(addr), (void*) phystokv(m[i].string), size); + bootmap_free(atop(m[i].string-phys_first_addr),atop(round_page(size))); m[i].string = addr; } } + + #endif /* MACH_XEN */ /* @@ -379,8 +393,11 @@ i386at_init(void) * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS. * XXX make the BIOS page (page 0) read-only. */ + pmap_bootstrap(); + + /* * Turn paging on. * We'll have to temporarily install a direct mapping @@ -395,7 +412,7 @@ i386at_init(void) #if PAE /* PAE page tables are 2MB only */ kernel_page_dir[lin2pdenum(VM_MIN_KERNEL_ADDRESS) + 1] = - kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS) + 1]; + kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS) + 1]; kernel_page_dir[lin2pdenum(VM_MIN_KERNEL_ADDRESS) + 2] = kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS) + 2]; #endif /* PAE */ @@ -486,6 +503,7 @@ i386at_init(void) as the interrupt stack for now. Later this will have to change, because the init stack will get freed after bootup. */ asm("movl %%esp,%0" : "=m" (int_stack_top)); + } /* @@ -569,6 +587,7 @@ void c_boot_entry(vm_offset_t bi) } #endif /* MACH_KDB */ + machine_slot[0].is_cpu = TRUE; machine_slot[0].running = TRUE; machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386; @@ -593,6 +612,7 @@ void c_boot_entry(vm_offset_t bi) /* * Start the system. */ + setup_main(); } @@ -650,127 +670,184 @@ unsigned int pmap_free_pages(void) return atop(avail_remaining); } -/* Always returns page-aligned regions. */ -boolean_t -init_alloc_aligned(vm_size_t size, vm_offset_t *addrp) +typedef struct init_bootmap { + vm_offset_t bitmap; + vm_offset_t next_avail; +} init_bootmap_t; + +static init_bootmap_t bootmap; + + +void +bootmap_free(unsigned long sidx, unsigned long pages) { - vm_offset_t addr; + unsigned long eidx = sidx + pages; + for (; sidx < eidx ; sidx++) + clear_bit(sidx,bootmap.bitmap); +} + +void +bootmap_allocate(unsigned long sidx, unsigned long pages) +{ + unsigned long eidx = sidx + pages; + for (; sidx < eidx ; sidx++) + set_bit(sidx,bootmap.bitmap); +} + +void +init_boot_allocator(void){ + + unsigned long sidx,eidx; + extern char start[], end[]; + unsigned long map_size; + + map_size = ((atop(round_page(phys_last_addr - phys_first_addr))) + 7) >> 3; + map_size = (map_size + sizeof(long) - 1UL) & ~(sizeof(long) -1UL); + bootmap.bitmap = 0x4000; /* Second Page*/ + bootmap.next_avail = 16*1024*1024; + memset((void *)bootmap.bitmap, 0x00, map_size); /* map is initially free */ #ifdef MACH_HYP /* There is none */ - if (!avail_next) - avail_next = _kvtophys(boot_info.pt_base) + (boot_info.nr_pt_frames + 3) * 0x1000; -#else /* MACH_HYP */ - extern char start[], end[]; - int i; - static int wrapped = 0; - - /* Memory regions to skip. */ - vm_offset_t cmdline_start_pa = boot_info.flags & MULTIBOOT_CMDLINE - ? boot_info.cmdline : 0; - vm_offset_t cmdline_end_pa = cmdline_start_pa - ? cmdline_start_pa+strlen((char*)phystokv(cmdline_start_pa))+1 - : 0; - vm_offset_t mods_start_pa = boot_info.flags & MULTIBOOT_MODS - ? boot_info.mods_addr : 0; - vm_offset_t mods_end_pa = mods_start_pa - ? mods_start_pa - + boot_info.mods_count * sizeof(struct multiboot_module) - : 0; - - retry: + if (bootmap.next_avail == 0) + bootmap.next_avail = _kvtophys(boot_info.pt_base) + (boot_info.nr_pt_frames + 3) * 0x1000; #endif /* MACH_HYP */ - /* Page-align the start address. */ - avail_next = round_page(avail_next); -#ifndef MACH_HYP - /* Start with memory above 16MB, reserving the low memory for later. */ - /* Don't care on Xen */ - if (!wrapped && phys_last_addr > 16 * 1024*1024) - { - if (avail_next < 16 * 1024*1024) - avail_next = 16 * 1024*1024; - else if (avail_next == phys_last_addr) - { - /* We have used all the memory above 16MB, so now start on - the low memory. This will wind up at the end of the list - of free pages, so it should not have been allocated to any - other use in early initialization before the Linux driver - glue initialization needs to allocate low memory. */ - avail_next = 0x1000; - wrapped = 1; - } - } -#endif /* MACH_HYP */ - /* Check if we have reached the end of memory. */ - if (avail_next == - ( + #ifndef MACH_HYP - wrapped ? 16 * 1024*1024 : -#endif /* MACH_HYP */ - phys_last_addr)) - return FALSE; - /* Tentatively assign the current location to the caller. */ - addr = avail_next; - /* Bump the pointer past the newly allocated region - and see where that puts us. */ - avail_next += size; -#ifndef MACH_HYP - /* Skip past the I/O and ROM area. */ - if ((avail_next > (boot_info.mem_lower * 0x400)) && (addr < 0x100000)) - { - avail_next = 0x100000; - goto retry; - } + /* Reserve the first Page */ + bootmap_allocate(0,1); - /* Skip our own kernel code, data, and bss. */ - if ((avail_next > (vm_offset_t)start) && (addr < (vm_offset_t)end)) - { - avail_next = (vm_offset_t)end; - goto retry; - } + /* Reserve the area of the bootmap.bitmap*/ + bootmap_allocate(atop(bootmap.bitmap-phys_first_addr),atop(round_page(map_size))); - /* Skip any areas occupied by valuable boot_info data. */ - if ((avail_next > cmdline_start_pa) && (addr < cmdline_end_pa)) - { - avail_next = cmdline_end_pa; - goto retry; - } - if ((avail_next > mods_start_pa) && (addr < mods_end_pa)) - { - avail_next = mods_end_pa; - goto retry; - } - if ((avail_next > kern_sym_start) && (addr < kern_sym_end)) + /* Reserve the I/O and ROM area. */ + sidx = atop(boot_info.mem_lower * 0x400); + eidx = atop(0x100000); + bootmap_allocate(sidx, eidx-sidx+1); + + + + /* Reserve our own kernel code, data, and bss. */ + sidx = atop(start); + eidx = atop(round_page(end)); + bootmap_allocate(sidx, eidx-sidx+1); + + + + + /* Reserve any areas occupied by valuable boot_info data. */ + sidx = atop(kern_sym_start); + eidx = atop(round_page(kern_sym_end)); + bootmap_allocate(sidx, eidx-sidx+1); + + + + if (boot_info.flags & MULTIBOOT_CMDLINE) { - avail_next = kern_sym_end; - goto retry; + kernel_cmdline_len = strlen ((char*)phystokv(boot_info.cmdline)) + 1; + sidx = atop(boot_info.cmdline - phys_first_addr); + bootmap_allocate(sidx, atop(round_page(kernel_cmdline_len))); } + + + + /* Reserve some area for loaded modules */ if (boot_info.flags & MULTIBOOT_MODS) { struct multiboot_module *m = (struct multiboot_module *) phystokv(boot_info.mods_addr); + + sidx = atop(boot_info.mods_addr - phys_first_addr); + + bootmap_allocate(sidx, atop(round_page(boot_info.mods_count * sizeof(*m)))); + + int i; for (i = 0; i < boot_info.mods_count; i++) { - if ((avail_next > m[i].mod_start) - && (addr < m[i].mod_end)) - { - avail_next = m[i].mod_end; - goto retry; - } - /* XXX string */ + + sidx = atop(m[i].mod_start - phys_first_addr); + eidx = atop(round_page(m[i].mod_end) - phys_first_addr ); + bootmap_allocate(sidx, eidx-sidx+1); + sidx = atop(m[i].string - phys_first_addr); + bootmap_allocate(sidx, atop(round_page(strlen((char*)phystokv(m[i].string))+1))); } } + + + #endif /* MACH_HYP */ + + boot_allocator_initialized = 1; +} + +boolean_t +init_alloc_aligned(vm_size_t size, vm_offset_t *addrp) +{ + size = round_page(size); + if(!_init_alloc_aligned(size, addrp,bootmap.next_avail)){ + if(_init_alloc_aligned(size,addrp,0)){ + bootmap.next_avail = *addrp + size; + return TRUE; + }else{ + return FALSE; + } + }else{ + bootmap.next_avail = *addrp + size; + return TRUE; + } +} + +boolean_t +_init_alloc_aligned(vm_size_t size, vm_offset_t *addrp, vm_offset_t goal) +{ + if (!boot_allocator_initialized){ + init_boot_allocator(); + } + + + vm_offset_t map = bootmap.bitmap; + unsigned long sidx=0, idx=0,last_page,first_page; + vm_size_t size_found = 0; + + size = round_page(size); + goal = round_page(goal); + last_page = atop(phys_last_addr); + first_page = atop(phys_first_addr); + + if (goal >= phys_first_addr && goal+size <= phys_last_addr){ + sidx = idx = atop(goal - phys_first_addr); + }else{ + sidx = idx = 0; + } + + while(1){ + if(idx+first_page >= last_page) + return FALSE; + + if(test_bit(idx,map)){ + sidx = ++idx; + size_found = 0; + continue; + } + + size_found += PAGE_SIZE; + if (size_found >= size) + break; + + idx++; + } + avail_remaining -= size; + *addrp = ptoa(sidx) + phys_first_addr; - *addrp = addr; + bootmap_allocate(sidx,atop(size)); return TRUE; }