Compare commits

..

No commits in common. "a312d75bb260e381a724fe995f691bff31f10fdc" and "a9412aa741ba03ef8b2792f50f47a4a484acd4cd" have entirely different histories.

21 changed files with 121 additions and 1056 deletions

View File

@ -6,9 +6,7 @@ set(BOOTLOADER_SOURCES
boot.S
command_line.S
disk.S
elf.S
ext2.S
framebuffer.S
memory_map.S
utils.S
)

View File

@ -53,15 +53,9 @@ stage2_main:
movw $hello_msg, %si
call puts; call print_newline
call enter_unreal_mode
movw $unreal_enter_msg, %si
call puts; call print_newline
call get_memory_map
call read_user_command_line
call vesa_find_video_mode
call print_newline
movw $start_kernel_load_msg, %si
@ -80,91 +74,11 @@ stage2_main:
jz print_and_halt
call ext2_find_kernel
movl $ext2_inode_read_bytes, %esi
call elf_read_kernel_to_memory
call vesa_set_target_mode
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
movl %eax, %ecx
movl $0xD3C60CFF, %eax
movl $banan_boot_info, %ebx
xorl %edx, %edx
xorl %esi, %esi
xorl %edi, %edi
jmp *%ecx
.code16
enter_unreal_mode:
cli
pushw %ds
lgdt gdtr
movl %cr0, %eax
orb $1, %al
movl %eax, %cr0
ljmpl $0x8, $.enter_unreal_mode_pmode
.enter_unreal_mode_pmode:
movw $0x10, %bx
movw %bx, %ds
andb 0xFE, %al
movl %eax, %cr0
ljmpl $0x0, $.enter_unreal_mode_unreal
.enter_unreal_mode_unreal:
popw %ds
sti
ret
jmp halt
hello_msg:
.asciz "This is banan-os bootloader"
unreal_enter_msg:
.asciz "Entered unreal mode"
start_kernel_load_msg:
.asciz "Starting to load kernel"
gdt:
.quad 0x0000000000000000
.quad 0x00009A000000FFFF
.quad 0x00CF92000000FFFF
.quad 0x00CF9A000000FFFF
gdtr:
.short . - gdt - 1
.quad gdt
banan_boot_info:
boot_command_line:
.long command_line
boot_framebuffer:
.long framebuffer
boot_memory_map:
.long memory_map

View File

@ -6,20 +6,10 @@
# NO REGISTERS SAVED
.global read_user_command_line
read_user_command_line:
# print initial command line
movw $command_line_enter_msg, %si
call puts
movw $command_line_buffer, %si
call puts
# prepare registers for input
movw $command_line_enter_msg, %si
movw $command_line_buffer, %di
.read_user_command_line_goto_end:
cmpb $0, (%di)
jz .read_user_command_line_loop
incw %di
jmp .read_user_command_line_goto_end
.read_user_command_line_loop:
call getc
@ -33,13 +23,9 @@ read_user_command_line:
cmpb $'\n', %al
je .read_user_command_line_done
pushw %ax
call isprint
testb %al, %al
jz .read_user_command_line_loop
popw %ax
jnz .read_user_command_line_loop
# put byte to buffer
movb %al, (%di)
@ -75,9 +61,9 @@ read_user_command_line:
command_line_enter_msg:
.asciz "cmdline: "
.global command_line
command_line:
.section .bss
# 100 character command line
command_line_buffer:
.ascii "root=/dev/sda2"
.skip 100 - 28
.skip 100

View File

@ -1,222 +0,0 @@
.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_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
.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

View File

@ -232,8 +232,8 @@ ext2_read_inode:
addl $ext2_block_buffer, %esi
# edi := ext2_inode_buffer
movl $ext2_inode_buffer, %edi
# ecx := inode_size
movl (ext2_inode_size), %ecx
# cx := inode_size
movw (ext2_inode_size), %cx
rep movsb
popal
@ -245,10 +245,7 @@ ext2_read_inode:
# return:
# eax: block index
ext2_data_block_index:
pushl %ebx
pushl %ecx
pushl %edx
pushl %esi
# calculate max data blocks
movl (ext2_inode_buffer + i_size), %ecx
@ -263,87 +260,13 @@ ext2_data_block_index:
# check if this is direct block access
cmpl $12, %eax
jb .ext2_data_block_index_direct
subl $12, %eax
# check if this is singly indirect block access
cmpl $(EXT2_BLOCK_SIZE / 4), %eax
jb .ext2_data_block_index_singly_indirect
subl $(EXT2_BLOCK_SIZE / 4), %eax
# check if this is doubly indirect block access
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
jb .ext2_data_block_index_doubly_indirect
subl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
# check if this is triply indirect block access
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
jb .ext2_data_block_index_triply_indirect
# otherwise this is invalid access
jmp .ext2_data_block_index_invalid
jmp .ext2_data_block_index_unsupported
.ext2_data_block_index_direct:
movl $(ext2_inode_buffer + i_block), %esi
movl (%esi, %eax, 4), %eax
jmp .ext2_data_block_index_done
.ext2_data_block_index_singly_indirect:
movl %eax, %ebx
movl (ext2_inode_buffer + i_block + 12 * 4), %eax
movw $1, %cx
jmp .ext2_data_block_index_indirect
.ext2_data_block_index_doubly_indirect:
movl %eax, %ebx
movl (ext2_inode_buffer + i_block + 13 * 4), %eax
movw $2, %cx
jmp .ext2_data_block_index_indirect
.ext2_data_block_index_triply_indirect:
movl %eax, %ebx
movl (ext2_inode_buffer + i_block + 14 * 4), %eax
movw $3, %cx
jmp .ext2_data_block_index_indirect
# eax := current block
# ebx := index
# cx := depth
.ext2_data_block_index_indirect:
call ext2_read_block
# store depth and index
pushw %cx
pushl %ebx
cmpw $1, %cx
jbe .ext2_data_block_index_no_shift
# cl := shift
movb $(EXT2_BLOCK_SHIFT - 2), %al
decb %cl
mulb %cl
movb %al, %cl
# ebx := ebx >> cl
shrl %cl, %ebx
.ext2_data_block_index_no_shift:
# edx := index of next block
movl %ebx, %eax
xorl %edx, %edx
movl $(EXT2_BLOCK_SIZE / 4), %ebx
divl %ebx
# eax := next block
movl $ext2_block_buffer, %esi
movl (%esi, %edx, 4), %eax
# restore depth and index
popl %ebx
popw %cx
loop .ext2_data_block_index_indirect
movl $(ext2_inode_buffer + i_block), %ecx
addl %eax, %ecx
movl (%ecx), %eax
jmp .ext2_data_block_index_done
.ext2_data_block_index_out_of_bounds:
@ -352,112 +275,14 @@ ext2_data_block_index:
movl $0, %eax
jmp .ext2_data_block_index_done
.ext2_data_block_index_invalid:
movw $ext2_data_block_index_invalid_msg, %si
.ext2_data_block_index_unsupported:
movw $ext2_data_block_index_unsupported_msg, %si
call puts; call print_newline
movl $0, %eax
jmp .ext2_data_block_index_done
.ext2_data_block_index_done:
popl %esi
popl %edx
popl %ecx
popl %ebx
ret
# read bytes from inode (implements read callback)
# eax: first byte
# ecx: byte count
# edi: buffer
# returns only on success
.global ext2_inode_read_bytes
ext2_inode_read_bytes:
pushal
pushl %ebp
movl %esp, %ebp
subl $8, %esp
# save read info
movl %eax, 0(%esp)
movl %ecx, 4(%esp)
# check if eax % EXT2_BLOCK_SIZE != 0,
# then we need to read a partial block starting from an offset
xorl %edx, %edx
movl $EXT2_BLOCK_SIZE, %ebx
divl %ebx
testl %edx, %edx
jz .ext2_inode_read_bytes_no_partial_start
# get data block index and read block
call ext2_data_block_index
call ext2_read_block
# ecx := byte count (min(block_size - edx, remaining_bytes))
movl $EXT2_BLOCK_SIZE, %ecx
subl %edx, %ecx
cmpl %ecx, 4(%esp)
cmovbl 4(%esp), %ecx
# update remaining read info
addl %ecx, 0(%esp)
subl %ecx, 4(%esp)
# esi := start sector data (block_buffer + index * SECTOR_SIZE)
movl $ext2_block_buffer, %esi
addl %edx, %esi
# very dumb memcpy with 32 bit addresses
movl $0, %ebx
.ext2_inode_read_bytes_memcpy_partial:
movb (%esi, %ebx), %al
movb %al, (%edi, %ebx)
incl %ebx
decl %ecx
jnz .ext2_inode_read_bytes_memcpy_partial
addl %ebx, %edi
# check if all sectors are read
cmpl $0, 4(%esp)
je .ext2_inode_read_bytes_done
.ext2_inode_read_bytes_no_partial_start:
# eax := data block index (byte_start / block_size)
movl 0(%esp), %eax
shrl $(EXT2_BLOCK_SHIFT), %eax
# get data block index and read block
call ext2_data_block_index
call ext2_read_block
# calculate bytes to copy (min(block_size, remaining_bytes))
movl $EXT2_BLOCK_SIZE, %ecx
cmpl %ecx, 4(%esp)
cmovbl 4(%esp), %ecx
# update remaining read info
addl %ecx, 0(%esp)
subl %ecx, 4(%esp)
# very dumb memcpy with 32 bit addresses
movl $ext2_block_buffer, %esi
movl $0, %ebx
.ext2_inode_read_bytes_memcpy:
movb (%esi, %ebx), %al
movb %al, (%edi, %ebx)
incl %ebx
decl %ecx
jnz .ext2_inode_read_bytes_memcpy
addl %ebx, %edi
# read next block if more sectors remaining
cmpl $0, 4(%esp)
jnz .ext2_inode_read_bytes_no_partial_start
.ext2_inode_read_bytes_done:
leavel
popal
ret
@ -568,14 +393,8 @@ ext2_directory_find_inode:
# search for kernel file from filesystem
# returns only on success
.global ext2_find_kernel
ext2_find_kernel:
pushl %eax
pushw %cx
pushw %di
pushw %si
movl $EXT2_ROOT_INO, %eax
call ext2_read_inode
@ -624,10 +443,8 @@ ext2_find_kernel:
movw $ext2_kernel_found_msg, %si
call puts; call print_newline
popw %si
popw %di
popw %cx
popl %eax
1: jmp 1b
ret
.ext2_find_kernel_part_not_dir:
@ -673,8 +490,8 @@ ext2_kernel_found_msg:
ext2_data_block_index_out_of_bounds_msg:
.asciz "data block index out of bounds"
ext2_data_block_index_invalid_msg:
.asciz "data block index is invalid"
ext2_data_block_index_unsupported_msg:
.asciz "unsupported data block index"
ext2_looking_for_msg:
.asciz "looking for "

View File

@ -1,156 +0,0 @@
.set TARGET_WIDTH, 800
.set TARGET_HEIGHT, 600
.set TARGET_BPP, 32
.code16
.section .stage2
# Find suitable video mode
# return:
# ax: video mode number if found, 0 otherwise
.global vesa_find_video_mode
vesa_find_video_mode:
pushw %ax
pushw %cx
pushw %di
pushl %esi
# clear target mode and frame buffer
movw $0, (vesa_target_mode)
movl $0, (framebuffer + 0)
movl $0, (framebuffer + 4)
movl $0, (framebuffer + 8)
movl $0, (framebuffer + 12)
movw $0, (framebuffer + 16)
# get vesa information
movw $0x4F00, %ax
movw $vesa_info_buffer, %di
int $0x10
cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error
# confirm that response starts with 'VESA'
cmpl $0x41534556, (vesa_info_buffer)
jne .vesa_error
# confirm that version is atleast 2.0
cmpw $0x0200, (vesa_info_buffer + 0x04)
jb .vesa_unsupported_version
movl $(vesa_info_buffer + 0x0E), %esi
movl (%esi), %esi
.vesa_find_video_mode_loop_modes:
cmpw $0xFFFF, (%esi)
je .vesa_find_video_mode_loop_modes_done
# get info of next mode
movw $0x4F01, %ax
movw (%esi), %cx
movw $vesa_mode_info_buffer, %di
int $0x10
cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error
# check whether in graphics mode
testb $0x10, (vesa_mode_info_buffer + 0)
jz .vesa_find_video_mode_next_mode
# compare mode's dimensions
cmpw $TARGET_WIDTH, (vesa_mode_info_buffer + 0x12)
jne .vesa_find_video_mode_next_mode
cmpw $TARGET_HEIGHT, (vesa_mode_info_buffer + 0x14)
jne .vesa_find_video_mode_next_mode
cmpb $TARGET_BPP, (vesa_mode_info_buffer + 0x19)
jne .vesa_find_video_mode_next_mode
movl (vesa_mode_info_buffer + 0x28), %esi
movl %esi, (framebuffer + 0)
movw (vesa_mode_info_buffer + 0x10), %ax
movw %ax, (framebuffer + 4)
movl $TARGET_WIDTH, (framebuffer + 8)
movl $TARGET_HEIGHT, (framebuffer + 12)
movb $TARGET_BPP, (framebuffer + 16)
movb $1, (framebuffer + 17)
movw %cx, (vesa_target_mode)
jmp .vesa_find_video_mode_loop_modes_done
.vesa_find_video_mode_next_mode:
addl $2, %esi
jmp .vesa_find_video_mode_loop_modes
.vesa_find_video_mode_loop_modes_done:
popl %esi
popw %di
popw %cx
popw %ax
ret
.vesa_unsupported:
movw $vesa_unsupported_msg, %si
jmp print_and_halt
.vesa_unsupported_version:
movw $vesa_unsupported_version_msg, %si
jmp print_and_halt
.vesa_error:
movw $vesa_error_msg, %si
jmp print_and_halt
# set mode found from vesa_find_video_mode. if no mode
# was found, set it to 80x25 text mode to clear the screen.
.global vesa_set_target_mode
vesa_set_target_mode:
pushw %ax
pushw %bx
movw (vesa_target_mode), %bx
testw %bx, %bx
jz .vesa_set_target_mode_generic
movw $0x4F02, %ax
orw $0x4000, %bx
int $0x10
jmp .set_video_done
.vesa_set_target_mode_generic:
movb $0x03, %al
movb $0x00, %ah
int $0x10
.set_video_done:
popw %bx
popw %ax
ret
vesa_error_msg:
.asciz "VESA error"
vesa_unsupported_msg:
.asciz "VESA unsupported"
vesa_unsupported_version_msg:
.asciz "VESA unsupported version"
vesa_success_msg:
.asciz "VESA success"
.section .bss
vesa_info_buffer:
.skip 512
vesa_mode_info_buffer:
.skip 256
vesa_target_mode:
.skip 2
.global framebuffer
framebuffer:
.skip 4 # address
.skip 4 # pitch
.skip 4 # width
.skip 4 # height
.skip 1 # bpp
.skip 1 # type

View File

@ -122,8 +122,6 @@ memory_map_error_msg:
.section .bss
.global memory_map
memory_map:
memory_map_entry_count:
.skip 4
# 100 entries should be enough...

View File

@ -196,68 +196,6 @@ print_number:
popa
ret
# prints 8 bit hexadecimal number to screen
# al: number to print
.global print_hex8
print_hex8:
pushw %ax
pushw %bx
pushw %cx
movw $16, %bx
movw $2, %cx
andw $0xFF, %ax
call print_number
popw %cx
popw %bx
popw %ax
ret
# prints 16 bit hexadecimal number to screen
# ax: number to print
.global print_hex16
print_hex16:
pushw %bx
pushw %cx
movw $16, %bx
movw $4, %cx
call print_number
popw %cx
popw %bx
ret
# prints 32 bit hexadecimal number to screen
# eax: number to print
.global print_hex32
print_hex32:
pushl %eax
pushw %dx
movw %ax, %dx
shrl $16, %eax;
call print_hex16
movw %dx, %ax
call print_hex16
popw %dx
popl %eax
ret
# prints 64 bit hexadecimal number to screen
# edx:eax: number to print
.global print_hex64
print_hex64:
xchgl %eax, %edx
call print_hex32
xchgl %eax, %edx
call print_hex32
ret
# test if character is printable ascii
# al: character to test
# return:

View File

@ -12,7 +12,6 @@ set(KERNEL_SOURCES
font/prefs.psf.o
kernel/ACPI.cpp
kernel/APIC.cpp
kernel/BootInfo.cpp
kernel/CPUID.cpp
kernel/Debug.cpp
kernel/Device/Device.cpp

View File

@ -4,6 +4,7 @@
#include <kernel/LockGuard.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
extern uint8_t g_kernel_start[];
extern uint8_t g_kernel_end[];
@ -144,14 +145,6 @@ namespace Kernel
prepare_fast_page();
// Map main bios area below 1 MiB
map_range_at(
0x000E0000,
P2V(0x000E0000),
0x00100000 - 0x000E0000,
PageTable::Flags::Present
);
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
map_range_at(
@ -176,6 +169,22 @@ namespace Kernel
g_userspace_end - g_userspace_start,
Flags::Execute | Flags::UserSupervisor | Flags::Present
);
// Map multiboot memory
paddr_t multiboot2_data_start = (vaddr_t)g_multiboot2_info & PAGE_ADDR_MASK;
paddr_t multiboot2_data_end = (vaddr_t)g_multiboot2_info + g_multiboot2_info->total_size;
size_t multiboot2_needed_pages = BAN::Math::div_round_up<size_t>(multiboot2_data_end - multiboot2_data_start, PAGE_SIZE);
vaddr_t multiboot2_vaddr = reserve_free_contiguous_pages(multiboot2_needed_pages, KERNEL_OFFSET);
map_range_at(
multiboot2_data_start,
multiboot2_vaddr,
multiboot2_needed_pages * PAGE_SIZE,
Flags::ReadWrite | Flags::Present
);
g_multiboot2_info = (multiboot2_info_t*)(multiboot2_vaddr + ((vaddr_t)g_multiboot2_info % PAGE_SIZE));
}
void PageTable::prepare_fast_page()
@ -362,7 +371,7 @@ namespace Kernel
{
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET && s_current)
if (vaddr >= KERNEL_OFFSET)
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);

View File

@ -21,8 +21,8 @@ multiboot2_start:
.short 5
.short 0
.long 20
.long 800
.long 600
.long 1920
.long 1080
.long 32
# legacy start
@ -50,9 +50,11 @@ multiboot2_end:
g_kernel_cmdline:
.skip 4096
bootloader_magic:
.global g_multiboot2_info
g_multiboot2_info:
.skip 8
bootloader_info:
.global g_multiboot2_magic
g_multiboot2_magic:
.skip 8
.section .data
@ -165,8 +167,8 @@ initialize_paging:
_start:
# Initialize stack and multiboot info
movl $V2P(g_boot_stack_top), %esp
movl %eax, V2P(bootloader_magic)
movl %ebx, V2P(bootloader_info)
movl %eax, V2P(g_multiboot2_magic)
movl %ebx, V2P(g_multiboot2_info)
call check_requirements
call enable_sse
@ -198,11 +200,8 @@ higher_half:
# call global constuctors
call _init
# call to the kernel itself (clear rbp for stacktrace)
# call to the kernel itself (clear ebp for stacktrace)
xorq %rbp, %rbp
movl V2P(bootloader_magic), %edi
movl V2P(bootloader_info), %esi
call kernel_main
# call global destructors

View File

@ -1,36 +0,0 @@
#pragma once
#include <stdint.h>
#define BANAN_BOOTLOADER_MAGIC 0xD3C60CFF
#define BANAN_BOOTLOADER_FB_RGB 1
struct BananBootFramebufferInfo
{
uint32_t address;
uint32_t pitch;
uint32_t width;
uint32_t height;
uint8_t bpp;
uint8_t type;
};
struct BananBootloaderMemoryMapEntry
{
uint64_t address;
uint64_t length;
uint32_t type;
} __attribute__((packed));
struct BananBootloaderMemoryMapInfo
{
uint32_t entry_count;
BananBootloaderMemoryMapEntry entries[];
} __attribute__((packed));
struct BananBootloaderInfo
{
uint32_t command_line_addr;
uint32_t framebuffer_addr;
uint32_t memory_map_addr;
} __attribute__((packed));

View File

@ -1,47 +0,0 @@
#pragma once
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
namespace Kernel
{
enum class FramebufferType
{
NONE,
UNKNOWN,
RGB
};
struct FramebufferInfo
{
paddr_t address;
uint32_t pitch;
uint32_t width;
uint32_t height;
uint8_t bpp;
FramebufferType type = FramebufferType::NONE;
};
struct MemoryMapEntry
{
uint32_t type;
paddr_t address;
uint64_t length;
};
struct BootInfo
{
BAN::String command_line;
FramebufferInfo framebuffer;
BAN::Vector<MemoryMapEntry> memory_map_entries;
};
bool validate_boot_magic(uint32_t magic);
void parse_boot_info(uint32_t magic, uint32_t info);
BAN::StringView get_early_boot_command_line(uint32_t magic, uint32_t info);
extern BootInfo g_boot_info;
}

View File

@ -13,18 +13,11 @@
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT2_MAGIC 0x36d76289
struct multiboot2_tag_t
{
uint32_t type;
uint32_t size;
const multiboot2_tag_t* next() const
{
return reinterpret_cast<const multiboot2_tag_t*>(
reinterpret_cast<uintptr_t>(this) + ((size + 7) & ~7)
);
}
multiboot2_tag_t* next() { return (multiboot2_tag_t*)((uintptr_t)this + ((size + 7) & ~7)); }
} __attribute__((packed));
struct multiboot2_cmdline_tag_t : public multiboot2_tag_t
@ -69,3 +62,14 @@ struct multiboot2_info_t
uint32_t reserved;
multiboot2_tag_t tags[];
} __attribute__((packed));
extern "C" multiboot2_info_t* g_multiboot2_info;
extern "C" uint32_t g_multiboot2_magic;
inline multiboot2_tag_t* multiboot2_find_tag(uint32_t type)
{
for (auto* tag = g_multiboot2_info->tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next())
if (tag->type == type)
return tag;
return nullptr;
}

View File

@ -2,6 +2,7 @@
#include <BAN/StringView.h>
#include <kernel/ACPI.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <lai/core.h>
@ -84,14 +85,11 @@ namespace Kernel
static const RSDP* locate_rsdp()
{
// FIXME: add this back
#if 0
// Check the multiboot headers
if (auto* rsdp_new = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_NEW_RSDP))
return (const RSDP*)rsdp_new->data;
if (auto* rsdp_old = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_OLD_RSDP))
return (const RSDP*)rsdp_old->data;
#endif
// Look in main BIOS area below 1 MB
for (uintptr_t addr = P2V(0x000E0000); addr < P2V(0x000FFFFF); addr += 16)

View File

@ -1,135 +0,0 @@
#include <kernel/BootInfo.h>
#include <kernel/BananBootloader.h>
#include <kernel/multiboot2.h>
namespace Kernel
{
BootInfo g_boot_info;
void parse_boot_info_multiboot2(uint32_t info)
{
const auto& multiboot2_info = *reinterpret_cast<const multiboot2_info_t*>(info);
for (const auto* tag = multiboot2_info.tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next())
{
if (tag->type == MULTIBOOT2_TAG_CMDLINE)
{
const auto& command_line_tag = *reinterpret_cast<const multiboot2_cmdline_tag_t*>(tag);
MUST(g_boot_info.command_line.append(command_line_tag.cmdline));
}
else if (tag->type == MULTIBOOT2_TAG_FRAMEBUFFER)
{
const auto& framebuffer_tag = *reinterpret_cast<const multiboot2_framebuffer_tag_t*>(tag);
g_boot_info.framebuffer.address = framebuffer_tag.framebuffer_addr;
g_boot_info.framebuffer.pitch = framebuffer_tag.framebuffer_pitch;
g_boot_info.framebuffer.width = framebuffer_tag.framebuffer_width;
g_boot_info.framebuffer.height = framebuffer_tag.framebuffer_height;
g_boot_info.framebuffer.bpp = framebuffer_tag.framebuffer_bpp;
if (framebuffer_tag.framebuffer_type == MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
g_boot_info.framebuffer.type = FramebufferType::RGB;
else
g_boot_info.framebuffer.type = FramebufferType::UNKNOWN;
}
else if (tag->type == MULTIBOOT2_TAG_MMAP)
{
const auto& mmap_tag = *reinterpret_cast<const multiboot2_mmap_tag_t*>(tag);
const size_t entry_count = (mmap_tag.size - sizeof(multiboot2_mmap_tag_t)) / mmap_tag.entry_size;
MUST(g_boot_info.memory_map_entries.resize(entry_count));
for (size_t i = 0; i < entry_count; i++)
{
const auto& mmap_entry = *reinterpret_cast<const multiboot2_mmap_entry_t*>(reinterpret_cast<uintptr_t>(tag) + sizeof(multiboot2_mmap_tag_t) + i * mmap_tag.entry_size);
dprintln("entry {16H} {16H} {8H}",
(uint64_t)mmap_entry.base_addr,
(uint64_t)mmap_entry.length,
(uint64_t)mmap_entry.type
);
g_boot_info.memory_map_entries[i].address = mmap_entry.base_addr;
g_boot_info.memory_map_entries[i].length = mmap_entry.length;
g_boot_info.memory_map_entries[i].type = mmap_entry.type;
}
}
}
}
BAN::StringView get_early_boot_command_line_multiboot2(uint32_t info)
{
const auto& multiboot2_info = *reinterpret_cast<const multiboot2_info_t*>(info);
for (const auto* tag = multiboot2_info.tags; tag->type != MULTIBOOT2_TAG_END; tag = tag->next())
if (tag->type == MULTIBOOT2_TAG_CMDLINE)
return reinterpret_cast<const multiboot2_cmdline_tag_t*>(tag)->cmdline;
return {};
}
void parse_boot_info_banan_bootloader(uint32_t info)
{
const auto& banan_bootloader_info = *reinterpret_cast<const BananBootloaderInfo*>(info);
const char* command_line = reinterpret_cast<const char*>(banan_bootloader_info.command_line_addr);
MUST(g_boot_info.command_line.append(command_line));
const auto& framebuffer = *reinterpret_cast<BananBootFramebufferInfo*>(banan_bootloader_info.framebuffer_addr);
if (framebuffer.type == BANAN_BOOTLOADER_FB_RGB)
{
g_boot_info.framebuffer.address = framebuffer.address;
g_boot_info.framebuffer.width = framebuffer.width;
g_boot_info.framebuffer.height = framebuffer.height;
g_boot_info.framebuffer.pitch = framebuffer.pitch;
g_boot_info.framebuffer.bpp = framebuffer.bpp;
g_boot_info.framebuffer.type = FramebufferType::RGB;
}
const auto& memory_map = *reinterpret_cast<BananBootloaderMemoryMapInfo*>(banan_bootloader_info.memory_map_addr);
MUST(g_boot_info.memory_map_entries.resize(memory_map.entry_count));
for (size_t i = 0; i < memory_map.entry_count; i++)
{
const auto& mmap_entry = memory_map.entries[i];
g_boot_info.memory_map_entries[i].address = mmap_entry.address;
g_boot_info.memory_map_entries[i].length = mmap_entry.length;
g_boot_info.memory_map_entries[i].type = mmap_entry.type;
}
}
BAN::StringView get_early_boot_command_line_banan_bootloader(uint32_t info)
{
const auto& banan_bootloader_info = *reinterpret_cast<const BananBootloaderInfo*>(info);
return reinterpret_cast<const char*>(banan_bootloader_info.command_line_addr);
}
bool validate_boot_magic(uint32_t magic)
{
if (magic == MULTIBOOT2_MAGIC)
return true;
if (magic == BANAN_BOOTLOADER_MAGIC)
return true;
return false;
}
void parse_boot_info(uint32_t magic, uint32_t info)
{
switch (magic)
{
case MULTIBOOT2_MAGIC:
return parse_boot_info_multiboot2(info);
case BANAN_BOOTLOADER_MAGIC:
return parse_boot_info_banan_bootloader(info);
}
ASSERT_NOT_REACHED();
}
BAN::StringView get_early_boot_command_line(uint32_t magic, uint32_t info)
{
switch (magic)
{
case MULTIBOOT2_MAGIC:
return get_early_boot_command_line_multiboot2(info);
case BANAN_BOOTLOADER_MAGIC:
return get_early_boot_command_line_banan_bootloader(info);
}
ASSERT_NOT_REACHED();
}
}

View File

@ -56,7 +56,9 @@ namespace Kernel
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
const uint32_t divisor = (depth > 1) ? indices_per_block * (depth - 1) : 1;
uint32_t divisor = 1;
for (uint32_t i = 1; i < depth; i++)
divisor *= indices_per_block;
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block];
if (next_block == 0)

View File

@ -1,7 +1,7 @@
#include <kernel/BootInfo.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
extern uint8_t g_kernel_end[];
@ -26,33 +26,30 @@ namespace Kernel
void Heap::initialize_impl()
{
if (g_boot_info.memory_map_entries.empty())
auto* mmap_tag = (multiboot2_mmap_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_MMAP);
if (mmap_tag == nullptr)
Kernel::panic("Bootloader did not provide a memory map");
for (const auto& entry : g_boot_info.memory_map_entries)
for (size_t offset = sizeof(*mmap_tag); offset < mmap_tag->size; offset += mmap_tag->entry_size)
{
dprintln("{16H}, {16H}, {8H}",
entry.address,
entry.length,
entry.type
);
auto* mmap_entry = (multiboot2_mmap_entry_t*)((uintptr_t)mmap_tag + offset);
if (entry.type != 1)
continue;
if (mmap_entry->type == 1)
{
paddr_t start = mmap_entry->base_addr;
if (start < V2P(g_kernel_end))
start = V2P(g_kernel_end);
if (auto rem = start % PAGE_SIZE)
start += PAGE_SIZE - rem;
paddr_t start = entry.address;
if (start < V2P(g_kernel_end))
start = V2P(g_kernel_end);
if (auto rem = start % PAGE_SIZE)
start += PAGE_SIZE - rem;
paddr_t end = mmap_entry->base_addr + mmap_entry->length;
if (auto rem = end % PAGE_SIZE)
end -= rem;
paddr_t end = entry.address + entry.length;
if (auto rem = end % PAGE_SIZE)
end -= rem;
// Physical pages needs atleast 2 pages
if (end > start + PAGE_SIZE)
MUST(m_physical_ranges.emplace_back(start, end - start));
// Physical pages needs atleast 2 pages
if (end > start + PAGE_SIZE)
MUST(m_physical_ranges.emplace_back(start, end - start));
}
}
size_t total = 0;

View File

@ -57,11 +57,7 @@ namespace Kernel
auto& driver = s_serial_drivers[i];
driver.m_port = s_serial_ports[i];
if (!driver.initialize_size())
{
// if size detection fails, just use some random size
driver.m_width = 999;
driver.m_height = 999;
}
continue;
count++;
}
}

View File

@ -1,41 +1,42 @@
#include <BAN/Errors.h>
#include <kernel/BootInfo.h>
#include <kernel/Debug.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <kernel/Terminal/VesaTerminalDriver.h>
using namespace Kernel;
VesaTerminalDriver* VesaTerminalDriver::create()
{
if (g_boot_info.framebuffer.type == FramebufferType::NONE)
auto* framebuffer_tag = (multiboot2_framebuffer_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_FRAMEBUFFER);
if (framebuffer_tag == nullptr)
{
dprintln("Bootloader did not provide framebuffer");
return nullptr;
}
if (g_boot_info.framebuffer.type != FramebufferType::RGB)
if (framebuffer_tag->framebuffer_type != MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
{
dprintln("unsupported framebuffer type");
dprintln("unsupported framebuffer type {}", framebuffer_tag->framebuffer_type);
return nullptr;
}
if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32)
if (framebuffer_tag->framebuffer_bpp != 24 && framebuffer_tag->framebuffer_bpp != 32)
{
dprintln("Unsupported bpp {}", g_boot_info.framebuffer.bpp);
dprintln("Unsupported bpp {}", framebuffer_tag->framebuffer_bpp);
return nullptr;
}
dprintln("Graphics Mode {}x{} ({} bpp)",
g_boot_info.framebuffer.width,
g_boot_info.framebuffer.height,
g_boot_info.framebuffer.bpp
(uint32_t)framebuffer_tag->framebuffer_width,
(uint32_t)framebuffer_tag->framebuffer_height,
(uint8_t)framebuffer_tag->framebuffer_bpp
);
paddr_t paddr = g_boot_info.framebuffer.address & PAGE_ADDR_MASK;
paddr_t paddr = framebuffer_tag->framebuffer_addr & PAGE_ADDR_MASK;
size_t needed_pages = range_page_count(
g_boot_info.framebuffer.address,
g_boot_info.framebuffer.pitch * g_boot_info.framebuffer.height
framebuffer_tag->framebuffer_addr,
framebuffer_tag->framebuffer_pitch * framebuffer_tag->framebuffer_height
);
vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
@ -44,10 +45,10 @@ VesaTerminalDriver* VesaTerminalDriver::create()
PageTable::kernel().map_range_at(paddr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
auto* driver = new VesaTerminalDriver(
g_boot_info.framebuffer.width,
g_boot_info.framebuffer.height,
g_boot_info.framebuffer.pitch,
g_boot_info.framebuffer.bpp,
framebuffer_tag->framebuffer_width,
framebuffer_tag->framebuffer_height,
framebuffer_tag->framebuffer_pitch,
framebuffer_tag->framebuffer_bpp,
vaddr
);
driver->set_cursor_position(0, 0);

View File

@ -1,6 +1,5 @@
#include <kernel/ACPI.h>
#include <kernel/Arch.h>
#include <kernel/BootInfo.h>
#include <kernel/Debug.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/ProcFS/FileSystem.h>
@ -13,6 +12,7 @@
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/multiboot2.h>
#include <kernel/PCI.h>
#include <kernel/PIC.h>
#include <kernel/Process.h>
@ -31,9 +31,13 @@ struct ParsedCommandLine
BAN::StringView root;
};
static bool should_disable_serial(BAN::StringView full_command_line)
static bool should_disable_serial()
{
const char* start = full_command_line.data();
auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE);
if (cmdline_tag == nullptr)
return false;
const char* start = cmdline_tag->cmdline;
const char* current = start;
while (true)
{
@ -55,8 +59,13 @@ static ParsedCommandLine cmdline;
static void parse_command_line()
{
auto full_command_line = Kernel::g_boot_info.command_line.sv();
auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE);
if (cmdline_tag == nullptr)
return;
BAN::StringView full_command_line(cmdline_tag->cmdline);
auto arguments = MUST(full_command_line.split(' '));
for (auto argument : arguments)
{
if (argument == "noapic")
@ -74,31 +83,27 @@ TerminalDriver* g_terminal_driver = nullptr;
static void init2(void*);
extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
extern "C" void kernel_main()
{
using namespace Kernel;
DISABLE_INTERRUPTS();
if (!validate_boot_magic(boot_magic))
{
Serial::initialize();
dprintln("Unrecognized boot magic {8H}", boot_magic);
return;
}
if (!should_disable_serial(get_early_boot_command_line(boot_magic, boot_info)))
if (!should_disable_serial())
{
Serial::initialize();
dprintln("Serial output initialized");
}
if (g_multiboot2_magic != 0x36d76289)
{
dprintln("Invalid multiboot magic number");
return;
}
kmalloc_initialize();
dprintln("kmalloc initialized");
parse_boot_info(boot_magic, boot_info);
dprintln("boot info parsed");
GDT::initialize();
dprintln("GDT initialized");