diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index af4555c3..cb518cce 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -35,42 +35,51 @@ jobs:
- name: Integration tests
working-directory: inttest
run: cargo fmt --check
- documentation:
+ book:
runs-on: [self-hosted, linux]
needs: clippy
steps:
- name: Build book
run: mdbook build doc/
+ documentation:
+ runs-on: [self-hosted, linux]
+ needs: clippy
+ strategy:
+ matrix:
+ arch: ["x86", "x86_64"]
+ steps:
- name: Build references
working-directory: kernel
- run: ci/doc.sh
+ run: cargo doc --target target/${{ matrix.arch }}/${{ matrix.arch }}.json
build:
runs-on: [self-hosted, linux]
needs: clippy
+ strategy:
+ matrix:
+ arch: ["x86", "x86_64"]
steps:
- name: Debug
working-directory: kernel
- run: ci/build.sh
+ run: cargo build --target target/${{ matrix.arch }}/${{ matrix.arch }}.json
- name: Check Multiboot2 for x86 (debug)
working-directory: kernel
run: grub-file --is-x86-multiboot2 target/x86/debug/maestro
- name: Release
working-directory: kernel
- env:
- CARGOFLAGS: --release
- run: ci/build.sh
+ run: cargo build --target target/${{ matrix.arch }}/${{ matrix.arch }}.json --release
- name: Check Multiboot2 for x86 (release)
working-directory: kernel
run: grub-file --is-x86-multiboot2 target/x86/release/maestro
strace:
runs-on: [self-hosted, linux]
needs: build
+ strategy:
+ matrix:
+ arch: ["x86", "x86_64"]
steps:
- name: Build
working-directory: kernel
- env:
- CARGOFLAGS: --features strace
- run: ci/build.sh
+ run: cargo build --target target/${{ matrix.arch }}/${{ matrix.arch }}.json --features strace
- name: Check Multiboot2 for x86
working-directory: kernel
run: grub-file --is-x86-multiboot2 target/x86/debug/maestro
@@ -87,6 +96,9 @@ jobs:
selftest:
runs-on: [self-hosted, linux]
needs: build
+ strategy:
+ matrix:
+ arch: ["x86", "x86_64"]
steps:
- name: Run utils tests
working-directory: utils
@@ -94,18 +106,31 @@ jobs:
timeout-minutes: 10
- name: Run kernel tests
working-directory: kernel
+ env:
+ CARGOFLAGS: --target arch/${{ matrix.arch }}/${{ matrix.arch }}.json
run: ci/test.sh self
timeout-minutes: 10
inttest:
runs-on: [self-hosted, linux]
needs: build
+ strategy:
+ matrix:
+ arch:
+ - kernel: "x86"
+ user: "i686-unknown-linux-musl"
+ - kernel: "x86_64"
+ user: "x86_64-unknown-linux-musl"
steps:
- name: Build tests
working-directory: inttest
+ env:
+ TARGET: ${{ matrix.arch.user }}
run: |
./build.sh
mv disk ../kernel/qemu_disk
- name: Run
working-directory: kernel
+ env:
+ CARGOFLAGS: --target arch/${{ matrix.arch.kernel }}/${{ matrix.arch.kernel }}.json
run: ci/test.sh int
timeout-minutes: 10
diff --git a/inttest/build.sh b/inttest/build.sh
index 593039c3..dbc06fcd 100755
--- a/inttest/build.sh
+++ b/inttest/build.sh
@@ -3,7 +3,7 @@
set -e
if [ -z "$TARGET" ]; then
- export TARGET=i686-unknown-linux-musl
+ export TARGET=x86_64-unknown-linux-musl
fi
# Build
diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml
index 7682cf19..7c40c6e1 100644
--- a/kernel/.cargo/config.toml
+++ b/kernel/.cargo/config.toml
@@ -4,6 +4,9 @@ build-std = ["core", "alloc"]
[target.x86]
runner = "scripts/qemu.sh"
+[target.x86_64]
+runner = "scripts/qemu.sh"
+
[build]
# Set default target
-target = "arch/x86/x86.json"
+target = "arch/x86_64/x86_64.json"
diff --git a/kernel/arch/x86/linker.ld b/kernel/arch/x86/linker.ld
index 62fd4285..e4ef3472 100644
--- a/kernel/arch/x86/linker.ld
+++ b/kernel/arch/x86/linker.ld
@@ -17,7 +17,7 @@
*/
/*
- * This file is the linker script for the x86 architecture.
+ * The linker script for the x86 architecture.
*
* The kernel image is split into two parts:
* - The boot part, in lower memory (sections with the `.boot` prefix)
@@ -27,10 +27,11 @@
* the kernel image is relocated to higher memory.
* After running the kernel code, the booting code isn't useful anymore.
*
- * Sections need to be aligned on the page boundary to be protected against writing (for those
- * where it applies).
+ * Sections need to be aligned on the page boundary to be protected against
+ * writing (for those where it applies).
*
- * BSS sections are located right after read-only sections to limit damages if the stack(s) they contain overflows.
+ * BSS sections are located right after read-only sections to limit damages if
+ * the stack(s) they contain overflows.
*/
ENTRY(multiboot_entry)
diff --git a/kernel/arch/x86_64/linker.ld b/kernel/arch/x86_64/linker.ld
new file mode 100644
index 00000000..0a8eb0c9
--- /dev/null
+++ b/kernel/arch/x86_64/linker.ld
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2024 Luc Lenôtre
+ *
+ * This file is part of Maestro.
+ *
+ * Maestro is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Maestro. If not, see .
+ */
+
+/*
+ * The linker script for the x86_64 architecture.
+ *
+ * For more information about the organization of this particular file, check
+ * the documentation in the linker script for the x86 architecture.
+ */
+
+ENTRY(multiboot_entry)
+
+SECTIONS
+{
+ . = 0x100000;
+
+ .boot.text : ALIGN(4K)
+ {
+ *(.boot.text)
+ }
+
+ .boot.stack : ALIGN(4K)
+ {
+ *(.boot.stack)
+ }
+
+ .boot.data : ALIGN(4K)
+ {
+ *(.boot.data)
+ }
+
+ . = 0xc0200000;
+
+ .text : AT (ADDR (.text) - 0xc0000000) ALIGN(4K)
+ {
+ *(.text*)
+ }
+
+ .rodata : AT (ADDR (.rodata) - 0xc0000000) ALIGN(4K)
+ {
+ *(.rodata*)
+ }
+
+ .user : AT (ADDR (.user) - 0xc0000000) ALIGN(4K)
+ {
+ *(.user*)
+ }
+
+ .bss : AT (ADDR (.bss) - 0xc0000000) ALIGN(4K)
+ {
+ *(COMMON)
+ *(.bss*)
+ }
+
+ .data : AT (ADDR (.data) - 0xc0000000) ALIGN(4K)
+ {
+ *(.data*)
+ }
+}
diff --git a/kernel/arch/x86_64/x86_64.json b/kernel/arch/x86_64/x86_64.json
new file mode 100644
index 00000000..41f029ed
--- /dev/null
+++ b/kernel/arch/x86_64/x86_64.json
@@ -0,0 +1,16 @@
+{
+ "arch": "x86_64",
+ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
+ "disable-redzone": true,
+ "dynamic-linking": true,
+ "executables": true,
+ "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float",
+ "linker": "x86_64-elf-ld",
+ "linker-flavor": "ld",
+ "llvm-target": "x86_64-unknown-none",
+ "os": "none",
+ "panic-strategy": "abort",
+ "target-c-int-width": "32",
+ "target-endian": "little",
+ "target-pointer-width": "64"
+}
diff --git a/kernel/ci/build.sh b/kernel/ci/build.sh
deleted file mode 100755
index faeaaf1a..00000000
--- a/kernel/ci/build.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-EXIT_CODE=0
-
-for arch in $(ls -1 arch/); do
- echo "Build for architecture $arch..."
- cargo build --target arch/$arch/$arch.json $CARGOFLAGS
- EXIT_CODE=$(($EXIT_CODE + $?))
-done
-
-exit $EXIT_CODE
diff --git a/kernel/ci/doc.sh b/kernel/ci/doc.sh
deleted file mode 100755
index 2a52a4a6..00000000
--- a/kernel/ci/doc.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-EXIT_CODE=0
-
-for arch in $(ls -1 arch/); do
- echo "Build documentation for architecture $arch..."
- cargo doc --target arch/$arch/$arch.json $CARGOFLAGS
- EXIT_CODE=$(($EXIT_CODE + $?))
-done
-
-exit $EXIT_CODE
diff --git a/kernel/scripts/gdb.sh b/kernel/scripts/gdb.sh
index 710f0af6..5888972a 100755
--- a/kernel/scripts/gdb.sh
+++ b/kernel/scripts/gdb.sh
@@ -11,7 +11,7 @@ setsid cargo run $CARGOFLAGS >qemu.log 2>&1 &
QEMU_PID=$!
if [ -z "$ARCH" ]; then
- ARCH="x86"
+ ARCH="x86_64"
fi
KERN_PATH="target/$ARCH/debug/maestro"
diff --git a/kernel/src/boot.rs b/kernel/src/boot.rs
new file mode 100644
index 00000000..a3b4c2b6
--- /dev/null
+++ b/kernel/src/boot.rs
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2024 Luc Lenôtre
+ *
+ * This file is part of Maestro.
+ *
+ * Maestro is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Maestro. If not, see .
+ */
+
+use crate::{
+ gdt,
+ memory::{
+ vmem::x86::{FLAG_PAGE_SIZE, FLAG_PRESENT, FLAG_WRITE},
+ PhysAddr,
+ },
+};
+use core::arch::global_asm;
+use utils::limits::PAGE_SIZE;
+
+/// The value of the Multiboot2 magic.
+const MULTIBOOT_MAGIC: u32 = 0xe85250d6;
+
+/// Multiboot header tag: End
+const MULTIBOOT_HEADER_TAG_END: u16 = 0;
+/// Multiboot header tag: The kernel's entry point address
+const MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS: u16 = 3;
+
+/// The physical address of the GDT.
+const GDT_PHYS_ADDR: PhysAddr = PhysAddr(0x800);
+
+/// The header of a multiboot2 tag.
+#[repr(C, align(8))]
+struct MultibootTagHdr {
+ /// The tag's type.
+ r#type: u16,
+ /// The tag's flags.
+ ///
+ /// Currently, has only one flag:
+ /// - `0`: if set, the tag may be considered as optional by the bootloader.
+ flags: u16,
+ /// The size of the tag in bytes.
+ size: u32,
+}
+
+/// Layout of the multiboot2 tag indicating the entry point of the kernel.
+#[repr(C, align(8))]
+struct MultibootEntryAddrTag {
+ /// The tag's header.
+ hdr: MultibootTagHdr,
+ /// The entry point's physical address.
+ entry_addr: u32,
+}
+
+/// Layout of the multiboot2 header.
+#[repr(C, align(8))]
+struct MultibootHeader {
+ // Mandatory fields
+ /// Multiboot magic number.
+ magic: u32,
+ /// The CPU architecture to boot for.
+ architecture: u32,
+ /// The size of this header in bytes.
+ header_length: u32,
+ /// The checksum of the previous fields.
+ checksum: u32,
+
+ /// The entry point tag.
+ entry_addr_tag: MultibootEntryAddrTag,
+ /// The end tag.
+ end_tag: MultibootTagHdr,
+}
+
+/// The header used to provide multiboot2 with the necessary information to boot the kernel.
+#[no_mangle]
+#[link_section = ".boot.rodata"]
+pub static MULTIBOOT_HEADER: MultibootHeader = MultibootHeader {
+ magic: MULTIBOOT_MAGIC,
+ // x86
+ architecture: 0,
+ header_length: size_of::() as _,
+ // Compute checksum of the previous values
+ checksum: 0.wrapping_sub(MULTIBOOT_MAGIC + 0 + size_of::()),
+
+ entry_addr_tag: MultibootEntryAddrTag {
+ hdr: MultibootTagHdr {
+ r#type: MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS,
+ flags: 0,
+ size: size_of::(),
+ },
+ entry_addr: multiboot_entry as _,
+ },
+ end_tag: MultibootTagHdr {
+ r#type: MULTIBOOT_HEADER_TAG_END,
+ flags: 0,
+ size: size_of::(),
+ },
+};
+
+/// The initial Global Descriptor Table.
+#[no_mangle]
+#[link_section = ".boot.rodata"]
+pub static INIT_GDT: [gdt::Entry; 9] = [
+ // First entry, empty
+ gdt::Entry::default(),
+ // Kernel code segment
+ gdt::Entry::new(0, !0, 0b10011010, 0b1100),
+ // Kernel data segment
+ gdt::Entry::new(0, !0, 0b10010010, 0b1100),
+ // User code segment
+ gdt::Entry::new(0, !0, 0b11111010, 0b1100),
+ // User data segment
+ gdt::Entry::new(0, !0, 0b11110010, 0b1100),
+ // TSS
+ gdt::Entry::default(),
+ // TLS entries
+ gdt::Entry::default(),
+ gdt::Entry::default(),
+ gdt::Entry::default(),
+];
+
+/// A page directory.
+#[repr(C, align(8))]
+struct PageDir([u32; 1024]);
+
+impl PageDir {
+ /// Initializes a page directory to remap the kernel to the higher half of the memory.
+ pub const fn higher_half() -> Self {
+ let mut dir = [0; 1024];
+ for i in 0..256 {
+ let addr = (i * PAGE_SIZE * 1024) as u32;
+ let ent = addr | FLAG_PAGE_SIZE | FLAG_WRITE | FLAG_PRESENT;
+ dir[i] = ent;
+ dir[i + 768] = ent;
+ }
+ Self(dir)
+ }
+}
+
+/// The page directory used to remap the kernel to higher memory.
+#[no_mangle]
+#[link_section = ".boot.rodata"]
+pub static REMAP_DIR: PageDir = PageDir::higher_half();
+
+extern "C" {
+ /// The kernel's entry point.
+ fn multiboot_entry();
+}
+
+global_asm!(
+ r"
+.global multiboot_entry
+.type multiboot_entry, @function
+
+.section .boot.text
+
+multiboot_entry:
+ mov esp, boot_stack_begin
+ xor ebp, ebp
+ pushl 0
+ popf
+
+ push ebx
+ push eax
+ call setup_gdt
+ call remap
+
+ call kernel_main
+ # `kernel_main` cannot return
+ ud2
+
+setup_gdt:
+ # Copy GDT to its physical address
+ mov esi, INIT_GDT
+ mov edi, {GDT_PHYS_ADDR}
+ mov ecx, {GDT_SIZE}
+ rep movsb
+
+ # Load GDT
+ pushl {GDT_PHYS_ADDR}
+ pushw ({GDT_SIZE} - 1)
+ lgdt [esp]
+ add esp, 6
+ jmp 8, complete_flush
+complete_flush:
+ mov ax, GDT_KERNEL_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov ax, 0
+ mov fs, ax
+ mov gs, ax
+
+ ret
+
+/*
+ * Remaps the first gigabyte of memory to the last one, enabling paging and PSE.
+ */
+remap:
+ # Set page directory
+ mov cr3, {REMAP_DIR_ADDR}
+
+ # Enable PSE
+ mov eax, cr4
+ or eax, 0x00000010
+ mov cr4, eax
+
+ # Enable paging
+ mov eax, cr0
+ or eax, 0x80010000
+ mov cr0, eax
+
+ # Update stack
+ add esp, 0xc0000000
+
+ ret
+
+.section .boot.stack
+
+.align 8
+
+boot_stack:
+.size boot_stack, STACK_SIZE
+.skip STACK_SIZE
+boot_stack_begin:
+",
+ GDT_SIZE = size_of_val(&INIT_GDT),
+ REMAP_DIR_ADDR = &REMAP_DIR
+);
diff --git a/kernel/src/boot/a20.s b/kernel/src/boot/a20.s
deleted file mode 100644
index ba848dd3..00000000
--- a/kernel/src/boot/a20.s
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2024 Luc Lenôtre
- *
- * This file is part of Maestro.
- *
- * Maestro is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Maestro. If not, see .
- */
-
-.global a20_handle
-
-.type a20_handle, @function
-.type a20_check, @function
-.type a20_wait_read, @function
-.type a20_wait_write, @function
-
-.section .boot.text, "ax"
-
-/*
- * Ensures that the A20 line is enabled.
- */
-a20_handle:
- call a20_check
- test $0, %eax
- je a20_handle_
- ret
-a20_handle_:
- call a20_enable
- ret
-
-/*
- * Checks whether the a20 line is enabled or not.
- */
-a20_check:
- pusha
- mov $0x888888, %edi
- mov $0x088888, %esi
- mov %edi, (%edi)
- mov %esi, (%esi)
- cmpsl
- popa
- jne a20_enabled
- xor %eax, %eax
- ret
-a20_enabled:
- mov $1, %eax
- ret
-
-/*
- * Enables the a20 line using the PS2 controller.
- * Note: Interrupts must be disabled for this function.
- */
-a20_enable:
- pushf
- cli
-
- call a20_wait_write
- mov $0xad, %al
- outb %al, $0x64
-
- call a20_wait_write
- mov $0xd0, %al
- outb %al, $0x64
-
- call a20_wait_read
- inb $0x60, %al
- push %eax
-
- call a20_wait_write
- mov $0xd1, %al
- outb %al, $0x64
-
- pop %eax
- or $2, %al
- outb %al, $0x60
-
- call a20_wait_write
-
- popf
- ret
-
-/*
- * Waits for the PS2 controller to be available for reading.
- */
-a20_wait_read:
- in $0x64, %al
- test $1, %al
- jz a20_wait_read
- ret
-
-/*
- * Waits for the PS2 controller to be available for writing.
- */
-a20_wait_write:
- in $0x64, %al
- test $2, %al
- jnz a20_wait_write
- ret
diff --git a/kernel/src/boot/boot.s b/kernel/src/boot/boot.s
deleted file mode 100644
index 24a46cae..00000000
--- a/kernel/src/boot/boot.s
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2024 Luc Lenôtre
- *
- * This file is part of Maestro.
- *
- * Maestro is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Maestro. If not, see .
- */
-
-.section .boot.text, "ax"
-
-/*
- * Constants used by Multiboot2 to detect the kernel.
- */
-.set MULTIBOOT_MAGIC, 0xe85250d6
-.set MULTIBOOT_ARCHITECTURE, 0
-.set HEADER_LENGTH, (header_end - header)
-.set CHECKSUM, -(MULTIBOOT_MAGIC + MULTIBOOT_ARCHITECTURE + HEADER_LENGTH)
-
-/*
- * Multiboot header tags constants.
- */
-.set MULTIBOOT_HEADER_TAG_END, 0
-.set MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS, 3
-
-/*
- * The Multiboot2 kernel header.
- */
-.align 8
-header:
- .long MULTIBOOT_MAGIC
- .long MULTIBOOT_ARCHITECTURE
- .long HEADER_LENGTH
- .long CHECKSUM
-
-/*
- * The entry tag, setting the entry point of the kernel.
- */
-.align 8
-entry_address_tag:
- .short MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
- .short 1
- .long (entry_address_tag_end - entry_address_tag)
- .long multiboot_entry
-entry_address_tag_end:
-
-.align 8
- .short MULTIBOOT_HEADER_TAG_END
- .short 0
- .long 8
-header_end:
-
-/*
- * The size of the kernel stack.
- */
-.set STACK_SIZE, 32768
-
-.global boot_stack
-.global boot_stack_begin
-
-.global multiboot_entry
-.type multiboot_entry, @function
-
-.extern setup_gdt
-.extern _init
-.extern _fini
-
-/*
- * The entry point of the kernel.
- */
-multiboot_entry:
- mov $boot_stack_begin, %esp
- xor %ebp, %ebp
- pushl $0
- popf
- cli
-
- push %eax
- push %ebx
- call a20_handle
- call setup_gdt
- call kernel_remap
- pop %ebx
- pop %eax
-
- mov $(0xc0000000 + boot_stack_begin), %esp
- push %ebx
- push %eax
- call kernel_main
- # `kernel_main` cannot return
- ud2
-
-
-
-.section .boot.stack, "aw"
-
-.align 8
-
-/*
- * The kernel stack.
- */
-boot_stack:
-.size boot_stack, STACK_SIZE
-.skip STACK_SIZE
-boot_stack_begin:
diff --git a/kernel/src/boot/gdt.s b/kernel/src/boot/gdt.s
deleted file mode 100644
index 79c49561..00000000
--- a/kernel/src/boot/gdt.s
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2024 Luc Lenôtre
- *
- * This file is part of Maestro.
- *
- * Maestro is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Maestro. If not, see .
- */
-
-.global GDT_KERNEL_CS
-.global GDT_KERNEL_DS
-.global GDT_USER_CS
-.global GDT_USER_DS
-.global GDT_TSS
-
-.global GDT_DESC_VIRT_PTR
-
-.global setup_gdt
-.global gdt_move
-
-.type setup_gdt, @function
-.type gdt_copy, @function
-.type gdt_move, @function
-
-.section .boot.data, "aw"
-
-.align 8
-
-/*
- * The beginning of the GDT.
- * Every segment covers the whole memory space.
- */
-gdt_start:
- .quad 0
-
-/*
- * Segment for the kernel code.
- */
-gdt_kernel_code:
- .word 0xffff
- .word 0
- .byte 0
- .byte 0b10011010
- .byte 0b11001111
- .byte 0
-
-/*
- * Segment for the kernel data.
- */
-gdt_kernel_data:
- .word 0xffff
- .word 0
- .byte 0
- .byte 0b10010010
- .byte 0b11001111
- .byte 0
-
-/*
- * Segment for the user code.
- */
-gdt_user_code:
- .word 0xffff
- .word 0
- .byte 0
- .byte 0b11111010
- .byte 0b11001111
- .byte 0
-
-/*
- * Segment for the user data.
- */
-gdt_user_data:
- .word 0xffff
- .word 0
- .byte 0
- .byte 0b11110010
- .byte 0b11001111
- .byte 0
-
-/*
- * Reserved space for the Task State Segment.
- */
-gdt_tss:
- .quad 0
-
-/*
- * TLS GDT entries.
- */
-gdt_tls:
- .quad 0
- .quad 0
- .quad 0
-
-/*
- * The GDT descriptor.
- */
-gdt:
- .word gdt - gdt_start - 1
- .long gdt_start
-
-/*
- * Offsets into the GDT for each segment.
- */
-.set GDT_KERNEL_CS, (gdt_kernel_code - gdt_start)
-.set GDT_KERNEL_DS, (gdt_kernel_data - gdt_start)
-.set GDT_USER_CS, (gdt_user_code - gdt_start)
-.set GDT_USER_DS, (gdt_user_data - gdt_start)
-.set GDT_TSS, (gdt_tss - gdt_start)
-
-/*
- * Physical address to the GDT.
- */
-.set GDT_PHYS_PTR, 0x800
-/*
- * The size of the GDT in bytes.
- */
-.set GDT_SIZE, (gdt - gdt_start)
-/*
- * Physical address to the GDT descriptor.
- */
-.set GDT_DESC_PHYS_PTR, (GDT_PHYS_PTR + (gdt - gdt_start))
-/*
- * Virtual address to the GDT.
- */
-.set GDT_VIRT_PTR, (0xc0000000 + GDT_PHYS_PTR)
-/*
- * Virtual address to the GDT descriptor.
- */
-.set GDT_DESC_VIRT_PTR, (GDT_VIRT_PTR + (gdt - gdt_start))
-
-.section .boot.text, "ax"
-
-/*
- * Switches the CPU to protected mode.
- */
-setup_gdt:
- cli
-
- call gdt_copy
- mov $GDT_DESC_PHYS_PTR, %eax
- movl $GDT_PHYS_PTR, 2(%eax)
-
- lgdt GDT_DESC_PHYS_PTR
-
- mov %cr0, %eax
- or $1, %al
- mov %eax, %cr0
-
- jmp $GDT_KERNEL_CS, $complete_flush
-complete_flush:
- mov $GDT_KERNEL_DS, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %ss
-
- mov $0, %ax
- mov %ax, %fs
- mov %ax, %gs
-
- ret
-
-/*
- * Copies the GDT to its physical address.
- */
-gdt_copy:
- mov $gdt_start, %esi
- mov $GDT_PHYS_PTR, %edi
- mov $(GDT_SIZE + 6), %ecx
- rep movsb
-
- ret
-
-/*
- * Moves the GDT to the new virtual address after kernel relocation.
- */
-gdt_move:
- mov $GDT_DESC_VIRT_PTR, %eax
- movl $GDT_VIRT_PTR, 2(%eax)
-
- lgdt GDT_DESC_VIRT_PTR
-
- ret
diff --git a/kernel/src/boot/remap.s b/kernel/src/boot/remap.s
deleted file mode 100644
index 3d021008..00000000
--- a/kernel/src/boot/remap.s
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2024 Luc Lenôtre
- *
- * This file is part of Maestro.
- *
- * Maestro is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * Maestro is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Maestro. If not, see .
- */
-
-/*
- * This file handles kernel remapping in order to place it in High Memory.
- * To do so, paging is enabled using a page directory that remaps the whole
- * kernel.
- *
- * The created page directory has to be replaced when kernel memory management
- * is ready.
- */
-
-.section .boot.text, "ax"
-
-.global kernel_remap
-
-.type kernel_remap, @function
-.type pse_enable, @function
-
-.extern gdt_move
-
-/*
- * Remaps the first gigabyte of memory to the last one.
- *
- * This function enables PSE.
- */
-kernel_remap:
- push %ebx
-
- // Zero page directory
- xor %eax, %eax
- mov $remap_dir, %esi
-L1:
- movl $0, (%esi)
- add $4, %esi
- add $1, %eax
- cmp $768, %eax
- jne L1
-
- // Fill entries
- xor %eax, %eax
- mov $remap_dir, %esi
-L2:
- // (i * PAGE_SIZE * 1024)
- mov %eax, %ebx
- mov $22, %cl
- shl %cl, %ebx
- // PAGE_SIZE | WRITE | PRESENT
- or $(128 + 2 + 1), %ebx
- movl %ebx, (%esi)
- movl %ebx, (4 * 768)(%esi)
- add $4, %esi
- add $1, %eax
- cmp $256, %eax
- jne L2
-
- push $remap_dir
- call pse_enable
- add $4, %esp
-
- call gdt_move
-
- pop %ebx
- ret
-
-/*
- * Enables Page Size Extension (PSE) and paging using the given page directory.
- */
-pse_enable:
- push %ebp
- mov %esp, %ebp
- push %eax
-
- mov 8(%ebp), %eax
- mov %eax, %cr3
-
- mov %cr4, %eax
- or $0x00000010, %eax
- mov %eax, %cr4
-
- mov %cr0, %eax
- or $0x80010000, %eax
- mov %eax, %cr0
-
- pop %eax
- mov %ebp, %esp
- pop %ebp
- ret
-
-.section .boot.data, "aw"
-
-/*
- * The page directory used for kernel remapping.
- */
-.align 4096
-remap_dir:
-.size remap_dir, 4096
-.skip 4096
diff --git a/kernel/src/gdt.rs b/kernel/src/gdt.rs
index 6ce6286f..bcd48015 100644
--- a/kernel/src/gdt.rs
+++ b/kernel/src/gdt.rs
@@ -41,21 +41,32 @@ pub const TSS_OFFSET: usize = 40;
/// The offset of Thread Local Storage (TLS) entries.
pub const TLS_OFFSET: usize = 48;
-/// Structure representing a GDT entry.
-#[repr(transparent)]
+/// A GDT entry.
+#[repr(C, align(8))]
#[derive(Clone, Copy, Default)]
pub struct Entry(pub u64);
impl Entry {
+ /// Creates a new entry with the give information.
+ #[inline(always)]
+ pub const fn new(base: u32, limit: u32, access_byte: u8, flags: u8) -> Self {
+ let mut ent = Self(0);
+ ent.set_base(base);
+ ent.set_limit(limit);
+ ent.set_access_byte(access_byte);
+ ent.set_flags(flags);
+ ent
+ }
+
/// Returns the entry's base address.
#[inline(always)]
- pub fn get_base(&self) -> u32 {
+ pub const fn get_base(&self) -> u32 {
(((self.0 >> 16) & 0xffffff) | ((self.0 >> 32) & 0xff000000)) as _
}
/// Sets the entry's base address.
#[inline(always)]
- pub fn set_base(&mut self, base: u32) {
+ pub const fn set_base(&mut self, base: u32) {
self.0 &= !(0xffffff << 16);
self.0 &= !(0xff << 56);
@@ -65,7 +76,7 @@ impl Entry {
/// Returns the entry's limit.
#[inline(always)]
- pub fn get_limit(&self) -> u32 {
+ pub const fn get_limit(&self) -> u32 {
((self.0 & 0xffff) | (((self.0 >> 48) & 0xf) << 16)) as _
}
@@ -73,7 +84,7 @@ impl Entry {
///
/// If the given limit is more than `pow(2, 20) - 1`, the value is truncated.
#[inline(always)]
- pub fn set_limit(&mut self, limit: u32) {
+ pub const fn set_limit(&mut self, limit: u32) {
self.0 &= !0xffff;
self.0 &= !(0xf << 48);
@@ -83,39 +94,39 @@ impl Entry {
/// Returns the value of the access byte.
#[inline(always)]
- pub fn get_access_byte(&self) -> u8 {
+ pub const fn get_access_byte(&self) -> u8 {
((self.0 >> 40) & 0xff) as _
}
/// Sets the value of the access byte.
#[inline(always)]
- pub fn set_access_byte(&mut self, byte: u8) {
+ pub const fn set_access_byte(&mut self, byte: u8) {
self.0 &= !(0xff << 40);
self.0 |= (byte as u64) << 40;
}
/// Returns the flags.
#[inline(always)]
- pub fn get_flags(&self) -> u8 {
+ pub const fn get_flags(&self) -> u8 {
((self.0 >> 52) & 0x0f) as _
}
/// Sets the flags.
#[inline(always)]
- pub fn set_flags(&mut self, flags: u8) {
+ pub const fn et_flags(&mut self, flags: u8) {
self.0 &= !(0x0f << 52);
self.0 |= ((flags as u64) & 0x0f) << 52;
}
/// Tells whether the entry is present.
#[inline(always)]
- pub fn is_present(&self) -> bool {
+ pub const fn is_present(&self) -> bool {
(self.0 >> 47 & 1) != 0
}
/// Sets the entry present or not.
#[inline(always)]
- pub fn set_present(&mut self, present: bool) {
+ pub const fn set_present(&mut self, present: bool) {
if present {
self.0 |= 1 << 47;
} else {
diff --git a/kernel/src/kernel.rs b/kernel/src/kernel.rs
index 335e947b..177169ed 100644
--- a/kernel/src/kernel.rs
+++ b/kernel/src/kernel.rs
@@ -52,6 +52,7 @@
extern crate alloc;
pub mod acpi;
+mod boot;
pub mod cmdline;
pub mod cpu;
pub mod crypto;
@@ -60,7 +61,7 @@ pub mod device;
pub mod elf;
pub mod event;
pub mod file;
-#[cfg(target_arch = "x86")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod gdt;
#[macro_use]
pub mod idt;
diff --git a/kernel/src/memory/vmem/mod.rs b/kernel/src/memory/vmem/mod.rs
index 9cb2de93..ffd99eaa 100644
--- a/kernel/src/memory/vmem/mod.rs
+++ b/kernel/src/memory/vmem/mod.rs
@@ -19,7 +19,7 @@
//! The virtual memory makes the kernel able to isolate processes, which is
//! essential for modern systems.
-#[cfg(target_arch = "x86")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub mod x86;
use crate::{
diff --git a/mod/build b/mod/build
index ffdb740c..28ec8fd4 100755
--- a/mod/build
+++ b/mod/build
@@ -4,14 +4,14 @@
KERN_SRC=$(realpath $(dirname $0)/..)
if [ -z "$ARCH" ]; then
- ARCH="x86"
+ ARCH="x86_64"
fi
-CARGOFLAGS="--target $KERN_SRC/kernel/arch/$ARCH/$ARCH.json $CARGOFLAGS"
+export CARGOFLAGS="--target $KERN_SRC/kernel/arch/$ARCH/$ARCH.json $CARGOFLAGS"
if [ ! -z "$PROFILE" ] && [ "$PROFILE" != "debug" ]; then
CARGOFLAGS="$CARGOFLAGS --profile $PROFILE"
else
- PROFILE="debug"
+ export PROFILE="debug"
fi
export RUSTFLAGS="--extern kernel=$KERN_SRC/kernel/target/$ARCH/$PROFILE/libkernel.so -L $KERN_SRC/kernel/target/$ARCH/$PROFILE/deps -L $KERN_SRC/kernel/target/$PROFILE/deps $RUSTFLAGS"
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index b375b519..86e3fff4 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,4 @@
[toolchain]
channel = "nightly-2024-09-18"
components = ["rustfmt", "rustc-dev", "rust-src", "clippy", "miri"]
-targets = ["i686-unknown-linux-musl"]
profile = "minimal"