aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2024-09-27 06:45:13 -0400
committerClyne Sullivan <clyne@bitgloo.com>2024-09-27 06:45:13 -0400
commit56f5c483ee516245867a312c7e1520c3f4df16c7 (patch)
treed230b66c8eb06e0af915facf20966fbe2c098193
parent0f5bbed9a9463adbd23f281f7d7c689cbe7f4182 (diff)
convert boot.s to c++
-rw-r--r--Makefile30
-rw-r--r--boot.cpp72
-rw-r--r--boot.s127
-rw-r--r--kernel.cpp1
4 files changed, 84 insertions, 146 deletions
diff --git a/Makefile b/Makefile
index 17adbac..652f617 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,18 @@
-ASFLAGS := --32
CXXFLAGS := -m32 -ggdb -g3 -O0 -fno-pic -ffreestanding -fno-rtti -fno-exceptions -std=c++23
LDFLAGS := -m32 -static -T link.ld -ffreestanding -nostdlib
-ASFILES := boot.s
-CXXFILES := gdt.cpp \
- idt.cpp \
- memory.cpp \
- multiboot.cpp \
- pic.cpp \
- pit.cpp \
- tasking.cpp \
- vgaterminal.cpp \
- kernel.cpp
+CXXFILES := boot.cpp \
+ gdt.cpp \
+ idt.cpp \
+ memory.cpp \
+ multiboot.cpp \
+ pic.cpp \
+ pit.cpp \
+ tasking.cpp \
+ vgaterminal.cpp \
+ kernel.cpp
-OBJS := $(subst .s,.o,$(ASFILES)) \
- $(subst .cpp,.o,$(CXXFILES))
+OBJS := $(subst .cpp,.o,$(CXXFILES))
all: myos.iso
@@ -27,10 +25,6 @@ myos.bin: $(OBJS) link.ld
@echo " LD " $@
@g++ $(LDFLAGS) -o $@ $(OBJS)
-%.o: %.s
- @echo " AS " $<
- @as $(ASFLAGS) -c $< -o $@
-
%.o: %.cpp
@echo " CXX " $<
@g++ $(CXXFLAGS) -c $< -o $@
@@ -41,5 +35,5 @@ clean:
run: myos.iso
@echo " QEMU"
- @qemu-system-i386 -cdrom $< -monitor stdio -no-reboot -s -S #-d int
+ @qemu-system-i386 -cdrom $< -monitor stdio -no-reboot #-s -S #-d int
diff --git a/boot.cpp b/boot.cpp
new file mode 100644
index 0000000..0b003fd
--- /dev/null
+++ b/boot.cpp
@@ -0,0 +1,72 @@
+#include <array>
+#include <cstdint>
+
+extern void kernel_main();
+
+struct multiboot2
+{
+ static constexpr std::uint32_t MAGIC = 0xE85250D6;
+ static constexpr std::uint32_t FLAGS = 0;
+ static constexpr std::uint32_t LENGTH = 16;
+ static constexpr std::uint32_t CHECKSUM = -(MAGIC + FLAGS + LENGTH);
+
+ alignas(8)
+ std::uint32_t magic = MAGIC;
+ std::uint32_t flags = FLAGS;
+ std::uint32_t length = LENGTH;
+ std::uint32_t checksum = CHECKSUM;
+} __attribute__((packed));
+
+struct multiboot2_tag
+{
+ alignas(8)
+ std::uint16_t id;
+ std::uint16_t flags;
+ std::uint32_t length;
+ std::uint32_t data[];
+} __attribute__((packed));
+
+__attribute__((section(".multiboot2")))
+multiboot2 multibootHeader;
+
+__attribute__((section(".multiboot2")))
+multiboot2_tag multibootTagInfoRequest = {
+ 1, 0, sizeof(multiboot2_tag) + sizeof(std::uint32_t),
+ {4}
+};
+
+__attribute__((section(".multiboot2")))
+multiboot2_tag multibootTagEnd = {
+ 0, 0, sizeof(multiboot2_tag), {}
+};
+
+alignas(16)
+std::array<std::uint8_t, 16384> stack;
+
+extern "C"
+__attribute__((naked))
+void _start()
+{
+ asm volatile(R"(
+ mov %%eax, multiboot_magic
+ mov %%ebx, multiboot_ptr
+ mov %0, %%esp
+ )" :: "i" (stack.data() + stack.size()));
+
+ extern std::uint32_t __init_array_start;
+ extern std::uint32_t __init_array_end;
+
+ auto it = &__init_array_start;
+ while (it < &__init_array_end) {
+ auto fn = reinterpret_cast<void (*)()>(*it);
+ fn();
+ ++it;
+ }
+
+ kernel_main();
+
+ asm volatile("cli");
+ for (;;)
+ asm volatile("hlt");
+}
+
diff --git a/boot.s b/boot.s
deleted file mode 100644
index 7908d3e..0000000
--- a/boot.s
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Declare constants for the multiboot header. */
-.set MAGIC, 0xE85250D6
-.set FLAGS, 0x0
-.set LENGTH, 16
-.set CHECKSUM, -(MAGIC + FLAGS + LENGTH)
-
-.section .multiboot2
-.align 8
-.int MAGIC
-.int FLAGS
-.int LENGTH
-.int CHECKSUM
-
-/* info request */
-.align 8
-.hword 1, 0
-.int 12
-.int 4
-
-/* end tag */
-.align 8
-.hword 0, 0
-.int 8
-
-/*
-The multiboot standard does not define the value of the stack pointer register
-(esp) and it is up to the kernel to provide a stack. This allocates room for a
-small stack by creating a symbol at the bottom of it, then allocating 16384
-bytes for it, and finally creating a symbol at the top. The stack grows
-downwards on x86. The stack is in its own section so it can be marked nobits,
-which means the kernel file is smaller because it does not contain an
-uninitialized stack. The stack on x86 must be 16-byte aligned according to the
-System V ABI standard and de-facto extensions. The compiler will assume the
-stack is properly aligned and failure to align the stack will result in
-undefined behavior.
-*/
-.section .bss
-.align 16
-stack_bottom:
-.skip 16384 # 16 KiB
-stack_top:
-
-/*
-The linker script specifies _start as the entry point to the kernel and the
-bootloader will jump to this position once the kernel has been loaded. It
-doesn't make sense to return from this function as the bootloader is gone.
-*/
-.section .text
-.global _start
-.type _start, @function
-_start:
- /*
- The bootloader has loaded us into 32-bit protected mode on a x86
- machine. Interrupts are disabled. Paging is disabled. The processor
- state is as defined in the multiboot standard. The kernel has full
- control of the CPU. The kernel can only make use of hardware features
- and any code it provides as part of itself. There's no printf
- function, unless the kernel provides its own <stdio.h> header and a
- printf implementation. There are no security restrictions, no
- safeguards, no debugging mechanisms, only what the kernel provides
- itself. It has absolute and complete power over the
- machine.
- */
- mov %eax, multiboot_magic
- mov %ebx, multiboot_ptr
-
- /*
- To set up a stack, we set the esp register to point to the top of the
- stack (as it grows downwards on x86 systems). This is necessarily done
- in assembly as languages such as C cannot function without a stack.
- */
- mov $stack_top, %esp
-
- /*
- This is a good place to initialize crucial processor state before the
- high-level kernel is entered. It's best to minimize the early
- environment where crucial features are offline. Note that the
- processor is not fully initialized yet: Features such as floating
- point instructions and instruction set extensions are not initialized
- yet. The GDT should be loaded here. Paging should be enabled here.
- C++ features such as global constructors and exceptions will require
- runtime support to work as well.
- */
- mov $__init_array_start, %eax
-.again:
- cmp $__init_array_end, %eax
- je .next
- push %eax
- call *(%eax)
- pop %eax
- add $0x4, %eax
- jmp .again
-
-.next:
-
- /*
- Enter the high-level kernel. The ABI requires the stack is 16-byte
- aligned at the time of the call instruction (which afterwards pushes
- the return pointer of size 4 bytes). The stack was originally 16-byte
- aligned above and we've pushed a multiple of 16 bytes to the
- stack since (pushed 0 bytes so far), so the alignment has thus been
- preserved and the call is well defined.
- */
- call kernel_main
-
- /*
- If the system has nothing more to do, put the computer into an
- infinite loop. To do that:
- 1) Disable interrupts with cli (clear interrupt enable in eflags).
- They are already disabled by the bootloader, so this is not needed.
- Mind that you might later enable interrupts and return from
- kernel_main (which is sort of nonsensical to do).
- 2) Wait for the next interrupt to arrive with hlt (halt instruction).
- Since they are disabled, this will lock up the computer.
- 3) Jump to the hlt instruction if it ever wakes up due to a
- non-maskable interrupt occurring or due to system management mode.
- */
- cli
-1: hlt
- jmp 1b
-
-/*
-Set the size of the _start symbol to the current location '.' minus its start.
-This is useful when debugging or when you implement call tracing.
-*/
-.size _start, . - _start
-
diff --git a/kernel.cpp b/kernel.cpp
index 41c3a61..dab93c6 100644
--- a/kernel.cpp
+++ b/kernel.cpp
@@ -10,7 +10,6 @@
static VGATerminal vga;
TextOutput& term = vga;
-extern "C"
void kernel_main(void)
{
term.write("Clyne's kernel, v2024\n\n");