mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Adapt Multiboot2 and switch from Limine to Grub2
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
49f2750108
commit
47a51eb423
@ -1,6 +1,6 @@
|
||||
|
||||
[target.'cfg(target_os = "none")']
|
||||
runner = "cargo run --package jinux-boot --"
|
||||
runner = "cargo run --package jinux-build --"
|
||||
|
||||
[alias]
|
||||
kcheck = "check --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem"
|
||||
|
137
Cargo.lock
generated
137
Cargo.lock
generated
@ -92,6 +92,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
@ -110,7 +116,7 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43f9365b6b0c9e1663ca4ca9440c00eda46bc85a3407070be8b5e0d8d1f29629"
|
||||
dependencies = [
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -254,7 +260,7 @@ version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
@ -280,6 +286,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
@ -388,7 +405,7 @@ dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
@ -471,7 +488,6 @@ dependencies = [
|
||||
"jinux-framebuffer",
|
||||
"jinux-std",
|
||||
"jinux-time",
|
||||
"limine",
|
||||
"x86_64",
|
||||
]
|
||||
|
||||
@ -479,7 +495,7 @@ dependencies = [
|
||||
name = "jinux-block"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"component",
|
||||
"jinux-frame",
|
||||
"jinux-pci",
|
||||
@ -487,11 +503,11 @@ dependencies = [
|
||||
"jinux-virtio",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinux-boot"
|
||||
name = "jinux-build"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
@ -506,16 +522,16 @@ dependencies = [
|
||||
"acpi",
|
||||
"align_ext",
|
||||
"aml",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"buddy_system_allocator",
|
||||
"cfg-if",
|
||||
"inherit-methods-macro",
|
||||
"intrusive-collections",
|
||||
"lazy_static",
|
||||
"limine",
|
||||
"log",
|
||||
"multiboot2",
|
||||
"pod",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
"trapframe",
|
||||
"volatile",
|
||||
"x86",
|
||||
@ -530,14 +546,14 @@ dependencies = [
|
||||
"font8x8",
|
||||
"jinux-frame",
|
||||
"log",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinux-input"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"component",
|
||||
"jinux-frame",
|
||||
"jinux-pci",
|
||||
@ -545,7 +561,7 @@ dependencies = [
|
||||
"jinux-virtio",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
"virtio-input-decoder",
|
||||
]
|
||||
|
||||
@ -561,28 +577,28 @@ dependencies = [
|
||||
"log",
|
||||
"ringbuf",
|
||||
"smoltcp",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinux-pci"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"component",
|
||||
"jinux-frame",
|
||||
"jinux-util",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"pod",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinux-rights"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"jinux-rights-proc",
|
||||
"typeflags",
|
||||
"typeflags-util",
|
||||
@ -603,7 +619,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"align_ext",
|
||||
"ascii",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"controlled",
|
||||
"core2",
|
||||
"cpio-decoder",
|
||||
@ -627,7 +643,7 @@ dependencies = [
|
||||
"pod",
|
||||
"ringbuf",
|
||||
"smoltcp",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
"time",
|
||||
"typeflags",
|
||||
"typeflags-util",
|
||||
@ -643,7 +659,7 @@ dependencies = [
|
||||
"component",
|
||||
"jinux-frame",
|
||||
"log",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -662,7 +678,7 @@ name = "jinux-virtio"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"align_ext",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"component",
|
||||
"int-to-c-enum",
|
||||
@ -671,7 +687,7 @@ dependencies = [
|
||||
"jinux-util",
|
||||
"log",
|
||||
"pod",
|
||||
"spin 0.9.4",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -745,15 +761,6 @@ dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "limine"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e9d0c951056ac044f0e6b09448b9d702f8fb1001db89cffd2bc467bd1c25307"
|
||||
dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
@ -819,6 +826,19 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multiboot2"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b624a7b3f704734d98d21455b617607eb7043d4509d1c34bf9e7ff7dd47b31a"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"derive_more",
|
||||
"log",
|
||||
"ptr_meta",
|
||||
"uefi-raw",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "never-say-never"
|
||||
version = "6.6.666"
|
||||
@ -915,6 +935,26 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
@ -936,7 +976,7 @@ version = "10.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1021,7 +1061,7 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"defmt",
|
||||
@ -1038,9 +1078,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.4"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
@ -1189,6 +1229,23 @@ dependencies = [
|
||||
name = "typeflags-util"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "uefi-raw"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62642516099c6441a5f41b0da8486d5fc3515a0603b0fdaea67b31600e22082e"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"ptr_meta",
|
||||
"uguid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uguid"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16dfbd255defbd727b3a30e8950695d2e6d045841ee250ff0f1f7ced17917f8d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
@ -1201,12 +1258,6 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@ -1286,7 +1337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"raw-cpuid",
|
||||
]
|
||||
|
||||
@ -1297,7 +1348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"rustversion",
|
||||
"volatile",
|
||||
]
|
||||
|
@ -8,8 +8,7 @@ name = "jinux"
|
||||
path = "kernel/main.rs"
|
||||
|
||||
[dependencies]
|
||||
limine = "0.1.10"
|
||||
jinux-frame = { path = "framework/jinux-frame" }
|
||||
jinux-frame = { path = "framework/jinux-frame", features = ["multiboot2"] }
|
||||
jinux-std = { path = "services/libs/jinux-std" }
|
||||
component = { path = "services/libs/comp-sys/component" }
|
||||
|
||||
@ -21,7 +20,7 @@ jinux-framebuffer = { path = "services/comps/framebuffer" }
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"boot",
|
||||
"build",
|
||||
"framework/jinux-frame",
|
||||
"services/comps/pci",
|
||||
"services/comps/virtio",
|
||||
|
@ -94,7 +94,7 @@ Then, we can run the following script inside the OS to run all syscall test case
|
||||
|
||||
The codebase of Jinux is organized as below.
|
||||
|
||||
* `boot/`: creating a bootable Jinux kernel image along with an initramfs image.
|
||||
* `build/`: creating a bootable Jinux kernel image along with an initramfs image. It also supports `cargo run` since it is the only package with `main()`.
|
||||
* `kernel/`: defining the entry point of the Jinux kernel.
|
||||
* `framework/`: the privileged half of Jinux (allowed to use `unsafe` keyword)
|
||||
* `jinux-frame`: providing the safe Rust abstractions for low-level resources like CPU, memory, interrupts, etc;
|
||||
|
@ -1,18 +0,0 @@
|
||||
|
||||
# For a detailed description of the limine.cfg format, see CONFIG.md in the Limine repo:
|
||||
# https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md
|
||||
|
||||
TIMEOUT=1
|
||||
SERIAL=yes
|
||||
VERBOSE=yes
|
||||
|
||||
# The name of kernel
|
||||
: Jinux
|
||||
|
||||
PROTOCOL=limine
|
||||
# Tell Limine where to look for the kernel.
|
||||
# The runner (.cargo/runner.sh) will use the name of the package from Cargo.toml,
|
||||
# so change this path if you change that.
|
||||
KERNEL_PATH=boot:///jinux
|
||||
# The path to the module
|
||||
MODULE_PATH=boot:///ramdisk.cpio.gz
|
@ -1,81 +0,0 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
KERNEL_BASE = 0xffffffff80000000;
|
||||
|
||||
SECTIONS {
|
||||
. = KERNEL_BASE + SIZEOF_HEADERS;
|
||||
|
||||
.hash : { *(.hash) }
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.rela : { *(.rela*) }
|
||||
.rodata : { *(.rodata .rodata.*) }
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||
.eh_frame_hdr : {
|
||||
PROVIDE(__eh_frame_hdr = .);
|
||||
KEEP(*(.eh_frame_hdr))
|
||||
PROVIDE(__eh_frame_hdr_end = .);
|
||||
}
|
||||
.eh_frame : {
|
||||
PROVIDE(__eh_frame = .);
|
||||
KEEP(*(.eh_frame))
|
||||
PROVIDE(__eh_frame_end = .);
|
||||
}
|
||||
.gcc_except_table : { KEEP(*(.gcc_except_table .gcc_except_table.*)) }
|
||||
|
||||
. += CONSTANT(MAXPAGESIZE);
|
||||
|
||||
.plt : { *(.plt .plt.*) }
|
||||
.text : { *(.text .text.*) }
|
||||
|
||||
. += CONSTANT(MAXPAGESIZE);
|
||||
|
||||
.tdata : { *(.tdata .tdata.*) }
|
||||
.tbss : { *(.tbss .tbss.*) }
|
||||
|
||||
.data.rel.ro : { *(.data.rel.ro .data.rel.ro.*) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
|
||||
. = ALIGN(4K);
|
||||
sinit_array = .;
|
||||
.init_array : {
|
||||
*(.init_array .init_array.*)
|
||||
}
|
||||
einit_array = .;
|
||||
|
||||
. = DATA_SEGMENT_RELRO_END(0, .);
|
||||
|
||||
.got : { *(.got .got.*) }
|
||||
.got.plt : { *(.got.plt .got.plt.*) }
|
||||
.data : { *(.data .data.*) }
|
||||
.bss : { *(.bss .bss.*) *(COMMON) }
|
||||
|
||||
. = DATA_SEGMENT_END(.);
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
.debug 0 : { *(.debug) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_typenames 0 : { *(.debug_typenames) }
|
||||
.debug_varnames 0 : { *(.debug_varnames) }
|
||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||
.line 0 : { *(.line) }
|
||||
.shstrtab 0 : { *(.shstrtab) }
|
||||
.strtab 0 : { *(.strtab) }
|
||||
.symtab 0 : { *(.symtab) }
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -xe
|
||||
|
||||
LIMINE_GIT_URL="https://github.com/limine-bootloader/limine.git"
|
||||
|
||||
# Cargo passes the path to the built executable as the first argument.
|
||||
KERNEL=$1
|
||||
|
||||
# Clone the `limine` repository if we don't have it yet.
|
||||
if [ ! -d target/limine ]; then
|
||||
git clone $LIMINE_GIT_URL --depth=1 --branch v4.x-branch-binary target/limine
|
||||
fi
|
||||
|
||||
cd target/limine
|
||||
make
|
||||
cd -
|
||||
|
||||
# Copy the needed files into an ISO image.
|
||||
mkdir -p target/iso_root
|
||||
cp $KERNEL target/iso_root/jinux
|
||||
cp boot/limine/conf/limine.cfg target/iso_root
|
||||
cp target/limine/limine.sys target/iso_root
|
||||
cp target/limine/limine-cd.bin target/iso_root
|
||||
cp target/limine/limine-cd-efi.bin target/iso_root
|
||||
|
||||
# Copy ramdisk
|
||||
cp regression/build/ramdisk.cpio.gz target/iso_root
|
||||
|
||||
xorriso -as mkisofs \
|
||||
-b limine-cd.bin \
|
||||
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||
--efi-boot limine-cd-efi.bin \
|
||||
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||
target/iso_root -o $KERNEL.iso
|
||||
|
||||
# For the image to be bootable on BIOS systems, we must run `limine-deploy` on it.
|
||||
target/limine/limine-deploy $KERNEL.iso
|
10
build.rs
10
build.rs
@ -1,13 +1,9 @@
|
||||
use std::error::Error;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
limine_build_script()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn limine_build_script() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
// Have cargo rerun this script if the linker script or CARGO_PKG_ENV changes.
|
||||
println!("cargo:rerun-if-changed=boot/limine/conf/linker.ld");
|
||||
let linker_script_path = "build/grub/conf/linker.ld";
|
||||
println!("cargo:rerun-if-changed={}", linker_script_path);
|
||||
println!("cargo:rustc-link-arg=-T{}", linker_script_path);
|
||||
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
|
||||
|
||||
Ok(())
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "jinux-boot"
|
||||
name = "jinux-build"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -10,6 +10,5 @@ anyhow = "1.0.32"
|
||||
cfg-if = "1.0"
|
||||
|
||||
[features]
|
||||
default = ["limine"]
|
||||
limine = []
|
||||
default = []
|
||||
iommu = []
|
5
build/build.rs
Normal file
5
build/build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use std::error::Error;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
Ok(())
|
||||
}
|
5
build/grub/conf/grub.cfg
Normal file
5
build/grub/conf/grub.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
menuentry 'jinux' {
|
||||
multiboot2 /jinux
|
||||
module2 --nounzip /ramdisk.cpio.gz
|
||||
boot
|
||||
}
|
51
build/grub/conf/linker.ld
Normal file
51
build/grub/conf/linker.ld
Normal file
@ -0,0 +1,51 @@
|
||||
ENTRY(__boot)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
KERNEL_LMA = 0x100000;
|
||||
KERNEL_VMA = 0xffffffff80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = KERNEL_LMA;
|
||||
|
||||
__kernel_start = .;
|
||||
|
||||
.boot : { KEEP(*(.boot)) }
|
||||
|
||||
. += KERNEL_VMA;
|
||||
|
||||
.text : AT(ADDR(.text) - KERNEL_VMA) { *(.text .text.*) }
|
||||
.rodata : AT(ADDR(.rodata) - KERNEL_VMA) { *(.rodata .rodata.*) }
|
||||
|
||||
.data : AT(ADDR(.data) - KERNEL_VMA) { *(.data .data.*) }
|
||||
.bss : AT(ADDR(.bss) - KERNEL_VMA) {
|
||||
__bss = .;
|
||||
*(.bss .bss.*) *(COMMON)
|
||||
__bss_end = .;
|
||||
}
|
||||
|
||||
.tdata : AT(ADDR(.tdata) - KERNEL_VMA) { *(.tdata .tdata.*) }
|
||||
.tbss : AT(ADDR(.tbss) - KERNEL_VMA) { *(.tbss .tbss.*) }
|
||||
|
||||
.init_array : AT(ADDR(.init_array) - KERNEL_VMA) {
|
||||
__sinit_array = .;
|
||||
*(.init_array .init_array.*)
|
||||
__einit_array = .;
|
||||
}
|
||||
|
||||
.data.rel.ro : AT(ADDR(.data.rel.ro) - KERNEL_VMA) { *(.data.rel.ro .data.rel.ro.*) }
|
||||
.dynamic : AT(ADDR(.dynamic) - KERNEL_VMA) { *(.dynamic) }
|
||||
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA) {
|
||||
__eh_frame_hdr = .;
|
||||
KEEP(*(.eh_frame_hdr))
|
||||
__eh_frame_hdr_end = .;
|
||||
}
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) {
|
||||
__eh_frame = .;
|
||||
KEEP(*(.eh_frame))
|
||||
__eh_frame_end = .;
|
||||
}
|
||||
|
||||
__kernel_end = . - KERNEL_VMA;
|
||||
}
|
16
build/grub/scripts/build-grub-image.sh
Executable file
16
build/grub/scripts/build-grub-image.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Cargo passes the path to the built executable as the first argument.
|
||||
KERNEL=$1
|
||||
|
||||
# Copy the needed files into an ISO image.
|
||||
mkdir -p target/iso_root
|
||||
cp $KERNEL target/iso_root/jinux
|
||||
mkdir -p target/iso_root/boot/grub
|
||||
cp build/grub/conf/grub.cfg target/iso_root/boot/grub
|
||||
|
||||
# Copy ramdisk
|
||||
cp regression/build/ramdisk.cpio.gz target/iso_root
|
||||
|
||||
# Make boot device .iso image
|
||||
grub-mkrescue -o $KERNEL.iso target/iso_root
|
@ -16,6 +16,7 @@ const COMMON_ARGS: &[&str] = &[
|
||||
"Icelake-Server,+x2apic",
|
||||
"-m",
|
||||
"2G",
|
||||
"-nographic", // TODO: figure out why grub can't shown up without it
|
||||
"-monitor",
|
||||
"vc",
|
||||
"-serial",
|
||||
@ -73,9 +74,11 @@ fn main() -> anyhow::Result<()> {
|
||||
path.canonicalize().unwrap()
|
||||
};
|
||||
|
||||
#[cfg(feature = "limine")]
|
||||
call_limine_build_script(&kernel_binary_path).unwrap();
|
||||
// add .iso
|
||||
call_bootloader_build_script(
|
||||
&PathBuf::from("build/grub/scripts/build-grub-image.sh"),
|
||||
&kernel_binary_path,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let kernel_iso_path = {
|
||||
let a = kernel_binary_path.parent().unwrap();
|
||||
@ -92,6 +95,7 @@ fn main() -> anyhow::Result<()> {
|
||||
|
||||
let binary_kind = runner_utils::binary_kind(&kernel_binary_path);
|
||||
let mut qemu_args = COMMON_ARGS.clone().to_vec();
|
||||
|
||||
qemu_args.extend(DEVICE_ARGS.clone().to_vec().iter());
|
||||
qemu_args.extend(OPTION_ARGS.clone().to_vec().iter());
|
||||
qemu_args.push("-drive");
|
||||
@ -123,9 +127,12 @@ fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_limine_build_script(path: &PathBuf) -> anyhow::Result<()> {
|
||||
let mut cmd = Command::new("boot/limine/scripts/limine-build.sh");
|
||||
cmd.arg(path.to_str().unwrap());
|
||||
fn call_bootloader_build_script(
|
||||
script_path: &PathBuf,
|
||||
kernel_path: &PathBuf,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut cmd = Command::new(script_path.to_str().unwrap());
|
||||
cmd.arg(kernel_path.to_str().unwrap());
|
||||
let exit_status = cmd.status()?;
|
||||
if !exit_status.success() {
|
||||
std::process::exit(exit_status.code().unwrap_or(1));
|
@ -18,12 +18,13 @@ log = "0.4"
|
||||
lazy_static = { version = "1.0", features = ["spin_no_std"] }
|
||||
trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "e886763" }
|
||||
inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" }
|
||||
multiboot2 = "0.16.0"
|
||||
|
||||
[target.x86_64-custom.dependencies]
|
||||
limine = { version = "0.1.10", features = ["into-uuid"] }
|
||||
x86_64 = "0.14.2"
|
||||
x86 = "0.52.0"
|
||||
acpi = "4.1.1"
|
||||
aml = "0.16.3"
|
||||
|
||||
[features]
|
||||
multiboot2 = []
|
||||
|
@ -1,27 +0,0 @@
|
||||
use crate::config::{self, PAGE_SIZE};
|
||||
use limine::{LimineBootInfoRequest, LimineHhdmRequest, LimineStackSizeRequest};
|
||||
use log::info;
|
||||
|
||||
pub fn init() {
|
||||
if let Some(bootinfo) = BOOTLOADER_INFO_REQUEST.get_response().get() {
|
||||
info!(
|
||||
"booted by {} v{}",
|
||||
bootinfo.name.to_str().unwrap().to_str().unwrap(),
|
||||
bootinfo.version.to_str().unwrap().to_str().unwrap(),
|
||||
);
|
||||
}
|
||||
let response = HHDM_REQUEST
|
||||
.get_response()
|
||||
.get()
|
||||
.expect("Not found HHDM Features");
|
||||
assert_eq!(config::PHYS_OFFSET as u64, response.offset);
|
||||
STACK_REQUEST.get_response().get().unwrap();
|
||||
}
|
||||
|
||||
static BOOTLOADER_INFO_REQUEST: LimineBootInfoRequest = LimineBootInfoRequest::new(0);
|
||||
static HHDM_REQUEST: LimineHhdmRequest = LimineHhdmRequest::new(0);
|
||||
static STACK_REQUEST: LimineStackSizeRequest = {
|
||||
let a = LimineStackSizeRequest::new(0);
|
||||
// 64 * 4096(PAGE_SIZE)
|
||||
a.stack_size(64 * PAGE_SIZE as u64)
|
||||
};
|
122
framework/jinux-frame/src/arch/x86/boot/memory_region.rs
Normal file
122
framework/jinux-frame/src/arch/x86/boot/memory_region.rs
Normal file
@ -0,0 +1,122 @@
|
||||
//! Information of memory regions in the boot phase.
|
||||
//!
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use crate::config::PAGE_SIZE;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
/// The type of initial memory regions that are needed for the kernel.
|
||||
pub enum MemoryRegionType {
|
||||
/// Maybe points to an unplugged DIMM module. It's bad anyway.
|
||||
BadMemory = 0,
|
||||
/// In ACPI spec, this area needs to be preserved when sleeping.
|
||||
NonVolatileSleep = 1,
|
||||
/// Reserved by BIOS or bootloader, do not use.
|
||||
Reserved = 2,
|
||||
/// The place where kernel sections are loaded.
|
||||
Kernel = 3,
|
||||
/// The place where kernel modules (e.g. initrd) are loaded, could be reused.
|
||||
Module = 4,
|
||||
/// The memory region provided as the framebuffer.
|
||||
Framebuffer = 5,
|
||||
/// Once used in the boot phase. Kernel can reclaim it after initialization.
|
||||
Reclaimable = 6,
|
||||
/// Directly usable by the frame allocator.
|
||||
Usable = 7,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
/// The information of initial memory regions that are needed by the kernel.
|
||||
/// The sections are **not** guaranteed to not overlap. The region must be page aligned.
|
||||
pub struct MemoryRegion {
|
||||
base: usize,
|
||||
len: usize,
|
||||
typ: MemoryRegionType,
|
||||
}
|
||||
|
||||
impl MemoryRegion {
|
||||
/// Construct a page aligned memory region.
|
||||
pub fn new(base: usize, len: usize, typ: MemoryRegionType) -> Self {
|
||||
let aligned_base;
|
||||
let aligned_end;
|
||||
match typ {
|
||||
MemoryRegionType::Usable | MemoryRegionType::Reclaimable => {
|
||||
// Align shrinked.
|
||||
aligned_base = base.align_up(PAGE_SIZE);
|
||||
aligned_end = (base + len).align_down(PAGE_SIZE);
|
||||
}
|
||||
_ => {
|
||||
// Align bloated.
|
||||
aligned_base = base.align_down(PAGE_SIZE);
|
||||
aligned_end = (base + len).align_up(PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
MemoryRegion {
|
||||
base: aligned_base,
|
||||
len: aligned_end - aligned_base,
|
||||
typ: typ,
|
||||
}
|
||||
}
|
||||
|
||||
/// The physical address of the base of the region.
|
||||
pub fn base(&self) -> usize {
|
||||
self.base
|
||||
}
|
||||
|
||||
/// The length in bytes of the region.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// The type of the region.
|
||||
pub fn typ(&self) -> MemoryRegionType {
|
||||
self.typ
|
||||
}
|
||||
|
||||
/// Remove range t from self, resulting in 0, 1 or 2 truncated ranges.
|
||||
/// We need to have this method since memory regions can overlap.
|
||||
pub fn truncate(&self, t: MemoryRegion) -> Vec<MemoryRegion> {
|
||||
if self.base < t.base {
|
||||
if self.base + self.len > t.base {
|
||||
if self.base + self.len > t.base + t.len {
|
||||
vec![
|
||||
MemoryRegion {
|
||||
base: self.base,
|
||||
len: t.base - self.base,
|
||||
typ: self.typ,
|
||||
},
|
||||
MemoryRegion {
|
||||
base: t.base + t.len,
|
||||
len: self.base + self.len - (t.base + t.len),
|
||||
typ: self.typ,
|
||||
},
|
||||
]
|
||||
} else {
|
||||
vec![MemoryRegion {
|
||||
base: self.base,
|
||||
len: t.base - self.base,
|
||||
typ: self.typ,
|
||||
}]
|
||||
}
|
||||
} else {
|
||||
vec![*self]
|
||||
}
|
||||
} else {
|
||||
if self.base < t.base + t.len {
|
||||
if self.base + self.len > t.base + t.len {
|
||||
vec![MemoryRegion {
|
||||
base: t.base + t.len,
|
||||
len: self.base + self.len - (t.base + t.len),
|
||||
typ: self.typ,
|
||||
}]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
} else {
|
||||
vec![*self]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,94 @@
|
||||
mod limine;
|
||||
//! The boot module defines the entrypoints of Jinux and the corresponding
|
||||
//! headers for different bootloaders.
|
||||
//!
|
||||
//! We currently support Multiboot2 and the Limine Boot Protocol. The
|
||||
//! support for Linux boot protocol is on its way.
|
||||
//!
|
||||
//! In this module, we use println! to print information on screen rather
|
||||
//! than logging since the logger is not initialized here.
|
||||
//!
|
||||
|
||||
/// init bootloader
|
||||
pub fn init() {
|
||||
limine::init();
|
||||
#[cfg(feature = "multiboot2")]
|
||||
pub mod multiboot2;
|
||||
#[cfg(feature = "multiboot2")]
|
||||
use self::multiboot2::*;
|
||||
|
||||
pub mod memory_region;
|
||||
pub use memory_region::*;
|
||||
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use spin::Once;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// The boot crate can choose either providing the raw RSDP physical address or
|
||||
/// providing the RSDT/XSDT physical address after parsing RSDP.
|
||||
/// This is because bootloaders differ in such behaviors.
|
||||
pub enum BootloaderAcpiArg {
|
||||
/// Physical address of the RSDP.
|
||||
Rsdp(usize),
|
||||
/// Address of RSDT provided in RSDP v1.
|
||||
Rsdt(usize),
|
||||
/// Address of XSDT provided in RSDP v2+.
|
||||
Xsdt(usize),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// The framebuffer arguments.
|
||||
pub struct BootloaderFramebufferArg {
|
||||
pub address: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
/// Bits per pixel of the buffer.
|
||||
pub bpp: usize,
|
||||
}
|
||||
|
||||
/// After initializing the boot module, the get_* functions could be called.
|
||||
/// The initialization must be done after the heap is set and before physical
|
||||
/// mappings are cancelled.
|
||||
pub fn init() {
|
||||
init_bootloader_name();
|
||||
init_kernel_commandline();
|
||||
init_initramfs();
|
||||
init_acpi_rsdp();
|
||||
init_framebuffer_info();
|
||||
init_memory_regions();
|
||||
}
|
||||
|
||||
// The public get_* APIs.
|
||||
|
||||
static BOOTLOADER_NAME: Once<String> = Once::new();
|
||||
/// Get the name and the version of the bootloader.
|
||||
pub fn get_bootloader_name() -> String {
|
||||
BOOTLOADER_NAME.get().unwrap().clone()
|
||||
}
|
||||
|
||||
static KERNEL_COMMANDLINE: Once<String> = Once::new();
|
||||
/// Get the raw unparsed kernel commandline string.
|
||||
pub fn get_kernel_commandline() -> String {
|
||||
KERNEL_COMMANDLINE.get().unwrap().clone()
|
||||
}
|
||||
|
||||
static INITRAMFS: Once<&'static [u8]> = Once::new();
|
||||
/// The slice of the bootloader-loaded init ram disk.
|
||||
pub fn get_initramfs() -> &'static [u8] {
|
||||
INITRAMFS.get().unwrap()
|
||||
}
|
||||
|
||||
static ACPI_RSDP: Once<BootloaderAcpiArg> = Once::new();
|
||||
/// The ACPI RDSP/XSDT address.
|
||||
pub fn get_acpi_rsdp() -> BootloaderAcpiArg {
|
||||
ACPI_RSDP.get().unwrap().clone()
|
||||
}
|
||||
|
||||
static FRAMEBUFFER_INFO: Once<BootloaderFramebufferArg> = Once::new();
|
||||
/// Framebuffer information.
|
||||
pub fn get_framebuffer_info() -> BootloaderFramebufferArg {
|
||||
FRAMEBUFFER_INFO.get().unwrap().clone()
|
||||
}
|
||||
|
||||
static MEMORY_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
|
||||
/// Get memory regions.
|
||||
/// The returned usable memory regions are guarenteed to not overlap with other unusable ones.
|
||||
pub fn get_memory_regions() -> Vec<MemoryRegion> {
|
||||
MEMORY_REGIONS.get().unwrap().clone()
|
||||
}
|
||||
|
276
framework/jinux-frame/src/arch/x86/boot/multiboot2/boot.S
Normal file
276
framework/jinux-frame/src/arch/x86/boot/multiboot2/boot.S
Normal file
@ -0,0 +1,276 @@
|
||||
// The boot header, initial boot setup code, temporary GDT and page tables are
|
||||
// in the boot section. The boot section is mapped writable since kernel may
|
||||
// modify the initial page table.
|
||||
.section ".boot", "awx"
|
||||
.code32
|
||||
|
||||
// The entry point of our ELF target.
|
||||
.global __boot
|
||||
__boot:
|
||||
jmp initial_boot_setup
|
||||
|
||||
// This is the GNU Multiboot 2 header.
|
||||
// Reference: https://www.gnu.org/software/grub/manual/multiboot2/html_node/Index.html//Index
|
||||
|
||||
// Macros for cleaner code in the header fields.
|
||||
MB2_MAGIC = 0xE85250D6
|
||||
MB2_ARCHITECTURE = 0 // 32-bit (protected) mode of i386
|
||||
MB2_HEADERLEN = header_end - header_start
|
||||
MB2_CHECKSUM = -(MB2_MAGIC + MB2_ARCHITECTURE + MB2_HEADERLEN)
|
||||
|
||||
header_start:
|
||||
.align 8
|
||||
|
||||
.long MB2_MAGIC
|
||||
.long MB2_ARCHITECTURE
|
||||
.long MB2_HEADERLEN
|
||||
.long MB2_CHECKSUM
|
||||
|
||||
// Tag: information request
|
||||
.align 8
|
||||
info_request:
|
||||
.short 1
|
||||
.short 0 // Required
|
||||
.long info_request_end - info_request
|
||||
.long 6 // Memory map request
|
||||
.long 15 // ACPI (new) request
|
||||
info_request_end:
|
||||
|
||||
// Tag: header end
|
||||
.align 8
|
||||
.short 0 // type: tags end
|
||||
.short 0 // flags
|
||||
.long 8 // size
|
||||
header_end:
|
||||
|
||||
initial_boot_setup:
|
||||
cli
|
||||
cld
|
||||
|
||||
// Set the kernel call stack.
|
||||
mov esp, offset boot_stack_top
|
||||
|
||||
// Save the multiboot magic and 64-bit physical address of multiboot info onto the stack.
|
||||
push 0 // Upper 32-bits.
|
||||
push eax
|
||||
push 0 // Upper 32-bits.
|
||||
push ebx
|
||||
|
||||
// Prepare for far return. We use a far return as a fence after setting GDT.
|
||||
mov eax, 24
|
||||
push eax
|
||||
lea edx, [protected_mode]
|
||||
push edx
|
||||
|
||||
// Switch to our own temporary GDT.
|
||||
lgdt [boot_gdtr]
|
||||
retf
|
||||
|
||||
protected_mode:
|
||||
mov ax, 16
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
page_table_setup:
|
||||
// Zero out the page table.
|
||||
mov al, 0x00
|
||||
lea edi, [boot_page_table_start]
|
||||
lea ecx, [boot_page_table_end]
|
||||
sub ecx, edi
|
||||
cld
|
||||
rep stosb
|
||||
|
||||
// PTE flags used in this file.
|
||||
PTE_PRESENT = (1)
|
||||
PTE_WRITE = (1 << 1)
|
||||
PTE_HUGE = (1 << 7)
|
||||
PTE_GLOBAL = (1 << 8)
|
||||
|
||||
// PML4: 0x00000000_00000000 ~ 0x00000000_3fffffff
|
||||
// 0x00000000_40000000 ~ 0x00000000_7fffffff
|
||||
// 0x00000000_80000000 ~ 0x00000000_bfffffff
|
||||
// 0x00000000_c0000000 ~ 0x00000000_ffffffff
|
||||
lea edi, [boot_pml4]
|
||||
lea eax, [boot_pdpt + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PML4: 0xffff8000_00000000 ~ 0xffff8000_3fffffff
|
||||
// 0xffff8000_40000000 ~ 0xffff8000_7fffffff
|
||||
// 0xffff8000_80000000 ~ 0xffff8000_bfffffff
|
||||
// 0xffff8000_c0000000 ~ 0xffff8000_ffffffff
|
||||
lea edi, [boot_pml4 + 0x100 * 8]
|
||||
lea eax, [boot_pdpt + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PML4: 0xffffffff_80000000 ~ 0xffffffff_bfffffff
|
||||
// 0xffffffff_c0000000 ~ 0xffffffff_ffffffff
|
||||
lea edi, [boot_pml4 + 0x1ff * 8]
|
||||
lea eax, [boot_pdpt + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0x00000000_00000000 ~ 0x00000000_3fffffff
|
||||
lea edi, [boot_pdpt]
|
||||
lea eax, [boot_pd_0g_1g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0x00000000_40000000 ~ 0x00000000_7fffffff
|
||||
lea edi, [boot_pdpt + 0x1 * 8]
|
||||
lea eax, [boot_pd_1g_2g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0x00000000_80000000 ~ 0x00000000_bfffffff
|
||||
lea edi, [boot_pdpt + 0x2 * 8]
|
||||
lea eax, [boot_pd_2g_3g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0x00000000_c0000000 ~ 0x00000000_ffffffff
|
||||
lea edi, [boot_pdpt + 0x3 * 8]
|
||||
lea eax, [boot_pd_3g_4g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0xffffffff_80000000 ~ 0xffffffff_bfffffff
|
||||
lea edi, [boot_pdpt + 0x1fe * 8]
|
||||
lea eax, [boot_pd_0g_1g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// PDPT: 0xffffffff_c0000000 ~ 0xffffffff_ffffffff
|
||||
lea edi, [boot_pdpt + 0x1ff * 8]
|
||||
lea eax, [boot_pd_1g_2g + (PTE_PRESENT | PTE_WRITE | PTE_GLOBAL)]
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
|
||||
// Page Directory: map to low 1 GiB * 4 space
|
||||
lea edi, [boot_pd]
|
||||
mov eax, PTE_PRESENT | PTE_WRITE | PTE_HUGE | PTE_GLOBAL
|
||||
mov ecx, 512 * 4 // (of entries in PD) * (number of PD)
|
||||
|
||||
write_pd_entry:
|
||||
mov dword ptr [edi], eax
|
||||
mov dword ptr [edi + 4], 0
|
||||
add eax, 0x200000 // 2 MiB
|
||||
add edi, 8
|
||||
loop write_pd_entry
|
||||
|
||||
jmp enable_long_mode
|
||||
|
||||
enable_long_mode:
|
||||
// Enable PAE and PGE.
|
||||
mov eax, cr4
|
||||
or eax, 0xa0
|
||||
mov cr4, eax
|
||||
|
||||
// Set the page table address.
|
||||
lea eax, [boot_pml4]
|
||||
mov cr3, eax
|
||||
|
||||
// Enable long mode.
|
||||
mov ecx, 0xc0000080
|
||||
rdmsr
|
||||
or eax, 0x0100
|
||||
wrmsr
|
||||
|
||||
// Prepare for far return.
|
||||
mov eax, 8
|
||||
push eax
|
||||
lea edx, [long_mode_in_low_address]
|
||||
push edx
|
||||
|
||||
// Enable paging.
|
||||
mov eax, cr0
|
||||
or eax, 0x80000000
|
||||
mov cr0, eax
|
||||
|
||||
retf
|
||||
|
||||
// Temporary GDTR/GDT entries. This must be located in the .boot section as its
|
||||
// address (gdt) must be physical to load.
|
||||
.align 16
|
||||
.global boot_gdtr
|
||||
boot_gdtr:
|
||||
.word gdt_end - gdt - 1
|
||||
.quad gdt
|
||||
|
||||
.align 16
|
||||
gdt:
|
||||
.quad 0x0000000000000000 // 0: null descriptor
|
||||
.quad 0x00af9a000000ffff // 8: 64-bit code segment (kernel)
|
||||
.quad 0x00cf92000000ffff // 16: 64-bit data segment (kernel)
|
||||
.quad 0x00cf9a000000ffff // 24: 32-bit code segment (kernel)
|
||||
gdt_end:
|
||||
|
||||
// The page tables and the stack
|
||||
.align 4096
|
||||
|
||||
boot_page_table_start:
|
||||
boot_pml4:
|
||||
.skip 4096
|
||||
boot_pdpt:
|
||||
.skip 4096
|
||||
boot_pd:
|
||||
boot_pd_0g_1g:
|
||||
.skip 4096
|
||||
boot_pd_1g_2g:
|
||||
.skip 4096
|
||||
boot_pd_2g_3g:
|
||||
.skip 4096
|
||||
boot_pd_3g_4g:
|
||||
.skip 4096
|
||||
boot_page_table_end:
|
||||
|
||||
boot_stack_bottom:
|
||||
.skip 0x40000
|
||||
boot_stack_top:
|
||||
|
||||
.code64
|
||||
long_mode_in_low_address:
|
||||
mov ax, 0
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
|
||||
// Update RSP/RIP to use the virtual address.
|
||||
mov rbx, 0xffffffff80000000
|
||||
or rsp, rbx
|
||||
lea rax, [long_mode - 0xffffffff80000000]
|
||||
or rax, rbx
|
||||
jmp rax
|
||||
|
||||
// From here, we're in the .text section: we no longer use physical address.
|
||||
.code64
|
||||
.text
|
||||
long_mode:
|
||||
// Clear .bss section.
|
||||
mov al, 0x00
|
||||
lea rdi, [rip + __bss]
|
||||
lea rcx, [rip + __bss_end]
|
||||
sub rcx, rdi
|
||||
cld
|
||||
rep stosb
|
||||
|
||||
pop rsi // the address of multiboot info
|
||||
pop rdi // multiboot magic
|
||||
|
||||
// Clear the frame pointer to stop backtracing here.
|
||||
xor rbp, rbp
|
||||
|
||||
lea rax, [rip + boot] // jump into Rust code
|
||||
call rax
|
||||
|
||||
// In case boot() returns.
|
||||
halt:
|
||||
cli
|
||||
hlt
|
||||
jmp halt
|
195
framework/jinux-frame/src/arch/x86/boot/multiboot2/mod.rs
Normal file
195
framework/jinux-frame/src/arch/x86/boot/multiboot2/mod.rs
Normal file
@ -0,0 +1,195 @@
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use multiboot2::{BootInformation, BootInformationHeader, MemoryAreaType};
|
||||
|
||||
use super::{
|
||||
BootloaderAcpiArg, BootloaderFramebufferArg, MemoryRegion, MemoryRegionType, ACPI_RSDP,
|
||||
BOOTLOADER_NAME, FRAMEBUFFER_INFO, INITRAMFS, KERNEL_COMMANDLINE, MEMORY_REGIONS,
|
||||
};
|
||||
use core::{arch::global_asm, mem::swap};
|
||||
use spin::Once;
|
||||
|
||||
use crate::{config::PHYS_OFFSET, vm::paddr_to_vaddr};
|
||||
|
||||
global_asm!(include_str!("boot.S"));
|
||||
|
||||
static MB2_INFO: Once<BootInformation> = Once::new();
|
||||
|
||||
pub fn init_bootloader_name() {
|
||||
BOOTLOADER_NAME.call_once(|| {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.boot_loader_name_tag()
|
||||
.expect("Bootloader name not found from the Multiboot2 header!")
|
||||
.name()
|
||||
.expect("UTF-8 error: failed to parse bootloader name!")
|
||||
.to_string()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_kernel_commandline() {
|
||||
KERNEL_COMMANDLINE.call_once(|| {
|
||||
MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.command_line_tag()
|
||||
.expect("Kernel commandline not found from the Multiboot2 header!")
|
||||
.cmdline()
|
||||
.expect("UTF-8 error: failed to parse kernel commandline!")
|
||||
.to_string()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_initramfs() {
|
||||
let mb2_module_tag = MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.module_tags()
|
||||
.next()
|
||||
.expect("No Multiboot2 modules found!");
|
||||
let base_addr = mb2_module_tag.start_address() as usize;
|
||||
// We must return a slice composed by VA since kernel should read every in VA.
|
||||
let base_va = if base_addr < PHYS_OFFSET {
|
||||
paddr_to_vaddr(base_addr)
|
||||
} else {
|
||||
base_addr
|
||||
};
|
||||
let length = mb2_module_tag.module_size() as usize;
|
||||
INITRAMFS.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
||||
}
|
||||
|
||||
pub fn init_acpi_rsdp() {
|
||||
ACPI_RSDP.call_once(|| {
|
||||
if let Some(v2_tag) = MB2_INFO.get().unwrap().rsdp_v2_tag() {
|
||||
// check for rsdp v2
|
||||
BootloaderAcpiArg::Xsdt(v2_tag.xsdt_address())
|
||||
} else if let Some(v1_tag) = MB2_INFO.get().unwrap().rsdp_v1_tag() {
|
||||
// fall back to rsdp v1
|
||||
BootloaderAcpiArg::Rsdt(v1_tag.rsdt_address())
|
||||
} else {
|
||||
panic!("No ACPI RDSP information found!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_framebuffer_info() {
|
||||
let fb_tag = MB2_INFO.get().unwrap().framebuffer_tag().unwrap().unwrap();
|
||||
FRAMEBUFFER_INFO.call_once(|| BootloaderFramebufferArg {
|
||||
address: fb_tag.address() as usize,
|
||||
width: fb_tag.width() as usize,
|
||||
height: fb_tag.height() as usize,
|
||||
bpp: fb_tag.bpp() as usize,
|
||||
});
|
||||
}
|
||||
|
||||
impl From<MemoryAreaType> for MemoryRegionType {
|
||||
fn from(value: MemoryAreaType) -> Self {
|
||||
match value {
|
||||
MemoryAreaType::Available => Self::Usable,
|
||||
MemoryAreaType::Reserved => Self::Reserved,
|
||||
MemoryAreaType::AcpiAvailable => Self::Reclaimable,
|
||||
MemoryAreaType::ReservedHibernate => Self::NonVolatileSleep,
|
||||
_ => Self::BadMemory,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_memory_regions() {
|
||||
// We should later use regions in `regions_unusable` to truncate all
|
||||
// regions in `regions_usable`.
|
||||
// The difference is that regions in `regions_usable` could be used by
|
||||
// the frame allocator.
|
||||
let mut regions_usable = Vec::<MemoryRegion>::new();
|
||||
let mut regions_unusable = Vec::<MemoryRegion>::new();
|
||||
|
||||
// Add the regions returned by Grub.
|
||||
let memory_regions_tag = MB2_INFO
|
||||
.get()
|
||||
.unwrap()
|
||||
.memory_map_tag()
|
||||
.expect("Memory region not found from the Multiboot2 header!");
|
||||
let num_memory_regions = memory_regions_tag.memory_areas().len();
|
||||
for i in 0..num_memory_regions {
|
||||
let start = memory_regions_tag.memory_areas()[i].start_address();
|
||||
let end = memory_regions_tag.memory_areas()[i].end_address();
|
||||
let area_typ: MemoryRegionType = memory_regions_tag.memory_areas()[i].typ().into();
|
||||
let region = MemoryRegion::new(
|
||||
start.try_into().unwrap(),
|
||||
(end - start).try_into().unwrap(),
|
||||
area_typ,
|
||||
);
|
||||
match area_typ {
|
||||
MemoryRegionType::Usable | MemoryRegionType::Reclaimable => {
|
||||
regions_usable.push(region);
|
||||
}
|
||||
_ => {
|
||||
regions_unusable.push(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add the framebuffer region since Grub does not specify it.
|
||||
let fb_tag = MB2_INFO.get().unwrap().framebuffer_tag().unwrap().unwrap();
|
||||
let fb = BootloaderFramebufferArg {
|
||||
address: fb_tag.address() as usize,
|
||||
width: fb_tag.width() as usize,
|
||||
height: fb_tag.height() as usize,
|
||||
bpp: fb_tag.bpp() as usize,
|
||||
};
|
||||
regions_unusable.push(MemoryRegion::new(
|
||||
fb.address,
|
||||
(fb.width * fb.height * fb.bpp + 7) / 8, // round up when divide with 8 (bits/Byte)
|
||||
MemoryRegionType::Framebuffer,
|
||||
));
|
||||
// Add the kernel region since Grub does not specify it.
|
||||
// These are physical addresses provided by the linker script.
|
||||
extern "C" {
|
||||
fn __kernel_start();
|
||||
fn __kernel_end();
|
||||
}
|
||||
regions_unusable.push(MemoryRegion::new(
|
||||
__kernel_start as usize,
|
||||
__kernel_end as usize - __kernel_start as usize,
|
||||
MemoryRegionType::Kernel,
|
||||
));
|
||||
// Add the boot module region since Grub does not specify it.
|
||||
let mb2_module_tag = MB2_INFO.get().unwrap().module_tags();
|
||||
for m in mb2_module_tag {
|
||||
regions_unusable.push(MemoryRegion::new(
|
||||
m.start_address() as usize,
|
||||
m.module_size() as usize,
|
||||
MemoryRegionType::Module,
|
||||
));
|
||||
}
|
||||
|
||||
// `regions_*` are 2 rolling vectors since we are going to truncate
|
||||
// the regions in a iterative manner.
|
||||
let mut regions = Vec::<MemoryRegion>::new();
|
||||
let regions_src = &mut regions_usable;
|
||||
let regions_dst = &mut regions;
|
||||
// Truncate the usable regions.
|
||||
for &r_unusable in ®ions_unusable {
|
||||
regions_dst.clear();
|
||||
for r_usable in &*regions_src {
|
||||
regions_dst.append(&mut r_usable.truncate(r_unusable));
|
||||
}
|
||||
swap(regions_src, regions_dst);
|
||||
}
|
||||
|
||||
// Initialize with regions_unusable + regions_src
|
||||
regions_unusable.append(regions_src);
|
||||
MEMORY_REGIONS.call_once(|| regions_unusable);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
fn jinux_main() -> !;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
/// The entry point of Rust code called by inline asm.
|
||||
unsafe extern "C" fn boot(boot_magic: u32, boot_params: u64) -> ! {
|
||||
assert_eq!(boot_magic, 0x36d76289_u32);
|
||||
MB2_INFO.call_once(|| unsafe {
|
||||
BootInformation::load(boot_params as *const BootInformationHeader).unwrap()
|
||||
});
|
||||
jinux_main();
|
||||
}
|
@ -87,6 +87,10 @@ impl PageTableFlagsTrait for PageTableFlags {
|
||||
self.contains(Self::ACCESSED)
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.contains(Self::DIRTY)
|
||||
}
|
||||
|
||||
fn accessible_by_user(&self) -> bool {
|
||||
true
|
||||
}
|
||||
@ -102,6 +106,16 @@ impl PageTableFlagsTrait for PageTableFlags {
|
||||
fn insert(&mut self, flags: &Self) {
|
||||
self.insert(*flags)
|
||||
}
|
||||
|
||||
fn is_huge(&self) -> bool {
|
||||
// FIXME: this is super bad
|
||||
false
|
||||
}
|
||||
|
||||
fn set_huge(self, huge: bool) -> Self {
|
||||
// FIXME: this is super bad
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableEntry {
|
||||
|
@ -6,9 +6,9 @@ use core::{
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use crate::{config, vm::paddr_to_vaddr};
|
||||
use crate::arch::boot::{self, BootloaderAcpiArg};
|
||||
use crate::vm::paddr_to_vaddr;
|
||||
use acpi::{sdt::SdtHeader, AcpiHandler, AcpiTable, AcpiTables};
|
||||
use limine::LimineRsdpRequest;
|
||||
use log::info;
|
||||
use spin::{Mutex, Once};
|
||||
|
||||
@ -89,17 +89,18 @@ impl AcpiHandler for AcpiMemoryHandler {
|
||||
fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {}
|
||||
}
|
||||
|
||||
static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0);
|
||||
|
||||
pub fn init() {
|
||||
let response = RSDP_REQUEST
|
||||
.get_response()
|
||||
.get()
|
||||
.expect("Need RSDP address");
|
||||
let rsdp = response.address.as_ptr().unwrap().addr() - config::PHYS_OFFSET;
|
||||
// Safety: The RSDP is the value provided by bootloader.
|
||||
let acpi_tables =
|
||||
unsafe { AcpiTables::from_rsdp(AcpiMemoryHandler {}, rsdp as usize).unwrap() };
|
||||
let acpi_tables = match boot::get_acpi_rsdp() {
|
||||
BootloaderAcpiArg::Rsdp(addr) => unsafe {
|
||||
AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr as usize).unwrap()
|
||||
},
|
||||
BootloaderAcpiArg::Rsdt(addr) => unsafe {
|
||||
AcpiTables::from_rsdt(AcpiMemoryHandler {}, 0, addr as usize).unwrap()
|
||||
},
|
||||
BootloaderAcpiArg::Xsdt(addr) => unsafe {
|
||||
AcpiTables::from_rsdt(AcpiMemoryHandler {}, 1, addr as usize).unwrap()
|
||||
},
|
||||
};
|
||||
|
||||
for (signature, sdt) in acpi_tables.sdts.iter() {
|
||||
info!("ACPI found signature:{:?}", signature);
|
||||
|
@ -1,6 +1,4 @@
|
||||
use alloc::{collections::BTreeMap, fmt, vec::Vec};
|
||||
use limine::{LimineMemmapEntry, LimineMemmapRequest, LimineMemoryMapEntryType};
|
||||
use log::debug;
|
||||
use alloc::{collections::BTreeMap, fmt};
|
||||
use pod::Pod;
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::paging::PhysFrame;
|
||||
@ -9,7 +7,7 @@ use crate::{
|
||||
config::ENTRY_COUNT,
|
||||
vm::{
|
||||
page_table::{table_of, PageTableEntryTrait, PageTableFlagsTrait},
|
||||
MemoryRegions, MemoryRegionsType, Paddr,
|
||||
Paddr,
|
||||
},
|
||||
};
|
||||
|
||||
@ -31,6 +29,10 @@ bitflags::bitflags! {
|
||||
const NO_CACHE = 1 << 4;
|
||||
/// Whether this entry has been used for linear-address translation.
|
||||
const ACCESSED = 1 << 5;
|
||||
/// Whether the memory area represented by this entry is modified.
|
||||
const DIRTY = 1 << 6;
|
||||
/// Only in the non-starting and non-ending levels, indication of huge page.
|
||||
const HUGE = 1 << 7;
|
||||
/// Indicates that the mapping is present in all address spaces, so it isn't flushed from
|
||||
/// the TLB on an address space switch.
|
||||
const GLOBAL = 1 << 8;
|
||||
@ -52,20 +54,6 @@ pub unsafe fn activate_page_table(root_paddr: Paddr, flags: x86_64::registers::c
|
||||
|
||||
pub static ALL_MAPPED_PTE: Mutex<BTreeMap<usize, PageTableEntry>> = Mutex::new(BTreeMap::new());
|
||||
|
||||
/// Get memory regions, this function should call after the heap was initialized
|
||||
pub fn get_memory_regions() -> Vec<MemoryRegions> {
|
||||
let mut memory_regions = Vec::new();
|
||||
let response = MEMMAP_REQUEST
|
||||
.get_response()
|
||||
.get()
|
||||
.expect("Not found memory region information");
|
||||
for i in response.memmap() {
|
||||
debug!("Found memory region:{:x?}", **i);
|
||||
memory_regions.push(MemoryRegions::from(&**i));
|
||||
}
|
||||
memory_regions
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let (page_directory_base, _) = x86_64::registers::control::Cr3::read();
|
||||
let page_directory_base = page_directory_base.start_address().as_u64() as usize;
|
||||
@ -137,6 +125,10 @@ impl PageTableFlagsTrait for PageTableFlags {
|
||||
self.contains(Self::ACCESSED)
|
||||
}
|
||||
|
||||
fn is_dirty(&self) -> bool {
|
||||
self.contains(Self::DIRTY)
|
||||
}
|
||||
|
||||
fn union(&self, flags: &Self) -> Self {
|
||||
(*self).union(*flags)
|
||||
}
|
||||
@ -148,6 +140,15 @@ impl PageTableFlagsTrait for PageTableFlags {
|
||||
fn insert(&mut self, flags: &Self) {
|
||||
self.insert(*flags)
|
||||
}
|
||||
|
||||
fn is_huge(&self) -> bool {
|
||||
self.contains(Self::HUGE)
|
||||
}
|
||||
|
||||
fn set_huge(mut self, huge: bool) -> Self {
|
||||
self.set(Self::HUGE, huge);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableEntry {
|
||||
@ -193,30 +194,3 @@ impl fmt::Debug for PageTableEntry {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest::new(0);
|
||||
|
||||
impl From<&LimineMemmapEntry> for MemoryRegions {
|
||||
fn from(value: &LimineMemmapEntry) -> Self {
|
||||
Self {
|
||||
base: value.base,
|
||||
len: value.len,
|
||||
typ: MemoryRegionsType::from(value.typ),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LimineMemoryMapEntryType> for MemoryRegionsType {
|
||||
fn from(value: LimineMemoryMapEntryType) -> Self {
|
||||
match value {
|
||||
LimineMemoryMapEntryType::Usable => Self::Usable,
|
||||
LimineMemoryMapEntryType::Reserved => Self::Reserved,
|
||||
LimineMemoryMapEntryType::AcpiReclaimable => Self::AcpiReclaimable,
|
||||
LimineMemoryMapEntryType::AcpiNvs => Self::AcpiNvs,
|
||||
LimineMemoryMapEntryType::BadMemory => Self::BadMemory,
|
||||
LimineMemoryMapEntryType::BootloaderReclaimable => Self::BootloaderReclaimable,
|
||||
LimineMemoryMapEntryType::KernelAndModules => Self::KernelAndModules,
|
||||
LimineMemoryMapEntryType::Framebuffer => Self::Framebuffer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod boot;
|
||||
pub mod boot;
|
||||
pub(crate) mod cpu;
|
||||
pub mod device;
|
||||
pub mod iommu;
|
||||
|
@ -8,8 +8,8 @@
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_ops)]
|
||||
#![feature(generators)]
|
||||
@ -23,6 +23,7 @@ pub mod bus;
|
||||
pub mod config;
|
||||
pub mod cpu;
|
||||
mod error;
|
||||
mod heap_allocator;
|
||||
pub mod logger;
|
||||
pub mod io_mem;
|
||||
pub mod prelude;
|
||||
@ -39,14 +40,13 @@ pub use self::error::Error;
|
||||
pub use self::prelude::Result;
|
||||
use alloc::vec::Vec;
|
||||
use core::{mem, panic::PanicInfo};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use limine::{LimineFramebufferRequest, LimineModuleRequest};
|
||||
use trap::{IrqCallbackHandle, IrqLine};
|
||||
use trapframe::TrapFrame;
|
||||
|
||||
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
|
||||
|
||||
pub fn init() {
|
||||
heap_allocator::init();
|
||||
arch::before_all_init();
|
||||
logger::init();
|
||||
vm::init();
|
||||
@ -68,13 +68,13 @@ fn register_irq_common_callback() {
|
||||
|
||||
fn invoke_c_init_funcs() {
|
||||
extern "C" {
|
||||
fn sinit_array();
|
||||
fn einit_array();
|
||||
fn __sinit_array();
|
||||
fn __einit_array();
|
||||
}
|
||||
let call_len = (einit_array as u64 - sinit_array as u64) / 8;
|
||||
let call_len = (__einit_array as u64 - __sinit_array as u64) / 8;
|
||||
for i in 0..call_len {
|
||||
unsafe {
|
||||
let address = (sinit_array as u64 + 8 * i) as *const u64;
|
||||
let address = (__sinit_array as u64 + 8 * i) as *const u64;
|
||||
let function = address as *const fn();
|
||||
(*function)();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use spin::Once;
|
||||
|
||||
use crate::{config::PAGE_SIZE, sync::SpinLock};
|
||||
|
||||
use super::{frame::VmFrameFlags, MemoryRegions, MemoryRegionsType, VmFrame};
|
||||
use super::{frame::VmFrameFlags, MemoryRegion, MemoryRegionType, VmFrame};
|
||||
|
||||
pub(super) static FRAME_ALLOCATOR: Once<SpinLock<FrameAllocator>> = Once::new();
|
||||
|
||||
@ -55,19 +55,17 @@ pub(crate) unsafe fn dealloc(index: usize) {
|
||||
FRAME_ALLOCATOR.get().unwrap().lock().dealloc(index, 1);
|
||||
}
|
||||
|
||||
pub(crate) fn init(regions: &Vec<MemoryRegions>) {
|
||||
pub(crate) fn init(regions: &Vec<MemoryRegion>) {
|
||||
let mut allocator = FrameAllocator::<32>::new();
|
||||
for region in regions.iter() {
|
||||
if region.typ == MemoryRegionsType::Usable {
|
||||
assert_eq!(region.base % PAGE_SIZE as u64, 0);
|
||||
assert_eq!(region.len % PAGE_SIZE as u64, 0);
|
||||
let start = region.base as usize / PAGE_SIZE;
|
||||
let end = start + region.len as usize / PAGE_SIZE;
|
||||
if region.typ() == MemoryRegionType::Usable {
|
||||
let start = region.base() / PAGE_SIZE;
|
||||
let end = start + region.len() / PAGE_SIZE;
|
||||
allocator.add_frame(start, end);
|
||||
info!(
|
||||
"Found usable region, start:{:x}, end:{:x}",
|
||||
region.base,
|
||||
region.base + region.len
|
||||
region.base(),
|
||||
region.base() + region.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ pub type Paddr = usize;
|
||||
|
||||
mod frame;
|
||||
mod frame_allocator;
|
||||
mod heap_allocator;
|
||||
mod io;
|
||||
mod memory_set;
|
||||
mod offset;
|
||||
@ -29,33 +28,7 @@ pub use self::{
|
||||
use alloc::vec::Vec;
|
||||
use spin::Once;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MemoryRegions {
|
||||
pub base: u64,
|
||||
pub len: u64,
|
||||
pub typ: MemoryRegionsType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
/// Copy from limine boot protocol
|
||||
pub enum MemoryRegionsType {
|
||||
Usable = 0,
|
||||
Reserved = 1,
|
||||
AcpiReclaimable = 2,
|
||||
AcpiNvs = 3,
|
||||
BadMemory = 4,
|
||||
BootloaderReclaimable = 5,
|
||||
/// The kernel and modules loaded are not marked as usable memory. They are
|
||||
/// marked as Kernel/Modules. The entries are guaranteed to be sorted by base
|
||||
/// address, lowest to highest. Usable and bootloader reclaimable entries are
|
||||
/// guaranteed to be 4096 byte aligned for both base and length. Usable and
|
||||
/// bootloader reclaimable entries are guaranteed not to overlap with any
|
||||
/// other entry. To the contrary, all non-usable entries (including kernel/modules)
|
||||
/// are not guaranteed any alignment, nor is it guaranteed that they do not
|
||||
/// overlap other entries.
|
||||
KernelAndModules = 6,
|
||||
Framebuffer = 7,
|
||||
}
|
||||
use crate::arch::boot::{MemoryRegion, MemoryRegionType};
|
||||
|
||||
/// Convert physical address to virtual address using offset, only available inside jinux-frame
|
||||
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize {
|
||||
@ -76,23 +49,21 @@ pub const fn is_page_aligned(p: usize) -> bool {
|
||||
}
|
||||
|
||||
/// Only available inside jinux-frame
|
||||
pub(crate) static MEMORY_REGIONS: Once<Vec<MemoryRegions>> = Once::new();
|
||||
pub(crate) static MEMORY_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
|
||||
|
||||
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegions>> = Once::new();
|
||||
pub static FRAMEBUFFER_REGIONS: Once<Vec<MemoryRegion>> = Once::new();
|
||||
|
||||
pub(crate) fn init() {
|
||||
heap_allocator::init();
|
||||
let memory_regions = crate::arch::mm::get_memory_regions();
|
||||
let memory_regions = crate::arch::boot::get_memory_regions();
|
||||
frame_allocator::init(&memory_regions);
|
||||
|
||||
let mut framebuffer_regions = Vec::new();
|
||||
for i in memory_regions.iter() {
|
||||
if i.typ == MemoryRegionsType::Framebuffer {
|
||||
if i.typ() == MemoryRegionType::Framebuffer {
|
||||
framebuffer_regions.push(i.clone());
|
||||
}
|
||||
}
|
||||
|
||||
frame_allocator::init(&memory_regions);
|
||||
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
|
||||
|
||||
MEMORY_REGIONS.call_once(|| memory_regions);
|
||||
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
|
||||
|
||||
fn set_executable(self, executable: bool) -> Self;
|
||||
|
||||
fn set_huge(self, huge: bool) -> Self;
|
||||
|
||||
fn is_present(&self) -> bool;
|
||||
|
||||
fn writable(&self) -> bool;
|
||||
@ -35,6 +37,10 @@ pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
|
||||
|
||||
fn has_accessed(&self) -> bool;
|
||||
|
||||
fn is_dirty(&self) -> bool;
|
||||
|
||||
fn is_huge(&self) -> bool;
|
||||
|
||||
fn accessible_by_user(&self) -> bool;
|
||||
|
||||
/// Returns a new set of flags, containing any flags present in either self or other. It is similar to the OR operation.
|
||||
@ -178,7 +184,7 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
||||
};
|
||||
|
||||
while count > 1 {
|
||||
if current.paddr() == 0 {
|
||||
if !current.flags().is_present() {
|
||||
if !create {
|
||||
return None;
|
||||
}
|
||||
@ -196,6 +202,9 @@ impl<T: PageTableEntryTrait> PageTable<T> {
|
||||
current.update(frame.start_paddr(), flags);
|
||||
self.tables.push(frame);
|
||||
}
|
||||
if current.flags().is_huge() {
|
||||
break;
|
||||
}
|
||||
count -= 1;
|
||||
debug_assert!(size_of::<T>() * (T::page_index(vaddr, count) + 1) <= PAGE_SIZE);
|
||||
// Safety: The offset does not exceed the value of PAGE_SIZE.
|
||||
|
@ -10,31 +10,18 @@ extern crate jinux_frame;
|
||||
|
||||
use core::panic::PanicInfo;
|
||||
use jinux_frame::println;
|
||||
use limine::{LimineBootInfoRequest, LimineModuleRequest};
|
||||
|
||||
static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0);
|
||||
static BOOTLOADER_MODULE: LimineModuleRequest = LimineModuleRequest::new(0);
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
#[cfg(test)]
|
||||
test_main();
|
||||
jinux_frame::init();
|
||||
println!("[kernel] finish init jinux_frame");
|
||||
component::init_all(component::parse_metadata!()).unwrap();
|
||||
jinux_std::init(read_ramdisk_content());
|
||||
jinux_std::init();
|
||||
jinux_std::run_first_process();
|
||||
}
|
||||
|
||||
fn read_ramdisk_content() -> &'static [u8] {
|
||||
let module_info = BOOTLOADER_MODULE.get_response().get().unwrap();
|
||||
assert!(module_info.module_count == 1);
|
||||
let ramdisk_file = &module_info.modules()[0];
|
||||
let base_ptr = ramdisk_file.base.as_ptr().unwrap();
|
||||
let length = ramdisk_file.length as usize;
|
||||
unsafe { core::slice::from_raw_parts(base_ptr, length) }
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! The frambuffer of jinux
|
||||
//! The framebuffer of jinux
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
#![feature(strict_provenance)]
|
||||
@ -13,7 +13,7 @@ use core::{
|
||||
};
|
||||
use font8x8::UnicodeFonts;
|
||||
use jinux_frame::{
|
||||
config::PAGE_SIZE, io_mem::IoMem, sync::SpinLock, vm::VmIo, LimineFramebufferRequest,
|
||||
config::PAGE_SIZE, io_mem::IoMem, sync::SpinLock, vm::VmIo, arch::boot,
|
||||
};
|
||||
use spin::Once;
|
||||
|
||||
@ -24,24 +24,19 @@ fn framebuffer_init() -> Result<(), ComponentInitError> {
|
||||
}
|
||||
|
||||
pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
|
||||
static FRAMEBUFFER_REUEST: LimineFramebufferRequest = LimineFramebufferRequest::new(0);
|
||||
|
||||
pub(crate) fn init() {
|
||||
let mut writer = {
|
||||
let response = FRAMEBUFFER_REUEST
|
||||
.get_response()
|
||||
.get()
|
||||
.expect("Not found framebuffer");
|
||||
assert_eq!(response.framebuffer_count, 1);
|
||||
let framebuffer = boot::get_framebuffer_info();
|
||||
let mut writer = None;
|
||||
let mut size = 0;
|
||||
for i in jinux_frame::vm::FRAMEBUFFER_REGIONS.get().unwrap().iter() {
|
||||
size = i.len as usize;
|
||||
size = i.len() as usize;
|
||||
}
|
||||
for i in response.framebuffers() {
|
||||
|
||||
let page_size = size / PAGE_SIZE;
|
||||
|
||||
let start_paddr = i.address.as_ptr().unwrap().addr();
|
||||
let start_paddr = framebuffer.address.as_ptr().unwrap().addr();
|
||||
let io_mem =
|
||||
IoMem::new(start_paddr..(start_paddr + jinux_frame::config::PAGE_SIZE * page_size))
|
||||
.unwrap();
|
||||
@ -50,18 +45,18 @@ pub(crate) fn init() {
|
||||
for _ in 0..size {
|
||||
buffer.push(0);
|
||||
}
|
||||
log::debug!("Found framebuffer:{:?}", *i);
|
||||
log::debug!("Found framebuffer:{:?}", framebuffer);
|
||||
|
||||
writer = Some(Writer {
|
||||
io_mem,
|
||||
x_pos: 0,
|
||||
y_pos: 0,
|
||||
bytes_per_pixel: (i.bpp / 8) as usize,
|
||||
width: i.width as usize,
|
||||
height: i.height as usize,
|
||||
bytes_per_pixel: (framebuffer.bpp / 8) as usize,
|
||||
width: framebuffer.width as usize,
|
||||
height: framebuffer.height as usize,
|
||||
buffer: buffer.leak(),
|
||||
})
|
||||
}
|
||||
|
||||
writer.unwrap()
|
||||
};
|
||||
writer.clear();
|
||||
|
@ -26,7 +26,7 @@ use crate::{
|
||||
process::status::ProcessStatus,
|
||||
thread::{kernel_thread::KernelThreadExt, Thread},
|
||||
};
|
||||
use jinux_frame::exit_qemu;
|
||||
use jinux_frame::{arch::boot, exit_qemu};
|
||||
use process::Process;
|
||||
|
||||
extern crate alloc;
|
||||
@ -48,11 +48,11 @@ pub mod time;
|
||||
mod util;
|
||||
pub mod vm;
|
||||
|
||||
pub fn init(ramdisk: &[u8]) {
|
||||
pub fn init() {
|
||||
driver::init();
|
||||
net::init();
|
||||
process::fifo_scheduler::init();
|
||||
fs::initramfs::init(ramdisk).unwrap();
|
||||
fs::initramfs::init(boot::get_initramfs()).unwrap();
|
||||
device::init().unwrap();
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ use jinux_frame::println;
|
||||
static mut INPUT_VALUE: u8 = 0;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
jinux_frame::init();
|
||||
test_main();
|
||||
loop {}
|
||||
|
@ -7,7 +7,7 @@ extern crate alloc;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
jinux_frame::init();
|
||||
component::init_all(component::parse_metadata!()).unwrap();
|
||||
test_main();
|
||||
|
@ -8,7 +8,7 @@ use core::panic::PanicInfo;
|
||||
use jinux_frame::println;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
jinux_frame::init();
|
||||
component::init_all(component::parse_metadata!()).unwrap();
|
||||
test_main();
|
||||
|
@ -6,7 +6,7 @@
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
jinux_frame::init();
|
||||
test_main();
|
||||
loop {}
|
||||
|
@ -13,7 +13,7 @@ use jinux_frame::println;
|
||||
static mut TICK: usize = 0;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn _start() -> ! {
|
||||
pub fn jinux_main() -> ! {
|
||||
jinux_frame::init();
|
||||
test_main();
|
||||
loop {}
|
||||
|
@ -11,11 +11,6 @@
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"-Tboot/limine/conf/linker.ld"
|
||||
]
|
||||
},
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
|
||||
|
Reference in New Issue
Block a user