Skip to content

Commit

Permalink
port to aarch64
Browse files Browse the repository at this point in the history
  • Loading branch information
coolyjg committed Feb 20, 2023
1 parent ed02471 commit e4d7b70
Show file tree
Hide file tree
Showing 28 changed files with 938 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ lto = true
rustflags = [
"-Clink-arg=-Tmodules/axhal/linker.lds"
]

[target.aarch64-unknown-none-softfloat]
rustflags = [
"-Clink-arg=-Tmodules/axhal/linker.lds"
]
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
fail-fast: false
matrix:
arch: [riscv64]
arch: [riscv64, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
Expand All @@ -28,7 +28,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
arch: [riscv64]
arch: [riscv64, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
Expand Down
30 changes: 24 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ NET ?= off
ifeq ($(ARCH), riscv64)
PLATFORM ?= qemu-virt-riscv
target := riscv64gc-unknown-none-elf
else ifeq ($(ARCH), aarch64)
PLATFORM ?= qemu-virt-aarch64
target := aarch64-unknown-none-softfloat
else
$(error "ARCH" must be "riscv64")
$(error "ARCH" must be "riscv64" or "aarch64")
endif

export ARCH
Expand Down Expand Up @@ -63,6 +66,11 @@ ifeq ($(ARCH), riscv64)
-machine virt \
-bios default \
-kernel $(kernel_bin)
else ifeq ($(ARCH), aarch64)
qemu_args += \
-cpu cortex-a72 \
-machine virt \
-kernel $(kernel_bin)
endif

ifeq ($(FS), on)
Expand Down Expand Up @@ -98,7 +106,7 @@ clean:
cargo clean

clippy:
cargo clippy --target $(target) --all-features
cargo clippy --target $(target)

fmt:
cargo fmt --all
Expand Down
206 changes: 206 additions & 0 deletions crates/page_table/src/arch/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
use core::fmt;

use memory_addr::PhysAddr;

use crate::{GenericPTE, MappingFlags, PageSize, PageTable64, PagingMetaData};

bitflags::bitflags! {
/// Memory attribute fields in the VMSAv8-64 translation table format descriptors.
pub struct DescriptorAttr: u64 {
// Attribute fields in stage 1 VMSAv8-64 Block and Page descriptors:

/// Whether the descriptor is valid.
const VALID = 1 << 0;
/// The descriptor gives the address of the next level of translation table or 4KB page.
/// (not a 2M, 1G block)
const NON_BLOCK = 1 << 1;
/// Memory attributes index field.
const ATTR_INDX = 0b111 << 2;
/// Non-secure bit. For memory accesses from Secure state, specifies whether the output
/// address is in Secure or Non-secure memory.
const NS = 1 << 5;
/// Access permission: accessable at EL0.
const AP_EL0 = 1 << 6;
/// Access permission: read-only.
const AP_RO = 1 << 7;
/// Shareability: Inner Shareable (otherwise Outer Shareable).
const INNER = 1 << 8;
/// Shareability: Inner or Outer Shareable (otherwise Non-shareable).
const SHAREABLE = 1 << 9;
/// The Access flag.
const AF = 1 << 10;
/// The not global bit.
const NG = 1 << 11;
/// Indicates that 16 adjacent translation table entries point to contiguous memory regions.
const CONTIGUOUS = 1 << 52;
/// The Privileged execute-never field.
const PXN = 1 << 53;
/// The Execute-never or Unprivileged execute-never field.
const UXN = 1 << 54;

// Next-level attributes in stage 1 VMSAv8-64 Table descriptors:

/// PXN limit for subsequent levels of lookup.
const PXN_TABLE = 1 << 59;
/// XN limit for subsequent levels of lookup.
const XN_TABLE = 1 << 60;
/// Access permissions limit for subsequent levels of lookup: access at EL0 not permitted.
const AP_NO_EL0_TABLE = 1 << 61;
/// Access permissions limit for subsequent levels of lookup: write access not permitted.
const AP_NO_WRITE_TABLE = 1 << 62;
/// For memory accesses from Secure state, specifies the Security state for subsequent
/// levels of lookup.
const NS_TABLE = 1 << 63;
}
}

#[repr(u64)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum MemType {
Device = 0,
Normal = 1,
}

impl DescriptorAttr {
const ATTR_INDEX_MASK: u64 = 0b111_00;

const fn from_mem_type(mem_type: MemType) -> Self {
let mut bits = (mem_type as u64) << 2;
if matches!(mem_type, MemType::Normal) {
bits |= Self::INNER.bits() | Self::SHAREABLE.bits();
}
Self::from_bits_truncate(bits)
}

fn mem_type(&self) -> MemType {
let idx = (self.bits() & Self::ATTR_INDEX_MASK) >> 2;
match idx {
0 => MemType::Device,
1 => MemType::Normal,
_ => panic!("Invalid memory attribute index"),
}
}
}

impl From<DescriptorAttr> for MappingFlags {
fn from(attr: DescriptorAttr) -> Self {
let mut flags = Self::empty();
if attr.contains(DescriptorAttr::VALID) {
flags |= Self::READ;
}
if !attr.contains(DescriptorAttr::AP_RO) {
flags |= Self::WRITE;
}
if attr.contains(DescriptorAttr::AP_EL0) {
flags |= Self::USER;
if !attr.contains(DescriptorAttr::UXN) {
flags |= Self::EXECUTE;
}
} else if !attr.intersects(DescriptorAttr::PXN) {
flags |= Self::EXECUTE;
}
if attr.mem_type() == MemType::Device {
flags |= Self::DEVICE;
}
flags
}
}

impl From<MappingFlags> for DescriptorAttr {
fn from(flags: MappingFlags) -> Self {
let mut attr = if flags.contains(MappingFlags::DEVICE) {
Self::from_mem_type(MemType::Device)
} else {
Self::from_mem_type(MemType::Normal)
};
if flags.contains(MappingFlags::READ) {
attr |= Self::VALID;
}
if !flags.contains(MappingFlags::WRITE) {
attr |= Self::AP_RO;
}
if flags.contains(MappingFlags::USER) {
attr |= Self::AP_EL0 | Self::PXN;
if !flags.contains(MappingFlags::EXECUTE) {
attr |= Self::UXN;
}
} else {
attr |= Self::UXN;
if !flags.contains(MappingFlags::EXECUTE) {
attr |= Self::PXN;
}
}
attr
}
}

#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct A64PTE(u64);

impl A64PTE {
const PHYS_ADDR_MASK: usize = A64PagingMetaData::PA_MAX_ADDR & !(PageSize::Size4K as usize - 1);

pub const fn empty() -> Self {
Self(0)
}
}

impl GenericPTE for A64PTE {
fn new_page(paddr: PhysAddr, flags: MappingFlags, is_huge: bool) -> Self {
let mut attr = DescriptorAttr::from(flags) | DescriptorAttr::AF;
if !is_huge {
attr |= DescriptorAttr::NON_BLOCK;
}
Self(attr.bits() | (paddr.as_usize() & Self::PHYS_ADDR_MASK) as u64)
}
fn new_table(paddr: PhysAddr) -> Self {
let attr = DescriptorAttr::NON_BLOCK | DescriptorAttr::VALID;
Self(attr.bits() | (paddr.as_usize() & Self::PHYS_ADDR_MASK) as u64)
}
fn paddr(&self) -> PhysAddr {
PhysAddr::from(self.0 as usize & Self::PHYS_ADDR_MASK)
}
fn flags(&self) -> MappingFlags {
DescriptorAttr::from_bits_truncate(self.0).into()
}
fn is_unused(&self) -> bool {
self.0 == 0
}
fn is_present(&self) -> bool {
DescriptorAttr::from_bits_truncate(self.0).contains(DescriptorAttr::VALID)
}
fn is_huge(&self) -> bool {
!DescriptorAttr::from_bits_truncate(self.0).contains(DescriptorAttr::NON_BLOCK)
}
fn clear(&mut self) {
self.0 = 0
}
}

impl fmt::Debug for A64PTE {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_struct("A64PTE");
f.field("raw", &self.0)
.field("paddr", &self.paddr())
.field("attr", &DescriptorAttr::from_bits_truncate(self.0))
.field("flags", &self.flags())
.finish()
}
}

#[derive(Copy, Clone)]
pub struct A64PagingMetaData;

impl const PagingMetaData for A64PagingMetaData {
const LEVELS: usize = 4;
const PA_MAX_BITS: usize = 40;
const VA_MAX_BITS: usize = 48;

fn vaddr_is_valid(vaddr: usize) -> bool {
let top_bits = vaddr >> Self::VA_MAX_BITS;
top_bits == 0 || top_bits == 0xffff
}
}

pub type A64PageTable<I> = PageTable64<A64PagingMetaData, A64PTE, I>;
2 changes: 2 additions & 0 deletions crates/page_table/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ cfg_if::cfg_if! {
pub mod x86_64;
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
pub mod riscv;
} else if #[cfg(target_arch = "aarch64")] {
pub mod aarch64;
}
}
1 change: 1 addition & 0 deletions modules/axconfig/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ authors = ["Yuekai Jia <[email protected]>"]

[features]
platform-qemu-virt-riscv = []
platform-qemu-virt-aarch64 = []
default = []

[dependencies]
Expand Down
2 changes: 2 additions & 0 deletions modules/axconfig/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ fn main() {
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let platform = if cfg!(feature = "platform-qemu-virt-riscv") {
"qemu-virt-riscv"
} else if cfg!(feature = "platform-qemu-virt-aarch64") {
"qemu-virt-aarch64"
} else {
println!("Unsupported platform, use dummy config!");
"dummy"
Expand Down
4 changes: 4 additions & 0 deletions modules/axconfig/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ cfg_if::cfg_if! {
#[rustfmt::skip]
#[path = "config_qemu_virt_riscv.rs"]
mod config;
} else if #[cfg(feature = "platform-qemu-virt-aarch64")] {
#[rustfmt::skip]
#[path = "config_qemu_virt_aarch64.rs"]
mod config;
} else {
#[rustfmt::skip]
#[path = "config_dummy.rs"]
Expand Down
12 changes: 12 additions & 0 deletions modules/axconfig/src/platform/qemu-virt-aarch64.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
arch = "aarch64"
platform = "qemu-virt-aarch64"

phys-memory-base = "0x4000_0000"
phys-memory-size = "0x800_0000" # 128M
kernel-base-paddr = "0x4008_0000"
kernel-base-vaddr = "0xffff_0000_4008_0000"
phys-virt-offset = "0xffff_0000_0000_0000"
mmio-regions = [
["0x0900_0000", "0x1000"], # PL011 UART
["0x0800_0000", "0x2_0000"], # GICv2
]
Loading

0 comments on commit e4d7b70

Please sign in to comment.