diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:56:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:56:35 +0000 |
commit | eba0cfa6b0bef4f2e73c8630a7efa3944df8b0f8 (patch) | |
tree | 74c37eede1f0634cc5de1c63c934edaa1630c6bc /kexec_test | |
parent | Initial commit. (diff) | |
download | kexec-tools-upstream.tar.xz kexec-tools-upstream.zip |
Adding upstream version 1:2.0.27.upstream/1%2.0.27upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'kexec_test')
-rw-r--r-- | kexec_test/Makefile | 40 | ||||
-rw-r--r-- | kexec_test/kexec_test.S | 477 | ||||
-rw-r--r-- | kexec_test/kexec_test16.S | 1004 | ||||
-rw-r--r-- | kexec_test/x86-setup-legacy-pic.S | 53 |
4 files changed, 1574 insertions, 0 deletions
diff --git a/kexec_test/Makefile b/kexec_test/Makefile new file mode 100644 index 0000000..fec6210 --- /dev/null +++ b/kexec_test/Makefile @@ -0,0 +1,40 @@ +# +# kexec_test Debugging payload to be certain the infrastructure works +# +RELOC:=0x10000 +KEXEC_TEST_SRCS:= kexec_test/kexec_test16.S kexec_test/kexec_test.S + +dist += kexec_test/Makefile $(KEXEC_TEST_SRCS) \ + kexec_test/x86-setup-legacy-pic.S + +BUILD_KEXEC_TEST = no +ifeq ($(ARCH),i386) +BUILD_KEXEC_TEST = yes +endif +ifeq ($(ARCH),x86_64) +BUILD_KEXEC_TEST = yes +endif + +ifeq ($(BUILD_KEXEC_TEST),yes) + +KEXEC_TEST_OBJS = $(call objify, $(KEXEC_TEST_SRCS)) +KEXEC_TEST_DEPS = $(call depify, $(KEXEC_TEST_OBJS)) + +KEXEC_TEST = $(PKGLIBDIR)/kexec_test + +clean += $(KEXEC_TEST_OBJS) $(KEXEC_TEST_DEPS) $(KEXEC_TEST) + +-include $(KEXEC_TEST_DEPS) + +$(KEXEC_TEST): CC=$(TARGET_CC) +$(KEXEC_TEST): CPPFLAGS+=-DRELOC=$(RELOC) +$(KEXEC_TEST): ASFLAGS+=-m32 +#$(KEXEC_TEST): LDFLAGS=-m32 -Wl,-e -Wl,_start -Wl,-Ttext -Wl,$(RELOC) \ +# -nostartfiles +$(KEXEC_TEST): LDFLAGS=-melf_i386 -e _start -Ttext $(RELOC) + +$(KEXEC_TEST): $(KEXEC_TEST_OBJS) + mkdir -p $(@D) + $(TARGET_LD) $(LDFLAGS) -o $@ $^ + +endif diff --git a/kexec_test/kexec_test.S b/kexec_test/kexec_test.S new file mode 100644 index 0000000..ad081bc --- /dev/null +++ b/kexec_test/kexec_test.S @@ -0,0 +1,477 @@ +/* + * 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. + */ + +#include "config.h" + + .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 PACKAGE_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 |