sync: Spinlock lock_irqsave() impl

This commit is contained in:
2025-03-18 14:37:31 +02:00
committed by Eugene Rossokha
parent c0df9d712d
commit d3e44e5067
5 changed files with 58 additions and 10 deletions
+1 -1
View File
@@ -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.
+16
View File
@@ -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) {}
}
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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);