fix(clippy): make clippy = host libs + riscv programs (shared PROGRAMS); libkos alloc spinlock (was unlocked across threads); keystore Account; gpu Rect; factory Entry; Default impls, let-chains, div_ceil, iter loops
This commit is contained in:
16
Makefile
16
Makefile
@@ -28,8 +28,11 @@ check:
|
|||||||
fmt:
|
fmt:
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
|
|
||||||
|
# Libraries on the host; programs (no_std, they link only for RISC-V) for
|
||||||
|
# their target, as `build` builds them. The adapter is `kernel-clippy`'s.
|
||||||
clippy:
|
clippy:
|
||||||
cargo clippy --workspace -- -D warnings
|
cargo clippy --workspace --exclude adapter-riscv --lib -- -D warnings
|
||||||
|
cargo clippy --target $(RISCV_TARGET) --release $(PROGRAMS) -- -D warnings
|
||||||
|
|
||||||
test:
|
test:
|
||||||
cargo test --workspace
|
cargo test --workspace
|
||||||
@@ -48,14 +51,15 @@ kani-kernel:
|
|||||||
|
|
||||||
kani: kani-types kani-domain kani-kernel
|
kani: kani-types kani-domain kani-kernel
|
||||||
|
|
||||||
|
PROGRAMS = -p init -p echo -p sleep -p snake \
|
||||||
|
-p display-qemu -p input-qemu -p storage-qemu \
|
||||||
|
-p log-server -p permission-manager -p session-server -p smptest -p spawntest -p hello \
|
||||||
|
-p terminal-server -p shell -p cat -p ls -p counter -p gatekeeper
|
||||||
|
|
||||||
# Programs first: the kernel image packs init and storage (see the
|
# Programs first: the kernel image packs init and storage (see the
|
||||||
# adapter's build.rs).
|
# adapter's build.rs).
|
||||||
build:
|
build:
|
||||||
cargo build --target $(RISCV_TARGET) --release \
|
cargo build --target $(RISCV_TARGET) --release $(PROGRAMS)
|
||||||
-p init -p echo -p sleep -p snake \
|
|
||||||
-p display-qemu -p input-qemu -p storage-qemu \
|
|
||||||
-p log-server -p permission-manager -p session-server -p smptest -p spawntest -p hello \
|
|
||||||
-p terminal-server -p shell -p cat -p ls -p counter -p gatekeeper
|
|
||||||
cargo build --target $(RISCV_TARGET) --release -p adapter-riscv
|
cargo build --target $(RISCV_TARGET) --release -p adapter-riscv
|
||||||
|
|
||||||
# The keystore holds the owner's sealed keys: made once, never rebuilt.
|
# The keystore holds the owner's sealed keys: made once, never rebuilt.
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ pub struct Snake {
|
|||||||
rng_state: u32,
|
rng_state: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Snake {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Snake {
|
impl Snake {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let start = Position { x: GRID_WIDTH / 2, y: GRID_HEIGHT / 2 };
|
let start = Position { x: GRID_WIDTH / 2, y: GRID_HEIGHT / 2 };
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ fn main() {
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
let count = renderer::render(&snake, &mut commands);
|
let count = renderer::render(&snake, &mut commands);
|
||||||
for i in 0..count {
|
for cmd in &commands[..count] {
|
||||||
let cmd = &commands[i];
|
|
||||||
draw_rect(cmd.x, cmd.y, cmd.w, cmd.h, cmd.color);
|
draw_rect(cmd.x, cmd.y, cmd.w, cmd.h, cmd.color);
|
||||||
}
|
}
|
||||||
flush();
|
flush();
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ impl Framebuffer for VirtioFramebuffer {
|
|||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
let w = self.width.raw() as u32;
|
let w = self.width.raw() as u32;
|
||||||
let h = self.height.raw() as u32;
|
let h = self.height.raw() as u32;
|
||||||
gpu::transfer_to_host(&self.mmio, &self.queue, &self.dma, RESOURCE_ID, 0, 0, w, h);
|
let whole = gpu::Rect { x: 0, y: 0, w, h };
|
||||||
gpu::resource_flush(&self.mmio, &self.queue, &self.dma, RESOURCE_ID, 0, 0, w, h);
|
gpu::transfer_to_host(&self.mmio, &self.queue, &self.dma, RESOURCE_ID, whole);
|
||||||
|
gpu::resource_flush(&self.mmio, &self.queue, &self.dma, RESOURCE_ID, whole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,18 +56,27 @@ pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddr
|
|||||||
submit_cmd(mmio, queue, dma, 48)
|
submit_cmd(mmio, queue, dma, 48)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) -> bool {
|
/// A rectangle of a resource, in pixels.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Rect {
|
||||||
|
pub x: u32,
|
||||||
|
pub y: u32,
|
||||||
|
pub w: u32,
|
||||||
|
pub h: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, rect: Rect) -> bool {
|
||||||
write_cmd_header(&dma.cmd, 0x0105);
|
write_cmd_header(&dma.cmd, 0x0105);
|
||||||
put_rect(&dma.cmd, x, y, w, h);
|
put_rect(&dma.cmd, rect);
|
||||||
// Offset into the resource's memory, then the resource id.
|
// Offset into the resource's memory, then the resource id.
|
||||||
dma.cmd.write(BODY + 16, 0u64);
|
dma.cmd.write(BODY + 16, 0u64);
|
||||||
dma.cmd.write(BODY + 24, resource_id);
|
dma.cmd.write(BODY + 24, resource_id);
|
||||||
submit_cmd(mmio, queue, dma, 56)
|
submit_cmd(mmio, queue, dma, 56)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) -> bool {
|
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, rect: Rect) -> bool {
|
||||||
write_cmd_header(&dma.cmd, 0x0104);
|
write_cmd_header(&dma.cmd, 0x0104);
|
||||||
put_rect(&dma.cmd, x, y, w, h);
|
put_rect(&dma.cmd, rect);
|
||||||
dma.cmd.write(BODY + 16, resource_id);
|
dma.cmd.write(BODY + 16, resource_id);
|
||||||
submit_cmd(mmio, queue, dma, 48)
|
submit_cmd(mmio, queue, dma, 48)
|
||||||
}
|
}
|
||||||
@@ -77,11 +86,11 @@ fn write_cmd_header(cmd: &Window, cmd_type: u32) {
|
|||||||
cmd.write(TYPE, cmd_type);
|
cmd.write(TYPE, cmd_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_rect(cmd: &Window, x: u32, y: u32, w: u32, h: u32) {
|
fn put_rect(cmd: &Window, r: Rect) {
|
||||||
cmd.write(RECT_X, x);
|
cmd.write(RECT_X, r.x);
|
||||||
cmd.write(RECT_Y, y);
|
cmd.write(RECT_Y, r.y);
|
||||||
cmd.write(RECT_W, w);
|
cmd.write(RECT_W, r.w);
|
||||||
cmd.write(RECT_H, h);
|
cmd.write(RECT_H, r.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs) -> Option<(u32, u32)> {
|
pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs) -> Option<(u32, u32)> {
|
||||||
|
|||||||
@@ -43,16 +43,30 @@ impl Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Up to `BATCH` entries of `dir`: names and whether each is a folder.
|
/// One thing in a folder.
|
||||||
fn entries(fs: &mut Storage, dir: &Path) -> Option<([([u8; NAME], usize, bool); BATCH], usize)> {
|
#[derive(Clone, Copy)]
|
||||||
let mut out = [([0u8; NAME], 0, false); BATCH];
|
struct Entry {
|
||||||
|
name: [u8; NAME],
|
||||||
|
len: usize,
|
||||||
|
is_dir: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entry {
|
||||||
|
fn name(&self) -> &[u8] {
|
||||||
|
&self.name[..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Up to `BATCH` entries of `dir`.
|
||||||
|
fn entries(fs: &mut Storage, dir: &Path) -> Option<([Entry; BATCH], usize)> {
|
||||||
|
let mut out = [Entry { name: [0; NAME], len: 0, is_dir: false }; BATCH];
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
fs.list_dir(dir.as_bytes(), |e| {
|
fs.list_dir(dir.as_bytes(), |e| {
|
||||||
let name = e.name();
|
let name = e.name();
|
||||||
if name != b"." && name != b".." && n < BATCH {
|
if name != b"." && name != b".." && n < BATCH {
|
||||||
out[n].0[..name.len()].copy_from_slice(name);
|
out[n].name[..name.len()].copy_from_slice(name);
|
||||||
out[n].1 = name.len();
|
out[n].len = name.len();
|
||||||
out[n].2 = e.is_dir;
|
out[n].is_dir = e.is_dir;
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -83,9 +97,9 @@ fn copy_tree(fs: &mut Storage, from: &Path, to: &Path, buf: &mut [u8]) -> Result
|
|||||||
// Nothing shipped for this area.
|
// Nothing shipped for this area.
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
for (name, len, is_dir) in &list[..n] {
|
for entry in &list[..n] {
|
||||||
let (src, dst) = (from.join(&name[..*len]).ok_or("path too long")?, to.join(&name[..*len]).ok_or("path too long")?);
|
let (src, dst) = (from.join(entry.name()).ok_or("path too long")?, to.join(entry.name()).ok_or("path too long")?);
|
||||||
if *is_dir {
|
if entry.is_dir {
|
||||||
fs.mkdir(dst.as_bytes()).map_err(|_| "cannot make a folder")?;
|
fs.mkdir(dst.as_bytes()).map_err(|_| "cannot make a folder")?;
|
||||||
copy_tree(fs, &src, &dst, buf)?;
|
copy_tree(fs, &src, &dst, buf)?;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub(crate) fn load_binary(
|
|||||||
let page_start = segment.vaddr & !0xFFF;
|
let page_start = segment.vaddr & !0xFFF;
|
||||||
let offset_in_page = segment.vaddr & 0xFFF;
|
let offset_in_page = segment.vaddr & 0xFFF;
|
||||||
let total_size = offset_in_page + segment.mem_size;
|
let total_size = offset_in_page + segment.mem_size;
|
||||||
let seg_pages = (total_size + PAGE_SIZE - 1) / PAGE_SIZE;
|
let seg_pages = total_size.div_ceil(PAGE_SIZE);
|
||||||
|
|
||||||
let page_count = PageCount::new(u16::try_from(seg_pages).ok()?)?;
|
let page_count = PageCount::new(u16::try_from(seg_pages).ok()?)?;
|
||||||
let local = libkos::window::request(page_count)?;
|
let local = libkos::window::request(page_count)?;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ mod user;
|
|||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use record::{
|
pub use record::{
|
||||||
|
Account,
|
||||||
Copies, Entry, KdfParams, Outcome, RECORD_SIZE, Record, Refused, SLOTS, Session, State,
|
Copies, Entry, KdfParams, Outcome, RECORD_SIZE, Record, Refused, SLOTS, Session, State,
|
||||||
};
|
};
|
||||||
pub use user::{Name, Role, User, UserId};
|
pub use user::{Name, Role, User, UserId};
|
||||||
|
|||||||
@@ -154,6 +154,15 @@ fn parse_user(role: u8, id: &[u8], name: &[u8]) -> Option<User> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A user about to be added: who, and the passcodes that will open their
|
||||||
|
/// slot (and, if given, their duress slot).
|
||||||
|
pub struct Account<'a> {
|
||||||
|
pub name: Name,
|
||||||
|
pub role: Role,
|
||||||
|
pub passcode: &'a [u8],
|
||||||
|
pub duress: Option<&'a [u8]>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Record {
|
impl Record {
|
||||||
fn name_tag(&self, name: &Name) -> [u8; NAME_TAG] {
|
fn name_tag(&self, name: &Name) -> [u8; NAME_TAG] {
|
||||||
let mut m = <Blake2sMac256 as KeyInit>::new_from_slice(&self.pepper)
|
let mut m = <Blake2sMac256 as KeyInit>::new_from_slice(&self.pepper)
|
||||||
@@ -273,7 +282,7 @@ impl Record {
|
|||||||
admin: Some(admin),
|
admin: Some(admin),
|
||||||
};
|
};
|
||||||
let (record, user) = first
|
let (record, user) = first
|
||||||
.add_user(&owner, name, Role::Owner, passcode, duress, memory, rng)
|
.add_user(&owner, Account { name, role: Role::Owner, passcode, duress }, memory, rng)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let session = record.unlock(name.as_bytes(), passcode, memory);
|
let session = record.unlock(name.as_bytes(), passcode, memory);
|
||||||
let _ = user;
|
let _ = user;
|
||||||
@@ -371,16 +380,8 @@ impl Record {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An owner adds a user; the new record and the user.
|
/// An owner adds a user; the new record and the user.
|
||||||
pub fn add_user(
|
pub fn add_user(&self, by: &Session, account: Account, memory: &mut [Block], rng: &mut impl Random) -> Result<(Self, User), Refused> {
|
||||||
&self,
|
let Account { name, role, passcode, duress } = account;
|
||||||
by: &Session,
|
|
||||||
name: Name,
|
|
||||||
role: Role,
|
|
||||||
passcode: &[u8],
|
|
||||||
duress: Option<&[u8]>,
|
|
||||||
memory: &mut [Block],
|
|
||||||
rng: &mut impl Random,
|
|
||||||
) -> Result<(Self, User), Refused> {
|
|
||||||
let admin = by.admin.clone().ok_or(Refused::NotOwner)?;
|
let admin = by.admin.clone().ok_or(Refused::NotOwner)?;
|
||||||
let mut entries = self.entries(&admin).ok_or(Refused::Failed)?;
|
let mut entries = self.entries(&admin).ok_or(Refused::Failed)?;
|
||||||
if entries.iter().flatten().any(|e| e.user.name == name) {
|
if entries.iter().flatten().any(|e| e.user.name == name) {
|
||||||
@@ -467,10 +468,10 @@ impl Record {
|
|||||||
return Err(Refused::LastOwner);
|
return Err(Refused::LastOwner);
|
||||||
}
|
}
|
||||||
let mut r = self.next(|_| {});
|
let mut r = self.next(|_| {});
|
||||||
for i in 0..SLOTS {
|
for (entry, slot) in entries.iter_mut().zip(r.slots.iter_mut()) {
|
||||||
if entries[i].is_some_and(|e| e.user.id == gone.id) {
|
if entry.is_some_and(|e| e.user.id == gone.id) {
|
||||||
r.slots[i] = Slot(noise(rng).ok_or(Refused::Failed)?);
|
*slot = Slot(noise(rng).ok_or(Refused::Failed)?);
|
||||||
entries[i] = None;
|
*entry = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !r.seal_directory(&admin, &entries, rng) {
|
if !r.seal_directory(&admin, &entries, rng) {
|
||||||
|
|||||||
@@ -79,15 +79,7 @@ fn users_have_their_own_keys_and_may_even_share_a_passcode() {
|
|||||||
let (r, owner) = setup(None, 2);
|
let (r, owner) = setup(None, 2);
|
||||||
let mut rng = Counter(40);
|
let mut rng = Counter(40);
|
||||||
let (r, work) = r
|
let (r, work) = r
|
||||||
.add_user(
|
.add_user(&owner, Account { name: name("work"), role: Role::Standard, passcode: b"1234", duress: None }, &mut memory(), &mut rng)
|
||||||
&owner,
|
|
||||||
name("work"),
|
|
||||||
Role::Standard,
|
|
||||||
b"1234",
|
|
||||||
None,
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let w = signed_in(&r, "work", b"1234").unwrap();
|
let w = signed_in(&r, "work", b"1234").unwrap();
|
||||||
let g = signed_in(&r, "gabriel", b"1234").unwrap();
|
let g = signed_in(&r, "gabriel", b"1234").unwrap();
|
||||||
@@ -105,15 +97,7 @@ fn users_have_their_own_keys_and_may_even_share_a_passcode() {
|
|||||||
"not even hidden in their slot"
|
"not even hidden in their slot"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
r.add_user(
|
r.add_user(&w, Account { name: name("x"), role: Role::Standard, passcode: b"9", duress: None }, &mut memory(), &mut rng)
|
||||||
&w,
|
|
||||||
name("x"),
|
|
||||||
Role::Standard,
|
|
||||||
b"9",
|
|
||||||
None,
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng
|
|
||||||
)
|
|
||||||
.err(),
|
.err(),
|
||||||
Some(Refused::NotOwner)
|
Some(Refused::NotOwner)
|
||||||
);
|
);
|
||||||
@@ -125,26 +109,10 @@ fn owners_see_and_manage_the_users() {
|
|||||||
let (r, owner) = setup(Some(b"0000"), 3);
|
let (r, owner) = setup(Some(b"0000"), 3);
|
||||||
let mut rng = Counter(50);
|
let mut rng = Counter(50);
|
||||||
let (r, _) = r
|
let (r, _) = r
|
||||||
.add_user(
|
.add_user(&owner, Account { name: name("work"), role: Role::Standard, passcode: b"5678", duress: Some(b"8765") }, &mut memory(), &mut rng)
|
||||||
&owner,
|
|
||||||
name("work"),
|
|
||||||
Role::Standard,
|
|
||||||
b"5678",
|
|
||||||
Some(b"8765"),
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (r, second) = r
|
let (r, second) = r
|
||||||
.add_user(
|
.add_user(&owner, Account { name: name("anna"), role: Role::Owner, passcode: b"4321", duress: None }, &mut memory(), &mut rng)
|
||||||
&owner,
|
|
||||||
name("anna"),
|
|
||||||
Role::Owner,
|
|
||||||
b"4321",
|
|
||||||
None,
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let names: Vec<_> = r
|
let names: Vec<_> = r
|
||||||
.users(&owner)
|
.users(&owner)
|
||||||
@@ -155,15 +123,7 @@ fn owners_see_and_manage_the_users() {
|
|||||||
.collect();
|
.collect();
|
||||||
assert_eq!(names.len(), 3, "duress slots are not listed: {names:?}");
|
assert_eq!(names.len(), 3, "duress slots are not listed: {names:?}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
r.add_user(
|
r.add_user(&owner, Account { name: name("work"), role: Role::Standard, passcode: b"x", duress: None }, &mut memory(), &mut rng)
|
||||||
&owner,
|
|
||||||
name("work"),
|
|
||||||
Role::Standard,
|
|
||||||
b"x",
|
|
||||||
None,
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng
|
|
||||||
)
|
|
||||||
.err(),
|
.err(),
|
||||||
Some(Refused::NameTaken)
|
Some(Refused::NameTaken)
|
||||||
);
|
);
|
||||||
@@ -205,15 +165,7 @@ fn slots_run_out() {
|
|||||||
let mut added = 0;
|
let mut added = 0;
|
||||||
for i in 0..SLOTS {
|
for i in 0..SLOTS {
|
||||||
let n = std::format!("u{i}");
|
let n = std::format!("u{i}");
|
||||||
match r.add_user(
|
match r.add_user(&owner, Account { name: name(&n), role: Role::Standard, passcode: b"pass", duress: None }, &mut memory(), &mut rng) {
|
||||||
&owner,
|
|
||||||
name(&n),
|
|
||||||
Role::Standard,
|
|
||||||
b"pass",
|
|
||||||
None,
|
|
||||||
&mut memory(),
|
|
||||||
&mut rng,
|
|
||||||
) {
|
|
||||||
Ok((next, _)) => {
|
Ok((next, _)) => {
|
||||||
r = next;
|
r = next;
|
||||||
added += 1;
|
added += 1;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
const PAGE_SIZE: usize = 4096;
|
const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
@@ -10,6 +12,8 @@ struct FreeBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct KosAllocator {
|
pub struct KosAllocator {
|
||||||
|
/// A program's threads share the heap: one at a time in the free list.
|
||||||
|
locked: AtomicBool,
|
||||||
inner: UnsafeCell<AllocatorInner>,
|
inner: UnsafeCell<AllocatorInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,12 +28,45 @@ unsafe impl Sync for KosAllocator {}
|
|||||||
impl KosAllocator {
|
impl KosAllocator {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
locked: AtomicBool::new(false),
|
||||||
inner: UnsafeCell::new(AllocatorInner { free_list: ptr::null_mut() }),
|
inner: UnsafeCell::new(AllocatorInner { free_list: ptr::null_mut() }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_mut(&self) -> &mut AllocatorInner {
|
fn lock(&self) -> Locked<'_> {
|
||||||
unsafe { &mut *self.inner.get() }
|
while self.locked.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
|
Locked(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for KosAllocator {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The free list, held until dropped.
|
||||||
|
struct Locked<'a>(&'a KosAllocator);
|
||||||
|
|
||||||
|
impl Deref for Locked<'_> {
|
||||||
|
type Target = AllocatorInner;
|
||||||
|
fn deref(&self) -> &AllocatorInner {
|
||||||
|
// Only one `Locked` exists at a time.
|
||||||
|
unsafe { &*self.0.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Locked<'_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut AllocatorInner {
|
||||||
|
unsafe { &mut *self.0.inner.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Locked<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.locked.store(false, Ordering::Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +140,7 @@ impl AllocatorInner {
|
|||||||
|
|
||||||
unsafe impl GlobalAlloc for KosAllocator {
|
unsafe impl GlobalAlloc for KosAllocator {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
let inner = self.inner_mut();
|
let mut inner = self.lock();
|
||||||
let size = layout.size().max(core::mem::size_of::<FreeBlock>());
|
let size = layout.size().max(core::mem::size_of::<FreeBlock>());
|
||||||
let align = layout.align();
|
let align = layout.align();
|
||||||
|
|
||||||
@@ -113,7 +150,7 @@ unsafe impl GlobalAlloc for KosAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alignment can cost up to `align` bytes of the block.
|
// Alignment can cost up to `align` bytes of the block.
|
||||||
let pages_needed = (size + align + PAGE_SIZE - 1) / PAGE_SIZE;
|
let pages_needed = (size + align).div_ceil(PAGE_SIZE);
|
||||||
let block = inner.request_pages(pages_needed);
|
let block = inner.request_pages(pages_needed);
|
||||||
if block.is_null() {
|
if block.is_null() {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
@@ -124,7 +161,7 @@ unsafe impl GlobalAlloc for KosAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
let inner = self.inner_mut();
|
let mut inner = self.lock();
|
||||||
let size = layout.size().max(core::mem::size_of::<FreeBlock>());
|
let size = layout.size().max(core::mem::size_of::<FreeBlock>());
|
||||||
inner.add_to_free_list(ptr, size);
|
inner.add_to_free_list(ptr, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,17 @@ use types::time::Ticks;
|
|||||||
|
|
||||||
pub fn exit() -> ! {
|
pub fn exit() -> ! {
|
||||||
let _ = call0(SYS_EXIT);
|
let _ = call0(SYS_EXIT);
|
||||||
loop {}
|
// The kernel does not return from an exit.
|
||||||
|
loop {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit_thread() -> ! {
|
pub fn exit_thread() -> ! {
|
||||||
let _ = call0(SYS_EXIT_THREAD);
|
let _ = call0(SYS_EXIT_THREAD);
|
||||||
loop {}
|
loop {
|
||||||
|
core::hint::spin_loop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn yield_now() {
|
pub fn yield_now() {
|
||||||
@@ -28,7 +33,9 @@ pub fn yield_now() {
|
|||||||
/// call fails and this spins, since there is nothing sensible to return.
|
/// call fails and this spins, since there is nothing sensible to return.
|
||||||
pub fn halt(control: CapSlot) -> ! {
|
pub fn halt(control: CapSlot) -> ! {
|
||||||
let _ = raw(SYS_HALT, [control.value() as usize, 0, 0, 0, 0, 0]);
|
let _ = raw(SYS_HALT, [control.value() as usize, 0, 0, 0, 0, 0]);
|
||||||
loop {}
|
loop {
|
||||||
|
yield_now();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_time() -> Ticks {
|
pub fn get_time() -> Ticks {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//! randomness, and the owner (`Prompt`). No kernel, no hardware: tested on
|
//! randomness, and the owner (`Prompt`). No kernel, no hardware: tested on
|
||||||
//! the host.
|
//! the host.
|
||||||
|
|
||||||
use keystore::{Block, Copies, KdfParams, Key, Name, Outcome, RECORD_SIZE, Random, Record, Refused, Role, SLOTS, Session, User, UserId};
|
use keystore::{Account, Block, Copies, KdfParams, Key, Name, Outcome, RECORD_SIZE, Random, Record, Refused, Role, SLOTS, Session, User, UserId};
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
/// The keystore device: the record's two copies.
|
/// The keystore device: the record's two copies.
|
||||||
@@ -228,7 +228,7 @@ fn manage(ks: &mut impl Keystore, rng: &mut impl Random, prompt: &mut impl Promp
|
|||||||
let (mut real, mut duress) = (Secret::new(), Secret::new());
|
let (mut real, mut duress) = (Secret::new(), Secret::new());
|
||||||
ask_passcodes(prompt, &mut real, &mut duress)?;
|
ask_passcodes(prompt, &mut real, &mut duress)?;
|
||||||
let duress = (duress.len > 0).then_some(duress.as_bytes());
|
let duress = (duress.len > 0).then_some(duress.as_bytes());
|
||||||
record.add_user(session, name, role, real.as_bytes(), duress, memory, rng).map(|(r, _)| r)
|
record.add_user(session, Account { name, role, passcode: real.as_bytes(), duress }, memory, rng).map(|(r, _)| r)
|
||||||
}
|
}
|
||||||
b"r" => {
|
b"r" => {
|
||||||
let name = ask_name(prompt, "Remove whom: ")?;
|
let name = ask_name(prompt, "Remove whom: ")?;
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ pub struct MockInputDevice {
|
|||||||
tail: usize,
|
tail: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MockInputDevice {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MockInputDevice {
|
impl MockInputDevice {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ pub struct LogServer<O: FnMut(&[u8]) = fn(&[u8])> {
|
|||||||
out: O,
|
out: O,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for LogServer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LogServer {
|
impl LogServer {
|
||||||
/// Text goes nowhere.
|
/// Text goes nowhere.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
|||||||
@@ -44,16 +44,21 @@ impl MockFileSystem {
|
|||||||
|
|
||||||
fn find_by_name(&self, path: &[u8]) -> Option<usize> {
|
fn find_by_name(&self, path: &[u8]) -> Option<usize> {
|
||||||
for i in 0..MAX_FILES {
|
for i in 0..MAX_FILES {
|
||||||
if let Some(entry) = &self.files[i] {
|
if let Some(entry) = &self.files[i]
|
||||||
if entry.name == *path {
|
&& entry.name == *path {
|
||||||
return Some(i);
|
return Some(i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MockFileSystem {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FileSystem for MockFileSystem {
|
impl FileSystem for MockFileSystem {
|
||||||
fn writable(&self) -> bool {
|
fn writable(&self) -> bool {
|
||||||
!self.read_only
|
!self.read_only
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ impl FileName {
|
|||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.len as usize
|
self.len as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<[u8]> for FileName {
|
impl PartialEq<[u8]> for FileName {
|
||||||
|
|||||||
@@ -37,11 +37,10 @@ pub fn find_entry<B: BlockDevice>(
|
|||||||
let name_len = block_buf[pos + 6] as usize;
|
let name_len = block_buf[pos + 6] as usize;
|
||||||
|
|
||||||
if rec_len == 0 { break; }
|
if rec_len == 0 { break; }
|
||||||
if entry_inode != 0 && name_len == name.len() {
|
if entry_inode != 0 && name_len == name.len()
|
||||||
if &block_buf[pos + 8..pos + 8 + name_len] == name {
|
&& &block_buf[pos + 8..pos + 8 + name_len] == name {
|
||||||
return Some(entry_inode);
|
return Some(entry_inode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pos += rec_len;
|
pos += rec_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,8 +146,8 @@ pub fn remove_entry<B: BlockDevice>(
|
|||||||
let name_len = block_buf[pos + 6] as usize;
|
let name_len = block_buf[pos + 6] as usize;
|
||||||
|
|
||||||
if rec_len == 0 { break; }
|
if rec_len == 0 { break; }
|
||||||
if entry_inode != 0 && name_len == name.len() {
|
if entry_inode != 0 && name_len == name.len()
|
||||||
if &block_buf[pos + 8..pos + 8 + name_len] == name {
|
&& &block_buf[pos + 8..pos + 8 + name_len] == name {
|
||||||
if let Some(pp) = prev_pos {
|
if let Some(pp) = prev_pos {
|
||||||
let prev_rec = read_u16(&block_buf, pp + 4) as usize;
|
let prev_rec = read_u16(&block_buf, pp + 4) as usize;
|
||||||
write_u16(&mut block_buf, pp + 4, (prev_rec + rec_len) as u16);
|
write_u16(&mut block_buf, pp + 4, (prev_rec + rec_len) as u16);
|
||||||
@@ -158,7 +157,6 @@ pub fn remove_entry<B: BlockDevice>(
|
|||||||
write_block(device, phys, spb, &block_buf);
|
write_block(device, phys, spb, &block_buf);
|
||||||
return Some(entry_inode);
|
return Some(entry_inode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
prev_pos = Some(pos);
|
prev_pos = Some(pos);
|
||||||
pos += rec_len;
|
pos += rec_len;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,9 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
|||||||
done += chunk;
|
done += chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.open_files[handle.raw() as usize].as_mut().map(|f| f.offset += done);
|
if let Some(f) = self.open_files[handle.raw() as usize].as_mut() {
|
||||||
|
f.offset += done;
|
||||||
|
}
|
||||||
Some(done)
|
Some(done)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,13 +206,12 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
|||||||
|
|
||||||
fn close(&mut self, handle: FileHandle) {
|
fn close(&mut self, handle: FileHandle) {
|
||||||
if handle.raw() as usize >= MAX_OPEN_FILES { return; }
|
if handle.raw() as usize >= MAX_OPEN_FILES { return; }
|
||||||
if let Some(file) = self.open_files[handle.raw() as usize].take() {
|
if let Some(file) = self.open_files[handle.raw() as usize].take()
|
||||||
if let Some(mut inode) = self.read_inode(file.inode_num) {
|
&& let Some(mut inode) = self.read_inode(file.inode_num) {
|
||||||
inode.size = file.size as u64;
|
inode.size = file.size as u64;
|
||||||
inode.block_data = file.block_data;
|
inode.block_data = file.block_data;
|
||||||
self.write_inode(file.inode_num, &inode);
|
self.write_inode(file.inode_num, &inode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_dir(&mut self, path: &[u8], entries: &mut [DirEntry]) -> Option<usize> {
|
fn list_dir(&mut self, path: &[u8], entries: &mut [DirEntry]) -> Option<usize> {
|
||||||
@@ -222,14 +223,13 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
|||||||
|
|
||||||
let inode = self.read_inode(dir_inode_num)?;
|
let inode = self.read_inode(dir_inode_num)?;
|
||||||
let count = dir::list_entries(&mut self.device, &self.sb, &inode, entries)?;
|
let count = dir::list_entries(&mut self.device, &self.sb, &inode, entries)?;
|
||||||
for i in 0..count {
|
for entry in entries.iter_mut().take(count) {
|
||||||
if !entries[i].is_dir {
|
if !entry.is_dir {
|
||||||
let name = entries[i].name;
|
let name = entry.name;
|
||||||
if let Some(child_ino) = dir::find_entry(&mut self.device, &self.sb, &inode, name.as_bytes()) {
|
if let Some(child_ino) = dir::find_entry(&mut self.device, &self.sb, &inode, name.as_bytes())
|
||||||
if let Some(child) = self.read_inode(child_ino) {
|
&& let Some(child) = self.read_inode(child_ino) {
|
||||||
entries[i].size = child.size as usize;
|
entry.size = child.size as usize;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(count)
|
Some(count)
|
||||||
@@ -279,11 +279,10 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
|||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(child_inode) = self.read_inode(child_inode_num) {
|
if let Some(child_inode) = self.read_inode(child_inode_num)
|
||||||
if child_inode.is_dir() {
|
&& child_inode.is_dir() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let parent_inode = match self.read_inode(parent_inode_num) {
|
let parent_inode = match self.read_inode(parent_inode_num) {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
@@ -299,11 +298,10 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
|
|||||||
self.clear_inode(child_inode_num);
|
self.clear_inode(child_inode_num);
|
||||||
self.free_inode(child_inode_num);
|
self.free_inode(child_inode_num);
|
||||||
for slot in self.open_files.iter_mut() {
|
for slot in self.open_files.iter_mut() {
|
||||||
if let Some(f) = slot {
|
if let Some(f) = slot
|
||||||
if f.inode_num == child_inode_num {
|
&& f.inode_num == child_inode_num {
|
||||||
*slot = None;
|
*slot = None;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,3 +102,9 @@ impl Grants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Grants {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user