--- trunk/mkinitrd-magellan/isolinux/highmem.inc 2010/08/19 08:27:19 1132 +++ trunk/mkinitrd-magellan/isolinux/highmem.inc 2010/08/19 09:50:43 1133 @@ -1,7 +1,6 @@ -;; $Id: highmem.inc,v 1.1 2007-09-01 22:44:04 niro Exp $ ;; ----------------------------------------------------------------------- -;; -;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved +;; +;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved ;; ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -13,7 +12,7 @@ ;; ;; highmem.inc -;; +;; ;; Probe for the size of high memory. This can be overridden by a ;; mem= command on the command line while booting a new kernel. ;; @@ -22,27 +21,38 @@ ; ; This is set up as a subroutine; it will set up the global variable -; HighMemSize. All registers are preserved. Assumes DS == CS. +; HighMemSize. All registers are preserved. ; highmemsize: push es + pushfd pushad + push cs + pop es + ; ; First, try INT 15:E820 (get BIOS memory map) ; +; Note: we may have to scan this multiple times, because some (daft) BIOSes +; report main memory as multiple contiguous ranges... +; get_e820: - xor ebx,ebx ; Start with first record mov dword [E820Max],-(1 << 20) ; Max amount of high memory - mov dword [E820Mem],ebx ; Detected amount of high memory - mov es,bx ; Need ES = DS = 0 for now + mov dword [E820Mem],(1 << 20) ; End of detected high memory +.start_over: + mov di,E820Buf + xor ax,ax + mov cx,10 + rep stosw ; Clear buffer + xor ebx,ebx ; Start with first record jmp short .do_e820 ; Skip "at end" check first time! .int_loop: and ebx,ebx ; If we're back at beginning... jz .e820_done ; ... we're done .do_e820: mov eax,0000E820h mov edx,534D4150h ; "SMAP" backwards xor ecx,ecx - mov cl,20 ; ECX <- 20 + mov cl,20 ; ECX <- 20 (size of buffer) mov di,E820Buf int 15h jnc .no_carry @@ -53,50 +63,53 @@ .no_carry: cmp eax,534D4150h jne no_e820 + cmp cx,20 + jb no_e820 + ; ; Look for a memory block starting at <= 1 MB and continuing upward ; cmp dword [E820Buf+4], byte 0 ja .int_loop ; Start >= 4 GB? - mov edx, (1 << 20) - sub edx, [E820Buf] - jnb .ram_range ; Start >= 1 MB? - ; If we get here, it starts > 1 MB but < 4 GB; if this is a - ; *non*-memory range, remember this as unusable; some BIOSes - ; get the length of primary RAM wrong! - cmp dword [E820Buf+16], byte 1 - je .int_loop ; If it's memory, don't worry about it - neg edx ; This means what for memory limit? - cmp edx,[E820Max] ; Better or worse - jnb .int_loop - mov [E820Max],edx + mov eax, [E820Buf] + cmp dword [E820Buf+16],1 + je .is_ram ; Is it memory? + ; + ; Non-memory range. Remember this as a limit; some BIOSes get the length + ; of primary RAM incorrect! + ; +.not_ram: + cmp eax, (1 << 20) + jb .int_loop ; Starts in lowmem region + cmp eax,[E820Max] + jae .int_loop ; Already above limit + mov [E820Max],eax ; Set limit jmp .int_loop - -.ram_range: - stc - sbb eax,eax ; eax <- 0xFFFFFFFF - cmp dword [E820Buf+12], byte 0 - ja .huge ; Size >= 4 GB - mov eax, [E820Buf+8] -.huge: sub eax, edx ; Adjust size to start at 1 MB - jbe .int_loop ; Completely below 1 MB? - - ; Now EAX contains the size of memory 1 MB...up - cmp dword [E820Buf+16], byte 1 - jne .int_loop ; High memory isn't usable memory!!!! - ; We're good! +.is_ram: + cmp eax,[E820Mem] + ja .int_loop ; Not contiguous with our starting point + add eax,[E820Buf+8] + jc .overflow + cmp dword [E820Buf+12],0 + je .nooverflow +.overflow: + or eax,-1 +.nooverflow: + cmp eax,[E820Mem] + jbe .int_loop ; All is below our baseline mov [E820Mem],eax - jmp .int_loop ; Still need to add low 1 MB + jmp .start_over ; Start over in case we find an adjacent range .e820_done: mov eax,[E820Mem] - and eax,eax - jz no_e820 ; Nothing found by E820? - cmp eax,[E820Max] ; Make sure we're not limited - jna got_highmem_add1mb + cmp eax,[E820Max] + jna .not_limited mov eax,[E820Max] - jmp got_highmem_add1mb +.not_limited: + cmp eax,(1 << 20) + ja got_highmem ; Did we actually find memory? + ; otherwise fall through ; ; INT 15:E820 failed. Try INT 15:E801. @@ -112,7 +125,7 @@ mov ax,bx shl eax,16 ; 64K chunks add eax,(16 << 20) ; Add first 16M - jmp short got_highmem + jmp short got_highmem ; ; INT 15:E801 failed. Try INT 15:88. @@ -126,7 +139,6 @@ e801_hole: and eax,0ffffh shl eax,10 ; Convert from kilobytes -got_highmem_add1mb: add eax,(1 << 20) ; First megabyte got_highmem: %if HIGHMEM_SLOP != 0 @@ -134,6 +146,7 @@ %endif mov [HighMemSize],eax popad + popfd pop es ret ; Done!