Adapt Multiboot2 and switch from Limine to Grub2

This commit is contained in:
Zhang Junyang
2023-07-19 10:08:59 +08:00
committed by Tate, Hongliang Tian
parent 49f2750108
commit 47a51eb423
38 changed files with 992 additions and 401 deletions

View File

@ -1,6 +1,6 @@
[target.'cfg(target_os = "none")'] [target.'cfg(target_os = "none")']
runner = "cargo run --package jinux-boot --" runner = "cargo run --package jinux-build --"
[alias] [alias]
kcheck = "check --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem" kcheck = "check --target x86_64-custom.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem"

137
Cargo.lock generated
View File

@ -92,6 +92,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]] [[package]]
name = "bitvec" name = "bitvec"
version = "1.0.1" version = "1.0.1"
@ -110,7 +116,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43f9365b6b0c9e1663ca4ca9440c00eda46bc85a3407070be8b5e0d8d1f29629" checksum = "43f9365b6b0c9e1663ca4ca9440c00eda46bc85a3407070be8b5e0d8d1f29629"
dependencies = [ dependencies = [
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
@ -254,7 +260,7 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882" checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"defmt-macros", "defmt-macros",
] ]
@ -280,6 +286,17 @@ dependencies = [
"thiserror", "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]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.8.0"
@ -388,7 +405,7 @@ dependencies = [
"atomic-polyfill", "atomic-polyfill",
"hash32", "hash32",
"rustc_version", "rustc_version",
"spin 0.9.4", "spin 0.9.8",
"stable_deref_trait", "stable_deref_trait",
] ]
@ -471,7 +488,6 @@ dependencies = [
"jinux-framebuffer", "jinux-framebuffer",
"jinux-std", "jinux-std",
"jinux-time", "jinux-time",
"limine",
"x86_64", "x86_64",
] ]
@ -479,7 +495,7 @@ dependencies = [
name = "jinux-block" name = "jinux-block"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"component", "component",
"jinux-frame", "jinux-frame",
"jinux-pci", "jinux-pci",
@ -487,11 +503,11 @@ dependencies = [
"jinux-virtio", "jinux-virtio",
"lazy_static", "lazy_static",
"log", "log",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
name = "jinux-boot" name = "jinux-build"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
@ -506,16 +522,16 @@ dependencies = [
"acpi", "acpi",
"align_ext", "align_ext",
"aml", "aml",
"bitflags", "bitflags 1.3.2",
"buddy_system_allocator", "buddy_system_allocator",
"cfg-if", "cfg-if",
"inherit-methods-macro", "inherit-methods-macro",
"intrusive-collections", "intrusive-collections",
"lazy_static", "lazy_static",
"limine",
"log", "log",
"multiboot2",
"pod", "pod",
"spin 0.9.4", "spin 0.9.8",
"trapframe", "trapframe",
"volatile", "volatile",
"x86", "x86",
@ -530,14 +546,14 @@ dependencies = [
"font8x8", "font8x8",
"jinux-frame", "jinux-frame",
"log", "log",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
name = "jinux-input" name = "jinux-input"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"component", "component",
"jinux-frame", "jinux-frame",
"jinux-pci", "jinux-pci",
@ -545,7 +561,7 @@ dependencies = [
"jinux-virtio", "jinux-virtio",
"lazy_static", "lazy_static",
"log", "log",
"spin 0.9.4", "spin 0.9.8",
"virtio-input-decoder", "virtio-input-decoder",
] ]
@ -561,28 +577,28 @@ dependencies = [
"log", "log",
"ringbuf", "ringbuf",
"smoltcp", "smoltcp",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
name = "jinux-pci" name = "jinux-pci"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"component", "component",
"jinux-frame", "jinux-frame",
"jinux-util", "jinux-util",
"lazy_static", "lazy_static",
"log", "log",
"pod", "pod",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
name = "jinux-rights" name = "jinux-rights"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"jinux-rights-proc", "jinux-rights-proc",
"typeflags", "typeflags",
"typeflags-util", "typeflags-util",
@ -603,7 +619,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"align_ext", "align_ext",
"ascii", "ascii",
"bitflags", "bitflags 1.3.2",
"controlled", "controlled",
"core2", "core2",
"cpio-decoder", "cpio-decoder",
@ -627,7 +643,7 @@ dependencies = [
"pod", "pod",
"ringbuf", "ringbuf",
"smoltcp", "smoltcp",
"spin 0.9.4", "spin 0.9.8",
"time", "time",
"typeflags", "typeflags",
"typeflags-util", "typeflags-util",
@ -643,7 +659,7 @@ dependencies = [
"component", "component",
"jinux-frame", "jinux-frame",
"log", "log",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
@ -662,7 +678,7 @@ name = "jinux-virtio"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"align_ext", "align_ext",
"bitflags", "bitflags 1.3.2",
"bytes", "bytes",
"component", "component",
"int-to-c-enum", "int-to-c-enum",
@ -671,7 +687,7 @@ dependencies = [
"jinux-util", "jinux-util",
"log", "log",
"pod", "pod",
"spin 0.9.4", "spin 0.9.8",
] ]
[[package]] [[package]]
@ -745,15 +761,6 @@ dependencies = [
"rle-decode-fast", "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]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"
@ -819,6 +826,19 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "never-say-never" name = "never-say-never"
version = "6.6.666" version = "6.6.666"
@ -915,6 +935,26 @@ dependencies = [
"unicode-ident", "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]] [[package]]
name = "quote" name = "quote"
version = "1.0.26" version = "1.0.26"
@ -936,7 +976,7 @@ version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
] ]
[[package]] [[package]]
@ -1021,7 +1061,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea" checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"byteorder", "byteorder",
"cfg-if", "cfg-if",
"defmt", "defmt",
@ -1038,9 +1078,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.4" version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [ dependencies = [
"lock_api", "lock_api",
] ]
@ -1189,6 +1229,23 @@ dependencies = [
name = "typeflags-util" name = "typeflags-util"
version = "0.1.0" 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]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.5" version = "1.0.5"
@ -1201,12 +1258,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "uuid"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -1286,7 +1337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"bitflags", "bitflags 1.3.2",
"raw-cpuid", "raw-cpuid",
] ]
@ -1297,7 +1348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"bitflags", "bitflags 1.3.2",
"rustversion", "rustversion",
"volatile", "volatile",
] ]

View File

@ -8,8 +8,7 @@ name = "jinux"
path = "kernel/main.rs" path = "kernel/main.rs"
[dependencies] [dependencies]
limine = "0.1.10" jinux-frame = { path = "framework/jinux-frame", features = ["multiboot2"] }
jinux-frame = { path = "framework/jinux-frame" }
jinux-std = { path = "services/libs/jinux-std" } jinux-std = { path = "services/libs/jinux-std" }
component = { path = "services/libs/comp-sys/component" } component = { path = "services/libs/comp-sys/component" }
@ -21,7 +20,7 @@ jinux-framebuffer = { path = "services/comps/framebuffer" }
[workspace] [workspace]
members = [ members = [
"boot", "build",
"framework/jinux-frame", "framework/jinux-frame",
"services/comps/pci", "services/comps/pci",
"services/comps/virtio", "services/comps/virtio",

View File

@ -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. 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. * `kernel/`: defining the entry point of the Jinux kernel.
* `framework/`: the privileged half of Jinux (allowed to use `unsafe` keyword) * `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; * `jinux-frame`: providing the safe Rust abstractions for low-level resources like CPU, memory, interrupts, etc;

View File

@ -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

View File

@ -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) }
}

View File

@ -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

View File

@ -1,13 +1,9 @@
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<dyn Error + Send + Sync>> { fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
limine_build_script()?; let linker_script_path = "build/grub/conf/linker.ld";
Ok(()) println!("cargo:rerun-if-changed={}", linker_script_path);
} println!("cargo:rustc-link-arg=-T{}", linker_script_path);
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");
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME"); println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
Ok(()) Ok(())

View File

@ -1,5 +1,5 @@
[package] [package]
name = "jinux-boot" name = "jinux-build"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # 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" cfg-if = "1.0"
[features] [features]
default = ["limine"] default = []
limine = []
iommu = [] iommu = []

5
build/build.rs Normal file
View 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
View File

@ -0,0 +1,5 @@
menuentry 'jinux' {
multiboot2 /jinux
module2 --nounzip /ramdisk.cpio.gz
boot
}

51
build/grub/conf/linker.ld Normal file
View 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;
}

View 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

View File

@ -16,6 +16,7 @@ const COMMON_ARGS: &[&str] = &[
"Icelake-Server,+x2apic", "Icelake-Server,+x2apic",
"-m", "-m",
"2G", "2G",
"-nographic", // TODO: figure out why grub can't shown up without it
"-monitor", "-monitor",
"vc", "vc",
"-serial", "-serial",
@ -73,9 +74,11 @@ fn main() -> anyhow::Result<()> {
path.canonicalize().unwrap() path.canonicalize().unwrap()
}; };
#[cfg(feature = "limine")] call_bootloader_build_script(
call_limine_build_script(&kernel_binary_path).unwrap(); &PathBuf::from("build/grub/scripts/build-grub-image.sh"),
// add .iso &kernel_binary_path,
)
.unwrap();
let kernel_iso_path = { let kernel_iso_path = {
let a = kernel_binary_path.parent().unwrap(); 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 binary_kind = runner_utils::binary_kind(&kernel_binary_path);
let mut qemu_args = COMMON_ARGS.clone().to_vec(); let mut qemu_args = COMMON_ARGS.clone().to_vec();
qemu_args.extend(DEVICE_ARGS.clone().to_vec().iter()); qemu_args.extend(DEVICE_ARGS.clone().to_vec().iter());
qemu_args.extend(OPTION_ARGS.clone().to_vec().iter()); qemu_args.extend(OPTION_ARGS.clone().to_vec().iter());
qemu_args.push("-drive"); qemu_args.push("-drive");
@ -123,9 +127,12 @@ fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
fn call_limine_build_script(path: &PathBuf) -> anyhow::Result<()> { fn call_bootloader_build_script(
let mut cmd = Command::new("boot/limine/scripts/limine-build.sh"); script_path: &PathBuf,
cmd.arg(path.to_str().unwrap()); 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()?; let exit_status = cmd.status()?;
if !exit_status.success() { if !exit_status.success() {
std::process::exit(exit_status.code().unwrap_or(1)); std::process::exit(exit_status.code().unwrap_or(1));

View File

@ -18,12 +18,13 @@ log = "0.4"
lazy_static = { version = "1.0", features = ["spin_no_std"] } lazy_static = { version = "1.0", features = ["spin_no_std"] }
trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "e886763" } trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "e886763" }
inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" } inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" }
multiboot2 = "0.16.0"
[target.x86_64-custom.dependencies] [target.x86_64-custom.dependencies]
limine = { version = "0.1.10", features = ["into-uuid"] }
x86_64 = "0.14.2" x86_64 = "0.14.2"
x86 = "0.52.0" x86 = "0.52.0"
acpi = "4.1.1" acpi = "4.1.1"
aml = "0.16.3" aml = "0.16.3"
[features] [features]
multiboot2 = []

View File

@ -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)
};

View 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]
}
}
}
}

View File

@ -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 #[cfg(feature = "multiboot2")]
pub fn init() { pub mod multiboot2;
limine::init(); #[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()
} }

View 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

View 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 &regions_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();
}

View File

@ -87,6 +87,10 @@ impl PageTableFlagsTrait for PageTableFlags {
self.contains(Self::ACCESSED) self.contains(Self::ACCESSED)
} }
fn is_dirty(&self) -> bool {
self.contains(Self::DIRTY)
}
fn accessible_by_user(&self) -> bool { fn accessible_by_user(&self) -> bool {
true true
} }
@ -102,6 +106,16 @@ impl PageTableFlagsTrait for PageTableFlags {
fn insert(&mut self, flags: &Self) { fn insert(&mut self, flags: &Self) {
self.insert(*flags) 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 { impl PageTableEntry {

View File

@ -6,9 +6,9 @@ use core::{
ptr::NonNull, 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 acpi::{sdt::SdtHeader, AcpiHandler, AcpiTable, AcpiTables};
use limine::LimineRsdpRequest;
use log::info; use log::info;
use spin::{Mutex, Once}; use spin::{Mutex, Once};
@ -89,17 +89,18 @@ impl AcpiHandler for AcpiMemoryHandler {
fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {} fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {}
} }
static RSDP_REQUEST: LimineRsdpRequest = LimineRsdpRequest::new(0);
pub fn init() { pub fn init() {
let response = RSDP_REQUEST let acpi_tables = match boot::get_acpi_rsdp() {
.get_response() BootloaderAcpiArg::Rsdp(addr) => unsafe {
.get() AcpiTables::from_rsdp(AcpiMemoryHandler {}, addr as usize).unwrap()
.expect("Need RSDP address"); },
let rsdp = response.address.as_ptr().unwrap().addr() - config::PHYS_OFFSET; BootloaderAcpiArg::Rsdt(addr) => unsafe {
// Safety: The RSDP is the value provided by bootloader. AcpiTables::from_rsdt(AcpiMemoryHandler {}, 0, addr as usize).unwrap()
let acpi_tables = },
unsafe { AcpiTables::from_rsdp(AcpiMemoryHandler {}, rsdp as usize).unwrap() }; BootloaderAcpiArg::Xsdt(addr) => unsafe {
AcpiTables::from_rsdt(AcpiMemoryHandler {}, 1, addr as usize).unwrap()
},
};
for (signature, sdt) in acpi_tables.sdts.iter() { for (signature, sdt) in acpi_tables.sdts.iter() {
info!("ACPI found signature:{:?}", signature); info!("ACPI found signature:{:?}", signature);

View File

@ -1,6 +1,4 @@
use alloc::{collections::BTreeMap, fmt, vec::Vec}; use alloc::{collections::BTreeMap, fmt};
use limine::{LimineMemmapEntry, LimineMemmapRequest, LimineMemoryMapEntryType};
use log::debug;
use pod::Pod; use pod::Pod;
use spin::Mutex; use spin::Mutex;
use x86_64::structures::paging::PhysFrame; use x86_64::structures::paging::PhysFrame;
@ -9,7 +7,7 @@ use crate::{
config::ENTRY_COUNT, config::ENTRY_COUNT,
vm::{ vm::{
page_table::{table_of, PageTableEntryTrait, PageTableFlagsTrait}, page_table::{table_of, PageTableEntryTrait, PageTableFlagsTrait},
MemoryRegions, MemoryRegionsType, Paddr, Paddr,
}, },
}; };
@ -31,6 +29,10 @@ bitflags::bitflags! {
const NO_CACHE = 1 << 4; const NO_CACHE = 1 << 4;
/// Whether this entry has been used for linear-address translation. /// Whether this entry has been used for linear-address translation.
const ACCESSED = 1 << 5; 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 /// Indicates that the mapping is present in all address spaces, so it isn't flushed from
/// the TLB on an address space switch. /// the TLB on an address space switch.
const GLOBAL = 1 << 8; 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()); 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() { pub fn init() {
let (page_directory_base, _) = x86_64::registers::control::Cr3::read(); let (page_directory_base, _) = x86_64::registers::control::Cr3::read();
let page_directory_base = page_directory_base.start_address().as_u64() as usize; 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) self.contains(Self::ACCESSED)
} }
fn is_dirty(&self) -> bool {
self.contains(Self::DIRTY)
}
fn union(&self, flags: &Self) -> Self { fn union(&self, flags: &Self) -> Self {
(*self).union(*flags) (*self).union(*flags)
} }
@ -148,6 +140,15 @@ impl PageTableFlagsTrait for PageTableFlags {
fn insert(&mut self, flags: &Self) { fn insert(&mut self, flags: &Self) {
self.insert(*flags) 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 { impl PageTableEntry {
@ -193,30 +194,3 @@ impl fmt::Debug for PageTableEntry {
.finish() .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,
}
}
}

View File

@ -1,4 +1,4 @@
mod boot; pub mod boot;
pub(crate) mod cpu; pub(crate) mod cpu;
pub mod device; pub mod device;
pub mod iommu; pub mod iommu;

View File

@ -8,8 +8,8 @@
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(new_uninit)] #![feature(new_uninit)]
#![feature(link_llvm_intrinsics)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(link_llvm_intrinsics)]
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(const_ops)] #![feature(const_ops)]
#![feature(generators)] #![feature(generators)]
@ -23,6 +23,7 @@ pub mod bus;
pub mod config; pub mod config;
pub mod cpu; pub mod cpu;
mod error; mod error;
mod heap_allocator;
pub mod logger; pub mod logger;
pub mod io_mem; pub mod io_mem;
pub mod prelude; pub mod prelude;
@ -39,14 +40,13 @@ pub use self::error::Error;
pub use self::prelude::Result; pub use self::prelude::Result;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{mem, panic::PanicInfo}; use core::{mem, panic::PanicInfo};
#[cfg(target_arch = "x86_64")]
pub use limine::{LimineFramebufferRequest, LimineModuleRequest};
use trap::{IrqCallbackHandle, IrqLine}; use trap::{IrqCallbackHandle, IrqLine};
use trapframe::TrapFrame; use trapframe::TrapFrame;
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new(); static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
pub fn init() { pub fn init() {
heap_allocator::init();
arch::before_all_init(); arch::before_all_init();
logger::init(); logger::init();
vm::init(); vm::init();
@ -68,13 +68,13 @@ fn register_irq_common_callback() {
fn invoke_c_init_funcs() { fn invoke_c_init_funcs() {
extern "C" { extern "C" {
fn sinit_array(); fn __sinit_array();
fn einit_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 { for i in 0..call_len {
unsafe { 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(); let function = address as *const fn();
(*function)(); (*function)();
} }

View File

@ -5,7 +5,7 @@ use spin::Once;
use crate::{config::PAGE_SIZE, sync::SpinLock}; 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(); 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); 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(); let mut allocator = FrameAllocator::<32>::new();
for region in regions.iter() { for region in regions.iter() {
if region.typ == MemoryRegionsType::Usable { if region.typ() == MemoryRegionType::Usable {
assert_eq!(region.base % PAGE_SIZE as u64, 0); let start = region.base() / PAGE_SIZE;
assert_eq!(region.len % PAGE_SIZE as u64, 0); let end = start + region.len() / PAGE_SIZE;
let start = region.base as usize / PAGE_SIZE;
let end = start + region.len as usize / PAGE_SIZE;
allocator.add_frame(start, end); allocator.add_frame(start, end);
info!( info!(
"Found usable region, start:{:x}, end:{:x}", "Found usable region, start:{:x}, end:{:x}",
region.base, region.base(),
region.base + region.len region.base() + region.len()
); );
} }
} }

View File

@ -8,7 +8,6 @@ pub type Paddr = usize;
mod frame; mod frame;
mod frame_allocator; mod frame_allocator;
mod heap_allocator;
mod io; mod io;
mod memory_set; mod memory_set;
mod offset; mod offset;
@ -29,33 +28,7 @@ pub use self::{
use alloc::vec::Vec; use alloc::vec::Vec;
use spin::Once; use spin::Once;
#[derive(Clone, Copy)] use crate::arch::boot::{MemoryRegion, MemoryRegionType};
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,
}
/// Convert physical address to virtual address using offset, only available inside jinux-frame /// Convert physical address to virtual address using offset, only available inside jinux-frame
pub(crate) fn paddr_to_vaddr(pa: usize) -> usize { 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 /// 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() { pub(crate) fn init() {
heap_allocator::init(); let memory_regions = crate::arch::boot::get_memory_regions();
let memory_regions = crate::arch::mm::get_memory_regions(); frame_allocator::init(&memory_regions);
let mut framebuffer_regions = Vec::new(); let mut framebuffer_regions = Vec::new();
for i in memory_regions.iter() { for i in memory_regions.iter() {
if i.typ == MemoryRegionsType::Framebuffer { if i.typ() == MemoryRegionType::Framebuffer {
framebuffer_regions.push(i.clone()); framebuffer_regions.push(i.clone());
} }
} }
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
frame_allocator::init(&memory_regions);
MEMORY_REGIONS.call_once(|| memory_regions); MEMORY_REGIONS.call_once(|| memory_regions);
FRAMEBUFFER_REGIONS.call_once(|| framebuffer_regions);
} }

View File

@ -25,6 +25,8 @@ pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
fn set_executable(self, executable: bool) -> Self; fn set_executable(self, executable: bool) -> Self;
fn set_huge(self, huge: bool) -> Self;
fn is_present(&self) -> bool; fn is_present(&self) -> bool;
fn writable(&self) -> bool; fn writable(&self) -> bool;
@ -35,6 +37,10 @@ pub trait PageTableFlagsTrait: Clone + Copy + Sized + Pod + Debug {
fn has_accessed(&self) -> bool; fn has_accessed(&self) -> bool;
fn is_dirty(&self) -> bool;
fn is_huge(&self) -> bool;
fn accessible_by_user(&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. /// 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 { while count > 1 {
if current.paddr() == 0 { if !current.flags().is_present() {
if !create { if !create {
return None; return None;
} }
@ -196,6 +202,9 @@ impl<T: PageTableEntryTrait> PageTable<T> {
current.update(frame.start_paddr(), flags); current.update(frame.start_paddr(), flags);
self.tables.push(frame); self.tables.push(frame);
} }
if current.flags().is_huge() {
break;
}
count -= 1; count -= 1;
debug_assert!(size_of::<T>() * (T::page_index(vaddr, count) + 1) <= PAGE_SIZE); debug_assert!(size_of::<T>() * (T::page_index(vaddr, count) + 1) <= PAGE_SIZE);
// Safety: The offset does not exceed the value of PAGE_SIZE. // Safety: The offset does not exceed the value of PAGE_SIZE.

View File

@ -10,31 +10,18 @@ extern crate jinux_frame;
use core::panic::PanicInfo; use core::panic::PanicInfo;
use jinux_frame::println; use jinux_frame::println;
use limine::{LimineBootInfoRequest, LimineModuleRequest};
static BOOTLOADER_INFO: LimineBootInfoRequest = LimineBootInfoRequest::new(0);
static BOOTLOADER_MODULE: LimineModuleRequest = LimineModuleRequest::new(0);
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
#[cfg(test)] #[cfg(test)]
test_main(); test_main();
jinux_frame::init(); jinux_frame::init();
println!("[kernel] finish init jinux_frame"); println!("[kernel] finish init jinux_frame");
component::init_all(component::parse_metadata!()).unwrap(); component::init_all(component::parse_metadata!()).unwrap();
jinux_std::init(read_ramdisk_content()); jinux_std::init();
jinux_std::run_first_process(); 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))] #[cfg(not(test))]
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {

View File

@ -1,4 +1,4 @@
//! The frambuffer of jinux //! The framebuffer of jinux
#![no_std] #![no_std]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
@ -13,7 +13,7 @@ use core::{
}; };
use font8x8::UnicodeFonts; use font8x8::UnicodeFonts;
use jinux_frame::{ 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; use spin::Once;
@ -24,44 +24,39 @@ fn framebuffer_init() -> Result<(), ComponentInitError> {
} }
pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new(); pub(crate) static WRITER: Once<SpinLock<Writer>> = Once::new();
static FRAMEBUFFER_REUEST: LimineFramebufferRequest = LimineFramebufferRequest::new(0);
pub(crate) fn init() { pub(crate) fn init() {
let mut writer = { let mut writer = {
let response = FRAMEBUFFER_REUEST let framebuffer = boot::get_framebuffer_info();
.get_response()
.get()
.expect("Not found framebuffer");
assert_eq!(response.framebuffer_count, 1);
let mut writer = None; let mut writer = None;
let mut size = 0; let mut size = 0;
for i in jinux_frame::vm::FRAMEBUFFER_REGIONS.get().unwrap().iter() { 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 page_size = size / PAGE_SIZE;
let io_mem =
IoMem::new(start_paddr..(start_paddr + jinux_frame::config::PAGE_SIZE * page_size))
.unwrap();
let mut buffer: Vec<u8> = Vec::with_capacity(size); let start_paddr = framebuffer.address.as_ptr().unwrap().addr();
for _ in 0..size { let io_mem =
buffer.push(0); IoMem::new(start_paddr..(start_paddr + jinux_frame::config::PAGE_SIZE * page_size))
} .unwrap();
log::debug!("Found framebuffer:{:?}", *i);
writer = Some(Writer { let mut buffer: Vec<u8> = Vec::with_capacity(size);
io_mem, for _ in 0..size {
x_pos: 0, buffer.push(0);
y_pos: 0,
bytes_per_pixel: (i.bpp / 8) as usize,
width: i.width as usize,
height: i.height as usize,
buffer: buffer.leak(),
})
} }
log::debug!("Found framebuffer:{:?}", framebuffer);
writer = Some(Writer {
io_mem,
x_pos: 0,
y_pos: 0,
bytes_per_pixel: (framebuffer.bpp / 8) as usize,
width: framebuffer.width as usize,
height: framebuffer.height as usize,
buffer: buffer.leak(),
})
writer.unwrap() writer.unwrap()
}; };
writer.clear(); writer.clear();

View File

@ -26,7 +26,7 @@ use crate::{
process::status::ProcessStatus, process::status::ProcessStatus,
thread::{kernel_thread::KernelThreadExt, Thread}, thread::{kernel_thread::KernelThreadExt, Thread},
}; };
use jinux_frame::exit_qemu; use jinux_frame::{arch::boot, exit_qemu};
use process::Process; use process::Process;
extern crate alloc; extern crate alloc;
@ -48,11 +48,11 @@ pub mod time;
mod util; mod util;
pub mod vm; pub mod vm;
pub fn init(ramdisk: &[u8]) { pub fn init() {
driver::init(); driver::init();
net::init(); net::init();
process::fifo_scheduler::init(); process::fifo_scheduler::init();
fs::initramfs::init(ramdisk).unwrap(); fs::initramfs::init(boot::get_initramfs()).unwrap();
device::init().unwrap(); device::init().unwrap();
} }

View File

@ -10,7 +10,7 @@ use jinux_frame::println;
static mut INPUT_VALUE: u8 = 0; static mut INPUT_VALUE: u8 = 0;
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
jinux_frame::init(); jinux_frame::init();
test_main(); test_main();
loop {} loop {}

View File

@ -7,7 +7,7 @@ extern crate alloc;
use core::panic::PanicInfo; use core::panic::PanicInfo;
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
jinux_frame::init(); jinux_frame::init();
component::init_all(component::parse_metadata!()).unwrap(); component::init_all(component::parse_metadata!()).unwrap();
test_main(); test_main();

View File

@ -8,7 +8,7 @@ use core::panic::PanicInfo;
use jinux_frame::println; use jinux_frame::println;
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
jinux_frame::init(); jinux_frame::init();
component::init_all(component::parse_metadata!()).unwrap(); component::init_all(component::parse_metadata!()).unwrap();
test_main(); test_main();

View File

@ -6,7 +6,7 @@
use core::panic::PanicInfo; use core::panic::PanicInfo;
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
jinux_frame::init(); jinux_frame::init();
test_main(); test_main();
loop {} loop {}

View File

@ -13,7 +13,7 @@ use jinux_frame::println;
static mut TICK: usize = 0; static mut TICK: usize = 0;
#[no_mangle] #[no_mangle]
pub extern "C" fn _start() -> ! { pub fn jinux_main() -> ! {
jinux_frame::init(); jinux_frame::init();
test_main(); test_main();
loop {} loop {}

View File

@ -11,11 +11,6 @@
"executables": true, "executables": true,
"linker-flavor": "ld.lld", "linker-flavor": "ld.lld",
"linker": "rust-lld", "linker": "rust-lld",
"pre-link-args": {
"ld.lld": [
"-Tboot/limine/conf/linker.ld"
]
},
"panic-strategy": "abort", "panic-strategy": "abort",
"disable-redzone": true, "disable-redzone": true,
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"