Home | History | Annotate | Download | only in prefix
      1 /*
      2  * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  *
     18  */
     19 
     20 FILE_LICENCE ( GPL2_OR_LATER )
     21 
     22 	.arch i386
     23 
     24 /**
     25  * High memory temporary load address
     26  *
     27  * Temporary buffer into which to copy (or decompress) our runtime
     28  * image, prior to calling get_memmap() and relocate().  We don't
     29  * actually leave anything here once install() has returned.
     30  *
     31  * We use the start of an even megabyte so that we don't have to worry
     32  * about the current state of the A20 line.
     33  *
     34  * We use 4MB rather than 2MB because some PXE stack / PMM BIOS
     35  * combinations are known to place data required by other UNDI ROMs
     36  * loader around the 2MB mark.
     37  */
     38 	.globl	HIGHMEM_LOADPOINT
     39 	.equ	HIGHMEM_LOADPOINT, ( 4 << 20 )
     40 
     41 /* Image compression enabled */
     42 #define COMPRESS 1
     43 
     44 #define CR0_PE 1
     45 
     46 /*****************************************************************************
     47  * Utility function: print character (with LF -> LF,CR translation)
     48  *
     49  * Parameters:
     50  *   %al : character to print
     51  *   %ds:di : output buffer (or %di=0 to print to console)
     52  * Returns:
     53  *   %ds:di : next character in output buffer (if applicable)
     54  *****************************************************************************
     55  */
     56 	.section ".prefix.lib", "awx", @progbits
     57 	.code16
     58 	.globl	print_character
     59 print_character:
     60 	/* Preserve registers */
     61 	pushw	%ax
     62 	pushw	%bx
     63 	pushw	%bp
     64 	/* If %di is non-zero, write character to buffer and exit */
     65 	testw	%di, %di
     66 	jz	1f
     67 	movb	%al, %ds:(%di)
     68 	incw	%di
     69 	jmp	3f
     70 1:	/* Print character */
     71 	movw	$0x0007, %bx		/* page 0, attribute 7 (normal) */
     72 	movb	$0x0e, %ah		/* write char, tty mode */
     73 	cmpb	$0x0a, %al		/* '\n'? */
     74 	jne	2f
     75 	int	$0x10
     76 	movb	$0x0d, %al
     77 2:	int	$0x10
     78 	/* Restore registers and return */
     79 3:	popw	%bp
     80 	popw	%bx
     81 	popw	%ax
     82 	ret
     83 	.size	print_character, . - print_character
     84 
     85 /*****************************************************************************
     86  * Utility function: print a NUL-terminated string
     87  *
     88  * Parameters:
     89  *   %ds:si : string to print
     90  *   %ds:di : output buffer (or %di=0 to print to console)
     91  * Returns:
     92  *   %ds:si : character after terminating NUL
     93  *   %ds:di : next character in output buffer (if applicable)
     94  *****************************************************************************
     95  */
     96 	.section ".prefix.lib", "awx", @progbits
     97 	.code16
     98 	.globl	print_message
     99 print_message:
    100 	/* Preserve registers */
    101 	pushw	%ax
    102 	/* Print string */
    103 1: 	lodsb
    104 	testb	%al, %al
    105 	je	2f
    106 	call	print_character
    107 	jmp	1b
    108 2:	/* Restore registers and return */
    109 	popw	%ax
    110 	ret
    111 	.size	print_message, . - print_message
    112 
    113 /*****************************************************************************
    114  * Utility functions: print hex digit/byte/word/dword
    115  *
    116  * Parameters:
    117  *   %al (low nibble) : digit to print
    118  *   %al : byte to print
    119  *   %ax : word to print
    120  *   %eax : dword to print
    121  *   %ds:di : output buffer (or %di=0 to print to console)
    122  * Returns:
    123  *   %ds:di : next character in output buffer (if applicable)
    124  *****************************************************************************
    125  */
    126 	.section ".prefix.lib", "awx", @progbits
    127 	.code16
    128 	.globl	print_hex_dword
    129 print_hex_dword:
    130 	rorl	$16, %eax
    131 	call	print_hex_word
    132 	rorl	$16, %eax
    133 	/* Fall through */
    134 	.size	print_hex_dword, . - print_hex_dword
    135 	.globl	print_hex_word
    136 print_hex_word:
    137 	xchgb	%al, %ah
    138 	call	print_hex_byte
    139 	xchgb	%al, %ah
    140 	/* Fall through */
    141 	.size	print_hex_word, . - print_hex_word
    142 	.globl	print_hex_byte
    143 print_hex_byte:
    144 	rorb	$4, %al
    145 	call	print_hex_nibble
    146 	rorb	$4, %al
    147 	/* Fall through */
    148 	.size	print_hex_byte, . - print_hex_byte
    149 	.globl	print_hex_nibble
    150 print_hex_nibble:
    151 	/* Preserve registers */
    152 	pushw	%ax
    153 	/* Print digit (technique by Norbert Juffa <norbert.juffa (at) amd.com> */
    154 	andb	$0x0f, %al
    155 	cmpb	$10, %al
    156 	sbbb	$0x69, %al
    157 	das
    158 	call	print_character
    159 	/* Restore registers and return */
    160 	popw	%ax
    161 	ret
    162 	.size	print_hex_nibble, . - print_hex_nibble
    163 
    164 /*****************************************************************************
    165  * Utility function: print PCI bus:dev.fn
    166  *
    167  * Parameters:
    168  *   %ax : PCI bus:dev.fn to print
    169  *   %ds:di : output buffer (or %di=0 to print to console)
    170  * Returns:
    171  *   %ds:di : next character in output buffer (if applicable)
    172  *****************************************************************************
    173  */
    174 	.section ".prefix.lib", "awx", @progbits
    175 	.code16
    176 	.globl	print_pci_busdevfn
    177 print_pci_busdevfn:
    178 	/* Preserve registers */
    179 	pushw	%ax
    180 	/* Print bus */
    181 	xchgb	%al, %ah
    182 	call	print_hex_byte
    183 	/* Print ":" */
    184 	movb	$( ':' ), %al
    185 	call	print_character
    186 	/* Print device */
    187 	movb	%ah, %al
    188 	shrb	$3, %al
    189 	call	print_hex_byte
    190 	/* Print "." */
    191 	movb	$( '.' ), %al
    192 	call	print_character
    193 	/* Print function */
    194 	movb	%ah, %al
    195 	andb	$0x07, %al
    196 	call	print_hex_nibble
    197 	/* Restore registers and return */
    198 	popw	%ax
    199 	ret
    200 	.size	print_pci_busdevfn, . - print_pci_busdevfn
    201 
    202 /*****************************************************************************
    203  * Utility function: clear current line
    204  *
    205  * Parameters:
    206  *   %ds:di : output buffer (or %di=0 to print to console)
    207  * Returns:
    208  *   %ds:di : next character in output buffer (if applicable)
    209  *****************************************************************************
    210  */
    211 	.section ".prefix.lib", "awx", @progbits
    212 	.code16
    213 	.globl	print_kill_line
    214 print_kill_line:
    215 	/* Preserve registers */
    216 	pushw	%ax
    217 	pushw	%cx
    218 	/* Print CR */
    219 	movb	$( '\r' ), %al
    220 	call	print_character
    221 	/* Print 79 spaces */
    222 	movb	$( ' ' ), %al
    223 	movw	$79, %cx
    224 1:	call	print_character
    225 	loop	1b
    226 	/* Print CR */
    227 	movb	$( '\r' ), %al
    228 	call	print_character
    229 	/* Restore registers and return */
    230 	popw	%cx
    231 	popw	%ax
    232 	ret
    233 	.size	print_kill_line, . - print_kill_line
    234 
    235 /****************************************************************************
    236  * pm_call (real-mode near call)
    237  *
    238  * Call routine in 16-bit protected mode for access to extended memory
    239  *
    240  * Parameters:
    241  *   %ax : address of routine to call in 16-bit protected mode
    242  * Returns:
    243  *   none
    244  * Corrupts:
    245  *   %ax
    246  *
    247  * The specified routine is called in 16-bit protected mode, with:
    248  *
    249  *   %cs : 16-bit code segment with base matching real-mode %cs
    250  *   %ss : 16-bit data segment with base matching real-mode %ss
    251  *   %ds,%es,%fs,%gs : 32-bit data segment with zero base and 4GB limit
    252  *
    253  ****************************************************************************
    254  */
    255 
    256 #ifndef KEEP_IT_REAL
    257 
    258 	/* GDT for protected-mode calls */
    259 	.section ".prefix.lib", "awx", @progbits
    260 	.align 16
    261 pm_call_vars:
    262 gdt:
    263 gdt_limit:		.word gdt_length - 1
    264 gdt_base:		.long 0
    265 			.word 0 /* padding */
    266 pm_cs:		/* 16-bit protected-mode code segment */
    267 	.equ    PM_CS, pm_cs - gdt
    268 	.word   0xffff, 0
    269 	.byte   0, 0x9b, 0x00, 0
    270 pm_ss:		/* 16-bit protected-mode stack segment */
    271 	.equ    PM_SS, pm_ss - gdt
    272 	.word   0xffff, 0
    273 	.byte   0, 0x93, 0x00, 0
    274 pm_ds:		/* 32-bit protected-mode flat data segment */
    275 	.equ    PM_DS, pm_ds - gdt
    276 	.word   0xffff, 0
    277 	.byte   0, 0x93, 0xcf, 0
    278 gdt_end:
    279 	.equ	gdt_length, . - gdt
    280 	.size	gdt, . - gdt
    281 
    282 	.section ".prefix.lib", "awx", @progbits
    283 	.align 16
    284 pm_saved_gdt:
    285 	.long	0, 0
    286 	.size	pm_saved_gdt, . - pm_saved_gdt
    287 
    288 	.equ	pm_call_vars_size, . - pm_call_vars
    289 #define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
    290 
    291 	.section ".prefix.lib", "awx", @progbits
    292 	.code16
    293 pm_call:
    294 	/* Preserve registers, flags, and RM return point */
    295 	pushw	%bp
    296 	movw	%sp, %bp
    297 	subw	$pm_call_vars_size, %sp
    298 	andw	$0xfff0, %sp
    299 	pushfl
    300 	pushw	%gs
    301 	pushw	%fs
    302 	pushw	%es
    303 	pushw	%ds
    304 	pushw	%ss
    305 	pushw	%cs
    306 	pushw	$99f
    307 
    308 	/* Set up local variable block, and preserve GDT */
    309 	pushw	%cx
    310 	pushw	%si
    311 	pushw	%di
    312 	pushw	%ss
    313 	popw	%es
    314 	movw	$pm_call_vars, %si
    315 	leaw	PM_CALL_VAR(pm_call_vars)(%bp), %di
    316 	movw	$pm_call_vars_size, %cx
    317 	cs rep movsb
    318 	popw	%di
    319 	popw	%si
    320 	popw	%cx
    321 	sgdt	PM_CALL_VAR(pm_saved_gdt)(%bp)
    322 
    323 	/* Set up GDT bases */
    324 	pushl	%eax
    325 	pushl	%edi
    326 	xorl	%eax, %eax
    327 	movw	%ss, %ax
    328 	shll	$4, %eax
    329 	movzwl	%bp, %edi
    330 	addr32 leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
    331 	movl	%eax, PM_CALL_VAR(gdt_base)(%bp)
    332 	movw	%cs, %ax
    333 	movw	$PM_CALL_VAR(pm_cs), %di
    334 	call	set_seg_base
    335 	movw	%ss, %ax
    336 	movw	$PM_CALL_VAR(pm_ss), %di
    337 	call	set_seg_base
    338 	popl	%edi
    339 	popl	%eax
    340 
    341 	/* Switch CPU to protected mode and load up segment registers */
    342 	pushl	%eax
    343 	cli
    344 	data32 lgdt PM_CALL_VAR(gdt)(%bp)
    345 	movl	%cr0, %eax
    346 	orb	$CR0_PE, %al
    347 	movl	%eax, %cr0
    348 	ljmp	$PM_CS, $1f
    349 1:	movw	$PM_SS, %ax
    350 	movw	%ax, %ss
    351 	movw	$PM_DS, %ax
    352 	movw	%ax, %ds
    353 	movw	%ax, %es
    354 	movw	%ax, %fs
    355 	movw	%ax, %gs
    356 	popl	%eax
    357 
    358 	/* Call PM routine */
    359 	call	*%ax
    360 
    361 	/* Set real-mode segment limits on %ds, %es, %fs and %gs */
    362 	movw	%ss, %ax
    363 	movw	%ax, %ds
    364 	movw	%ax, %es
    365 	movw	%ax, %fs
    366 	movw	%ax, %gs
    367 
    368 	/* Return CPU to real mode */
    369 	movl	%cr0, %eax
    370 	andb	$0!CR0_PE, %al
    371 	movl	%eax, %cr0
    372 
    373 	/* Restore registers and flags */
    374 	lret	/* will ljmp to 99f */
    375 99:	popw	%ss
    376 	popw	%ds
    377 	popw	%es
    378 	popw	%fs
    379 	popw	%gs
    380 	data32 lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
    381 	popfl
    382 	movw	%bp, %sp
    383 	popw	%bp
    384 	ret
    385 	.size pm_call, . - pm_call
    386 
    387 set_seg_base:
    388 	rolw	$4, %ax
    389 	movw	%ax, 2(%bp,%di)
    390 	andw	$0xfff0, 2(%bp,%di)
    391 	movb	%al, 4(%bp,%di)
    392 	andb	$0x0f, 4(%bp,%di)
    393 	ret
    394 	.size set_seg_base, . - set_seg_base
    395 
    396 #endif /* KEEP_IT_REAL */
    397 
    398 /****************************************************************************
    399  * copy_bytes (real-mode or 16-bit protected-mode near call)
    400  *
    401  * Copy bytes
    402  *
    403  * Parameters:
    404  *   %ds:esi : source address
    405  *   %es:edi : destination address
    406  *   %ecx : length
    407  * Returns:
    408  *   %ds:esi : next source address
    409  *   %es:edi : next destination address
    410  * Corrupts:
    411  *   None
    412  ****************************************************************************
    413  */
    414 	.section ".prefix.lib", "awx", @progbits
    415 	.code16
    416 copy_bytes:
    417 	pushl %ecx
    418 	rep addr32 movsb
    419 	popl %ecx
    420 	ret
    421 	.size copy_bytes, . - copy_bytes
    422 
    423 /****************************************************************************
    424  * install_block (real-mode near call)
    425  *
    426  * Install block to specified address
    427  *
    428  * Parameters:
    429  *   %esi : source physical address (must be a multiple of 16)
    430  *   %edi : destination physical address (must be a multiple of 16)
    431  *   %ecx : length of (decompressed) data
    432  *   %edx : total length of block (including any uninitialised data portion)
    433  * Returns:
    434  *   %esi : next source physical address (will be a multiple of 16)
    435  * Corrupts:
    436  *   none
    437  ****************************************************************************
    438  */
    439 	.section ".prefix.lib", "awx", @progbits
    440 	.code16
    441 install_block:
    442 
    443 #ifdef KEEP_IT_REAL
    444 
    445 	/* Preserve registers */
    446 	pushw	%ds
    447 	pushw	%es
    448 	pushl	%ecx
    449 	pushl	%edi
    450 
    451 	/* Convert %esi and %edi to segment registers */
    452 	shrl	$4, %esi
    453 	movw	%si, %ds
    454 	xorw	%si, %si
    455 	shrl	$4, %edi
    456 	movw	%di, %es
    457 	xorw	%di, %di
    458 
    459 #else /* KEEP_IT_REAL */
    460 
    461 	/* Call self in protected mode */
    462 	pushw	%ax
    463 	movw	$1f, %ax
    464 	call	pm_call
    465 	popw	%ax
    466 	ret
    467 1:
    468 	/* Preserve registers */
    469 	pushl	%ecx
    470 	pushl	%edi
    471 
    472 #endif /* KEEP_IT_REAL */
    473 
    474 
    475 #if COMPRESS
    476 	/* Decompress source to destination */
    477 	call	decompress16
    478 #else
    479 	/* Copy source to destination */
    480 	call	copy_bytes
    481 #endif
    482 
    483 	/* Zero .bss portion */
    484 	negl	%ecx
    485 	addl	%edx, %ecx
    486 	pushw	%ax
    487 	xorw	%ax, %ax
    488 	rep addr32 stosb
    489 	popw	%ax
    490 
    491 	/* Round up %esi to start of next source block */
    492 	addl	$0xf, %esi
    493 	andl	$~0xf, %esi
    494 
    495 
    496 #ifdef KEEP_IT_REAL
    497 
    498 	/* Convert %ds:esi back to a physical address */
    499 	movzwl	%ds, %cx
    500 	shll	$4, %ecx
    501 	addl	%ecx, %esi
    502 
    503 	/* Restore registers */
    504 	popl	%edi
    505 	popl	%ecx
    506 	popw	%es
    507 	popw	%ds
    508 
    509 #else /* KEEP_IT_REAL */
    510 
    511 	/* Restore registers */
    512 	popl	%edi
    513 	popl	%ecx
    514 
    515 #endif
    516 
    517 	ret
    518 	.size install_block, . - install_block
    519 
    520 /****************************************************************************
    521  * alloc_basemem (real-mode near call)
    522  *
    523  * Allocate space for .text16 and .data16 from top of base memory.
    524  * Memory is allocated using the BIOS free base memory counter at
    525  * 0x40:13.
    526  *
    527  * Parameters:
    528  *   none
    529  * Returns:
    530  *   %ax : .text16 segment address
    531  *   %bx : .data16 segment address
    532  * Corrupts:
    533  *   none
    534  ****************************************************************************
    535  */
    536 	.section ".prefix.lib", "awx", @progbits
    537 	.code16
    538 	.globl	alloc_basemem
    539 alloc_basemem:
    540 	/* Preserve registers */
    541 	pushw	%fs
    542 
    543 	/* FBMS => %ax as segment address */
    544 	pushw	$0x40
    545 	popw	%fs
    546 	movw	%fs:0x13, %ax
    547 	shlw	$6, %ax
    548 
    549 	/* Calculate .data16 segment address */
    550 	subw	$_data16_memsz_pgh, %ax
    551 	pushw	%ax
    552 
    553 	/* Calculate .text16 segment address */
    554 	subw	$_text16_memsz_pgh, %ax
    555 	pushw	%ax
    556 
    557 	/* Update FBMS */
    558 	shrw	$6, %ax
    559 	movw	%ax, %fs:0x13
    560 
    561 	/* Retrieve .text16 and .data16 segment addresses */
    562 	popw	%ax
    563 	popw	%bx
    564 
    565 	/* Restore registers and return */
    566 	popw	%fs
    567 	ret
    568 	.size alloc_basemem, . - alloc_basemem
    569 
    570 /****************************************************************************
    571  * free_basemem (real-mode near call)
    572  *
    573  * Free space allocated with alloc_basemem.
    574  *
    575  * Parameters:
    576  *   %ax : .text16 segment address
    577  *   %bx : .data16 segment address
    578  * Returns:
    579  *   %ax : 0 if successfully freed
    580  * Corrupts:
    581  *   none
    582  ****************************************************************************
    583  */
    584 	.section ".text16", "ax", @progbits
    585 	.code16
    586 	.globl	free_basemem
    587 free_basemem:
    588 	/* Preserve registers */
    589 	pushw	%fs
    590 
    591 	/* Check FBMS counter */
    592 	pushw	%ax
    593 	shrw	$6, %ax
    594 	pushw	$0x40
    595 	popw	%fs
    596 	cmpw	%ax, %fs:0x13
    597 	popw	%ax
    598 	jne	1f
    599 
    600 	/* Check hooked interrupt count */
    601 	cmpw	$0, %cs:hooked_bios_interrupts
    602 	jne	1f
    603 
    604 	/* OK to free memory */
    605 	addw	$_text16_memsz_pgh, %ax
    606 	addw	$_data16_memsz_pgh, %ax
    607 	shrw	$6, %ax
    608 	movw	%ax, %fs:0x13
    609 	xorw	%ax, %ax
    610 
    611 1:	/* Restore registers and return */
    612 	popw	%fs
    613 	ret
    614 	.size free_basemem, . - free_basemem
    615 
    616 	.section ".text16.data", "aw", @progbits
    617 	.globl	hooked_bios_interrupts
    618 hooked_bios_interrupts:
    619 	.word	0
    620 	.size	hooked_bios_interrupts, . - hooked_bios_interrupts
    621 
    622 /****************************************************************************
    623  * install (real-mode near call)
    624  *
    625  * Install all text and data segments.
    626  *
    627  * Parameters:
    628  *   none
    629  * Returns:
    630  *   %ax  : .text16 segment address
    631  *   %bx  : .data16 segment address
    632  * Corrupts:
    633  *   none
    634  ****************************************************************************
    635  */
    636 	.section ".prefix.lib", "awx", @progbits
    637 	.code16
    638 	.globl install
    639 install:
    640 	/* Preserve registers */
    641 	pushl	%esi
    642 	pushl	%edi
    643 	/* Allocate space for .text16 and .data16 */
    644 	call	alloc_basemem
    645 	/* Image source = %cs:0000 */
    646 	xorl	%esi, %esi
    647 	/* Image destination = HIGHMEM_LOADPOINT */
    648 	movl	$HIGHMEM_LOADPOINT, %edi
    649 	/* Install text and data segments */
    650 	call	install_prealloc
    651 	/* Restore registers and return */
    652 	popl	%edi
    653 	popl	%esi
    654 	ret
    655 	.size install, . - install
    656 
    657 /****************************************************************************
    658  * install_prealloc (real-mode near call)
    659  *
    660  * Install all text and data segments.
    661  *
    662  * Parameters:
    663  *   %ax  : .text16 segment address
    664  *   %bx  : .data16 segment address
    665  *   %esi : Image source physical address (or zero for %cs:0000)
    666  *   %edi : Decompression temporary area physical address
    667  * Corrupts:
    668  *   none
    669  ****************************************************************************
    670  */
    671 	.section ".prefix.lib", "awx", @progbits
    672 	.code16
    673 	.globl install_prealloc
    674 install_prealloc:
    675 	/* Save registers */
    676 	pushal
    677 	pushw	%ds
    678 	pushw	%es
    679 
    680 	/* Sanity: clear the direction flag asap */
    681 	cld
    682 
    683 	/* Calculate physical address of payload (i.e. first source) */
    684 	testl	%esi, %esi
    685 	jnz	1f
    686 	movw	%cs, %si
    687 	shll	$4, %esi
    688 1:	addl	$_payload_lma, %esi
    689 
    690 	/* Install .text16 and .data16 */
    691 	pushl	%edi
    692 	movzwl	%ax, %edi
    693 	shll	$4, %edi
    694 	movl	$_text16_memsz, %ecx
    695 	movl	%ecx, %edx
    696 	call	install_block		/* .text16 */
    697 	movzwl	%bx, %edi
    698 	shll	$4, %edi
    699 	movl	$_data16_filesz, %ecx
    700 	movl	$_data16_memsz, %edx
    701 	call	install_block		/* .data16 */
    702 	popl	%edi
    703 
    704 	/* Set up %ds for access to .data16 */
    705 	movw	%bx, %ds
    706 
    707 #ifdef KEEP_IT_REAL
    708 	/* Initialise libkir */
    709 	movw	%ax, (init_libkir_vector+2)
    710 	lcall	*init_libkir_vector
    711 #else
    712 	/* Install .text and .data to temporary area in high memory,
    713 	 * prior to reading the E820 memory map and relocating
    714 	 * properly.
    715 	 */
    716 	movl	$_textdata_filesz, %ecx
    717 	movl	$_textdata_memsz, %edx
    718 	call	install_block
    719 
    720 	/* Initialise librm at current location */
    721 	movw	%ax, (init_librm_vector+2)
    722 	lcall	*init_librm_vector
    723 
    724 	/* Call relocate() to determine target address for relocation.
    725 	 * relocate() will return with %esi, %edi and %ecx set up
    726 	 * ready for the copy to the new location.
    727 	 */
    728 	movw	%ax, (prot_call_vector+2)
    729 	pushl	$relocate
    730 	lcall	*prot_call_vector
    731 	popl	%edx /* discard */
    732 
    733 	/* Copy code to new location */
    734 	pushl	%edi
    735 	pushw	%ax
    736 	movw	$copy_bytes, %ax
    737 	call	pm_call
    738 	popw	%ax
    739 	popl	%edi
    740 
    741 	/* Initialise librm at new location */
    742 	lcall	*init_librm_vector
    743 
    744 #endif
    745 	/* Restore registers */
    746 	popw	%es
    747 	popw	%ds
    748 	popal
    749 	ret
    750 	.size install_prealloc, . - install_prealloc
    751 
    752 	/* Vectors for far calls to .text16 functions */
    753 	.section ".data16", "aw", @progbits
    754 #ifdef KEEP_IT_REAL
    755 init_libkir_vector:
    756 	.word init_libkir
    757 	.word 0
    758 	.size init_libkir_vector, . - init_libkir_vector
    759 #else
    760 init_librm_vector:
    761 	.word init_librm
    762 	.word 0
    763 	.size init_librm_vector, . - init_librm_vector
    764 prot_call_vector:
    765 	.word prot_call
    766 	.word 0
    767 	.size prot_call_vector, . - prot_call_vector
    768 #endif
    769 
    770 /****************************************************************************
    771  * uninstall (real-mode near call)
    772  *
    773  * Uninstall all text and data segments.
    774  *
    775  * Parameters:
    776  *   %ax  : .text16 segment address
    777  *   %bx  : .data16 segment address
    778  * Returns:
    779  *   none
    780  * Corrupts:
    781  *   none
    782  ****************************************************************************
    783  */
    784 	.section ".text16", "ax", @progbits
    785 	.code16
    786 	.globl uninstall
    787 uninstall:
    788 	call	free_basemem
    789 	ret
    790 	.size uninstall, . - uninstall
    791 
    792 
    793 
    794 	/* File split information for the compressor */
    795 #if COMPRESS
    796 	.section ".zinfo", "a", @progbits
    797 	.ascii	"COPY"
    798 	.long	_prefix_lma
    799 	.long	_prefix_filesz
    800 	.long	_max_align
    801 	.ascii	"PACK"
    802 	.long	_text16_lma
    803 	.long	_text16_filesz
    804 	.long	_max_align
    805 	.ascii	"PACK"
    806 	.long	_data16_lma
    807 	.long	_data16_filesz
    808 	.long	_max_align
    809 	.ascii	"PACK"
    810 	.long	_textdata_lma
    811 	.long	_textdata_filesz
    812 	.long	_max_align
    813 #else /* COMPRESS */
    814 	.section ".zinfo", "a", @progbits
    815 	.ascii	"COPY"
    816 	.long	_prefix_lma
    817 	.long	_filesz
    818 	.long	_max_align
    819 #endif /* COMPRESS */
    820