mirror of
https://github.com/llenotre/maestro.git
synced 2024-10-05 16:37:42 +03:00
Merge db625a1683
into b79bb4288b
This commit is contained in:
commit
bb33890d6f
43
.github/workflows/check.yml
vendored
43
.github/workflows/check.yml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
74
kernel/arch/x86_64/linker.ld
Normal file
74
kernel/arch/x86_64/linker.ld
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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*)
|
||||
}
|
||||
}
|
16
kernel/arch/x86_64/x86_64.json
Normal file
16
kernel/arch/x86_64/x86_64.json
Normal file
@ -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"
|
||||
}
|
@ -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
|
@ -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
|
@ -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"
|
||||
|
||||
|
238
kernel/src/boot.rs
Normal file
238
kernel/src/boot.rs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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::<MultibootHeader>() as _,
|
||||
// Compute checksum of the previous values
|
||||
checksum: 0.wrapping_sub(MULTIBOOT_MAGIC + 0 + size_of::<MultibootHeader>()),
|
||||
|
||||
entry_addr_tag: MultibootEntryAddrTag {
|
||||
hdr: MultibootTagHdr {
|
||||
r#type: MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS,
|
||||
flags: 0,
|
||||
size: size_of::<MultibootEntryAddrTag>(),
|
||||
},
|
||||
entry_addr: multiboot_entry as _,
|
||||
},
|
||||
end_tag: MultibootTagHdr {
|
||||
r#type: MULTIBOOT_HEADER_TAG_END,
|
||||
flags: 0,
|
||||
size: size_of::<MultibootTagHdr>(),
|
||||
},
|
||||
};
|
||||
|
||||
/// 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
|
||||
);
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.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
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.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:
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.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
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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::{
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user