From ec572bff8150e2f8cd2dc99e053c5e8c8a0b99e3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 16:25:00 +0000 Subject: arch: prepare interfaces --- arch/x86_64/src/boot/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 7932045..5488073 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -364,5 +364,5 @@ _transition_to_long_mode: call _init - call kernel_main + call main call halt -- cgit v1.2.3 From 05ac8c2bdd000d27b38411db2223eabb649c318f Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 14 Jul 2025 21:29:10 +0000 Subject: build: reintroduce bootable ISO --- arch/x86_64/src/boot/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 5488073..728380d 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -105,7 +105,7 @@ mesage_long_mode_not_supported: * We need a pointer to our current position in the VGA text buffer. */ .global vga_buffer_pointer -vga_buffer_pointer: .long 0xb8000 +vga_buffer_pointer: .quad 0xb8000 /** * Code for the bootstrapping process. -- cgit v1.2.3 From a832505d9696ae66248b53602d41637bef4868aa Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 10:49:03 +0000 Subject: kernel: turn into a PIE --- arch/x86_64/src/boot/boot.s | 112 ++++++++++++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 30 deletions(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 728380d..ada6426 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -71,16 +71,7 @@ stack_top: global_descriptor_table: .quad 0 global_descriptor_table_code = . - global_descriptor_table .quad (1<<43) | (1<<44) | (1<<47) | (1<<53) - -/** - * We also need a pointer that we can load into the GDTR. - * - * The pointer consists of a word describing the size of the table minus 1 and - * the pointer to the actual table. - */ -global_descriptor_table_pointer: -.word . - global_descriptor_table - 1 -.quad global_descriptor_table +global_descriptor_table_end: /** * We are going to print some messages in case we panic during boot, so we are @@ -130,7 +121,12 @@ _panic: push %ebp mov %esp, %ebp - push message_prefix_panic + call .Lpanic_get_ip +.Lpanic_get_ip: + pop %eax + lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + + push %eax push $0x4f call _print add $8, %esp @@ -155,10 +151,17 @@ _print: push %ebx push %esi + push %edi + + call .Lprint_get_ip +.Lprint_get_ip: + pop %edi + lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi + mov 8(%ebp), %eax mov 12(%ebp), %ebx mov $0, %ecx - mov (vga_buffer_pointer), %esi + mov (%edi), %esi .Lprint_loop: mov (%ebx, %ecx), %dl @@ -171,9 +174,11 @@ _print: .Lupdate_vga_buffer_address: shl $1, %ecx - add %ecx, (vga_buffer_pointer) + add %ecx, %esi + mov %esi, (%edi) .Lprint_end: + pop %edi pop %esi pop %ebx mov %ebp, %esp @@ -187,7 +192,12 @@ _print: */ .global _start _start: - mov $stack_top, %esp + call .Lstart_get_ip +.Lstart_get_ip: + pop %esi + lea (stack_top - .Lstart_get_ip)(%esi), %ebx + + mov %ebx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader @@ -197,8 +207,19 @@ _start: call enable_paging call enable_sse - lgdt (global_descriptor_table_pointer) - jmp $global_descriptor_table_code, $_transition_to_long_mode + sub $10, %esp + lea (global_descriptor_table - .Lstart_get_ip)(%esi), %eax + movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) + mov %eax, 2(%esp) + movl $0, 6(%esp) + + lgdt (%esp) + add $10, %esp + + lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax + pushl $global_descriptor_table_code + pushl %eax + lret call halt @@ -217,7 +238,11 @@ assert_cpu_supports_long_mode: jz .Llong_mode_assertion_failed ret .Llong_mode_assertion_failed: - push $mesage_long_mode_not_supported + call .Lassert_cpu_supports_long_mode_fail_get_ip +.Lassert_cpu_supports_long_mode_fail_get_ip: + pop %eax + lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -245,7 +270,11 @@ assert_cpuid_instruction_is_supported: je .Lcpuid_assertion_fail ret .Lcpuid_assertion_fail: - push $message_cpuid_instruction_no_supported + call .Lassert_cpuid_instruction_is_supported_fail_get_ip +.Lassert_cpuid_instruction_is_supported_fail_get_ip: + pop %eax + lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -259,10 +288,18 @@ assert_loaded_by_multiboot2_loader: cmp $0x36d76289, %eax /* Check if we received the expected magic */ jne .Lmultiboot2_assertion_fail /* Panic otherwise */ - mov %ebx, multiboot_information_pointer /* Store the MBI pointer */ + call .Lassert_loaded_by_multiboot2_loader_get_ip +.Lassert_loaded_by_multiboot2_loader_get_ip: + pop %eax + lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax + mov %ebx, (%eax) /* Store the MBI pointer */ ret .Lmultiboot2_assertion_fail: - push $message_not_loaded_by_multiboot2 + call .Lassert_loaded_by_multiboot2_loader_fail_get_ip +.Lassert_loaded_by_multiboot2_loader_fail_get_ip: + pop %eax + lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax + push %eax call _panic /** @@ -272,7 +309,10 @@ assert_loaded_by_multiboot2_loader: * set up for use. */ enable_paging: - mov $page_map_level_4, %eax + call .Lenable_paging_get_ip +.Lenable_paging_get_ip: + pop %eax +lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -316,37 +356,46 @@ enable_sse: * page map entries. */ prepare_page_maps: + call .Lprepare_page_maps_get_ip +.Lprepare_page_maps_get_ip: + pop %edi /* Map the P4 table recursively */ - mov $page_map_level_4, %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax + mov %eax, %ebx or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (page_map_level_4 + 511 * 8) + mov %eax, (511 * 8)(%ebx) /* Add an entry to the PML4, pointing to the PML3 */ - mov $page_map_level_3, %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_4 + ((0x0000000000100000 >> 39) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) /* Add an entry to the PML3, pointing to the PML2 */ - mov $page_map_level_2, %eax + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax + lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx or $0x3, %eax - mov %eax, (page_map_level_3 + ((0x0000000000100000 >> 30) & 0x1ff) * 8) + mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) xor %ecx, %ecx - mov $_end_linear, %esi + push %esi + lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi shr $21, %esi add $2, %esi .Lmap_pages: + lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx mov $(1 << 21), %eax mul %ecx or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, page_map_level_2(,%ecx,8) + mov %eax, (%ebx,%ecx,8) inc %ecx cmp %esi, %ecx jne .Lmap_pages + pop %esi ret .section .boot_text, "ax", @progbits @@ -360,7 +409,10 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - movl $0xb8000, (vga_buffer_pointer) + leaq vga_buffer_pointer(%rip), %rax + movl $0xb8000, (%rax) + + xor %rax, %rax call _init -- cgit v1.2.3 From 14ed096fc5de6844cb116f3319c0d03043d26ea2 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 17 Jul 2025 21:09:02 +0000 Subject: x86-64: prepare new architecture --- arch/x86_64/src/boot/boot.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ada6426..e0cff7c 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -12,7 +12,7 @@ * Reserve some space for the Multiboot 2 information pointer. */ .global multiboot_information_pointer -multiboot_information_pointer: .skip 4 +multiboot_information_pointer: .skip 8 /** * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. -- cgit v1.2.3 From 4ae38294b0db1870f82cc402dc4a8bb38cea4a67 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:16:43 +0000 Subject: x86_64: don't lose multi boot information pointer Since the transition to a PIE, more registers are required to perform the relative lookups of data references. As part of that change, a subtle mistake was introduced in _start, overwriting the multiboot information pointer that gets handed to kernel by the boot loader in %ebx. --- arch/x86_64/src/boot/boot.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index e0cff7c..ba5c6f0 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -195,9 +195,9 @@ _start: call .Lstart_get_ip .Lstart_get_ip: pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ebx + lea (stack_top - .Lstart_get_ip)(%esi), %ecx - mov %ebx, %esp + mov %ecx, %esp mov %esp, %ebp call assert_loaded_by_multiboot2_loader -- cgit v1.2.3 From fd6282947bb13af4cfff8cf2209c442b568275f3 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:35:58 +0000 Subject: x86_64: add data segment to boot GDT --- arch/x86_64/src/boot/boot.s | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index ba5c6f0..2decf26 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -58,19 +58,22 @@ stack_top: .section .boot_rodata, "a", @progbits /** - * A valid Global Descriptor Table is still required in long mode. However, we - * only need a single entry for the "code segment", so we will setup a single - * segment table below. + * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * Bit 43: "E" in the access byte => mark the segment as executable. * Bit 44: "S" in the access byte => mark the segment as code or data. * Bit 47: "P" in the access byte => mark the segment as being present. * Bit 53: "L" in the flags byte => mark the segment as being for long mode */ -global_descriptor_table: .quad 0 +global_descriptor_table: +global_descriptor_table_null = . - global_descriptor_table +.quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +global_descriptor_table_data = . - global_descriptor_table +.quad (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** @@ -402,7 +405,7 @@ prepare_page_maps: .code64 _transition_to_long_mode: - xor %rax, %rax + mov $global_descriptor_table_data, %rax mov %rax, %ss mov %rax, %ds mov %rax, %es -- cgit v1.2.3 From 3a67a3e1088508148002e7c20befa571fb0b72c0 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 18 Jul 2025 11:44:15 +0000 Subject: x86_64: set GDT entries as accessed. --- arch/x86_64/src/boot/boot.s | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index 2decf26..f3d9585 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -60,6 +60,7 @@ stack_top: /** * A valid Global Descriptor Table is still required in long mode. * + * Bit 41: "A" in the access byte => mark the segment as accessed. * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). * Bit 43: "E" in the access byte => mark the segment as executable. * Bit 44: "S" in the access byte => mark the segment as code or data. @@ -71,9 +72,9 @@ global_descriptor_table: global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<41) | (1<<44) | (1<<47) +.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) global_descriptor_table_end: /** -- cgit v1.2.3 From eb22cdcad4c27527a63a6e457e80c752f76821c6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 21 Jul 2025 12:13:10 +0000 Subject: x86_64: clean up bootstrap code --- arch/x86_64/src/boot/boot.s | 512 +++++++++++++++++++++++--------------------- 1 file changed, 265 insertions(+), 247 deletions(-) (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s index f3d9585..7a46795 100644 --- a/arch/x86_64/src/boot/boot.s +++ b/arch/x86_64/src/boot/boot.s @@ -1,50 +1,22 @@ -.extern _end_physical -.extern _init -.extern kernel_main - - /** - * Uninitialized data for the bootstrapping process. + * @brief Uninitialized data for the bootstrapping process. */ .section .boot_bss, "aw", @nobits /** - * Reserve some space for the Multiboot 2 information pointer. + * @brief Storage for the multiboot2 information pointer. */ .global multiboot_information_pointer multiboot_information_pointer: .skip 8 -/** - * Align page maps to 4 KiB or the assembler code, will cause crashes when attempting to enable paging. - */ .align 4096 -/** - * Reserve space for the page maps we are going to use during startup. - * - * Note: We are going to use large pages to make the initial mapping code - * simpler. - * - * We need: - * - A single PML 4 (since we will only use 4-level paging) - * - 1 PML 3 - * - 1 PML 2 - */ - -.global page_map_level_4 page_map_level_4: .skip 512 * 8 - -.global page_map_level_3 page_map_level_3: .skip 512 * 8 - -.global page_map_level_2 page_map_level_2: .skip 512 * 8 /** - * Stack space for the bootstrapping process. - * - * Note: We are going to reserve 1 MiB for now. If/when the kernel requires - * more space to run, it will have to relocate the stack. + * @brief Storage for the bootstrap stack. */ .section .boot_stack, "aw", @nobits .align 16 @@ -53,210 +25,240 @@ stack_bottom: .skip 1 << 20 stack_top: /** - * Constants for the bootstrapping process. + * @brief Constants for the bootstrapping process. */ .section .boot_rodata, "a", @progbits /** - * A valid Global Descriptor Table is still required in long mode. - * - * Bit 41: "A" in the access byte => mark the segment as accessed. - * Bit 41: "RW" in the access byte => mark the segment as readable (code) or writable (data). - * Bit 43: "E" in the access byte => mark the segment as executable. - * Bit 44: "S" in the access byte => mark the segment as code or data. - * Bit 47: "P" in the access byte => mark the segment as being present. - * Bit 53: "L" in the flags byte => mark the segment as being for long mode + * @brief A basic GDT for long mode. */ - global_descriptor_table: +.set GDT_ACCESSED, 40 +.set GDT_READ_WRITE, 41 +.set GDT_EXECUTABLE, 43 +.set GDT_DESCRIPTOR_TYPE, 44 +.set GDT_PRESENT, 47 +.set GDT_LONG_MODE, 53 global_descriptor_table_null = . - global_descriptor_table .quad 0 global_descriptor_table_code = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<43) | (1<<44) | (1<<47) | (1<<53) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) global_descriptor_table_data = . - global_descriptor_table -.quad (1<<40) | (1<<41) | (1<<44) | (1<<47) +.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) global_descriptor_table_end: -/** - * We are going to print some messages in case we panic during boot, so we are - * going to store them here as well - */ -.global message_prefix_panic -message_prefix_panic: -.string "TeachOS Panic: " -message_not_loaded_by_multiboot2: -.string "The operating system was not loaded by a Multiboot 2 loader." -message_cpuid_instruction_no_supported: -.string "The 'cpuid' instruction is not supported on this platform." -mesage_long_mode_not_supported: -.string "Long mode is not supported by this platform." +message_prefix_panic: .string "Panic: " +message_not_loaded_by_multiboot2: .string "The operating system was not loaded by a Multiboot 2 loader." +message_cpuid_instruction_no_supported: .string "The 'cpuid' instruction is not supported on this platform." +message_long_mode_not_supported: .string "Long mode is not supported by this platform." +message_return_from_kernel_main: .string "Execution returned from kernel main." /** - * Mutable data for the bootstrapping process. + * @brief Initialized data for the bootstrapping process. */ .section .boot_data, "aw", @progbits /** - * We need a pointer to our current position in the VGA text buffer. + * @brief A pointer to the current position within the VGA text buffer. */ .global vga_buffer_pointer vga_buffer_pointer: .quad 0xb8000 /** - * Code for the bootstrapping process. + * @brief Code for the bootstrapping process. */ .section .boot_text, "ax", @progbits .align 16 .code32 -.global halt -halt: -1: - hlt - jmp 1b +.macro pie_base + push %esi + call 0f + 0: + pop %esi +.endm + +.macro function_start + push %ebp + mov %esp, %ebp +.endm + +.macro function_end + leave + ret +.endm + +.macro pie_function_start + function_start + pie_base +.endm + +.macro pie_function_end + pop %esi + function_end +.endm /** - * Print a given panic message and then halt the machine. + * @brief Prepare the environment and start the kernel. * - * Parameters: - * - [stack - 0] message: the message to print + * This function performs all necessary checks to ensure the system was loaded + * by the expected loader and supports all features required to run the kernel. + * If successful, it prepares the system by setting up memory virtualization + * and then start the kernel proper. + * + * @param %eax The Multiboot 2 magic marker. + * @param %ebx The Multiboot 2 information pointer. + * @return void This function does not return. */ -_panic: - push %ebp +.global _start +_start: + call 0f +0: + pop %esi + + lea (stack_top - 0b)(%esi), %ecx + + mov %ecx, %esp mov %esp, %ebp - call .Lpanic_get_ip -.Lpanic_get_ip: - pop %eax - lea (message_prefix_panic - .Lpanic_get_ip)(%eax), %eax + call _assert_loaded_by_multiboot2_loader + call _save_multiboot_information_pointer - push %eax - push $0x4f - call _print - add $8, %esp + call _assert_cpuid_instruction_is_supported + call _assert_cpu_supports_long_mode - push 8(%ebp) - push 0x4f - call _print - add $8, %esp + call _prepare_page_maps + call _enable_paging + call _enable_sse + call _reload_gdt + + lea (_transition_to_long_mode - 0b)(%esi), %eax + pushl $global_descriptor_table_code + pushl %eax + lret + +/** + * @brief Halt the system. + * + * This function will instruct the CPU to halt. It will try to keep the CPU + * halted, even if interrupts occur. + * + * @return This function never returns. + */ +.global halt +_halt: + function_start - call halt +1: + hlt + jmp 1b + + function_end /** - * Print a message via the VGA buffer. + * @brief Print a message via the VGA text buffer. * - * Parameters: - * - [stack - 4] message: the message to print - * - [stack - 0] color: the color of the message + * @param ebp+12 The message to print. + * @param ebp+8 The color to print the message in. */ _print: - push %ebp - mov %esp, %ebp + pie_function_start - push %ebx - push %esi push %edi + push %ebx - call .Lprint_get_ip -.Lprint_get_ip: - pop %edi - lea (vga_buffer_pointer - .Lprint_get_ip)(%edi), %edi - - mov 8(%ebp), %eax - mov 12(%ebp), %ebx + mov 8(%ebp), %al + mov 12(%ebp), %edx mov $0, %ecx - mov (%edi), %esi - -.Lprint_loop: - mov (%ebx, %ecx), %dl - test %dl, %dl - je .Lupdate_vga_buffer_address - mov %dl, (%esi, %ecx, 2) - mov %al, 1(%esi, %ecx, 2) + lea (vga_buffer_pointer - 0b)(%esi), %edi + mov (%edi), %edi + +1: + mov (%edx, %ecx), %bl + test %bl, %bl + je 2f + mov %bl, (%edi, %ecx, 2) + mov %al, 1(%edi, %ecx, 2) inc %ecx - jmp .Lprint_loop + jmp 1b -.Lupdate_vga_buffer_address: +2: shl $1, %ecx - add %ecx, %esi - mov %esi, (%edi) + add %ecx, %edi + lea (vga_buffer_pointer - 0b)(%esi), %ecx + mov %edi, (%ecx) -.Lprint_end: - pop %edi - pop %esi pop %ebx - mov %ebp, %esp - pop %ebp - ret + pop %edi + + pie_function_end /** - * This is our entry point after being loaded by the bootloader. + * @brief Print a given panic message and then halt the machine as if by calling ::halt() * - * Having this in assembly makes it easier for us to keep things together. + * @param ebp+4 A message to print. + * @return This function does not return. */ -.global _start -_start: - call .Lstart_get_ip -.Lstart_get_ip: - pop %esi - lea (stack_top - .Lstart_get_ip)(%esi), %ecx - - mov %ecx, %esp - mov %esp, %ebp +_panic: + pie_function_start - call assert_loaded_by_multiboot2_loader - call assert_cpuid_instruction_is_supported - call assert_cpu_supports_long_mode - call prepare_page_maps - call enable_paging - call enable_sse + lea (message_prefix_panic - 0b)(%esi), %eax - sub $10, %esp - lea (global_descriptor_table - .Lstart_get_ip)(%esi), %eax - movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) - mov %eax, 2(%esp) - movl $0, 6(%esp) + push %eax + push $0x4f + call _print - lgdt (%esp) - add $10, %esp + mov 16(%ebp), %eax + mov %eax, 8(%ebp) + call _print + add $8, %esp - lea (_transition_to_long_mode - .Lstart_get_ip)(%esi), %eax - pushl $global_descriptor_table_code - pushl %eax - lret + call _halt - call halt + pie_function_end /** - * Assert that the CPU supports going into long mode. + * Assert that we were loaded by a Multiboot 2 compliant bootloader. + * + * This assertion will panic the system if the magic signature was not found. + * If we were loaded my an appropriate bootloader, this function also saves + * the provided MBI pointer to `multiboot_information_pointer`. */ -assert_cpu_supports_long_mode: - mov $0x80000000, %eax - cpuid - cmp $0x80000001, %eax - jb .Llong_mode_assertion_failed +_assert_loaded_by_multiboot2_loader: + pie_function_start - mov $0x80000001, %eax - cpuid - test $(1 << 29), %edx - jz .Llong_mode_assertion_failed - ret -.Llong_mode_assertion_failed: - call .Lassert_cpu_supports_long_mode_fail_get_ip -.Lassert_cpu_supports_long_mode_fail_get_ip: - pop %eax - lea (mesage_long_mode_not_supported - .Lassert_cpu_supports_long_mode_fail_get_ip)(%eax), %eax + .set MULTIBOOT2_MAGIC, 0x36d76289 + cmp $MULTIBOOT2_MAGIC, %eax + je 1f + lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax push %eax call _panic +1: + pie_function_end /** - * Assert that the CPU supports the CPUID instruction. + * @brief Store the multiboot 2 information pointer in the global memory. + * + * @return void + */ +_save_multiboot_information_pointer: + pie_function_start + + lea (multiboot_information_pointer - 0b)(%esi), %eax + mov %ebx, (%eax) + + pie_function_end + +/** + * @brief Assert that the CPU supports the CPUID instruction. * * The primary way to check for support of the instruction is to flip the ID * bin in EFLAGS and then check if this changed was accepted. If so, the CPU * supports the CPUID instruction, otherwise it most-likely doesn't. */ -assert_cpuid_instruction_is_supported: +_assert_cpuid_instruction_is_supported: + pie_function_start + pushfl pop %eax mov %eax, %ecx @@ -271,52 +273,100 @@ assert_cpuid_instruction_is_supported: popfl cmp %ecx, %eax - je .Lcpuid_assertion_fail - ret -.Lcpuid_assertion_fail: - call .Lassert_cpuid_instruction_is_supported_fail_get_ip -.Lassert_cpuid_instruction_is_supported_fail_get_ip: - pop %eax - lea (message_cpuid_instruction_no_supported - .Lassert_cpuid_instruction_is_supported_fail_get_ip)(%eax), %eax + jne 1f + lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax push %eax call _panic +1: + pie_function_end + /** - * Assert that we were loaded by a Multiboot 2 compliant bootloader. - * - * This assertion will panic the system if the magic signature was not found. - * If we were loaded my an appropriate bootloader, this function also saves - * the provided MBI pointer to `multiboot_information_pointer`. + * @brief Assert that the CPU supports going into long mode. */ -assert_loaded_by_multiboot2_loader: - cmp $0x36d76289, %eax /* Check if we received the - expected magic */ - jne .Lmultiboot2_assertion_fail /* Panic otherwise */ - call .Lassert_loaded_by_multiboot2_loader_get_ip -.Lassert_loaded_by_multiboot2_loader_get_ip: - pop %eax - lea (multiboot_information_pointer - .Lassert_loaded_by_multiboot2_loader_get_ip)(%eax), %eax - mov %ebx, (%eax) /* Store the MBI pointer */ - ret -.Lmultiboot2_assertion_fail: - call .Lassert_loaded_by_multiboot2_loader_fail_get_ip -.Lassert_loaded_by_multiboot2_loader_fail_get_ip: - pop %eax - lea (message_not_loaded_by_multiboot2 - .Lassert_loaded_by_multiboot2_loader_fail_get_ip)(%eax), %eax +_assert_cpu_supports_long_mode: + pie_function_start + + mov $0x80000000, %eax + cpuid + cmp $0x80000001, %eax + jb 1f + + mov $0x80000001, %eax + cpuid + test $(1 << 29), %edx + jnz 2f +1: + lea (message_long_mode_not_supported - 0b)(%esi), %eax push %eax call _panic +2: + pie_function_end /** - * Enable paging. + * @brief Prepare a recursive page map hierarchy + * + * We map all physical memory we were loaded in plus one additional page. The + * mapping is done in terms of huge pages (2 MiB per page) to save on required + * page map entries. + * + * @return void + */ +_prepare_page_maps: + pie_function_start + push %ebx + + .set HUGE_PAGES_TO_MAP, 16 + + /* Map the P4 table recursively */ + lea (page_map_level_4 - 0b)(%esi), %eax + mov %eax, %ebx + or $0b11, %ebx + mov %ebx, (511 * 8)(%eax) + + /* Add an entry to the PML4, pointing to the PML3 */ + lea (page_map_level_3 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) + + /* Add an entry to the PML3, pointing to the PML2 */ + lea (page_map_level_3 - 0b)(%esi), %eax + lea (page_map_level_2 - 0b)(%esi), %ebx + or $0b11, %ebx + mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) + + /* Add entries for huge pages to the PML2 */ + push %edi + lea (page_map_level_2 - 0b)(%esi), %ebx + mov $HUGE_PAGES_TO_MAP, %edi + xor %ecx, %ecx + +1: + mov $(1 << 21), %eax + mul %ecx + or $0b10000011, %eax + mov %eax, (%ebx, %ecx, 8) + + inc %ecx + cmp %edi, %ecx + jne 1b + + pop %edi + pop %ebx + pie_function_end + +/** + * @p Enable memory virtualization via paging. * * Note: This routine expects for there to be a valid set of page maps already * set up for use. - */ -enable_paging: - call .Lenable_paging_get_ip -.Lenable_paging_get_ip: - pop %eax -lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax + * + * @return void + */For +_enable_paging: + pie_function_start + + lea (page_map_level_4 - 0b)(%esi), %eax mov %eax, %cr3 /* Enable Physical Address Extension */ @@ -335,12 +385,14 @@ lea (page_map_level_4 - .Lenable_paging_get_ip)(%eax), %eax or $(1 << 31), %eax mov %eax, %cr0 - ret + pie_function_end /** - * Enable use of SSE instructions. + * @brief Enable use of SSE instructions. */ -enable_sse: +_enable_sse: + function_start + mov %cr0, %eax and $0xfffffffb, %eax or $0x00000002, %eax @@ -350,57 +402,26 @@ enable_sse: or $(3 << 9), %eax mov %eax, %cr4 - ret + function_end /** - * Prepare the page maps. + * @brief Prepare a new GTD and load make it active. * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. + * @return void */ -prepare_page_maps: - call .Lprepare_page_maps_get_ip -.Lprepare_page_maps_get_ip: - pop %edi - /* Map the P4 table recursively */ - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %eax - mov %eax, %ebx - or $0b11, %eax /* Write present + writable flags into eax register */ - mov %eax, (511 * 8)(%ebx) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_4 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%ebx) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %eax - lea (page_map_level_3 - .Lprepare_page_maps_get_ip)(%edi), %ebx - or $0x3, %eax - mov %eax, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%ebx) - - xor %ecx, %ecx - - push %esi - lea (_end_linear - .Lprepare_page_maps_get_ip)(%edi), %esi - shr $21, %esi - add $2, %esi +_reload_gdt: + pie_function_start -.Lmap_pages: - lea (page_map_level_2 - .Lprepare_page_maps_get_ip)(%edi), %ebx - mov $(1 << 21), %eax - mul %ecx - or $((1 << 0) | (1 << 1) | (1 << 7)), %eax - mov %eax, (%ebx,%ecx,8) + sub $10, %esp + lea (global_descriptor_table - 0b)(%esi), %eax + movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) + mov %eax, 2(%esp) + movl $0, 6(%esp) - inc %ecx - cmp %esi, %ecx - jne .Lmap_pages + lgdt (%esp) + add $10, %esp - pop %esi - ret + pie_function_end .section .boot_text, "ax", @progbits .code64 @@ -413,12 +434,9 @@ _transition_to_long_mode: mov %rax, %fs mov %rax, %gs - leaq vga_buffer_pointer(%rip), %rax - movl $0xb8000, (%rax) - xor %rax, %rax call _init call main - call halt + call _halt -- cgit v1.2.3 From ce8683e63fc9ef59e1800927afb1753507a42ef6 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Tue, 22 Jul 2025 20:48:11 +0000 Subject: x86_64: extract constants from bootstrap code --- arch/x86_64/src/boot/boot.s | 442 -------------------------------------------- 1 file changed, 442 deletions(-) delete mode 100644 arch/x86_64/src/boot/boot.s (limited to 'arch/x86_64/src/boot/boot.s') diff --git a/arch/x86_64/src/boot/boot.s b/arch/x86_64/src/boot/boot.s deleted file mode 100644 index 7a46795..0000000 --- a/arch/x86_64/src/boot/boot.s +++ /dev/null @@ -1,442 +0,0 @@ -/** - * @brief Uninitialized data for the bootstrapping process. - */ -.section .boot_bss, "aw", @nobits - -/** - * @brief Storage for the multiboot2 information pointer. - */ -.global multiboot_information_pointer -multiboot_information_pointer: .skip 8 - -.align 4096 - -page_map_level_4: .skip 512 * 8 -page_map_level_3: .skip 512 * 8 -page_map_level_2: .skip 512 * 8 - -/** - * @brief Storage for the bootstrap stack. - */ -.section .boot_stack, "aw", @nobits -.align 16 - -stack_bottom: .skip 1 << 20 -stack_top: - -/** - * @brief Constants for the bootstrapping process. - */ -.section .boot_rodata, "a", @progbits - -/** - * @brief A basic GDT for long mode. - */ -global_descriptor_table: -.set GDT_ACCESSED, 40 -.set GDT_READ_WRITE, 41 -.set GDT_EXECUTABLE, 43 -.set GDT_DESCRIPTOR_TYPE, 44 -.set GDT_PRESENT, 47 -.set GDT_LONG_MODE, 53 -global_descriptor_table_null = . - global_descriptor_table -.quad 0 -global_descriptor_table_code = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_EXECUTABLE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) | (1 << GDT_LONG_MODE) -global_descriptor_table_data = . - global_descriptor_table -.quad (1 << GDT_ACCESSED) | (1 << GDT_READ_WRITE) | (1 << GDT_DESCRIPTOR_TYPE) | (1 << GDT_PRESENT) -global_descriptor_table_end: - -message_prefix_panic: .string "Panic: " -message_not_loaded_by_multiboot2: .string "The operating system was not loaded by a Multiboot 2 loader." -message_cpuid_instruction_no_supported: .string "The 'cpuid' instruction is not supported on this platform." -message_long_mode_not_supported: .string "Long mode is not supported by this platform." -message_return_from_kernel_main: .string "Execution returned from kernel main." - -/** - * @brief Initialized data for the bootstrapping process. - */ -.section .boot_data, "aw", @progbits - -/** - * @brief A pointer to the current position within the VGA text buffer. - */ -.global vga_buffer_pointer -vga_buffer_pointer: .quad 0xb8000 - -/** - * @brief Code for the bootstrapping process. - */ -.section .boot_text, "ax", @progbits -.align 16 -.code32 - -.macro pie_base - push %esi - call 0f - 0: - pop %esi -.endm - -.macro function_start - push %ebp - mov %esp, %ebp -.endm - -.macro function_end - leave - ret -.endm - -.macro pie_function_start - function_start - pie_base -.endm - -.macro pie_function_end - pop %esi - function_end -.endm - -/** - * @brief Prepare the environment and start the kernel. - * - * This function performs all necessary checks to ensure the system was loaded - * by the expected loader and supports all features required to run the kernel. - * If successful, it prepares the system by setting up memory virtualization - * and then start the kernel proper. - * - * @param %eax The Multiboot 2 magic marker. - * @param %ebx The Multiboot 2 information pointer. - * @return void This function does not return. - */ -.global _start -_start: - call 0f -0: - pop %esi - - lea (stack_top - 0b)(%esi), %ecx - - mov %ecx, %esp - mov %esp, %ebp - - call _assert_loaded_by_multiboot2_loader - call _save_multiboot_information_pointer - - call _assert_cpuid_instruction_is_supported - call _assert_cpu_supports_long_mode - - call _prepare_page_maps - call _enable_paging - call _enable_sse - call _reload_gdt - - lea (_transition_to_long_mode - 0b)(%esi), %eax - pushl $global_descriptor_table_code - pushl %eax - lret - -/** - * @brief Halt the system. - * - * This function will instruct the CPU to halt. It will try to keep the CPU - * halted, even if interrupts occur. - * - * @return This function never returns. - */ -.global halt -_halt: - function_start - -1: - hlt - jmp 1b - - function_end - -/** - * @brief Print a message via the VGA text buffer. - * - * @param ebp+12 The message to print. - * @param ebp+8 The color to print the message in. - */ -_print: - pie_function_start - - push %edi - push %ebx - - mov 8(%ebp), %al - mov 12(%ebp), %edx - mov $0, %ecx - lea (vga_buffer_pointer - 0b)(%esi), %edi - mov (%edi), %edi - -1: - mov (%edx, %ecx), %bl - test %bl, %bl - je 2f - mov %bl, (%edi, %ecx, 2) - mov %al, 1(%edi, %ecx, 2) - inc %ecx - jmp 1b - -2: - shl $1, %ecx - add %ecx, %edi - lea (vga_buffer_pointer - 0b)(%esi), %ecx - mov %edi, (%ecx) - - pop %ebx - pop %edi - - pie_function_end - -/** - * @brief Print a given panic message and then halt the machine as if by calling ::halt() - * - * @param ebp+4 A message to print. - * @return This function does not return. - */ -_panic: - pie_function_start - - lea (message_prefix_panic - 0b)(%esi), %eax - - push %eax - push $0x4f - call _print - - mov 16(%ebp), %eax - mov %eax, 8(%ebp) - call _print - add $8, %esp - - call _halt - - pie_function_end - -/** - * Assert that we were loaded by a Multiboot 2 compliant bootloader. - * - * This assertion will panic the system if the magic signature was not found. - * If we were loaded my an appropriate bootloader, this function also saves - * the provided MBI pointer to `multiboot_information_pointer`. - */ -_assert_loaded_by_multiboot2_loader: - pie_function_start - - .set MULTIBOOT2_MAGIC, 0x36d76289 - cmp $MULTIBOOT2_MAGIC, %eax - je 1f - lea (message_not_loaded_by_multiboot2 - 0b)(%esi), %eax - push %eax - call _panic -1: - pie_function_end - -/** - * @brief Store the multiboot 2 information pointer in the global memory. - * - * @return void - */ -_save_multiboot_information_pointer: - pie_function_start - - lea (multiboot_information_pointer - 0b)(%esi), %eax - mov %ebx, (%eax) - - pie_function_end - -/** - * @brief Assert that the CPU supports the CPUID instruction. - * - * The primary way to check for support of the instruction is to flip the ID - * bin in EFLAGS and then check if this changed was accepted. If so, the CPU - * supports the CPUID instruction, otherwise it most-likely doesn't. - */ -_assert_cpuid_instruction_is_supported: - pie_function_start - - pushfl - pop %eax - mov %eax, %ecx - - xor $(1 << 21), %eax /* Flip the ID bit */ - push %eax /* Move the new bitset on the stack for loading */ - popfl /* Load the flags with ID set back into EFLAGS */ - pushfl /* Copy the flags back onto the stack */ - pop %eax /* Load the flags for further checking */ - - push %ecx - popfl - - cmp %ecx, %eax - jne 1f - lea (message_cpuid_instruction_no_supported - 0b)(%esi), %eax - push %eax - call _panic - -1: - pie_function_end - -/** - * @brief Assert that the CPU supports going into long mode. - */ -_assert_cpu_supports_long_mode: - pie_function_start - - mov $0x80000000, %eax - cpuid - cmp $0x80000001, %eax - jb 1f - - mov $0x80000001, %eax - cpuid - test $(1 << 29), %edx - jnz 2f -1: - lea (message_long_mode_not_supported - 0b)(%esi), %eax - push %eax - call _panic -2: - pie_function_end - -/** - * @brief Prepare a recursive page map hierarchy - * - * We map all physical memory we were loaded in plus one additional page. The - * mapping is done in terms of huge pages (2 MiB per page) to save on required - * page map entries. - * - * @return void - */ -_prepare_page_maps: - pie_function_start - push %ebx - - .set HUGE_PAGES_TO_MAP, 16 - - /* Map the P4 table recursively */ - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %ebx - or $0b11, %ebx - mov %ebx, (511 * 8)(%eax) - - /* Add an entry to the PML4, pointing to the PML3 */ - lea (page_map_level_3 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 39) & 0x1ff) * 8)(%eax) - - /* Add an entry to the PML3, pointing to the PML2 */ - lea (page_map_level_3 - 0b)(%esi), %eax - lea (page_map_level_2 - 0b)(%esi), %ebx - or $0b11, %ebx - mov %ebx, (((0x0000000000100000 >> 30) & 0x1ff) * 8)(%eax) - - /* Add entries for huge pages to the PML2 */ - push %edi - lea (page_map_level_2 - 0b)(%esi), %ebx - mov $HUGE_PAGES_TO_MAP, %edi - xor %ecx, %ecx - -1: - mov $(1 << 21), %eax - mul %ecx - or $0b10000011, %eax - mov %eax, (%ebx, %ecx, 8) - - inc %ecx - cmp %edi, %ecx - jne 1b - - pop %edi - pop %ebx - pie_function_end - -/** - * @p Enable memory virtualization via paging. - * - * Note: This routine expects for there to be a valid set of page maps already - * set up for use. - * - * @return void - */For -_enable_paging: - pie_function_start - - lea (page_map_level_4 - 0b)(%esi), %eax - mov %eax, %cr3 - - /* Enable Physical Address Extension */ - mov %cr4, %eax - or $(1 << 5), %eax - mov %eax, %cr4 - - /* Enable long mode support */ - mov $0xC0000080, %ecx - rdmsr - or $(1 << 8), %eax - wrmsr - - /* Enable paging */ - mov %cr0, %eax - or $(1 << 31), %eax - mov %eax, %cr0 - - pie_function_end - -/** - * @brief Enable use of SSE instructions. - */ -_enable_sse: - function_start - - mov %cr0, %eax - and $0xfffffffb, %eax - or $0x00000002, %eax - mov %eax, %cr0 - - mov %cr4, %eax - or $(3 << 9), %eax - mov %eax, %cr4 - - function_end - -/** - * @brief Prepare a new GTD and load make it active. - * - * @return void - */ -_reload_gdt: - pie_function_start - - sub $10, %esp - lea (global_descriptor_table - 0b)(%esi), %eax - movw $(global_descriptor_table_end - global_descriptor_table -1), (%esp) - mov %eax, 2(%esp) - movl $0, 6(%esp) - - lgdt (%esp) - add $10, %esp - - pie_function_end - -.section .boot_text, "ax", @progbits -.code64 - -_transition_to_long_mode: - mov $global_descriptor_table_data, %rax - mov %rax, %ss - mov %rax, %ds - mov %rax, %es - mov %rax, %fs - mov %rax, %gs - - xor %rax, %rax - - call _init - - call main - call _halt -- cgit v1.2.3