Compare commits
14 Commits
a9412aa741
...
a312d75bb2
Author | SHA1 | Date |
---|---|---|
Bananymous | a312d75bb2 | |
Bananymous | a554bd0fd8 | |
Bananymous | f0d2a211ea | |
Bananymous | 065eec430e | |
Bananymous | 5f4d81a502 | |
Bananymous | 41065d2f9a | |
Bananymous | 3daf3d53a3 | |
Bananymous | ec56e9c6f1 | |
Bananymous | 07ae1bbf34 | |
Bananymous | 03b80ed113 | |
Bananymous | 407a7b80c5 | |
Bananymous | 8b4f169d0f | |
Bananymous | 6f9b3ab5de | |
Bananymous | aa7a8124ce |
|
@ -6,7 +6,9 @@ set(BOOTLOADER_SOURCES
|
||||||
boot.S
|
boot.S
|
||||||
command_line.S
|
command_line.S
|
||||||
disk.S
|
disk.S
|
||||||
|
elf.S
|
||||||
ext2.S
|
ext2.S
|
||||||
|
framebuffer.S
|
||||||
memory_map.S
|
memory_map.S
|
||||||
utils.S
|
utils.S
|
||||||
)
|
)
|
||||||
|
|
|
@ -53,9 +53,15 @@ stage2_main:
|
||||||
movw $hello_msg, %si
|
movw $hello_msg, %si
|
||||||
call puts; call print_newline
|
call puts; call print_newline
|
||||||
|
|
||||||
|
call enter_unreal_mode
|
||||||
|
movw $unreal_enter_msg, %si
|
||||||
|
call puts; call print_newline
|
||||||
|
|
||||||
call get_memory_map
|
call get_memory_map
|
||||||
call read_user_command_line
|
call read_user_command_line
|
||||||
|
|
||||||
|
call vesa_find_video_mode
|
||||||
|
|
||||||
call print_newline
|
call print_newline
|
||||||
|
|
||||||
movw $start_kernel_load_msg, %si
|
movw $start_kernel_load_msg, %si
|
||||||
|
@ -74,11 +80,91 @@ 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
hello_msg:
|
hello_msg:
|
||||||
.asciz "This is banan-os bootloader"
|
.asciz "This is banan-os bootloader"
|
||||||
|
|
||||||
|
unreal_enter_msg:
|
||||||
|
.asciz "Entered unreal mode"
|
||||||
|
|
||||||
start_kernel_load_msg:
|
start_kernel_load_msg:
|
||||||
.asciz "Starting to load kernel"
|
.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
|
||||||
|
|
|
@ -6,10 +6,20 @@
|
||||||
# NO REGISTERS SAVED
|
# NO REGISTERS SAVED
|
||||||
.global read_user_command_line
|
.global read_user_command_line
|
||||||
read_user_command_line:
|
read_user_command_line:
|
||||||
|
# print initial command line
|
||||||
movw $command_line_enter_msg, %si
|
movw $command_line_enter_msg, %si
|
||||||
call puts
|
call puts
|
||||||
|
movw $command_line_buffer, %si
|
||||||
|
call puts
|
||||||
|
|
||||||
|
# prepare registers for input
|
||||||
|
movw $command_line_enter_msg, %si
|
||||||
movw $command_line_buffer, %di
|
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:
|
.read_user_command_line_loop:
|
||||||
call getc
|
call getc
|
||||||
|
@ -23,9 +33,13 @@ read_user_command_line:
|
||||||
cmpb $'\n', %al
|
cmpb $'\n', %al
|
||||||
je .read_user_command_line_done
|
je .read_user_command_line_done
|
||||||
|
|
||||||
|
pushw %ax
|
||||||
|
|
||||||
call isprint
|
call isprint
|
||||||
testb %al, %al
|
testb %al, %al
|
||||||
jnz .read_user_command_line_loop
|
jz .read_user_command_line_loop
|
||||||
|
|
||||||
|
popw %ax
|
||||||
|
|
||||||
# put byte to buffer
|
# put byte to buffer
|
||||||
movb %al, (%di)
|
movb %al, (%di)
|
||||||
|
@ -61,9 +75,9 @@ read_user_command_line:
|
||||||
command_line_enter_msg:
|
command_line_enter_msg:
|
||||||
.asciz "cmdline: "
|
.asciz "cmdline: "
|
||||||
|
|
||||||
|
.global command_line
|
||||||
.section .bss
|
command_line:
|
||||||
|
|
||||||
# 100 character command line
|
# 100 character command line
|
||||||
command_line_buffer:
|
command_line_buffer:
|
||||||
.skip 100
|
.ascii "root=/dev/sda2"
|
||||||
|
.skip 100 - 28
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
.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
|
|
@ -232,8 +232,8 @@ ext2_read_inode:
|
||||||
addl $ext2_block_buffer, %esi
|
addl $ext2_block_buffer, %esi
|
||||||
# edi := ext2_inode_buffer
|
# edi := ext2_inode_buffer
|
||||||
movl $ext2_inode_buffer, %edi
|
movl $ext2_inode_buffer, %edi
|
||||||
# cx := inode_size
|
# ecx := inode_size
|
||||||
movw (ext2_inode_size), %cx
|
movl (ext2_inode_size), %ecx
|
||||||
rep movsb
|
rep movsb
|
||||||
|
|
||||||
popal
|
popal
|
||||||
|
@ -245,7 +245,10 @@ ext2_read_inode:
|
||||||
# return:
|
# return:
|
||||||
# eax: block index
|
# eax: block index
|
||||||
ext2_data_block_index:
|
ext2_data_block_index:
|
||||||
|
pushl %ebx
|
||||||
pushl %ecx
|
pushl %ecx
|
||||||
|
pushl %edx
|
||||||
|
pushl %esi
|
||||||
|
|
||||||
# calculate max data blocks
|
# calculate max data blocks
|
||||||
movl (ext2_inode_buffer + i_size), %ecx
|
movl (ext2_inode_buffer + i_size), %ecx
|
||||||
|
@ -260,13 +263,87 @@ ext2_data_block_index:
|
||||||
# check if this is direct block access
|
# check if this is direct block access
|
||||||
cmpl $12, %eax
|
cmpl $12, %eax
|
||||||
jb .ext2_data_block_index_direct
|
jb .ext2_data_block_index_direct
|
||||||
|
subl $12, %eax
|
||||||
|
|
||||||
jmp .ext2_data_block_index_unsupported
|
# 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
|
||||||
|
|
||||||
.ext2_data_block_index_direct:
|
.ext2_data_block_index_direct:
|
||||||
movl $(ext2_inode_buffer + i_block), %ecx
|
movl $(ext2_inode_buffer + i_block), %esi
|
||||||
addl %eax, %ecx
|
movl (%esi, %eax, 4), %eax
|
||||||
movl (%ecx), %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
|
||||||
|
|
||||||
jmp .ext2_data_block_index_done
|
jmp .ext2_data_block_index_done
|
||||||
|
|
||||||
.ext2_data_block_index_out_of_bounds:
|
.ext2_data_block_index_out_of_bounds:
|
||||||
|
@ -275,14 +352,112 @@ ext2_data_block_index:
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
jmp .ext2_data_block_index_done
|
jmp .ext2_data_block_index_done
|
||||||
|
|
||||||
.ext2_data_block_index_unsupported:
|
.ext2_data_block_index_invalid:
|
||||||
movw $ext2_data_block_index_unsupported_msg, %si
|
movw $ext2_data_block_index_invalid_msg, %si
|
||||||
call puts; call print_newline
|
call puts; call print_newline
|
||||||
movl $0, %eax
|
movl $0, %eax
|
||||||
jmp .ext2_data_block_index_done
|
jmp .ext2_data_block_index_done
|
||||||
|
|
||||||
.ext2_data_block_index_done:
|
.ext2_data_block_index_done:
|
||||||
|
popl %esi
|
||||||
|
popl %edx
|
||||||
popl %ecx
|
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
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -393,8 +568,14 @@ ext2_directory_find_inode:
|
||||||
|
|
||||||
|
|
||||||
# search for kernel file from filesystem
|
# search for kernel file from filesystem
|
||||||
|
# returns only on success
|
||||||
.global ext2_find_kernel
|
.global ext2_find_kernel
|
||||||
ext2_find_kernel:
|
ext2_find_kernel:
|
||||||
|
pushl %eax
|
||||||
|
pushw %cx
|
||||||
|
pushw %di
|
||||||
|
pushw %si
|
||||||
|
|
||||||
movl $EXT2_ROOT_INO, %eax
|
movl $EXT2_ROOT_INO, %eax
|
||||||
call ext2_read_inode
|
call ext2_read_inode
|
||||||
|
|
||||||
|
@ -443,8 +624,10 @@ ext2_find_kernel:
|
||||||
movw $ext2_kernel_found_msg, %si
|
movw $ext2_kernel_found_msg, %si
|
||||||
call puts; call print_newline
|
call puts; call print_newline
|
||||||
|
|
||||||
1: jmp 1b
|
popw %si
|
||||||
|
popw %di
|
||||||
|
popw %cx
|
||||||
|
popl %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.ext2_find_kernel_part_not_dir:
|
.ext2_find_kernel_part_not_dir:
|
||||||
|
@ -490,8 +673,8 @@ ext2_kernel_found_msg:
|
||||||
|
|
||||||
ext2_data_block_index_out_of_bounds_msg:
|
ext2_data_block_index_out_of_bounds_msg:
|
||||||
.asciz "data block index out of bounds"
|
.asciz "data block index out of bounds"
|
||||||
ext2_data_block_index_unsupported_msg:
|
ext2_data_block_index_invalid_msg:
|
||||||
.asciz "unsupported data block index"
|
.asciz "data block index is invalid"
|
||||||
|
|
||||||
ext2_looking_for_msg:
|
ext2_looking_for_msg:
|
||||||
.asciz "looking for "
|
.asciz "looking for "
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
.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
|
|
@ -122,6 +122,8 @@ memory_map_error_msg:
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
|
.global memory_map
|
||||||
|
memory_map:
|
||||||
memory_map_entry_count:
|
memory_map_entry_count:
|
||||||
.skip 4
|
.skip 4
|
||||||
# 100 entries should be enough...
|
# 100 entries should be enough...
|
||||||
|
|
|
@ -196,6 +196,68 @@ print_number:
|
||||||
popa
|
popa
|
||||||
ret
|
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
|
# test if character is printable ascii
|
||||||
# al: character to test
|
# al: character to test
|
||||||
# return:
|
# return:
|
||||||
|
|
|
@ -12,6 +12,7 @@ set(KERNEL_SOURCES
|
||||||
font/prefs.psf.o
|
font/prefs.psf.o
|
||||||
kernel/ACPI.cpp
|
kernel/ACPI.cpp
|
||||||
kernel/APIC.cpp
|
kernel/APIC.cpp
|
||||||
|
kernel/BootInfo.cpp
|
||||||
kernel/CPUID.cpp
|
kernel/CPUID.cpp
|
||||||
kernel/Debug.cpp
|
kernel/Debug.cpp
|
||||||
kernel/Device/Device.cpp
|
kernel/Device/Device.cpp
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <kernel/LockGuard.h>
|
#include <kernel/LockGuard.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/multiboot2.h>
|
|
||||||
|
|
||||||
extern uint8_t g_kernel_start[];
|
extern uint8_t g_kernel_start[];
|
||||||
extern uint8_t g_kernel_end[];
|
extern uint8_t g_kernel_end[];
|
||||||
|
@ -145,6 +144,14 @@ namespace Kernel
|
||||||
|
|
||||||
prepare_fast_page();
|
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)
|
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
|
||||||
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
|
||||||
map_range_at(
|
map_range_at(
|
||||||
|
@ -169,22 +176,6 @@ namespace Kernel
|
||||||
g_userspace_end - g_userspace_start,
|
g_userspace_end - g_userspace_start,
|
||||||
Flags::Execute | Flags::UserSupervisor | Flags::Present
|
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()
|
void PageTable::prepare_fast_page()
|
||||||
|
@ -371,7 +362,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
if (vaddr >= KERNEL_OFFSET)
|
if (vaddr >= KERNEL_OFFSET && s_current)
|
||||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||||
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
|
||||||
|
|
|
@ -21,8 +21,8 @@ multiboot2_start:
|
||||||
.short 5
|
.short 5
|
||||||
.short 0
|
.short 0
|
||||||
.long 20
|
.long 20
|
||||||
.long 1920
|
.long 800
|
||||||
.long 1080
|
.long 600
|
||||||
.long 32
|
.long 32
|
||||||
|
|
||||||
# legacy start
|
# legacy start
|
||||||
|
@ -50,11 +50,9 @@ multiboot2_end:
|
||||||
g_kernel_cmdline:
|
g_kernel_cmdline:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
|
|
||||||
.global g_multiboot2_info
|
bootloader_magic:
|
||||||
g_multiboot2_info:
|
|
||||||
.skip 8
|
.skip 8
|
||||||
.global g_multiboot2_magic
|
bootloader_info:
|
||||||
g_multiboot2_magic:
|
|
||||||
.skip 8
|
.skip 8
|
||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
@ -167,8 +165,8 @@ initialize_paging:
|
||||||
_start:
|
_start:
|
||||||
# Initialize stack and multiboot info
|
# Initialize stack and multiboot info
|
||||||
movl $V2P(g_boot_stack_top), %esp
|
movl $V2P(g_boot_stack_top), %esp
|
||||||
movl %eax, V2P(g_multiboot2_magic)
|
movl %eax, V2P(bootloader_magic)
|
||||||
movl %ebx, V2P(g_multiboot2_info)
|
movl %ebx, V2P(bootloader_info)
|
||||||
|
|
||||||
call check_requirements
|
call check_requirements
|
||||||
call enable_sse
|
call enable_sse
|
||||||
|
@ -200,8 +198,11 @@ higher_half:
|
||||||
# call global constuctors
|
# call global constuctors
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
# call to the kernel itself (clear ebp for stacktrace)
|
# call to the kernel itself (clear rbp for stacktrace)
|
||||||
xorq %rbp, %rbp
|
xorq %rbp, %rbp
|
||||||
|
|
||||||
|
movl V2P(bootloader_magic), %edi
|
||||||
|
movl V2P(bootloader_info), %esi
|
||||||
call kernel_main
|
call kernel_main
|
||||||
|
|
||||||
# call global destructors
|
# call global destructors
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#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));
|
|
@ -0,0 +1,47 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
}
|
|
@ -13,11 +13,18 @@
|
||||||
|
|
||||||
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
#define MULTIBOOT2_FRAMEBUFFER_TYPE_RGB 1
|
||||||
|
|
||||||
|
#define MULTIBOOT2_MAGIC 0x36d76289
|
||||||
|
|
||||||
struct multiboot2_tag_t
|
struct multiboot2_tag_t
|
||||||
{
|
{
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
multiboot2_tag_t* next() { return (multiboot2_tag_t*)((uintptr_t)this + ((size + 7) & ~7)); }
|
const multiboot2_tag_t* next() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const multiboot2_tag_t*>(
|
||||||
|
reinterpret_cast<uintptr_t>(this) + ((size + 7) & ~7)
|
||||||
|
);
|
||||||
|
}
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct multiboot2_cmdline_tag_t : public multiboot2_tag_t
|
struct multiboot2_cmdline_tag_t : public multiboot2_tag_t
|
||||||
|
@ -62,14 +69,3 @@ struct multiboot2_info_t
|
||||||
uint32_t reserved;
|
uint32_t reserved;
|
||||||
multiboot2_tag_t tags[];
|
multiboot2_tag_t tags[];
|
||||||
} __attribute__((packed));
|
} __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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <BAN/StringView.h>
|
#include <BAN/StringView.h>
|
||||||
#include <kernel/ACPI.h>
|
#include <kernel/ACPI.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/multiboot2.h>
|
|
||||||
|
|
||||||
#include <lai/core.h>
|
#include <lai/core.h>
|
||||||
|
|
||||||
|
@ -85,11 +84,14 @@ namespace Kernel
|
||||||
|
|
||||||
static const RSDP* locate_rsdp()
|
static const RSDP* locate_rsdp()
|
||||||
{
|
{
|
||||||
|
// FIXME: add this back
|
||||||
|
#if 0
|
||||||
// Check the multiboot headers
|
// Check the multiboot headers
|
||||||
if (auto* rsdp_new = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_NEW_RSDP))
|
if (auto* rsdp_new = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_NEW_RSDP))
|
||||||
return (const RSDP*)rsdp_new->data;
|
return (const RSDP*)rsdp_new->data;
|
||||||
if (auto* rsdp_old = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_OLD_RSDP))
|
if (auto* rsdp_old = (multiboot2_rsdp_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_OLD_RSDP))
|
||||||
return (const RSDP*)rsdp_old->data;
|
return (const RSDP*)rsdp_old->data;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Look in main BIOS area below 1 MB
|
// Look in main BIOS area below 1 MB
|
||||||
for (uintptr_t addr = P2V(0x000E0000); addr < P2V(0x000FFFFF); addr += 16)
|
for (uintptr_t addr = P2V(0x000E0000); addr < P2V(0x000FFFFF); addr += 16)
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -56,9 +56,7 @@ namespace Kernel
|
||||||
|
|
||||||
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
|
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
|
||||||
|
|
||||||
uint32_t divisor = 1;
|
const uint32_t divisor = (depth > 1) ? indices_per_block * (depth - 1) : 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];
|
const uint32_t next_block = block_buffer.span().as_span<uint32_t>()[(index / divisor) % indices_per_block];
|
||||||
if (next_block == 0)
|
if (next_block == 0)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/LockGuard.h>
|
#include <kernel/LockGuard.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/multiboot2.h>
|
|
||||||
|
|
||||||
extern uint8_t g_kernel_end[];
|
extern uint8_t g_kernel_end[];
|
||||||
|
|
||||||
|
@ -26,23 +26,27 @@ namespace Kernel
|
||||||
|
|
||||||
void Heap::initialize_impl()
|
void Heap::initialize_impl()
|
||||||
{
|
{
|
||||||
auto* mmap_tag = (multiboot2_mmap_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_MMAP);
|
if (g_boot_info.memory_map_entries.empty())
|
||||||
if (mmap_tag == nullptr)
|
|
||||||
Kernel::panic("Bootloader did not provide a memory map");
|
Kernel::panic("Bootloader did not provide a memory map");
|
||||||
|
|
||||||
for (size_t offset = sizeof(*mmap_tag); offset < mmap_tag->size; offset += mmap_tag->entry_size)
|
for (const auto& entry : g_boot_info.memory_map_entries)
|
||||||
{
|
{
|
||||||
auto* mmap_entry = (multiboot2_mmap_entry_t*)((uintptr_t)mmap_tag + offset);
|
dprintln("{16H}, {16H}, {8H}",
|
||||||
|
entry.address,
|
||||||
|
entry.length,
|
||||||
|
entry.type
|
||||||
|
);
|
||||||
|
|
||||||
if (mmap_entry->type == 1)
|
if (entry.type != 1)
|
||||||
{
|
continue;
|
||||||
paddr_t start = mmap_entry->base_addr;
|
|
||||||
|
paddr_t start = entry.address;
|
||||||
if (start < V2P(g_kernel_end))
|
if (start < V2P(g_kernel_end))
|
||||||
start = V2P(g_kernel_end);
|
start = V2P(g_kernel_end);
|
||||||
if (auto rem = start % PAGE_SIZE)
|
if (auto rem = start % PAGE_SIZE)
|
||||||
start += PAGE_SIZE - rem;
|
start += PAGE_SIZE - rem;
|
||||||
|
|
||||||
paddr_t end = mmap_entry->base_addr + mmap_entry->length;
|
paddr_t end = entry.address + entry.length;
|
||||||
if (auto rem = end % PAGE_SIZE)
|
if (auto rem = end % PAGE_SIZE)
|
||||||
end -= rem;
|
end -= rem;
|
||||||
|
|
||||||
|
@ -50,7 +54,6 @@ namespace Kernel
|
||||||
if (end > start + PAGE_SIZE)
|
if (end > start + PAGE_SIZE)
|
||||||
MUST(m_physical_ranges.emplace_back(start, end - start));
|
MUST(m_physical_ranges.emplace_back(start, end - start));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
for (auto& range : m_physical_ranges)
|
for (auto& range : m_physical_ranges)
|
||||||
|
|
|
@ -57,7 +57,11 @@ namespace Kernel
|
||||||
auto& driver = s_serial_drivers[i];
|
auto& driver = s_serial_drivers[i];
|
||||||
driver.m_port = s_serial_ports[i];
|
driver.m_port = s_serial_ports[i];
|
||||||
if (!driver.initialize_size())
|
if (!driver.initialize_size())
|
||||||
continue;
|
{
|
||||||
|
// if size detection fails, just use some random size
|
||||||
|
driver.m_width = 999;
|
||||||
|
driver.m_height = 999;
|
||||||
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,41 @@
|
||||||
#include <BAN/Errors.h>
|
#include <BAN/Errors.h>
|
||||||
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/Debug.h>
|
#include <kernel/Debug.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/multiboot2.h>
|
|
||||||
#include <kernel/Terminal/VesaTerminalDriver.h>
|
#include <kernel/Terminal/VesaTerminalDriver.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
VesaTerminalDriver* VesaTerminalDriver::create()
|
VesaTerminalDriver* VesaTerminalDriver::create()
|
||||||
{
|
{
|
||||||
auto* framebuffer_tag = (multiboot2_framebuffer_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_FRAMEBUFFER);
|
if (g_boot_info.framebuffer.type == FramebufferType::NONE)
|
||||||
if (framebuffer_tag == nullptr)
|
|
||||||
{
|
{
|
||||||
dprintln("Bootloader did not provide framebuffer");
|
dprintln("Bootloader did not provide framebuffer");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framebuffer_tag->framebuffer_type != MULTIBOOT2_FRAMEBUFFER_TYPE_RGB)
|
if (g_boot_info.framebuffer.type != FramebufferType::RGB)
|
||||||
{
|
{
|
||||||
dprintln("unsupported framebuffer type {}", framebuffer_tag->framebuffer_type);
|
dprintln("unsupported framebuffer type");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (framebuffer_tag->framebuffer_bpp != 24 && framebuffer_tag->framebuffer_bpp != 32)
|
if (g_boot_info.framebuffer.bpp != 24 && g_boot_info.framebuffer.bpp != 32)
|
||||||
{
|
{
|
||||||
dprintln("Unsupported bpp {}", framebuffer_tag->framebuffer_bpp);
|
dprintln("Unsupported bpp {}", g_boot_info.framebuffer.bpp);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
dprintln("Graphics Mode {}x{} ({} bpp)",
|
dprintln("Graphics Mode {}x{} ({} bpp)",
|
||||||
(uint32_t)framebuffer_tag->framebuffer_width,
|
g_boot_info.framebuffer.width,
|
||||||
(uint32_t)framebuffer_tag->framebuffer_height,
|
g_boot_info.framebuffer.height,
|
||||||
(uint8_t)framebuffer_tag->framebuffer_bpp
|
g_boot_info.framebuffer.bpp
|
||||||
);
|
);
|
||||||
|
|
||||||
paddr_t paddr = framebuffer_tag->framebuffer_addr & PAGE_ADDR_MASK;
|
paddr_t paddr = g_boot_info.framebuffer.address & PAGE_ADDR_MASK;
|
||||||
size_t needed_pages = range_page_count(
|
size_t needed_pages = range_page_count(
|
||||||
framebuffer_tag->framebuffer_addr,
|
g_boot_info.framebuffer.address,
|
||||||
framebuffer_tag->framebuffer_pitch * framebuffer_tag->framebuffer_height
|
g_boot_info.framebuffer.pitch * g_boot_info.framebuffer.height
|
||||||
);
|
);
|
||||||
|
|
||||||
vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
vaddr_t vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
||||||
|
@ -45,10 +44,10 @@ VesaTerminalDriver* VesaTerminalDriver::create()
|
||||||
PageTable::kernel().map_range_at(paddr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
PageTable::kernel().map_range_at(paddr, vaddr, needed_pages * PAGE_SIZE, PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
||||||
|
|
||||||
auto* driver = new VesaTerminalDriver(
|
auto* driver = new VesaTerminalDriver(
|
||||||
framebuffer_tag->framebuffer_width,
|
g_boot_info.framebuffer.width,
|
||||||
framebuffer_tag->framebuffer_height,
|
g_boot_info.framebuffer.height,
|
||||||
framebuffer_tag->framebuffer_pitch,
|
g_boot_info.framebuffer.pitch,
|
||||||
framebuffer_tag->framebuffer_bpp,
|
g_boot_info.framebuffer.bpp,
|
||||||
vaddr
|
vaddr
|
||||||
);
|
);
|
||||||
driver->set_cursor_position(0, 0);
|
driver->set_cursor_position(0, 0);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <kernel/ACPI.h>
|
#include <kernel/ACPI.h>
|
||||||
#include <kernel/Arch.h>
|
#include <kernel/Arch.h>
|
||||||
|
#include <kernel/BootInfo.h>
|
||||||
#include <kernel/Debug.h>
|
#include <kernel/Debug.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/FS/ProcFS/FileSystem.h>
|
#include <kernel/FS/ProcFS/FileSystem.h>
|
||||||
|
@ -12,7 +13,6 @@
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
#include <kernel/Memory/kmalloc.h>
|
#include <kernel/Memory/kmalloc.h>
|
||||||
#include <kernel/Memory/PageTable.h>
|
#include <kernel/Memory/PageTable.h>
|
||||||
#include <kernel/multiboot2.h>
|
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
#include <kernel/PIC.h>
|
#include <kernel/PIC.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
|
@ -31,13 +31,9 @@ struct ParsedCommandLine
|
||||||
BAN::StringView root;
|
BAN::StringView root;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool should_disable_serial()
|
static bool should_disable_serial(BAN::StringView full_command_line)
|
||||||
{
|
{
|
||||||
auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE);
|
const char* start = full_command_line.data();
|
||||||
if (cmdline_tag == nullptr)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const char* start = cmdline_tag->cmdline;
|
|
||||||
const char* current = start;
|
const char* current = start;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -59,13 +55,8 @@ static ParsedCommandLine cmdline;
|
||||||
|
|
||||||
static void parse_command_line()
|
static void parse_command_line()
|
||||||
{
|
{
|
||||||
auto* cmdline_tag = (multiboot2_cmdline_tag_t*)multiboot2_find_tag(MULTIBOOT2_TAG_CMDLINE);
|
auto full_command_line = Kernel::g_boot_info.command_line.sv();
|
||||||
if (cmdline_tag == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BAN::StringView full_command_line(cmdline_tag->cmdline);
|
|
||||||
auto arguments = MUST(full_command_line.split(' '));
|
auto arguments = MUST(full_command_line.split(' '));
|
||||||
|
|
||||||
for (auto argument : arguments)
|
for (auto argument : arguments)
|
||||||
{
|
{
|
||||||
if (argument == "noapic")
|
if (argument == "noapic")
|
||||||
|
@ -83,27 +74,31 @@ TerminalDriver* g_terminal_driver = nullptr;
|
||||||
|
|
||||||
static void init2(void*);
|
static void init2(void*);
|
||||||
|
|
||||||
extern "C" void kernel_main()
|
extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
|
||||||
{
|
{
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
DISABLE_INTERRUPTS();
|
DISABLE_INTERRUPTS();
|
||||||
|
|
||||||
if (!should_disable_serial())
|
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)))
|
||||||
{
|
{
|
||||||
Serial::initialize();
|
Serial::initialize();
|
||||||
dprintln("Serial output initialized");
|
dprintln("Serial output initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_multiboot2_magic != 0x36d76289)
|
|
||||||
{
|
|
||||||
dprintln("Invalid multiboot magic number");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
kmalloc_initialize();
|
kmalloc_initialize();
|
||||||
dprintln("kmalloc initialized");
|
dprintln("kmalloc initialized");
|
||||||
|
|
||||||
|
parse_boot_info(boot_magic, boot_info);
|
||||||
|
dprintln("boot info parsed");
|
||||||
|
|
||||||
GDT::initialize();
|
GDT::initialize();
|
||||||
dprintln("GDT initialized");
|
dprintln("GDT initialized");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue