lib.rs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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. const MAX_CPUS: usize = 256;
  16. #[repr(align(16))]
  17. pub struct PercpuData();
  18. pub struct PercpuArea {
  19. data: NonNull<PercpuData>,
  20. }
  21. static PERCPU_POINTERS: [AtomicPtr<PercpuData>; MAX_CPUS] =
  22. [const { AtomicPtr::new(null_mut()) }; MAX_CPUS];
  23. impl PercpuArea {
  24. fn len() -> usize {
  25. unsafe extern "C" {
  26. fn PERCPU_LENGTH();
  27. }
  28. let len = PERCPU_LENGTH as usize;
  29. assert_ne!(len, 0, "Percpu length should not be zero.");
  30. len
  31. }
  32. fn data_start() -> NonNull<u8> {
  33. unsafe extern "C" {
  34. fn PERCPU_DATA_START();
  35. }
  36. let addr = PERCPU_DATA_START as usize;
  37. NonNull::new(addr as *mut _).expect("Percpu data should not be null.")
  38. }
  39. fn layout() -> Layout {
  40. Layout::from_size_align(Self::len(), align_of::<PercpuData>()).expect("Invalid layout.")
  41. }
  42. pub fn new<F>(allocate: F) -> Self
  43. where
  44. F: FnOnce(Layout) -> NonNull<u8>,
  45. {
  46. let data_pointer = allocate(Self::layout());
  47. unsafe {
  48. // SAFETY: The `data_pointer` is of valid length and properly aligned.
  49. data_pointer.copy_from_nonoverlapping(Self::data_start(), Self::len());
  50. }
  51. Self {
  52. data: data_pointer.cast(),
  53. }
  54. }
  55. pub fn register(self, cpuid: usize) {
  56. PERCPU_POINTERS[cpuid].store(self.data.as_ptr(), Ordering::Release);
  57. }
  58. pub fn get_for(cpuid: usize) -> Option<NonNull<()>> {
  59. let pointer = PERCPU_POINTERS[cpuid].load(Ordering::Acquire);
  60. NonNull::new(pointer.cast())
  61. }
  62. pub fn setup(&mut self, func: impl FnOnce(NonNull<PercpuData>)) {
  63. func(self.data)
  64. }
  65. }