123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /*
- * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * 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 the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- .text
- .arch i386
- .section ".text16", "ax", @progbits
- .section ".data16", "aw", @progbits
- .section ".text16.data", "aw", @progbits
- .code16
-
- #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
- *
- * 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
- *
- * 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
- *
- * 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
-
- /****************************************************************************
- * Truncate region
- *
- * Parameters:
- * %edx:%eax Region start
- * %ecx:%ebx Region length (*not* region end)
- * %bp truncate_to_start or truncate_to_end
- * Returns:
- * %edx:%eax Modified region start
- * %ecx:%ebx Modified region length
- * CF set Region was truncated
- * CF clear Region was not truncated
- ****************************************************************************
- */
- .section ".text16"
- truncate:
- pushw %si
- pushfw
- /* 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) */
- subl %eax, %ebx
- sbbl %edx, %ecx
- popfw
- popw %si
- ret
- .size truncate, . - truncate
-
- /****************************************************************************
- * Patch "memory above 1MB" figure
- *
- * Parameters:
- * %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
- /* Convert back to "memory above 1MB" format and return via %ax */
- pushfw
- shrl $10, %ebx
- popfw
- movw %sp, %bp
- movw %bx, 28(%bp)
- popal
- ret
- .size patch_1m, . - patch_1m
-
- /****************************************************************************
- * Patch "memory above 16MB" figure
- *
- * Parameters:
- * %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
- /* Convert back to "memory above 16MB" format and return via %bx */
- pushfw
- shrl $16, %ebx
- popfw
- movw %sp, %bp
- movw %bx, 16(%bp)
- popal
- ret
- .size patch_16m, . - patch_16m
-
- /****************************************************************************
- * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
- *
- * Parameters:
- * %ax Memory between 1MB and 16MB, in 1kB blocks
- * %bx Memory above 16MB, in 64kB blocks
- * 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 */
- xorw %bx, %bx
- ret
- .size patch_1m_16m, . - patch_1m_16m
-
- /****************************************************************************
- * 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.
- ****************************************************************************
- */
- .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
- 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
- /* Skip empty region checking if we've reached the end of the
- * map or hit an error, to avoid a potential endless loop.
- */
- jc 1f
- testl %ebx, %ebx
- jz 1f
- /* Check for an empty region */
- pushl %eax
- movl %es:8(%di), %eax
- orl %es:12(%di), %eax
- popl %eax
- jnz 1f
- /* Strip empty regions out of the returned map */
- popfw
- popl %edx
- popl %ecx
- popl %eax
- jmp int15_e820
- /* Restore flags from original INT 15,e820 call and return */
- 1: popfw
- addr32 leal 12(%esp), %esp /* avoid changing flags */
- lret $2
- .size int15_e820, . - int15_e820
-
- /****************************************************************************
- * INT 15,e801 handler
- ****************************************************************************
- */
- .section ".text16"
- int15_e801:
- /* Call previous handler */
- pushfw
- lcall *%cs:int15_vector
- pushfw
- /* Edit result */
- pushw %ds
- pushw %cs:rm_ds
- popw %ds
- call patch_1m_16m
- xchgw %ax, %cx
- xchgw %bx, %dx
- call patch_1m_16m
- xchgw %ax, %cx
- xchgw %bx, %dx
- popw %ds
- /* Restore flags returned by previous handler and return */
- popfw
- lret $2
- .size int15_e801, . - int15_e801
-
- /****************************************************************************
- * INT 15,88 handler
- ****************************************************************************
- */
- .section ".text16"
- int15_88:
- /* Call previous handler */
- pushfw
- lcall *%cs:int15_vector
- pushfw
- /* Edit result */
- pushw %ds
- pushw %cs:rm_ds
- popw %ds
- call patch_1m
- popw %ds
- /* Restore flags returned by previous handler and return */
- popfw
- lret $2
- .size int15_88, . - int15_88
-
- /****************************************************************************
- * INT 15 handler
- ****************************************************************************
- */
- .section ".text16"
- .globl int15
- int15:
- /* See if we want to intercept this call */
- pushfw
- cmpw $0xe820, %ax
- jne 1f
- cmpl $SMAP, %edx
- jne 1f
- popfw
- jmp int15_e820
- 1: cmpw $0xe801, %ax
- jne 2f
- popfw
- jmp int15_e801
- 2: cmpb $0x88, %ah
- jne 3f
- popfw
- jmp int15_88
- 3: popfw
- ljmp *%cs:int15_vector
- .size int15, . - int15
-
- .section ".text16.data"
- .globl int15_vector
- int15_vector:
- .long 0
- .size int15_vector, . - int15_vector
|