321 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
			
		
		
	
	
			321 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
| .set SECTOR_SIZE,	512
 | |
| 
 | |
| # file header field offsets
 | |
| .set e_type,		16
 | |
| .set e_machine,		18
 | |
| .set e_version,		20
 | |
| .set e_entry,		24
 | |
| 
 | |
| .set e32_phoff,		28
 | |
| .set e32_shoff,		32
 | |
| .set e32_flags,		36
 | |
| .set e32_ehsize,	40
 | |
| .set e32_phentsize,	42
 | |
| .set e32_phnum,		44
 | |
| .set e32_shentsize,	46
 | |
| .set e32_shnum,		48
 | |
| .set e32_shstrndx,	50
 | |
| 
 | |
| .set e64_phoff,		32
 | |
| .set e64_shoff,		40
 | |
| .set e64_flags,		48
 | |
| .set e64_ehsize,	52
 | |
| .set e64_phentsize,	54
 | |
| .set e64_phnum,		56
 | |
| .set e64_shentsize,	58
 | |
| .set e64_shnum,		60
 | |
| .set e64_shstrndx,	62
 | |
| 
 | |
| # e_ident offsets
 | |
| .set EI_CLASS,		4
 | |
| .set EI_DATA,		5
 | |
| .set EI_VERSION,	6
 | |
| 
 | |
| # e_ident constants
 | |
| .set ELFMAGIC,		0x464C457F
 | |
| .set ELFCLASS32,	1
 | |
| .set ELFCLASS64,	2
 | |
| .set ELFDATA2LSB,	1
 | |
| .set EV_CURRENT,	1
 | |
| 
 | |
| # e_type constants
 | |
| .set ET_EXEC,		2
 | |
| 
 | |
| # program header field offsets
 | |
| .set p_type,		0
 | |
| 
 | |
| .set p32_offset,	4
 | |
| .set p32_vaddr,		8
 | |
| .set p32_paddr,		12
 | |
| .set p32_filesz,	16
 | |
| .set p32_memsz,		20
 | |
| .set p32_flags,		24
 | |
| .set p32_align,		28
 | |
| 
 | |
| .set p64_flags,		4
 | |
| .set p64_offset,	8
 | |
| .set p64_vaddr,		16
 | |
| .set p64_paddr,		24
 | |
| .set p64_filesz,	32
 | |
| .set p64_memsz,		40
 | |
| .set p64_align,		48
 | |
| 
 | |
| # p_type constants
 | |
| .set PT_NULL,		0
 | |
| .set PT_LOAD,		1
 | |
| 
 | |
| # mask for entry point and segment loading
 | |
| .set LOAD_MASK,		0x07FFFFFF
 | |
| 
 | |
| .code16
 | |
| .section .stage2
 | |
| 
 | |
| # Validate file header stored in elf_file_header
 | |
| # returns only on success
 | |
| elf_validate_file_header:
 | |
| 	cmpl $ELFMAGIC, (elf_file_header)
 | |
| 	jne .elf_validate_file_header_invalid_magic
 | |
| 
 | |
| 	cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
 | |
| 	je .elf_validate_file_header_class_valid
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	je .elf_validate_file_header_class_valid
 | |
| 	jmp .elf_validate_file_header_invalid_class
 | |
|  .elf_validate_file_header_class_valid:
 | |
| 
 | |
| 	cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
 | |
| 	jne .elf_validate_file_header_only_little_endian_supported
 | |
| 
 | |
| 	cmpb $EV_CURRENT, (elf_file_header + EI_VERSION)
 | |
| 	jne .elf_validate_file_header_not_current_version
 | |
| 
 | |
| 	cmpl $EV_CURRENT, (elf_file_header + e_version)
 | |
| 	jne .elf_validate_file_header_not_current_version
 | |
| 
 | |
| 	cmpw $ET_EXEC, (elf_file_header + e_type)
 | |
| 	jne .elf_validate_file_header_not_executable
 | |
| 
 | |
| 	ret
 | |
| 
 | |
|  .elf_validate_file_header_invalid_magic:
 | |
| 	movw $elf_validate_file_header_invalid_magic_msg, %si
 | |
| 	jmp print_and_halt
 | |
|  .elf_validate_file_header_invalid_class:
 | |
| 	movw $elf_validate_file_header_invalid_class_msg, %si
 | |
| 	jmp print_and_halt
 | |
|  .elf_validate_file_header_only_little_endian_supported:
 | |
| 	movw $elf_validate_file_header_only_little_endian_supported_msg, %si
 | |
| 	jmp print_and_halt
 | |
|  .elf_validate_file_header_not_current_version:
 | |
| 	movw $elf_validate_file_header_not_current_version_msg, %si
 | |
| 	jmp print_and_halt
 | |
|  .elf_validate_file_header_not_executable:
 | |
| 	movw $elf_validate_file_header_not_executable_msg, %si
 | |
| 	jmp print_and_halt
 | |
| 
 | |
| # reads memory specified by 32 bit elf_program_header to memory
 | |
| elf_read_program_header32_to_memory:
 | |
| 	pushal
 | |
| 	pushl %ebp
 | |
| 	movl %esp, %ebp
 | |
| 
 | |
| 	# memset p_filesz -> p_memsz to 0
 | |
| 	movl (elf_program_header + p32_filesz), %ebx
 | |
| 	movl (elf_program_header + p32_vaddr),  %edi
 | |
| 	andl $LOAD_MASK, %edi
 | |
| 	addl %ebx, %edi
 | |
| 	movl (elf_program_header + p32_memsz),  %ecx
 | |
| 	subl %ebx, %ecx
 | |
| 	xorb %al, %al; call memset32
 | |
| 
 | |
| 	# read file specified in program header to memory
 | |
| 	movl (elf_program_header + p32_offset), %eax
 | |
| 	movl (elf_program_header + p32_vaddr),  %edi
 | |
| 	andl $LOAD_MASK, %edi
 | |
| 	movl (elf_program_header + p32_filesz), %ecx
 | |
| 	call *%esi
 | |
| 
 | |
| 	leavel
 | |
| 	popal
 | |
| 	ret
 | |
| 
 | |
| 
 | |
| # reads memory specified by 64 bit elf_program_header to memory
 | |
| elf_read_program_header64_to_memory:
 | |
| 	pushal
 | |
| 	pushl %ebp
 | |
| 	movl %esp, %ebp
 | |
| 
 | |
| 	# memset p_filesz -> p_memsz to 0
 | |
| 	movl (elf_program_header + p64_filesz), %ebx
 | |
| 	movl (elf_program_header + p64_vaddr),  %edi
 | |
| 	andl $LOAD_MASK, %edi
 | |
| 	addl %ebx, %edi
 | |
| 	movl (elf_program_header + p64_memsz),  %ecx
 | |
| 	subl %ebx, %ecx
 | |
| 	xorb %al, %al; call memset32
 | |
| 
 | |
| 	# read file specified in program header to memory
 | |
| 	movl (elf_program_header + p64_offset), %eax
 | |
| 	movl (elf_program_header + p64_vaddr),  %edi
 | |
| 	andl $LOAD_MASK, %edi
 | |
| 	movl (elf_program_header + p64_filesz), %ecx
 | |
| 	call *%esi
 | |
| 
 | |
| 	leavel
 | |
| 	popal
 | |
| 	ret
 | |
| 
 | |
| 
 | |
| # read callback format
 | |
| #	eax: first byte
 | |
| #	ecx: byte count
 | |
| #	edi: buffer
 | |
| # returns only on success
 | |
| 
 | |
| 
 | |
| # reads kernel to memory
 | |
| #	esi:	callback for reading from kernel image
 | |
| # return:
 | |
| #	eax:	kernel entry address
 | |
| .global elf_read_kernel_to_memory
 | |
| elf_read_kernel_to_memory:
 | |
| 	pushal
 | |
| 	pushl %ebp
 | |
| 	movl %esp, %ebp
 | |
| 	subl $2, %esp
 | |
| 
 | |
| 	# read start of file header
 | |
| 	movl $0, %eax
 | |
| 	movl $24, %ecx
 | |
| 	movl $elf_file_header, %edi
 | |
| 	call *%esi
 | |
| 
 | |
| 	call elf_validate_file_header
 | |
| 
 | |
| 	# determine file header size
 | |
| 	movl $52, %ecx
 | |
| 	movl $64, %edx
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	cmovel %edx, %ecx
 | |
| 
 | |
| 	# read full file header
 | |
| 	movl $0, %eax
 | |
| 	movl $elf_file_header, %edi
 | |
| 	call *%esi
 | |
| 
 | |
| 	# verify that e_phoff fits in 32 bits
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	jne .elf_read_kernel_to_memory_valid_offset
 | |
| 	cmpl $0, (elf_file_header + e64_phoff + 4)
 | |
| 	jnz .elf_read_kernel_to_memory_unsupported_offset
 | |
|  .elf_read_kernel_to_memory_valid_offset:
 | |
| 
 | |
| 	# read architecture phentsize and phnum to fixed locations
 | |
| 	movw (elf_file_header + e32_phentsize), %ax
 | |
| 	movw (elf_file_header + e32_phnum),     %bx
 | |
| 	movl (elf_file_header + e32_phoff),     %ecx
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	cmovew (elf_file_header + e64_phentsize), %ax
 | |
| 	cmovew (elf_file_header + e64_phnum),     %bx
 | |
| 	cmovel (elf_file_header + e64_phoff),     %ecx
 | |
| 	movw %ax,  (elf_file_header_phentsize)
 | |
| 	movw %bx,  (elf_file_header_phnum)
 | |
| 	movl %ecx, (elf_file_header_phoff)
 | |
| 
 | |
| 	# current program header
 | |
| 	movw $0, -2(%ebp)
 | |
| 
 | |
|  .elf_read_kernel_to_memory_loop_program_headers:
 | |
| 	movw -2(%ebp), %cx
 | |
| 	cmpw (elf_file_header_phnum), %cx
 | |
| 	jae .elf_read_kernel_to_memory_done
 | |
| 
 | |
| 	# eax := program_header_index * e_phentsize + e_phoff
 | |
| 	xorl %eax, %eax
 | |
| 	movw %cx, %ax
 | |
| 	xorl %ebx, %ebx
 | |
| 	movw (elf_file_header_phentsize), %bx
 | |
| 	mull %ebx
 | |
| 	addl (elf_file_header_phoff), %eax
 | |
| 	jc .elf_read_kernel_to_memory_unsupported_offset
 | |
| 
 | |
| 	# determine program header size
 | |
| 	movl $32, %ecx
 | |
| 	movl $56, %edx
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	cmovel %edx, %ecx
 | |
| 
 | |
| 	# read program header
 | |
| 	movl $elf_program_header, %edi
 | |
| 	call *%esi
 | |
| 
 | |
| 	# test if program header is NULL header
 | |
| 	cmpl $PT_NULL, (elf_program_header + p_type)
 | |
| 	je .elf_read_kernel_to_memory_null_program_header
 | |
| 
 | |
| 	# confirm that the program header is loadable
 | |
| 	cmpl $PT_LOAD, (elf_program_header + p_type)
 | |
| 	jne .elf_read_kernel_to_memory_not_loadable_header
 | |
| 
 | |
| 	# read program header to memory
 | |
| 	movl $elf_read_program_header32_to_memory, %eax
 | |
| 	movl $elf_read_program_header64_to_memory, %ebx
 | |
| 	cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
 | |
| 	cmovel %ebx, %eax
 | |
| 	call *%eax
 | |
| 
 | |
|  .elf_read_kernel_to_memory_null_program_header:
 | |
| 	incw -2(%ebp)
 | |
| 	jmp .elf_read_kernel_to_memory_loop_program_headers
 | |
| 
 | |
|  .elf_read_kernel_to_memory_done:
 | |
| 	leavel
 | |
| 	popal
 | |
| 
 | |
| 	# set kernel entry address
 | |
| 	movl (elf_file_header + e_entry), %eax
 | |
| 	andl $LOAD_MASK, %eax
 | |
| 
 | |
| 	ret
 | |
| 
 | |
|  .elf_read_kernel_to_memory_unsupported_offset:
 | |
| 	movw $elf_read_kernel_to_memory_unsupported_offset_msg, %si
 | |
| 	jmp print_and_halt
 | |
|  .elf_read_kernel_to_memory_not_loadable_header:
 | |
| 	movw $elf_read_kernel_to_memory_not_loadable_header_msg, %si
 | |
| 	jmp print_and_halt
 | |
| 
 | |
| .section .data
 | |
| 
 | |
| elf_validate_file_header_invalid_magic_msg:
 | |
| 	.asciz "ELF: file has invalid ELF magic"
 | |
| elf_validate_file_header_invalid_class_msg:
 | |
| 	.asciz "ELF: file has invalid ELF class"
 | |
| elf_validate_file_header_only_little_endian_supported_msg:
 | |
| 	.asciz "ELF: file is not in little endian format"
 | |
| elf_validate_file_header_not_current_version_msg:
 | |
| 	.asciz "ELF: file is not in current ELF version"
 | |
| elf_validate_file_header_not_executable_msg:
 | |
| 	.asciz "ELF: file is not an executable"
 | |
| 
 | |
| elf_read_kernel_to_memory_unsupported_offset_msg:
 | |
| 	.asciz "ELF: unsupported offset (only 32 bit offsets supported)"
 | |
| elf_read_kernel_to_memory_not_loadable_header_msg:
 | |
| 	.asciz "ELF: kernel contains non-loadable program header"
 | |
| 
 | |
| .section .bss
 | |
| 
 | |
| elf_file_header:
 | |
| 	.skip 64
 | |
| 
 | |
| elf_file_header_phentsize:
 | |
| 	.skip 2
 | |
| elf_file_header_phnum:
 | |
| 	.skip 2
 | |
| elf_file_header_phoff:
 | |
| 	.skip 4 # NOTE: only 32 bit offsets are supported
 | |
| 
 | |
| elf_program_header:
 | |
| 	.skip 56
 |