blob: d7f26195719c98b5d834d9b99b561825fbb28b6c [file] [log] [blame]
/*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
#include <librm.h>
.arch i386
/* Image compression enabled */
#define COMPRESS 1
/* Protected mode flag */
#define CR0_PE 1
/* Allow for DBG()-style messages within libprefix */
#ifdef NDEBUG
.macro progress message, regs:vararg
.endm
#else
.macro dumpreg reg, others:vararg
pushl %eax
movl \reg, %eax
pushw %di
xorw %di, %di
call print_space
call print_hex_dword
popw %di
popl %eax
.ifnb \others
dumpreg \others
.endif
.endm
.macro progress message, regs:vararg
pushfl
pushw %ds
pushw %si
pushw %di
pushw %cs
popw %ds
xorw %di, %di
movw $progress_\@, %si
call print_message
popw %di
popw %si
.ifnb \regs
dumpreg \regs
.endif
pushw %di
pushw %ax
xorw %di, %di
movb $( '\n' ), %al
call print_character
popw %ax
popw %di
popw %ds
popfl
.section ".prefix.data", "aw", @progbits
progress_\@:
.asciz "\message"
.size progress_\@, . - progress_\@
.previous
.endm
#endif
/*****************************************************************************
* Utility function: print character (with LF -> LF,CR translation)
*
* Parameters:
* %al : character to print
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_character", "awx", @progbits
.code16
.globl print_character
print_character:
/* Preserve registers */
pushw %ax
pushw %bx
pushw %bp
/* If %di is non-zero, write character to buffer and exit */
testw %di, %di
jz 1f
movb %al, %ds:(%di)
incw %di
jmp 3f
1: /* Print character */
movw $0x0007, %bx /* page 0, attribute 7 (normal) */
movb $0x0e, %ah /* write char, tty mode */
cmpb $0x0a, %al /* '\n'? */
jne 2f
int $0x10
movb $0x0d, %al
2: int $0x10
/* Restore registers and return */
3: popw %bp
popw %bx
popw %ax
ret
.size print_character, . - print_character
/*****************************************************************************
* Utility function: print space
*
* Parameters:
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_space", "awx", @progbits
.code16
.globl print_space
print_space:
/* Preserve registers */
pushw %ax
/* Print space */
movb $( ' ' ), %al
call print_character
/* Restore registers and return */
popw %ax
ret
.size print_space, . - print_space
/*****************************************************************************
* Utility function: print a NUL-terminated string
*
* Parameters:
* %ds:si : string to print
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:si : character after terminating NUL
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_message", "awx", @progbits
.code16
.globl print_message
print_message:
/* Preserve registers */
pushw %ax
/* Print string */
1: lodsb
testb %al, %al
je 2f
call print_character
jmp 1b
2: /* Restore registers and return */
popw %ax
ret
.size print_message, . - print_message
/*****************************************************************************
* Utility functions: print hex digit/byte/word/dword
*
* Parameters:
* %al (low nibble) : digit to print
* %al : byte to print
* %ax : word to print
* %eax : dword to print
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_hex", "awx", @progbits
.code16
.globl print_hex_dword
print_hex_dword:
rorl $16, %eax
call print_hex_word
rorl $16, %eax
/* Fall through */
.size print_hex_dword, . - print_hex_dword
.globl print_hex_word
print_hex_word:
xchgb %al, %ah
call print_hex_byte
xchgb %al, %ah
/* Fall through */
.size print_hex_word, . - print_hex_word
.globl print_hex_byte
print_hex_byte:
rorb $4, %al
call print_hex_nibble
rorb $4, %al
/* Fall through */
.size print_hex_byte, . - print_hex_byte
.globl print_hex_nibble
print_hex_nibble:
/* Preserve registers */
pushw %ax
/* Print digit (technique by Norbert Juffa <norbert.juffa@amd.com> */
andb $0x0f, %al
cmpb $10, %al
sbbb $0x69, %al
das
call print_character
/* Restore registers and return */
popw %ax
ret
.size print_hex_nibble, . - print_hex_nibble
/*****************************************************************************
* Utility function: print PCI bus:dev.fn
*
* Parameters:
* %ax : PCI bus:dev.fn to print
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_pci_busdevfn", "awx", @progbits
.code16
.globl print_pci_busdevfn
print_pci_busdevfn:
/* Preserve registers */
pushw %ax
/* Print bus */
xchgb %al, %ah
call print_hex_byte
/* Print ":" */
movb $( ':' ), %al
call print_character
/* Print device */
movb %ah, %al
shrb $3, %al
call print_hex_byte
/* Print "." */
movb $( '.' ), %al
call print_character
/* Print function */
movb %ah, %al
andb $0x07, %al
call print_hex_nibble
/* Restore registers and return */
popw %ax
ret
.size print_pci_busdevfn, . - print_pci_busdevfn
/*****************************************************************************
* Utility function: clear current line
*
* Parameters:
* %ds:di : output buffer (or %di=0 to print to console)
* Returns:
* %ds:di : next character in output buffer (if applicable)
*****************************************************************************
*/
.section ".prefix.print_kill_line", "awx", @progbits
.code16
.globl print_kill_line
print_kill_line:
/* Preserve registers */
pushw %ax
pushw %cx
/* Print CR */
movb $( '\r' ), %al
call print_character
/* Print 79 spaces */
movw $79, %cx
1: call print_space
loop 1b
/* Print CR */
call print_character
/* Restore registers and return */
popw %cx
popw %ax
ret
.size print_kill_line, . - print_kill_line
/****************************************************************************
* copy_bytes
*
* Copy bytes
*
* Parameters:
* %ds:esi : source address
* %es:edi : destination address
* %ecx : length
* Returns:
* %ds:esi : next source address
* %es:edi : next destination address
* Corrupts:
* None
****************************************************************************
*/
.section ".prefix.copy_bytes", "awx", @progbits
.code16
copy_bytes:
pushl %ecx
rep addr32 movsb
popl %ecx
ret
.size copy_bytes, . - copy_bytes
/****************************************************************************
* zero_bytes
*
* Zero bytes
*
* Parameters:
* %es:edi : destination address
* %ecx : length
* Returns:
* %es:edi : next destination address
* Corrupts:
* None
****************************************************************************
*/
.section ".prefix.zero_bytes", "awx", @progbits
.code16
zero_bytes:
pushl %ecx
pushw %ax
xorw %ax, %ax
rep addr32 stosb
popw %ax
popl %ecx
ret
.size zero_bytes, . - zero_bytes
/****************************************************************************
* process_bytes
*
* Call memcpy()-like function
*
* Parameters:
* %esi : source physical address
* %edi : destination physical address
* %ecx : length
* %bx : memcpy()-like function to call, passing parameters:
* %ds:esi : source address
* %es:edi : destination address
* %ecx : length
* and returning:
* %ds:esi : next source address
* %es:edi : next destination address
* Returns:
* %esi : next source physical address
* %edi : next destination physical address
* CF : as returned by memcpy()-like function
* Corrupts:
* None
****************************************************************************
*/
.section ".prefix.process_bytes", "awx", @progbits
.code16
process_bytes:
#ifndef KEEP_IT_REAL
/* Preserve registers */
pushl %eax
pushl %ebp
/* Construct ljmp code on stack (since .prefix may not be writable) */
.equ LJMP_LEN, 0x06
pushw %cs /* "nop ; ljmp %cs, $2f" */
pushw $2f
pushw $0xea90
/* Construct GDT on stack (since .prefix may not be writable) */
.equ GDT_LEN, 0x20
.equ PM_DS, 0x18 /* Flat data segment */
pushl $0x00cf9300
pushl $0x0000ffff
.equ PM_SS, 0x10 /* Stack segment based at %ss:0000 */
pushl $0x008f0930
pushw %ss
pushw $0xffff
.equ PM_CS, 0x08 /* Code segment based at %cs:0000 */
pushl $0x008f09b0
pushw %cs
pushw $0xffff
pushl $0 /* Base and length */
pushw %ss
pushw $( GDT_LEN - 1 )
movzwl %sp, %ebp
shll $4, 0x02(%bp)
addl %ebp, 0x02(%bp)
shll $4, 0x0a(%bp)
shll $4, 0x12(%bp)
subw $8, %sp
sgdt -8(%bp)
/* Switch to protected mode */
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushw %ss
pushw %ss /* Far pointer to ljmp code on stack */
leaw (GDT_LEN + 1)(%bp), %ax
pushw %ax
cli
data32 lgdt (%bp)
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
ljmp $PM_CS, $1f
1: movw $PM_SS, %ax
movw %ax, %ss
movw $PM_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
#ifdef NDEBUG
/* Call memcpy()-like function */
call *%bx
#endif
/* Return to (flat) real mode */
movl %cr0, %eax
pushfw
andb $0!CR0_PE, %al
popfw
movl %eax, %cr0
lret
2: /* lret will ljmp to here (via constructed ljmp on stack) */
popw %ss
popw %ds
popw %es
popw %fs
popw %gs
#ifndef NDEBUG
/* Call memcpy()-like function in flat real mode (to allow for
* debug output via INT 10).
*/
pushw %ds
pushw %es
xorw %ax, %ax
movw %ax, %ds
movw %ax, %es
call *%bx
popw %es
popw %ds
#endif
/* Restore GDT */
data32 lgdt -8(%bp)
leaw (GDT_LEN + LJMP_LEN)(%bp), %sp
/* Restore registers and return */
popl %ebp
popl %eax
ret
#else /* KEEP_IT_REAL */
/* Preserve registers */
pushl %eax
pushw %ds
pushw %es
/* Convert %esi and %edi to %ds:esi and %es:edi */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
shll $4, %esi
shrl $4, %edi
movw %di, %es
xorw %di, %di
shll $4, %edi
/* Call memcpy()-like function */
call *%bx
/* Convert %ds:esi and %es:edi back to physical addresses */
pushfw
xorl %eax, %eax
movw %ds, %ax
shll $4, %eax
addl %eax, %esi
xorl %eax, %eax
movw %es, %ax
shll $4, %eax
addl %eax, %edi
popfw
/* Restore registers and return */
popw %es
popw %ds
popl %eax
ret
#endif /* KEEP_IT_REAL */
.size process_bytes, . - process_bytes
/****************************************************************************
* install_block
*
* Install block to specified address
*
* Parameters:
* %esi : source physical address (must be a multiple of 16)
* %edi : destination physical address (must be a multiple of 16)
* %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* %edi : next destination physical address (will be a multiple of 16)
* CF set on failure
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.install_block", "awx", @progbits
.code16
install_block:
/* Preserve registers */
pushl %ecx
pushw %bx
/* Decompress (or copy) source to destination */
#if COMPRESS
movw $decompress16, %bx
#else
movw $copy_bytes, %bx
#endif
call process_bytes
jc 99f
/* Zero .bss portion */
negl %ecx
addl %edx, %ecx
movw $zero_bytes, %bx
call process_bytes
/* Round up %esi and %edi to start of next blocks */
addl $0xf, %esi
andl $~0xf, %esi
addl $0xf, %edi
andl $~0xf, %edi /* Will also clear CF */
99: /* Restore registers and return */
popw %bx
popl %ecx
ret
.size install_block, . - install_block
/****************************************************************************
* alloc_basemem
*
* Allocate space for .text16 and .data16 from top of base memory.
* Memory is allocated using the BIOS free base memory counter at
* 0x40:13.
*
* Parameters:
* none
* Returns:
* %ax : .text16 segment address
* %bx : .data16 segment address
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.alloc_basemem", "awx", @progbits
.code16
.globl alloc_basemem
alloc_basemem:
/* Preserve registers */
pushw %fs
/* FBMS => %ax as segment address */
pushw $0x40
popw %fs
movw %fs:0x13, %ax
shlw $6, %ax
/* Calculate .data16 segment address */
subw $_data16_memsz_ppgh, %ax
pushw %ax
/* Calculate .text16 segment address */
subw $_text16_memsz_ppgh, %ax
pushw %ax
/* Update FBMS */
shrw $6, %ax
movw %ax, %fs:0x13
/* Retrieve .text16 and .data16 segment addresses */
popw %ax
popw %bx
/* Restore registers and return */
popw %fs
ret
.size alloc_basemem, . - alloc_basemem
/****************************************************************************
* free_basemem
*
* Free space allocated with alloc_basemem.
*
* Parameters:
* none (.text16 segment address is implicit in %cs)
* Returns:
* %ax : 0 if successfully freed
* Corrupts:
* none
****************************************************************************
*/
.section ".text16.free_basemem", "ax", @progbits
.code16
.globl free_basemem
free_basemem:
/* Preserve registers */
pushw %fs
pushw %ax
/* Check FBMS counter */
movw %cs, %ax
shrw $6, %ax
pushw $0x40
popw %fs
cmpw %ax, %fs:0x13
jne 1f
/* Check hooked interrupt count */
cmpw $0, %cs:hooked_bios_interrupts
jne 1f
/* OK to free memory */
movw %cs, %ax
addw $_text16_memsz_ppgh, %ax
addw $_data16_memsz_ppgh, %ax
shrw $6, %ax
movw %ax, %fs:0x13
xorw %ax, %ax
1: /* Restore registers and return */
popw %ax
popw %fs
ret
.size free_basemem, . - free_basemem
.section ".text16.data.hooked_bios_interrupts", "aw", @progbits
.globl hooked_bios_interrupts
hooked_bios_interrupts:
.word 0
.size hooked_bios_interrupts, . - hooked_bios_interrupts
/****************************************************************************
* install
*
* Install all text and data segments.
*
* Parameters:
* none
* Returns:
* %ax : .text16 segment address
* %bx : .data16 segment address
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.install", "awx", @progbits
.code16
.globl install
install:
progress "\ninstall:"
/* Preserve registers */
pushl %esi
pushl %edi
pushl %ebp
/* Allocate space for .text16 and .data16 */
call alloc_basemem
/* Image source = %cs:0000 */
xorl %esi, %esi
/* Image destination = default */
xorl %edi, %edi
/* Allow arbitrary relocation */
orl $0xffffffff, %ebp
/* Install text and data segments */
call install_prealloc
/* Restore registers and return */
popl %ebp
popl %edi
popl %esi
ret
.size install, . - install
/****************************************************************************
* install_prealloc
*
* Install all text and data segments.
*
* Parameters:
* %ax : .text16 segment address
* %bx : .data16 segment address
* %esi : Image source physical address (or zero for %cs:0000)
* %edi : Decompression temporary area physical address (or zero for default)
* %ebp : Maximum end address for relocation
* - 0xffffffff for no maximum
* - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
* Corrupts:
* none
****************************************************************************
*/
.section ".prefix.install_prealloc", "awx", @progbits
.code16
.globl install_prealloc
install_prealloc:
progress "\ninstall_prealloc:", %eax, %ebx, %esi, %edi, %ebp
/* Save registers on external stack */
pushal
pushw %ds
pushw %es
cld /* Sanity: clear the direction flag asap */
/* Switch to temporary stack in .bss16 */
pushw %ss
popw %ds
movl %esp, %ecx
movw %bx, %ss
movl $_data16_memsz, %esp
pushw %ds
pushl %ecx
/* Set up %ds for (read-only) access to .prefix */
pushw %cs
popw %ds
/* Save decompression temporary area physical address */
pushl %edi
/* Install .text16.early and calculate %ecx as offset to next block */
pushl %esi
xorl %esi, %esi
movw %cs, %si
shll $4, %esi
pushl %esi /* Save original %cs:0000 */
addl $_text16_early_lma, %esi
movzwl %ax, %edi
shll $4, %edi
movl $_text16_early_filesz, %ecx
movl $_text16_early_memsz, %edx
progress " .text16.early ", %esi, %edi, %ecx, %edx
call install_block /* .text16.early */
jc install_block_death
popl %ecx /* Calculate offset to next block */
subl %esi, %ecx
negl %ecx
popl %esi
#ifndef KEEP_IT_REAL
/* Access high memory by enabling the A20 gate. (We will
* already have 4GB segment limits as a result of calling
* install_block.)
*/
progress " access_highmem"
pushw %cs
pushw $1f
pushw %ax
pushw $access_highmem
lret
1: /* Die if we could not access high memory */
jc access_highmem_death
#endif
/* Open payload (which may not yet be in memory) */
progress " open_payload ", %esi, %ecx
pushw %cs
pushw $1f
pushw %ax
pushw $open_payload
lret
1: /* Die if we could not access the payload */
jc open_payload_death
/* Calculate physical address of payload (i.e. first source) */
testl %esi, %esi
jnz 1f
movw %cs, %si
shll $4, %esi
1: addl %ecx, %esi
/* Install .text16.late and .data16 */
movl $_text16_late_filesz, %ecx
movl $_text16_late_memsz, %edx
progress " .text16.late ", %esi, %edi, %ecx, %edx
call install_block /* .text16.late */
jc install_block_death
movzwl %bx, %edi
shll $4, %edi
movl $_data16_filesz, %ecx
movl $_data16_filesz, %edx /* do not zero our temporary stack */
progress " .data16 ", %esi, %edi, %ecx, %edx
call install_block /* .data16 */
jc install_block_death
/* Set up %ds for access to .data16 */
movw %bx, %ds
/* Restore decompression temporary area physical address */
popl %edi
#ifndef KEEP_IT_REAL
/* Find a suitable decompression temporary area, if none specified */
pushl %eax
testl %edi, %edi
jnz 1f
/* Use INT 15,88 to find the highest available address via INT
* 15,88. This limits us to around 64MB, which should avoid
* all of the POST-time memory map failure modes.
*/
movb $0x88, %ah
int $0x15
movw %ax, %di
addl $0x400, %edi
subl $_textdata_memsz_kb, %edi
andw $~0x03, %di
shll $10, %edi
/* Sanity check: if we have ended up below 1MB, use 1MB */
cmpl $0x100000, %edi
jae 1f
movl $0x100000, %edi
1: popl %eax
/* Install .text and .data to temporary area in high memory,
* prior to reading the E820 memory map and relocating
* properly.
*/
pushl %edi
movl $_textdata_filesz, %ecx
movl $_textdata_memsz, %edx
progress " .textdata ", %esi, %edi, %ecx, %edx
call install_block
jc install_block_death
popl %edi
#endif /* KEEP_IT_REAL */
/* Switch back to original stack and zero .bss16 */
addr32 lss %ss:(%esp), %esp
pushl %edi
pushw %es
movw %bx, %es
movl $_data16_filesz, %edi
movl $_data16_memsz, %ecx
subl %edi, %ecx
call zero_bytes
popw %es
popl %edi
#ifndef KEEP_IT_REAL
/* Initialise librm at current location */
progress " init_librm ", %eax, %ebx, %edi
movw %ax, (init_librm_vector+2)
lcall *init_librm_vector
/* Prepare for return to .prefix segment */
pushw %cs
/* Jump to .text16 segment */
pushw %ax
pushw $1f
lret
.section ".text16.install_prealloc", "ax", @progbits
1:
/* Inhibit INT 15,e820 and INT 15,e801 if applicable */
testl %ebp, %ebp
jnz 1f
incb memmap_post
decl %ebp
1:
/* Call relocate() to determine target address for relocation.
* relocate() will return with %esi, %edi and %ecx set up
* ready for the copy to the new location.
*/
virtcall relocate
/* Jump back to .prefix segment */
pushw $1f
lret
.section ".prefix.install_prealloc", "awx", @progbits
1:
/* Copy code to new location */
progress " copy ", %esi, %edi, %ecx
pushl %edi
pushw %bx
movw $copy_bytes, %bx
call process_bytes
popw %bx
popl %edi
/* Initialise librm at new location */
progress " init_librm ", %eax, %ebx, %edi
lcall *init_librm_vector
#else /* KEEP_IT_REAL */
/* Initialise libkir */
movw %ax, (init_libkir_vector+2)
lcall *init_libkir_vector
#endif /* KEEP_IT_REAL */
/* Close access to payload */
progress " close_payload"
movw %ax, (close_payload_vector+2)
lcall *close_payload_vector
/* Restore registers */
popw %es
popw %ds
popal
ret
.size install_prealloc, . - install_prealloc
/* Vectors for far calls to .text16 functions. Must be in
* .data16, since .prefix may not be writable.
*/
.section ".data16.install_prealloc", "aw", @progbits
#ifdef KEEP_IT_REAL
init_libkir_vector:
.word init_libkir
.word 0
.size init_libkir_vector, . - init_libkir_vector
#else
init_librm_vector:
.word init_librm
.word 0
.size init_librm_vector, . - init_librm_vector
#endif
close_payload_vector:
.word close_payload
.word 0
.size close_payload_vector, . - close_payload_vector
/* Dummy routines to open and close payload */
.section ".text16.early.data.open_payload", "aw", @progbits
.weak open_payload
.weak close_payload
open_payload:
close_payload:
clc
lret
.size open_payload, . - open_payload
.size close_payload, . - close_payload
/* Report installation failure */
.section ".prefix.install_death", "ax", @progbits
install_death:
pushw %cs
popw %ds
xorw %di, %di
call print_hex_dword
call print_space
movl %esi, %eax
call print_hex_dword
call print_space
movl %ecx, %eax
call print_hex_dword
movw $install_death_message, %si
call print_message
2: /* Halt system */
cli
hlt
jmp 2b
.size install_death, . - install_death
.section ".prefix.data.install_death_message", "aw", @progbits
install_death_message:
.asciz "\nInstallation failed - cannot continue\n"
.size install_death_message, . - install_death_message
/* Report failure to access high memory */
.section ".prefix.install_block_death", "ax", @progbits
install_block_death:
movl $0x1b101b10, %eax
jmp install_death
.size install_block_death, . - install_block_death
/* Report failure to access high memory */
.section ".prefix.access_highmem_death", "ax", @progbits
access_highmem_death:
movl $0x0a200a20, %eax
jmp install_death
.size access_highmem_death, . - access_highmem_death
/* Report failure to open payload */
.section ".prefix.open_payload_death", "ax", @progbits
open_payload_death:
xorl %eax, %eax
jmp install_death
.size open_payload_death, . - open_payload_death
/****************************************************************************
* uninstall
*
* Uninstall all text and data segments.
*
* Parameters:
* none (.text16 segment address is implicit in %cs)
* Returns:
* none
* Corrupts:
* none
****************************************************************************
*/
.section ".text16.uninstall", "ax", @progbits
.code16
.globl uninstall
uninstall:
call free_basemem
ret
.size uninstall, . - uninstall
/* File split information for the compressor */
#if COMPRESS
#define PACK_OR_COPY "PACK"
#else
#define PACK_OR_COPY "COPY"
#endif
.section ".zinfo", "a", @progbits
.ascii "COPY"
.long _prefix_lma
.long _prefix_filesz
.long _max_align
.ascii PACK_OR_COPY
.long _text16_early_lma
.long _text16_early_filesz
.long _max_align
.ascii "PAYL"
.long 0
.long 0
.long _payload_align
.ascii "COPY"
.long _pprefix_lma
.long _pprefix_filesz
.long _max_align
.ascii PACK_OR_COPY
.long _text16_late_lma
.long _text16_late_filesz
.long _max_align
.ascii PACK_OR_COPY
.long _data16_lma
.long _data16_filesz
.long _max_align
.ascii PACK_OR_COPY
.long _textdata_lma
.long _textdata_filesz
.long _max_align
.weak _payload_align
.equ _payload_align, 1