diff options
Diffstat (limited to 'src/arch/i386/firmware/pcbios/e820mangler.S')
-rw-r--r-- | src/arch/i386/firmware/pcbios/e820mangler.S | 384 |
1 files changed, 73 insertions, 311 deletions
diff --git a/src/arch/i386/firmware/pcbios/e820mangler.S b/src/arch/i386/firmware/pcbios/e820mangler.S index 0ab857b6..3c4cf21b 100644 --- a/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/src/arch/i386/firmware/pcbios/e820mangler.S @@ -26,159 +26,82 @@ #define SMAP 0x534d4150 /**************************************************************************** - * Check for overlap * - * Parameters: - * %edx:%eax Region start - * %ecx:%ebx Region end - * %si Pointer to hidden region descriptor - * Returns: - * CF set Region overlaps - * CF clear No overlap - **************************************************************************** - */ - .section ".text16" -check_overlap: - /* If start >= hidden_end, there is no overlap. */ - testl %edx, %edx - jnz no_overlap - cmpl 4(%si), %eax - jae no_overlap - /* If end <= hidden_start, there is no overlap; equivalently, - * if end > hidden_start, there is overlap. - */ - testl %ecx, %ecx - jnz overlap - cmpl 0(%si), %ebx - ja overlap -no_overlap: - clc - ret -overlap: - stc - ret - .size check_overlap, . - check_overlap - -/**************************************************************************** - * Check for overflow/underflow + * Allowed memory windows * - * Parameters: - * %edx:%eax Region start - * %ecx:%ebx Region end - * Returns: - * CF set start < end - * CF clear start >= end - **************************************************************************** - */ - .section ".text16" -check_overflow: - pushl %ecx - pushl %ebx - subl %eax, %ebx - sbbl %edx, %ecx - popl %ebx - popl %ecx - ret - .size check_overflow, . - check_overflow - -/**************************************************************************** - * Truncate towards start of region + * There are two ways to view this list. The first is as a list of + * (non-overlapping) allowed memory regions, sorted by increasing + * address. The second is as a list of (non-overlapping) hidden + * memory regions, again sorted by increasing address. The second + * view is offset by half an entry from the first: think about this + * for a moment and it should make sense. * - * Parameters: - * %edx:%eax Region start - * %ecx:%ebx Region end - * %si Pointer to hidden region descriptor - * Returns: - * %edx:%eax Modified region start - * %ecx:%ebx Modified region end - * CF set Region was truncated - * CF clear Region was not truncated - **************************************************************************** - */ - .section ".text16" -truncate_to_start: - /* If overlaps, set region end = hidden region start */ - call check_overlap - jnc 99f - movl 0(%si), %ebx - xorl %ecx, %ecx - /* If region end < region start, set region end = region start */ - call check_overflow - jnc 1f - movl %eax, %ebx - movl %edx, %ecx -1: stc -99: ret - .size truncate_to_start, . - truncate_to_start - -/**************************************************************************** - * Truncate towards end of region + * xxx_memory_window is used to indicate an "allowed region" + * structure, hidden_xxx_memory is used to indicate a "hidden region" + * structure. Each structure is 16 bytes in length. * - * Parameters: - * %edx:%eax Region start - * %ecx:%ebx Region end - * %si Pointer to hidden region descriptor - * Returns: - * %edx:%eax Modified region start - * %ecx:%ebx Modified region end - * CF set Region was truncated - * CF clear Region was not truncated **************************************************************************** */ - .section ".text16" -truncate_to_end: - /* If overlaps, set region start = hidden region end */ - call check_overlap - jnc 99f - movl 4(%si), %eax - xorl %edx, %edx - /* If region start > region end, set region start = region end */ - call check_overflow - jnc 1f - movl %ebx, %eax - movl %ecx, %edx -1: stc -99: ret - .size truncate_to_end, . - truncate_to_end - + .section ".data16" + .align 16 + .globl hidemem_base + .globl hidemem_umalloc + .globl hidemem_text +memory_windows: +base_memory_window: .long 0x00000000, 0x00000000 /* Start of memory */ + +hidemem_base: .long 0x000a0000, 0x00000000 /* Changes at runtime */ +ext_memory_window: .long 0x000a0000, 0x00000000 /* 640kB mark */ + +hidemem_umalloc: .long 0xffffffff, 0xffffffff /* Changes at runtime */ + .long 0xffffffff, 0xffffffff /* Changes at runtime */ + +hidemem_text: .long 0xffffffff, 0xffffffff /* Changes at runtime */ + .long 0xffffffff, 0xffffffff /* Changes at runtime */ + + .long 0xffffffff, 0xffffffff /* End of memory */ +memory_windows_end: + /**************************************************************************** - * Truncate region + * Truncate region to memory window * * Parameters: - * %edx:%eax Region start - * %ecx:%ebx Region length (*not* region end) - * %bp truncate_to_start or truncate_to_end + * %edx:%eax Start of region + * %ecx:%ebx Length of region + * %si Memory window * Returns: - * %edx:%eax Modified region start - * %ecx:%ebx Modified region length - * CF set Region was truncated - * CF clear Region was not truncated + * %edx:%eax Start of windowed region + * %ecx:%ebx Length of windowed region **************************************************************************** */ .section ".text16" -truncate: - pushw %si - pushfw - /* Convert (start,len) to (start,end) */ +window_region: + /* Convert (start,len) to (start, end) */ addl %eax, %ebx adcl %edx, %ecx - /* Hide all hidden regions, truncating as directed */ - movw $hidden_regions, %si -1: call *%bp - jnc 2f - popfw /* If CF was set, set stored CF in flags word on stack */ - stc - pushfw -2: addw $8, %si - cmpl $0, 0(%si) - jne 1b - /* Convert modified (start,end) back to (start,len) */ + /* Truncate to window start */ + cmpl 4(%si), %edx + jne 1f + cmpl 0(%si), %eax +1: jae 2f + movl 4(%si), %edx + movl 0(%si), %eax +2: /* Truncate to window end */ + cmpl 12(%si), %ecx + jne 1f + cmpl 8(%si), %ebx +1: jbe 2f + movl 12(%si), %ecx + movl 8(%si), %ebx +2: /* Convert (start, end) back to (start, len) */ subl %eax, %ebx sbbl %edx, %ecx - popfw - popw %si + /* If length is <0, set length to 0 */ + jae 1f + xorl %ebx, %ebx + xorl %ecx, %ecx ret - .size truncate, . - truncate + .size window_region, . - window_region /**************************************************************************** * Patch "memory above 1MB" figure @@ -187,21 +110,19 @@ truncate: * %ax Memory above 1MB, in 1kB blocks * Returns: * %ax Modified memory above 1M in 1kB blocks - * CF set Region was truncated - * CF clear Region was not truncated **************************************************************************** */ .section ".text16" patch_1m: pushal /* Convert to (start,len) format and call truncate */ - movw $truncate_to_start, %bp xorl %ecx, %ecx movzwl %ax, %ebx shll $10, %ebx xorl %edx, %edx movl $0x100000, %eax - call truncate + movw $ext_memory_window, %si + call window_region /* Convert back to "memory above 1MB" format and return via %ax */ pushfw shrl $10, %ebx @@ -219,20 +140,18 @@ patch_1m: * %bx Memory above 16MB, in 64kB blocks * Returns: * %bx Modified memory above 16M in 64kB blocks - * CF set Region was truncated - * CF clear Region was not truncated **************************************************************************** */ .section ".text16" patch_16m: pushal /* Convert to (start,len) format and call truncate */ - movw $truncate_to_start, %bp xorl %ecx, %ecx shll $16, %ebx xorl %edx, %edx movl $0x1000000, %eax - call truncate + movw $ext_memory_window, %si + call window_region /* Convert back to "memory above 16MB" format and return via %bx */ pushfw shrl $16, %ebx @@ -252,19 +171,17 @@ patch_16m: * Returns: * %ax Modified memory between 1MB and 16MB, in 1kB blocks * %bx Modified memory above 16MB, in 64kB blocks - * CF set Region was truncated - * CF clear Region was not truncated **************************************************************************** */ .section ".text16" patch_1m_16m: call patch_1m - jc 1f call patch_16m - ret -1: /* 1m region was truncated; kill the 16m region */ + /* If 1M region is no longer full-length, kill off the 16M region */ + cmpw $( 15 * 1024 ), %ax + je 1f xorw %bx, %bx - ret +1: ret .size patch_1m_16m, . - patch_1m_16m /**************************************************************************** @@ -337,7 +254,7 @@ get_underlying_e820: je 2f /* 'SMAP' missing: error */ 1: /* An error occurred: return values returned by underlying e820 call */ stc /* Force CF set if SMAP was missing */ - leal 16(%esp), %esp /* avoid changing other flags */ + addr32 leal 16(%esp), %esp /* avoid changing other flags */ ret 2: /* No error occurred */ movl %ebx, underlying_e820_ebx @@ -400,18 +317,6 @@ underlying_e820_cache: * **************************************************************************** */ - - .section ".tbl.data16.memory_windows.00" - .align 16 -memory_windows: - - // Dummy memory window encompassing entire 64-bit address space - .long 0, 0, 0xffffffff, 0xffffffff - - .section ".tbl.data16.memory_windows.99" - .align 16 -memory_windows_end: - .section ".text16" get_windowed_e820: @@ -421,7 +326,6 @@ get_windowed_e820: /* Split %ebx into %si:%bx, store original %bx in %bp */ pushl %ebx - xorl %esi, %esi popw %bp popw %si @@ -441,30 +345,8 @@ get_windowed_e820: movl %es:4(%di), %edx movl %es:8(%di), %ebx movl %es:12(%di), %ecx - /* Convert (start,len) to (start, end) */ - addl %eax, %ebx - adcl %edx, %ecx - /* Truncate to window start */ - cmpl 4(%esi), %edx - jne 1f - cmpl 0(%esi), %eax -1: jae 2f - movl 4(%esi), %edx - movl 0(%esi), %eax -2: /* Truncate to window end */ - cmpl 12(%esi), %ecx - jne 1f - cmpl 8(%esi), %ebx -1: jbe 2f - movl 12(%esi), %ecx - movl 8(%esi), %ebx -2: /* Convert (start, end) back to (start, len) */ - subl %eax, %ebx - sbbl %edx, %ecx - /* If length is <0, set length to 0 */ - jae 1f - xorl %ebx, %ebx - xorl %ecx, %ecx + /* Truncate region to current window */ + call window_region 1: /* Store modified values in e820 map entry */ movl %eax, %es:0(%di) movl %edx, %es:4(%di) @@ -537,7 +419,7 @@ get_nonempty_e820: 98: /* Clear CF */ clc 99: /* Return values from underlying call */ - leal 12(%esp), %esp /* avoid changing flags */ + addr32 leal 12(%esp), %esp /* avoid changing flags */ ret .size get_nonempty_e820, . - get_nonempty_e820 @@ -572,7 +454,7 @@ get_mangled_e820: popw %es movw %sp, %di call get_nonempty_e820 - leal 20(%esp), %esp /* avoid changing flags */ + addr32 leal 20(%esp), %esp /* avoid changing flags */ popal jnc 99f /* There are further nonempty regions */ @@ -584,136 +466,16 @@ get_mangled_e820: .size get_mangled_e820, . - get_mangled_e820 /**************************************************************************** - * Patch E820 memory map entry - * - * Parameters: - * %es:di Pointer to E820 memory map descriptor - * %bp truncate_to_start or truncate_to_end - * Returns: - * %es:di Pointer to now-modified E820 memory map descriptor - * CF set Region was truncated - * CF clear Region was not truncated - **************************************************************************** - */ - .section ".text16" -patch_e820: - pushal - movl %es:0(%di), %eax - movl %es:4(%di), %edx - movl %es:8(%di), %ebx - movl %es:12(%di), %ecx - call truncate - movl %eax, %es:0(%di) - movl %edx, %es:4(%di) - movl %ebx, %es:8(%di) - movl %ecx, %es:12(%di) - popal - ret - .size patch_e820, . - patch_e820 - -/**************************************************************************** - * Split E820 memory map entry if necessary - * - * Parameters: - * As for INT 15,e820 - * Returns: - * As for INT 15,e820 - * - * Calls the underlying INT 15,e820 and returns a modified memory map. - * Regions will be split around any hidden regions. + * INT 15,e820 handler **************************************************************************** */ .section ".text16" -split_e820: - pushw %si - pushw %bp - /* Caller's %bx => %si, real %ebx to %ebx, call previous handler */ - pushfw - movw %bx, %si - testl %ebx, %ebx - jnz 1f - movl %ebx, %cs:real_ebx -1: movl %cs:real_ebx, %ebx - -// lcall *%cs:int15_vector - /* Hacked in call to get_mangled_e820 in place of underlying INT15 */ - popfw +int15_e820: pushw %ds pushw %cs:rm_ds popw %ds call get_mangled_e820 popw %ds - - pushfw - /* Edit result */ - pushw %ds - pushw %cs:rm_ds - popw %ds - movw $truncate_to_start, %bp - incw %si - jns 2f - movw $truncate_to_end, %bp -2: call patch_e820 - jnc 3f - xorw $0x8000, %si -3: testw %si, %si - js 4f - movl %ebx, %cs:real_ebx - testl %ebx, %ebx - jz 5f -4: movw %si, %bx -5: popw %ds - /* Restore flags returned by previous handler and return */ - popfw - popw %bp - popw %si - ret - .size split_e820, . - split_e820 - - .section ".text16.data" -real_ebx: - .long 0 - .size real_ebx, . - real_ebx - -/**************************************************************************** - * INT 15,e820 handler - **************************************************************************** - */ - .section ".text16" -int15_e820: - pushl %eax - pushl %ecx - pushl %edx - call split_e820 - pushfw - /* If we've hit an error, exit immediately */ - jc 99f - /* If region is non-empty, return this region */ - pushl %eax - movl %es:8(%di), %eax - orl %es:12(%di), %eax - popl %eax - jnz 99f - /* Region is empty. If this is not the end of the map, - * skip over this region. - */ - testl %ebx, %ebx - jz 1f - popfw - popl %edx - popl %ecx - popl %eax - jmp int15_e820 -1: /* Region is empty and this is the end of the map. Return - * with CF set to avoid placing an empty region at the end of - * the map. - */ - popfw - stc - pushfw -99: /* Restore flags from original INT 15,e820 call and return */ - popfw - addr32 leal 12(%esp), %esp /* avoid changing flags */ lret $2 .size int15_e820, . - int15_e820 |