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.
|
/// Modifies the interrupt mask to either allow or block IRQs from being delivered to the CPU.
|
||||||
/// Returns the old IRQ mask.
|
/// Returns the old IRQ mask.
|
||||||
pub inline fn setInterruptMask(masked: bool) bool {
|
pub inline fn setInterruptMask(masked: bool) bool {
|
||||||
impl.setInterruptMask(masked);
|
return impl.setInterruptMask(masked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Suspends the CPU until an interrupt is signalled.
|
/// Suspends the CPU until an interrupt is signalled.
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const boot = @import("aarch64/boot.zig");
|
const boot = @import("aarch64/boot.zig");
|
||||||
|
const regs = @import("aarch64/regs.zig");
|
||||||
|
|
||||||
export const _ = boot.aa64BspLowerEntry;
|
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 {
|
pub fn halt() noreturn {
|
||||||
while (true) {}
|
while (true) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,20 @@ pub const TTBR1_EL1 = Register("ttbr1_el1", u64);
|
|||||||
pub const VBAR_EL1 = Register("vbar_el1", u64);
|
pub const VBAR_EL1 = Register("vbar_el1", u64);
|
||||||
pub const ELR_EL1 = Register("elr_el1", u64);
|
pub const ELR_EL1 = Register("elr_el1", u64);
|
||||||
pub const FAR_EL1 = Register("far_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) {
|
pub const ESR_EL1 = Register("esr_el1", packed struct(u64) {
|
||||||
// 0..25
|
// 0..25
|
||||||
|
|||||||
+7
-7
@@ -9,7 +9,7 @@ const vmm = @import("vmm.zig");
|
|||||||
const sync = @import("../sync.zig");
|
const sync = @import("../sync.zig");
|
||||||
|
|
||||||
const Range = @import("../util/range.zig").Range;
|
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).
|
/// Represents a single region of physical memory (reserved or available).
|
||||||
pub const MemoryRegion = struct {
|
pub const MemoryRegion = struct {
|
||||||
@@ -262,8 +262,8 @@ fn trace_free(page: mem.PhysicalAddress) void {
|
|||||||
|
|
||||||
/// Allocates a single 4KiB physical memory page.
|
/// Allocates a single 4KiB physical memory page.
|
||||||
pub fn alloc_page() ?mem.PhysicalAddress {
|
pub fn alloc_page() ?mem.PhysicalAddress {
|
||||||
gPhysicalMemoryLock.lock();
|
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||||
defer gPhysicalMemoryLock.release();
|
defer guard.release();
|
||||||
const page = gPhysicalMemory.alloc_page();
|
const page = gPhysicalMemory.alloc_page();
|
||||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||||
trace_allocation(1, page);
|
trace_allocation(1, page);
|
||||||
@@ -273,8 +273,8 @@ pub fn alloc_page() ?mem.PhysicalAddress {
|
|||||||
|
|
||||||
/// Allocates a set of `count` contiguous 4KiB pages.
|
/// Allocates a set of `count` contiguous 4KiB pages.
|
||||||
pub fn alloc_pages(count: usize) ?mem.PhysicalAddress {
|
pub fn alloc_pages(count: usize) ?mem.PhysicalAddress {
|
||||||
gPhysicalMemoryLock.lock();
|
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||||
defer gPhysicalMemoryLock.release();
|
defer guard.release();
|
||||||
const pages = gPhysicalMemory.alloc_pages(count);
|
const pages = gPhysicalMemory.alloc_pages(count);
|
||||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||||
trace_allocation(count, pages);
|
trace_allocation(count, pages);
|
||||||
@@ -293,8 +293,8 @@ pub fn free_page(page: mem.PhysicalAddress) void {
|
|||||||
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
if (comptime kernel.TRACE_PHYSICAL_ALLOCATOR) {
|
||||||
trace_free(page);
|
trace_free(page);
|
||||||
}
|
}
|
||||||
gPhysicalMemoryLock.lock();
|
const guard = gPhysicalMemoryLock.lock_irqsave();
|
||||||
defer gPhysicalMemoryLock.release();
|
defer guard.release();
|
||||||
gPhysicalMemory.free_page(page);
|
gPhysicalMemory.free_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-2
@@ -4,10 +4,21 @@ const std = @import("std");
|
|||||||
const arch = @import("kernel.zig").arch;
|
const arch = @import("kernel.zig").arch;
|
||||||
|
|
||||||
/// Basic spinlock implementation
|
/// Basic spinlock implementation
|
||||||
// TODO not actually IRQ safe, lol.
|
pub const Spinlock = struct {
|
||||||
pub const IrqSafeSpinlock = struct {
|
|
||||||
state: std.atomic.Value(bool) = .{ .raw = false },
|
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.
|
/// Acquires a lock over `self`. Returns `false` if the lock is already held by someone else.
|
||||||
pub fn tryLock(self: *@This()) bool {
|
pub fn tryLock(self: *@This()) bool {
|
||||||
return self.state.cmpxchgStrong(false, true, .acquire, .monotonic) orelse false;
|
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`.
|
/// Releases a lock over `self`.
|
||||||
pub fn release(self: *@This()) void {
|
pub fn release(self: *@This()) void {
|
||||||
self.state.store(false, .release);
|
self.state.store(false, .release);
|
||||||
|
|||||||
Reference in New Issue
Block a user