Bootloader: Load kernel to memory and jump to it!
This commit is contained in:
parent
9e69053e64
commit
641a2dec00
|
@ -6,6 +6,7 @@ set(BOOTLOADER_SOURCES
|
||||||
boot.S
|
boot.S
|
||||||
command_line.S
|
command_line.S
|
||||||
disk.S
|
disk.S
|
||||||
|
elf.S
|
||||||
ext2.S
|
ext2.S
|
||||||
memory_map.S
|
memory_map.S
|
||||||
utils.S
|
utils.S
|
||||||
|
|
|
@ -78,10 +78,35 @@ stage2_main:
|
||||||
jz print_and_halt
|
jz print_and_halt
|
||||||
|
|
||||||
call ext2_find_kernel
|
call ext2_find_kernel
|
||||||
|
movl $ext2_inode_read_bytes, %esi
|
||||||
|
|
||||||
jmp halt
|
call elf_read_kernel_to_memory
|
||||||
|
|
||||||
|
cli
|
||||||
|
|
||||||
|
|
||||||
|
# setup protected mode
|
||||||
|
movl %cr0, %ebx
|
||||||
|
orb $1, %bl
|
||||||
|
movl %ebx, %cr0
|
||||||
|
|
||||||
|
|
||||||
|
# jump to kernel in protected mode
|
||||||
|
ljmpl $0x18, $protected_mode
|
||||||
|
|
||||||
|
|
||||||
|
.code32
|
||||||
|
protected_mode:
|
||||||
|
movw $0x10, %bx
|
||||||
|
movw %bx, %ds
|
||||||
|
movw %bx, %es
|
||||||
|
movw %bx, %fs
|
||||||
|
movw %bx, %gs
|
||||||
|
movw %bx, %ss
|
||||||
|
jmp *%eax
|
||||||
|
|
||||||
|
|
||||||
|
.code16
|
||||||
enter_unreal_mode:
|
enter_unreal_mode:
|
||||||
cli
|
cli
|
||||||
pushw %ds
|
pushw %ds
|
||||||
|
@ -120,6 +145,7 @@ gdt:
|
||||||
.quad 0x0000000000000000
|
.quad 0x0000000000000000
|
||||||
.quad 0x00009A000000FFFF
|
.quad 0x00009A000000FFFF
|
||||||
.quad 0x00CF92000000FFFF
|
.quad 0x00CF92000000FFFF
|
||||||
|
.quad 0x00CF9A000000FFFF
|
||||||
gdtr:
|
gdtr:
|
||||||
.short . - gdt - 1
|
.short . - gdt - 1
|
||||||
.quad gdt
|
.quad gdt
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
.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 e_phoff, 32
|
||||||
|
.set e_shoff, 40
|
||||||
|
.set e_flags, 48
|
||||||
|
.set e_ehsize, 52
|
||||||
|
.set e_phentsize, 54
|
||||||
|
.set e_phnum, 56
|
||||||
|
.set e_shentsize, 58
|
||||||
|
.set e_shnum, 60
|
||||||
|
.set e_shstrndx, 62
|
||||||
|
|
||||||
|
# e_ident offsets
|
||||||
|
.set EI_CLASS, 4
|
||||||
|
.set EI_DATA, 5
|
||||||
|
.set EI_VERSION, 6
|
||||||
|
|
||||||
|
# e_ident constants
|
||||||
|
.set ELFMAGIC, 0x464C457F
|
||||||
|
.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 p_flags, 4
|
||||||
|
.set p_offset, 8
|
||||||
|
.set p_vaddr, 16
|
||||||
|
.set p_paddr, 24
|
||||||
|
.set p_filesz, 32
|
||||||
|
.set p_memsz, 40
|
||||||
|
.set p_align, 48
|
||||||
|
|
||||||
|
# p_type constants
|
||||||
|
.set PT_NULL, 0
|
||||||
|
.set PT_LOAD, 1
|
||||||
|
|
||||||
|
.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 $ELFCLASS64, (elf_file_header + EI_CLASS)
|
||||||
|
jne .elf_validate_file_header_only_64bit_supported
|
||||||
|
|
||||||
|
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_only_64bit_supported:
|
||||||
|
movw $elf_validate_file_header_only_64bit_supported_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
|
||||||
|
|
||||||
|
|
||||||
|
# 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 file header
|
||||||
|
movl $0, %eax
|
||||||
|
movl $64, %ecx
|
||||||
|
movl $elf_file_header, %edi
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
call elf_validate_file_header
|
||||||
|
|
||||||
|
cmpl $0, (elf_file_header + e_phoff + 4)
|
||||||
|
jnz .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
|
||||||
|
# current program header
|
||||||
|
movw $0, -2(%ebp)
|
||||||
|
|
||||||
|
.elf_read_kernel_to_memory_loop_program_headers:
|
||||||
|
movw -2(%ebp), %cx
|
||||||
|
cmpw (elf_file_header + e_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 + e_phentsize), %bx
|
||||||
|
mull %ebx
|
||||||
|
addl (elf_file_header + e_phoff), %eax
|
||||||
|
jc .elf_read_kernel_to_memory_unsupported_offset
|
||||||
|
|
||||||
|
# setup program header size and address
|
||||||
|
movl $56, %ecx
|
||||||
|
movl $elf_program_header, %edi
|
||||||
|
|
||||||
|
# read the program header
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
# test if program header is empty
|
||||||
|
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
|
||||||
|
|
||||||
|
# memset p_filesz -> p_memsz to 0
|
||||||
|
movl (elf_program_header + p_filesz), %ebx
|
||||||
|
|
||||||
|
movl (elf_program_header + p_vaddr), %edi
|
||||||
|
andl $0x7FFFFFFF, %edi
|
||||||
|
addl %ebx, %edi
|
||||||
|
|
||||||
|
movl (elf_program_header + p_memsz), %ecx
|
||||||
|
subl %ebx, %ecx
|
||||||
|
jz .elf_read_kernel_to_memory_no_memset
|
||||||
|
|
||||||
|
.elf_read_kernel_to_memory_memset:
|
||||||
|
movb $0, (%edi)
|
||||||
|
decl %ecx
|
||||||
|
jnz .elf_read_kernel_to_memory_memset
|
||||||
|
.elf_read_kernel_to_memory_no_memset:
|
||||||
|
|
||||||
|
# read file specified in program header to memory
|
||||||
|
movl (elf_program_header + p_offset), %eax
|
||||||
|
movl (elf_program_header + p_vaddr), %edi
|
||||||
|
andl $0x7FFFFFFF, %edi
|
||||||
|
movl (elf_program_header + p_filesz), %ecx
|
||||||
|
|
||||||
|
call print_hex32; call print_newline
|
||||||
|
|
||||||
|
call *%esi
|
||||||
|
|
||||||
|
.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 $0x7FFFFF, %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
|
||||||
|
|
||||||
|
|
||||||
|
elf_validate_file_header_invalid_magic_msg:
|
||||||
|
.asciz "ELF: file has invalid ELF magic"
|
||||||
|
elf_validate_file_header_only_64bit_supported_msg:
|
||||||
|
.asciz "ELF: file is not targettint 64 bit"
|
||||||
|
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_program_header:
|
||||||
|
.skip 56
|
|
@ -408,8 +408,14 @@ ext2_inode_read_bytes:
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
addl %edx, %esi
|
addl %edx, %esi
|
||||||
|
|
||||||
# copy partial block to destination buffer
|
# very dumb memcpy with 32 bit addresses
|
||||||
rep movsb # not sure if this uses (si or esi) and (di or edi)
|
.ext2_inode_read_bytes_memcpy_partial:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
incl %esi
|
||||||
|
incl %edi
|
||||||
|
decl %ecx
|
||||||
|
jnz .ext2_inode_read_bytes_memcpy_partial
|
||||||
|
|
||||||
# check if all sectors are read
|
# check if all sectors are read
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
@ -433,9 +439,15 @@ ext2_inode_read_bytes:
|
||||||
addl %ecx, 0(%esp)
|
addl %ecx, 0(%esp)
|
||||||
subl %ecx, 4(%esp)
|
subl %ecx, 4(%esp)
|
||||||
|
|
||||||
# copy bytes from block into destination
|
# very dumb memcpy with 32 bit addresses
|
||||||
movl $ext2_block_buffer, %esi
|
movl $ext2_block_buffer, %esi
|
||||||
rep movsb # not sure if this uses (si or esi) and (di or edi)
|
.ext2_inode_read_bytes_memcpy:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
incl %esi
|
||||||
|
incl %edi
|
||||||
|
decl %ecx
|
||||||
|
jnz .ext2_inode_read_bytes_memcpy
|
||||||
|
|
||||||
# read next block if more sectors remaining
|
# read next block if more sectors remaining
|
||||||
cmpl $0, 4(%esp)
|
cmpl $0, 4(%esp)
|
||||||
|
|
Loading…
Reference in New Issue