summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/firmware/pcbios/e820mangler.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/i386/firmware/pcbios/e820mangler.S')
-rw-r--r--src/arch/i386/firmware/pcbios/e820mangler.S384
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