Compare commits

...

3 Commits

11 changed files with 302 additions and 134 deletions

View File

@ -5,15 +5,26 @@
.set e_machine, 18
.set e_version, 20
.set e_entry, 24
.set e_phoff, 32
.set e_shoff, 40
.set e_flags, 48
.set e_ehsize, 52
.set e_phentsize, 54
.set e_phnum, 56
.set e_shentsize, 58
.set e_shnum, 60
.set e_shstrndx, 62
.set e32_phoff, 28
.set e32_shoff, 32
.set e32_flags, 36
.set e32_ehsize, 40
.set e32_phentsize, 42
.set e32_phnum, 44
.set e32_shentsize, 46
.set e32_shnum, 48
.set e32_shstrndx, 50
.set e64_phoff, 32
.set e64_shoff, 40
.set e64_flags, 48
.set e64_ehsize, 52
.set e64_phentsize, 54
.set e64_phnum, 56
.set e64_shentsize, 58
.set e64_shnum, 60
.set e64_shstrndx, 62
# e_ident offsets
.set EI_CLASS, 4
@ -22,6 +33,7 @@
# e_ident constants
.set ELFMAGIC, 0x464C457F
.set ELFCLASS32, 1
.set ELFCLASS64, 2
.set ELFDATA2LSB, 1
.set EV_CURRENT, 1
@ -31,18 +43,30 @@
# program header field offsets
.set p_type, 0
.set p_flags, 4
.set p_offset, 8
.set p_vaddr, 16
.set p_paddr, 24
.set p_filesz, 32
.set p_memsz, 40
.set p_align, 48
.set p32_offset, 4
.set p32_vaddr, 8
.set p32_paddr, 12
.set p32_filesz, 16
.set p32_memsz, 20
.set p32_flags, 24
.set p32_align, 28
.set p64_flags, 4
.set p64_offset, 8
.set p64_vaddr, 16
.set p64_paddr, 24
.set p64_filesz, 32
.set p64_memsz, 40
.set p64_align, 48
# p_type constants
.set PT_NULL, 0
.set PT_LOAD, 1
# mask for entry point and segment loading
.set LOAD_MASK, 0x07FFFFFF
.code16
.section .stage2
@ -52,8 +76,12 @@ elf_validate_file_header:
cmpl $ELFMAGIC, (elf_file_header)
jne .elf_validate_file_header_invalid_magic
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
je .elf_validate_file_header_class_valid
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
jne .elf_validate_file_header_only_64bit_supported
je .elf_validate_file_header_class_valid
jmp .elf_validate_file_header_invalid_class
.elf_validate_file_header_class_valid:
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
jne .elf_validate_file_header_only_little_endian_supported
@ -72,8 +100,8 @@ elf_validate_file_header:
.elf_validate_file_header_invalid_magic:
movw $elf_validate_file_header_invalid_magic_msg, %si
jmp print_and_halt
.elf_validate_file_header_only_64bit_supported:
movw $elf_validate_file_header_only_64bit_supported_msg, %si
.elf_validate_file_header_invalid_class:
movw $elf_validate_file_header_invalid_class_msg, %si
jmp print_and_halt
.elf_validate_file_header_only_little_endian_supported:
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
@ -86,6 +114,90 @@ elf_validate_file_header:
jmp print_and_halt
# sets memory to zero
# edi: start address
# ecx: byte count
# on return
# edi: start address + byte count
# ecx: 0
elf_memset_zero:
test %ecx, %ecx
jz .elf_memset_zero_done
.elf_memset_zero_loop:
movb $0, (%edi)
incl %edi
decl %ecx
jnz .elf_memset_zero_loop
.elf_memset_zero_done:
ret
# reads memory specified by 32 bit elf_program_header to memory
elf_read_program_header32_to_memory:
pushal
pushl %ebp
movl %esp, %ebp
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p32_filesz), %ebx
movl (elf_program_header + p32_vaddr), %edi
andl $LOAD_MASK, %edi
addl %ebx, %edi
movl (elf_program_header + p32_memsz), %ecx
subl %ebx, %ecx
movl %edi, %eax; call print_hex32; movb $',', %al; call putc; movb $' ', %al; call putc
movl %ecx, %eax; call print_hex32; movb $';', %al; call putc; movb $' ', %al; call putc
call elf_memset_zero
# read file specified in program header to memory
movl (elf_program_header + p32_offset), %eax
movl (elf_program_header + p32_vaddr), %edi
andl $LOAD_MASK, %edi
movl (elf_program_header + p32_filesz), %ecx
pushl %eax
movl %eax, %eax; call print_hex32; movb $',', %al; call putc; movb $' ', %al; call putc
movl %ecx, %eax; call print_hex32; movb $',', %al; call putc; movb $' ', %al; call putc
movl %edi, %eax; call print_hex32; call print_newline
popl %eax
call *%esi
movl $0x69696969, %eax; call print_hex32; call print_newline
leavel
popal
ret
# reads memory specified by 64 bit elf_program_header to memory
elf_read_program_header64_to_memory:
pushal
pushl %ebp
movl %esp, %ebp
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p64_filesz), %ebx
movl (elf_program_header + p64_vaddr), %edi
andl $LOAD_MASK, %edi
addl %ebx, %edi
movl (elf_program_header + p64_memsz), %ecx
subl %ebx, %ecx
call elf_memset_zero
# read file specified in program header to memory
movl (elf_program_header + p64_offset), %eax
movl (elf_program_header + p64_vaddr), %edi
andl $LOAD_MASK, %edi
movl (elf_program_header + p64_filesz), %ecx
call *%esi
leavel
popal
ret
# read callback format
# eax: first byte
# ecx: byte count
@ -104,42 +216,72 @@ elf_read_kernel_to_memory:
movl %esp, %ebp
subl $2, %esp
# read file header
# read start of file header
movl $0, %eax
movl $64, %ecx
movl $24, %ecx
movl $elf_file_header, %edi
call *%esi
call elf_validate_file_header
cmpl $0, (elf_file_header + e_phoff + 4)
# determine file header size
movl $52, %ecx
movl $64, %edx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %edx, %ecx
# read full file header
movl $0, %eax
movl $elf_file_header, %edi
call *%esi
# verify that e_phoff fits in 32 bits
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
jne .elf_read_kernel_to_memory_valid_offset
cmpl $0, (elf_file_header + e64_phoff + 4)
jnz .elf_read_kernel_to_memory_unsupported_offset
.elf_read_kernel_to_memory_valid_offset:
# read architecture phentsize and phnum to fixed locations
movw (elf_file_header + e32_phentsize), %ax
movw (elf_file_header + e32_phnum), %bx
movl (elf_file_header + e32_phoff), %ecx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovew (elf_file_header + e64_phentsize), %ax
cmovew (elf_file_header + e64_phnum), %bx
cmovel (elf_file_header + e64_phoff), %ecx
movw %ax, (elf_file_header_phentsize)
movw %bx, (elf_file_header_phnum)
movl %ecx, (elf_file_header_phoff)
# current program header
movw $0, -2(%ebp)
.elf_read_kernel_to_memory_loop_program_headers:
movw -2(%ebp), %cx
cmpw (elf_file_header + e_phnum), %cx
cmpw (elf_file_header_phnum), %cx
jae .elf_read_kernel_to_memory_done
# eax := program_header_index * e_phentsize + e_phoff
xorl %eax, %eax
movw %cx, %ax
xorl %ebx, %ebx
movw (elf_file_header + e_phentsize), %bx
movw (elf_file_header_phentsize), %bx
mull %ebx
addl (elf_file_header + e_phoff), %eax
addl (elf_file_header_phoff), %eax
jc .elf_read_kernel_to_memory_unsupported_offset
# setup program header size and address
movl $56, %ecx
movl $elf_program_header, %edi
# determine program header size
movl $32, %ecx
movl $56, %edx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %edx, %ecx
# read the program header
# read program header
movl $elf_program_header, %edi
call *%esi
# test if program header is empty
# test if program header is NULL header
cmpl $PT_NULL, (elf_program_header + p_type)
je .elf_read_kernel_to_memory_null_program_header
@ -147,33 +289,12 @@ elf_read_kernel_to_memory:
cmpl $PT_LOAD, (elf_program_header + p_type)
jne .elf_read_kernel_to_memory_not_loadable_header
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p_filesz), %ebx
movl (elf_program_header + p_vaddr), %edi
andl $0x7FFFFFFF, %edi
addl %ebx, %edi
movl (elf_program_header + p_memsz), %ecx
subl %ebx, %ecx
jz .elf_read_kernel_to_memory_memset_done
.elf_read_kernel_to_memory_memset:
movb $0, (%edi)
incl %edi
decl %ecx
jnz .elf_read_kernel_to_memory_memset
.elf_read_kernel_to_memory_memset_done:
# read file specified in program header to memory
movl (elf_program_header + p_offset), %eax
movl (elf_program_header + p_vaddr), %edi
andl $0x7FFFFFFF, %edi
movl (elf_program_header + p_filesz), %ecx
#call print_hex32; call print_newline
call *%esi
# read program header to memory
movl $elf_read_program_header32_to_memory, %eax
movl $elf_read_program_header64_to_memory, %ebx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %ebx, %eax
call *%eax
.elf_read_kernel_to_memory_null_program_header:
incw -2(%ebp)
@ -185,7 +306,7 @@ elf_read_kernel_to_memory:
# set kernel entry address
movl (elf_file_header + e_entry), %eax
andl $0x7FFFFF, %eax
andl $LOAD_MASK, %eax
ret
@ -200,8 +321,8 @@ elf_read_kernel_to_memory:
elf_validate_file_header_invalid_magic_msg:
.asciz "ELF: file has invalid ELF magic"
elf_validate_file_header_only_64bit_supported_msg:
.asciz "ELF: file is not targettint 64 bit"
elf_validate_file_header_invalid_class_msg:
.asciz "ELF: file has invalid ELF class"
elf_validate_file_header_only_little_endian_supported_msg:
.asciz "ELF: file is not in little endian format"
elf_validate_file_header_not_current_version_msg:
@ -219,5 +340,12 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
elf_file_header:
.skip 64
elf_file_header_phentsize:
.skip 2
elf_file_header_phnum:
.skip 2
elf_file_header_phoff:
.skip 4 # NOTE: only 32 bit offsets are supported
elf_program_header:
.skip 56

View File

@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.26)
project(x86_64-banan_os-bootloader-installer CXX)
if (NOT DEFINED ENV{BANAN_ARCH})
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
endif ()
set(BANAN_ARCH $ENV{BANAN_ARCH})
project(banan_os-bootloader-installer CXX)
set(SOURCES
crc32.cpp
@ -10,8 +15,8 @@ set(SOURCES
main.cpp
)
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
add_executable(banan_os-bootloader-installer ${SOURCES})
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)

View File

@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
#if ARCH(x86_64)
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
#elif ARCH(i386)
#elif ARCH(i686)
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
#endif
{

View File

@ -4,40 +4,31 @@ read_ip:
popl %eax
jmp *%eax
# void start_thread(uint32_t sp, uint32_t ip)
.global start_thread
start_thread:
movl 8(%esp), %edi # ip
movl 4(%esp), %esp # sp
# void start_kernel_thread()
.global start_kernel_thread
start_kernel_thread:
call get_start_kernel_thread_sp
movl %eax, %esp
# STACK LAYOUT
# NULL
# thread ptr
# &Thread::on_exit
# data
# on_exit arg
# on_exit func
# entry arg
# entry func
xorl %ebp, %ebp
movl 4(%esp), %edi
movl 0(%esp), %esi
subl $12, %esp
pushl %edi
sti
call *%edi
call *%esi
addl $16, %esp
movl 4(%esp), %edi # &Thread::on_exit
movl 12(%esp), %edi
movl 8(%esp), %esi
movl 8(%esp), %eax # thread ptr
movl %eax, (%esp)
call *%edi
# void continue_thread(uint32_t sp, uint32_t ip)
.global continue_thread
continue_thread:
movl 8(%esp), %edi # ip
movl 4(%esp), %esp # sp
xorl %eax, %eax
jmp *%edi
# void thread_userspace_trampoline(uint32_t sp, uint32_t ip, int argc, char** argv, char** envp)
.global thread_userspace_trampoline
thread_userspace_trampoline:
ud2
subl $12, %esp
pushl %edi
call *%esi
addl $16, %esp

View File

@ -26,17 +26,31 @@ isr_stub:
irq_stub:
pusha
leal 40(%esp), %eax // interrupt stack ptr
movl 32(%esp), %ebx // irq number
movl 32(%esp), %eax # interrupt number
subl $8, %esp
pushl %eax
call cpp_irq_handler
addl $12, %esp
popa
addl $8, %esp
iret
.global asm_reschedule_handler
asm_reschedule_handler:
pusha
movl %esp, %eax # interrupt registers ptr
leal 32(%esp), %ebx # interrupt stack ptr
subl $12, %esp
pushl %eax
pushl %ebx
call cpp_irq_handler
call cpp_reschedule_handler
addl $20, %esp
popa
addl $8, %esp
iret
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
@ -158,4 +172,3 @@ irq 28
irq 29
irq 30
irq 31
irq 32

View File

@ -4,9 +4,12 @@ read_ip:
popq %rax
jmp *%rax
# void start_thread()
# void start_kernel_thread()
.global start_kernel_thread
start_kernel_thread:
call get_start_kernel_thread_sp
movq %rax, %rsp
# STACK LAYOUT
# on_exit arg
# on_exit func
@ -15,6 +18,7 @@ start_kernel_thread:
movq 8(%rsp), %rdi
movq 0(%rsp), %rsi
sti
call *%rsi
movq 24(%rsp), %rdi

View File

@ -14,6 +14,7 @@ namespace Kernel
uintptr_t ss;
};
#if ARCH(x86_64)
struct InterruptRegisters
{
uintptr_t r15;
@ -33,5 +34,18 @@ namespace Kernel
uintptr_t rcx;
uintptr_t rax;
};
#elif ARCH(i686)
struct InterruptRegisters
{
uintptr_t edi;
uintptr_t esi;
uintptr_t ebp;
uintptr_t unused;
uintptr_t ebx;
uintptr_t edx;
uintptr_t ecx;
uintptr_t eax;
};
#endif
}

View File

@ -77,7 +77,6 @@ namespace Kernel
size_t virtual_page_count() const { return (m_kernel_stack->size() / PAGE_SIZE) + (m_userspace_stack->size() / PAGE_SIZE); }
size_t physical_page_count() const { return virtual_page_count(); }
uintptr_t& interrupt_sp() { return m_interrupt_sp; }
InterruptStack& interrupt_stack() { return m_interrupt_stack; }
InterruptRegisters& interrupt_registers() { return m_interrupt_registers; }
@ -89,6 +88,8 @@ namespace Kernel
private:
Thread(pid_t tid, Process*);
static void on_exit_trampoline(Thread*);
void on_exit();
private:
@ -104,7 +105,6 @@ namespace Kernel
InterruptStack m_interrupt_stack { };
InterruptRegisters m_interrupt_registers { };
uintptr_t m_interrupt_sp { };
uint64_t m_signal_pending_mask { 0 };
uint64_t m_signal_block_mask { 0 };

View File

@ -14,17 +14,6 @@ namespace Kernel
static Scheduler* s_instance = nullptr;
static BAN::Atomic<bool> s_started { false };
ALWAYS_INLINE static void load_temp_stack()
{
#if ARCH(x86_64)
asm volatile("movq %0, %%rsp" :: "rm"(Processor::current_stack_top()));
#elif ARCH(i686)
asm volatile("movl %0, %%esp" :: "rm"(Processor::current_stack_top()));
#else
#error
#endif
}
BAN::ErrorOr<void> Scheduler::initialize()
{
ASSERT(s_instance == nullptr);
@ -40,6 +29,11 @@ namespace Kernel
return *s_instance;
}
extern "C" uintptr_t get_start_kernel_thread_sp()
{
return Scheduler::get().current_thread().kernel_stack_top() - 4 * sizeof(uintptr_t);
}
void Scheduler::start()
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
@ -86,7 +80,6 @@ namespace Kernel
if (thread->state() != Thread::State::NotStarted)
{
thread->interrupt_stack() = Processor::get_interrupt_stack();
thread->interrupt_stack().sp = thread->interrupt_sp();
thread->interrupt_registers() = Processor::get_interrupt_registers();
}
@ -155,15 +148,29 @@ namespace Kernel
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
#if ARCH(x86_64)
asm volatile(
"movq %%rsp, %[save_sp];"
"movq %%rsp, %%rcx;"
"movq %[load_sp], %%rsp;"
"int %[ipi];"
: [save_sp]"=m"(Thread::current().interrupt_sp())
: [load_sp]"r"(Processor::current_stack_top()),
[ipi]"i"(IRQ_VECTOR_BASE + IRQ_IPI)
: "memory"
"movq %%rcx, %%rsp;"
:: [load_sp]"r"(Processor::current_stack_top()),
[ipi]"i"(IRQ_VECTOR_BASE + IRQ_IPI)
: "memory", "rcx"
);
#elif ARCH(i686)
asm volatile(
"movl %%esp, %%ecx;"
"movl %[load_sp], %%esp;"
"int %[ipi];"
"movl %%ecx, %%esp;"
:: [load_sp]"r"(Processor::current_stack_top()),
[ipi]"i"(IRQ_VECTOR_BASE + IRQ_IPI)
: "memory", "ecx"
);
#else
#error
#endif
Processor::set_interrupt_state(state);
}

View File

@ -12,19 +12,15 @@
namespace Kernel
{
extern "C" [[noreturn]] void start_userspace_thread();
extern "C" [[noreturn]] void start_kernel_thread();
extern "C" void signal_trampoline();
template<typename T>
static void write_to_stack(uintptr_t& rsp, const T& value)
static void write_to_stack(uintptr_t& rsp, const T& value) requires(sizeof(T) <= sizeof(uintptr_t))
{
rsp -= sizeof(uintptr_t);
if constexpr(sizeof(T) < sizeof(uintptr_t))
*(uintptr_t*)rsp = (uintptr_t)value;
else
memcpy((void*)rsp, (void*)&value, sizeof(uintptr_t));
*(uintptr_t*)rsp = (uintptr_t)value;
}
static pid_t s_next_tid = 1;
@ -50,13 +46,13 @@ namespace Kernel
// Initialize stack for returning
uintptr_t sp = thread->kernel_stack_top();
write_to_stack(sp, thread);
write_to_stack(sp, &Thread::on_exit);
write_to_stack(sp, &Thread::on_exit_trampoline);
write_to_stack(sp, data);
write_to_stack(sp, entry);
thread->m_interrupt_stack.ip = reinterpret_cast<vaddr_t>(start_kernel_thread);
thread->m_interrupt_stack.cs = 0x08;
thread->m_interrupt_stack.flags = 0x202;
thread->m_interrupt_stack.flags = 0x002;
thread->m_interrupt_stack.sp = sp;
thread->m_interrupt_stack.ss = 0x10;
@ -245,7 +241,7 @@ namespace Kernel
PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] {
uintptr_t sp = PageTable::fast_page() + PAGE_SIZE;
write_to_stack(sp, this);
write_to_stack(sp, &Thread::on_exit);
write_to_stack(sp, &Thread::on_exit_trampoline);
write_to_stack(sp, m_process);
write_to_stack(sp, entry);
});
@ -422,6 +418,11 @@ namespace Kernel
return {};
}
void Thread::on_exit_trampoline(Thread* thread)
{
thread->on_exit();
}
void Thread::on_exit()
{
ASSERT(this == &Thread::current());

View File

@ -2,6 +2,11 @@
set -e
if [[ -z $BANAN_ARCH ]]; then
echo "You must set the BANAN_ARCH environment variable" >&2
exit 1
fi
if [[ -z $BANAN_DISK_IMAGE_PATH ]]; then
echo "You must set the BANAN_DISK_IMAGE_PATH environment variable" >&2
exit 1
@ -26,7 +31,7 @@ ROOT_PARTITION_INDEX=2
ROOT_PARTITION_INFO=$(fdisk -x $BANAN_DISK_IMAGE_PATH | grep "^$BANAN_DISK_IMAGE_PATH" | head -$ROOT_PARTITION_INDEX | tail -1)
ROOT_PARTITION_GUID=$(echo $ROOT_PARTITION_INFO | cut -d' ' -f6)
INSTALLER_BUILD_DIR=$BANAN_ROOT_DIR/bootloader/installer/build
INSTALLER_BUILD_DIR=$BANAN_ROOT_DIR/bootloader/installer/build/$BANAN_ARCH
BOOTLOADER_ELF=$BANAN_BUILD_DIR/bootloader/bios/bootloader
if ! [ -f $BOOTLOADER_ELF ]; then
@ -37,11 +42,11 @@ fi
if ! [ -d $INSTALLER_BUILD_DIR ]; then
mkdir -p $INSTALLER_BUILD_DIR
cd $INSTALLER_BUILD_DIR
$CMAKE_COMMAND ..
$CMAKE_COMMAND ../..
fi
cd $INSTALLER_BUILD_DIR
make
echo installing bootloader
$INSTALLER_BUILD_DIR/x86_64-banan_os-bootloader-installer $BOOTLOADER_ELF $BANAN_DISK_IMAGE_PATH $ROOT_PARTITION_GUID
$INSTALLER_BUILD_DIR/banan_os-bootloader-installer $BOOTLOADER_ELF $BANAN_DISK_IMAGE_PATH $ROOT_PARTITION_GUID