Add protected mode sub-crate for Linux boot setup

This commit is contained in:
Zhang Junyang 2023-10-06 22:08:20 +08:00 committed by Tate, Hongliang Tian
parent 7d5295ab25
commit d0c84e0b6f
20 changed files with 138 additions and 66 deletions

View File

@ -10,9 +10,9 @@ on:
jobs:
test:
runs-on: ubuntu-latest
container: jinuxdev/jinux:0.1.1
container: jinuxdev/jinux:0.1.2
steps:
- run: echo "Running in jinuxdev/jinux:0.1.1"
- run: echo "Running in jinuxdev/jinux:0.1.2"
- uses: actions/checkout@v3

View File

@ -10,9 +10,9 @@ on:
jobs:
test:
runs-on: ubuntu-latest
container: jinuxdev/jinux:0.1.1
container: jinuxdev/jinux:0.1.2
steps:
- run: echo "Running in jinuxdev/jinux:0.1.1"
- run: echo "Running in jinuxdev/jinux:0.1.2"
- uses: actions/checkout@v3
@ -20,8 +20,8 @@ jobs:
id: syscall_test_mb2
run: RUSTFLAGS="-C opt-level=1" make run AUTO_SYSCALL_TEST=1 ENABLE_KVM=0 SKIP_GRUB_MENU=1 BOOT_METHOD=grub-multiboot2
- name: Syscall Test (Linux Boot Protocol)
id: syscall_test_lbp
run: RUSTFLAGS="-C opt-level=1" make run AUTO_SYSCALL_TEST=1 ENABLE_KVM=0 SKIP_GRUB_MENU=1 BOOT_METHOD=grub-linux
# TODO: include the integration tests for Multiboot and MicroVM, which are not ready yet.
# TODO: include the integration tests for Multiboot/MicroVM/Linux boot methods, which are not ready yet.
# - name: Syscall Test (Linux Boot Protocol)
# id: syscall_test_lbp
# run: RUSTFLAGS="-C opt-level=1" make run AUTO_SYSCALL_TEST=1 ENABLE_KVM=0 SKIP_GRUB_MENU=1 BOOT_METHOD=grub-linux

6
Cargo.lock generated
View File

@ -599,7 +599,7 @@ dependencies = [
[[package]]
name = "jinux"
version = "0.1.1"
version = "0.1.2"
dependencies = [
"component",
"jinux-frame",
@ -659,6 +659,10 @@ dependencies = [
"x86_64",
]
[[package]]
name = "jinux-frame-x86-boot-setup"
version = "0.1.0"
[[package]]
name = "jinux-framebuffer"
version = "0.1.0"

View File

@ -1,6 +1,6 @@
[package]
name = "jinux"
version = "0.1.1"
version = "0.1.2"
edition = "2021"
[[bin]]
@ -22,6 +22,7 @@ jinux-framebuffer = { path = "services/comps/framebuffer" }
members = [
"build",
"framework/jinux-frame",
"framework/jinux-frame/src/arch/x86/boot/linux_boot/setup",
"framework/libs/align_ext",
"services/comps/virtio",
"services/comps/input",

View File

@ -56,7 +56,8 @@ export
export JINUX_BOOT_PROTOCOL=$(BOOT_PROTOCOL)
# GNU toolchain variables
# Toolchain variables
export CARGO := cargo
export AS := as
export CC := gcc
export OBJCOPY := objcopy

View File

@ -34,12 +34,12 @@ git clone [repository url]
2. After downloading the source code, run the following command to pull the development image.
```bash
docker pull jinuxdev/jinux:0.1.1
docker pull jinuxdev/jinux:0.1.2
```
3. Start the development container.
```bash
docker run -it --privileged --network=host --device=/dev/kvm -v `pwd`:/root/jinux jinuxdev/jinux:0.1.1
docker run -it --privileged --network=host --device=/dev/kvm -v `pwd`:/root/jinux jinuxdev/jinux:0.1.2
```
**All build and test commands should be run inside the development container.**

View File

@ -1 +1 @@
0.1.1
0.1.2

View File

@ -1,7 +1,7 @@
use std::{error::Error, path::PathBuf};
fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let linker_script_path = get_source_dir()
let linker_script_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join("framework")
.join("jinux-frame")
.join("src")
@ -9,19 +9,8 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
.join("x86")
.join("boot")
.join("linker.ld");
println!(
"cargo:rerun-if-changed={}",
linker_script_path.to_str().unwrap()
);
println!(
"cargo:rustc-link-arg=-T{}",
linker_script_path.to_str().unwrap()
);
println!("cargo:rerun-if-changed={}", linker_script_path.display());
println!("cargo:rustc-link-arg=-T{}", linker_script_path.display());
println!("cargo:rerun-if-env-changed=CARGO_PKG_NAME");
Ok(())
}
fn get_source_dir() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
PathBuf::from(manifest_dir)
}

View File

@ -63,7 +63,9 @@ pub fn create_bootdev_image(
// Find the setup header in the build script output directory.
let out_dir = glob("target/x86_64-custom/debug/build/jinux-frame-*").unwrap();
let header_bin = Path::new(out_dir.into_iter().next().unwrap().unwrap().as_path())
.join("out/linux_header.bin");
.join("out")
.join("bin")
.join("jinux-frame-x86-boot-setup.bin");
// Deliver the kernel image to the boot directory.
match protocol {

View File

@ -5,59 +5,65 @@ fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
Ok(())
}
fn get_source_dir() -> PathBuf {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
PathBuf::from(manifest_dir)
}
fn get_header_out_dir() -> PathBuf {
PathBuf::from(std::env::var("OUT_DIR").unwrap())
}
fn build_linux_setup_header() -> Result<(), Box<dyn Error + Send + Sync>> {
// Compile the header to raw binary.
let linux_boot_header_asm_path = get_source_dir()
// Build the setup header to raw binary.
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let setup_crate_dir = source_dir
.join("src")
.join("arch")
.join("x86")
.join("boot")
.join("linux_boot")
.join("header.S");
.join("setup");
let target_json = setup_crate_dir.join("x86_64-i386_protected_mode.json");
println!(
"cargo:rerun-if-changed={}",
linux_boot_header_asm_path.to_str().unwrap()
setup_crate_dir.to_str().unwrap()
);
let linux_boot_header_elf_path = get_header_out_dir().join("linux_header.o");
let gas = std::env::var("AS").unwrap();
let mut cmd = std::process::Command::new(gas);
cmd.arg(linux_boot_header_asm_path);
cmd.arg("-o")
.arg(linux_boot_header_elf_path.to_str().unwrap());
let cargo = std::env::var("CARGO").unwrap();
let mut cmd = std::process::Command::new(cargo);
cmd.arg("install").arg("jinux-frame-x86-boot-setup");
cmd.arg("--locked");
cmd.arg("--path").arg(setup_crate_dir.to_str().unwrap());
cmd.arg("--target").arg(target_json.as_os_str());
cmd.arg("-Zbuild-std=core,compiler_builtins");
cmd.arg("-Zbuild-std-features=compiler-builtins-mem");
cmd.arg("--root").arg(out_dir.as_os_str());
cmd.env_remove("RUSTFLAGS");
cmd.env_remove("CARGO_ENCODED_RUSTFLAGS");
let output = cmd.output()?;
if !output.status.success() {
std::io::stdout().write_all(&output.stdout).unwrap();
std::io::stderr().write_all(&output.stderr).unwrap();
panic!(
"Failed to compile linux boot header:\n\tcommand `{:?}`\n\treturned {}",
return Err(format!(
"Failed to build linux x86 setup header::\n\tcommand `{:?}`\n\treturned {}",
cmd, output.status
);
)
.into());
}
// Strip the elf header to get the raw header.
let linux_boot_header_bin_path = get_header_out_dir().join("linux_header.bin");
let elf_path = out_dir.join("bin").join("jinux-frame-x86-boot-setup");
let bin_path = out_dir.join("bin").join("jinux-frame-x86-boot-setup.bin");
let objcopy = std::env::var("OBJCOPY").unwrap();
let mut cmd = std::process::Command::new(objcopy);
cmd.arg("-O").arg("binary");
cmd.arg("-j").arg(".boot_compatibility_bin");
cmd.arg(linux_boot_header_elf_path.to_str().unwrap());
cmd.arg(linux_boot_header_bin_path.to_str().unwrap());
cmd.arg("-j").arg(".boot_real_mode");
cmd.arg(elf_path.to_str().unwrap());
cmd.arg(bin_path.to_str().unwrap());
let output = cmd.output()?;
if !output.status.success() {
std::io::stdout().write_all(&output.stdout).unwrap();
std::io::stderr().write_all(&output.stderr).unwrap();
panic!(
return Err(format!(
"Failed to strip linux boot header:\n\tcommand `{:?}`\n\treturned {}",
cmd, output.status
);
)
.into());
}
Ok(())
}

View File

@ -0,0 +1,8 @@
[package]
name = "jinux-frame-x86-boot-setup"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,9 @@
use std::path::PathBuf;
fn main() {
let source_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
println!(
"cargo:rustc-link-arg-bins=--script={}",
source_dir.join("linker.ld").display()
)
}

View File

@ -0,0 +1,22 @@
ENTRY(start_of_setup)
OUTPUT_ARCH(i386:x86)
OUTPUT_FORMAT(elf32-i386)
SETUP_LMA = 0x1000;
SECTIONS
{
. = SETUP_LMA;
.boot_real_mode : AT(ADDR(.boot_real_mode) - SETUP_LMA) { KEEP(*(.boot_real_mode)) }
.text : AT(ADDR(.text) - SETUP_LMA) { *(.text .text.*) }
.rodata : AT(ADDR(.rodata) - SETUP_LMA) { *(.rodata .rodata.*) }
.data : AT(ADDR(.data) - SETUP_LMA) { *(.data .data.*) }
.bss : AT(ADDR(.bss) - SETUP_LMA) {
__bss = .;
*(.bss .bss.*) *(COMMON)
__bss_end = .;
}
}

View File

@ -2,11 +2,9 @@
// See https://www.kernel.org/doc/html/v5.6/x86/boot.html for
// more information on the Linux x86 Boot Protocol.
.intel_syntax noprefix
// The section name is used by the build script to strip and make
// the binary file.
.section ".boot_compatibility_bin", "awx"
.section ".boot_real_mode", "awx"
// The Linux x86 Boot Protocol header.
//
@ -68,7 +66,8 @@ kernel_info_offset: .long 0
.align 16
real_gdtr:
.word gdt_end - gdt - 1
.quad gdt
.long 0 # upper 32-bit address of GDT
.long gdt # lower 32-bit address of GDT
.align 16
gdt:

View File

@ -0,0 +1,11 @@
#![no_std]
#![no_main]
use core::arch::global_asm;
global_asm!(include_str!("header.S"));
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

View File

@ -0,0 +1,20 @@
{
"llvm-target": "i386-unknown-none",
"data-layout": "e-m:e-i32:32-f80:128-n8:16:32-S128-p:32:32",
"cpu": "i386",
"arch": "x86",
"dynamic-linking": false,
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"max-atomic-width": 64,
"position-independent-executables": false,
"disable-redzone": true,
"target-c-int-width": "32",
"target-pointer-width": "32",
"target-endian": "little",
"panic-strategy": "abort",
"os": "none",
"relocation-model": "static",
"features": "+soft-float,-sse,-mmx"
}

View File

@ -9,7 +9,7 @@
#![feature(core_intrinsics)]
#![feature(new_uninit)]
#![feature(strict_provenance)]
#![feature(link_llvm_intrinsics)]
//#![feature(link_llvm_intrinsics)]
#![feature(const_trait_impl)]
#![feature(generators)]
#![feature(iter_from_generator)]

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-08-01"
channel = "nightly-2023-10-05"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View File

@ -24,7 +24,7 @@ static CARGO_COMPONENT_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
});
pub fn run_cargo_component(test_name: &str) -> String {
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let root_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let target_dir = root_dir.join("target").join(test_name);
let cwd = root_dir.join("tests").join(test_name);
let output = cargo_clean(&cwd, &target_dir);

View File

@ -199,7 +199,7 @@ fn calculate_priority(
}
fn metadata() -> json::JsonValue {
let mut cmd = Command::new(env!("CARGO"));
let mut cmd = Command::new(std::env::var("CARGO").unwrap());
cmd.arg("metadata");
cmd.arg("--format-version").arg("1");
let output = cmd.output().unwrap();