diff options
Diffstat (limited to 'kexec_test/kexec_test.S')
-rw-r--r-- | kexec_test/kexec_test.S | 477 |
1 files changed, 477 insertions, 0 deletions
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 + |