Skip to content

Commit

Permalink
Merge pull request #6 from qclic/dev/ctx
Browse files Browse the repository at this point in the history
重构cpu上下文
  • Loading branch information
ZR233 authored Jan 22, 2025
2 parents 3846708 + 697330e commit 4bd3752
Show file tree
Hide file tree
Showing 10 changed files with 317 additions and 363 deletions.
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
"lldb.dereferencePointers": true,
"lldb.consoleMode": "commands",
"rust-targets.targets": [
"aarch64-unknown-none"
"aarch64-unknown-none",
"aarch64-unknown-none-softfloat"
],
"rust-analyzer.check.targets": [
"aarch64-unknown-none"
"aarch64-unknown-none",
],
}
54 changes: 54 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/sparreal-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ quote = "1.0"
proc-macro2 = "1.0"
syn = { version = "2.0", features = ["extra-traits", "full"] }
abi-singleton = "0.3"
darling = "0.20"

[features]
2 changes: 0 additions & 2 deletions crates/sparreal-macros/src/api_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ mod tests {

use syn::TraitItem;

use super::*;

#[test]
fn it_works() {
let f = syn::parse_str::<syn::ItemTrait>(
Expand Down
183 changes: 178 additions & 5 deletions crates/sparreal-macros/src/arch/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,173 @@
#![allow(unused)]

use proc_macro::TokenStream;
use syn::parse;
use syn::{Ident, ItemFn, parse};

fn ctx_store_x_q() -> String {
let mut out = reg_op_pair("stp", "x", 1..32, "[sp,#-0x10]!", true);
trait AsmFmt {
fn fmt_asm(&self) -> Vec<String>;
}

impl AsmFmt for String {
fn fmt_asm(&self) -> Vec<String> {
self.split('\n')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect()
}
}
pub fn trap_handle_irq(func: ItemFn) -> proc_macro2::TokenStream {
let inner_name = format_ident!("__{}", func.sig.ident);
let stmts = &func.block.stmts;
let inputs = &func.sig.inputs;

let fp = __trap_handle_irq(&func, &inner_name, true);
let sp = __trap_handle_irq(&func, &inner_name, false);

quote! {
#[cfg(hard_float)]
#fp

#[cfg(not(hard_float))]
#sp

fn #inner_name(#inputs)->usize{
#(#stmts)*
}
}
}

pub fn __trap_handle_irq(
func: &ItemFn,
inner_name: &Ident,
is_fp: bool,
) -> proc_macro2::TokenStream {
let func_name = &func.sig.ident;
let vis = &func.vis;

let mut asm_str = trap_store_regs(is_fp);
asm_str += "
mov x0, sp
BL {f}
mov sp, x0
";

asm_str += &trap_restore_regs(is_fp);
asm_str += "
eret
";

let asm = asm_str.fmt_asm();

quote! {
#[unsafe(no_mangle)]
#[naked]
#vis unsafe extern "C" fn #func_name() {
core::arch::naked_asm!(
#(#asm),*,
f = sym #inner_name,
);
}
}
}

pub fn tcb_switch(is_fp: bool) -> proc_macro2::TokenStream {
let mut out = ctx_store_x_q(is_fp);
// 保存 sp, lr
out += "
mov x10, lr
mov x9, sp
sub x9, x9, #0x10
stp x9, x10, [sp, #-0x10]!
mov x8, sp
str x8, [x0, {sp_addr}] // prev.sp = sp
ldr x9, [x8, {lr_addr}] // x9 = prev.lr
str x9, [x8, {pc_addr}] // prev.pc = x9
ldr x8, [x1, {sp_addr}] // x8 = next.sp
mov sp, x8
ldp x9, lr, [sp], #0x10
";

out += &ctx_restore_x_q(is_fp);
out += "
ret
";
let asm = out.fmt_asm();

quote! {
#[unsafe(no_mangle)]
#[naked]
pub unsafe extern "C" fn __tcb_switch(_prev: *mut u8, _next: *mut u8) {
core::arch::naked_asm!(
#(#asm),*,
sp_addr = const core::mem::offset_of!(sparreal_kernel::task::TaskControlBlockData, sp),
lr_addr = const core::mem::offset_of!(Context, lr),
pc_addr = const core::mem::offset_of!(Context, pc)
)
}
}
}

fn trap_store_regs(is_fp: bool) -> String {
let mut out = ctx_store_x_q(is_fp);
out += "
mrs x10, ELR_EL1
mov x9, sp
sub x9, x9, #0x10
stp x9, x10, [sp,#-0x10]!
";
out
}

fn trap_restore_regs(is_fp: bool) -> String {
let mut out = "
ldp X0, X10, [sp], #0x10
msr ELR_EL1, X10
"
.to_string();
out += &ctx_restore_x_q(is_fp);

out
}

fn ctx_store_x_q(is_fp: bool) -> String {
let mut out = reg_op_pair("stp", "x", 1..31, "[sp, #-0x10]!", true);
out = format!(
"{out}\r\n mrs x9, SPSR_EL1
stp x9, x0, [sp,#-0x10]!"
"{out}
mrs x9, SPSR_EL1
stp x9, x0, [sp,#-0x10]!
"
);

if is_fp {
out += &reg_op_pair("stp", "q", 0..32, "[sp, #-0x20]!", true);
out += "
mrs x9, FPCR
mrs x10, FPSR
stp x9, x10, [sp, #-0x10]!
"
}
out
}

fn ctx_restore_x_q(is_fp: bool) -> String {
let mut out = String::new();
if is_fp {
out += "
ldp x9, x10, [sp], #0x10
msr FPCR, x9
msr FPSR, x10
";
out += &reg_op_pair("ldp", "q", 0..32, "[sp], #0x20", false);
}

out += "
ldp x9, x0, [sp], #0x10
msr SPSR_EL1, x9
";

out += &reg_op_pair("ldp", "x", 1..31, "[sp], #0x10", false);
out
}

Expand Down Expand Up @@ -67,4 +226,18 @@ ldp X29,X30, [sp], #0x10

assert_eq!(a_str.trim(), want.trim());
}

#[test]
fn test_asm_fmt() {
let a = "
str x8, [x0, {sp_addr}] // prev.sp = sp
ldr x9, [x8, {lr_addr}] // x9 = prev.lr
"
.to_string();

let asm = a.fmt_asm();

println!("{asm:?}");
}
}
60 changes: 52 additions & 8 deletions crates/sparreal-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern crate syn;
mod api_trait;
mod arch;

use darling::{FromMeta, ast::NestedMeta};
use proc_macro::TokenStream;
use proc_macro2::Span;
use syn::{FnArg, ItemFn, PathArguments, Type, Visibility, parse, spanned::Spanned};
Expand Down Expand Up @@ -193,16 +194,59 @@ pub fn module_driver(input: TokenStream) -> TokenStream {
}

#[proc_macro]
pub fn define_tcb_switch(input: TokenStream) -> TokenStream {
let s = "mov sp, x0";
pub fn define_aarch64_tcb_switch(_input: TokenStream) -> TokenStream {
let fp = arch::aarch64::tcb_switch(true);
let sp = arch::aarch64::tcb_switch(false);

quote! {
#[naked]
pub unsafe extern "C" fn __tcb_switch(prev: *mut u8, next: *mut u8) {
core::arch::naked_asm!(
#s
)
}
#[cfg(hard_float)]
#fp

#[cfg(not(hard_float))]
#sp
}
.into()
}

/// A speaking volume. Deriving `FromMeta` will cause this to be usable
/// as a string value for a meta-item key.
#[derive(Debug, Clone, Copy, FromMeta)]
#[darling(default)]
enum Aarch64TrapHandlerKind {
Irq,
Fiq,
Sync,
#[darling(rename = "serror")]
SError,
}

#[derive(Debug, FromMeta)]
struct Aarch64TrapHandlerArgs {
kind: Aarch64TrapHandlerKind,
}

#[proc_macro_attribute]
pub fn aarch64_trap_handler(args: TokenStream, input: TokenStream) -> TokenStream {
let attr_args = match NestedMeta::parse_meta_list(args.into()) {
Ok(v) => v,
Err(e) => {
return TokenStream::from(darling::Error::from(e).write_errors());
}
};
let args = match Aarch64TrapHandlerArgs::from_list(&attr_args) {
Ok(v) => v,
Err(e) => {
return TokenStream::from(e.write_errors());
}
};

let func = parse_macro_input!(input as ItemFn);

match args.kind {
Aarch64TrapHandlerKind::Irq | Aarch64TrapHandlerKind::Fiq => {
arch::aarch64::trap_handle_irq(func).into()
}
Aarch64TrapHandlerKind::Sync => arch::aarch64::trap_handle_irq(func).into(),
Aarch64TrapHandlerKind::SError => arch::aarch64::trap_handle_irq(func).into(),
}
}
Loading

0 comments on commit 4bd3752

Please sign in to comment.