mirror of
				https://github.com/meizu-m86/kexec-tools-arm64
				synced 2025-11-04 13:56:01 +08:00 
			
		
		
		
	- Initial import into git - initial nbi image formage support - ppc32 initial register setting fixes. - gzipped multiboot file support
		
			
				
	
	
		
			476 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			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
 | 
						|
 |