blob: f32a6577d8ec194d17d3e0a512edfc1a8e52fc4c [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
// Copyright 2022-2023 Google LLC
// Author: Ard Biesheuvel <ardb@google.com>
use crate::paging::*;
use core::arch::asm;
use core::ops::Range;
// Use a different ASID for the full ID map, as well as non-global attributes
// for all its DRAM mappings. This way, we can ignore break-before-make rules
// entirely when breaking down block mappings, as long as we don't do so while
// the full ID map is active.
const ASID: u64 = 1;
// We use 4k pages with a VA range of 39-bits. This gives us a VA space of 512 GB,
// which is plenty for our identity mapping, and allow us to start at level 1.
const ROOT_LEVEL: usize = 1;
extern "C" {
// Root level of the initial ID map in NOR flash
static idmap: PageTable;
}
pub struct IdMap {
root: RootTable,
}
impl IdMap {
pub fn new() -> IdMap {
let mut id = IdMap {
root: RootTable::new(ROOT_LEVEL),
};
unsafe {
// accessing static externs is unsafe
id.root.clone_raw_entry(&idmap, 0);
}
id
}
pub fn activate(&self) {
unsafe {
// inline asm is unsafe
asm!(
"msr ttbr0_el1, {ttbrval}",
"isb",
ttbrval = in(reg) self.root.as_ptr() as u64 | (ASID << 48),
options(preserves_flags),
);
}
}
pub fn deactivate(&self) {
unsafe {
// inline asm is unsafe
asm!(
"msr ttbr0_el1, {ttbrval}",
"isb",
"tlbi aside1, {asid}",
"dsb nsh",
"isb",
asid = in(reg) ASID << 48,
ttbrval = in(reg) &idmap as *const _ as u64,
options(preserves_flags),
);
}
}
fn chunk_from_slice(slice: &[u8]) -> Chunk {
let start = slice.as_ptr() as usize;
let base = align_down!(start, PAGE_SIZE);
let size = align_up!(start - base + slice.len(), PAGE_SIZE);
Chunk(base..base + size)
}
pub fn map_range(&mut self, slice: &[u8], flags: Attributes) {
let c = Self::chunk_from_slice(slice);
log::info!(
"Mapping memory at [0x{:X} - 0x{:X}] {:?}\n",
c.0.start,
c.0.end - 1,
flags
);
self.root.map_range(&c, c.0.start as u64, flags);
}
pub fn map_range_(&mut self, range: &Range<usize>, flags: Attributes) {
let c = Chunk(range.start..range.end);
log::info!(
"Mapping memory at [0x{:X} - 0x{:X}] {:?}\n",
c.0.start,
c.0.end - 1,
flags
);
self.root.map_range(&c, c.0.start as u64, flags);
}
pub fn walk_range<F>(&self, range: &Range<usize>, f: &mut F)
where
F: FnMut(&Descriptor, usize, usize),
{
let c = Chunk(range.start..range.end);
self.root.walk_range(&c, f);
}
pub fn update_range<F>(&mut self, range: &Range<usize>, f: &F)
where
F: Fn(&mut Descriptor),
{
let c = Chunk(range.start..range.end);
log::info!(
"Updating mapping attributes for [0x{:X} - 0x{:X}]\n",
c.0.start,
c.0.end - 1,
);
self.root.update_range(&c, f);
}
}
impl Drop for IdMap {
fn drop(&mut self) {
self.deactivate();
}
}