diff --git a/src/kernel/boot/arch/x86/bootblock.asm b/src/kernel/boot/arch/x86/bootblock.asm index 999caf044e..7d4ca6ee31 100644 --- a/src/kernel/boot/arch/x86/bootblock.asm +++ b/src/kernel/boot/arch/x86/bootblock.asm @@ -25,11 +25,12 @@ ; ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; /* -; ** Copyright 2001, Travis Geiselbrecht. All rights reserved. +; ** Copyright 2004, The OpenBeOS Team. All rights reserved. +; ** Distributed under the terms of the OpenBeOS License. +; ** +; ** Copyright 2001-2004, Travis Geiselbrecht. All rights reserved. ; ** Distributed under the terms of the NewOS License. -; */ - -; /* +; ** ; ** Reviewed, documented and some minor modifications and bug-fixes ; ** applied by Michael Noisternig on 2001-09-02. ; */ @@ -89,15 +90,17 @@ unreal: sti mov si,loadmsg call print - dec cx ; TK: one sector is already read as second part of boot block call load_floppy ; read remaining sectors at address edi call disable_floppy_motor mov si,okmsg call print cli + ; uncomment the next two lines to enable the VESA mode switch ; call enable_vesa - mov [in_vesa],al + ; mov [in_vesa],al + + call find_mem_size_real mov ebx,[dword 0x100074] ; load dword at rel. address 0x74 from read-destination-buffer add ebx,0x101000 ; for stage2 entry @@ -111,7 +114,7 @@ unreal: jmp dword 0x8:code32 ; flush prefetch queue code32: BITS 32 - mov ax,0x10 ; load descriptor 2 in all segment selectors (except cs) + mov ax,0x10 ; load descriptor 2 in all segment selectors (except cs) mov ds,ax mov es,ax mov fs,ax @@ -120,38 +123,39 @@ BITS 32 mov ebp,0x10000 mov esp,ebp - mov eax,[vesa_info] + mov eax,[vesa_info] ; set up arguments for _start() push eax xor eax,eax mov al,[in_vesa] push eax - call find_mem_size + xor eax,eax + mov al,[ext_mem_count] push eax - call ebx ; jump to stage2 entry -inf:jmp short inf + cmp al, 0x0 + je probe_mem -; find memory size by testing -; OUT: eax = memory size -find_mem_size: - mov eax,0x31323738 ; test value - mov esi,0x100ff0 ; start above conventional mem + HMA = 1 MB + 1024 Byte -_fms_loop: - mov edx,[esi] ; read value - mov [esi],eax ; write test value - mov ecx,[esi] ; read it again - mov [esi],edx ; write back old value - cmp ecx,eax - jnz _fms_loop_out ; read value != test value -> above mem limit - add esi,0x1000 ; test next page (4 K) - jmp short _fms_loop -_fms_loop_out: - mov eax,esi - sub eax,0x1000 - add eax,byte +0x10 - ret + mov eax,[ext_mem_info] + push eax + + xor eax,eax ; argument mem_size is loaded + push eax ; with zero + + jmp call_stage2 + +probe_mem: + xor eax,eax ; argument ext_mem_info is + push eax ; loaded with zero + + call find_mem_size_probe + push eax + ; falls through + +call_stage2: + call ebx ; jump to stage2 entry +inf:jmp short inf BITS 16 ; read sectors into memory @@ -276,13 +280,64 @@ gdt: retrycnt db 3 in_vesa db 0 -vesa_info dw 0 +vesa_info dd 0 +ext_mem_info dd 0 +ext_mem_count db 0 times 510-($-$$) db 0 ; filler for boot sector dw 0xaa55 ; magic number for boot sector ; Starting here is the second sector of the boot code +BITS 32 +; find memory size by testing +; OUT: eax = memory size +find_mem_size_probe: + mov eax,0x31323738 ; test value + mov esi,0x100ff0 ; start above conventional mem + HMA = 1 MB + 1024 Byte +_fms_loop: + mov edx,[esi] ; read value + mov [esi],eax ; write test value + mov ecx,[esi] ; read it again + mov [esi],edx ; write back old value + cmp ecx,eax + jnz _fms_loop_out ; read value != test value -> above mem limit + add esi,0x1000 ; test next page (4 K) + jmp short _fms_loop +_fms_loop_out: + mov eax,esi + sub eax,0x1000 + add eax,byte +0x10 + ret + +BITS 16 +find_mem_size_real: + ; use int 0x15, EAX=0xe820 to test for memory + ; assumes es is null + + mov ebx,0 + mov edi,0x7000 ; the extended memory structures will go at 0x7000 + mov [ext_mem_info],edi + +find_mem_next: + mov eax,0xe820 + mov edx,'PAMS' ; 'SMAP' in the correct order + mov ecx,0x20 + + int 0x15 + jc done_mem_real ; if carry is set, it wasn't supported + + inc byte [ext_mem_count] ; increment the count of the number + + cmp ebx,0x0 ; test if we're done + je done_mem_real + + add edi,0x20 ; increment the buffer by 0x20 + jmp find_mem_next + +done_mem_real: + ret + ; fool around with vesa mode enable_vesa: ; put the VBEInfo struct at 0x30000 @@ -325,6 +380,7 @@ mode_loop: test ax,0x1 ; test the supported bit jz next_mode test ax,0x08 ; test the linear frame mode bit + jz next_mode mov ax,[es:di+18] cmp ax,VESA_X_TARGET ; x jne next_mode diff --git a/src/kernel/boot/arch/x86/bootblock.bin b/src/kernel/boot/arch/x86/bootblock.bin index d5682be040..4804db82c9 100644 Binary files a/src/kernel/boot/arch/x86/bootblock.bin and b/src/kernel/boot/arch/x86/bootblock.bin differ diff --git a/src/kernel/boot/arch/x86/stage2.c b/src/kernel/boot/arch/x86/stage2.c index b3dd83bd8f..4cad61a54a 100644 --- a/src/kernel/boot/arch/x86/stage2.c +++ b/src/kernel/boot/arch/x86/stage2.c @@ -25,11 +25,19 @@ const unsigned kBSSSize = 0x9000; # define MESSAGE(x) #endif +// memory structure returned by int 0x15, ax 0xe820 +typedef struct ext_memory { + uint64 base_addr; + uint64 length; + uint64 type; + uint64 filler; +} ext_memory; + // we're running out of the first 'file' contained in the bootdir, which is // a set of binaries and data packed back to back, described by an array // of boot_entry structures at the beginning. The load address is fixed. #define BOOTDIR_ADDR 0x100000 -static const boot_entry *bootdir = (boot_entry*)BOOTDIR_ADDR; +static const boot_entry *bootdir = (boot_entry *)BOOTDIR_ADDR; // stick the kernel arguments in a pseudo-random page that will be mapped // at least during the call into the kernel. The kernel should copy the @@ -37,7 +45,7 @@ static const boot_entry *bootdir = (boot_entry*)BOOTDIR_ADDR; static kernel_args *ka = (kernel_args *)0x20000; // needed for message -static uint16 *kScreenBase = (unsigned short*) 0xb8000; +static uint16 *kScreenBase = (uint16 *)0xb8000; static uint32 screenOffset = 0; unsigned int cv_factor = 0; @@ -50,6 +58,7 @@ static uint32 *pgdir = 0; static uint32 *pgtable = 0; // function decls for this module +static void sort_addr_range(addr_range *range, int count); static void calculate_cpu_conversion_factor(void); static void load_elf_image(void *data, uint32 *next_paddr, addr_range *ar0, addr_range *ar1, uint32 *start_addr, addr_range *dynamic_section); @@ -58,6 +67,9 @@ static void mmu_map_page(uint32 vaddr, uint32 paddr); static int check_cpu(void); +extern void _start(uint32 memSize, ext_memory *extMemoryBlock, uint32 extMemoryCount, + int in_vesa, uint32 vesa_ptr); + /* called by the stage1 bootloader. * State: * 32-bit @@ -67,7 +79,8 @@ static int check_cpu(void); */ void -_start(uint32 mem, int in_vesa, uint32 vesa_ptr) +_start(uint32 memSize, ext_memory *extMemoryBlock, uint32 extMemoryCount, + int in_vesa, uint32 vesa_ptr) { uint32 *idt; segment_descriptor *gdt; @@ -82,7 +95,8 @@ _start(uint32 mem, int in_vesa, uint32 vesa_ptr) clearscreen(); dprintf("stage2 bootloader entry.\n"); - dprintf("memsize = 0x%x, in_vesa %d, vesa_ptr 0x%x\n", mem, in_vesa, vesa_ptr); + dprintf("args: memsize 0x%x, emem_block %p, emem_count %d, in_vesa %d, vesa = %p\n", + memSize, extMemoryBlock, extMemoryCount, in_vesa, vesa_ptr); // verify we can run on this cpu if (check_cpu() < 0) { @@ -95,6 +109,16 @@ _start(uint32 mem, int in_vesa, uint32 vesa_ptr) for (;;); } + if (extMemoryCount > 0) { + uint32 i; + + dprintf("extended memory info (from 0xe820):\n"); + for (i = 0; i < extMemoryCount; i++) { + dprintf(" base 0x%Lx, len 0x%Lx, type %Ld\n", + extMemoryBlock[i].base_addr, extMemoryBlock[i].length, extMemoryBlock[i].type); + } + } + // calculate the conversion factor that translates rdtsc time to real microseconds calculate_cpu_conversion_factor(); @@ -234,18 +258,96 @@ _start(uint32 mem, int in_vesa, uint32 vesa_ptr) ka->arch_args.vir_pgdir = next_vaddr; next_vaddr += PAGE_SIZE; - // save the kernel args - ka->arch_args.system_time_cv_factor = cv_factor; - ka->physical_memory_range[0].start = 0; - ka->physical_memory_range[0].size = mem; - ka->num_physical_memory_ranges = 1; - ka->str = NULL; + // mark memory that we know is used ka->physical_allocated_range[0].start = BOOTDIR_ADDR; ka->physical_allocated_range[0].size = next_paddr - BOOTDIR_ADDR; ka->num_physical_allocated_ranges = 1; + + // figure out the memory map + if (extMemoryCount > 0) { + uint32 i; + + ka->num_physical_memory_ranges = 0; + + for (i = 0; i < extMemoryCount; i++) { + if (extMemoryBlock[i].type == 1) { + // round everything up to page boundaries, exclusive of pages it partially occupies + extMemoryBlock[i].length -= (extMemoryBlock[i].base_addr % PAGE_SIZE) + ? (PAGE_SIZE - (extMemoryBlock[i].base_addr % PAGE_SIZE)) : 0; + extMemoryBlock[i].base_addr = ROUNDUP(extMemoryBlock[i].base_addr, PAGE_SIZE); + extMemoryBlock[i].length = ROUNDOWN(extMemoryBlock[i].length, PAGE_SIZE); + + // this is mem we can use + if (ka->num_physical_memory_ranges == 0) { + ka->physical_memory_range[0].start = (addr_t)extMemoryBlock[i].base_addr; + ka->physical_memory_range[0].size = (addr_t)extMemoryBlock[i].length; + ka->num_physical_memory_ranges++; + } else { + // we might have to extend the previous hole + addr_t previous_end = ka->physical_memory_range[ka->num_physical_memory_ranges - 1].start + + ka->physical_memory_range[ka->num_physical_memory_ranges - 1].size; + + if (previous_end <= extMemoryBlock[i].base_addr + && ((extMemoryBlock[i].base_addr - previous_end) < 0x100000)) { + // extend the previous buffer + ka->physical_memory_range[ka->num_physical_memory_ranges - 1].size += + (extMemoryBlock[i].base_addr - previous_end) + + extMemoryBlock[i].length; + + // mark the gap between the two allocated ranges in use + ka->physical_allocated_range[ka->num_physical_allocated_ranges].start = previous_end; + ka->physical_allocated_range[ka->num_physical_allocated_ranges].size = extMemoryBlock[i].base_addr - previous_end; + ka->num_physical_allocated_ranges++; + } + } + } + } + } else { + // we dont have an extended map, assume memory is contiguously mapped at 0x0 + ka->physical_memory_range[0].start = 0; + ka->physical_memory_range[0].size = memSize; + ka->num_physical_memory_ranges = 1; + + // mark the bios area allocated + ka->physical_allocated_range[ka->num_physical_allocated_ranges].start = 0x9f000; // 640k - 1 page + ka->physical_allocated_range[ka->num_physical_allocated_ranges].size = 0x61000; + ka->num_physical_allocated_ranges++; + } + + // save the memory we've virtually allocated (for the kernel and other stuff) ka->virtual_allocated_range[0].start = KERNEL_BASE; ka->virtual_allocated_range[0].size = next_vaddr - KERNEL_BASE; ka->num_virtual_allocated_ranges = 1; + + // sort the address ranges + sort_addr_range(ka->physical_memory_range, ka->num_physical_memory_ranges); + sort_addr_range(ka->physical_allocated_range, ka->num_physical_allocated_ranges); + sort_addr_range(ka->virtual_allocated_range, ka->num_virtual_allocated_ranges); + +#if 1 + { + unsigned int i; + + dprintf("phys memory ranges:\n"); + for (i = 0; i < ka->num_physical_memory_ranges; i++) { + dprintf(" base 0x%08lx, length 0x%08lx\n", ka->physical_memory_range[i].start, ka->physical_memory_range[i].size); + } + + dprintf("allocated phys memory ranges:\n"); + for (i = 0; i < ka->num_physical_allocated_ranges; i++) { + dprintf(" base 0x%08lx, length 0x%08lx\n", ka->physical_allocated_range[i].start, ka->physical_allocated_range[i].size); + } + + dprintf("allocated virt memory ranges:\n"); + for (i = 0; i < ka->num_virtual_allocated_ranges; i++) { + dprintf(" base 0x%08lx, length 0x%08lx\n", ka->virtual_allocated_range[i].start, ka->virtual_allocated_range[i].size); + } + } +#endif + + // save the kernel args + ka->arch_args.system_time_cv_factor = cv_factor; + ka->str = NULL; ka->arch_args.page_hole = 0xffc00000; ka->num_cpus = 1; #if 0 @@ -491,6 +593,27 @@ sleep(uint64 time) } +static void +sort_addr_range(addr_range *range, int count) +{ + addr_range tempRange; + bool done; + int i; + + do { + done = true; + for (i = 1; i < count; i++) { + if (range[i].start < range[i - 1].start) { + done = false; + memcpy(&tempRange, &range[i], sizeof(addr_range)); + memcpy(&range[i], &range[i - 1], sizeof(addr_range)); + memcpy(&range[i - 1], &tempRange, sizeof(addr_range)); + } + } + } while (!done); +} + + #define outb(value,port) \ asm("outb %%al,%%dx"::"a" (value),"d" (port)) @@ -687,10 +810,12 @@ static void scrup() { int i; + memcpy(kScreenBase, kScreenBase + SCREEN_WIDTH, SCREEN_WIDTH * SCREEN_HEIGHT * 2 - SCREEN_WIDTH * 2); screenOffset = (SCREEN_HEIGHT - 1) * SCREEN_WIDTH; - for(i=0; i