sync: Spinlock lock_irqsave() impl
This commit is contained in:
+1
-1
@@ -23,7 +23,7 @@ pub inline fn interruptMask() bool {
|
||||
/// Modifies the interrupt mask to either allow or block IRQs from being delivered to the CPU.
|
||||
/// Returns the old IRQ mask.
|
||||
pub inline fn setInterruptMask(masked: bool) bool {
|
||||
impl.setInterruptMask(masked);
|
||||
return impl.setInterruptMask(masked);
|
||||
}
|
||||
|
||||
/// Suspends the CPU until an interrupt is signalled.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const std = @import("std");
|
||||
|
||||
const boot = @import("aarch64/boot.zig");
|
||||
const regs = @import("aarch64/regs.zig");
|
||||
|
||||
export const _ = boot.aa64BspLowerEntry;
|
||||
|
||||
@@ -26,6 +28,20 @@ pub const Context = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn setInterruptMask(masked: bool) bool {
|
||||
const old = interruptMask();
|
||||
if (masked) {
|
||||
regs.DAIF.modify(.{ .I = true }, .{});
|
||||
} else {
|
||||
regs.DAIF.modify(.{}, .{ .I = true });
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
pub fn interruptMask() bool {
|
||||
return regs.DAIF.read().I;
|
||||
}
|
||||
|
||||
pub fn halt() noreturn {
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,20 @@ pub const TTBR1_EL1 = Register("ttbr1_el1", u64);
|
||||
pub const VBAR_EL1 = Register("vbar_el1", u64);
|
||||
pub const ELR_EL1 = Register("elr_el1", u64);
|
||||
pub const FAR_EL1 = Register("far_el1", u64);
|
||||
pub const DAIF = Register("daif", packed struct(u64) {
|
||||
// 0..6
|
||||
_0: u6 = 0,
|
||||
// 6
|
||||
F: bool = false,
|
||||
// 7
|
||||
I: bool = false,
|
||||
// 8
|
||||
A: bool = false,
|
||||
// 9
|
||||
D: bool = false,
|
||||
// 10..64
|
||||
_1: u54 = 0,
|
||||
});
|
||||
|
||||
pub const ESR_EL1 = Register("esr_el1", packed struct(u64) {
|
||||
// 0..25
|
||||
|
||||
+7
-7
@@ -9,7 +9,7 @@ const vmm = @import("vmm.zig");
|
||||
const sync = @import("../sync.zig");
|
||||
|
||||
const Range = @import("../util/range.zig").Range;
|
||||
const Spinlock = sync.IrqSafeSpinlock;
|
||||
const Spinlock = sync.Spinlock;
|
||||
|
||||
/// Represents a single region of physical memory (reserved or available).
|
||||
pub const MemoryRegion = struct {
|
||||
@@ -262,8 +262,8 @@ fn trace_free(page: mem.PhysicalAddress) void {
|
||||
|
||||
/// Allocates a single 4KiB physical memory page.
|
||||
pub fn alloc_page() ?mem.PhysicalAddress {
|
||||
gPhysicalMemoryLock.lock();
|
||||
defer gPhysicalMemoryLock.release();
|
||||
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||
defer guard.release();
|
||||
const page = gPhysicalMemory.alloc_page();
|
||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||
trace_allocation(1, page);
|
||||
@@ -273,8 +273,8 @@ pub fn alloc_page() ?mem.PhysicalAddress {
|
||||
|
||||
/// Allocates a set of `count` contiguous 4KiB pages.
|
||||
pub fn alloc_pages(count: usize) ?mem.PhysicalAddress {
|
||||
gPhysicalMemoryLock.lock();
|
||||
defer gPhysicalMemoryLock.release();
|
||||
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||
defer guard.release();
|
||||
const pages = gPhysicalMemory.alloc_pages(count);
|
||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||
trace_allocation(count, pages);
|
||||
@@ -293,8 +293,8 @@ pub fn free_page(page: mem.PhysicalAddress) void {
|
||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||
trace_free(page);
|
||||
}
|
||||
gPhysicalMemoryLock.lock();
|
||||
defer gPhysicalMemoryLock.release();
|
||||
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||
defer guard.release();
|
||||
gPhysicalMemory.free_page(page);
|
||||
}
|
||||
|
||||
|
||||
+20
-2
@@ -4,10 +4,21 @@ const std = @import("std");
|
||||
const arch = @import("kernel.zig").arch;
|
||||
|
||||
/// Basic spinlock implementation
|
||||
// TODO not actually IRQ safe, lol.
|
||||
pub const IrqSafeSpinlock = struct {
|
||||
pub const Spinlock = struct {
|
||||
state: std.atomic.Value(bool) = .{ .raw = false },
|
||||
|
||||
const Guard = struct {
|
||||
lock: *Spinlock,
|
||||
irqMask: bool,
|
||||
|
||||
/// Releases the `Guard`, restoring the previous IRQ state and releasing the lock used
|
||||
/// to acquire it.
|
||||
pub fn release(self: @This()) void {
|
||||
self.lock.release();
|
||||
_ = arch.setInterruptMask(self.irqMask);
|
||||
}
|
||||
};
|
||||
|
||||
/// Acquires a lock over `self`. Returns `false` if the lock is already held by someone else.
|
||||
pub fn tryLock(self: *@This()) bool {
|
||||
return self.state.cmpxchgStrong(false, true, .acquire, .monotonic) orelse false;
|
||||
@@ -20,6 +31,13 @@ pub const IrqSafeSpinlock = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `lock()`, but additionally saves current IRQ state and masks IRQs.
|
||||
pub fn lock_irqsave(self: *@This()) Guard {
|
||||
const irqMask = arch.setInterruptMask(true);
|
||||
self.lock();
|
||||
return .{ .irqMask = irqMask, .lock = self };
|
||||
}
|
||||
|
||||
/// Releases a lock over `self`.
|
||||
pub fn release(self: *@This()) void {
|
||||
self.state.store(false, .release);
|
||||
|
||||
Reference in New Issue
Block a user