Skip to content

Commit

Permalink
Change some API name
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Jan 18, 2025
1 parent 9f89ed9 commit fdc9575
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 89 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ jobs:
- name: Check code format
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --target ${{ matrix.targets }} --all-features -- -A clippy::new_without_default
run: cargo clippy --target ${{ matrix.targets }} --features "preempt,arm-el2"
- name: Build
run: cargo build --target ${{ matrix.targets }} --all-features
run: cargo build --target ${{ matrix.targets }} --features "preempt,arm-el2"
- name: Unit test
if: ${{ matrix.targets == 'x86_64-unknown-linux-gnu' }}
run: cargo test --target ${{ matrix.targets }} -- --nocapture
run: |
cargo test --target ${{ matrix.targets }} --features "sp-naive" -- --nocapture
cargo test --target ${{ matrix.targets }} -- --nocapture
doc:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [

[workspace.package]
version = "0.1.6"
authors = ["Yuekai Jia <equation618@gmail.com>"]
authors = ["Yuekai Jia <equation618@gmail.com>", "hky1999 <976929993@qq.com>", "Su Mingxian <aarkegz@gmail.com>"]
license = "GPL-3.0-or-later OR Apache-2.0 OR MulanPSL-2.0"
homepage = "https://github.com/arceos-org/arceos"
documentation = "https://arceos-org.github.io/percpu"
Expand Down
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static CPU_ID: usize = 0;
// initialize per-CPU data for 4 CPUs.
percpu::init(4);
// set the thread pointer register to the per-CPU data area 0.
percpu::set_local_thread_pointer(0);
percpu::init_percpu_reg(0);
// access the per-CPU data `CPU_ID` on the current CPU.
println!("{}", CPU_ID.read_current()); // prints "0"
Expand All @@ -38,26 +38,27 @@ Currently, you need to **modify the linker script manually**, add the following
```text,ignore
. = ALIGN(4K);
_percpu_start = .;
_percpu_end = _percpu_start + SIZEOF(.percpu);
.percpu 0x0 (NOLOAD) : AT(_percpu_start) {
_percpu_load_start = .;
*(.percpu .percpu.*)
_percpu_load_end = .;
. = _percpu_load_start + ALIGN(64) * CPU_NUM;
}
. = _percpu_start + SIZEOF(.percpu);
. = _percpu_end;
```

## Cargo Features

- `sp-naive`: For **single-core** use. In this case, each per-CPU data is
just a global variable, architecture-specific thread pointer register is
not used.
just a global variable, architecture-specific thread pointer register is
not used.
- `preempt`: For **preemptible** system use. In this case, we need to disable
preemption when accessing per-CPU data. Otherwise, the data may be corrupted
when it's being accessing and the current thread happens to be preempted.
preemption when accessing per-CPU data. Otherwise, the data may be corrupted
when it's being accessing and the current thread happens to be preempted.
- `arm-el2`: For **ARM system** running at **EL2** use (e.g. hypervisors).
In this case, we use `TPIDR_EL2` instead of `TPIDR_EL1`
to store the base address of per-CPU data area.
In this case, we use `TPIDR_EL2` instead of `TPIDR_EL1`
to store the base address of per-CPU data area.

## Note for RISC-V

Expand Down
4 changes: 2 additions & 2 deletions percpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ keywords.workspace = true
categories.workspace = true

[features]
default = []

# For single CPU use, just make the per-CPU data a global variable.
sp-naive = ["percpu_macros/sp-naive"]

# Whether the system enables preemption.
preempt = ["percpu_macros/preempt", "dep:kernel_guard"]

default = []

# ARM specific, whether to run at the EL2 privilege level.
arm-el2 = ["percpu_macros/arm-el2"]

Expand Down
32 changes: 23 additions & 9 deletions percpu/src/imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const fn align_up_64(val: usize) -> usize {
static PERCPU_AREA_BASE: spin::once::Once<usize> = spin::once::Once::new();

/// Returns the per-CPU data area size for one CPU.
#[doc(cfg(not(feature = "sp-naive")))]
pub fn percpu_area_size() -> usize {
extern "C" {
fn _percpu_load_start();
Expand All @@ -25,7 +24,6 @@ pub fn percpu_area_size() -> usize {
/// Returns the base address of the per-CPU data area on the given CPU.
///
/// if `cpu_id` is 0, it returns the base address of all per-CPU data areas.
#[doc(cfg(not(feature = "sp-naive")))]
pub fn percpu_area_base(cpu_id: usize) -> usize {
cfg_if::cfg_if! {
if #[cfg(target_os = "none")] {
Expand Down Expand Up @@ -77,8 +75,10 @@ pub fn init(max_cpu_num: usize) {
}
}

/// Read the architecture-specific thread pointer register on the current CPU.
pub fn get_local_thread_pointer() -> usize {
/// Reads the architecture-specific per-CPU data register.
///
/// This register is used to hold the per-CPU data base on each CPU.
pub fn read_percpu_reg() -> usize {
let tp;
unsafe {
cfg_if::cfg_if! {
Expand All @@ -102,12 +102,14 @@ pub fn get_local_thread_pointer() -> usize {
tp
}

/// Set the architecture-specific thread pointer register to the per-CPU data
/// area base on the current CPU.
/// Writes the architecture-specific per-CPU data register.
///
/// `cpu_id` indicates which per-CPU data area to use.
pub fn set_local_thread_pointer(cpu_id: usize) {
let tp = percpu_area_base(cpu_id);
/// This register is used to hold the per-CPU data base on each CPU.
///
/// # Safety
///
/// This function is unsafe because it writes the low-level register directly.
pub unsafe fn write_percpu_reg(tp: usize) {
unsafe {
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
Expand Down Expand Up @@ -137,6 +139,18 @@ pub fn set_local_thread_pointer(cpu_id: usize) {
}
}

/// Initializes the per-CPU data register.
///
/// It is equivalent to `write_percpu_reg(percpu_area_base(cpu_id))`, which set
/// the architecture-specific per-CPU data register to the base address of the
/// corresponding per-CPU data area.
///
/// `cpu_id` indicates which per-CPU data area to use.
pub fn init_percpu_reg(cpu_id: usize) {
let tp = percpu_area_base(cpu_id);
unsafe { write_percpu_reg(tp) }
}

/// To use `percpu::__priv::NoPreemptGuard::new()` and `percpu::percpu_area_base()` in macro expansion.
#[allow(unused_imports)]
use crate as percpu;
Expand Down
4 changes: 2 additions & 2 deletions percpu/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![cfg_attr(target_os = "none", no_std)]
#![feature(doc_cfg)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]

extern crate percpu_macros;
Expand All @@ -19,7 +19,7 @@ pub mod __priv {
cfg_if::cfg_if! {
if #[cfg(doc)] {
/// Example per-CPU data for documentation only.
#[doc(cfg(doc))]
#[cfg_attr(docsrs, doc(cfg(doc)))]
#[def_percpu]
pub static EXAMPLE_PERCPU_DATA: usize = 0;
}
Expand Down
38 changes: 32 additions & 6 deletions percpu/src/naive.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
/// No effect for "sp-naive" use.
pub fn init(_max_cpu_num: usize) {}
//! Naive implementation for single CPU use.
/// Returns the per-CPU data area size for one CPU.
///
/// Always returns `0` for "sp-naive" use.
pub fn get_local_thread_pointer() -> usize {
pub fn percpu_area_size() -> usize {
0
}

/// No effect for "sp-naive" use.
pub fn set_local_thread_pointer(_cpu_id: usize) {}

/// Returns the base address of the per-CPU data area on the given CPU.
///
/// Always returns `0` for "sp-naive" use.
pub fn percpu_area_base(_cpu_id: usize) -> usize {
0
}

/// Reads the architecture-specific per-CPU data register.
///
/// Always returns `0` for "sp-naive" use.
pub fn read_percpu_reg() -> usize {
0
}

/// Writes the architecture-specific per-CPU data register.
///
/// No effect for "sp-naive" use.
///
/// # Safety
///
/// This function is marked as `unsafe` for consistency with non "sp-naive"
/// implementations.
pub unsafe fn write_percpu_reg(_tp: usize) {}

/// Initializes the per-CPU data register.
///
/// No effect for "sp-naive" use.
pub fn init_percpu_reg(_cpu_id: usize) {}

/// Initialize the per-CPU data area for `max_cpu_num` CPUs.
///
/// No effect for "sp-naive" use.
pub fn init(_max_cpu_num: usize) {}
3 changes: 2 additions & 1 deletion percpu/test_percpu.x
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ SECTIONS
{
. = ALIGN(4K);
_percpu_start = .;
_percpu_end = _percpu_start + SIZEOF(.percpu);
.percpu 0x0 (NOLOAD) : AT(_percpu_start) {
_percpu_load_start = .;
*(.percpu .percpu.*)
_percpu_load_end = .;
. = _percpu_load_start + ALIGN(64) * CPU_NUM;
}
. = _percpu_start + SIZEOF(.percpu);
. = _percpu_end;
}
INSERT AFTER .bss;
115 changes: 61 additions & 54 deletions percpu/tests/test_percpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,63 @@ struct Struct {
#[def_percpu]
static STRUCT: Struct = Struct { foo: 0, bar: 0 };

#[cfg(all(target_os = "linux", not(feature = "sp-naive")))]
fn test_remote_access() {
// test remote write
unsafe {
*BOOL.remote_ref_mut_raw(1) = false;
*U8.remote_ref_mut_raw(1) = 222;
*U16.remote_ref_mut_raw(1) = 0x1234;
*U32.remote_ref_mut_raw(1) = 0xf00d_f00d;
*U64.remote_ref_mut_raw(1) = 0xfeed_feed_feed_feed;
*USIZE.remote_ref_mut_raw(1) = 0x0000_ffff;

*STRUCT.remote_ref_mut_raw(1) = Struct {
foo: 0x6666,
bar: 200,
};
}

// test remote read
unsafe {
assert!(!*BOOL.remote_ptr(1));
assert_eq!(*U8.remote_ptr(1), 222);
assert_eq!(*U16.remote_ptr(1), 0x1234);
assert_eq!(*U32.remote_ptr(1), 0xf00d_f00d);
assert_eq!(*U64.remote_ptr(1), 0xfeed_feed_feed_feed);
assert_eq!(*USIZE.remote_ptr(1), 0x0000_ffff);

let s = STRUCT.remote_ref_raw(1);
assert_eq!(s.foo, 0x6666);
assert_eq!(s.bar, 200);
}

// test read on another CPU
unsafe { write_percpu_reg(percpu_area_base(1)) }; // we are now on CPU 1

println!();
println!("bool value on CPU 1: {}", BOOL.read_current());
println!("u8 value on CPU 1: {}", U8.read_current());
println!("u16 value on CPU 1: {:#x}", U16.read_current());
println!("u32 value on CPU 1: {:#x}", U32.read_current());
println!("u64 value on CPU 1: {:#x}", U64.read_current());
println!("usize value on CPU 1: {:#x}", USIZE.read_current());

assert!(!BOOL.read_current());
assert_eq!(U8.read_current(), 222);
assert_eq!(U16.read_current(), 0x1234);
assert_eq!(U32.read_current(), 0xf00d_f00d);
assert_eq!(U64.read_current(), 0xfeed_feed_feed_feed);
assert_eq!(USIZE.read_current(), 0x0000_ffff);

STRUCT.with_current(|s| {
println!("struct.foo value on CPU 1: {:#x}", s.foo);
println!("struct.bar value on CPU 1: {}", s.bar);
assert_eq!(s.foo, 0x6666);
assert_eq!(s.bar, 200);
});
}

#[cfg(target_os = "linux")]
#[test]
fn test_percpu() {
Expand All @@ -41,9 +98,9 @@ fn test_percpu() {
#[cfg(not(feature = "sp-naive"))]
let base = {
init(4);
set_local_thread_pointer(0);
unsafe { write_percpu_reg(percpu_area_base(0)) };

let base = get_local_thread_pointer();
let base = read_percpu_reg();
println!("per-CPU area base = {:#x}", base);
println!("per-CPU area size = {}", percpu_area_size());
base
Expand Down Expand Up @@ -100,56 +157,6 @@ fn test_percpu() {
assert_eq!(s.bar, 100);
});

// test remote write
unsafe {
*BOOL.remote_ref_mut_raw(1) = false;
*U8.remote_ref_mut_raw(1) = 222;
*U16.remote_ref_mut_raw(1) = 0x1234;
*U32.remote_ref_mut_raw(1) = 0xf00d_f00d;
*U64.remote_ref_mut_raw(1) = 0xfeed_feed_feed_feed;
*USIZE.remote_ref_mut_raw(1) = 0x0000_ffff;

*STRUCT.remote_ref_mut_raw(1) = Struct {
foo: 0x6666,
bar: 200,
};
}

// test remote read
unsafe {
assert!(!*BOOL.remote_ptr(1));
assert_eq!(*U8.remote_ptr(1), 222);
assert_eq!(*U16.remote_ptr(1), 0x1234);
assert_eq!(*U32.remote_ptr(1), 0xf00d_f00d);
assert_eq!(*U64.remote_ptr(1), 0xfeed_feed_feed_feed);
assert_eq!(*USIZE.remote_ptr(1), 0x0000_ffff);

let s = STRUCT.remote_ref_raw(1);
assert_eq!(s.foo, 0x6666);
assert_eq!(s.bar, 200);
}

// test read on another CPU
set_local_thread_pointer(1); // we are now on CPU 1

println!("bool value on CPU 1: {}", BOOL.read_current());
println!("u8 value on CPU 1: {}", U8.read_current());
println!("u16 value on CPU 1: {:#x}", U16.read_current());
println!("u32 value on CPU 1: {:#x}", U32.read_current());
println!("u64 value on CPU 1: {:#x}", U64.read_current());
println!("usize value on CPU 1: {:#x}", USIZE.read_current());

assert!(!BOOL.read_current());
assert_eq!(U8.read_current(), 222);
assert_eq!(U16.read_current(), 0x1234);
assert_eq!(U32.read_current(), 0xf00d_f00d);
assert_eq!(U64.read_current(), 0xfeed_feed_feed_feed);
assert_eq!(USIZE.read_current(), 0x0000_ffff);

STRUCT.with_current(|s| {
println!("struct.foo value on CPU 1: {:#x}", s.foo);
println!("struct.bar value on CPU 1: {}", s.bar);
assert_eq!(s.foo, 0x6666);
assert_eq!(s.bar, 200);
});
#[cfg(not(feature = "sp-naive"))]
test_remote_access();
}
4 changes: 1 addition & 3 deletions percpu_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@
//! are generated to accelerate the access.
//!
//! - A static variable `X` of type `X_WRAPPER` that is used to access the per-CPU data.
//!
//!
//! This variable is always generated with the same visibility and attributes as the original static variable.
//!
#![feature(doc_cfg)]

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, quote};
Expand Down

0 comments on commit fdc9575

Please sign in to comment.