From 98a651e8e46025e6aecd52ae4ae86b6661cd70a3 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 18 Dec 2023 14:32:27 +0200 Subject: [PATCH 1/8] Initial commit --- .gitignore | 1 + Cargo.lock | 23 ++++++++ Cargo.toml | 18 ++++++ src/allocator.rs | 68 ++++++++++++++++++++++ src/bucket.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++++ src/global.rs | 29 ++++++++++ src/lib.rs | 16 ++++++ src/util.rs | 90 +++++++++++++++++++++++++++++ 8 files changed, 390 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/allocator.rs create mode 100644 src/bucket.rs create mode 100644 src/global.rs create mode 100644 src/lib.rs create mode 100644 src/util.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ea8c4bf7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..32c544de --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libyalloc" +version = "0.1.0" +dependencies = [ + "libc", + "rustc-std-workspace-core", +] + +[[package]] +name = "rustc-std-workspace-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..09d036a3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "libyalloc" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } + +[target.'cfg(unix)'.dependencies] +libc = "0.2.151" + +[features] +default = [] +rustc-dep-of-std = [ + "core" +] diff --git a/src/allocator.rs b/src/allocator.rs new file mode 100644 index 00000000..a53d2a6d --- /dev/null +++ b/src/allocator.rs @@ -0,0 +1,68 @@ +use core::{ + alloc::Layout, + ptr::{null_mut, NonNull}, +}; + +use crate::bucket::BitmapBucketHeader; + +const BUCKET_SIZE_32: usize = 8192; +const BUCKET_SIZE_64: usize = 16384; +const BUCKET_SIZE_128: usize = 32768; +const BUCKET_SIZE_256: usize = 32768; +const BUCKET_SIZE_512: usize = 65536; +const BUCKET_SIZE_1024: usize = 65536; + +pub struct Allocator { + buckets_32: *mut BitmapBucketHeader<32, { BUCKET_SIZE_32 / 32 }>, + buckets_64: *mut BitmapBucketHeader<64, { BUCKET_SIZE_64 / 64 }>, + buckets_128: *mut BitmapBucketHeader<128, { BUCKET_SIZE_128 / 128 }>, + buckets_256: *mut BitmapBucketHeader<256, { BUCKET_SIZE_256 / 256 }>, + buckets_512: *mut BitmapBucketHeader<512, { BUCKET_SIZE_512 / 512 }>, + buckets_1024: *mut BitmapBucketHeader<1024, { BUCKET_SIZE_1024 / 1024 }>, +} + +impl Allocator { + pub const fn new() -> Self { + Self { + buckets_32: null_mut(), + buckets_64: null_mut(), + buckets_128: null_mut(), + buckets_256: null_mut(), + buckets_512: null_mut(), + buckets_1024: null_mut(), + } + } + + pub fn alloc(&mut self, layout: Layout) -> Option> { + // TODO handle align properly + match layout.size() { + c if c > 1024 => todo!(), // No bucket + c if c > 512 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_1024), + c if c > 256 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_512), + c if c > 128 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_256), + c if c > 64 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_128), + c if c > 32 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_64), + _ => BitmapBucketHeader::alloc_from_list(&mut self.buckets_32), + } + } + + pub fn free(&mut self, ptr: NonNull, layout: Layout) { + match layout.size() { + c if c > 1024 => todo!(), // No bucket + c if c > 512 => BitmapBucketHeader::free_from_list(&mut self.buckets_1024, ptr), + c if c > 256 => BitmapBucketHeader::free_from_list(&mut self.buckets_512, ptr), + c if c > 128 => BitmapBucketHeader::free_from_list(&mut self.buckets_256, ptr), + c if c > 64 => BitmapBucketHeader::free_from_list(&mut self.buckets_128, ptr), + c if c > 32 => BitmapBucketHeader::free_from_list(&mut self.buckets_64, ptr), + _ => BitmapBucketHeader::free_from_list(&mut self.buckets_32, ptr), + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn multi_size_alloc() { + todo!() + } +} diff --git a/src/bucket.rs b/src/bucket.rs new file mode 100644 index 00000000..a4bf21d8 --- /dev/null +++ b/src/bucket.rs @@ -0,0 +1,145 @@ +use core::{ + mem::size_of, + ptr::{null_mut, NonNull}, +}; + +use crate::util::{map_pages, Assert, IsTrue, PAGE_SIZE}; + +pub type BitmapWord = u64; + +pub const fn bitmap_size(element_count: usize) -> usize { + (element_count + BitmapWord::BITS as usize - 1) / BitmapWord::BITS as usize +} + +pub const fn header_size(element_count: usize, element_size: usize) -> usize { + (bitmap_size(element_count) + 2 * size_of::<*mut ()>() + element_size - 1) & !(element_size - 1) +} + +// Page-aligned bucket size with its header +pub const fn bucket_size(element_count: usize, element_size: usize) -> usize { + let header_size = header_size(element_count, element_size); + let data_size = element_count * element_size; + (header_size + data_size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) +} + +/// M - element size +/// N - element count +pub struct BitmapBucketHeader +where + Assert<{ (M * N) % PAGE_SIZE == 0 }>: IsTrue, + [(); bitmap_size(N)]: Sized, +{ + bitmap: [BitmapWord; bitmap_size(N)], + count: usize, + next: *mut Self, +} + +impl BitmapBucketHeader +where + Assert<{ (M * N) % PAGE_SIZE == 0 }>: IsTrue, + [(); bitmap_size(N)]: Sized, +{ + pub fn new_bucket() -> Option<*mut Self> { + let size = bucket_size(N, M); + let base = map_pages(size / PAGE_SIZE)? as *mut Self; + + unsafe { + base.write(Self { + bitmap: [0; bitmap_size(N)], + count: 0, + next: null_mut(), + }); + } + + Some(base) + } + + pub fn alloc(self: *mut Self) -> Option> { + let bucket = unsafe { &mut *self }; + + for i in 0..N { + let word = &mut bucket.bitmap[i / BitmapWord::BITS as usize]; + let mask = 1 << (i % BitmapWord::BITS as usize); + + if *word & mask == 0 { + *word |= mask; + + let offset = M * i; + bucket.count += 1; + + return Some(unsafe { + NonNull::new_unchecked((self as usize + header_size(N, M) + offset) as *mut u8) + }); + } + } + None + } + + pub fn free(self: *mut Self, ptr: NonNull) -> (bool, bool) { + let bucket = unsafe { &mut *self }; + + if bucket.count == 0 { + return (false, false); + } + + let self_addr = self.addr(); + let ptr_addr = usize::from(ptr.addr()); + + if let Some(offset) = ptr_addr.checked_sub(self_addr + header_size(N, M)) + && offset < N * M + { + let index = offset / M; + + let word = &mut bucket.bitmap[index / BitmapWord::BITS as usize]; + let mask = 1 << (index % BitmapWord::BITS as usize); + + if *word & mask == 0 { + panic!("TODO: double-free?"); + } + + *word &= !mask; + bucket.count -= 1; + + (true, bucket.count == 0) + } else { + (false, false) + } + } + + pub(crate) fn alloc_from_list(list: &mut *mut Self) -> Option> { + let mut bucket = *list; + + while !bucket.is_null() { + if let Some(ptr) = bucket.alloc() { + return Some(ptr); + } + + bucket = unsafe { (*bucket).next }; + } + + // No bucket could allocate the request, make a new one + let bucket = Self::new_bucket()?; + unsafe { (*bucket).next = *list }; + *list = bucket; + + bucket.alloc() + } + + pub(crate) fn free_from_list(list: &mut *mut Self, ptr: NonNull) { + let mut bucket = *list; + + while !bucket.is_null() { + let (here, bucket_empty) = bucket.free(ptr); + if here { + if bucket_empty { + // TODO mark bucket for removal? + } + return; + } + + bucket = unsafe { (*bucket).next }; + } + + panic!("ptr did not belong to any bucket"); + } +} diff --git a/src/global.rs b/src/global.rs new file mode 100644 index 00000000..9e1cd2d7 --- /dev/null +++ b/src/global.rs @@ -0,0 +1,29 @@ +use core::{ + alloc::{GlobalAlloc, Layout}, + ptr::{null_mut, NonNull}, +}; + +use crate::{util::Spinlock, Allocator}; + +pub struct GlobalAllocator; + +unsafe impl GlobalAlloc for GlobalAllocator { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + let ptr = GLOBAL_ALLOCATOR.lock().alloc(layout); + + if let Some(ptr) = ptr { + ptr.as_ptr() + } else { + null_mut() + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + let ptr = NonNull::new(ptr).expect("Invalid pointer"); + GLOBAL_ALLOCATOR.lock().free(ptr, layout); + } +} + +static GLOBAL_ALLOCATOR: Spinlock = Spinlock::new(Allocator::new()); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..a32199cd --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,16 @@ +#![feature( + generic_const_exprs, + arbitrary_self_types, + strict_provenance, + let_chains +)] +#![cfg_attr(not(test), no_std)] +#![allow(incomplete_features)] + +mod allocator; +mod bucket; +mod global; +mod util; + +pub use allocator::Allocator; +pub use global::GlobalAllocator; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 00000000..1aaa949b --- /dev/null +++ b/src/util.rs @@ -0,0 +1,90 @@ +use core::{ + cell::UnsafeCell, + ops::{Deref, DerefMut}, + ptr::null_mut, + sync::atomic::{AtomicBool, Ordering}, +}; + +pub const PAGE_SIZE: usize = 0x1000; + +pub enum Assert {} +pub trait IsTrue {} +impl IsTrue for Assert {} + +pub struct Spinlock { + state: AtomicBool, + data: UnsafeCell, +} + +pub struct SpinlockGuard<'a, T: ?Sized> { + lock: &'a Spinlock, +} + +pub fn map_pages(count: usize) -> Option { + #[cfg(unix)] + { + let address = unsafe { + libc::mmap( + null_mut(), + count * PAGE_SIZE, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_ANONYMOUS | libc::MAP_PRIVATE, + -1, + 0, + ) + }; + + if address.is_null() { + None + } else { + Some(address as usize) + } + } +} + +impl Spinlock { + pub const fn new(value: T) -> Self + where + T: Sized, + { + Self { + state: AtomicBool::new(false), + data: UnsafeCell::new(value), + } + } + + pub fn lock(&self) -> SpinlockGuard { + while self + .state + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_err() + { + core::hint::spin_loop(); + } + + // Locked + SpinlockGuard { lock: self } + } +} + +impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.lock.data.get() } + } +} + +impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.lock.data.get() } + } +} + +impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> { + fn drop(&mut self) { + self.lock.state.store(false, Ordering::Release); + } +} + +unsafe impl Sync for Spinlock {} From 2027aa45fdc1131974643292c82296efd643c464 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 18 Dec 2023 14:36:54 +0200 Subject: [PATCH 2/8] Fix libc deps --- Cargo.lock | 3 +++ Cargo.toml | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 32c544de..5740d8c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,9 @@ name = "libc" version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +dependencies = [ + "rustc-std-workspace-core", +] [[package]] name = "libyalloc" diff --git a/Cargo.toml b/Cargo.toml index 09d036a3..4f9d5c51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,13 @@ edition = "2021" core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } [target.'cfg(unix)'.dependencies] -libc = "0.2.151" +libc = { version = "0.2.140", optional = true, default-features = false } [features] -default = [] -rustc-dep-of-std = [ - "core" +default = [ + "libc", +] +rustc-dep-of-std = [ + "core", + "libc/rustc-dep-of-std" ] From 437bd0826e032815876f6ad3027c168165c203b6 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 18 Dec 2023 14:42:05 +0200 Subject: [PATCH 3/8] Add yggdrasil mmap --- Cargo.lock | 36 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 +++++++----- src/util.rs | 7 +++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5740d8c4..0e6d1990 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "compiler_builtins" +version = "0.1.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3686cc48897ce1950aa70fd595bd2dc9f767a3c4cca4cd17b2cb52a2d37e6eb4" +dependencies = [ + "rustc-std-workspace-core", +] + [[package]] name = "libc" version = "0.2.151" @@ -17,10 +26,37 @@ version = "0.1.0" dependencies = [ "libc", "rustc-std-workspace-core", + "yggdrasil-rt", ] +[[package]] +name = "rustc-std-workspace-alloc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff66d57013a5686e1917ed6a025d54dd591fcda71a41fe07edf4d16726aefa86" + [[package]] name = "rustc-std-workspace-core" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" + +[[package]] +name = "yggdrasil-abi" +version = "0.1.0" +source = "git+https://git.alnyan.me/yggdrasil/yggdrasil-abi.git#449da18378f3340bb3aa06f00c1f99c79835e18f" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + +[[package]] +name = "yggdrasil-rt" +version = "0.1.0" +source = "git+https://git.alnyan.me/yggdrasil/yggdrasil-rt.git#54029c01f14902b11b079fa709f87ab4e4951911" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", + "yggdrasil-abi", +] diff --git a/Cargo.toml b/Cargo.toml index 4f9d5c51..9063620f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,13 +9,15 @@ edition = "2021" core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } [target.'cfg(unix)'.dependencies] -libc = { version = "0.2.140", optional = true, default-features = false } +libc = { version = "0.2.140", default-features = false } + +[target.'cfg(target_os = "yggdrasil")'.dependencies] +yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git", default-features = false } [features] -default = [ - "libc", -] +default = [] rustc-dep-of-std = [ "core", - "libc/rustc-dep-of-std" + "libc/rustc-dep-of-std", + "yggdrasil-rt/rustc-dep-of-std" ] diff --git a/src/util.rs b/src/util.rs index 1aaa949b..83187d0a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -40,6 +40,13 @@ pub fn map_pages(count: usize) -> Option { Some(address as usize) } } + + #[cfg(target_os = "yggdrasil")] + { + let address = unsafe { yggdrasil_rt::sys::map_memory(None, count * PAGE_SIZE) }.ok()?; + + Some(address as usize) + } } impl Spinlock { From 93395a67ac5647c6e675a6efb4bd1ec2c4c2d2d0 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 18 Dec 2023 14:52:23 +0200 Subject: [PATCH 4/8] Fix 4K page allocation --- Cargo.toml | 3 +++ src/allocator.rs | 26 +++++++++++++++++++++++--- src/util.rs | 16 +++++----------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9063620f..b8ab52ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1", optional = true } [target.'cfg(unix)'.dependencies] libc = { version = "0.2.140", default-features = false } @@ -18,6 +19,8 @@ yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git", defau default = [] rustc-dep-of-std = [ "core", + "compiler_builtins", + "compiler_builtins/rustc-dep-of-std", "libc/rustc-dep-of-std", "yggdrasil-rt/rustc-dep-of-std" ] diff --git a/src/allocator.rs b/src/allocator.rs index a53d2a6d..9a174ae6 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -3,7 +3,10 @@ use core::{ ptr::{null_mut, NonNull}, }; -use crate::bucket::BitmapBucketHeader; +use crate::{ + bucket::BitmapBucketHeader, + util::{map_pages, PAGE_SIZE}, +}; const BUCKET_SIZE_32: usize = 8192; const BUCKET_SIZE_64: usize = 16384; @@ -36,7 +39,16 @@ impl Allocator { pub fn alloc(&mut self, layout: Layout) -> Option> { // TODO handle align properly match layout.size() { - c if c > 1024 => todo!(), // No bucket + c if c > 1024 => { + let page_count = (c + PAGE_SIZE - 1) / PAGE_SIZE; + let address = map_pages(page_count); + + if let Some(address) = address { + Some(unsafe { NonNull::new_unchecked(address as *mut u8) }) + } else { + None + } + } // No bucket c if c > 512 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_1024), c if c > 256 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_512), c if c > 128 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_256), @@ -48,7 +60,13 @@ impl Allocator { pub fn free(&mut self, ptr: NonNull, layout: Layout) { match layout.size() { - c if c > 1024 => todo!(), // No bucket + c if c > 1024 => { + let page_count = (c + PAGE_SIZE - 1) / PAGE_SIZE; + + // TODO release the pages + + let _ = page_count; + } // No bucket c if c > 512 => BitmapBucketHeader::free_from_list(&mut self.buckets_1024, ptr), c if c > 256 => BitmapBucketHeader::free_from_list(&mut self.buckets_512, ptr), c if c > 128 => BitmapBucketHeader::free_from_list(&mut self.buckets_256, ptr), @@ -59,6 +77,8 @@ impl Allocator { } } +unsafe impl Send for Allocator {} + #[cfg(test)] mod tests { #[test] diff --git a/src/util.rs b/src/util.rs index 83187d0a..afe8a741 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,6 @@ use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, - ptr::null_mut, sync::atomic::{AtomicBool, Ordering}, }; @@ -23,6 +22,8 @@ pub struct SpinlockGuard<'a, T: ?Sized> { pub fn map_pages(count: usize) -> Option { #[cfg(unix)] { + use core::ptr::null_mut; + let address = unsafe { libc::mmap( null_mut(), @@ -34,11 +35,7 @@ pub fn map_pages(count: usize) -> Option { ) }; - if address.is_null() { - None - } else { - Some(address as usize) - } + if address.is_null() { None } else { Some(address as usize) } } #[cfg(target_os = "yggdrasil")] @@ -54,13 +51,10 @@ impl Spinlock { where T: Sized, { - Self { - state: AtomicBool::new(false), - data: UnsafeCell::new(value), - } + Self { state: AtomicBool::new(false), data: UnsafeCell::new(value) } } - pub fn lock(&self) -> SpinlockGuard { + pub fn lock<'a>(&'a self) -> SpinlockGuard<'a, T> { while self .state .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) From 22d3a94d2cd43ab6c54996b5b038c6a1362a9b41 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 22 Dec 2023 13:34:47 +0200 Subject: [PATCH 5/8] Update the MapMemory interface --- src/util.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/util.rs b/src/util.rs index afe8a741..52c11cfb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -35,12 +35,21 @@ pub fn map_pages(count: usize) -> Option { ) }; - if address.is_null() { None } else { Some(address as usize) } + if address.is_null() { + None + } else { + Some(address as usize) + } } #[cfg(target_os = "yggdrasil")] { - let address = unsafe { yggdrasil_rt::sys::map_memory(None, count * PAGE_SIZE) }.ok()?; + use yggdrasil_rt::mem::MappingSource; + + let address = unsafe { + yggdrasil_rt::sys::map_memory(None, count * PAGE_SIZE, &MappingSource::Anonymous) + } + .ok()?; Some(address as usize) } @@ -51,7 +60,10 @@ impl Spinlock { where T: Sized, { - Self { state: AtomicBool::new(false), data: UnsafeCell::new(value) } + Self { + state: AtomicBool::new(false), + data: UnsafeCell::new(value), + } } pub fn lock<'a>(&'a self) -> SpinlockGuard<'a, T> { From 36c3e930ca22ecde96617b4ac53970cbd20f1af7 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Thu, 4 Jan 2024 21:33:06 +0200 Subject: [PATCH 6/8] Add authors --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index b8ab52ec..adb8cc61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "libyalloc" version = "0.1.0" edition = "2021" +authors = ["Mark Poliakov "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From a057630186b33944569acecdd7d02f39689b53c0 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Mon, 15 Jan 2024 18:22:45 +0200 Subject: [PATCH 7/8] Rework the allocator with MIRI and strict_provenance --- src/allocator.rs | 271 ++++++++++++++++++++++++++++++++++++----------- src/bucket.rs | 247 ++++++++++++++++++++++-------------------- src/global.rs | 19 +++- src/lib.rs | 15 +-- src/util.rs | 34 ++++-- 5 files changed, 390 insertions(+), 196 deletions(-) diff --git a/src/allocator.rs b/src/allocator.rs index 9a174ae6..ff2878a5 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,88 +1,233 @@ -use core::{ - alloc::Layout, - ptr::{null_mut, NonNull}, -}; +use core::{alloc::Layout, ops::Index, ptr::NonNull}; use crate::{ - bucket::BitmapBucketHeader, - util::{map_pages, PAGE_SIZE}, + bucket::Bucket, + util::{self, Assert, IsTrue}, }; -const BUCKET_SIZE_32: usize = 8192; -const BUCKET_SIZE_64: usize = 16384; -const BUCKET_SIZE_128: usize = 32768; -const BUCKET_SIZE_256: usize = 32768; -const BUCKET_SIZE_512: usize = 65536; -const BUCKET_SIZE_1024: usize = 65536; - -pub struct Allocator { - buckets_32: *mut BitmapBucketHeader<32, { BUCKET_SIZE_32 / 32 }>, - buckets_64: *mut BitmapBucketHeader<64, { BUCKET_SIZE_64 / 64 }>, - buckets_128: *mut BitmapBucketHeader<128, { BUCKET_SIZE_128 / 128 }>, - buckets_256: *mut BitmapBucketHeader<256, { BUCKET_SIZE_256 / 256 }>, - buckets_512: *mut BitmapBucketHeader<512, { BUCKET_SIZE_512 / 512 }>, - buckets_1024: *mut BitmapBucketHeader<1024, { BUCKET_SIZE_1024 / 1024 }>, +struct BucketList +where + [u64; M / 64]: Sized, + Assert<{ M % 64 == 0 }>: IsTrue, +{ + head: Option>>, } -impl Allocator { +pub struct BucketAllocator { + // 1024x64 = 16 pages + buckets_1024: BucketList<1024, 64>, + // 512x64 = 8 pages + buckets_512: BucketList<512, 64>, + // 256x128 = 8 pages + buckets_256: BucketList<256, 128>, + // 128x128 = 4 pages + buckets_128: BucketList<128, 128>, + // 64x128 = 2 pages + buckets_64: BucketList<128, 128>, + // 32x256 = 2 pages + buckets_32: BucketList<128, 128>, +} + +impl BucketList +where + [u64; M / 64]: Sized, + Assert<{ M % 64 == 0 }>: IsTrue, +{ + const fn new() -> Self { + Self { head: None } + } + + fn allocate(&mut self) -> Option> { + let mut node = self.head; + while let Some(mut bucket) = node { + let bucket = unsafe { bucket.as_mut() }; + + if let Some(ptr) = bucket.allocate() { + return Some(ptr); + } + + node = bucket.next; + } + + // No usable bucket found + let mut node = Bucket::new()?; + let bucket = unsafe { node.as_mut() }; + bucket.next = self.head; + self.head = Some(node); + + bucket.allocate() + } + + unsafe fn free(&mut self, ptr: NonNull) { + let mut node = self.head; + while let Some(mut bucket) = node { + let bucket = bucket.as_mut(); + + if let (true, _last) = bucket.free(ptr) { + // TODO free the node if last? + return; + } + + node = bucket.next; + } + + panic!("Possible double free detected: pointer {:p} from bucket list {}x{}B, no corresponding bucket found", ptr, N, M); + } +} + +impl Index for BucketList +where + [u64; M / 64]: Sized, + Assert<{ M % 64 == 0 }>: IsTrue, +{ + type Output = Bucket; + + fn index(&self, index: usize) -> &Self::Output { + let mut current = 0; + let mut node = self.head; + while let Some(bucket) = node { + let bucket = unsafe { bucket.as_ref() }; + if current == index { + return bucket; + } + current += 1; + node = bucket.next; + } + panic!( + "BucketList index out of range: contains {} buckets, tried to index {}", + current, index + ); + } +} + +impl BucketAllocator { pub const fn new() -> Self { Self { - buckets_32: null_mut(), - buckets_64: null_mut(), - buckets_128: null_mut(), - buckets_256: null_mut(), - buckets_512: null_mut(), - buckets_1024: null_mut(), + buckets_1024: BucketList::new(), + buckets_512: BucketList::new(), + buckets_256: BucketList::new(), + buckets_128: BucketList::new(), + buckets_64: BucketList::new(), + buckets_32: BucketList::new(), } } - pub fn alloc(&mut self, layout: Layout) -> Option> { - // TODO handle align properly - match layout.size() { - c if c > 1024 => { - let page_count = (c + PAGE_SIZE - 1) / PAGE_SIZE; - let address = map_pages(page_count); + pub fn allocate(&mut self, layout: Layout) -> Option> { + let aligned = layout.pad_to_align(); - if let Some(address) = address { - Some(unsafe { NonNull::new_unchecked(address as *mut u8) }) - } else { - None - } - } // No bucket - c if c > 512 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_1024), - c if c > 256 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_512), - c if c > 128 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_256), - c if c > 64 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_128), - c if c > 32 => BitmapBucketHeader::alloc_from_list(&mut self.buckets_64), - _ => BitmapBucketHeader::alloc_from_list(&mut self.buckets_32), + match aligned.size() { + 0 => todo!(), + ..=32 => self.buckets_32.allocate(), + ..=64 => self.buckets_64.allocate(), + ..=128 => self.buckets_128.allocate(), + ..=256 => self.buckets_256.allocate(), + ..=512 => self.buckets_512.allocate(), + ..=1024 => self.buckets_1024.allocate(), + size => util::map_pages((size + util::PAGE_SIZE - 1) / util::PAGE_SIZE), } } - pub fn free(&mut self, ptr: NonNull, layout: Layout) { - match layout.size() { - c if c > 1024 => { - let page_count = (c + PAGE_SIZE - 1) / PAGE_SIZE; + pub unsafe fn free(&mut self, ptr: NonNull, layout: Layout) { + let aligned = layout.pad_to_align(); - // TODO release the pages - - let _ = page_count; - } // No bucket - c if c > 512 => BitmapBucketHeader::free_from_list(&mut self.buckets_1024, ptr), - c if c > 256 => BitmapBucketHeader::free_from_list(&mut self.buckets_512, ptr), - c if c > 128 => BitmapBucketHeader::free_from_list(&mut self.buckets_256, ptr), - c if c > 64 => BitmapBucketHeader::free_from_list(&mut self.buckets_128, ptr), - c if c > 32 => BitmapBucketHeader::free_from_list(&mut self.buckets_64, ptr), - _ => BitmapBucketHeader::free_from_list(&mut self.buckets_32, ptr), + match aligned.size() { + 0 => todo!(), + ..=32 => self.buckets_32.free(ptr), + ..=64 => self.buckets_64.free(ptr), + ..=128 => self.buckets_128.free(ptr), + ..=256 => self.buckets_256.free(ptr), + ..=512 => self.buckets_512.free(ptr), + ..=1024 => self.buckets_1024.free(ptr), + size => { + assert_eq!(usize::from(ptr.addr()) % util::PAGE_SIZE, 0); + util::unmap_pages(ptr, (size + util::PAGE_SIZE - 1) / util::PAGE_SIZE); + } } } } -unsafe impl Send for Allocator {} - #[cfg(test)] mod tests { + use core::{alloc::Layout, ptr::NonNull}; + + use super::{BucketAllocator, BucketList}; + #[test] - fn multi_size_alloc() { - todo!() + fn single_list_allocation() { + let mut list = BucketList::<32, 64>::new(); + let mut vec = vec![]; + + for _ in 0..4 * 64 + 3 { + let ptr = list.allocate().unwrap(); + vec.push(ptr); + } + + for ptr in vec { + unsafe { + list.free(ptr); + } + } + } + + #[test] + fn multi_list_allocation() { + const SIZES: &[usize] = &[1, 3, 7, 15, 16, 24, 33, 65, 126, 255, 500, 1000]; + + let mut allocator = BucketAllocator::new(); + let mut vec = vec![]; + + for _ in 0..65 { + for &size in SIZES { + let layout = Layout::from_size_align(size, 16).unwrap(); + let ptr = allocator.allocate(layout).unwrap(); + assert_eq!(usize::from(ptr.addr()) % 16, 0); + let mut slice = NonNull::slice_from_raw_parts(ptr, size); + unsafe { + slice.as_mut().fill(123); + } + vec.push((ptr, layout)); + } + } + + for (ptr, layout) in vec { + unsafe { + allocator.free(ptr, layout); + } + } + } + + #[test] + #[should_panic] + fn double_free() { + let mut allocator = BucketAllocator::new(); + let layout = Layout::from_size_align(63, 32).unwrap(); + let ptr = allocator.allocate(layout).unwrap(); + + unsafe { + allocator.free(ptr, layout); + allocator.free(ptr, layout); + } + } + + #[test] + fn large_alloc() { + const SIZES: &[usize] = &[2000, 2048, 4000, 4096, 8192]; + + let mut allocator = BucketAllocator::new(); + let mut vec = vec![]; + + for &size in SIZES { + let layout = Layout::from_size_align(size, 32).unwrap(); + let ptr = allocator.allocate(layout).unwrap(); + vec.push((ptr, layout)); + } + + for (ptr, layout) in vec { + assert_eq!(usize::from(ptr.addr()) % 0x1000, 0); + + unsafe { + allocator.free(ptr, layout); + } + } } } diff --git a/src/bucket.rs b/src/bucket.rs index a4bf21d8..3b0bc1a1 100644 --- a/src/bucket.rs +++ b/src/bucket.rs @@ -1,145 +1,160 @@ use core::{ - mem::size_of, - ptr::{null_mut, NonNull}, + mem::{size_of, MaybeUninit}, + ptr::NonNull, }; -use crate::util::{map_pages, Assert, IsTrue, PAGE_SIZE}; +use crate::util::{self, Assert, IsTrue, NonNullExt}; -pub type BitmapWord = u64; - -pub const fn bitmap_size(element_count: usize) -> usize { - (element_count + BitmapWord::BITS as usize - 1) / BitmapWord::BITS as usize -} - -pub const fn header_size(element_count: usize, element_size: usize) -> usize { - (bitmap_size(element_count) + 2 * size_of::<*mut ()>() + element_size - 1) & !(element_size - 1) -} - -// Page-aligned bucket size with its header -pub const fn bucket_size(element_count: usize, element_size: usize) -> usize { - let header_size = header_size(element_count, element_size); - let data_size = element_count * element_size; - (header_size + data_size + PAGE_SIZE - 1) & !(PAGE_SIZE - 1) -} - -/// M - element size -/// N - element count -pub struct BitmapBucketHeader +pub struct Bucket where - Assert<{ (M * N) % PAGE_SIZE == 0 }>: IsTrue, - [(); bitmap_size(N)]: Sized, + [u64; M / 64]: Sized, + Assert<{ M % 64 == 0 }>: IsTrue, { - bitmap: [BitmapWord; bitmap_size(N)], - count: usize, - next: *mut Self, + pub(crate) data: NonNull, + bitmap: [u64; M / 64], + allocated_count: usize, + pub(crate) next: Option>>, } -impl BitmapBucketHeader +impl Bucket where - Assert<{ (M * N) % PAGE_SIZE == 0 }>: IsTrue, - [(); bitmap_size(N)]: Sized, + [u64; M / 64]: Sized, + Assert<{ M % 64 == 0 }>: IsTrue, { - pub fn new_bucket() -> Option<*mut Self> { - let size = bucket_size(N, M); - let base = map_pages(size / PAGE_SIZE)? as *mut Self; + pub fn new() -> Option> { + let data_page_count = (M * N + 0xFFF) / 0x1000; + let info_page_count = (size_of::() + 0xFFF) / 0x1000; - unsafe { - base.write(Self { - bitmap: [0; bitmap_size(N)], - count: 0, - next: null_mut(), - }); - } + let data = util::map_pages(data_page_count)?; + let info = util::map_pages(info_page_count)?; - Some(base) + let bucket = unsafe { info.cast::>().as_mut() }; + let bucket = bucket.write(Self { + data, + bitmap: [0; M / 64], + allocated_count: 0, + next: None, + }); + + Some(bucket.into()) } - pub fn alloc(self: *mut Self) -> Option> { - let bucket = unsafe { &mut *self }; + pub fn allocate(&mut self) -> Option> { + for i in 0..self.bitmap.len() { + for j in 0..64 { + if self.bitmap[i] & (1 << j) != 0 { + continue; + } - for i in 0..N { - let word = &mut bucket.bitmap[i / BitmapWord::BITS as usize]; - let mask = 1 << (i % BitmapWord::BITS as usize); + self.bitmap[i] |= 1 << j; + self.allocated_count += 1; - if *word & mask == 0 { - *word |= mask; - - let offset = M * i; - bucket.count += 1; - - return Some(unsafe { - NonNull::new_unchecked((self as usize + header_size(N, M) + offset) as *mut u8) - }); + return Some(unsafe { self.data.add_ext((i * 64 + j) * N) }); } } + None } - pub fn free(self: *mut Self, ptr: NonNull) -> (bool, bool) { - let bucket = unsafe { &mut *self }; - - if bucket.count == 0 { + pub fn free(&mut self, ptr: NonNull) -> (bool, bool) { + if ptr.addr() < self.data.addr() { + return (false, false); + } + let offset = (usize::from(ptr.addr()) - usize::from(self.data.addr())) / N; + if offset >= M { return (false, false); } - let self_addr = self.addr(); - let ptr_addr = usize::from(ptr.addr()); + let index = offset / 64; + let bit = offset % 64; - if let Some(offset) = ptr_addr.checked_sub(self_addr + header_size(N, M)) - && offset < N * M - { - let index = offset / M; - - let word = &mut bucket.bitmap[index / BitmapWord::BITS as usize]; - let mask = 1 << (index % BitmapWord::BITS as usize); - - if *word & mask == 0 { - panic!("TODO: double-free?"); - } - - *word &= !mask; - bucket.count -= 1; - - (true, bucket.count == 0) - } else { - (false, false) + if self.bitmap[index] & (1 << bit) == 0 { + panic!( + "Possible double free detected: pointer {:p} from bucket {}x{}B, index {}:{}", + ptr, M, N, index, bit + ); } - } + self.bitmap[index] &= !(1 << bit); + self.allocated_count -= 1; - pub(crate) fn alloc_from_list(list: &mut *mut Self) -> Option> { - let mut bucket = *list; - - while !bucket.is_null() { - if let Some(ptr) = bucket.alloc() { - return Some(ptr); - } - - bucket = unsafe { (*bucket).next }; - } - - // No bucket could allocate the request, make a new one - let bucket = Self::new_bucket()?; - unsafe { (*bucket).next = *list }; - *list = bucket; - - bucket.alloc() - } - - pub(crate) fn free_from_list(list: &mut *mut Self, ptr: NonNull) { - let mut bucket = *list; - - while !bucket.is_null() { - let (here, bucket_empty) = bucket.free(ptr); - if here { - if bucket_empty { - // TODO mark bucket for removal? - } - return; - } - - bucket = unsafe { (*bucket).next }; - } - - panic!("ptr did not belong to any bucket"); + (true, self.allocated_count == 0) + } +} + +#[cfg(test)] +mod tests { + use core::ptr::NonNull; + + use crate::{bucket::Bucket, util::NonNullExt}; + + #[test] + fn bucket_creation() { + let mut bucket = Bucket::<32, 64>::new().unwrap(); + let bucket = unsafe { bucket.as_mut() }; + assert_eq!(bucket.allocated_count, 0); + assert_eq!(bucket.next, None); + } + + #[test] + fn bucket_allocation() { + let mut bucket = Bucket::<32, 64>::new().unwrap(); + let bucket = unsafe { bucket.as_mut() }; + let mut vec = vec![]; + + let mut index = 0; + loop { + if let Some(ptr) = bucket.allocate() { + if index == bucket.bitmap.len() * 64 { + panic!("WTF"); + } + vec.push(ptr); + } else { + break; + } + index += 1; + } + assert_eq!(bucket.allocated_count, index); + assert_eq!(index, bucket.bitmap.len() * 64); + + for (i, item) in vec.into_iter().enumerate() { + assert_eq!(item, unsafe { bucket.data.add_ext(i * 32) }); + let last = i == bucket.bitmap.len() * 64 - 1; + + { + let mut slice = NonNull::slice_from_raw_parts(item, 32); + let slice = unsafe { slice.as_mut() }; + slice.fill(123); + } + + assert_eq!(bucket.free(item), (true, last)); + } + } + + #[test] + fn free_outside_of_bucket() { + let mut bucket0 = Bucket::<32, 64>::new().unwrap(); + let mut bucket1 = Bucket::<64, 64>::new().unwrap(); + let bucket0 = unsafe { bucket0.as_mut() }; + let bucket1 = unsafe { bucket1.as_mut() }; + + let ptr0 = bucket0.allocate().unwrap(); + let ptr1 = bucket1.allocate().unwrap(); + + assert_eq!(bucket1.free(ptr0), (false, false)); + assert_eq!(bucket0.free(ptr1), (false, false)); + + assert_eq!(bucket0.free(ptr0), (true, true)); + assert_eq!(bucket1.free(ptr1), (true, true)); + } + + #[test] + #[should_panic] + fn double_free() { + let mut bucket0 = Bucket::<32, 64>::new().unwrap(); + let bucket0 = unsafe { bucket0.as_mut() }; + + let ptr = bucket0.allocate().unwrap(); + assert_eq!(bucket0.free(ptr), (false, false)); + bucket0.free(ptr); } } diff --git a/src/global.rs b/src/global.rs index 9e1cd2d7..f5bb6bdb 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,16 +1,16 @@ use core::{ - alloc::{GlobalAlloc, Layout}, + alloc::{AllocError, Allocator, GlobalAlloc, Layout}, ptr::{null_mut, NonNull}, }; -use crate::{util::Spinlock, Allocator}; +use crate::{allocator::BucketAllocator, util::Spinlock}; pub struct GlobalAllocator; unsafe impl GlobalAlloc for GlobalAllocator { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - let ptr = GLOBAL_ALLOCATOR.lock().alloc(layout); + let ptr = GLOBAL_ALLOCATOR.lock().allocate(layout); if let Some(ptr) = ptr { ptr.as_ptr() @@ -26,4 +26,15 @@ unsafe impl GlobalAlloc for GlobalAllocator { } } -static GLOBAL_ALLOCATOR: Spinlock = Spinlock::new(Allocator::new()); +unsafe impl Allocator for GlobalAllocator { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + let ptr = GLOBAL_ALLOCATOR.lock().allocate(layout).ok_or(AllocError)?; + Ok(NonNull::slice_from_raw_parts(ptr, layout.size())) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + GLOBAL_ALLOCATOR.lock().free(ptr, layout); + } +} + +static GLOBAL_ALLOCATOR: Spinlock = Spinlock::new(BucketAllocator::new()); diff --git a/src/lib.rs b/src/lib.rs index a32199cd..a00521a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,15 +2,18 @@ generic_const_exprs, arbitrary_self_types, strict_provenance, - let_chains + let_chains, + test, + allocator_api )] #![cfg_attr(not(test), no_std)] #![allow(incomplete_features)] +#![deny(fuzzy_provenance_casts, lossy_provenance_casts)] -mod allocator; +#[cfg(test)] +extern crate test; + +pub mod allocator; mod bucket; -mod global; +pub mod global; mod util; - -pub use allocator::Allocator; -pub use global::GlobalAllocator; diff --git a/src/util.rs b/src/util.rs index 52c11cfb..93e3a17d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,6 +1,7 @@ use core::{ cell::UnsafeCell, ops::{Deref, DerefMut}, + ptr::NonNull, sync::atomic::{AtomicBool, Ordering}, }; @@ -10,6 +11,16 @@ pub enum Assert {} pub trait IsTrue {} impl IsTrue for Assert {} +pub trait NonNullExt { + unsafe fn add_ext(self, offset: usize) -> Self; +} + +impl NonNullExt for NonNull { + unsafe fn add_ext(self, offset: usize) -> Self { + NonNull::new_unchecked(self.as_ptr().add(offset)) + } +} + pub struct Spinlock { state: AtomicBool, data: UnsafeCell, @@ -19,7 +30,7 @@ pub struct SpinlockGuard<'a, T: ?Sized> { lock: &'a Spinlock, } -pub fn map_pages(count: usize) -> Option { +pub fn map_pages(count: usize) -> Option> { #[cfg(unix)] { use core::ptr::null_mut; @@ -35,11 +46,7 @@ pub fn map_pages(count: usize) -> Option { ) }; - if address.is_null() { - None - } else { - Some(address as usize) - } + NonNull::new(address as *mut u8) } #[cfg(target_os = "yggdrasil")] @@ -51,7 +58,20 @@ pub fn map_pages(count: usize) -> Option { } .ok()?; - Some(address as usize) + NonNull::new(core::ptr::from_exposed_addr_mut(address)) + } +} + +pub fn unmap_pages(address: NonNull, count: usize) { + #[cfg(unix)] + unsafe { + libc::munmap(address.as_ptr() as _, count * PAGE_SIZE); + } + #[cfg(target_os = "yggdrasil")] + { + unsafe { + yggdrasil_rt::sys::unmap_memory(address.addr().into(), count * PAGE_SIZE).unwrap(); + } } } From c8399685ff776a08799c5e4c6eecd6fef1dce7bd Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 3 Mar 2024 01:59:05 +0200 Subject: [PATCH 8/8] Fix target #[cfg]s --- Cargo.toml | 4 ++-- src/lib.rs | 1 + src/util.rs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index adb8cc61..3570285b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,10 +10,10 @@ authors = ["Mark Poliakov "] core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } compiler_builtins = { version = "0.1", optional = true } + [target.'cfg(unix)'.dependencies] libc = { version = "0.2.140", default-features = false } - -[target.'cfg(target_os = "yggdrasil")'.dependencies] +[target.'cfg(not(unix))'.dependencies] yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git", default-features = false } [features] diff --git a/src/lib.rs b/src/lib.rs index a00521a4..7eb56561 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ generic_const_exprs, arbitrary_self_types, strict_provenance, + exposed_provenance, let_chains, test, allocator_api diff --git a/src/util.rs b/src/util.rs index 93e3a17d..3e97c1b3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -49,7 +49,7 @@ pub fn map_pages(count: usize) -> Option> { NonNull::new(address as *mut u8) } - #[cfg(target_os = "yggdrasil")] + #[cfg(not(unix))] { use yggdrasil_rt::mem::MappingSource; @@ -67,7 +67,7 @@ pub fn unmap_pages(address: NonNull, count: usize) { unsafe { libc::munmap(address.as_ptr() as _, count * PAGE_SIZE); } - #[cfg(target_os = "yggdrasil")] + #[cfg(not(unix))] { unsafe { yggdrasil_rt::sys::unmap_memory(address.addr().into(), count * PAGE_SIZE).unwrap();