Files
zing/src/mem.zig
T

98 lines
3.1 KiB
Zig

//! Platform-independent memory management functions.
const std = @import("std");
pub const vmm = @import("mem/vmm.zig");
pub const phys = @import("mem/phys.zig");
pub const TranslationLevel = vmm.TranslationLevel;
/// A representation for physical address.
pub const PhysicalAddress = packed struct(u64) {
raw: u64,
/// NULL/zero physical address constant.
pub const NULL: @This() = .{ .raw = 0 };
/// Base address to add to a given `PhysicalAddress` in order to "virtualize" it.
pub var g_virtualize_base: usize = 0;
/// Maximum `PhysicalAddress` that can be represented as a virtual address.
pub var g_virtualize_size: usize = 0;
/// Adds an `offset` to this `PhysicalAddress`
pub fn add(self: @This(), offset: usize) @This() {
return .{ .raw = self.raw + @as(u64, @intCast(offset)) };
}
/// "Virtualizes" a `PhysicalAddress` by turning it into a virtual address representation of
/// the memory pointed to by this physical address.
///
/// # Panics
///
/// Panics if the physical address points to a memory that cannot be represented by a virtual
/// address.
pub fn virtualize(self: @This()) usize {
if (self.raw > g_virtualize_size) {
@panic("Physical address out of virtualize bounds");
}
return self.raw + g_virtualize_base;
}
/// "De-virtualizes" a previously "virtualized" physical address by mapping it back into its
/// physical form.
///
/// # Panics
///
/// Panics if the virtual address provided is outside of virtualizable memory range.
pub fn from_virtualized(virt: usize) @This() {
if ((virt < g_virtualize_base) || (virt - g_virtualize_base > g_virtualize_size)) {
@panic("Invalid virtualized physical address");
}
return .{ .raw = virt - g_virtualize_base };
}
};
/// Helper function to format a byte quantity into a human-readable size.
/// Writes its result to the `buffer` provided and returns a pointer to it.
pub fn format_size(buffer: []u8, size: u64) []const u8 {
const KIBI: u64 = 1024;
const MIBI: u64 = KIBI * 1024;
const GIBI: u64 = MIBI * 1024;
const log2: u64 = std.math.log2_int(u64, size);
const opts: struct { u64, []const u8 } = switch (log2) {
0...9 => .{ 1, "B" },
10...19 => .{ KIBI, " KiB" },
20...29 => .{ MIBI, " MiB" },
else => .{ GIBI, " GiB" },
};
const div: u64 = opts[0];
const suffix: []const u8 = opts[1];
const integer = size / div;
const dot = size >= 1024;
const ilen = std.fmt.formatIntBuf(buffer, integer, 10, .lower, .{});
var len = ilen;
var flen: usize = 0;
if (dot and integer < 100) {
const fractional = (((size * 1000) / div) % 1000) / 10;
if (ilen < buffer.len + 1) {
buffer[ilen] = '.';
flen = 1 + std.fmt.formatIntBuf(buffer[ilen + 1 ..], fractional, 10, .lower, .{ .fill = '0', .width = 2 });
}
}
len += flen;
if (len + suffix.len < buffer.len) {
std.mem.copyForwards(u8, buffer[len..], suffix);
len += suffix.len;
}
return buffer[0..len];
}