Skip to content

Commit 67821c1

Browse files
block: page cache
Signed-off-by: Andy-Python-Programmer <andypythonappdeveloper@gmail.com>
1 parent be3c623 commit 67821c1

File tree

5 files changed

+97
-52
lines changed

5 files changed

+97
-52
lines changed

aero.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,11 @@ def prepare_iso(args, kernel_bin, user_bins):
435435
shutil.copy(os.path.join(limine_path, 'BOOTAA64.EFI'), efi_boot)
436436
shutil.copy(os.path.join(limine_path, 'BOOTX64.EFI'), efi_boot)
437437

438+
sysroot_dir = os.path.join(SYSROOT_DIR, 'system-root')
439+
for file in user_bins:
440+
bin_name = os.path.basename(file)
441+
shutil.copy(file, os.path.join(sysroot_dir, "usr", "bin", bin_name))
442+
438443
with open(os.path.join(iso_root, 'limine.cfg'), 'w') as limine_cfg:
439444
limine_cfg.write(LIMINE_TEMPLATE)
440445

base-files/.bashrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ HISTCONTROL=ignoredups
44
HISTSIZE=-1
55
HISTFILESIZE=-1
66

7-
TERM=linux
7+
export TERM=linux
88

99
alias ls="ls --color=auto"
1010
alias clear='printf "\e[2J\e[H"'

src/aero_kernel/src/fs/block/mod.rs

Lines changed: 81 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
mod gpt;
2121

22-
use alloc::boxed::Box;
2322
use gpt::Gpt;
2423

2524
use core::mem::MaybeUninit;
@@ -32,34 +31,92 @@ use crate::fs::devfs::install_device;
3231
use crate::fs::{FileSystem, Result};
3332

3433
use crate::fs::ext2::Ext2;
34+
use crate::mem::paging::*;
3535
use crate::utils::sync::Mutex;
3636

37-
use super::cache::{Cache, Cacheable};
37+
use super::cache::{Cache, CacheArc, CacheItem, Cacheable};
3838
use super::devfs::{alloc_device_marker, Device};
3939
use super::inode::INodeInterface;
4040

41-
type CachedBlockKey = (usize, usize); // (block device pointer, block)
41+
type PageCacheKey = (usize, usize); // (block device pointer, offset)
42+
type PageCacheItem = CacheArc<CacheItem<PageCacheKey, CachedPage>>;
4243

43-
struct CachedBlock {
44+
struct CachedPage {
4445
device: Weak<dyn CachedAccess>,
45-
block: usize,
46-
buffer: Box<[u8]>,
46+
offset: usize,
47+
page: PhysFrame,
4748
}
4849

49-
impl CachedBlock {
50-
fn make_key(device: Weak<dyn CachedAccess>, block: usize) -> CachedBlockKey {
51-
(device.as_ptr() as *const u8 as usize, block)
50+
impl CachedPage {
51+
fn new(device: Weak<dyn CachedAccess>, offset: usize) -> Self {
52+
Self {
53+
device,
54+
offset,
55+
page: FRAME_ALLOCATOR
56+
.allocate_frame()
57+
.expect("page_cache: out of memory"),
58+
}
59+
}
60+
61+
fn data_mut(&self) -> &mut [MaybeUninit<u8>] {
62+
let data_ptr = self
63+
.page
64+
.start_address()
65+
.as_hhdm_virt()
66+
.as_mut_ptr::<MaybeUninit<u8>>();
67+
68+
// SAFETY: It is safe to create a slice of MaybeUninit<T> because it has the same
69+
// size and alignment as T.
70+
unsafe { core::slice::from_raw_parts_mut(data_ptr, Size4KiB::SIZE as usize) }
71+
}
72+
73+
fn make_key(device: Weak<dyn CachedAccess>, offset: usize) -> PageCacheKey {
74+
(device.as_ptr() as *const u8 as usize, offset)
5275
}
5376
}
5477

55-
impl Cacheable<CachedBlockKey> for CachedBlock {
56-
fn cache_key(&self) -> CachedBlockKey {
57-
Self::make_key(self.device.clone(), self.block)
78+
impl Cacheable<PageCacheKey> for CachedPage {
79+
fn cache_key(&self) -> PageCacheKey {
80+
Self::make_key(self.device.clone(), self.offset)
5881
}
5982
}
6083

6184
lazy_static::lazy_static! {
62-
static ref BLOCK_CACHE: Arc<Cache<CachedBlockKey, CachedBlock>> = Cache::new();
85+
static ref PAGE_CACHE: Arc<Cache<PageCacheKey, CachedPage>> = Cache::new();
86+
}
87+
88+
impl Cache<PageCacheKey, CachedPage> {
89+
/// Returns the cached page at the given offset, if not present, it will be allocated,
90+
/// initialized with the data on the disk and placed in the page cache.
91+
///
92+
/// ## Arguments
93+
///
94+
/// * `device` - The device to get the page from.
95+
///
96+
/// * `offset` - The offset in bytes to the data. This will be rounded down to
97+
/// the nearest page boundary.
98+
pub fn get_page(&self, device: Weak<dyn CachedAccess>, offset: usize) -> PageCacheItem {
99+
let cache_offset = offset / Size4KiB::SIZE as usize;
100+
let cache_key = CachedPage::make_key(device.clone(), cache_offset);
101+
102+
if let Some(page) = PAGE_CACHE.get(cache_key) {
103+
return page;
104+
}
105+
106+
let page = CachedPage::new(device.clone(), offset);
107+
let device = device.upgrade().expect("page_cache: device dropped");
108+
109+
let aligned_offset = align_down(offset as u64, Size4KiB::SIZE) as usize;
110+
111+
device
112+
// FIXME(perf,mem): internally read_block makes use of the DMA API (cc drivers::nvme::dma), which in turn
113+
// allocates another frame in order to make sure the destination buffer is DMA capable. In this
114+
// case, this is not required since we have already allocated a DMA capable frame.
115+
.read_block(aligned_offset / device.block_size(), page.data_mut())
116+
.expect("page_cache: failed to read block");
117+
118+
PAGE_CACHE.make_item_cached(page)
119+
}
63120
}
64121

65122
pub trait BlockDeviceInterface: Send + Sync {
@@ -72,44 +129,23 @@ pub trait BlockDeviceInterface: Send + Sync {
72129
pub trait CachedAccess: BlockDeviceInterface {
73130
fn sref(&self) -> Weak<dyn CachedAccess>;
74131

75-
fn read(&self, offset: usize, dest: &mut [MaybeUninit<u8>]) -> Option<usize> {
76-
let mut progress = 0;
77-
let block_size = self.block_size();
78-
79-
while progress < dest.len() {
80-
let block = (offset + progress) / block_size;
81-
let loc = (offset + progress) % block_size;
132+
fn read(&self, mut offset: usize, dest: &mut [MaybeUninit<u8>]) -> Option<usize> {
133+
let mut loc = 0;
82134

83-
let mut chunk = dest.len() - progress;
135+
while loc < dest.len() {
136+
let page = PAGE_CACHE.get_page(self.sref(), offset);
84137

85-
if chunk > (block_size - loc) {
86-
chunk = block_size - loc;
87-
}
138+
let page_offset = offset % Size4KiB::SIZE as usize;
139+
let size = core::cmp::min(Size4KiB::SIZE as usize - page_offset, dest.len() - loc);
88140

89-
let key = CachedBlock::make_key(self.sref(), block);
90-
91-
if let Some(cached) = BLOCK_CACHE.get(key) {
92-
MaybeUninit::write_slice(
93-
&mut dest[progress..(progress + chunk)],
94-
&cached.buffer[loc..loc + chunk],
95-
);
96-
} else {
97-
let mut buffer = Box::<[u8]>::new_uninit_slice(block_size);
98-
99-
self.read_block(block, MaybeUninit::slice_as_bytes_mut(&mut buffer))?;
100-
dest[progress..(progress + chunk)].copy_from_slice(&buffer[loc..loc + chunk]);
101-
102-
BLOCK_CACHE.make_item_cached(CachedBlock {
103-
device: self.sref(),
104-
block,
105-
buffer: unsafe { buffer.assume_init() },
106-
});
107-
}
141+
let data = &page.data_mut()[page_offset..page_offset + size];
142+
dest[loc..loc + size].copy_from_slice(data);
108143

109-
progress += chunk;
144+
loc += size;
145+
offset += align_down(offset as u64 + Size4KiB::SIZE, Size4KiB::SIZE) as usize;
110146
}
111147

112-
Some(progress)
148+
Some(loc)
113149
}
114150
}
115151

src/aero_kernel/src/fs/epoll.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,20 @@ impl EPoll {
8686
Ok(())
8787
}
8888

89-
/// Retrieves ready events, and delivers them to the caller-supplied event buffer.
89+
/// Retrieves ready events, and delivers them to the caller-supplied event buffer and
90+
/// returns the number of ready events if the call was successful.
9091
///
9192
/// ## Arguments
9293
///
9394
/// * `events`: Used to return information from the ready list about file descriptors in the
94-
/// interest list that have some events available.
95+
/// interest list that have some events available.
9596
///
9697
/// * `max_events`: Maximum number of events.
9798
///
9899
/// * `timeout`: specifies the minimum number of milliseconds that epoll wait will block. Specifying
99-
/// a timeout of `-1` will block indefinitely. While specifing a timeout of `0` will return immediately
100-
/// even if there are available no events.
100+
/// a timeout of `-1` will block indefinitely. While specifing a timeout of `0` will return
101+
/// immediately even if there are available no events.
101102
///
102-
/// ## Return
103-
/// Returns the number of ready events if the call was successful.
104103
///
105104
/// ## Blocking
106105
/// Blocks the current task until either:

tools/mkimage.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# sync the sysroot
2+
echo "sysroot: syncing base-files"
3+
cp -r base-files/. sysroot/system-root/
4+
5+
# make the disk image
16
rm -rf disk.img
27

38
dd if=/dev/zero bs=1G count=0 seek=512 of=disk.img

0 commit comments

Comments
 (0)