ret
.size patch_1m_16m, . - patch_1m_16m
+/****************************************************************************
+ * Get underlying e820 memory region to underlying_e820 buffer
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that the continuation
+ * value (%ebx) is a 16-bit simple sequence counter (with the high 16
+ * bits ignored), and termination is always via CF=1 rather than
+ * %ebx=0.
+ *
+ ****************************************************************************
+ */
+ .section ".text16"
+get_underlying_e820:
+
+ /* If the requested region is in the cache, return it */
+ cmpw %bx, underlying_e820_index
+ jne 1f
+ pushw %di
+ pushw %si
+ movw $underlying_e820_cache, %si
+ movw $20, %cx
+ rep movsb
+ popw %si
+ popw %di
+ movw $20, %cx
+ incw %bx
+ movl %edx, %eax
+ ret
+1:
+ /* If the requested region is earlier than the cached region,
+ * invalidate the cache.
+ */
+ cmpw %bx, underlying_e820_index
+ jbe 1f
+ movw $0xffff, underlying_e820_index
+1:
+ /* If the cache is invalid, reset the underlying %ebx */
+ cmpw $0xffff, underlying_e820_index
+ jne 1f
+ andl $0, underlying_e820_ebx
+1:
+ /* If the cache is valid but the continuation value is zero,
+ * this means that the previous underlying call returned with
+ * %ebx=0. Return with CF=1 in this case.
+ */
+ cmpw $0xffff, underlying_e820_index
+ je 1f
+ cmpl $0, underlying_e820_ebx
+ jne 1f
+ stc
+ ret
+1:
+ /* Get the next region into the cache */
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ movl underlying_e820_ebx, %ebx
+ stc
+ pushfw
+ lcall *%cs:int15_vector
+ jc 1f /* CF set: error */
+ cmpl $SMAP, %eax
+ 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 */
+ ret
+2: /* No error occurred */
+ movl %ebx, underlying_e820_ebx
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ /* Copy result to cache */
+ pushw %es
+ pushw %fs
+ pushw %si
+ pushw %di
+ pushw %cx
+ pushw %es
+ popw %fs
+ movw %di, %si
+ pushw %ds
+ popw %es
+ movw $underlying_e820_cache, %di
+ movw $20, %cx
+ fs rep movsb
+ popw %cx
+ popw %di
+ popw %si
+ popw %fs
+ popw %es
+ /* Mark cache as containing this result */
+ incw underlying_e820_index
+
+ /* Loop until found */
+ jmp get_underlying_e820
+ .size get_underlying_e820, . - get_underlying_e820
+
+ .section ".data16"
+underlying_e820_index:
+ .word 0xffff /* Initialise to an invalid value */
+ .size underlying_e820_index, . - underlying_e820_index
+
+ .section ".bss16"
+underlying_e820_ebx:
+ .long 0
+ .size underlying_e820_ebx, . - underlying_e820_ebx
+
+ .section ".bss16"
+underlying_e820_cache:
+ .space 20
+ .size underlying_e820_cache, . - underlying_e820_cache
+
+/****************************************************************************
+ * Get windowed e820 region, without empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned N times, windowed to fit within N visible-memory
+ * windows. Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+
+ .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:
+
+ /* Preserve registers */
+ pushl %esi
+ pushw %bp
+
+ /* Split %ebx into %si:%bx, store original %bx in %bp */
+ pushl %ebx
+ xorl %esi, %esi
+ popw %bp
+ popw %si
+
+ /* %si == 0 => start of memory_windows list */
+ testw %si, %si
+ jne 1f
+ movw $memory_windows, %si
+1:
+ /* Get (cached) underlying e820 region to buffer */
+ call get_underlying_e820
+ jc 99f /* Abort on error */
+
+ /* Preserve registers */
+ pushal
+ /* start => %edx:%eax, len => %ecx:%ebx */
+ movl %es:0(%di), %eax
+ 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
+1: /* Store modified values in e820 map entry */
+ movl %eax, %es:0(%di)
+ movl %edx, %es:4(%di)
+ movl %ebx, %es:8(%di)
+ movl %ecx, %es:12(%di)
+ /* Restore registers */
+ popal
+
+ /* Derive continuation value for next call */
+ addw $16, %si
+ cmpw $memory_windows_end, %si
+ jne 1f
+ /* End of memory windows: reset %si and allow %bx to continue */
+ xorw %si, %si
+ jmp 2f
+1: /* More memory windows to go: restore original %bx */
+ movw %bp, %bx
+2: /* Construct %ebx from %si:%bx */
+ pushw %si
+ pushw %bx
+ popl %ebx
+
+98: /* Clear CF */
+ clc
+99: /* Restore registers and return */
+ popw %bp
+ popl %esi
+ ret
+ .size get_windowed_e820, . - get_windowed_e820
+
+/****************************************************************************
+ * Get windowed e820 region, with empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that each underlying
+ * region is returned up to N times, windowed to fit within N
+ * visible-memory windows. Empty windows are never returned.
+ * Termination is always via CF=1.
+ *
+ ****************************************************************************
+ */
+ .section ".text16"
+get_nonempty_e820:
+
+ /* Record entry parameters */
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+
+ /* Get next windowed region */
+ call get_windowed_e820
+ jc 99f /* abort on error */
+
+ /* If region is non-empty, finish here */
+ cmpl $0, %es:8(%di)
+ jne 98f
+ cmpl $0, %es:12(%di)
+ jne 98f
+
+ /* Region was empty: restore entry parameters and go to next region */
+ popl %edx
+ popl %ecx
+ popl %eax
+ jmp get_nonempty_e820
+
+98: /* Clear CF */
+ clc
+99: /* Return values from underlying call */
+ leal 12(%esp), %esp /* avoid changing flags */
+ ret
+ .size get_nonempty_e820, . - get_nonempty_e820
+
+/****************************************************************************
+ * Get mangled e820 region, with empty region stripping
+ *
+ * Parameters:
+ * As for INT 15,e820
+ * Returns:
+ * As for INT 15,e820
+ *
+ * Wraps the underlying INT 15,e820 call so that underlying regions
+ * are windowed to the allowed memory regions. Empty regions are
+ * stripped from the map. Termination is always via %ebx=0.
+ *
+ ****************************************************************************
+ */
+ .section ".text16"
+get_mangled_e820:
+
+ /* Get a nonempty region */
+ call get_nonempty_e820
+ jc 99f /* Abort on error */
+
+ /* Peek ahead to see if there are any further nonempty regions */
+ pushal
+ subw $20, %sp
+ movl $0xe820, %eax
+ movl $SMAP, %edx
+ movl $20, %ecx
+ pushw %ss
+ popw %es
+ movw %sp, %di
+ call get_nonempty_e820
+ leal 20(%esp), %esp /* avoid changing flags */
+ popal
+ jnc 99f /* There are further nonempty regions */
+
+ /* No futher nonempty regions: zero %ebx and clear CF */
+ xorl %ebx, %ebx
+
+99: /* Return */
+ ret
+ .size get_mangled_e820, . - get_mangled_e820
+
/****************************************************************************
* Patch E820 memory map entry
*
/****************************************************************************
* Split E820 memory map entry if necessary
*
- * Parameters:
+ * Parameters:
* As for INT 15,e820
* Returns:
* As for INT 15,e820
jnz 1f
movl %ebx, %cs:real_ebx
1: movl %cs:real_ebx, %ebx
- lcall *%cs:int15_vector
+
+// lcall *%cs:int15_vector
+ /* Hacked in call to get_mangled_e820 in place of underlying INT15 */
+ popfw
+ pushw %ds
+ pushw %cs:rm_ds
+ popw %ds
+ call get_mangled_e820
+ popw %ds
+
pushfw
/* Edit result */
pushw %ds