mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-18 09:53:04 +00:00
rust: Initial Rust-based EFI FAT32 chainloader
This code is gated behind the CHAINLOADING define. To build a release-style m1n1 with chainloading for use with the installer or kmutil, use: make CHAINLOADING=1 RELEASE=1 To tell m1n1 to chainload another binary, use this var payload: chainload=<ESP partition UUID>;<file path> e.g. chainload=a17b7e46-e950-bb4f-bc82-8ab1047a058e;m1n1/m1n1.bin Closes: #154 Co-authored-by: Finn Behrens <me@kloenk.dev> Co-authored-by: Joey Gouly <joey.gouly@arm.com> Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
e386e17550
commit
eb49df38bd
26 changed files with 821 additions and 21 deletions
38
.github/workflows/build.yml
vendored
38
.github/workflows/build.yml
vendored
|
@ -18,18 +18,26 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: install aarch64-linux-gnu- toolchain
|
|
||||||
run: |
|
- name: install aarch64-linux-gnu- toolchain
|
||||||
sudo apt-get update
|
run: |
|
||||||
sudo apt-get install --no-install-recommends -y device-tree-compiler gcc-aarch64-linux-gnu
|
sudo apt-get update
|
||||||
- name: build
|
sudo apt-get install --no-install-recommends -y device-tree-compiler gcc-aarch64-linux-gnu
|
||||||
run: make -k -j2 ARCH=aarch64-linux-gnu-
|
|
||||||
- uses: actions/upload-artifact@v2
|
- name: install nightly rust
|
||||||
with:
|
run: |
|
||||||
name: m1n1
|
export RUSTUP_TOOLCHAIN=nightly
|
||||||
path: |
|
rustup target install aarch64-unknown-none-softfloat
|
||||||
build/m1n1.macho
|
|
||||||
build/dtb/t8103-j274.dtb
|
- name: build
|
||||||
|
run: make -k -j2 ARCH=aarch64-linux-gnu- CHAINLOADING=1
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: m1n1
|
||||||
|
path: |
|
||||||
|
build/m1n1.macho
|
||||||
|
build/dtb/t8103-j274.dtb
|
||||||
|
|
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
|
@ -21,5 +21,13 @@ jobs:
|
||||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: install nightly rust
|
||||||
|
run: |
|
||||||
|
rm -f ~/.cargo/bin/rustfmt
|
||||||
|
rm -f ~/.cargo/bin/cargo-fmt
|
||||||
|
rustup toolchain install nightly --component rustfmt --component clippy --allow-downgrade
|
||||||
|
|
||||||
- name: Run format-check
|
- name: Run format-check
|
||||||
run: make format-check
|
run: |
|
||||||
|
make format-check
|
||||||
|
make rustfmt-check
|
||||||
|
|
24
.gitmodules
vendored
24
.gitmodules
vendored
|
@ -1,3 +1,27 @@
|
||||||
[submodule "artwork"]
|
[submodule "artwork"]
|
||||||
path = artwork
|
path = artwork
|
||||||
url = https://github.com/AsahiLinux/artwork.git
|
url = https://github.com/AsahiLinux/artwork.git
|
||||||
|
[submodule "rust/vendor/rust-fatfs"]
|
||||||
|
path = rust/vendor/rust-fatfs
|
||||||
|
url = https://github.com/rafalh/rust-fatfs
|
||||||
|
[submodule "rust/vendor/bitflags"]
|
||||||
|
path = rust/vendor/bitflags
|
||||||
|
url = https://github.com/bitflags/bitflags
|
||||||
|
[submodule "rust/vendor/cfg-if"]
|
||||||
|
path = rust/vendor/cfg-if
|
||||||
|
url = https://github.com/alexcrichton/cfg-if
|
||||||
|
[submodule "rust/vendor/cstr_core"]
|
||||||
|
path = rust/vendor/cstr_core
|
||||||
|
url = https://github.com/Amanieu/cstr_core
|
||||||
|
[submodule "rust/vendor/cty"]
|
||||||
|
path = rust/vendor/cty
|
||||||
|
url = https://github.com/japaric/cty
|
||||||
|
[submodule "rust/vendor/uuid"]
|
||||||
|
path = rust/vendor/uuid
|
||||||
|
url = https://github.com/uuid-rs/uuid
|
||||||
|
[submodule "rust/vendor/log"]
|
||||||
|
path = rust/vendor/log
|
||||||
|
url = https://github.com/rust-lang/log
|
||||||
|
[submodule "rust/vendor/memchr"]
|
||||||
|
path = rust/vendor/memchr
|
||||||
|
url = https://github.com/BurntSushi/memchr
|
||||||
|
|
39
Makefile
39
Makefile
|
@ -1,4 +1,5 @@
|
||||||
ARCH ?= aarch64-linux-gnu-
|
ARCH ?= aarch64-linux-gnu-
|
||||||
|
RUSTARCH ?= aarch64-unknown-none-softfloat
|
||||||
|
|
||||||
ifeq ($(shell uname),Darwin)
|
ifeq ($(shell uname),Darwin)
|
||||||
USE_CLANG ?= 1
|
USE_CLANG ?= 1
|
||||||
|
@ -35,8 +36,18 @@ CFLAGS := -O2 -Wall -g -Wundef -Werror=strict-prototypes -fno-common -fno-PIE \
|
||||||
-fno-stack-protector -mgeneral-regs-only -mstrict-align -march=armv8.2-a \
|
-fno-stack-protector -mgeneral-regs-only -mstrict-align -march=armv8.2-a \
|
||||||
$(EXTRA_CFLAGS)
|
$(EXTRA_CFLAGS)
|
||||||
|
|
||||||
|
CFG :=
|
||||||
ifeq ($(RELEASE),1)
|
ifeq ($(RELEASE),1)
|
||||||
CFLAGS += -DRELEASE
|
CFG += \#define RELEASE\\n
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Required for no_std + alloc for now
|
||||||
|
export RUSTUP_TOOLCHAIN=nightly
|
||||||
|
RUST_LIB := librust.a
|
||||||
|
RUST_LIBS :=
|
||||||
|
ifeq ($(CHAINLOADING),1)
|
||||||
|
CFG += \#define CHAINLOADING\\n
|
||||||
|
RUST_LIBS += $(RUST_LIB)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS := -EL -maarch64elf --no-undefined -X -Bsymbolic \
|
LDFLAGS := -EL -maarch64elf --no-undefined -X -Bsymbolic \
|
||||||
|
@ -102,7 +113,7 @@ OBJECTS := \
|
||||||
utils.o utils_asm.o \
|
utils.o utils_asm.o \
|
||||||
vsprintf.o \
|
vsprintf.o \
|
||||||
wdt.o \
|
wdt.o \
|
||||||
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS)
|
$(MINILZLIB_OBJECTS) $(TINF_OBJECTS) $(DLMALLOC_OBJECTS) $(LIBFDT_OBJECTS) $(RUST_LIBS)
|
||||||
|
|
||||||
DTS := t8103-j274.dts
|
DTS := t8103-j274.dts
|
||||||
|
|
||||||
|
@ -115,14 +126,18 @@ TARGET_RAW := m1n1.bin
|
||||||
|
|
||||||
DEPDIR := build/.deps
|
DEPDIR := build/.deps
|
||||||
|
|
||||||
.PHONY: all clean format update_tag
|
.PHONY: all clean format update_tag update_cfg
|
||||||
all: build/$(TARGET) build/$(TARGET_RAW) $(DTBS)
|
all: update_tag update_cfg build/$(TARGET) build/$(TARGET_RAW) $(DTBS)
|
||||||
clean:
|
clean:
|
||||||
rm -rf build/*
|
rm -rf build/*
|
||||||
format:
|
format:
|
||||||
$(CLANG_FORMAT) -i src/*.c src/*.h sysinc/*.h
|
$(CLANG_FORMAT) -i src/*.c src/*.h sysinc/*.h
|
||||||
format-check:
|
format-check:
|
||||||
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h
|
$(CLANG_FORMAT) --dry-run --Werror src/*.c src/*.h sysinc/*.h
|
||||||
|
rustfmt:
|
||||||
|
cd rust && cargo fmt
|
||||||
|
rustfmt-check:
|
||||||
|
cd rust && cargo fmt --check
|
||||||
|
|
||||||
build/dtb/%.dts: dts/%.dts
|
build/dtb/%.dts: dts/%.dts
|
||||||
@echo " DTCPP $@"
|
@echo " DTCPP $@"
|
||||||
|
@ -134,6 +149,13 @@ build/dtb/%.dtb: build/dtb/%.dts
|
||||||
@mkdir -p "$(dir $@)"
|
@mkdir -p "$(dir $@)"
|
||||||
@dtc -I dts -i dts $< -o $@
|
@dtc -I dts -i dts $< -o $@
|
||||||
|
|
||||||
|
build/$(RUST_LIB): rust/src/* rust/*
|
||||||
|
@echo " RS $@"
|
||||||
|
@mkdir -p $(DEPDIR)
|
||||||
|
@mkdir -p "$(dir $@)"
|
||||||
|
@cargo build --target $(RUSTARCH) --lib --release --manifest-path rust/Cargo.toml --target-dir build
|
||||||
|
@cp "build/$(RUSTARCH)/release/${RUST_LIB}" "$@"
|
||||||
|
|
||||||
build/%.o: src/%.S
|
build/%.o: src/%.S
|
||||||
@echo " AS $@"
|
@echo " AS $@"
|
||||||
@mkdir -p $(DEPDIR)
|
@mkdir -p $(DEPDIR)
|
||||||
|
@ -167,7 +189,13 @@ update_tag:
|
||||||
@cmp -s build/build_tag.h build/build_tag.tmp 2>/dev/null || \
|
@cmp -s build/build_tag.h build/build_tag.tmp 2>/dev/null || \
|
||||||
( mv -f build/build_tag.tmp build/build_tag.h && echo " TAG build/build_tag.h" )
|
( mv -f build/build_tag.tmp build/build_tag.h && echo " TAG build/build_tag.h" )
|
||||||
|
|
||||||
|
update_cfg:
|
||||||
|
@echo -ne "$(CFG)" > build/build_cfg.tmp
|
||||||
|
@cmp -s build/build_cfg.h build/build_cfg.tmp 2>/dev/null || \
|
||||||
|
( mv -f build/build_cfg.tmp build/build_cfg.h && echo " CFG build/build_cfg.h" )
|
||||||
|
|
||||||
build/build_tag.h: update_tag
|
build/build_tag.h: update_tag
|
||||||
|
build/build_cfg.h: update_cfg
|
||||||
|
|
||||||
build/%.bin: data/%.png
|
build/%.bin: data/%.png
|
||||||
@echo " IMG $@"
|
@echo " IMG $@"
|
||||||
|
@ -181,7 +209,8 @@ build/%.bin: font/%.bin
|
||||||
@echo " CP $@"
|
@echo " CP $@"
|
||||||
@cp $< $@
|
@cp $< $@
|
||||||
|
|
||||||
build/main.o: build/build_tag.h src/main.c
|
build/main.o: build/build_tag.h build/build_cfg.h src/main.c
|
||||||
build/usb_dwc3.o: build/build_tag.h src/usb_dwc3.c
|
build/usb_dwc3.o: build/build_tag.h src/usb_dwc3.c
|
||||||
|
build/chainload.o: build/build_cfg.h src/usb_dwc3.c
|
||||||
|
|
||||||
-include $(DEPDIR)/*
|
-include $(DEPDIR)/*
|
||||||
|
|
|
@ -132,3 +132,5 @@ licensed under the [OFL-1.1](3rdparty_licenses/LICENSE.OFL-1.1) license and copy
|
||||||
|
|
||||||
m1n1 embeds portions of the [dwc3 usb linux driver](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/dwc3/core.h?id=7bc5a6ba369217e0137833f5955cf0b0f08b0712), which was [BSD-or-GPLv2 dual-licensed](3rdparty_licenses/LICENSE.BSD-3.dwc3) and copyright
|
m1n1 embeds portions of the [dwc3 usb linux driver](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/dwc3/core.h?id=7bc5a6ba369217e0137833f5955cf0b0f08b0712), which was [BSD-or-GPLv2 dual-licensed](3rdparty_licenses/LICENSE.BSD-3.dwc3) and copyright
|
||||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
|
||||||
|
|
||||||
|
m1n1 embeds some rust crates. Licenses can be found in the vendor directory for every crate.
|
||||||
|
|
|
@ -45,6 +45,8 @@ SECTIONS {
|
||||||
*(.rela.text.*)
|
*(.rela.text.*)
|
||||||
*(.rela.data)
|
*(.rela.data)
|
||||||
*(.rela.data.*)
|
*(.rela.data.*)
|
||||||
|
*(.rela.rodata)
|
||||||
|
*(.rela.rodata*)
|
||||||
*(.rela.dyn)
|
*(.rela.dyn)
|
||||||
_rela_end = .;
|
_rela_end = .;
|
||||||
. = ALIGN(0x4000);
|
. = ALIGN(0x4000);
|
||||||
|
|
2
m1n1.ld
2
m1n1.ld
|
@ -150,6 +150,8 @@ SECTIONS {
|
||||||
*(.rela.text.*)
|
*(.rela.text.*)
|
||||||
*(.rela.data)
|
*(.rela.data)
|
||||||
*(.rela.data.*)
|
*(.rela.data.*)
|
||||||
|
*(.rela.rodata)
|
||||||
|
*(.rela.rodata*)
|
||||||
*(.rela.dyn)
|
*(.rela.dyn)
|
||||||
_rela_end = .;
|
_rela_end = .;
|
||||||
. = ALIGN(0x4000);
|
. = ALIGN(0x4000);
|
||||||
|
|
56
rust/Cargo.lock
generated
Normal file
56
rust/Cargo.lock
generated
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cstr_core"
|
||||||
|
version = "0.2.5"
|
||||||
|
dependencies = [
|
||||||
|
"cty",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cty"
|
||||||
|
version = "0.2.2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fatfs"
|
||||||
|
version = "0.4.0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.14"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cstr_core",
|
||||||
|
"cty",
|
||||||
|
"fatfs",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.0.0-alpha.1"
|
26
rust/Cargo.toml
Normal file
26
rust/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
[package]
|
||||||
|
name = "rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
repository = "https://github.com/AsahiLinux/m1n1"
|
||||||
|
license = "MIT"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = [ "staticlib" ]
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[dependencies]
|
||||||
|
fatfs = { path = "vendor/rust-fatfs", default-features = false, features = ["lfn", "alloc"] }
|
||||||
|
cstr_core = "0.2.5"
|
||||||
|
uuid = { version = "1.0.0-alpha.1", default-features = false }
|
||||||
|
cty = "0.2.2"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
uuid = { path = "vendor/uuid" }
|
||||||
|
cty = { path = "vendor/cty" }
|
||||||
|
cstr_core = { path = "vendor/cstr_core" }
|
||||||
|
memchr = { path = "vendor/memchr" }
|
||||||
|
log = { path = "vendor/log" }
|
||||||
|
bitflags = { path = "vendor/bitflags" }
|
||||||
|
cfg-if = { path = "vendor/cfg-if" }
|
85
rust/src/adt.rs
Normal file
85
rust/src/adt.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use core::ptr::null_mut;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
static mut adt: *mut c_void;
|
||||||
|
|
||||||
|
fn adt_path_offset_trace(adt: *const c_void, path: *const i8, offsets: *mut i32) -> isize;
|
||||||
|
fn adt_get_reg(
|
||||||
|
adt: *const c_void,
|
||||||
|
path: *const i32,
|
||||||
|
prop: *const i8,
|
||||||
|
idx: isize,
|
||||||
|
addr: *mut u64,
|
||||||
|
size: *mut u64,
|
||||||
|
) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Adt {
|
||||||
|
name: [i8; 32],
|
||||||
|
size: u32,
|
||||||
|
value: *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Adt {
|
||||||
|
pub unsafe fn get_default() -> &'static mut Self {
|
||||||
|
unsafe { core::mem::transmute(adt) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_reg(
|
||||||
|
&self,
|
||||||
|
path: &[i32],
|
||||||
|
prop: &[u8],
|
||||||
|
idx: isize,
|
||||||
|
addr: &mut u64,
|
||||||
|
size: Option<&mut u64>,
|
||||||
|
) -> isize {
|
||||||
|
let size = if let Some(size) = size {
|
||||||
|
size as *mut u64
|
||||||
|
} else {
|
||||||
|
null_mut()
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
adt_get_reg(
|
||||||
|
self.as_ptr(),
|
||||||
|
path.as_ptr(),
|
||||||
|
prop.as_ptr() as *const i8,
|
||||||
|
idx,
|
||||||
|
addr as *mut u64,
|
||||||
|
size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: return error with some sort of Error type
|
||||||
|
pub fn path_offset_trace(&self, path: &[u8], offsets: &mut [i32]) -> isize {
|
||||||
|
unsafe {
|
||||||
|
adt_path_offset_trace(
|
||||||
|
self.as_ptr(),
|
||||||
|
path.as_ptr() as *const i8,
|
||||||
|
offsets.as_mut_ptr(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_reg_addr(&self, path: &[i32], prop: &[u8], idx: isize) -> Result<u64, ()> {
|
||||||
|
let mut addr = 0;
|
||||||
|
|
||||||
|
let ret = self.get_reg(path, prop, idx, &mut addr, None);
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ptr(&self) -> *const c_void {
|
||||||
|
self as *const _ as *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut c_void {
|
||||||
|
self as *mut _ as *mut c_void
|
||||||
|
}
|
||||||
|
}
|
101
rust/src/chainload.rs
Normal file
101
rust/src/chainload.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
|
use crate::gpt;
|
||||||
|
use crate::nvme;
|
||||||
|
use crate::println;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use cstr_core::CStr;
|
||||||
|
use cty::*;
|
||||||
|
use fatfs::{FileSystem, FsOptions, Read, Seek, SeekFrom};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
FATError(fatfs::Error<nvme::Error>),
|
||||||
|
GPTError(gpt::Error<nvme::Error>),
|
||||||
|
BadArgs,
|
||||||
|
PartitionNotFound,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<fatfs::Error<nvme::Error>> for Error {
|
||||||
|
fn from(err: fatfs::Error<nvme::Error>) -> Error {
|
||||||
|
Error::FATError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<gpt::Error<nvme::Error>> for Error {
|
||||||
|
fn from(err: gpt::Error<nvme::Error>) -> Error {
|
||||||
|
Error::GPTError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_image(spec: &str) -> Result<Vec<u8>, Error> {
|
||||||
|
println!("Chainloading {}", spec);
|
||||||
|
|
||||||
|
let mut args = spec.split(';');
|
||||||
|
|
||||||
|
let uuid = Uuid::parse_str(args.next().ok_or(Error::BadArgs)?).or(Err(Error::BadArgs))?;
|
||||||
|
let path = args.next().ok_or(Error::BadArgs)?;
|
||||||
|
|
||||||
|
let part = {
|
||||||
|
let storage = nvme::NVMEStorage::new(1, 0);
|
||||||
|
let mut pt = gpt::GPT::new(storage)?;
|
||||||
|
|
||||||
|
//println!("Partitions:");
|
||||||
|
//pt.dump();
|
||||||
|
|
||||||
|
println!("Searching for partition UUID: {}", uuid);
|
||||||
|
pt.find_by_partuuid(uuid)?.ok_or(Error::PartitionNotFound)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = part.get_starting_lba();
|
||||||
|
|
||||||
|
println!("Partition offset: {}", offset);
|
||||||
|
|
||||||
|
let storage = nvme::NVMEStorage::new(1, offset);
|
||||||
|
let opts = FsOptions::new().update_accessed_date(false);
|
||||||
|
|
||||||
|
let fs = FileSystem::new(storage, opts)?;
|
||||||
|
let mut file = fs.root_dir().open_file(path)?;
|
||||||
|
|
||||||
|
let size = file.seek(SeekFrom::End(0))? as usize;
|
||||||
|
file.seek(SeekFrom::Start(0))?;
|
||||||
|
|
||||||
|
println!("File size: {}", size);
|
||||||
|
|
||||||
|
let mut buf: Vec<u8> = vec![0; size];
|
||||||
|
let mut slice = &mut buf[..];
|
||||||
|
while !slice.is_empty() {
|
||||||
|
let read = file.read(slice)?;
|
||||||
|
slice = &mut slice[read..];
|
||||||
|
}
|
||||||
|
println!("File read successfully");
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn rust_load_image(
|
||||||
|
raw_spec: *const c_char,
|
||||||
|
image: *mut *mut c_void,
|
||||||
|
size: *mut size_t,
|
||||||
|
) -> c_int {
|
||||||
|
let spec = unsafe { CStr::from_ptr(raw_spec).to_str().unwrap() };
|
||||||
|
|
||||||
|
match load_image(spec) {
|
||||||
|
Ok(buf) => {
|
||||||
|
unsafe {
|
||||||
|
*size = buf.len();
|
||||||
|
*image = buf.leak().as_mut_ptr() as *mut c_void;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("Chainload failed: {:?}", err);
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
rust/src/dlmalloc.rs
Normal file
57
rust/src/dlmalloc.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use core::ptr;
|
||||||
|
use cty::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn malloc(size: size_t) -> *mut c_void;
|
||||||
|
pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
|
||||||
|
pub fn free(p: *mut c_void);
|
||||||
|
pub fn posix_memalign(p: *mut *mut c_void, alignment: size_t, size: size_t) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DLMalloc;
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for DLMalloc {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let mut ptr = ptr::null_mut();
|
||||||
|
let ret = unsafe {
|
||||||
|
posix_memalign(
|
||||||
|
&mut ptr,
|
||||||
|
layout.align().max(core::mem::size_of::<usize>()),
|
||||||
|
layout.size(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret == 0 {
|
||||||
|
ptr as *mut u8
|
||||||
|
} else {
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||||
|
// Unfortunately, calloc doesn't make any alignment guarantees, so the memory
|
||||||
|
// has to be manually zeroed-out.
|
||||||
|
let ptr = unsafe { self.alloc(layout) };
|
||||||
|
if !ptr.is_null() {
|
||||||
|
unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
|
||||||
|
}
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||||
|
unsafe {
|
||||||
|
free(ptr as *mut c_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 {
|
||||||
|
unsafe { realloc(ptr as *mut c_void, new_size) as *mut u8 }
|
||||||
|
}
|
||||||
|
}
|
162
rust/src/gpt.rs
Normal file
162
rust/src/gpt.rs
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use crate::println;
|
||||||
|
use core::convert::TryInto;
|
||||||
|
use core::result::Result;
|
||||||
|
use fatfs::{Read, Seek};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
const EFI_SIGNATURE: u64 = 0x5452415020494645;
|
||||||
|
|
||||||
|
const SECTOR_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error<T> {
|
||||||
|
Io(T),
|
||||||
|
InvalidGPTHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Error<T> {
|
||||||
|
fn from(err: T) -> Error<T> {
|
||||||
|
Error::Io(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TableHeader {
|
||||||
|
bytes: [u8; Self::SIZE],
|
||||||
|
my_lba: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableHeader {
|
||||||
|
const SIZE: usize = 0x5C;
|
||||||
|
|
||||||
|
fn read<R: Read + Seek>(rdr: &mut R, lba: u64) -> Result<Self, Error<R::Error>> {
|
||||||
|
let mut hdr = Self {
|
||||||
|
bytes: [0; Self::SIZE],
|
||||||
|
my_lba: lba,
|
||||||
|
};
|
||||||
|
let off = SECTOR_SIZE * (lba as usize);
|
||||||
|
rdr.seek(fatfs::SeekFrom::Start(off as u64))?;
|
||||||
|
rdr.read_exact(&mut hdr.bytes)?;
|
||||||
|
match hdr.is_valid() {
|
||||||
|
true => Ok(hdr),
|
||||||
|
false => Err(Error::InvalidGPTHeader),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_signature(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[0..8].try_into().unwrap())
|
||||||
|
}
|
||||||
|
fn get_my_lba(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[24..32].try_into().unwrap())
|
||||||
|
}
|
||||||
|
fn get_partition_entry_lba(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[72..80].try_into().unwrap())
|
||||||
|
}
|
||||||
|
fn get_partition_entry_count(&self) -> usize {
|
||||||
|
u32::from_le_bytes(self.bytes[80..84].try_into().unwrap()) as usize
|
||||||
|
}
|
||||||
|
fn get_partition_entry_size(&self) -> usize {
|
||||||
|
u32::from_le_bytes(self.bytes[84..88].try_into().unwrap()) as usize
|
||||||
|
}
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
self.get_signature() == EFI_SIGNATURE && self.get_my_lba() == self.my_lba
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PartitionEntry {
|
||||||
|
bytes: [u8; Self::SIZE],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartitionEntry {
|
||||||
|
const SIZE: usize = 0x80;
|
||||||
|
|
||||||
|
fn read<R: Read + Seek>(rdr: &mut R, off: usize) -> Result<Self, Error<R::Error>> {
|
||||||
|
let mut part = Self {
|
||||||
|
bytes: [0; Self::SIZE],
|
||||||
|
};
|
||||||
|
rdr.seek(fatfs::SeekFrom::Start(off as u64))?;
|
||||||
|
rdr.read_exact(&mut part.bytes)?;
|
||||||
|
Ok(part)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_type_guid(&self) -> Uuid {
|
||||||
|
Uuid::from_bytes_le(self.bytes[0..16].try_into().unwrap())
|
||||||
|
}
|
||||||
|
pub fn get_partition_guid(&self) -> Uuid {
|
||||||
|
Uuid::from_bytes_le(self.bytes[16..32].try_into().unwrap())
|
||||||
|
}
|
||||||
|
pub fn get_starting_lba(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[32..40].try_into().unwrap())
|
||||||
|
}
|
||||||
|
pub fn get_ending_lba(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[40..48].try_into().unwrap())
|
||||||
|
}
|
||||||
|
pub fn get_attributes(&self) -> u64 {
|
||||||
|
u64::from_le_bytes(self.bytes[48..56].try_into().unwrap())
|
||||||
|
}
|
||||||
|
pub fn get_name(&self) -> &[u8] {
|
||||||
|
&self.bytes[56..72]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GPT<T: fatfs::ReadWriteSeek> {
|
||||||
|
disk: T,
|
||||||
|
hdr: TableHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<IO: fatfs::ReadWriteSeek> GPT<IO> {
|
||||||
|
pub fn new<T: fatfs::IntoStorage<IO>>(storage: T) -> Result<Self, Error<IO::Error>> {
|
||||||
|
let mut disk = storage.into_storage();
|
||||||
|
|
||||||
|
let hdr = TableHeader::read(&mut disk, 1)?;
|
||||||
|
|
||||||
|
let gpt = Self { disk, hdr };
|
||||||
|
Ok(gpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count(&self) -> usize {
|
||||||
|
self.hdr.get_partition_entry_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&mut self, index: usize) -> Result<PartitionEntry, Error<IO::Error>> {
|
||||||
|
let off = (self.hdr.get_partition_entry_lba() as usize * SECTOR_SIZE)
|
||||||
|
+ index * self.hdr.get_partition_entry_size();
|
||||||
|
PartitionEntry::read(&mut self.disk, off)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_by_partuuid(
|
||||||
|
&mut self,
|
||||||
|
uuid: Uuid,
|
||||||
|
) -> Result<Option<PartitionEntry>, Error<IO::Error>> {
|
||||||
|
for i in 0..self.count() {
|
||||||
|
let part = self.index(i)?;
|
||||||
|
if part.get_type_guid().is_nil() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if part.get_partition_guid() == uuid {
|
||||||
|
return Ok(Some(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(&mut self) {
|
||||||
|
for i in 0..self.count() {
|
||||||
|
let part = self.index(i).unwrap();
|
||||||
|
let guid = part.get_type_guid();
|
||||||
|
if guid.is_nil() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"{}: {}..{} {:x} {:x}",
|
||||||
|
i,
|
||||||
|
part.get_starting_lba(),
|
||||||
|
part.get_ending_lba(),
|
||||||
|
guid,
|
||||||
|
part.get_partition_guid()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
rust/src/lib.rs
Normal file
37
rust/src/lib.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
#![no_std]
|
||||||
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
#![feature(mixed_integer_ops)]
|
||||||
|
#![feature(new_uninit)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub mod adt;
|
||||||
|
pub mod chainload;
|
||||||
|
pub mod dlmalloc;
|
||||||
|
pub mod gpt;
|
||||||
|
pub mod nvme;
|
||||||
|
pub mod print;
|
||||||
|
|
||||||
|
use crate::dlmalloc::DLMalloc;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: DLMalloc = dlmalloc::DLMalloc;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn flush_and_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &::core::panic::PanicInfo) -> ! {
|
||||||
|
println!("{}", info);
|
||||||
|
unsafe { flush_and_reboot() };
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error(layout: core::alloc::Layout) -> ! {
|
||||||
|
panic!("memory allocation of {} bytes failed", layout.size())
|
||||||
|
}
|
93
rust/src/nvme.rs
Normal file
93
rust/src/nvme.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
use crate::println;
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use core::cmp::min;
|
||||||
|
use core::ffi::c_void;
|
||||||
|
use fatfs::SeekFrom;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn nvme_read(nsid: u32, lba: u64, buffer: *mut c_void) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SECTOR_SIZE: usize = 4096;
|
||||||
|
|
||||||
|
pub type Error = ();
|
||||||
|
|
||||||
|
#[repr(C, align(4096))]
|
||||||
|
struct SectorBuffer([u8; SECTOR_SIZE]);
|
||||||
|
|
||||||
|
fn alloc_sector_buf() -> Box<SectorBuffer> {
|
||||||
|
let p: Box<SectorBuffer> = unsafe { Box::new_zeroed().assume_init() };
|
||||||
|
debug_assert_eq!(0, p.0.as_ptr().align_offset(4096));
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NVMEStorage {
|
||||||
|
nsid: u32,
|
||||||
|
offset: u64,
|
||||||
|
lba: Option<u64>,
|
||||||
|
buf: Box<SectorBuffer>,
|
||||||
|
pos: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NVMEStorage {
|
||||||
|
pub fn new(nsid: u32, offset: u64) -> NVMEStorage {
|
||||||
|
NVMEStorage {
|
||||||
|
nsid: nsid,
|
||||||
|
offset: offset,
|
||||||
|
lba: None,
|
||||||
|
buf: alloc_sector_buf(),
|
||||||
|
pos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fatfs::IoBase for NVMEStorage {
|
||||||
|
type Error = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fatfs::Read for NVMEStorage {
|
||||||
|
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
let mut read = 0;
|
||||||
|
|
||||||
|
while !buf.is_empty() {
|
||||||
|
let lba = self.pos / SECTOR_SIZE as u64;
|
||||||
|
let off = self.pos as usize % SECTOR_SIZE;
|
||||||
|
|
||||||
|
if Some(lba) != self.lba {
|
||||||
|
self.lba = Some(lba);
|
||||||
|
let lba = lba + self.offset;
|
||||||
|
if !unsafe { nvme_read(self.nsid, lba, self.buf.0.as_mut_ptr() as *mut c_void) } {
|
||||||
|
println!("nvme_read({}, {}) failed", self.nsid, lba);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let copy_len = min(SECTOR_SIZE - off, buf.len());
|
||||||
|
buf[..copy_len].copy_from_slice(&self.buf.0[off..off + copy_len]);
|
||||||
|
buf = &mut buf[copy_len..];
|
||||||
|
read += copy_len;
|
||||||
|
self.pos += copy_len as u64;
|
||||||
|
}
|
||||||
|
Ok(read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fatfs::Write for NVMEStorage {
|
||||||
|
fn write(&mut self, _buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fatfs::Seek for NVMEStorage {
|
||||||
|
fn seek(&mut self, from: SeekFrom) -> Result<u64, Self::Error> {
|
||||||
|
self.pos = match from {
|
||||||
|
SeekFrom::Start(n) => n,
|
||||||
|
SeekFrom::End(_n) => panic!("SeekFrom::End not supported"),
|
||||||
|
SeekFrom::Current(n) => self.pos.checked_add_signed(n).ok_or(())?,
|
||||||
|
};
|
||||||
|
Ok(self.pos)
|
||||||
|
}
|
||||||
|
}
|
60
rust/src/print.rs
Normal file
60
rust/src/print.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
use core::ffi::c_void;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn iodev_console_write(buf: *const c_void, len: u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct IODevConsoleWriter;
|
||||||
|
|
||||||
|
impl core::fmt::Write for IODevConsoleWriter {
|
||||||
|
#[inline]
|
||||||
|
fn write_str(&mut self, msg: &str) -> core::fmt::Result {
|
||||||
|
write(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IODevConsoleWriter {
|
||||||
|
#[inline]
|
||||||
|
pub fn write_fmt(args: core::fmt::Arguments) -> core::fmt::Result {
|
||||||
|
core::fmt::Write::write_fmt(&mut Self, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_str(msg: &str) -> core::fmt::Result {
|
||||||
|
write(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_nl() -> core::fmt::Result {
|
||||||
|
write("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write(msg: &str) -> core::fmt::Result {
|
||||||
|
unsafe { iodev_console_write(msg.as_ptr() as _, msg.len() as u64) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => { $crate::println!("") };
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
{
|
||||||
|
$crate::print::IODevConsoleWriter::write_fmt(format_args!($($arg)*));
|
||||||
|
$crate::print::IODevConsoleWriter::write_nl();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
{
|
||||||
|
$crate::print::IODevConsoleWriter::write_fmt(format_args!($($arg)*));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
1
rust/vendor/bitflags
vendored
Submodule
1
rust/vendor/bitflags
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ed185cfb1c447c1b4bd6ac021c9ec3bb02c9e2f2
|
1
rust/vendor/cfg-if
vendored
Submodule
1
rust/vendor/cfg-if
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit e60fa1efeab0ec6e90c50d93ec526e1410459c23
|
1
rust/vendor/cstr_core
vendored
Submodule
1
rust/vendor/cstr_core
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 35e44d2a128f29a52ac0a43baa2d9238bd7239dd
|
1
rust/vendor/cty
vendored
Submodule
1
rust/vendor/cty
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit dcc347dc8afb74906719e68e2f48e3ff38dcc76f
|
1
rust/vendor/log
vendored
Submodule
1
rust/vendor/log
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 9d4206770dd93f07cb27c3e1f41dc21c45031302
|
1
rust/vendor/memchr
vendored
Submodule
1
rust/vendor/memchr
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 8e1da98fee06d66c13e66c330e3a3dd6ccf0e3a0
|
1
rust/vendor/rust-fatfs
vendored
Submodule
1
rust/vendor/rust-fatfs
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 87fc1ed5074a32b4e0344fcdde77359ef9e75432
|
1
rust/vendor/uuid
vendored
Submodule
1
rust/vendor/uuid
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit b98c9586c1359a5cc354defe20d8ea31e58f29f0
|
|
@ -1,5 +1,7 @@
|
||||||
/* SPDX-License-Identifier: MIT */
|
/* SPDX-License-Identifier: MIT */
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
#include "chainload.h"
|
#include "chainload.h"
|
||||||
#include "adt.h"
|
#include "adt.h"
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
|
@ -10,6 +12,10 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "xnuboot.h"
|
#include "xnuboot.h"
|
||||||
|
|
||||||
|
#ifdef CHAINLOADING
|
||||||
|
int rust_load_image(const char *spec, void **image, size_t *size);
|
||||||
|
#endif
|
||||||
|
|
||||||
extern u8 _chainload_stub_start[];
|
extern u8 _chainload_stub_start[];
|
||||||
extern u8 _chainload_stub_end[];
|
extern u8 _chainload_stub_end[];
|
||||||
|
|
||||||
|
@ -107,6 +113,29 @@ int chainload_image(void *image, size_t size, char **vars, size_t var_cnt)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CHAINLOADING
|
||||||
|
|
||||||
|
int chainload_load(const char *spec, char **vars, size_t var_cnt)
|
||||||
|
{
|
||||||
|
void *image;
|
||||||
|
size_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!nvme_init()) {
|
||||||
|
printf("chainload: NVME init failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rust_load_image(spec, &image, &size);
|
||||||
|
nvme_shutdown();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return chainload_image(image, size, vars, var_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
int chainload_load(const char *spec, char **vars, size_t var_cnt)
|
int chainload_load(const char *spec, char **vars, size_t var_cnt)
|
||||||
{
|
{
|
||||||
UNUSED(spec);
|
UNUSED(spec);
|
||||||
|
@ -116,3 +145,5 @@ int chainload_load(const char *spec, char **vars, size_t var_cnt)
|
||||||
printf("Chainloading files not supported in this build!\n");
|
printf("Chainloading files not supported in this build!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "payload.h"
|
#include "payload.h"
|
||||||
#include "adt.h"
|
#include "adt.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
#include "chainload.h"
|
||||||
#include "heapblock.h"
|
#include "heapblock.h"
|
||||||
#include "kboot.h"
|
#include "kboot.h"
|
||||||
#include "smp.h"
|
#include "smp.h"
|
||||||
|
@ -27,6 +28,7 @@ static const u8 empty[] = {0, 0, 0, 0};
|
||||||
static char expect_compatible[256];
|
static char expect_compatible[256];
|
||||||
static struct kernel_header *kernel = NULL;
|
static struct kernel_header *kernel = NULL;
|
||||||
static void *fdt = NULL;
|
static void *fdt = NULL;
|
||||||
|
static char *chainload_spec = NULL;
|
||||||
|
|
||||||
static void *load_one_payload(void *start, size_t size);
|
static void *load_one_payload(void *start, size_t size);
|
||||||
|
|
||||||
|
@ -172,6 +174,9 @@ static bool check_var(u8 **p)
|
||||||
printf("Too many chosen vars, ignoring %s='%s'\n", *p, val);
|
printf("Too many chosen vars, ignoring %s='%s'\n", *p, val);
|
||||||
else
|
else
|
||||||
chosen[chosen_cnt++] = (char *)*p;
|
chosen[chosen_cnt++] = (char *)*p;
|
||||||
|
} else if (IS_VAR("chainload=")) {
|
||||||
|
*end = 0;
|
||||||
|
chainload_spec = val;
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown variable %s\n", *p);
|
printf("Unknown variable %s\n", *p);
|
||||||
}
|
}
|
||||||
|
@ -242,6 +247,10 @@ int payload_run(void)
|
||||||
while (p)
|
while (p)
|
||||||
p = load_one_payload(p, 0);
|
p = load_one_payload(p, 0);
|
||||||
|
|
||||||
|
if (chainload_spec) {
|
||||||
|
return chainload_load(chainload_spec, chosen, chosen_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
if (kernel && fdt) {
|
if (kernel && fdt) {
|
||||||
smp_start_secondaries();
|
smp_start_secondaries();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue