lib.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #![no_std]
  2. use core::alloc::Layout;
  3. use core::ptr::null_mut;
  4. use core::ptr::NonNull;
  5. use core::sync::atomic::AtomicPtr;
  6. use core::sync::atomic::Ordering;
  7. #[cfg(target_arch = "x86_64")]
  8. pub use eonix_percpu_macros::define_percpu_x86_64 as define_percpu;
  9. #[cfg(target_arch = "x86_64")]
  10. pub use eonix_percpu_macros::define_percpu_shared_x86_64 as define_percpu_shared;
  11. #[cfg(target_arch = "riscv64")]
  12. pub use eonix_percpu_macros::define_percpu_riscv64 as define_percpu;
  13. #[cfg(target_arch = "riscv64")]
  14. pub use eonix_percpu_macros::define_percpu_shared_riscv64 as define_percpu_shared;
  15. #[cfg(target_arch = "loongarch64")]
  16. pub use eonix_percpu_macros::define_percpu_loongarch64 as define_percpu;
  17. #[cfg(target_arch = "loongarch64")]
  18. pub use eonix_percpu_macros::define_percpu_shared_loongarch64 as define_percpu_shared;
  19. const MAX_CPUS: usize = 256;
  20. #[repr(align(16))]
  21. pub struct PercpuData();
  22. pub struct PercpuArea {
  23. data: NonNull<PercpuData>,
  24. }
  25. static PERCPU_POINTERS: [AtomicPtr<PercpuData>; MAX_CPUS] =
  26. [const { AtomicPtr::new(null_mut()) }; MAX_CPUS];
  27. impl PercpuArea {
  28. fn len() -> usize {
  29. unsafe extern "C" {
  30. fn PERCPU_LENGTH();
  31. }
  32. let len = PERCPU_LENGTH as usize;
  33. assert_ne!(len, 0, "Percpu length should not be zero.");
  34. len
  35. }
  36. fn data_start() -> NonNull<u8> {
  37. unsafe extern "C" {
  38. fn PERCPU_DATA_START();
  39. }
  40. let addr = PERCPU_DATA_START as usize;
  41. NonNull::new(addr as *mut _).expect("Percpu data should not be null.")
  42. }
  43. fn layout() -> Layout {
  44. Layout::from_size_align(Self::len(), align_of::<PercpuData>()).expect("Invalid layout.")
  45. }
  46. pub fn new<F>(allocate: F) -> Self
  47. where
  48. F: FnOnce(Layout) -> NonNull<u8>,
  49. {
  50. let data_pointer = allocate(Self::layout());
  51. unsafe {
  52. // SAFETY: The `data_pointer` is of valid length and properly aligned.
  53. data_pointer.copy_from_nonoverlapping(Self::data_start(), Self::len());
  54. }
  55. Self {
  56. data: data_pointer.cast(),
  57. }
  58. }
  59. pub fn register(self, cpuid: usize) {
  60. PERCPU_POINTERS[cpuid].store(self.data.as_ptr(), Ordering::Release);
  61. }
  62. pub fn get_for(cpuid: usize) -> Option<NonNull<()>> {
  63. let pointer = PERCPU_POINTERS[cpuid].load(Ordering::Acquire);
  64. NonNull::new(pointer.cast())
  65. }
  66. pub fn setup(&mut self, func: impl FnOnce(NonNull<PercpuData>)) {
  67. func(self.data)
  68. }
  69. }