From 21d618172b5c840d653a4885afdeb621b88990a8 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 20 Feb 2025 22:55:58 +0100 Subject: [PATCH] add zynq-rt --- .cargo/config.toml | 8 +- Cargo.lock | 85 +++++++++++ Cargo.toml | 5 + link.x => link.x.tmp | 0 memory.x | 5 +- rust-toolchain.toml | 2 + src/main.rs | 12 +- zynq-rt/Cargo.lock | 7 + zynq-rt/Cargo.toml | 7 + zynq-rt/src/lib.rs | 339 +++++++++++++++++++++++++++++++++++++++++++ zynq-rt/src/mmu.rs | 1 + 11 files changed, 463 insertions(+), 8 deletions(-) rename link.x => link.x.tmp (100%) create mode 100644 rust-toolchain.toml create mode 100644 zynq-rt/Cargo.lock create mode 100644 zynq-rt/Cargo.toml create mode 100644 zynq-rt/src/lib.rs create mode 100644 zynq-rt/src/mmu.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 8ad96ae..450ec35 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,12 +2,14 @@ rustflags = [ "-Ctarget-cpu=cortex-a9", "-Ctarget-feature=+vfp3", + "-Ctarget-feature=+neon", "-Clink-arg=-Tlink.x", ] -[build] -target = "armv7a-none-eabihf" - # Tier 3 target, so no pre-compiled artifacts included. [unstable] build-std = ["core", "alloc"] + +[build] +target = "armv7a-none-eabihf" + diff --git a/Cargo.lock b/Cargo.lock index 9e73e66..170edb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,91 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "arbitrary-int" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5" + +[[package]] +name = "arm-targets" +version = "0.1.0" + +[[package]] +name = "bitbybit" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d317eeca82e7d88d606419a430590d83552bdceb899cb29904f63d694344b7fc" +dependencies = [ + "arbitrary-int", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cortex-r-a" +version = "0.1.0" +dependencies = [ + "arbitrary-int", + "arm-targets", + "bitbybit", +] + +[[package]] +name = "cortex-r-a-rt" +version = "0.1.0" +dependencies = [ + "arm-targets", + "cortex-r-a", + "semihosting", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "semihosting" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "407ec8d274cd77556e9c2bef886df91eb3447b4059e603d6fb19f85e6452e275" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" + [[package]] name = "zedboard-blinky-rs" version = "0.1.0" +dependencies = [ + "cortex-r-a", + "cortex-r-a-rt", +] diff --git a/Cargo.toml b/Cargo.toml index 124790e..03784bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,11 @@ +[workspace] +members = ["zynq-rt"] + [package] name = "zedboard-blinky-rs" version = "0.1.0" edition = "2021" [dependencies] +cortex-r-a = { path = "../cortex-r-a/cortex-r-a" } +cortex-r-a-rt = { path = "../cortex-r-a/cortex-a-rt", features = ["vfp-dp"] } diff --git a/link.x b/link.x.tmp similarity index 100% rename from link.x rename to link.x.tmp diff --git a/memory.x b/memory.x index f300371..c2400f8 100644 --- a/memory.x +++ b/memory.x @@ -2,8 +2,7 @@ MEMORY { /* Zedboard: 512 MB DDR3. */ - DDR(rx) : ORIGIN = 0x00100000, LENGTH = 512M + CODE(rx) : ORIGIN = 0x00100000, LENGTH = 512M } -_STACK_SIZE = 8M -_HEAP_SIZE = 64M +REGION_ALIAS("DATA", CODE); diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/src/main.rs b/src/main.rs index 7f6ec6f..66c3939 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,19 @@ #![no_main] use core::panic::PanicInfo; +use cortex_r_a::asm::nop; +use cortex_r_a_rt as _; /// Entry point (not called like a normal main function) #[no_mangle] -pub extern "C" fn _start() -> ! { - loop {} +pub extern "C" fn kmain() -> ! { + main(); +} + +pub fn main() -> ! { + loop { + nop(); + } } /// Panic handler diff --git a/zynq-rt/Cargo.lock b/zynq-rt/Cargo.lock new file mode 100644 index 0000000..d536135 --- /dev/null +++ b/zynq-rt/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "zynq-rt" +version = "0.1.0" diff --git a/zynq-rt/Cargo.toml b/zynq-rt/Cargo.toml new file mode 100644 index 0000000..142e484 --- /dev/null +++ b/zynq-rt/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "zynq-rt" +version = "0.1.0" +edition = "2024" + +[dependencies] +cortex-a-rt = { path = "../../cortex-r-a/cortex-a-rt" } diff --git a/zynq-rt/src/lib.rs b/zynq-rt/src/lib.rs new file mode 100644 index 0000000..250261c --- /dev/null +++ b/zynq-rt/src/lib.rs @@ -0,0 +1,339 @@ +#![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 */ +.if SIM_MODE == 1 +.set CRValMmuCac, 0b00000000000000 /* Disable IDC, and MMU */ +.else +.set CRValMmuCac, 0b01000000000101 /* Enable IDC, and MMU */ +.endif + +.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 */ + +.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 */ + +#ifdef SHAREABLE_DDR + /* Mark the entire DDR memory as shareable */ + ldr r3, =0x3ff /* 1024 entries to cover 1G DDR */ + ldr r0, =TblBase /* MMU Table address in memory */ + ldr r2, =0x15de6 /* S=b1 TEX=b101 AP=b11, Domain=b1111, C=b0, B=b1 */ +shareable_loop: + str r2, [r0] /* write the entry to MMU table */ + add r0, r0, #0x4 /* next entry in the table */ + add r2, r2, #0x100000 /* next section */ + subs r3, r3, #1 + bge shareable_loop /* loop till 1G is covered */ +#endif + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the irq stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x12 /* IRQ mode */ + msr cpsr, r2 + ldr r13,=IRQ_stack /* IRQ stack pointer */ + bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ + msr spsr_fsxc,r2 + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the supervisor stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x13 /* supervisor mode */ + msr cpsr, r2 + ldr r13,=SPV_stack /* Supervisor stack pointer */ + bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ + msr spsr_fsxc,r2 + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the Abort stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x17 /* Abort mode */ + msr cpsr, r2 + ldr r13,=Abort_stack /* Abort stack pointer */ + bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ + msr spsr_fsxc,r2 + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the FIQ stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x11 /* FIQ mode */ + msr cpsr, r2 + ldr r13,=FIQ_stack /* FIQ stack pointer */ + bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ + msr spsr_fsxc,r2 + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the Undefine stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x1b /* Undefine mode */ + msr cpsr, r2 + ldr r13,=Undef_stack /* Undefine stack pointer */ + bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ + msr spsr_fsxc,r2 + + mrs r0, cpsr /* get the current PSR */ + mvn r1, #0x1f /* set up the system stack pointer */ + and r2, r1, r0 + orr r2, r2, #0x1F /* SYS mode */ + msr cpsr, r2 + ldr r13,=SYS_stack /* SYS stack pointer */ + + /*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 15, 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; diff --git a/zynq-rt/src/mmu.rs b/zynq-rt/src/mmu.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/zynq-rt/src/mmu.rs @@ -0,0 +1 @@ +