[{"data":1,"prerenderedAt":1425},["ShallowReactive",2],{"page-/blog/embedded/trustzone-m/hello_from_non_secure":3},{"id":4,"title":5,"body":6,"date":1418,"description":17,"extension":1419,"meta":1420,"navigation":186,"path":1421,"seo":1422,"stem":1423,"__hash__":1424},"content/embedded/TrustZone-M/hello_from_non_secure.md","Getting Hello World from the Non-Secure World (Part 1)",{"type":7,"value":8,"toc":1405},"minimark",[9,13,18,23,33,36,40,43,49,66,73,78,86,89,92,110,114,121,143,146,151,166,218,222,229,232,259,343,347,354,357,371,619,623,626,629,647,778,782,1226,1230,1237,1240,1254,1259,1265,1321,1356,1360,1363,1398,1401],[10,11,5],"h1",{"id":12},"getting-hello-world-from-the-non-secure-world-part-1",[14,15,17],"h5",{"id":16},"the-first-switch-to-the-non-secure-world","The First Switch to the Non-Secure World",[19,20,22],"h2",{"id":21},"_1-catch-up","1. Catch up",[24,25,26,27,32],"p",{},"In ",[28,29,31],"a",{"href":30},"qemu_an521_setup","last post",", we created a QEMU-based test environment to test our ARMv8-M code. In this post, we will perform the first switch from the Secure world.",[24,34,35],{},"TrustZone-M chips always default to starting user code in the Secure world. It is our responsibility to configure the memory (text/RAM) regions for the Non-Secure world to use. Since all resources are Secure by default, if we skip the setup process in the Secure world and jump straight to Non-Secure code, the CPU will trigger a Secure Fault or Bus Fault when it attempts to fetch the first instruction.",[19,37,39],{"id":38},"_2-create-a-non-secure-app","2. Create a Non-Secure App.",[24,41,42],{},"Since code executed in the Secure world and Non-Secure world basically acts like two separate programs, our Secure code acts as a secure bootloader to set up the environment and start the Non-Secure code.",[24,44,45,46,48],{},"First, we need to create a Non-Secure project. We can follow the same process as the ",[28,47,31],{"href":30},", but this time we will name the project trustzone_non_secure_helloworld. Most steps will be the same, but we will change the print message to:",[50,51,56],"pre",{"className":52,"code":53,"language":54,"meta":55,"style":55},"language-rust shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","hprintln!(\"Hello from the Non-Secure World!\");\n","rust","",[57,58,59],"code",{"__ignoreMap":55},[60,61,64],"span",{"class":62,"line":63},"line",1,[60,65,53],{},[24,67,68,69,72],{},"We also have to modify the ",[57,70,71],{},"memory.x"," file. We cannot use the same memory space as the Secure world, as this would cause a conflict.",[24,74,75],{},[76,77,71],"strong",{},[50,79,84],{"className":80,"code":82,"language":83},[81],"language-text","MEMORY\n{\n  /* Code stays in SSRAM1 (0x00000000) */\n  FLASH : ORIGIN = 0x00200000, LENGTH = 2M\n  \n  /* Stack/Data moves to SSRAM3 (Non-Secure Address) */\n  /* AN505 SSRAM3 starts at 0x28200000 and is 2MB */\n  RAM   : ORIGIN = 0x28200000, LENGTH = 2M\n}\n","text",[57,85,82],{"__ignoreMap":55},[24,87,88],{},"Notice now we are using a different code reigion. And instead of SSRAM2 we are now using SSRAM3. And both addresses are using the non-Secure address.",[24,90,91],{},"Now we just need to run cargo build to build the binary file.",[50,93,97],{"className":94,"code":95,"language":96,"meta":55,"style":55},"language-shell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","$ file target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld\ntarget/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped\n","shell",[57,98,99,104],{"__ignoreMap":55},[60,100,101],{"class":62,"line":63},[60,102,103],{},"$ file target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld\n",[60,105,107],{"class":62,"line":106},2,[60,108,109],{},"target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped\n",[19,111,113],{"id":112},"_3-the-secure-world-bootloader","3. The Secure World Bootloader",[24,115,116,117,120],{},"Now we need to write the Secure World code (",[57,118,119],{},"main.rs","). This code acts as the system manager. It has three main jobs:",[122,123,124,131,137],"ul",{},[125,126,127,130],"li",{},[76,128,129],{},"Configure the SAU (Security Attribution Unit):"," Tell the CPU core which memory addresses are Non-Secure.",[125,132,133,136],{},[76,134,135],{},"Configure the MPC (Memory Protection Controller):"," Tell the memory bus that specific RAM banks (or halves of them) are Non-Secure.",[125,138,139,142],{},[76,140,141],{},"Jump:"," Switch the CPU state and hand over control.",[24,144,145],{},"Let's break down the implementation function by function.",[147,148,150],"h3",{"id":149},"step-1-imports-and-setup","Step 1: Imports and Setup",[24,152,153,154,157,158,161,162,165],{},"We need a standard ",[57,155,156],{},"no_std"," setup. We use ",[57,159,160],{},"cortex_m"," for hardware access and ",[57,163,164],{},"cortex_m_semihosting"," for debug printing.",[50,167,169],{"className":52,"code":168,"language":54,"meta":55,"style":55},"#![no_std]\n#![no_main]\n\nuse cortex_m::peripheral::sau;\nuse cortex_m_rt::entry;\nuse cortex_m_semihosting::hprintln;\nuse core::arch::asm;\nuse panic_halt as _;\n",[57,170,171,176,181,188,194,200,206,212],{"__ignoreMap":55},[60,172,173],{"class":62,"line":63},[60,174,175],{},"#![no_std]\n",[60,177,178],{"class":62,"line":106},[60,179,180],{},"#![no_main]\n",[60,182,184],{"class":62,"line":183},3,[60,185,187],{"emptyLinePlaceholder":186},true,"\n",[60,189,191],{"class":62,"line":190},4,[60,192,193],{},"use cortex_m::peripheral::sau;\n",[60,195,197],{"class":62,"line":196},5,[60,198,199],{},"use cortex_m_rt::entry;\n",[60,201,203],{"class":62,"line":202},6,[60,204,205],{},"use cortex_m_semihosting::hprintln;\n",[60,207,209],{"class":62,"line":208},7,[60,210,211],{},"use core::arch::asm;\n",[60,213,215],{"class":62,"line":214},8,[60,216,217],{},"use panic_halt as _;\n",[147,219,221],{"id":220},"step-2-configuring-the-sau-cpu-level","Step 2: Configuring the SAU (CPU Level)",[24,223,224,225,228],{},"The ",[76,226,227],{},"SAU (Security Attribution Unit)"," is inside the CPU. It checks every address the CPU tries to access. By default, everything is Secure. We must explicitly mark regions as Non-Secure (NS) so the NS application can run.",[24,230,231],{},"In this function, we define two regions:",[122,233,234,248],{},[125,235,236,239,240,243,244,247],{},[76,237,238],{},"Region 0 (Flash/Code)",": ",[57,241,242],{},"0x0020_0000"," to ",[57,245,246],{},"0x003F_FFFF",".",[125,249,250,239,253,243,256,247],{},[76,251,252],{},"Region 1 (RAM/Data)",[57,254,255],{},"0x2820_0000",[57,257,258],{},"0x283F_FFFF",[50,260,262],{"className":52,"code":261,"language":54,"meta":55,"style":55},"fn configure_sau(sau: &mut cortex_m::peripheral::SAU) {\n    unsafe {\n        sau.ctrl.write(sau::Ctrl(0));\n\n        sau.rnr.write(sau::Rnr(0));\n        sau.rbar.write(sau::Rbar(0x0020_0000));\n        sau.rlar.write(sau::Rlar((0x003F_FFFF & 0xFFFF_FFE0) | 1));\n\n        sau.rnr.write(sau::Rnr(1));\n        sau.rbar.write(sau::Rbar(0x2820_0000));\n        sau.rlar.write(sau::Rlar((0x283F_FFFF & 0xFFFF_FFE0) | 1));\n\n        sau.ctrl.write(sau::Ctrl(1));\n    }\n}\n",[57,263,264,269,274,279,283,288,293,298,302,308,314,320,325,331,337],{"__ignoreMap":55},[60,265,266],{"class":62,"line":63},[60,267,268],{},"fn configure_sau(sau: &mut cortex_m::peripheral::SAU) {\n",[60,270,271],{"class":62,"line":106},[60,272,273],{},"    unsafe {\n",[60,275,276],{"class":62,"line":183},[60,277,278],{},"        sau.ctrl.write(sau::Ctrl(0));\n",[60,280,281],{"class":62,"line":190},[60,282,187],{"emptyLinePlaceholder":186},[60,284,285],{"class":62,"line":196},[60,286,287],{},"        sau.rnr.write(sau::Rnr(0));\n",[60,289,290],{"class":62,"line":202},[60,291,292],{},"        sau.rbar.write(sau::Rbar(0x0020_0000));\n",[60,294,295],{"class":62,"line":208},[60,296,297],{},"        sau.rlar.write(sau::Rlar((0x003F_FFFF & 0xFFFF_FFE0) | 1));\n",[60,299,300],{"class":62,"line":214},[60,301,187],{"emptyLinePlaceholder":186},[60,303,305],{"class":62,"line":304},9,[60,306,307],{},"        sau.rnr.write(sau::Rnr(1));\n",[60,309,311],{"class":62,"line":310},10,[60,312,313],{},"        sau.rbar.write(sau::Rbar(0x2820_0000));\n",[60,315,317],{"class":62,"line":316},11,[60,318,319],{},"        sau.rlar.write(sau::Rlar((0x283F_FFFF & 0xFFFF_FFE0) | 1));\n",[60,321,323],{"class":62,"line":322},12,[60,324,187],{"emptyLinePlaceholder":186},[60,326,328],{"class":62,"line":327},13,[60,329,330],{},"        sau.ctrl.write(sau::Ctrl(1));\n",[60,332,334],{"class":62,"line":333},14,[60,335,336],{},"    }\n",[60,338,340],{"class":62,"line":339},15,[60,341,342],{},"}\n",[147,344,346],{"id":345},"step-3-configuring-the-mpc-bus-level","Step 3: Configuring the MPC (Bus Level)",[24,348,349,350,353],{},"While the SAU lives inside the CPU, the ",[76,351,352],{},"MPC (Memory Protection Controller)"," lives on the bus. It prevents Secure data from leaking even if the CPU allows access.",[24,355,356],{},"We use two different strategies here:",[122,358,359,365],{},[125,360,361,364],{},[76,362,363],{},"Split Strategy (SSRAM0)",": We calculate the midpoint of the memory block. We leave the lower half as Secure (default) and unlock the upper half for Non-Secure use. This is useful for shared memory.",[125,366,367,370],{},[76,368,369],{},"Full Unlock Strategy (SSRAM3)",": We unlock the entire bank because the Non-Secure world needs it for its Stack.",[50,372,374],{"className":52,"code":373,"language":54,"meta":55,"style":55},"fn configure_mpc() {\n    // --- 1. Configure SSRAM0 (Split Region) ---\n    // Physical Base: 0x5800_7000\n    {\n        let base = 0x5800_7000;\n        let ctrl_reg = base as *mut u32;\n        let blk_max  = (base + 0x10) as *mut u32;\n        let blk_idx  = (base + 0x18) as *mut u32;\n        let blk_lut  = (base + 0x1C) as *mut u32;\n\n        unsafe { ctrl_reg.write_volatile(0x110); }\n\n        let max_index = unsafe { blk_max.read_volatile() };\n        let total_indices = max_index + 1;\n        let midpoint = total_indices / 2;\n\n        unsafe { blk_idx.write_volatile(midpoint); }\n\n        for _ in midpoint..total_indices {\n            unsafe { blk_lut.write_volatile(0xFFFF_FFFF); }\n        }\n    }\n\n    // --- 2. Configure SSRAM3 (Full Unlock) ---\n    // Physical Base: 0x5800_9000\n    {\n        let base = 0x5800_9000;\n        let ctrl_reg = base as *mut u32;\n        let blk_max  = (base + 0x10) as *mut u32;\n        let blk_idx  = (base + 0x18) as *mut u32;\n        let blk_lut  = (base + 0x1C) as *mut u32;\n\n        unsafe {\n            ctrl_reg.write_volatile(0x110);\n            blk_idx.write_volatile(0);\n        }\n        \n        let max_idx = unsafe { blk_max.read_volatile() };\n        for _ in 0..=max_idx {\n            unsafe { blk_lut.write_volatile(0xFFFF_FFFF); }\n        }\n    }\n\n    cortex_m::asm::dsb();\n    cortex_m::asm::isb();\n}\n",[57,375,376,381,386,391,396,401,406,411,416,421,425,430,434,439,444,449,454,460,465,471,477,483,488,493,499,505,510,516,521,526,531,536,541,547,553,559,564,570,576,582,587,592,597,602,608,614],{"__ignoreMap":55},[60,377,378],{"class":62,"line":63},[60,379,380],{},"fn configure_mpc() {\n",[60,382,383],{"class":62,"line":106},[60,384,385],{},"    // --- 1. Configure SSRAM0 (Split Region) ---\n",[60,387,388],{"class":62,"line":183},[60,389,390],{},"    // Physical Base: 0x5800_7000\n",[60,392,393],{"class":62,"line":190},[60,394,395],{},"    {\n",[60,397,398],{"class":62,"line":196},[60,399,400],{},"        let base = 0x5800_7000;\n",[60,402,403],{"class":62,"line":202},[60,404,405],{},"        let ctrl_reg = base as *mut u32;\n",[60,407,408],{"class":62,"line":208},[60,409,410],{},"        let blk_max  = (base + 0x10) as *mut u32;\n",[60,412,413],{"class":62,"line":214},[60,414,415],{},"        let blk_idx  = (base + 0x18) as *mut u32;\n",[60,417,418],{"class":62,"line":304},[60,419,420],{},"        let blk_lut  = (base + 0x1C) as *mut u32;\n",[60,422,423],{"class":62,"line":310},[60,424,187],{"emptyLinePlaceholder":186},[60,426,427],{"class":62,"line":316},[60,428,429],{},"        unsafe { ctrl_reg.write_volatile(0x110); }\n",[60,431,432],{"class":62,"line":322},[60,433,187],{"emptyLinePlaceholder":186},[60,435,436],{"class":62,"line":327},[60,437,438],{},"        let max_index = unsafe { blk_max.read_volatile() };\n",[60,440,441],{"class":62,"line":333},[60,442,443],{},"        let total_indices = max_index + 1;\n",[60,445,446],{"class":62,"line":339},[60,447,448],{},"        let midpoint = total_indices / 2;\n",[60,450,452],{"class":62,"line":451},16,[60,453,187],{"emptyLinePlaceholder":186},[60,455,457],{"class":62,"line":456},17,[60,458,459],{},"        unsafe { blk_idx.write_volatile(midpoint); }\n",[60,461,463],{"class":62,"line":462},18,[60,464,187],{"emptyLinePlaceholder":186},[60,466,468],{"class":62,"line":467},19,[60,469,470],{},"        for _ in midpoint..total_indices {\n",[60,472,474],{"class":62,"line":473},20,[60,475,476],{},"            unsafe { blk_lut.write_volatile(0xFFFF_FFFF); }\n",[60,478,480],{"class":62,"line":479},21,[60,481,482],{},"        }\n",[60,484,486],{"class":62,"line":485},22,[60,487,336],{},[60,489,491],{"class":62,"line":490},23,[60,492,187],{"emptyLinePlaceholder":186},[60,494,496],{"class":62,"line":495},24,[60,497,498],{},"    // --- 2. Configure SSRAM3 (Full Unlock) ---\n",[60,500,502],{"class":62,"line":501},25,[60,503,504],{},"    // Physical Base: 0x5800_9000\n",[60,506,508],{"class":62,"line":507},26,[60,509,395],{},[60,511,513],{"class":62,"line":512},27,[60,514,515],{},"        let base = 0x5800_9000;\n",[60,517,519],{"class":62,"line":518},28,[60,520,405],{},[60,522,524],{"class":62,"line":523},29,[60,525,410],{},[60,527,529],{"class":62,"line":528},30,[60,530,415],{},[60,532,534],{"class":62,"line":533},31,[60,535,420],{},[60,537,539],{"class":62,"line":538},32,[60,540,187],{"emptyLinePlaceholder":186},[60,542,544],{"class":62,"line":543},33,[60,545,546],{},"        unsafe {\n",[60,548,550],{"class":62,"line":549},34,[60,551,552],{},"            ctrl_reg.write_volatile(0x110);\n",[60,554,556],{"class":62,"line":555},35,[60,557,558],{},"            blk_idx.write_volatile(0);\n",[60,560,562],{"class":62,"line":561},36,[60,563,482],{},[60,565,567],{"class":62,"line":566},37,[60,568,569],{},"        \n",[60,571,573],{"class":62,"line":572},38,[60,574,575],{},"        let max_idx = unsafe { blk_max.read_volatile() };\n",[60,577,579],{"class":62,"line":578},39,[60,580,581],{},"        for _ in 0..=max_idx {\n",[60,583,585],{"class":62,"line":584},40,[60,586,476],{},[60,588,590],{"class":62,"line":589},41,[60,591,482],{},[60,593,595],{"class":62,"line":594},42,[60,596,336],{},[60,598,600],{"class":62,"line":599},43,[60,601,187],{"emptyLinePlaceholder":186},[60,603,605],{"class":62,"line":604},44,[60,606,607],{},"    cortex_m::asm::dsb();\n",[60,609,611],{"class":62,"line":610},45,[60,612,613],{},"    cortex_m::asm::isb();\n",[60,615,617],{"class":62,"line":616},46,[60,618,342],{},[147,620,622],{"id":621},"step-4-the-jump-main","Step 4: The Jump (Main)",[24,624,625],{},"Finally, we perform the switch. This requires reading the Non-Secure Vector Table to find the correct Stack Pointer and Reset Vector.",[24,627,628],{},"We then use inline assembly to:",[122,630,631,637],{},[125,632,633,636],{},[57,634,635],{},"msr msp_ns",": Set the Non-Secure Main Stack Pointer.",[125,638,639,642,643,646],{},[57,640,641],{},"bxns",": Branch and Exchange to Non-Secure state. The address we jump to must have the Least Significant Bit (LSB) cleared (",[57,644,645],{},"& !1",") to indicate the target state.",[50,648,650],{"className":52,"code":649,"language":54,"meta":55,"style":55},"#[entry]\nfn main() -> ! {\n    hprintln!(\"Secure World: Initializing...\");\n\n    let mut peripherals = cortex_m::Peripherals::take().unwrap();\n    \n    configure_sau(&mut peripherals.SAU);\n    configure_mpc();\n\n    let ns_vector_table_addr: *const u32 = 0x0020_0000 as *const u32;\n\n    hprintln!(\"Secure World: Jumping to Non-Secure...\");\n\n    unsafe {\n        let ns_msp = *ns_vector_table_addr;\n        let ns_reset_vector = *ns_vector_table_addr.add(1);\n\n        asm!(\n            \"msr msp_ns, {ns_msp}\",\n            \"bxns {ns_reset_vector}\",\n            ns_msp = in(reg) ns_msp,\n            ns_reset_vector = in(reg) ns_reset_vector & !1, \n        );\n    }\n    \n    loop {}\n}\n",[57,651,652,657,662,667,671,676,681,686,691,695,700,704,709,713,717,722,727,731,736,741,746,751,756,761,765,769,774],{"__ignoreMap":55},[60,653,654],{"class":62,"line":63},[60,655,656],{},"#[entry]\n",[60,658,659],{"class":62,"line":106},[60,660,661],{},"fn main() -> ! {\n",[60,663,664],{"class":62,"line":183},[60,665,666],{},"    hprintln!(\"Secure World: Initializing...\");\n",[60,668,669],{"class":62,"line":190},[60,670,187],{"emptyLinePlaceholder":186},[60,672,673],{"class":62,"line":196},[60,674,675],{},"    let mut peripherals = cortex_m::Peripherals::take().unwrap();\n",[60,677,678],{"class":62,"line":202},[60,679,680],{},"    \n",[60,682,683],{"class":62,"line":208},[60,684,685],{},"    configure_sau(&mut peripherals.SAU);\n",[60,687,688],{"class":62,"line":214},[60,689,690],{},"    configure_mpc();\n",[60,692,693],{"class":62,"line":304},[60,694,187],{"emptyLinePlaceholder":186},[60,696,697],{"class":62,"line":310},[60,698,699],{},"    let ns_vector_table_addr: *const u32 = 0x0020_0000 as *const u32;\n",[60,701,702],{"class":62,"line":316},[60,703,187],{"emptyLinePlaceholder":186},[60,705,706],{"class":62,"line":322},[60,707,708],{},"    hprintln!(\"Secure World: Jumping to Non-Secure...\");\n",[60,710,711],{"class":62,"line":327},[60,712,187],{"emptyLinePlaceholder":186},[60,714,715],{"class":62,"line":333},[60,716,273],{},[60,718,719],{"class":62,"line":339},[60,720,721],{},"        let ns_msp = *ns_vector_table_addr;\n",[60,723,724],{"class":62,"line":451},[60,725,726],{},"        let ns_reset_vector = *ns_vector_table_addr.add(1);\n",[60,728,729],{"class":62,"line":456},[60,730,187],{"emptyLinePlaceholder":186},[60,732,733],{"class":62,"line":462},[60,734,735],{},"        asm!(\n",[60,737,738],{"class":62,"line":467},[60,739,740],{},"            \"msr msp_ns, {ns_msp}\",\n",[60,742,743],{"class":62,"line":473},[60,744,745],{},"            \"bxns {ns_reset_vector}\",\n",[60,747,748],{"class":62,"line":479},[60,749,750],{},"            ns_msp = in(reg) ns_msp,\n",[60,752,753],{"class":62,"line":485},[60,754,755],{},"            ns_reset_vector = in(reg) ns_reset_vector & !1, \n",[60,757,758],{"class":62,"line":490},[60,759,760],{},"        );\n",[60,762,763],{"class":62,"line":495},[60,764,336],{},[60,766,767],{"class":62,"line":501},[60,768,680],{},[60,770,771],{"class":62,"line":507},[60,772,773],{},"    loop {}\n",[60,775,776],{"class":62,"line":512},[60,777,342],{},[147,779,781],{"id":780},"step-5-full-source-code-mainrs","Step 5: Full Source Code (main.rs)",[50,783,785],{"className":52,"code":784,"language":54,"meta":55,"style":55},"#![no_std]\n#![no_main]\n\nuse cortex_m::peripheral::sau;\nuse cortex_m_rt::entry;\nuse cortex_m_semihosting::hprintln;\nuse core::arch::asm;\nuse panic_halt as _;\n\nfn configure_sau(sau: &mut cortex_m::peripheral::SAU) {\n    unsafe {\n        sau.ctrl.write(sau::Ctrl(0));\n\n        sau.rnr.write(sau::Rnr(0));\n        sau.rbar.write(sau::Rbar(0x0020_0000));\n        sau.rlar.write(sau::Rlar((0x003F_FFFF & 0xFFFF_FFE0) | 1));\n\n        sau.rnr.write(sau::Rnr(1));\n        sau.rbar.write(sau::Rbar(0x2820_0000));\n        sau.rlar.write(sau::Rlar((0x283F_FFFF & 0xFFFF_FFE0) | 1));\n\n        sau.ctrl.write(sau::Ctrl(1));\n    }\n}\n\nfn configure_mpc() {\n    // --- 1. Configure SSRAM0 (Split Region) ---\n    {\n        let base = 0x5800_7000;\n        let ctrl_reg = base as *mut u32;\n        let blk_max  = (base + 0x10) as *mut u32;\n        let blk_idx  = (base + 0x18) as *mut u32;\n        let blk_lut  = (base + 0x1C) as *mut u32;\n\n        unsafe { ctrl_reg.write_volatile(0x110); }\n\n        let max_index = unsafe { blk_max.read_volatile() };\n        let total_indices = max_index + 1;\n        let midpoint = total_indices / 2;\n\n        unsafe { blk_idx.write_volatile(midpoint); }\n\n        for _ in midpoint..total_indices {\n            unsafe { blk_lut.write_volatile(0xFFFF_FFFF); }\n        }\n    }\n\n    // --- 2. Configure SSRAM3 (Full Unlock) ---\n    {\n        let base = 0x5800_9000;\n        let ctrl_reg = base as *mut u32;\n        let blk_max  = (base + 0x10) as *mut u32;\n        let blk_idx  = (base + 0x18) as *mut u32;\n        let blk_lut  = (base + 0x1C) as *mut u32;\n\n        unsafe {\n            ctrl_reg.write_volatile(0x110);\n            blk_idx.write_volatile(0);\n        }\n        \n        let max_idx = unsafe { blk_max.read_volatile() };\n        for _ in 0..=max_idx {\n            unsafe { blk_lut.write_volatile(0xFFFF_FFFF); }\n        }\n    }\n\n    cortex_m::asm::dsb();\n    cortex_m::asm::isb();\n}\n\n#[entry]\nfn main() -> ! {\n    hprintln!(\"Secure World: Initializing...\");\n\n    let mut peripherals = cortex_m::Peripherals::take().unwrap();\n    \n    configure_sau(&mut peripherals.SAU);\n    configure_mpc();\n\n    let ns_vector_table_addr: *const u32 = 0x0020_0000 as *const u32;\n\n    hprintln!(\"Secure World: Jumping to Non-Secure...\");\n\n    unsafe {\n        let ns_msp = *ns_vector_table_addr;\n        let ns_reset_vector = *ns_vector_table_addr.add(1);\n\n        asm!(\n            \"msr msp_ns, {ns_msp}\",\n            \"bxns {ns_reset_vector}\",\n            ns_msp = in(reg) ns_msp,\n            ns_reset_vector = in(reg) ns_reset_vector & !1, \n        );\n    }\n    \n    loop {}\n}\n",[57,786,787,791,795,799,803,807,811,815,819,823,827,831,835,839,843,847,851,855,859,863,867,871,875,879,883,887,891,895,899,903,907,911,915,919,923,927,931,935,939,943,947,951,955,959,963,967,971,976,981,986,991,996,1001,1006,1011,1016,1021,1026,1031,1036,1041,1046,1051,1056,1061,1066,1071,1076,1081,1086,1091,1096,1101,1106,1111,1116,1121,1126,1131,1136,1141,1146,1151,1156,1161,1166,1171,1176,1181,1186,1191,1196,1201,1206,1211,1216,1221],{"__ignoreMap":55},[60,788,789],{"class":62,"line":63},[60,790,175],{},[60,792,793],{"class":62,"line":106},[60,794,180],{},[60,796,797],{"class":62,"line":183},[60,798,187],{"emptyLinePlaceholder":186},[60,800,801],{"class":62,"line":190},[60,802,193],{},[60,804,805],{"class":62,"line":196},[60,806,199],{},[60,808,809],{"class":62,"line":202},[60,810,205],{},[60,812,813],{"class":62,"line":208},[60,814,211],{},[60,816,817],{"class":62,"line":214},[60,818,217],{},[60,820,821],{"class":62,"line":304},[60,822,187],{"emptyLinePlaceholder":186},[60,824,825],{"class":62,"line":310},[60,826,268],{},[60,828,829],{"class":62,"line":316},[60,830,273],{},[60,832,833],{"class":62,"line":322},[60,834,278],{},[60,836,837],{"class":62,"line":327},[60,838,187],{"emptyLinePlaceholder":186},[60,840,841],{"class":62,"line":333},[60,842,287],{},[60,844,845],{"class":62,"line":339},[60,846,292],{},[60,848,849],{"class":62,"line":451},[60,850,297],{},[60,852,853],{"class":62,"line":456},[60,854,187],{"emptyLinePlaceholder":186},[60,856,857],{"class":62,"line":462},[60,858,307],{},[60,860,861],{"class":62,"line":467},[60,862,313],{},[60,864,865],{"class":62,"line":473},[60,866,319],{},[60,868,869],{"class":62,"line":479},[60,870,187],{"emptyLinePlaceholder":186},[60,872,873],{"class":62,"line":485},[60,874,330],{},[60,876,877],{"class":62,"line":490},[60,878,336],{},[60,880,881],{"class":62,"line":495},[60,882,342],{},[60,884,885],{"class":62,"line":501},[60,886,187],{"emptyLinePlaceholder":186},[60,888,889],{"class":62,"line":507},[60,890,380],{},[60,892,893],{"class":62,"line":512},[60,894,385],{},[60,896,897],{"class":62,"line":518},[60,898,395],{},[60,900,901],{"class":62,"line":523},[60,902,400],{},[60,904,905],{"class":62,"line":528},[60,906,405],{},[60,908,909],{"class":62,"line":533},[60,910,410],{},[60,912,913],{"class":62,"line":538},[60,914,415],{},[60,916,917],{"class":62,"line":543},[60,918,420],{},[60,920,921],{"class":62,"line":549},[60,922,187],{"emptyLinePlaceholder":186},[60,924,925],{"class":62,"line":555},[60,926,429],{},[60,928,929],{"class":62,"line":561},[60,930,187],{"emptyLinePlaceholder":186},[60,932,933],{"class":62,"line":566},[60,934,438],{},[60,936,937],{"class":62,"line":572},[60,938,443],{},[60,940,941],{"class":62,"line":578},[60,942,448],{},[60,944,945],{"class":62,"line":584},[60,946,187],{"emptyLinePlaceholder":186},[60,948,949],{"class":62,"line":589},[60,950,459],{},[60,952,953],{"class":62,"line":594},[60,954,187],{"emptyLinePlaceholder":186},[60,956,957],{"class":62,"line":599},[60,958,470],{},[60,960,961],{"class":62,"line":604},[60,962,476],{},[60,964,965],{"class":62,"line":610},[60,966,482],{},[60,968,969],{"class":62,"line":616},[60,970,336],{},[60,972,974],{"class":62,"line":973},47,[60,975,187],{"emptyLinePlaceholder":186},[60,977,979],{"class":62,"line":978},48,[60,980,498],{},[60,982,984],{"class":62,"line":983},49,[60,985,395],{},[60,987,989],{"class":62,"line":988},50,[60,990,515],{},[60,992,994],{"class":62,"line":993},51,[60,995,405],{},[60,997,999],{"class":62,"line":998},52,[60,1000,410],{},[60,1002,1004],{"class":62,"line":1003},53,[60,1005,415],{},[60,1007,1009],{"class":62,"line":1008},54,[60,1010,420],{},[60,1012,1014],{"class":62,"line":1013},55,[60,1015,187],{"emptyLinePlaceholder":186},[60,1017,1019],{"class":62,"line":1018},56,[60,1020,546],{},[60,1022,1024],{"class":62,"line":1023},57,[60,1025,552],{},[60,1027,1029],{"class":62,"line":1028},58,[60,1030,558],{},[60,1032,1034],{"class":62,"line":1033},59,[60,1035,482],{},[60,1037,1039],{"class":62,"line":1038},60,[60,1040,569],{},[60,1042,1044],{"class":62,"line":1043},61,[60,1045,575],{},[60,1047,1049],{"class":62,"line":1048},62,[60,1050,581],{},[60,1052,1054],{"class":62,"line":1053},63,[60,1055,476],{},[60,1057,1059],{"class":62,"line":1058},64,[60,1060,482],{},[60,1062,1064],{"class":62,"line":1063},65,[60,1065,336],{},[60,1067,1069],{"class":62,"line":1068},66,[60,1070,187],{"emptyLinePlaceholder":186},[60,1072,1074],{"class":62,"line":1073},67,[60,1075,607],{},[60,1077,1079],{"class":62,"line":1078},68,[60,1080,613],{},[60,1082,1084],{"class":62,"line":1083},69,[60,1085,342],{},[60,1087,1089],{"class":62,"line":1088},70,[60,1090,187],{"emptyLinePlaceholder":186},[60,1092,1094],{"class":62,"line":1093},71,[60,1095,656],{},[60,1097,1099],{"class":62,"line":1098},72,[60,1100,661],{},[60,1102,1104],{"class":62,"line":1103},73,[60,1105,666],{},[60,1107,1109],{"class":62,"line":1108},74,[60,1110,187],{"emptyLinePlaceholder":186},[60,1112,1114],{"class":62,"line":1113},75,[60,1115,675],{},[60,1117,1119],{"class":62,"line":1118},76,[60,1120,680],{},[60,1122,1124],{"class":62,"line":1123},77,[60,1125,685],{},[60,1127,1129],{"class":62,"line":1128},78,[60,1130,690],{},[60,1132,1134],{"class":62,"line":1133},79,[60,1135,187],{"emptyLinePlaceholder":186},[60,1137,1139],{"class":62,"line":1138},80,[60,1140,699],{},[60,1142,1144],{"class":62,"line":1143},81,[60,1145,187],{"emptyLinePlaceholder":186},[60,1147,1149],{"class":62,"line":1148},82,[60,1150,708],{},[60,1152,1154],{"class":62,"line":1153},83,[60,1155,187],{"emptyLinePlaceholder":186},[60,1157,1159],{"class":62,"line":1158},84,[60,1160,273],{},[60,1162,1164],{"class":62,"line":1163},85,[60,1165,721],{},[60,1167,1169],{"class":62,"line":1168},86,[60,1170,726],{},[60,1172,1174],{"class":62,"line":1173},87,[60,1175,187],{"emptyLinePlaceholder":186},[60,1177,1179],{"class":62,"line":1178},88,[60,1180,735],{},[60,1182,1184],{"class":62,"line":1183},89,[60,1185,740],{},[60,1187,1189],{"class":62,"line":1188},90,[60,1190,745],{},[60,1192,1194],{"class":62,"line":1193},91,[60,1195,750],{},[60,1197,1199],{"class":62,"line":1198},92,[60,1200,755],{},[60,1202,1204],{"class":62,"line":1203},93,[60,1205,760],{},[60,1207,1209],{"class":62,"line":1208},94,[60,1210,336],{},[60,1212,1214],{"class":62,"line":1213},95,[60,1215,680],{},[60,1217,1219],{"class":62,"line":1218},96,[60,1220,773],{},[60,1222,1224],{"class":62,"line":1223},97,[60,1225,342],{},[19,1227,1229],{"id":1228},"_4-configuring-the-runner-cargoconfigtoml","4. Configuring the Runner (.cargo/config.toml)",[24,1231,1232,1233,1236],{},"We have written the Secure bootloader and the Non-Secure application. Now, we need a way to run them together. This is where ",[57,1234,1235],{},".cargo/config.toml"," comes in. It automates the complex QEMU command required to load two separate binaries into memory at once.",[24,1238,1239],{},"For a TrustZone setup, QEMU needs to know two things:",[122,1241,1242,1248],{},[125,1243,1244,1247],{},[76,1245,1246],{},"Where is the Secure code?"," (This is our current project, passed via -kernel).",[125,1249,1250,1253],{},[76,1251,1252],{},"Where is the Non-Secure code?"," (This is the external binary we built in Step 2, passed via -device loader).",[24,1255,1256],{},[76,1257,1258],{},"The Configuration Breakdown",[24,1260,1261,1262,1264],{},"Create or edit ",[57,1263,1235],{}," in your Secure project root:",[50,1266,1270],{"className":1267,"code":1268,"language":1269,"meta":55,"style":55},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","[build]\ntarget = \"thumbv8m.main-none-eabi\" # Cortex-M33 (ARMv8-M Mainline)\n\n[target.thumbv8m.main-none-eabi]\nrunner = \"\"\"qemu-system-arm -machine mps2-an521 -cpu cortex-m33 -nographic -serial mon:stdio -semihosting \\\n -device loader,file=../trustzone_non_secure_helloworld/target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld,addr=0x00200000 \\\n -kernel \"\"\"\nrustflags = [\n  \"-C\", \"link-arg=-Tlink.x\"\n]\n","toml",[57,1271,1272,1277,1282,1286,1291,1296,1301,1306,1311,1316],{"__ignoreMap":55},[60,1273,1274],{"class":62,"line":63},[60,1275,1276],{},"[build]\n",[60,1278,1279],{"class":62,"line":106},[60,1280,1281],{},"target = \"thumbv8m.main-none-eabi\" # Cortex-M33 (ARMv8-M Mainline)\n",[60,1283,1284],{"class":62,"line":183},[60,1285,187],{"emptyLinePlaceholder":186},[60,1287,1288],{"class":62,"line":190},[60,1289,1290],{},"[target.thumbv8m.main-none-eabi]\n",[60,1292,1293],{"class":62,"line":196},[60,1294,1295],{},"runner = \"\"\"qemu-system-arm -machine mps2-an521 -cpu cortex-m33 -nographic -serial mon:stdio -semihosting \\\n",[60,1297,1298],{"class":62,"line":202},[60,1299,1300],{}," -device loader,file=../trustzone_non_secure_helloworld/target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld,addr=0x00200000 \\\n",[60,1302,1303],{"class":62,"line":208},[60,1304,1305],{}," -kernel \"\"\"\n",[60,1307,1308],{"class":62,"line":214},[60,1309,1310],{},"rustflags = [\n",[60,1312,1313],{"class":62,"line":304},[60,1314,1315],{},"  \"-C\", \"link-arg=-Tlink.x\"\n",[60,1317,1318],{"class":62,"line":310},[60,1319,1320],{},"]\n",[122,1322,1323,1342],{},[125,1324,1325,1328,1329,1332,1333],{},[57,1326,1327],{},"-device loader,file=...,addr=0x00200000",": This is the crucial part for TrustZone. It tells QEMU to side-load the Non-Secure binary into memory at address ",[57,1330,1331],{},"0x00200000"," before starting the CPU.",[122,1334,1335],{},[125,1336,1337,1338,1341],{},"Note: The path ",[57,1339,1340],{},"../trustzone_non_secure_helloworld/..."," assumes your Non-Secure project folder is next to your Secure project folder. Adjust if necessary.",[125,1343,1344,1347,1348,1351,1352,1355],{},[57,1345,1346],{},"-kernel",": This is where Cargo inserts the path to the Secure binary (the current project) automatically. This binary is loaded at the default reset address (usually ",[57,1349,1350],{},"0x00000000"," or ",[57,1353,1354],{},"0x10000000",") and the CPU starts executing here.",[19,1357,1359],{"id":1358},"_5-running-the-system","5. Running the System",[24,1361,1362],{},"Now, simply run:",[50,1364,1366],{"className":94,"code":1365,"language":96,"meta":55,"style":55},"$ cargo run\n    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s\n     Running `qemu-system-arm -machine mps2-an521 -cpu cortex-m33 -nographic -serial 'mon:stdio' -semihosting -device loader,file=../trustzone_non_secure_helloworld/target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld,addr=0x00200000 -kernel target/thumbv8m.main-none-eabi/debug/trustzone_helloworld`\nSecure World: Initializing...\nSecure World: Jumping to Non-Secure...\nHello from the Non-Secure World!\n",[57,1367,1368,1373,1378,1383,1388,1393],{"__ignoreMap":55},[60,1369,1370],{"class":62,"line":63},[60,1371,1372],{},"$ cargo run\n",[60,1374,1375],{"class":62,"line":106},[60,1376,1377],{},"    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s\n",[60,1379,1380],{"class":62,"line":183},[60,1381,1382],{},"     Running `qemu-system-arm -machine mps2-an521 -cpu cortex-m33 -nographic -serial 'mon:stdio' -semihosting -device loader,file=../trustzone_non_secure_helloworld/target/thumbv8m.main-none-eabi/debug/trustzone_non_secure_helloworld,addr=0x00200000 -kernel target/thumbv8m.main-none-eabi/debug/trustzone_helloworld`\n",[60,1384,1385],{"class":62,"line":190},[60,1386,1387],{},"Secure World: Initializing...\n",[60,1389,1390],{"class":62,"line":196},[60,1391,1392],{},"Secure World: Jumping to Non-Secure...\n",[60,1394,1395],{"class":62,"line":202},[60,1396,1397],{},"Hello from the Non-Secure World!\n",[24,1399,1400],{},"Congratulations! We have successfully booted a Secure world manager and handed off control to a Non-Secure application.",[1402,1403,1404],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":55,"searchDepth":106,"depth":106,"links":1406},[1407,1408,1409,1416,1417],{"id":21,"depth":106,"text":22},{"id":38,"depth":106,"text":39},{"id":112,"depth":106,"text":113,"children":1410},[1411,1412,1413,1414,1415],{"id":149,"depth":183,"text":150},{"id":220,"depth":183,"text":221},{"id":345,"depth":183,"text":346},{"id":621,"depth":183,"text":622},{"id":780,"depth":183,"text":781},{"id":1228,"depth":106,"text":1229},{"id":1358,"depth":106,"text":1359},"2026-2-8","md",{},"/embedded/trustzone-m/hello_from_non_secure",{"title":5,"description":17},"embedded/TrustZone-M/hello_from_non_secure","WNsoZCUuTw1kXFsp3f4ca2Hy87niU7_xcCjErpUMi2k",1776777282625]