summaryrefslogtreecommitdiff
path: root/kexec_test
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
committerEric W. Biederman <ebiederm@xmission.com>2006-07-27 02:36:23 -0600
commit283261998a9846019d898bc454b363e4aaf3d181 (patch)
treea4af6da4c5a2c6f7669d918c1f07dc68d6aa0ab2 /kexec_test
downloadkexec-tools-283261998a9846019d898bc454b363e4aaf3d181.tar.gz
kexec-tools-1.101v1.101
- Initial import into git - initial nbi image formage support - ppc32 initial register setting fixes. - gzipped multiboot file support
Diffstat (limited to 'kexec_test')
-rw-r--r--kexec_test/Makefile30
-rw-r--r--kexec_test/kexec_test.S475
-rw-r--r--kexec_test/kexec_test16.S1004
-rw-r--r--kexec_test/x86-setup-legacy-pic.S53
4 files changed, 1562 insertions, 0 deletions
diff --git a/kexec_test/Makefile b/kexec_test/Makefile
new file mode 100644
index 0000000..3e932d5
--- /dev/null
+++ b/kexec_test/Makefile
@@ -0,0 +1,30 @@
+#
+# kexec_test Debugging payload to be certain the infrastructure works
+#
+RELOC:=0x10000
+KEXEC_TEST_S_SRCS:= kexec_test/kexec_test16.S kexec_test/kexec_test.S
+KEXEC_TEST_S_TEMPS:=$(patsubst %.S, $(OBJDIR)/%.s, $(KEXEC_TEST_S_SRCS))
+KEXEC_TEST_S_OBJS:=$(patsubst $(OBJDIR)/%.s, $(OBJDIR)/%.o, $(KEXEC_TEST_S_TEMPS))
+KEXEC_TEST_S_DEPS:=$(patsubst %.S, $(OBJDIR)/%.d, $(KEXEC_TEST_S_SRCS))
+KEXEC_TEST_SRCS:= $(KEXEC_TEST_S_SRCS)
+KEXEC_TEST_OBJS:= $(KEXEC_TEST_S_OBJS)
+KEXEC_TEST_DEPS:= $(KEXEC_TEST_S_DEPS)
+KEXEC_TEST:=$(PKGLIBDIR)/kexec_test
+
+include $(KEXEC_TEST_DEPS)
+
+$(KEXEC_TEST_S_DEPS): $(OBJDIR)/%.d: %.S
+ mkdir -p $(@D)
+ $(CC) -m32 $(CFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
+
+$(KEXEC_TEST_S_TEMPS): $(OBJDIR)/%.s: %.S
+ mkdir -p $(@D)
+ $(CPP) $(CPPFLAGS) -DRELOC=$(RELOC) $< > $@
+
+$(KEXEC_TEST_S_OBJS): $(OBJDIR)/%.o: $(OBJDIR)/%.s
+ mkdir -p $(@D)
+ $(AS) --32 -o $@ $<
+
+$(KEXEC_TEST): $(KEXEC_TEST_OBJS)
+ mkdir -p $(@D)
+ $(LD) -m elf_i386 -e _start -Ttext $(RELOC) $(KEXEC_TEST_OBJS) -o $@
diff --git a/kexec_test/kexec_test.S b/kexec_test/kexec_test.S
new file mode 100644
index 0000000..5106c5c
--- /dev/null
+++ b/kexec_test/kexec_test.S
@@ -0,0 +1,475 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * 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 (version 2 of the License).
+ *
+ * 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.
+ */
+
+ .equ PROT_CODE_SEG, pmcs - gdt
+ .equ REAL_CODE_SEG, rmcs - gdt
+ .equ PROT_DATA_SEG, pmds - gdt
+ .equ REAL_DATA_SEG, rmds - gdt
+ .equ CR0_PE, 1
+ /* Gas thinks the .equs for these are non-absolute so use a define */
+#define PROT_CODE_SEG 0x08
+#define REAL_CODE_SEG 0x18
+#undef i386
+
+ .text
+ .arch i386
+ .globl _start
+_start:
+ .code32
+ # Disable interrupts
+ cli
+
+ # Save the initial registers
+ movl %eax, orig_eax
+ movl %ebx, orig_ebx
+ movl %ecx, orig_ecx
+ movl %edx, orig_edx
+ movl %esi, orig_esi
+ movl %edi, orig_edi
+ movl %esp, orig_esp
+ movl %ebp, orig_ebp
+
+ # Setup a stack
+ movl $stack_end, %esp
+
+ # Display a message to say everything is working so far
+ pushl $s_hello
+ call print_string
+ addl $4, %esp
+
+ # Save the idt and gdt
+ sidt orig_idtp
+ sgdt orig_gdtp
+
+ # Display the initial register contents
+ call print_orig_regs
+
+ pushl $s_switching_descriptors
+ call print_string
+ addl $4, %esp
+
+ # Load descriptor pointers
+ lgdt gdtp
+ lidt idtp
+ # Reload the data segments
+ movl $PROT_DATA_SEG, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ # Reload %cs
+ ljmp $PROT_CODE_SEG, $_start.1
+_start.1:
+
+ pushl $s_descriptors_changed
+ call print_string
+ addl $4, %esp
+
+ call setup_legacy_pic
+ pushl $s_legacy_pic_setup
+ call print_string
+ addl $4, %esp
+
+ call prot_to_real
+ .code16
+
+ callw test16
+
+ /* Return to 32bit mode */
+ data32 call real_to_prot
+ .code32
+ pushl $s_in_protected_mode
+ call print_string
+ addl $4, %esp
+
+ pushl $s_halting
+ call print_string
+ addl $4, %esp
+ jmp halt
+
+
+ /* Go from protected to real mode */
+prot_to_real:
+ .code32
+ /* Load the 16bit idt */
+ lidt idtp_real
+
+ popl %eax
+ subl $RELOC, %eax /* Adjust return address */
+ pushl %eax
+ subl $RELOC, %esp /* Adjust stack pointer */
+ ljmp $REAL_CODE_SEG, $1f - RELOC
+1:
+ .code16
+ /* Reload the segment registers to force a 16bit limit */
+ movw $REAL_DATA_SEG, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ /* Clear the PE bit of CR0 */
+ movl %cr0, %eax
+ andl $0!CR0_PE, %eax
+ movl %eax, %cr0
+
+ /* make intersegment jmp to flush the processor pipeline
+ * and reload %cs:%eip (to clear upper 16 bits of %eip).
+ */
+ data32 ljmp $(RELOC)>>4,$2f- RELOC
+2:
+ /* we are in real mode now
+ * set up the real mode segment registers
+ */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%ss
+ movw %ax,%fs
+ movw %ax,%gs
+ data32 ret
+
+real_to_prot:
+ .code16
+ pushl %ebx
+
+ /* Compute the address of gdtp */
+ movw %cs, %ax
+ shlw $4, %ax
+ movl $gdtp, %ebx
+ subw %ax, %bx
+
+ data32 lgdt %cs:(%bx)
+ movl %cr0, %eax
+ orl $CR0_PE, %eax
+ movl %eax, %cr0
+
+ /* flush prefetch queue and reload %cs:%eip */
+ data32 ljmp $PROT_CODE_SEG, $1f
+1:
+ .code32
+ /* reload other segment registers */
+ movl $PROT_DATA_SEG, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+ movl %eax, %fs
+ movl %eax, %gs
+
+ popl %ebx /* Restore %ebx */
+
+ addl $RELOC, %esp /* Fix up stack pointer */
+
+ popl %eax /* Fix up return address */
+ addl $RELOC, %eax
+ pushl %eax
+
+ lidt idtp /* Load a dummy idt */
+ ret
+
+
+halt:
+ .code32
+ hlt
+ jmp halt
+
+print_orig_regs:
+ .code32
+ # Display the initial register contents
+ pushl $s_eax
+ call print_string
+ pushl orig_eax
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+ pushl $s_ebx
+ call print_string
+ pushl orig_ebx
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+
+ pushl $s_ecx
+ call print_string
+ pushl orig_ecx
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+
+ pushl $s_edx
+ call print_string
+ pushl orig_edx
+ call print_hex
+ pushl $crlf
+ call print_string
+ addl $12, %esp
+
+
+ pushl $s_esi
+ call print_string
+ pushl orig_esi
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+ pushl $s_edi
+ call print_string
+ pushl orig_edi
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+
+ pushl $s_esp
+ call print_string
+ pushl orig_esp
+ call print_hex
+ pushl $space
+ call print_string
+ addl $12, %esp
+
+
+ pushl $s_ebp
+ call print_string
+ pushl orig_ebp
+ call print_hex
+ pushl $crlf
+ call print_string
+ addl $12, %esp
+
+ # display the interrupt descritor table pointer
+ pushl $s_idtp
+ call print_string
+ movzwl orig_idtp, %eax
+ pushl %eax
+ call print_hex
+ pushl $space
+ call print_string
+ pushl orig_idt_base
+ call print_hex
+ pushl $crlf
+ call print_string
+ addl $20, %esp
+
+ # display the global descritor table pointer
+ pushl $s_gdtp
+ call print_string
+ movzwl orig_gdtp, %eax
+ pushl %eax
+ call print_hex
+ pushl $space
+ call print_string
+ pushl orig_gdt_base
+ call print_hex
+ pushl $crlf
+ call print_string
+ addl $20, %esp
+
+ ret
+
+
+print_string:
+ .code32
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ movl 8(%ebp), %esi
+ xorl %eax, %eax
+print_string.1:
+ lodsb %ds:(%esi), %al
+ testb $0xff, %al
+ jz print_string.2
+ call print_char
+ jmp print_string.1
+print_string.2:
+ popl %esi
+ popl %ebp
+ ret
+
+
+print_hex:
+ .code32
+ pushl %ebp
+ movl %esp, %ebp
+ movb $32, %cl
+print_hex.1:
+ movl 8(%ebp), %eax
+ subb $4, %cl
+ shrl %cl, %eax
+ andb $0x0f, %al
+ cmpb $9, %al
+ ja print_hex.2
+ addb $'0', %al
+ jmp print_hex.3
+print_hex.2:
+ addb $'A' - 10, %al
+print_hex.3:
+ pushl %ecx
+ call print_char
+ popl %ecx
+ testb %cl, %cl
+ jnz print_hex.1
+
+ popl %ebp
+ ret
+
+print_char:
+ .code32
+ # The character to print is in al
+ call serial_print_char
+ retl
+
+
+#define TTYS0_BASE 0x3f8
+#define TTYS0_RBR (TTYS0_BASE + 0x00)
+#define TTYS0_TBR (TTYS0_BASE + 0x00)
+#define TTYS0_LSR (TTYS0_BASE + 0x05)
+serial_print_char:
+ .code32
+ # The character to print is in al
+ pushl %eax
+
+ # Wait until the serial port is ready to receive characters
+serial_print_char.1:
+ movl $TTYS0_LSR, %edx
+ inb %dx, %al
+ testb $0x20, %al
+ jz serial_print_char.1
+
+ # Output the character
+ movl $TTYS0_TBR, %edx
+ movb 0(%esp), %al
+ outb %al, %dx
+
+ # Wait until the serial port has transmitted the character
+serial_print_char.2:
+ movl $TTYS0_LSR, %edx
+ inb %dx, %al
+ testb $0x40, %al
+ jz serial_print_char.2
+
+ # Restore %eax
+ popl %eax
+ # Return to caller
+ ret
+
+ .code32
+
+idtp_real:
+ .word 0x400 # idt limit = 256
+ .word 0, 0
+idtp:
+ .word 0 # idt limit = 0
+ .word 0, 0 # idt base = 0L
+
+gdt:
+gdtp:
+ .word gdt_end - gdt - 1 # gdt limit
+ .long gdt # gdt base
+ .word 0 # dummy
+
+pmcs:
+ # the 32 bit protected mode code segment
+ .word 0xffff,0
+ .byte 0,0x9f,0xcf,0
+
+pmds:
+ # the 32 bit protected mode data segment
+ .word 0xffff,0
+ .byte 0,0x93,0xcf,0
+
+rmcs:
+ # the 16 bit real mode code segment
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x9b,0x00,(RELOC>>24)
+
+rmds:
+ # the 16 bit real mode data segment
+ .word 0xffff,(RELOC&0xffff)
+ .byte (RELOC>>16),0x93,0x00,(RELOC>>24)
+gdt_end:
+
+
+s_hello:
+ .ascii "kexec_test "
+ .ascii VERSION
+ .asciz " starting...\r\n"
+s_switching_descriptors:
+ .asciz "Switching descriptors.\r\n"
+s_descriptors_changed:
+ .asciz "Descriptors changed.\r\n"
+s_legacy_pic_setup:
+ .asciz "Legacy pic setup.\r\n"
+s_in_protected_mode:
+ .asciz "In protected mode.\r\n"
+s_halting:
+ .asciz "Halting.\r\n"
+
+
+space: .asciz " "
+crlf: .asciz "\r\n"
+s_eax: .asciz "eax: "
+s_ebx: .asciz "ebx: "
+s_ecx: .asciz "ecx: "
+s_edx: .asciz "edx: "
+s_esi: .asciz "esi: "
+s_edi: .asciz "edi: "
+s_esp: .asciz "esp: "
+s_ebp: .asciz "ebp: "
+
+
+s_idtp: .asciz "idt: "
+s_gdtp: .asciz "gdt: "
+
+#include "x86-setup-legacy-pic.S"
+
+ .bss
+ .balign 4096
+stack:
+ .skip 4096
+stack_end:
+
+ .bss
+ .balign 4
+orig_eax: .long 0
+orig_ebx: .long 0
+orig_ecx: .long 0
+orig_edx: .long 0
+orig_esi: .long 0
+orig_edi: .long 0
+orig_esp: .long 0
+orig_ebp: .long 0
+
+ .balign 4
+orig_idtp: .short 0
+orig_idt_base: .long 0
+orig_gdtp: .short 0
+orig_gdt_base: .long 0
+
diff --git a/kexec_test/kexec_test16.S b/kexec_test/kexec_test16.S
new file mode 100644
index 0000000..4d37915
--- /dev/null
+++ b/kexec_test/kexec_test16.S
@@ -0,0 +1,1004 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * 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 (version 2 of the License).
+ *
+ * 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
+ .code16
+
+ .globl test16
+ .balign 16
+ .globl _start16
+_start16:
+test16:
+ pushw $s_in_real_mode - _start16
+ call print_string16
+ addw $2, %sp
+
+#if 0
+ /* Disable interrupts */
+ movb $0xff, %al
+ outb %al, $0x21
+ outb %al, $0xa1
+#endif
+ /* Enable interrupts, BIOS calls may fail if we don't */
+ sti
+ pushw $s_interrupts_enabled - _start16
+ call print_string16
+ addw $2, %sp
+
+ /* Get the base memory size, via a bios call */
+ /* This is to test BIOS calls more than to achieve anything practical */
+ xorw %ax, %ax
+ int $0x12
+ pushw %ax
+ pushw $s_base_memory_size - _start16
+ call print_string16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+
+ /* Some things do not like a20 being enabled so disable it */
+ call disable_a20
+
+ /* Here we test various BIOS calls to determine how much of the system is working */
+ call get_meme820
+ call print_meme820
+ call print_meme801
+ call print_mem88
+ call disable_apm
+ call print_equipment_list
+ call print_sysdesc
+ call print_video
+ call print_cursor
+ call print_video_mode
+ call set_auto_repeat_rate
+ call print_dasd_type
+ call print_edd
+
+ /* Enable a20 */
+ call enable_a20
+ pushw $s_a20_enabled - _start16
+ call print_string16
+ addw $2, %sp
+
+ /* Disable interrupts */
+ cli
+ pushw $s_interrupts_disabled - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+#
+# Enable A20. This is at the very best an annoying procedure.
+# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
+#
+
+A20_TEST_LOOPS = 32 # Iterations per wait
+A20_ENABLE_LOOPS = 255 # Total loops to try
+A20_DISABLE_LOOPS = 255 # Total loops to try
+
+enable_a20:
+ .code16
+ movb $A20_ENABLE_LOOPS, a20_tries - _start16
+a20_try_loop:
+
+ # First, see if we are on a system with no A20 gate.
+a20_none:
+ call a20_test
+ jnz a20_done
+
+ # Next, try the BIOS (INT 0x15, AX=0x2401)
+a20_bios:
+ movw $0x2401, %ax
+ pushfl # Be paranoid about flags
+ int $0x15
+ popfl
+
+ call a20_test
+ jnz a20_done
+
+ # Try enabling A20 through the keyboard controller
+a20_kbc:
+ call empty_8042
+
+ call a20_test # Just in case the BIOS worked
+ jnz a20_done # but had a delayed reaction.
+
+ movb $0xD1, %al # command write
+ outb %al, $0x64
+ call empty_8042
+
+ movb $0xDF, %al # A20 on
+ outb %al, $0x60
+ call empty_8042
+
+ # Wait until a20 really *is* enabled; it can take a fair amount of
+ # time on certain systems; Toshiba Tecras are known to have this
+ # problem.
+a20_kbc_wait:
+ xorw %cx, %cx
+a20_kbc_wait_loop:
+ call a20_test
+ jnz a20_done
+ loop a20_kbc_wait_loop
+
+ # Final attempt: use "configuration port A"
+a20_fast:
+ inb $0x92, %al # Configuration Port A
+ orb $0x02, %al # "fast A20" version
+ andb $0xFE, %al # dont accidentally reset
+ outb %al, $0x92
+
+ # Wait for configuration port A to take effect
+a20_fast_wait:
+ xorw %cx, %cx
+a20_fast_wait_loop:
+ call a20_test
+ jnz a20_done
+ loop a20_fast_wait_loop
+
+ # A20 is still not responding. Try frobbing it again.
+ #
+ decb (a20_tries - _start16)
+ jnz a20_try_loop
+ jmp a20_die
+
+a20_die:
+ pushw $s_a20_err_msg - _start16
+ call print_string16
+ jmp halt16
+
+ # If we get here, all is good
+a20_done:
+ ret
+
+
+
+# This routine tests whether or not A20 is enabled. If so, it
+# exits with zf = 0.
+#
+# The memory address used, 0x200, is the int $0x80 vector, which
+# should be safe.
+
+A20_TEST_ADDR = 4*0x80
+
+a20_test:
+ .code16
+ pushw %cx
+ pushw %ax
+ xorw %cx, %cx
+ movw %cx, %fs # Low memory
+ decw %cx
+ movw %cx, %gs # High memory area
+ movw $A20_TEST_LOOPS, %cx
+ movw %fs:(A20_TEST_ADDR), %ax
+ pushw %ax
+a20_test_wait:
+ incw %ax
+ movw %ax, %fs:(A20_TEST_ADDR)
+ call delay # Serialize and make delay constant
+ cmpw %gs:(A20_TEST_ADDR+0x10), %ax
+ loope a20_test_wait
+
+ popw %fs:(A20_TEST_ADDR)
+ popw %ax
+ popw %cx
+
+ ret
+
+#
+# Disable A20
+#
+
+disable_a20:
+ .code16
+ movb $A20_DISABLE_LOOPS, a20_disable_tries - _start16
+a20_disable_loop:
+
+ # First see if gate A20 is already disabled
+ call a20_test
+ jz a20_disabled
+
+
+ # Next, try the BIOS (INT 0x15, AX= 0x2400)
+ movw $0x2400, %ax
+ pushfl # Be paranoid about flags
+ int $0x15
+ popfl
+
+ call a20_test
+ jz a20_disabled
+
+ # Try disabling A20 through the keyboard controller
+ call empty_8042
+
+ call a20_test # Just in case the BIOS worked
+ jz a20_disabled # but had a delayed reaction.
+
+ movb $0xD1, %al # command write
+ outb %al, $0x64
+ call empty_8042
+
+ movb $0xDD, %al # A20 off
+ outb %al, $0x60
+ call empty_8042
+
+ # Wait until a20 really *is* disabled
+ xorw %cx, %cx
+a20_kbc_disable_loop:
+ call a20_test
+ jz a20_disabled
+ loop a20_kbc_disable_loop
+
+ # Final attempt: use "configuration port A"
+ inb $0x92, %al # Configuratin Port A
+ andb $0xFD, %al # "fast A20" version
+ andb $0xFE, %al # dont accidentally reset
+ outb %al, $0x92
+
+ # Wait for configuration port A to take affect
+ xorw %cx, %cx
+a20_fast_disable_loop:
+ call a20_test
+ jz a20_disabled
+ loop a20_fast_disable_loop
+
+ # A20 is still not responding. Try it again
+ decb (a20_disable_tries - _start16)
+ jnz a20_disable_loop
+
+ pushw $s_a20_cant_disable - _start16
+ call print_string16
+ addw $2, %sp
+ retw
+
+ # If we get here, all is good
+a20_disabled:
+ pushw $s_a20_disabled - _start16
+ call print_string16
+ addw $2, %sp
+ retw
+
+
+# This routine checks that the keyboard command queue is empty
+# (after emptying the output buffers)
+#
+# Some machines have delusions that the keyboard buffer is always full
+# with no keyboard attached...
+#
+# If there is no keyboard controller, we will usually get 0xff
+# to all the reads. With each IO taking a microsecond and
+# a timeout of 100,000 iterations, this can take about half a
+# second ("delay" == outb to port 0x80). That should be ok,
+# and should also be plenty of time for a real keyboard controller
+# to empty.
+#
+
+empty_8042:
+ .code16
+ pushl %ecx
+ movl $100000, %ecx
+
+empty_8042_loop:
+ decl %ecx
+ jz empty_8042_end_loop
+
+ call delay
+
+ inb $0x64, %al # 8042 status port
+ testb $1, %al # output buffer?
+ jz no_output
+
+ call delay
+ inb $0x60, %al # read it
+ jmp empty_8042_loop
+
+no_output:
+ testb $2, %al # is input buffer full?
+ jnz empty_8042_loop # yes - loop
+empty_8042_end_loop:
+ popl %ecx
+ ret
+
+
+
+
+# method E820H:
+# the memory map from hell. e820h returns memory classified into
+# a whole bunch of different types, and allows memory holes and
+# everything. We scan through this memory map and build a list
+# of the first 32 memory areas, which we return at [E820MAP].
+# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
+
+#define SMAP 0x534d4150
+#define E820_MAX 32
+#define E820_SIZE 20
+
+get_meme820:
+ .code16
+ pushw %bp
+ movw %sp, %bp
+ pushw %ds
+ pushw %es
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ xorl %eax, %eax
+ movb %al, e820nr - _start16
+ xorl %ebx, %ebx # continuation counter
+ movw $e820_map - _start16, %di # point into the whitelist
+ # so we can have the bios
+ # directly write into it.
+
+jmpe820:
+ movl $0x0000e820, %eax # e820, upper word zeroed
+ movl $SMAP, %edx # ascii SMAP
+ movl $E820_SIZE, %ecx # size of the e820rec
+ pushw %ds # data record.
+ popw %es
+ int $0x15 # make the call
+ jc bail820 # fall to e801 if it fails
+
+ cmpl $SMAP, %eax # check the return is SMAP
+ jne bail820 # fall to e801 if it fails
+
+# cmpl $1, 16(%di) # is this usable memory?
+# jne again820
+
+ # If this is usable memory, we save it by simply advancing %di by
+ # sizeof(e820rec).
+ #
+good820:
+ movb e820nr - _start16, %al # up to 32 entries
+ cmpb $E820_MAX, %al
+ jnl bail820
+
+ incb e820nr - _start16
+ movw %di, %ax
+ addw $20, %ax
+ movw %ax, %di
+again820:
+ cmpl $0, %ebx # check to see if
+ jne jmpe820 # %ebx is set to EOF
+bail820:
+ popl %ebx
+ popl %edi
+ popl %esi
+ popw %es
+ popw %ds
+ popw %bp
+ retw
+
+
+print_meme820:
+ .code16
+ pushw %si
+ xorw %cx, %cx
+ movb (e820nr - _start16), %cl
+ movw $e820_map - _start16, %si
+
+ pushw $s_meme820 - _start16
+ call print_string16
+ addw $2, %sp
+
+print_meme820.1:
+ pushw %cx
+
+ pushw 8(%si)
+ pushw 10(%si)
+ pushw 12(%si)
+ pushw 14(%si)
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+
+ pushw $s_at - _start16
+ call print_string16
+ addw $2, %sp
+
+ pushw 0(%si)
+ pushw 2(%si)
+ pushw 4(%si)
+ pushw 6(%si)
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+
+ pushw $s_type - _start16
+ call print_string16
+ addw $2, %sp
+
+ pushw 16(%si)
+ pushw 18(%si)
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ popw %cx
+ addw $E820_SIZE, %si
+ subw $1, %cx
+ jnz print_meme820.1
+
+ popw %si
+ retw
+
+
+
+print_meme801:
+ .code16
+ pushw %bp
+ movw %sp, %bp
+ pushw %bx
+ pushl $0
+
+# method E801H:
+# memory size is in 1k chunksizes
+
+ stc # fix to work around buggy
+ xorw %cx,%cx # BIOSes which dont clear/set
+ xorw %dx,%dx # carry on pass/error of
+ # e801h memory size call
+ # or merely pass cx,dx though
+ # without changing them.
+ movw $0xe801, %ax
+ int $0x15
+ jc print_meme801.2
+
+ cmpw $0x0, %cx # Kludge to handle BIOSes
+ jne e801usecxdx # which report their extended
+ cmpw $0x0, %dx # memory in AX/BX rather than
+ jne e801usecxdx # CX/DX. The spec I have read
+ movw %ax, %cx # seems to indicate AX/BX
+ movw %bx, %dx # are more reasonable anyway...
+
+e801usecxdx:
+ andl $0xffff, %edx # clear sign extend
+ shll $6, %edx # and go from 64k to 1k chunks
+ movl %edx, -6(%bp) # store extended memory size
+ andl $0xffff, %ecx # clear sign extend
+ addl %ecx, -6(%bp) # and add lower memory into
+
+ pushw $s_meme801 - _start16
+ call print_string16
+ addw $2, %sp
+
+ pushw -6(%bp)
+ pushw -4(%bp)
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+print_meme801.2:
+ addw $4, %sp
+ popw %bx
+ popw %bp
+ retw
+
+print_mem88:
+ .code16
+# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
+# 64mb, depending on the bios) in ax.
+ movb $0x88, %ah
+ int $0x15
+
+ pushw %ax
+ pushw $s_mem88 - _start16
+ call print_string16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+print_dasd_type:
+ .code16
+ pushw $s_dasd_type - _start16
+ call print_string16
+ addw $2, %sp
+
+ movw $0x1500, %ax
+ movb $0x81, %dl
+ int $0x13
+ jc print_dasd_type.1
+
+ pushw %dx
+ pushw %cx
+ pushw $s_space - _start16
+ pushw %ax
+
+ call print_hex16
+ addw $2, %sp
+ call print_string16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ jmp print_dasd_type.2
+print_dasd_type.1:
+ pushw $s_none - _start16
+ call print_string16
+ addw $2, %sp
+
+print_dasd_type.2:
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+print_equipment_list:
+ .code16
+ pushw $s_equipment_list - _start16
+ call print_string16
+ addw $2, %sp
+
+ int $0x11
+ pushw %ax
+ call print_hex16
+ addw $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+print_sysdesc:
+ .code16
+ pushw $s_sysdesc - _start16
+ call print_string16
+ addw $2, %sp
+
+ pushw %es
+ movb $0xc0, %ah
+ stc
+ int $0x15
+ movw %es, %ax
+ popw %es
+ jc print_sysdesc.1
+
+ pushw %bx
+ pushw $s_colon - _start16
+ pushw %ax
+ call print_hex16
+ addw $2, %sp
+ call print_string16
+ addw $2, %sp
+ call print_hex16
+ addw $2, %sp
+ jmp print_sysdesc.2
+
+print_sysdesc.1:
+ pushw $s_none - _start16
+ call print_string16
+ addw $2, %sp
+
+print_sysdesc.2:
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+print_edd:
+ .code16
+ pushw $s_edd - _start16
+ call print_string16
+ add $2, %sp
+
+ movb $0x80, %dl
+ movb $0x41, %ah # Function 41
+ movw $0x55aa, %bx # magic
+ int $0x13 # make the call
+ jc print_edd.1 # no more BIOS devices
+
+ cmpw $0xAA55, %bx # is magic right?
+ jne print_edd.1 # nope
+
+ pushw $s_ok - _start16
+ call print_string16
+ add $2, %sp
+ jmp print_edd.2
+
+print_edd.1:
+ pushw $s_none - _start16
+ call print_string16
+ add $2, %sp
+
+print_edd.2:
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+set_auto_repeat_rate:
+ .code16
+ pushw $s_auto_repeat_rate - _start16
+ call print_string16
+ add $2, %sp
+
+# Set the keyboard repeat rate to the max
+ movw $0x0305, %ax
+ xorw %bx, %bx
+ int $0x16
+
+ pushw $s_done - _start16
+ call print_string16
+ add $2, %sp
+
+ retw
+
+print_video:
+ .code16
+ pushw $s_video_type - _start16
+ call print_string16
+ add $2, %sp
+
+ movb $0x12, %ah # Check EGA/VGA
+ movb $0x10, %bl
+ int $0x10
+ movw $s_video_pre_ega - _start16, %cx
+ cmpb $0x10, %bl
+ je print_video.1
+
+ movw $0x1a00, %ax # Check EGA or VGA?
+ int $0x10
+ movw $s_video_vga - _start16, %cx
+ cmpb $0x1a, %al # 1a means VGA...
+ je print_video.1 # anything else is EGA.
+
+ movw $s_video_ega - _start16, %cx
+
+print_video.1:
+ pushw %cx
+ call print_string16
+ addw $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ addw $2, %sp
+
+ retw
+
+print_cursor:
+ .code16
+ pushw $s_cursor - _start16
+ call print_string16
+ add $2, %sp
+
+ movb $0x03, %ah # Read cursor position
+ xorb %bh, %bh
+ int $0x10
+
+ xorw %ax, %ax
+ movb %dl, %al
+ pushw %ax
+ pushw $s_space - _start16
+ movb %dh, %al
+ pushw %ax
+
+ call print_hex16
+ add $2, %sp
+ call print_string16
+ add $2, %sp
+ call print_hex16
+ add $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ add $2, %sp
+
+ retw
+
+print_video_mode:
+ .code16
+ pushw $s_video_mode - _start16
+ call print_string16
+ add $2, %sp
+
+ movb $0x0f, %ah # Read cursor position
+ int $0x10
+
+ xorb %ah, %ah
+ pushw %ax
+ call print_hex16
+ add $2, %sp
+
+ pushw $s_crlf - _start16
+ call print_string16
+ add $2, %sp
+
+ retw
+
+
+disable_apm:
+ push %bp
+ movw %sp, %bp
+ pushw %bx
+
+ pushw $s_testing_for_apm - _start16
+ call print_string16
+ add $2, %sp
+
+ # check for APM BIOS
+ movw $0x5300, %ax # APM BIOS installation check
+ xorw %bx, %bx
+ int $0x15
+ jc done_apm_bios # error -> no APM BIOS
+
+ cmpw $0x504d, %bx # check for "PM" signature
+ jne done_apm_bios # no signature -> no APM BIOS
+
+ pushw $s_apm_found_disconnecting - _start16
+ call print_string16
+ add $2, %sp
+
+ movw $0x5304, %ax # Disconnect first just in case
+ xorw %bx, %bx
+ int $0x15 # ignore return code
+
+ pushw $s_apm_connecting - _start16
+ call print_string16
+ add $2, %sp
+
+ movw $0x5301, %ax # Real Mode connect
+ xorw %bx, %bx
+ int $0x15
+ jc done_apm_bios # error
+
+ pushw $s_apm_disabling - _start16
+ call print_string16
+ add $2, %sp
+
+ movw $0x5308, %ax # Disable APM
+ mov $0xffff, %bx
+ xorw %cx, %cx
+ int $0x15
+
+ pushw $s_apm_disconnecting - _start16
+ call print_string16
+ add $2, %sp
+
+ movw $0x5304, %ax # Do a final disconnect
+ xorw %bx, %bx
+ int $0x15
+
+done_apm_bios:
+ pushw $s_apm_test_done - _start16
+ call print_string16
+ add $2, %sp
+
+ popw %bx
+ popw %bp
+ retw
+
+
+# Delay is needed after doing I/O
+delay:
+ .code16
+ outb %al,$0x80
+ retw
+
+halt16:
+ .code16
+ hlt
+ jmp halt16
+
+
+print_string16:
+ .code16
+ pushw %bp
+ movw %sp, %bp
+ pushw %si
+ movw 4(%bp), %si
+ xorw %ax, %ax
+print_string16.1:
+ lodsb %ds:(%si), %al
+ testb $0xff, %al
+ jz print_string16.2
+ call print_char16
+ jmp print_string16.1
+print_string16.2:
+ popw %si
+ popw %bp
+ ret
+
+print_hex16:
+ .code16
+ pushw %bp
+ movw %sp, %bp
+ movw $16, %cx
+print_hex16.1:
+ movw 4(%bp), %ax
+ subb $4, %cl
+ shrw %cl, %ax
+ andb $0x0f, %al
+ cmpb $9, %al
+ ja print_hex16.2
+ addb $'0', %al
+ jmp print_hex16.3
+print_hex16.2:
+ addb $'A' - 10, %al
+print_hex16.3:
+ pushw %cx
+ call print_char16
+ popw %cx
+ testb %cl, %cl
+ jnz print_hex16.1
+
+ popw %bp
+ ret
+
+print_char16:
+ .code16
+ # The character to print is in al
+ call serial_print_char16
+ retw
+
+
+#define TTYS0_BASE 0x3f8
+#define TTYS0_RBR (TTYS0_BASE + 0x00)
+#define TTYS0_TBR (TTYS0_BASE + 0x00)
+#define TTYS0_LSR (TTYS0_BASE + 0x05)
+
+serial_print_char16:
+ .code16
+ pushw %bp
+ movw %sp, %bp
+ # The character to print is in al
+ pushw %ax
+
+ # Wait until the serial port is ready to receive characters
+serial_print_char16.1:
+ movw $TTYS0_LSR, %dx
+ inb %dx, %al
+ testb $0x20, %al
+ jz serial_print_char16.1
+
+ # Output the character
+ movw $TTYS0_TBR, %dx
+ movb -2(%bp), %al
+ outb %al, %dx
+
+ # Wait until the serial port has transmitted the character
+serial_print_char16.2:
+ movw $TTYS0_LSR, %dx
+ inb %dx, %al
+ testb $0x40, %al
+ jz serial_print_char16.2
+
+ # Restore %eax
+ popw %ax
+ # Return to caller
+ popw %bp
+ retw
+
+
+s_a20_err_msg:
+ .asciz "A20 gate not responding!\r\n"
+
+s_in_real_mode:
+ .asciz "In real mode.\r\n"
+s_base_memory_size:
+ .asciz "Base memory size: "
+s_interrupts_enabled:
+ .asciz "Interrupts enabled.\r\n"
+s_a20_disabled:
+ .asciz "A20 disabled.\r\n"
+s_a20_cant_disable:
+ .asciz "Can not A20 line.\r\n"
+s_a20_enabled:
+ .asciz "A20 enabled\r\n"
+s_interrupts_disabled:
+ .asciz "Interrupts disabled.\r\n"
+
+s_meme820: .asciz "E820 Memory Map.\r\n"
+s_at: .asciz " @ "
+s_type: .asciz " type: "
+s_space: .asciz " "
+s_colon: .asciz ":"
+s_none: .asciz " none "
+s_ok: .asciz " ok "
+s_done: .asciz " done\r\n"
+
+s_meme801:
+ .asciz "E801 Memory size: "
+s_mem88:
+ .asciz "Mem88 Memory size: "
+
+s_dasd_type:
+ .asciz "DASD type: "
+s_equipment_list:
+ .asciz "Equiptment list: "
+s_sysdesc:
+ .asciz "Sysdesc: "
+s_edd:
+ .asciz "EDD: "
+s_auto_repeat_rate:
+ .asciz "Setting auto repeat rate "
+
+
+s_video_type:
+ .asciz "Video type: "
+s_video_pre_ega:
+ .asciz "CGA/MDA/HGA"
+s_video_ega:
+ .asciz "EGA"
+s_video_vga:
+ .asciz "VGA"
+
+s_cursor:
+ .asciz "Cursor Position(Row,Column): "
+
+s_video_mode:
+ .asciz "Video Mode: "
+
+s_testing_for_apm:
+ .asciz "Testing for APM.\r\n"
+s_apm_found_disconnecting:
+ .asciz "APM Found disconnecting.\r\n"
+s_apm_connecting:
+ .asciz "APM connecting.\r\n"
+s_apm_disabling:
+ .asciz "APM disabling.\r\n"
+s_apm_disconnecting:
+ .asciz "APM disconnecting.\r\n"
+s_apm_test_done:
+ .asciz "APM test done.\r\n"
+
+s_crlf: .asciz "\r\n"
+
+
+
+a20_tries: .byte A20_ENABLE_LOOPS
+a20_disable_tries: .byte A20_DISABLE_LOOPS
+
+
+e820nr: .byte 0
+e820_map: .fill E820_MAX * E820_SIZE, 1, 0
diff --git a/kexec_test/x86-setup-legacy-pic.S b/kexec_test/x86-setup-legacy-pic.S
new file mode 100644
index 0000000..32ef42f
--- /dev/null
+++ b/kexec_test/x86-setup-legacy-pic.S
@@ -0,0 +1,53 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * 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 (version 2 of the License).
+ *
+ * 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
+ .code32
+setup_legacy_pic:
+ /* Load the legacy dos settings into the 8259A pic */
+ movb $0xff, %al
+ outb %al, $0x21 /* mask all of 8259A-1 */
+ outb %al, $0xa1 /* mask all of 8259A-1 */
+
+ movb $0x11, %al
+ outb %al, $0x20 /* ICW1: select 8259A-1 init */
+ outb %al, $0x80 /* A short delay */
+ movb $0x08, %al
+ outb %al, $0x21 /* ICW2: 8259A-1 IR0-7 mappend to 0x8-0xf */
+ outb %al, $0x80 /* A short delay */
+ movb $01, %al
+ outb %al, $0x21 /* Normal 8086 auto EOI mode */
+ outb %al, $0x80 /* A short delay */
+
+
+ movb $0x11, %al
+ outb %al, $0xA0 /* ICW1: select 8259A-2 init */
+ outb %al, $0x80 /* A short delay */
+ movb $0x70, %al
+ outb %al, $0xA1 /* ICW2: 8259A-2 IR0-7 mappend to 0x70-0x77 */
+ outb %al, $0x80 /* A short delay */
+ movb $01, %al
+ outb %al, $0xA1 /* Normal 8086 auto EOI mode */
+ outb %al, $0x80 /* A short delay */
+
+ movb $0, %al
+ outb %al, $0x21 /* Unmask all of 8259A-1 */
+ outb %al, $0xa1 /* Unmask all of 8259A-2 */
+
+ ret