generated table automatically
This commit is contained in:
parent
956f22b41b
commit
05709ba8a1
@ -4,6 +4,8 @@ rustflags = [
|
||||
"-Ctarget-feature=+vfp3",
|
||||
"-Ctarget-feature=+neon",
|
||||
"-Clink-arg=-Tlink.x",
|
||||
# Can be useful for debugging.
|
||||
# "-Clink-args=-Map=app.map"
|
||||
]
|
||||
|
||||
# Tier 3 target, so no pre-compiled artifacts included.
|
||||
@ -12,4 +14,3 @@ build-std = ["core", "alloc"]
|
||||
|
||||
[build]
|
||||
target = "armv7a-none-eabihf"
|
||||
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target
|
||||
/app.map
|
||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -96,4 +96,5 @@ name = "zynq-rt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-a-rt",
|
||||
"cortex-r-a",
|
||||
]
|
||||
|
@ -1,2 +1,3 @@
|
||||
[toolchain]
|
||||
# channel = "stable"
|
||||
channel = "nightly"
|
||||
|
@ -4,4 +4,10 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
cortex-a-rt = { path = "../../cortex-r-a/cortex-a-rt" }
|
||||
cortex-a-rt = { path = "../../cortex-r-a/cortex-a-rt", optional = true }
|
||||
cortex-r-a = { path = "../../cortex-r-a/cortex-r-a", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
rt = ["dep:cortex-a-rt", "dep:cortex-r-a"]
|
||||
|
||||
|
0
zynq-rt/src/bin/main.rs
Normal file
0
zynq-rt/src/bin/main.rs
Normal file
269
zynq-rt/src/bin/table-gen.rs
Normal file
269
zynq-rt/src/bin/table-gen.rs
Normal file
@ -0,0 +1,269 @@
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
|
||||
pub use zynq_rt::mmu::*;
|
||||
|
||||
fn main() {
|
||||
let file_path = "src/mmu_table.rs";
|
||||
let file = File::create(file_path).expect("Failed to create file");
|
||||
|
||||
let mut offset = 0;
|
||||
let attr_ddr = stringify!(SECTION_ATTRS_DDR);
|
||||
let attr_unassigned = stringify!(SECTION_ATTRS_UNASSIGNED_RESERVED);
|
||||
let attr_fpga_slaves = stringify!(SECTION_ATTRS_FPGA_SLAVES);
|
||||
let attr_shared_dev = stringify!(SECTION_ATTRS_SHAREABLE_DEVICE);
|
||||
let attr_sram = stringify!(SECTION_ATTRS_SRAM);
|
||||
let attr_qspi = stringify!(SECTION_ATTRS_QSPI_XIP);
|
||||
let attr_ocm_high = stringify!(SECTION_ATTRS_OCM_MAPPED_HIGH);
|
||||
|
||||
assert_eq!(
|
||||
1 + SEGMENTS_DDR_FULL_ACCESSIBLE
|
||||
+ SEGMENTS_FPGA_SLAVE
|
||||
+ SEGMENTS_FPGA_SLAVE
|
||||
+ SEGMENTS_UNASSIGNED_0
|
||||
+ SEGMENTS_IO_PERIPHS
|
||||
+ SEGMENTS_UNASSIGNED_1
|
||||
+ SEGMENTS_NAND
|
||||
+ SEGMENTS_NOR
|
||||
+ SEGMENTS_SRAM
|
||||
+ SEGMENTS_UNASSIGNED_2
|
||||
+ SEGMENTS_AMBA_APB
|
||||
+ SEGMENTS_UNASSIGNED_3
|
||||
+ SEGMENTS_QSPI_XIP
|
||||
+ SEGMENTS_UNASSIGNED_4
|
||||
+ SEGMENTS_OCM_MAPPED_HIGH,
|
||||
4096
|
||||
);
|
||||
let mut buf_writer = std::io::BufWriter::new(file);
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"//! This file is auto-generated by table-gen.rs. Do not edit it!"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(buf_writer, "use crate::mmu::*;").unwrap();
|
||||
writeln!(buf_writer, "").unwrap();
|
||||
|
||||
writeln!(buf_writer, "/// MMU Level 1 Page table.").unwrap();
|
||||
writeln!(buf_writer, "///").unwrap();
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"/// 4096 entries, each covering 1MB of the address space."
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"pub const MMU_L1_PAGE_TABLE: L1Table = L1Table(["
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// First DDR segment, OCM memory (0x0000_0000 - 0x0010_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(buf_writer, "L1Section::new({}, {}).0,", offset, attr_ddr).unwrap();
|
||||
|
||||
offset += ONE_MB;
|
||||
writeln!(buf_writer, "// DDR memory (0x00100000 - 0x4000_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_DDR_FULL_ACCESSIBLE {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, SECTION_ATTRS_DDR).0,",
|
||||
offset
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// FPGA slave 0 (0x4000_0000 - 0x8000_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_FPGA_SLAVE {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_fpga_slaves
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// FPGA slave 1 (0x8000_0000 - 0xC000_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_FPGA_SLAVE {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_fpga_slaves
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Unassigned/Reserved (0xC000_0000 - 0xE000_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_UNASSIGNED_0 {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_unassigned
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Segments IO peripherals (0xE000_0000 - 0xE030_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_IO_PERIPHS {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_shared_dev
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Unassigned/Reserved (0xE030_0000 - 0xE100_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_UNASSIGNED_1 {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_unassigned
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// NAND (0xE100_0000 - 0xE200_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_NAND {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_shared_dev
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// NOR (0xE200_0000 - 0xE400_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_NOR {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_shared_dev
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// SRAM (0xE400_0000 - 0xE600_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_SRAM {
|
||||
writeln!(buf_writer, "L1Section::new({}, {}).0,", offset, attr_sram).unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Unassigned/Reserved (0xE600_0000 - 0xF800_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_UNASSIGNED_2 {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_unassigned
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// AMBA APB peripherals (0xF800_0000 - 0xF900_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_AMBA_APB {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_shared_dev
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Unassigned/Reserved (0xF900_0000 - 0xFC00_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_UNASSIGNED_3 {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_unassigned
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// QSPI XIP (0xFC00_0000 - 0xFE00_0000)").unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_QSPI_XIP {
|
||||
writeln!(buf_writer, "L1Section::new({}, {}).0,", offset, attr_qspi).unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"// Unassiged/Reserved (0xFE00_0000 - 0xFFF0_0000)"
|
||||
)
|
||||
.unwrap();
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_UNASSIGNED_4 {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_unassigned
|
||||
)
|
||||
.unwrap();
|
||||
offset += ONE_MB;
|
||||
}
|
||||
|
||||
writeln!(buf_writer, "// OCM High (0xFFF0_0000 - 0xFFFF_FFFF)").unwrap();
|
||||
let mut offset_u64 = offset as u64;
|
||||
for _ in 0..zynq_rt::mmu::SEGMENTS_OCM_MAPPED_HIGH {
|
||||
writeln!(
|
||||
buf_writer,
|
||||
"L1Section::new({}, {}).0,",
|
||||
offset, attr_ocm_high
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
offset_u64 += ONE_MB as u64;
|
||||
}
|
||||
// Check that the full 4 GB were covered (not too much, or less)
|
||||
assert_eq!(offset_u64, 0x1_0000_0000 as u64);
|
||||
|
||||
writeln!(buf_writer, "]);").unwrap();
|
||||
// Finish the file.
|
||||
drop(buf_writer);
|
||||
println!("Generated mmu_table.rs");
|
||||
|
||||
// Run rustfmt on the generated file
|
||||
let output = Command::new("rustfmt")
|
||||
.arg(file_path)
|
||||
.output()
|
||||
.expect("Failed to run rustfmt");
|
||||
|
||||
if !output.status.success() {
|
||||
eprintln!("rustfmt failed: {:?}", output);
|
||||
}
|
||||
}
|
@ -1,113 +1,12 @@
|
||||
#![no_std]
|
||||
use cortex_a_rt as _;
|
||||
|
||||
// Start-up code for Armv7-A
|
||||
//
|
||||
// We set up our stacks and `kmain` in system mode.
|
||||
core::arch::global_asm!(
|
||||
r#"
|
||||
.set PSS_L2CC_BASE_ADDR, 0xF8F02000
|
||||
.set PSS_SLCR_BASE_ADDR, 0xF8000000
|
||||
|
||||
.set RESERVED, 0x0fffff00
|
||||
.set TblBase , MMUTable
|
||||
.set LRemap, 0xFE00000F /* set the base address of the peripheral block as not shared */
|
||||
.set L2CCWay, (PSS_L2CC_BASE_ADDR + 0x077C) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_INVLD_WAY_OFFSET)*/
|
||||
.set L2CCSync, (PSS_L2CC_BASE_ADDR + 0x0730) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_SYNC_OFFSET)*/
|
||||
.set L2CCCrtl, (PSS_L2CC_BASE_ADDR + 0x0100) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CNTRL_OFFSET)*/
|
||||
.set L2CCAuxCrtl, (PSS_L2CC_BASE_ADDR + 0x0104) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_AUX_CNTRL_OFFSET)*/
|
||||
.set L2CCTAGLatReg, (PSS_L2CC_BASE_ADDR + 0x0108) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_TAG_RAM_CNTRL_OFFSET)*/
|
||||
.set L2CCDataLatReg, (PSS_L2CC_BASE_ADDR + 0x010C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_DATA_RAM_CNTRL_OFFSET)*/
|
||||
.set L2CCIntClear, (PSS_L2CC_BASE_ADDR + 0x0220) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_IAR_OFFSET)*/
|
||||
.set L2CCIntRaw, (PSS_L2CC_BASE_ADDR + 0x021C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_ISR_OFFSET)*/
|
||||
|
||||
.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/
|
||||
.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/
|
||||
.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/
|
||||
.set SLCRCPURSTReg, (0xF8000000 + 0x244) /*(XPS_SYS_CTRL_BASEADDR + A9_CPU_RST_CTRL_OFFSET)*/
|
||||
.set EFUSEStatus, (0xF800D000 + 0x10) /*(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)*/
|
||||
|
||||
/* workaround for simulation not working when L1 D and I caches,MMU and L2 cache enabled - DT568997 */
|
||||
.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
|
||||
|
||||
.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */
|
||||
|
||||
.set L2CCAuxControl, 0x72360000 /* Enable all prefetching, Cache replacement policy, Parity enable,
|
||||
Event monitor bus enable and Way Size (64 KB) */
|
||||
.set L2CCControl, 0x01 /* Enable L2CC */
|
||||
.set L2CCTAGLatency, 0x0111 /* latency for TAG RAM */
|
||||
.set L2CCDataLatency, 0x0121 /* latency for DATA RAM */
|
||||
|
||||
.set SLCRlockKey, 0x767B /* SLCR lock key */
|
||||
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
|
||||
.set SLCRL2cRamConfig, 0x00020202 /* SLCR L2C ram configuration */
|
||||
|
||||
.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */
|
||||
|
||||
.section .text.startup
|
||||
.align 0
|
||||
|
||||
.global _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
/* only allow cpu0 through */
|
||||
/* Read MPIDR */
|
||||
mrc p15,0,r1,c0,c0,5
|
||||
/* Extract CPU ID bits. For single-core systems, this should always be 0 */
|
||||
and r1, r1, #0x3
|
||||
cmp r1, #0
|
||||
beq check_efuse
|
||||
b initialize
|
||||
|
||||
// Zynq specific code. It is recommended to restet CPU1 according to page 160 of the datasheet
|
||||
check_efuse:
|
||||
ldr r0,=EFUSEStatus
|
||||
ldr r1,[r0] /* Read eFuse setting */
|
||||
ands r1,r1,#0x80 /* Check whether device is having single core */
|
||||
beq initialize
|
||||
|
||||
/* single core device, reset cpu1 */
|
||||
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
|
||||
ldr r1,=SLCRUnlockKey /* set unlock key */
|
||||
str r1, [r0] /* Unlock SLCR */
|
||||
|
||||
ldr r0,=SLCRCPURSTReg
|
||||
ldr r1,[r0] /* Read CPU Software Reset Control register */
|
||||
orr r1,r1,#0x22
|
||||
str r1,[r0] /* Reset CPU1 */
|
||||
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
initialize:
|
||||
mrc p15, 0, r0, c0, c0, 0 /* Get the revision */
|
||||
and r5, r0, #0x00f00000
|
||||
and r6, r0, #0x0000000f
|
||||
orr r6, r6, r5, lsr #20-4
|
||||
|
||||
/* set VBAR to the _vector_table address in linker script */
|
||||
ldr r0, =vector_base
|
||||
mcr p15, 0, r0, c12, c0, 0
|
||||
|
||||
/*invalidate scu TODO: Put this behind cfg */
|
||||
#if USE_AMP!=1
|
||||
ldr r7, =0xf8f0000c
|
||||
ldr r6, =0xffff
|
||||
str r6, [r7]
|
||||
#endif
|
||||
|
||||
/* Invalidate caches and TLBs */
|
||||
mov r0,#0 /* r0 = 0 */
|
||||
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */
|
||||
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
|
||||
mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */
|
||||
bl invalidate_dcache /* invalidate dcache */
|
||||
|
||||
/* Disable MMU, if enabled */
|
||||
mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */
|
||||
bic r0, r0, #0x1 /* clear bit 0 */
|
||||
mcr p15, 0, r0, c1, c0, 0 /* write value back */
|
||||
#[cfg(feature="rt")]
|
||||
pub mod rt;
|
||||
pub mod mmu;
|
||||
mod mmu_table;
|
||||
|
||||
/*
|
||||
*
|
||||
mrs r0, cpsr /* get the current PSR */
|
||||
mvn r1, #0x1f /* set up the irq stack pointer */
|
||||
and r2, r1, r0
|
||||
@ -159,168 +58,4 @@ initialize:
|
||||
orr r2, r2, #0x1F /* SYS mode */
|
||||
msr cpsr, r2
|
||||
ldr r13,=SYS_stack /* SYS stack pointer */
|
||||
|
||||
bl init_mmu_table
|
||||
|
||||
/*set scu enable bit in scu*/
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
|
||||
/* enable MMU and cache */
|
||||
|
||||
ldr r0,=TblBase /* Load MMU translation table base */
|
||||
/* orr r0, r0, #0x5B Outer-cacheable, WB */
|
||||
mcr p15, 0, r0, c2, c0, 0 /* TTB0 */
|
||||
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
|
||||
/* Enable mmu, icahce and dcache */
|
||||
ldr r0,=CRValMmuCac
|
||||
mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */
|
||||
dsb /* dsb allow the MMU to start up */
|
||||
isb /* isb flush prefetch buffer */
|
||||
|
||||
/* Write to ACTLR */
|
||||
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
|
||||
orr r0, r0, #(0x01 << 6) /* set SMP bit */
|
||||
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
|
||||
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
|
||||
|
||||
/* Invalidate L2 Cache and enable L2 Cache*/
|
||||
/* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */
|
||||
#if USE_AMP!=1
|
||||
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
|
||||
mov r1, #0 /* force the disable bit */
|
||||
str r1, [r0] /* disable the L2 Caches */
|
||||
|
||||
ldr r0,=L2CCAuxCrtl /* Load L2CC base address base + Aux control register */
|
||||
ldr r1,[r0] /* read the register */
|
||||
ldr r2,=L2CCAuxControl /* set the default bits */
|
||||
orr r1,r1,r2
|
||||
str r1, [r0] /* store the Aux Control Register */
|
||||
|
||||
ldr r0,=L2CCTAGLatReg /* Load L2CC base address base + TAG Latency address */
|
||||
ldr r1,=L2CCTAGLatency /* set the latencies for the TAG*/
|
||||
str r1, [r0] /* store the TAG Latency register Register */
|
||||
|
||||
ldr r0,=L2CCDataLatReg /* Load L2CC base address base + Data Latency address */
|
||||
ldr r1,=L2CCDataLatency /* set the latencies for the Data*/
|
||||
str r1, [r0] /* store the Data Latency register Register */
|
||||
|
||||
ldr r0,=L2CCWay /* Load L2CC base address base + way register*/
|
||||
ldr r2, =0xFFFF
|
||||
str r2, [r0] /* force invalidate */
|
||||
|
||||
ldr r0,=L2CCSync /* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
|
||||
/* Load L2CC base address base + sync register*/
|
||||
/* poll for completion */
|
||||
Sync:
|
||||
ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
bne Sync
|
||||
|
||||
ldr r0,=L2CCIntRaw /* clear pending interrupts */
|
||||
ldr r1,[r0]
|
||||
ldr r0,=L2CCIntClear
|
||||
str r1,[r0]
|
||||
|
||||
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
|
||||
ldr r1,=SLCRUnlockKey /* set unlock key */
|
||||
str r1, [r0] /* Unlock SLCR */
|
||||
|
||||
ldr r0,=SLCRL2cRamReg /* Load SLCR base address base + l2c Ram Control register */
|
||||
ldr r1,=SLCRL2cRamConfig /* set the configuration value */
|
||||
str r1, [r0] /* store the L2c Ram Control Register */
|
||||
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
|
||||
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
|
||||
ldr r1,[r0] /* read the register */
|
||||
mov r2, #L2CCControl /* set the enable bit */
|
||||
orr r1,r1,r2
|
||||
str r1, [r0] /* enable the L2 Caches */
|
||||
#endif
|
||||
|
||||
mov r0, r0
|
||||
mrc p15, 0, r1, c1, c0, 2 /* read cp access control register (CACR) into r1 */
|
||||
orr r1, r1, #(0xf << 20) /* enable full access for p10 & p11 */
|
||||
mcr p15, 0, r1, c1, c0, 2 /* write back into CACR */
|
||||
|
||||
/* enable vfp */
|
||||
fmrx r1, FPEXC /* read the exception register */
|
||||
orr r1,r1, #FPEXC_EN /* set VFP enable bit, leave the others in orig state */
|
||||
fmxr FPEXC, r1 /* write back the exception register */
|
||||
|
||||
mrc p15,0,r0,c1,c0,0 /* flow prediction enable */
|
||||
orr r0, r0, #(0x01 << 11) /* #0x8000 */
|
||||
mcr p15,0,r0,c1,c0,0
|
||||
|
||||
mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */
|
||||
orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */
|
||||
orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */
|
||||
mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */
|
||||
|
||||
mrs r0, cpsr /* get the current PSR */
|
||||
bic r0, r0, #0x100 /* enable asynchronous abort exception */
|
||||
msr cpsr_xsf, r0
|
||||
// TODO: Add back zero bss and data init.
|
||||
|
||||
|
||||
// Jump to application
|
||||
bl kmain
|
||||
// In case the application returns, loop forever
|
||||
b .
|
||||
.size _start, . - _start
|
||||
|
||||
invalidate_dcache:
|
||||
mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */
|
||||
ands r3, r0, #0x7000000
|
||||
mov r3, r3, lsr #23 /* cache level value (naturally aligned) */
|
||||
beq finished
|
||||
mov r10, #0 /* start with level 0 */
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1 /* work out 3xcachelevel */
|
||||
mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */
|
||||
and r1, r1, #7 /* get those 3 bits alone */
|
||||
cmp r1, #2
|
||||
blt skip /* no cache or only instruction cache at this level */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */
|
||||
isb /* isb to sync the change to the CacheSizeID reg */
|
||||
mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */
|
||||
and r2, r1, #7 /* extract the line length field */
|
||||
add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */
|
||||
ldr r4, =0x3ff
|
||||
ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */
|
||||
clz r5, r4 /* r5 is the bit position of the way size increment */
|
||||
ldr r7, =0x7fff
|
||||
ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */
|
||||
loop2:
|
||||
mov r9, r4 /* r9 working copy of the max way size (right aligned) */
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */
|
||||
orr r11, r11, r7, lsl r2 /* factor in the index number */
|
||||
mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */
|
||||
subs r9, r9, #1 /* decrement the way number */
|
||||
bge loop3
|
||||
subs r7, r7, #1 /* decrement the index */
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2 /* increment the cache number */
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
mov r10, #0 /* switch back to cache level 0 */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
"#,
|
||||
);
|
||||
|
||||
mod mmu;
|
||||
*/
|
||||
|
@ -23,6 +23,10 @@
|
||||
//! of 1 MB, it is not possible to define separate regions for them. For region
|
||||
//! 0xFFF00000 - 0xFFFFFFFF, 0xFFF00000 to 0xFFFB0000 is reserved but due to 1MB
|
||||
//! granual size, it is not possible to define separate region for it.
|
||||
use core::arch::asm;
|
||||
|
||||
use crate::mmu_table::MMU_L1_PAGE_TABLE;
|
||||
|
||||
pub const OFFSET_DDR: usize = 0;
|
||||
pub const OFFSET_DDR_ALL_ACCESSIBLE: usize = 0x10_0000;
|
||||
|
||||
@ -62,18 +66,18 @@ pub const SEGMENTS_UNASSIGNED_0: usize =
|
||||
(OFFSET_IO_PERIPHERALS_START - OFFSET_FPGA_SLAVE_1_END) / ONE_MB;
|
||||
pub const SEGMENTS_IO_PERIPHS: usize =
|
||||
(OFFSET_IO_PERIPHERALS_END - OFFSET_IO_PERIPHERALS_START) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_1: usize = (OFFSET_NAND_MEMORY - OFFSET_IO_PERIPHERALS_END) / ONE_MB;
|
||||
pub const SEGMENTS_NAND: usize = (OFFSET_NOR_MEMORY - OFFSET_NAND_MEMORY) / ONE_MB;
|
||||
pub const SEGMENTS_NOR: usize = (OFFSET_SRAM_MEMORY - OFFSET_NOR_MEMORY) / ONE_MB;
|
||||
pub const SEGMENTS_SRAM: usize = (OFFSET_SMC_MEMORIES_END - OFFSET_SRAM_MEMORY) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_1: usize = (OFFSET_AMBA_APB_START - OFFSET_SMC_MEMORIES_END) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_2: usize = (OFFSET_AMBA_APB_START - OFFSET_SMC_MEMORIES_END) / ONE_MB;
|
||||
pub const SEGMENTS_AMBA_APB: usize = (OFFSET_AMBA_APB_END - OFFSET_AMBA_APB_START) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_2: usize = (OFFSET_QSPI_XIP_START - OFFSET_AMBA_APB_END) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_3: usize = (OFFSET_QSPI_XIP_START - OFFSET_AMBA_APB_END) / ONE_MB;
|
||||
pub const SEGMENTS_QSPI_XIP: usize = (OFFSET_QSPI_XIP_END - OFFSET_QSPI_XIP_START) / ONE_MB;
|
||||
pub const SEGMENTS_UNASSIGNED_3: usize =
|
||||
pub const SEGMENTS_UNASSIGNED_4: usize =
|
||||
(OFFSET_OCM_MAPPED_HIGH_START - OFFSET_QSPI_XIP_END) / ONE_MB;
|
||||
pub const SEGMENTS_OCM_MAPPED_HIGH: usize = ((OFFSET_OCM_MAPPED_HIGH_END
|
||||
- OFFSET_OCM_MAPPED_HIGH_START as u64)
|
||||
/ ONE_MB as u64) as usize;
|
||||
pub const SEGMENTS_OCM_MAPPED_HIGH: usize =
|
||||
((OFFSET_OCM_MAPPED_HIGH_END - OFFSET_OCM_MAPPED_HIGH_START as u64) / ONE_MB as u64) as usize;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
@ -111,10 +115,88 @@ pub enum L1EntryType {
|
||||
Supersection = 0b11,
|
||||
}
|
||||
|
||||
/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
|
||||
/// The ARM Cortex-A architecture reference manual p.1363 specifies these attributes in more detail.
|
||||
///
|
||||
/// The B (Bufferable), C (Cacheable), and TEX (Type extension) bit names are inherited from
|
||||
/// earlier versions of the architecture. These names no longer adequately describe the function
|
||||
/// of the B, C, and TEX bits.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct L1Section(u32);
|
||||
pub struct MemoryRegionAttributesRaw {
|
||||
/// TEX bits
|
||||
type_extensions: u8,
|
||||
c: bool,
|
||||
b: bool,
|
||||
}
|
||||
|
||||
impl MemoryRegionAttributesRaw {
|
||||
pub const fn new(type_extensions: u8, c: bool, b: bool) -> Self {
|
||||
Self {
|
||||
type_extensions,
|
||||
c,
|
||||
b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CacheableMemoryAttribute {
|
||||
NonCacheable = 0b00,
|
||||
WriteBackWriteAlloc = 0b01,
|
||||
WriteThroughNoWriteAlloc = 0b10,
|
||||
WriteBackNoWriteAlloc = 0b11,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum MemoryRegionAttributes {
|
||||
StronglyOrdered,
|
||||
ShareableDevice,
|
||||
OuterAndInnerWriteThroughNoWriteAlloc,
|
||||
OuterAndInnerWriteBackNoWriteAlloc,
|
||||
OuterAndInnerNonCacheable,
|
||||
OuterAndInnerWriteBackWriteAlloc,
|
||||
NonShareableDevice,
|
||||
CacheableMemory {
|
||||
inner: CacheableMemoryAttribute,
|
||||
outer: CacheableMemoryAttribute,
|
||||
},
|
||||
}
|
||||
|
||||
impl MemoryRegionAttributes {
|
||||
pub const fn as_raw(&self) -> MemoryRegionAttributesRaw {
|
||||
match self {
|
||||
MemoryRegionAttributes::StronglyOrdered => {
|
||||
MemoryRegionAttributesRaw::new(0b000, false, false)
|
||||
}
|
||||
MemoryRegionAttributes::ShareableDevice => {
|
||||
MemoryRegionAttributesRaw::new(0b000, false, true)
|
||||
}
|
||||
MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc => {
|
||||
MemoryRegionAttributesRaw::new(0b000, true, false)
|
||||
}
|
||||
MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc => {
|
||||
MemoryRegionAttributesRaw::new(0b000, true, true)
|
||||
}
|
||||
MemoryRegionAttributes::OuterAndInnerNonCacheable => {
|
||||
MemoryRegionAttributesRaw::new(0b001, false, false)
|
||||
}
|
||||
MemoryRegionAttributes::OuterAndInnerWriteBackWriteAlloc => {
|
||||
MemoryRegionAttributesRaw::new(0b001, true, true)
|
||||
}
|
||||
MemoryRegionAttributes::NonShareableDevice => {
|
||||
MemoryRegionAttributesRaw::new(0b010, false, false)
|
||||
}
|
||||
MemoryRegionAttributes::CacheableMemory { inner, outer } => {
|
||||
MemoryRegionAttributesRaw::new(
|
||||
1 << 2 | (*outer as u8),
|
||||
(*inner as u8 & 0b10) != 0,
|
||||
(*inner as u8 & 0b01) != 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SectionAttributes {
|
||||
/// NG bit
|
||||
non_global: bool,
|
||||
@ -123,17 +205,16 @@ pub struct SectionAttributes {
|
||||
shareable: bool,
|
||||
/// AP bits
|
||||
access: AccessPermissions,
|
||||
/// Type EXtension bits. See Zynq 7000 TRM
|
||||
type_extensions: u8,
|
||||
memory_attrs: MemoryRegionAttributesRaw,
|
||||
domain: u8,
|
||||
/// xN bit.
|
||||
execute_never: bool,
|
||||
/// C bit
|
||||
cacheable: bool,
|
||||
/// B bit
|
||||
bufferable: bool,
|
||||
}
|
||||
|
||||
/// 1 MB section translation entry, mapping a 1 MB region to a physical address.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct L1Section(pub u32);
|
||||
|
||||
impl L1Section {
|
||||
/// The physical base address. The uppermost 12 bits define which 1 MB of virtual address
|
||||
/// space are being accessed. They will be stored in the L1 section table. This address
|
||||
@ -148,194 +229,114 @@ impl L1Section {
|
||||
| ((section_attrs.non_global as u32) << 17)
|
||||
| ((section_attrs.shareable as u32) << 16)
|
||||
| ((section_attrs.access.apx() as u32) << 15)
|
||||
| ((section_attrs.type_extensions as u32) << 12)
|
||||
| ((section_attrs.memory_attrs.type_extensions as u32) << 12)
|
||||
| ((section_attrs.access.ap() as u32) << 10)
|
||||
| ((section_attrs.p_bit as u32) << 9)
|
||||
| ((section_attrs.domain as u32) << 5)
|
||||
| ((section_attrs.execute_never as u32) << 4)
|
||||
| ((section_attrs.cacheable as u32) << 3)
|
||||
| ((section_attrs.bufferable as u32) << 2)
|
||||
| ((section_attrs.memory_attrs.c as u32) << 3)
|
||||
| ((section_attrs.memory_attrs.b as u32) << 2)
|
||||
| L1EntryType::Section as u32;
|
||||
L1Section(raw)
|
||||
}
|
||||
}
|
||||
|
||||
const SECTION_ATTRS_DDR: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_DDR: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
type_extensions: 0b101,
|
||||
// Manager domain
|
||||
domain: 0b1111,
|
||||
execute_never: false,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
memory_attrs: MemoryRegionAttributes::CacheableMemory {
|
||||
inner: CacheableMemoryAttribute::WriteBackWriteAlloc,
|
||||
outer: CacheableMemoryAttribute::WriteBackWriteAlloc,
|
||||
}
|
||||
.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_FPGA_SLAVES: SectionAttributes = SectionAttributes {
|
||||
|
||||
pub const SECTION_ATTRS_FPGA_SLAVES: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
// Strongly ordered
|
||||
type_extensions: 0b000,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_SHAREABLE_DEVICE: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_SHAREABLE_DEVICE: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
type_extensions: 0b000,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
memory_attrs: MemoryRegionAttributes::ShareableDevice.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_SRAM: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_SRAM: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
type_extensions: 0b000,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteBackNoWriteAlloc.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_QSPI_XIP: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_QSPI_XIP: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
type_extensions: 0b000,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: true,
|
||||
bufferable: false,
|
||||
memory_attrs: MemoryRegionAttributes::OuterAndInnerWriteThroughNoWriteAlloc.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_OCM_MAPPED_HIGH: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_OCM_MAPPED_HIGH: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
type_extensions: 0b100,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
memory_attrs: MemoryRegionAttributes::CacheableMemory {
|
||||
inner: CacheableMemoryAttribute::WriteThroughNoWriteAlloc,
|
||||
outer: CacheableMemoryAttribute::NonCacheable,
|
||||
}
|
||||
.as_raw(),
|
||||
};
|
||||
const SECTION_ATTRS_UNASSIGNED_RESERVED: SectionAttributes = SectionAttributes {
|
||||
pub const SECTION_ATTRS_UNASSIGNED_RESERVED: SectionAttributes = SectionAttributes {
|
||||
non_global: false,
|
||||
p_bit: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
type_extensions: 0b000,
|
||||
domain: 0b0000,
|
||||
execute_never: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
memory_attrs: MemoryRegionAttributes::StronglyOrdered.as_raw(),
|
||||
};
|
||||
|
||||
const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096;
|
||||
pub const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096;
|
||||
|
||||
#[repr(C, align(16384))]
|
||||
pub struct L1Table([u32; NUM_L1_PAGE_TABLE_ENTRIES]);
|
||||
pub struct L1Table(pub(crate) [u32; NUM_L1_PAGE_TABLE_ENTRIES]);
|
||||
|
||||
/// MMU Level 1 Page table.
|
||||
/// Load the MMU translation table base address into the MMU.
|
||||
///
|
||||
/// 4096 entries, each covering 1MB
|
||||
/// # Safety
|
||||
///
|
||||
static mut MMU_L1_PAGE_TABLE: L1Table = L1Table([0; NUM_L1_PAGE_TABLE_ENTRIES]);
|
||||
|
||||
/// This function is unsafe because it directly writes to the MMU related registers. It has to be
|
||||
/// called once in the boot code before enabling the MMU, and it should be called while the MMU is
|
||||
/// disabled.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn init_mmu_table() {
|
||||
let mut offset = 0;
|
||||
let mut addr = 0;
|
||||
unsafe extern "C" fn load_mmu_table() {
|
||||
let table_base = &MMU_L1_PAGE_TABLE.0 as *const _ as u32;
|
||||
|
||||
unsafe {
|
||||
// The first entry (1 MB) is related to special DDR memory. See p.101 of the TMR.
|
||||
// We set is separtely to accomodate for future changes.
|
||||
MMU_L1_PAGE_TABLE.0[0] = L1Section::new(addr, SECTION_ATTRS_DDR).0;
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_DDR_FULL_ACCESSIBLE] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_DDR).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_DDR_FULL_ACCESSIBLE;
|
||||
|
||||
// 2 FPGA slaves.
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_FPGA_SLAVE * 2] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_FPGA_SLAVES).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += 2 * SEGMENTS_FPGA_SLAVE;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_UNASSIGNED_0] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_UNASSIGNED_RESERVED).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_UNASSIGNED_0;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_IO_PERIPHS] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_SHAREABLE_DEVICE).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_IO_PERIPHS;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_NAND] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_SHAREABLE_DEVICE).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_NAND;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_NOR] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_SHAREABLE_DEVICE).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_NOR;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_SRAM] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_SRAM).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_SRAM;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_UNASSIGNED_1] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_UNASSIGNED_RESERVED).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_UNASSIGNED_1;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_AMBA_APB] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_SHAREABLE_DEVICE).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_AMBA_APB;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_UNASSIGNED_2] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_UNASSIGNED_RESERVED).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_UNASSIGNED_2;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_QSPI_XIP] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_QSPI_XIP).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_QSPI_XIP;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_UNASSIGNED_3] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_UNASSIGNED_RESERVED).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
offset += SEGMENTS_UNASSIGNED_3;
|
||||
|
||||
for entry in &mut MMU_L1_PAGE_TABLE.0[offset..offset + SEGMENTS_OCM_MAPPED_HIGH] {
|
||||
*entry = L1Section::new(addr, SECTION_ATTRS_OCM_MAPPED_HIGH).0;
|
||||
addr += ONE_MB as u32;
|
||||
}
|
||||
core::arch::asm!(
|
||||
"orr {0}, {0}, #0x5B", // Outer-cacheable, WB
|
||||
"mcr p15, 0, {0}, c2, c0, 0", // Load table pointer
|
||||
inout(reg) table_base => _,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
4120
zynq-rt/src/mmu_table.rs
Normal file
4120
zynq-rt/src/mmu_table.rs
Normal file
File diff suppressed because it is too large
Load Diff
341
zynq-rt/src/rt.rs
Normal file
341
zynq-rt/src/rt.rs
Normal file
@ -0,0 +1,341 @@
|
||||
use cortex_a_rt as _;
|
||||
use cortex_r_a::register::{cpsr::ProcessorMode, Cpsr};
|
||||
|
||||
// Start-up code for Armv7-A
|
||||
//
|
||||
// We set up our stacks and `kmain` in system mode.
|
||||
core::arch::global_asm!(
|
||||
r#"
|
||||
.set PSS_L2CC_BASE_ADDR, 0xF8F02000
|
||||
.set PSS_SLCR_BASE_ADDR, 0xF8000000
|
||||
|
||||
.set RESERVED, 0x0fffff00
|
||||
.set LRemap, 0xFE00000F /* set the base address of the peripheral block as not shared */
|
||||
.set L2CCWay, (PSS_L2CC_BASE_ADDR + 0x077C) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_INVLD_WAY_OFFSET)*/
|
||||
.set L2CCSync, (PSS_L2CC_BASE_ADDR + 0x0730) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CACHE_SYNC_OFFSET)*/
|
||||
.set L2CCCrtl, (PSS_L2CC_BASE_ADDR + 0x0100) /*(PSS_L2CC_BASE_ADDR + PSS_L2CC_CNTRL_OFFSET)*/
|
||||
.set L2CCAuxCrtl, (PSS_L2CC_BASE_ADDR + 0x0104) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_AUX_CNTRL_OFFSET)*/
|
||||
.set L2CCTAGLatReg, (PSS_L2CC_BASE_ADDR + 0x0108) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_TAG_RAM_CNTRL_OFFSET)*/
|
||||
.set L2CCDataLatReg, (PSS_L2CC_BASE_ADDR + 0x010C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_DATA_RAM_CNTRL_OFFSET)*/
|
||||
.set L2CCIntClear, (PSS_L2CC_BASE_ADDR + 0x0220) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_IAR_OFFSET)*/
|
||||
.set L2CCIntRaw, (PSS_L2CC_BASE_ADDR + 0x021C) /*(PSS_L2CC_BASE_ADDR + XPSS_L2CC_ISR_OFFSET)*/
|
||||
|
||||
.set SLCRlockReg, (PSS_SLCR_BASE_ADDR + 0x04) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_LOCK_OFFSET)*/
|
||||
.set SLCRUnlockReg, (PSS_SLCR_BASE_ADDR + 0x08) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_UNLOCK_OFFSET)*/
|
||||
.set SLCRL2cRamReg, (PSS_SLCR_BASE_ADDR + 0xA1C) /*(PSS_SLCR_BASE_ADDR + XPSS_SLCR_L2C_RAM_OFFSET)*/
|
||||
.set SLCRCPURSTReg, (0xF8000000 + 0x244) /*(XPS_SYS_CTRL_BASEADDR + A9_CPU_RST_CTRL_OFFSET)*/
|
||||
.set EFUSEStatus, (0xF800D000 + 0x10) /*(XPS_EFUSE_BASEADDR + EFUSE_STATUS_OFFSET)*/
|
||||
|
||||
.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */
|
||||
.set CRValHiVectorAddr, 0b10000000000000 /* Set the Vector address to high, 0xFFFF0000 */
|
||||
|
||||
.set L2CCAuxControl, 0x72360000 /* Enable all prefetching, Cache replacement policy, Parity enable,
|
||||
Event monitor bus enable and Way Size (64 KB) */
|
||||
.set L2CCControl, 0x01 /* Enable L2CC */
|
||||
.set L2CCTAGLatency, 0x0111 /* latency for TAG RAM */
|
||||
.set L2CCDataLatency, 0x0121 /* latency for DATA RAM */
|
||||
|
||||
.set SLCRlockKey, 0x767B /* SLCR lock key */
|
||||
.set SLCRUnlockKey, 0xDF0D /* SLCR unlock key */
|
||||
.set SLCRL2cRamConfig, 0x00020202 /* SLCR L2C ram configuration */
|
||||
|
||||
.set FPEXC_EN, 0x40000000 /* FPU enable bit, (1 << 30) */
|
||||
|
||||
.section .text.startup
|
||||
.align 0
|
||||
|
||||
.global _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
/* only allow cpu0 through */
|
||||
/* Read MPIDR */
|
||||
mrc p15,0,r1,c0,c0,5
|
||||
/* Extract CPU ID bits. For single-core systems, this should always be 0 */
|
||||
and r1, r1, #0x3
|
||||
cmp r1, #0
|
||||
beq check_efuse
|
||||
b initialize
|
||||
|
||||
// Zynq specific code. It is recommended to restet CPU1 according to page 160 of the datasheet
|
||||
check_efuse:
|
||||
ldr r0,=EFUSEStatus
|
||||
ldr r1,[r0] /* Read eFuse setting */
|
||||
ands r1,r1,#0x80 /* Check whether device is having single core */
|
||||
beq initialize
|
||||
|
||||
/* single core device, reset cpu1 */
|
||||
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
|
||||
ldr r1,=SLCRUnlockKey /* set unlock key */
|
||||
str r1, [r0] /* Unlock SLCR */
|
||||
|
||||
ldr r0,=SLCRCPURSTReg
|
||||
ldr r1,[r0] /* Read CPU Software Reset Control register */
|
||||
orr r1,r1,#0x22
|
||||
str r1,[r0] /* Reset CPU1 */
|
||||
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
initialize:
|
||||
mrc p15, 0, r0, c0, c0, 0 /* Get the revision */
|
||||
and r5, r0, #0x00f00000
|
||||
and r6, r0, #0x0000000f
|
||||
orr r6, r6, r5, lsr #20-4
|
||||
|
||||
/* set VBAR to the _vector_table address in linker script */
|
||||
ldr r0, =_vector_table
|
||||
mcr p15, 0, r0, c12, c0, 0
|
||||
|
||||
/* Invalidate scu */
|
||||
ldr r7, =0xf8f0000c
|
||||
ldr r6, =0xffff
|
||||
str r6, [r7]
|
||||
|
||||
/* Invalidate caches and TLBs */
|
||||
mov r0,#0 /* r0 = 0 */
|
||||
mcr p15, 0, r0, c8, c7, 0 /* invalidate TLBs */
|
||||
mcr p15, 0, r0, c7, c5, 0 /* invalidate icache */
|
||||
mcr p15, 0, r0, c7, c5, 6 /* Invalidate branch predictor array */
|
||||
bl invalidate_dcache /* invalidate dcache */
|
||||
|
||||
/* Disable MMU, if enabled */
|
||||
mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */
|
||||
bic r0, r0, #0x1 /* clear bit 0 */
|
||||
mcr p15, 0, r0, c1, c0, 0 /* write value back */
|
||||
|
||||
/* Set up stacks first, might be required for MMU loader function */
|
||||
|
||||
// Set stack pointer (as the top) and mask interrupts for for FIQ mode (Mode 0x11)
|
||||
ldr r0, =_stack_top
|
||||
msr cpsr, {fiq_mode}
|
||||
mov sp, r0
|
||||
ldr r1, =_fiq_stack_size
|
||||
sub r0, r0, r1
|
||||
// Set stack pointer (right after) and mask interrupts for for IRQ mode (Mode 0x12)
|
||||
msr cpsr, {irq_mode}
|
||||
mov sp, r0
|
||||
ldr r1, =_irq_stack_size
|
||||
sub r0, r0, r1
|
||||
// Set stack pointer (right after) and mask interrupts for for SVC mode (Mode 0x13)
|
||||
msr cpsr, {svc_mode}
|
||||
mov sp, r0
|
||||
ldr r1, =_svc_stack_size
|
||||
sub r0, r0, r1
|
||||
// Set stack pointer (right after) and mask interrupts for for System mode (Mode 0x1F)
|
||||
msr cpsr, {sys_mode}
|
||||
mov sp, r0
|
||||
// Clear the Thumb Exception bit because we're in Arm mode
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
bic r0, #{te_bit}
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
/* Zero BSS and initialize data before calling any function which might require them. */
|
||||
|
||||
// Initialise .bss
|
||||
ldr r0, =__sbss
|
||||
ldr r1, =__ebss
|
||||
mov r2, 0
|
||||
0:
|
||||
cmp r1, r0
|
||||
beq 1f
|
||||
stm r0!, {{r2}}
|
||||
b 0b
|
||||
1:
|
||||
// Initialise .data
|
||||
ldr r0, =__sdata
|
||||
ldr r1, =__edata
|
||||
ldr r2, =__sidata
|
||||
0:
|
||||
cmp r1, r0
|
||||
beq 1f
|
||||
ldm r2!, {{r3}}
|
||||
stm r0!, {{r3}}
|
||||
b 0b
|
||||
1:
|
||||
|
||||
/* set scu enable bit in scu */
|
||||
ldr r7, =0xf8f00000
|
||||
ldr r0, [r7]
|
||||
orr r0, r0, #0x1
|
||||
str r0, [r7]
|
||||
|
||||
/* enable MMU and cache */
|
||||
bl load_mmu_table
|
||||
|
||||
mvn r0,#0 /* Load MMU domains -- all ones=manager */
|
||||
mcr p15,0,r0,c3,c0,0
|
||||
|
||||
/* Enable mmu, icahce and dcache */
|
||||
ldr r0,=CRValMmuCac
|
||||
mcr p15,0,r0,c1,c0,0 /* Enable cache and MMU */
|
||||
dsb /* dsb allow the MMU to start up */
|
||||
isb /* isb flush prefetch buffer */
|
||||
|
||||
/* Write to ACTLR */
|
||||
mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
|
||||
orr r0, r0, #(0x01 << 6) /* set SMP bit */
|
||||
orr r0, r0, #(0x01 ) /* Cache/TLB maintenance broadcast */
|
||||
mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
|
||||
|
||||
/* Invalidate L2 Cache and enable L2 Cache*/
|
||||
/* For AMP, assume running on CPU1. Don't initialize L2 Cache (up to Linux) */
|
||||
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
|
||||
mov r1, #0 /* force the disable bit */
|
||||
str r1, [r0] /* disable the L2 Caches */
|
||||
|
||||
ldr r0,=L2CCAuxCrtl /* Load L2CC base address base + Aux control register */
|
||||
ldr r1,[r0] /* read the register */
|
||||
ldr r2,=L2CCAuxControl /* set the default bits */
|
||||
orr r1,r1,r2
|
||||
str r1, [r0] /* store the Aux Control Register */
|
||||
|
||||
ldr r0,=L2CCTAGLatReg /* Load L2CC base address base + TAG Latency address */
|
||||
ldr r1,=L2CCTAGLatency /* set the latencies for the TAG*/
|
||||
str r1, [r0] /* store the TAG Latency register Register */
|
||||
|
||||
ldr r0,=L2CCDataLatReg /* Load L2CC base address base + Data Latency address */
|
||||
ldr r1,=L2CCDataLatency /* set the latencies for the Data*/
|
||||
str r1, [r0] /* store the Data Latency register Register */
|
||||
|
||||
ldr r0,=L2CCWay /* Load L2CC base address base + way register*/
|
||||
ldr r2, =0xFFFF
|
||||
str r2, [r0] /* force invalidate */
|
||||
|
||||
ldr r0,=L2CCSync /* need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET */
|
||||
/* Load L2CC base address base + sync register*/
|
||||
/* poll for completion */
|
||||
Sync:
|
||||
ldr r1, [r0]
|
||||
cmp r1, #0
|
||||
bne Sync
|
||||
|
||||
ldr r0,=L2CCIntRaw /* clear pending interrupts */
|
||||
ldr r1,[r0]
|
||||
ldr r0,=L2CCIntClear
|
||||
str r1,[r0]
|
||||
|
||||
ldr r0,=SLCRUnlockReg /* Load SLCR base address base + unlock register */
|
||||
ldr r1,=SLCRUnlockKey /* set unlock key */
|
||||
str r1, [r0] /* Unlock SLCR */
|
||||
|
||||
ldr r0,=SLCRL2cRamReg /* Load SLCR base address base + l2c Ram Control register */
|
||||
ldr r1,=SLCRL2cRamConfig /* set the configuration value */
|
||||
str r1, [r0] /* store the L2c Ram Control Register */
|
||||
|
||||
ldr r0,=SLCRlockReg /* Load SLCR base address base + lock register */
|
||||
ldr r1,=SLCRlockKey /* set lock key */
|
||||
str r1, [r0] /* lock SLCR */
|
||||
|
||||
ldr r0,=L2CCCrtl /* Load L2CC base address base + control register */
|
||||
ldr r1,[r0] /* read the register */
|
||||
mov r2, #L2CCControl /* set the enable bit */
|
||||
orr r1,r1,r2
|
||||
str r1, [r0] /* enable the L2 Caches */
|
||||
|
||||
mov r0, r0
|
||||
mrc p15, 0, r1, c1, c0, 2 /* read cp access control register (CACR) into r1 */
|
||||
orr r1, r1, #(0xf << 20) /* enable full access for p10 & p11 */
|
||||
mcr p15, 0, r1, c1, c0, 2 /* write back into CACR */
|
||||
|
||||
/* enable vfp */
|
||||
fmrx r1, FPEXC /* read the exception register */
|
||||
orr r1,r1, #FPEXC_EN /* set VFP enable bit, leave the others in orig state */
|
||||
fmxr FPEXC, r1 /* write back the exception register */
|
||||
|
||||
mrc p15,0,r0,c1,c0,0 /* flow prediction enable */
|
||||
orr r0, r0, #(0x01 << 11) /* #0x8000 */
|
||||
mcr p15,0,r0,c1,c0,0
|
||||
|
||||
mrc p15,0,r0,c1,c0,1 /* read Auxiliary Control Register */
|
||||
orr r0, r0, #(0x1 << 2) /* enable Dside prefetch */
|
||||
orr r0, r0, #(0x1 << 1) /* enable L2 Prefetch hint */
|
||||
mcr p15,0,r0,c1,c0,1 /* write Auxiliary Control Register */
|
||||
|
||||
mrs r0, cpsr /* get the current PSR */
|
||||
bic r0, r0, #0x100 /* enable asynchronous abort exception */
|
||||
msr cpsr_xsf, r0
|
||||
|
||||
// Jump to application
|
||||
bl kmain
|
||||
// In case the application returns, loop forever
|
||||
b .
|
||||
.size _start, . - _start
|
||||
|
||||
invalidate_dcache:
|
||||
mrc p15, 1, r0, c0, c0, 1 /* read CLIDR */
|
||||
ands r3, r0, #0x7000000
|
||||
mov r3, r3, lsr #23 /* cache level value (naturally aligned) */
|
||||
beq finished
|
||||
mov r10, #0 /* start with level 0 */
|
||||
loop1:
|
||||
add r2, r10, r10, lsr #1 /* work out 3xcachelevel */
|
||||
mov r1, r0, lsr r2 /* bottom 3 bits are the Cache type for this level */
|
||||
and r1, r1, #7 /* get those 3 bits alone */
|
||||
cmp r1, #2
|
||||
blt skip /* no cache or only instruction cache at this level */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* write the Cache Size selection register */
|
||||
isb /* isb to sync the change to the CacheSizeID reg */
|
||||
mrc p15, 1, r1, c0, c0, 0 /* reads current Cache Size ID register */
|
||||
and r2, r1, #7 /* extract the line length field */
|
||||
add r2, r2, #4 /* add 4 for the line length offset (log2 16 bytes) */
|
||||
ldr r4, =0x3ff
|
||||
ands r4, r4, r1, lsr #3 /* r4 is the max number on the way size (right aligned) */
|
||||
clz r5, r4 /* r5 is the bit position of the way size increment */
|
||||
ldr r7, =0x7fff
|
||||
ands r7, r7, r1, lsr #13 /* r7 is the max number of the index size (right aligned) */
|
||||
loop2:
|
||||
mov r9, r4 /* r9 working copy of the max way size (right aligned) */
|
||||
loop3:
|
||||
orr r11, r10, r9, lsl r5 /* factor in the way number and cache number into r11 */
|
||||
orr r11, r11, r7, lsl r2 /* factor in the index number */
|
||||
mcr p15, 0, r11, c7, c6, 2 /* invalidate by set/way */
|
||||
subs r9, r9, #1 /* decrement the way number */
|
||||
bge loop3
|
||||
subs r7, r7, #1 /* decrement the index */
|
||||
bge loop2
|
||||
skip:
|
||||
add r10, r10, #2 /* increment the cache number */
|
||||
cmp r3, r10
|
||||
bgt loop1
|
||||
|
||||
finished:
|
||||
mov r10, #0 /* switch back to cache level 0 */
|
||||
mcr p15, 2, r10, c0, c0, 0 /* select current cache level in cssr */
|
||||
dsb
|
||||
isb
|
||||
bx lr
|
||||
"#,
|
||||
fiq_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Fiq)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
irq_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Irq)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
svc_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Svc)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
sys_mode = const {
|
||||
Cpsr::new_with_raw_value(0)
|
||||
.with_mode(ProcessorMode::Sys)
|
||||
.with_i(true)
|
||||
.with_f(true)
|
||||
.raw_value()
|
||||
},
|
||||
te_bit = const {
|
||||
cortex_r_a::register::Sctlr::new_with_raw_value(0)
|
||||
.with_te(true)
|
||||
.raw_value()
|
||||
}
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user