Files
kexec-tools-arm64/kexec_test/kexec_test.S
Eric W. Biederman 283261998a kexec-tools-1.101
- Initial import into git
  - initial nbi image formage support
  - ppc32 initial register setting fixes.
  - gzipped multiboot file support
2006-07-27 02:36:23 -06:00

476 lines
8.1 KiB
ArmAsm

/*
* 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