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"