apps/rust: start of sdk runtime support for Rust apps

Rust application runtime support + equivalents of hello & fibnoacci.

Change-Id: Ica9b0d181387f159169cbe5f219d26c96540a56d
GitOrigin-RevId: 0a14b67ddd9b166a8ba5c13bac37a30204deb3b0
This commit is contained in:
Sam Leffler
2022-09-16 18:33:10 +00:00
parent d0d46c89e1
commit 95f8965986
15 changed files with 561 additions and 86 deletions

40
apps/rust/Cargo.toml Normal file
View File

@@ -0,0 +1,40 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[workspace]
members = [
"libkata",
"hello",
"fibonacci",
]
resolver = "2"
[profile.dev]
opt-level = 0
debug = true
# TODO(b/223253186): workaround gdb DIE errors
lto = false
codegen-units = 1
[profile.release]
opt-level = "z"
lto = "fat"
codegen-units = 1
split-debuginfo = "unpacked"
[profile.release.build-override]
opt-level = "z"
codegen-units = 1

View File

@@ -0,0 +1,39 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "fibonacci"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[build-dependencies]
# build.rs depends on SEL4_OUT_DIR = "${ROOTDIR}/out/kata/kernel"
sel4-config = { path = "../../system/components/kata-os-common/src/sel4-config" }
[features]
default = []
# Used by sel4-config to extract kernel config
CONFIG_PRINTING = []
[lib]
name = "fibonacci"
path = "fibonacci.rs"
crate-type = ["staticlib"]
[dependencies]
kata-os-common = { path = "../../system/components/kata-os-common", default-features = false }
kata-sdk-interface = { path = "../../system/components/SDKRuntime/kata-sdk-interface" }
libkata = { path = "../libkata" }
log = "0.4"

View File

@@ -0,0 +1,18 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
APPNAME := fibonacci
LIBKATA ?= ../libkata
include ${LIBKATA}/make/app.mk

View File

@@ -0,0 +1,34 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate sel4_config;
use std::env;
fn main() {
// If SEL4_OUT_DIR is not set we expect the kernel build at a fixed
// location relative to the ROOTDIR env variable.
println!("SEL4_OUT_DIR {:?}", env::var("SEL4_OUT_DIR"));
let sel4_out_dir = env::var("SEL4_OUT_DIR")
.unwrap_or_else(|_| format!("{}/out/kata/kernel", env::var("ROOTDIR").unwrap()));
println!("sel4_out_dir {}", sel4_out_dir);
// Dredge seL4 kernel config for settings we need as features to generate
// correct code: e.g. CONFIG_KERNEL_MCS enables MCS support which changes
// the system call numbering.
let features = sel4_config::get_sel4_features(&sel4_out_dir);
println!("features={:?}", features);
for feature in features {
println!("cargo:rustc-cfg=feature=\"{}\"", feature);
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2021, Google LLC
*
* Demo to show that concurrent applications can be running.
*
* This program prints the first LOG_FIBONACCI_LIMIT Fibonacci numbers
* to the console, waiting for INTERRUPTS_PER_WAIT interrupts between each
* number.
*
* SPDX-License-Identifier: Apache-2.0
*/
#![no_std]
#![no_main]
#![feature(asm)]
extern crate alloc;
extern crate libkata;
use alloc::format;
use kata_os_common::allocator;
use kata_sdk_interface::kata_sdk_log;
// How many Fibonacci numbers to write to the log.
const LOG_FIBONACCI_LIMIT: u64 = 80;
const CONFIG_TIMER_TICK_MS: usize = 5;
const INTERRUPTS_PER_VIRT_SEC: u64 = (1000 / CONFIG_TIMER_TICK_MS) as u64;
const INTERRUPTS_PER_WAIT: u64 = 1 * INTERRUPTS_PER_VIRT_SEC;
type ICount = u64;
struct Fibonacci {
f1: u64,
f2: u64,
n: u64,
}
impl Fibonacci {
pub fn new() -> Self { Self { f1: 0, f2: 1, n: 0 } }
pub fn increment(&mut self) {
let swap: u64 = self.f2;
self.f2 = self.f1 + self.f2;
self.f1 = swap;
self.n += 1;
}
pub fn reset(&mut self) {
self.f1 = 0;
self.f2 = 1;
self.n = 0;
}
pub fn log(&self, interrupt_count: ICount) {
let _ = kata_sdk_log(&format!(
"n == {}; f == {:x}; interrupt_count == {}; rdtime == {}; virt_sec ~= {:2}",
self.n,
self.f1,
interrupt_count,
rdtime(),
virtual_seconds(interrupt_count),
));
}
}
fn wait(interrupt_count_to_wait: ICount, count: &mut ICount) {
for _ in 0..interrupt_count_to_wait {
unsafe { asm!("wfi") }
(*count) += 1;
}
}
fn virtual_seconds(interrupt_count: ICount) -> f32 {
(interrupt_count as f32) / (INTERRUPTS_PER_VIRT_SEC as f32)
}
#[allow(unused_assignments)]
fn rdtime() -> u64 {
let mut upper: u32 = 0;
let mut lower: u32 = 0;
let mut upper_reread: u32 = 0;
loop {
unsafe {
asm!(
"rdtimeh {upper}
rdtime {lower}
rdtimeh {upper_reread}",
upper = out (reg) upper,
lower = out (reg) lower,
upper_reread = out (reg) upper_reread,
)
}
if upper_reread == upper {
break;
}
}
((upper as u64) << 32) | (lower as u64)
}
#[no_mangle]
pub fn main() {
static mut HEAP: [u8; 4096] = [0; 4096];
unsafe {
allocator::ALLOCATOR.init(HEAP.as_mut_ptr() as _, HEAP.len());
}
let _ = kata_sdk_log("Fibonacci");
let mut interrupt_count: ICount = 0;
let mut fib = Fibonacci::new();
loop {
wait(INTERRUPTS_PER_WAIT, &mut interrupt_count);
if fib.n >= LOG_FIBONACCI_LIMIT {
fib.reset();
}
fib.log(interrupt_count);
fib.increment();
}
}

View File

@@ -35,4 +35,6 @@ crate-type = ["staticlib"]
[dependencies] [dependencies]
cstr_core = { version = "0.2.3", default-features = false } cstr_core = { version = "0.2.3", default-features = false }
kata-os-common = { path = "../../system/components/kata-os-common", default-features = false } kata-os-common = { path = "../../system/components/kata-os-common", default-features = false }
kata-sdk-interface = { path = "../../system/components/SDKRuntime/kata-sdk-interface" }
libkata = { path = "../libkata" }
log = "0.4" log = "0.4"

View File

@@ -1,24 +1,18 @@
OUT_KATA ?= $(OUT)/kata/riscv32-unknown-elf/release # Copyright 2022 Google LLC
OUT_HELLO ?= $(OUT_KATA)/apps/hello #
CARGO_OPTS ?= --release # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# hello app staticlib (location set w/ --out-dir below) APPNAME := hello
LIB_HELLO := ${OUT_HELLO}/libhello.a
# To satisfy Rust core deps with debug build
LIB_LIBC := ${OUT_KATA}/musllibc/build-temp/stage/lib/libc.a
LD_FLAGS := -march=rv32imac -mabi=ilp32 -static -nostdlib -ftls-model=local-exec LIBKATA ?= ../libkata
#DBG:=-g include ${LIBKATA}/make/app.mk
# NB: let cargo handle incremental build steps
${OUT_HELLO}/hello.elf: hello.rs | tmp_check
SEL4_OUT_DIR=${OUT_KATA}/kernel kcargo build ${CARGO_OPTS} --target-dir ${OUT_HELLO} --out-dir ${OUT_HELLO}
riscv32-unknown-elf-gcc ${LD_FLAGS} $(DBG) ${LIB_HELLO} ${LIB_LIBC} -o ${OUT_HELLO}/hello.elf
tmp_check:
mkdir -p $(OUT_HELLO)
clean:
rm -rf ${OUT_HELLO}
PHONY: tmp_check

View File

@@ -5,83 +5,33 @@
*/ */
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(asm)]
#![feature(thread_local)]
// TODO(sleffler): plumb logger to SDKRuntime to eliminate seL4_DebugPutChar
// (or provide a logger alternative)
extern crate libkata;
use kata_os_common::logger::KataLogger; use kata_os_common::logger::KataLogger;
use kata_os_common::sel4_sys; use kata_sdk_interface::*;
use log::info;
use sel4_sys::seL4_IPCBuffer;
const PAGE_SIZE: usize = 4096;
#[no_mangle]
#[thread_local]
static mut __sel4_ipc_buffer: *mut seL4_IPCBuffer = 0 as _;
#[repr(align(4096))]
#[allow(dead_code)]
struct PageAlign {
data: [u8; PAGE_SIZE],
}
static mut STATIC_TLS: PageAlign = PageAlign {
data: [0u8; PAGE_SIZE],
};
#[no_mangle]
pub fn _start() {
unsafe {
asm!("
.option push
.option norelax
la gp, __global_pointer$
la tp, {tls}
lui t1,0
add t1,t1,tp
sw a0,0(t1) # __sel4_ipc_buffer>
addi sp,sp,-16
sw a0, 12(sp)
sw a1, 8(sp)
sw a2, 4(sp)
sw a3, 0(sp)
.option pop
j main",
tls = sym STATIC_TLS,
options(noreturn),
)
};
}
// Message output is sent through the kata-os-logger which calls logger_log // Message output is sent through the kata-os-logger which calls logger_log
// to deliver data to the console. We use seL4_DebugPutChar to write to the // to deliver data to the console. Redict to the sdk.
// console which only works if DEBUG_PRINTING is enabled in the kernel.
#[no_mangle] #[no_mangle]
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn logger_log(_level: u8, msg: *const cstr_core::c_char) { pub fn logger_log(_level: u8, msg: *const cstr_core::c_char) {
#[cfg(feature = "CONFIG_PRINTING")] if let Ok(str) = unsafe { cstr_core::CStr::from_ptr(msg) }.to_str() {
unsafe { let _ = kata_sdk_log(str);
for c in cstr_core::CStr::from_ptr(msg).to_bytes() {
let _ = sel4_sys::seL4_DebugPutChar(*c);
}
let _ = sel4_sys::seL4_DebugPutChar(b'\n');
} }
} }
#[no_mangle] #[no_mangle]
// XXX need SDK specification of main, use hack for now pub fn main() {
pub fn main(a0: u32, a1: u32, a2: u32, a3: u32) { // Setup logger; (XXX maybe belongs in the SDKRuntime)
// Setup logger; (XXX belongs in the SDKRuntime)
static KATA_LOGGER: KataLogger = KataLogger; static KATA_LOGGER: KataLogger = KataLogger;
log::set_logger(&KATA_LOGGER).unwrap(); log::set_logger(&KATA_LOGGER).unwrap();
log::set_max_level(log::LevelFilter::Trace); log::set_max_level(log::LevelFilter::Trace);
// XXX maybe setup a heap (XXX belongs in the SDKRuntime) match kata_sdk_ping() {
Ok(_) => info!("ping!"),
log::info!("I am a Rust app, hear me roar!"); Err(e) => info!("kata_sdk_ping failed: {:?}", e),
log::info!("a0 {:x} a1 {:x} a2 {:x} a3 {:x}", a0, a1, a2, a3); }
log::info!("__sel4_ipc_buffer {:p}", unsafe { __sel4_ipc_buffer }); info!("I am a Rust app, hear me log!");
log::info!("Done, wimper ..."); info!("Done, wimper ...");
} }

View File

@@ -0,0 +1,25 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "libkata"
version = "0.1.0"
edition = "2021"
[lib]
path = "lib.rs"
[dependencies]
sel4-sys = { path = "../../system/components/kata-os-common/src/sel4-sys", default-features = false }
static_assertions = "1.1"

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.section .text._start
.align 2
.globl _start
.type _start, @function
_start:
.option push
.option norelax
la gp, __global_pointer$
la x4, _tls
/* Setup __sel4_ipc_buffer */
lui t1, 0
add t1, t1, tp
sw a0, 0(t1)
/* Setup SDKRuntime RPC framework */
/* seL4_CPtr to SDKRuntime Endpoint */
la t1, KATA_SDK_ENDPOINT
sw a1, 0(t1)
/* seL4_CPtr to KATA_SDK_PARAMS Frame object */
la t1, KATA_SDK_FRAME
sw a2, 0(t1)
/* virtual address of KATA_SDK_PARAMS */
la t1, KATA_SDK_PARAMS
sw a3, 0(t1)
/* XXX included only for testing */
addi sp, sp, -16
sw a0, 12(sp)
sw a1, 8(sp)
sw a2, 4(sp)
sw a3, 0(sp)
.option pop
j main
.section .bss
.align 12
.globl _tls
.type _tls, tls_object
_tls:
.ds.b 4096
.align 2
.global KATA_SDK_ENDPOINT
KATA_SDK_ENDPOINT:
.ds.b 4
.align 2
.global KATA_SDK_FRAME
KATA_SDK_FRAME:
.ds.b 4
.align 2
.global KATA_SDK_PARAMS
KATA_SDK_PARAMS:
.ds.b 4

54
apps/rust/libkata/lib.rs Normal file
View File

@@ -0,0 +1,54 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_std]
#![allow(non_upper_case_globals)]
#![feature(global_asm)]
#![feature(thread_local)]
use core::arch::global_asm;
use sel4_sys::seL4_IPCBuffer;
use static_assertions::*;
// NB: this mimics the logic in build.rs
assert_cfg!(any(
all(target_arch = "arm", target_pointer_width = "32"),
all(target_arch = "aarch64"),
all(target_arch = "riscv32"),
all(target_arch = "riscv64"),
all(target_arch = "x86"),
all(target_arch = "x86_64"),
));
#[cfg(target_arch = "x86")]
global_asm!(include_str!("arch/x86/crt0.S"));
#[cfg(target_arch = "x86_64")]
global_asm!(include_str!("arch/x86_64/crt0.S"));
#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
global_asm!(include_str!("arch/aarch32/crt0.S"));
#[cfg(target_arch = "aarch64")]
global_asm!(include_str!("arch/aarch64/crt0.S"));
#[cfg(target_arch = "riscv32")]
global_asm!(include_str!("arch/riscv32/crt0.S"));
#[cfg(target_arch = "riscv64")]
global_asm!(include_str!("arch/riscv64/crt0.S"));
#[no_mangle]
#[thread_local]
static mut __sel4_ipc_buffer: *mut seL4_IPCBuffer = 0 as _;

View File

@@ -0,0 +1,35 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
MYDIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
include $(MYDIR)/common.mk
BUILD_DIR := $(BUILD_ROOT)/$(APPNAME)
INTERMEDIATES := ${BUILD_DIR}/lib${APPNAME}.a
$(BUILD_DIR)/$(APPNAME).elf: lib${APPNAME} ${LIB_LIBC} | $(BUILD_DIR)
$(LD) $(LDFLAGS) -o $(BUILD_DIR)/$(APPNAME).elf $(INTERMEDIATES) $(LIB_LIBC)
lib${APPNAME}:
SEL4_OUT_DIR=${OUT_KATA}/kernel \
${CARGO} build ${CARGO_OPTS} --target-dir ${BUILD_DIR} --out-dir ${BUILD_DIR}
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
clean:
rm -rf $(BUILD_DIR)
.PHONY: clean lib${APPNAME}

View File

@@ -0,0 +1,20 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
BASE_ARCH_NAME := riscv
ARCH_BITS := 32
FULL_ARCH_NAME := riscv32imac
ARCH_PREFIX := riscv32-unknown-elf
ARCH := rv32imac
ABI := ilp32

View File

@@ -0,0 +1,56 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
MYDIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
BUILD_TYPE ?= debug
BUILD_ARCH ?= riscv32
include $(MYDIR)/arch/$(BUILD_ARCH).mk
include $(MYDIR)/sel4.mk
ifeq ($(BUILD_TYPE),debug)
DEBUG := -g
OPT := -O0
CARGO_OPTS :=
else
DEBUG :=
OPT := -O0 # TODO(jtgans): Actually optimize in a release build
CARGO_OPTS := --release
endif
ROOTDIR ?= $(MYDIR)
BUILD_ROOT ?= $(ROOTDIR)/out/kata/$(ARCH_PREFIX)/$(BUILD_TYPE)/apps/rust
CC := $(ARCH_PREFIX)-gcc
AS := $(ARCH_PREFIX)-as
AR := $(ARCH_PREFIX)-ar
LD := $(ARCH_PREFIX)-gcc
KATA_RUST_VERSION ?= nightly-2021-11-05
CARGO := cargo +${KATA_RUST_VERSION}
CFLAGS := $(DEBUG) $(OPT) $(INCLUDES)
CFLAGS += -march=$(ARCH) -mabi=$(ABI)
CFLAGS += -std=gnu11 -nostdlib
CFLAGS += -ftls-model=${TLS_MODEL}
ASFLAGS := -march=$(ARCH) -mabi=$(ABI)
LDFLAGS := $(DEBUG) -nostartfiles -static -nostdlib
CARGO_OPTS += -Z unstable-options
CARGO_OPTS += -Z avoid-dev-deps
# XXX RUSTFLAGS is the only way to pass tls-model but seems to work w/o
#CARGO_OPTS += -Z tls-model=${TLS_MODEL}
CARGO_OPTS += --target ${FULL_ARCH_NAME}-unknown-none-elf

View File

@@ -0,0 +1,16 @@
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
OUT_KATA ?= $(OUT)/kata/$(ARCH_PREFIX)/$(BUILD_TYPE)
TLS_MODEL := local-exec