From 6ac36816043c7abd659cff5a6b02bc0b8b521ecb Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 2 Apr 2024 15:04:40 +0300 Subject: [PATCH] Bootloader: Implement loading for 32 bit ELF files. --- bootloader/bios/elf.S | 235 +++++++++++++++++++++++++++++++----------- 1 file changed, 175 insertions(+), 60 deletions(-) diff --git a/bootloader/bios/elf.S b/bootloader/bios/elf.S index 3499e5ee..e1d2d2c2 100644 --- a/bootloader/bios/elf.S +++ b/bootloader/bios/elf.S @@ -5,15 +5,26 @@ .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 + +.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 @@ -22,6 +33,7 @@ # e_ident constants .set ELFMAGIC, 0x464C457F +.set ELFCLASS32, 1 .set ELFCLASS64, 2 .set ELFDATA2LSB, 1 .set EV_CURRENT, 1 @@ -31,18 +43,30 @@ # 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 + +.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 @@ -52,8 +76,12 @@ 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) - jne .elf_validate_file_header_only_64bit_supported + 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 @@ -72,8 +100,8 @@ elf_validate_file_header: .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 + .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 @@ -86,6 +114,77 @@ elf_validate_file_header: jmp print_and_halt +# sets memory to zero +# edi: start address +# ecx: byte count +# on return +# edi: start address + byte count +# ecx: 0 +elf_memset_zero: + test %ecx, %ecx + jz .elf_memset_zero_done + .elf_memset_zero_loop: + movb $0, (%edi) + incl %edi + decl %ecx + jnz .elf_memset_zero_loop + .elf_memset_zero_done: + ret + +# 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 + call elf_memset_zero + + # 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 + call elf_memset_zero + + # 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 @@ -104,42 +203,72 @@ elf_read_kernel_to_memory: movl %esp, %ebp subl $2, %esp - # read file header + # read start of file header movl $0, %eax - movl $64, %ecx + movl $24, %ecx movl $elf_file_header, %edi call *%esi call elf_validate_file_header - cmpl $0, (elf_file_header + e_phoff + 4) + # 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 + e_phnum), %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 + e_phentsize), %bx + movw (elf_file_header_phentsize), %bx mull %ebx - addl (elf_file_header + e_phoff), %eax + addl (elf_file_header_phoff), %eax jc .elf_read_kernel_to_memory_unsupported_offset - # setup program header size and address - movl $56, %ecx - movl $elf_program_header, %edi + # determine program header size + movl $32, %ecx + movl $56, %edx + cmpb $ELFCLASS64, (elf_file_header + EI_CLASS) + cmovel %edx, %ecx - # read the program header + # read program header + movl $elf_program_header, %edi call *%esi - # test if program header is empty + # test if program header is NULL header cmpl $PT_NULL, (elf_program_header + p_type) je .elf_read_kernel_to_memory_null_program_header @@ -147,33 +276,12 @@ elf_read_kernel_to_memory: 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_memset_done - - .elf_read_kernel_to_memory_memset: - movb $0, (%edi) - incl %edi - decl %ecx - jnz .elf_read_kernel_to_memory_memset - .elf_read_kernel_to_memory_memset_done: - - # 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 + # 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) @@ -185,7 +293,7 @@ elf_read_kernel_to_memory: # set kernel entry address movl (elf_file_header + e_entry), %eax - andl $0x7FFFFF, %eax + andl $LOAD_MASK, %eax ret @@ -200,8 +308,8 @@ elf_read_kernel_to_memory: 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_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: @@ -219,5 +327,12 @@ elf_read_kernel_to_memory_not_loadable_header_msg: 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