diff --git a/src/arch/i386/firmware/pcbios/e820mangler.S b/src/arch/i386/firmware/pcbios/e820mangler.S index e9328041..0ab857b6 100644 --- a/src/arch/i386/firmware/pcbios/e820mangler.S +++ b/src/arch/i386/firmware/pcbios/e820mangler.S @@ -267,6 +267,322 @@ patch_1m_16m: 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 * @@ -298,7 +614,7 @@ patch_e820: /**************************************************************************** * Split E820 memory map entry if necessary * - * Parameters: + * Parameters: * As for INT 15,e820 * Returns: * As for INT 15,e820 @@ -318,7 +634,16 @@ split_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 diff --git a/src/arch/i386/scripts/i386.lds b/src/arch/i386/scripts/i386.lds index a5a01056..0422344d 100644 --- a/src/arch/i386/scripts/i386.lds +++ b/src/arch/i386/scripts/i386.lds @@ -82,6 +82,7 @@ SECTIONS { __data16 = .; *(.data16) *(.data16.*) + *(SORT(.tbl.data16.*)) /* Various tables. See include/tables.h */ _edata16_progbits = .; } .bss16 : AT ( _data16_load_offset + __bss16 ) {