Memory protection units (MPU) — preventing stack overflow, access faults
5.5.24· Coding › Embedded Systems & Real-Time Software
Memory Protection Unit kya hai?
MMU (Memory Management Unit) se key differences:
- No virtual memory: MPU sirf physical addresses ke saath kaam karta hai — na page tables, na address translation.
- Simpler, lower latency: hard real-time systems ke liye perfect jahan deterministic fault handling critical hoti hai.
- Typical use: RTOS task stacks ko protect karna, peripheral registers ko isolate karna, runtime par buffer overflows pakadna.
MPU kaise kaam karta hai: Region Configuration
Step 1: Regions Define Karo
MPU memory ko overlapping ya non-overlapping regions mein divide karta hai (ARM Cortex-M par typically 8–16 regions). Har region in chezon ke saath configure hoti hai:
- Base Address (region size ke saath align hona chahiye: = bytes, )
- Size (32 bytes se 4 GB tak, powers of two mein)
- Access Permissions:
APbits: None, RO (read-only), RW (read/write), Execute-Never (XN)- Privilege: sirf privileged mode (kernel) mein accessible, ya user mode (tasks) mein bhi
- Subregion disable (8 subregions per region; holes nikalne ke liye 1/8ths disable kar sakte hain)
Alignment kyun matter karta hai: Hardware low bits mask karke address decode karta hai. Ek 1KB region () address XX...0_0000_0000 par start honi chahiye (low 10 bits zero). Misaligned base → unpredictable behavior.
Step 2: MPU Enable Karo
Regions configure karne ke baad, MPU CTRL register set karo:
ENABLEbit: protection on karo.PRIVDEFENA: agar koi region match na kare, toh privileged access ko background mein allow karo (optional).- Fault par, CPU
MemManage_Handler()(ARM) par vector karta hai jahan tum fault address (MMFARregister) log karte ho aur decide karte ho: task kill karo, log karke continue karo, ya reset karo.
MPU se Stack Overflow Rokna
Problem
Har RTOS task ka RAM mein ek private stack hota hai. Deep recursion, bada local array, ya missing volatile stack pointer ko allocated boundary se aage doosre task ki memory ya heap data mein dhakka de sakta hai → silent corruption, ghanton baad crash.
Solution: Guard Regions
Har stack ke bottom par ek MPU region ko no-access guard band ke roop mein configure karo. Zaroori: har region base uski apni size se aligned honi chahiye. Ek 1 KB region 1 KB boundary par start honi chahiye (low 10 bits zero), ek 32-byte guard 32-byte boundary par start hona chahiye (low 5 bits zero).
// Task A stack layout (ALL bases aligned to region size):
// 0x2000_0000 – 0x2000_0400: Actual stack (1 KB, RW) -> base aligned to 1 KB
// 0x2000_0000 – 0x2000_0020: Guard region (32 bytes, no access) overlaps stack bottom
// The guard is a HIGHER-numbered region so it wins over the stack region.
void setup_task_stackprotection(void) {
// Region 0: Stack (1 KB), base aligned to 0x400
MPU->RBAR = 0x20000000 | REGION_VALID | 0; // low 10 bits = 0 -> aligned to 1 KB
MPU->RASR = (9 << 1) // Size: 2^10 = 1024 bytes
| (3 << 24) // AP = 011 -> RW in privileged+user
| (1 << 28) // XN = 1
| REGION_ENABLE;
// Region 1: Guard (bottom 32 bytes), base aligned to 0x20
// Higher region number -> its "no access" wins over Region 0's RW.
MPU->RBAR = 0x20000000 | REGION_VALID | 1; // low 5 bits = 0 -> aligned to 32 B
MPU->RASR = (4 << 1) // Size: 2^5 = 32 bytes
| (0 << 24) // AP = 000 -> no access
| (1 << 28) // XN = 1 (execute never)
| REGION_ENABLE;
MPU->CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA;
}Yeh kyun kaam karta hai: Stack region (Region 0) poore 1 KB ko cover karta hai, lekin guard region (Region 1) uske bottom 32 bytes ko no access ke saath overlap karta hai. Kyunki sabse zyada numbered matching region jitti hai, bottom 32 bytes protected hain. Agar taskA 0x2000_0000–0x2000_0020 mein neeche overflow kare, toh pehli write hi MemManage fault trigger karti hai. Tum use turant pakad lete ho, task name aur fault address log karte ho, aur handle karte ho (task kill karo, reboot karo, alert karo).
32 bytes kyun? Minimum ARM MPU region size 32 bytes hai (). Bade guards RAM waste karte hain lekin overflows ko pehle pakdte hain.
Access Faults Rokna: Peripherals & Code Ko Isolate Karna
Use Case 1: Peripheral Registers Ko Protect Karo
Peripheral memory (jaise ARM par 0x4000_0000–0x5FFF_FFFF) ko privileged-only banao. User tasks accidentally UART, SPI, ya system clock registers mein write nahi kar sakti.
// Region 2: Peripherals (512 MB), privileged RW only
MPU->RBAR = 0x40000000 | REGION_VALID | 2; // base aligned to 512 MB (0x20000000)
MPU->RASR = (28 << 1) // 2^29 = 512 MB
| (1 << 24) // AP = 001 → RW privileged, no user access
| (1 << 28) // XN
| REGION_ENABLE;User-mode task *UART_TXREG = data; call kare → instant MemManage fault.
Use Case 2: Data Regions Par Execute-Never (XN)
Stack aur heap ko XN (execute-never) mark karo. Agar buffer overflow koi return address ko stack par shellcode se overwrite kare, toh CPU stack bytes execute karne ki koshish par fault karta hai.
// Heap: RW but XN
MPU->RASR = ... | (1 << 28); // XN bit setYeh kyun matter karta hai: Classic code-injection attacks fail ho jaate hain. Chahe koi attacker stack data control kare, woh execution wahan redirect nahi kar sakta.
Common Mistakes & Fixes
Diagram: MPU Region Layout

Har task ke stack ko bottom par ek guard region milta hai (no access). Heap aur peripherals isolate hain. Code read-only + executable hai.
Worked Example: 3 Tasks ke liye MPU Configure Karna
System: ARM Cortex-M4, 128 KB SRAM at 0x2000_0000, 8 MPU regions.
Memory map (dhyan do ki har base uski region size se aligned hai):
- Region 0 (background): 0x2000_0000–0x2002_0000 (128 KB, ), RW privileged (low priority). Base 128 KB se aligned.
- Region 1: Task A stack, 0x2000_0000–0x2000_0400 (1 KB, ), RW user. Base 1 KB se aligned.
- Region 2: Task A stack guard, 0x2000_0000–0x2000_0020 (32 B, ), no access, Region 1 se zyada number toh yeh jeeega.
- Region 3: Task B stack, 0x2000_0800–0x2000_0C00 (1 KB), RW user. Base 0x2000_0800 1 KB se aligned.
- Region 4: Task B stack guard, 0x2000_0800–0x2000_0820 (32 B), no access, Region 3 se zyada number.
- Region 5: Shared heap, 0x2000_1000–0x2001_1000 (64 KB, ), RW user, XN. Base 0x2000_1000 64 KB se aligned.
- Region 6: Peripherals, 0x4000_0000–0x6000_0000 (512 MB, ), RW privileged only. Base 512 MB se aligned.
- Region 7: Flash code, 0x0000_0000–0x0008_0000 (512 KB, ), RO user+privileged, executable. Base aligned.
Code:
void configure_mpu(void) {
MPU->CTRL = 0; // Disable during config
// Region 0: Background (entire SRAM), privileged RW (base aligned to 128 KB)
MPU->RBAR = 0x20000000 | VALID | 0;
MPU->RASR = (16 << 1) | (1 << 24) | ENABLE; // 2^17 = 128 KB, AP=001
// Region 1: Task A stack (1 KB), base aligned to 0x400
MPU->RBAR = 0x20000000 | VALID | 1;
MPU->RASR = (9 << 1) | (3 << 24) | (1 << 28) | ENABLE; // 1 KB, RW user, XN
// Region 2: Task A guard (32 B) — higher number wins over Region 1
MPU->RBAR = 0x20000000 | VALID | 2;
MPU->RASR = (4 << 1) | (0 << 24) | (1 << 28) | ENABLE; // 32 B, no access
// Region 3: Task B stack (1 KB), base aligned to 0x400
MPU->RBAR = 0x20000800 | VALID | 3;
MPU->RASR = (9 << 1) | (3 << 24) | (1 << 28) | ENABLE;
// Region 4: Task B guard (32 B) — higher number wins over Region 3
MPU->RBAR = 0x20000800 | VALID | 4;
MPU->RASR = (4 << 1) | (0 << 24) | (1 << 28) | ENABLE;
// Region 5: Heap (64 KB), base aligned to 0x10000
MPU->RBAR = 0x20001000 | VALID | 5;
MPU->RASR = (15 << 1) | (3 << 24) | (1 << 28) | ENABLE; // 2^16 = 64 KB
// Region 6: Peripherals (512 MB), base aligned to 0x20000000
MPU->RBAR = 0x40000000 | VALID | 6;
MPU->RASR = (28 << 1) | (1 << 24) | (1 << 28) | ENABLE; // 2^29 = 512 MB
// Region 7: Flash (512 KB), RO user+privileged, executable
MPU->RBAR = 0x00000000 | VALID | 7;
MPU->RASR = (18 << 1) | (5 << 24) | (0 << 28) | ENABLE; // 2^19 = 512 KB, AP=101 (RO both), exec OK
MPU->CTRL = MPU_CTRL_ENABLE | MPU_CTRL_PRIVDEFENA;
__DSB(); // Data sync barrier
__ISB(); // Instruction sync barrier (flush pipeline)
}AP encoding par note:
AP = 0b101(5 << 24) matlab privileged aur unprivileged dono ke liye read-only.AP = 0b110(6 << 24) Cortex-M par reserved hai — ise use mat karo.AP = 0b001= RW privileged only;AP = 0b011= RW dono;AP = 0b000= no access.
Barriers kyun? ARM weakly ordered hai. __DSB() ensure karta hai ki MPU register writes enable karne se pehle complete ho jaayein. __ISB() instruction pipeline flush karta hai taaki agla instruction fetch nayi MPU rules ko respect kare.
Testing: Task A mein char overflow[2048]; declare karo aur usme write karo. Program guard region par fault karta hai, MemManage_Handler MMFAR = 0x2000_0010 log karta hai, tum Task A ka naam dekhte ho → turant root cause.
Active Recall Flashcards
#flashcards/coding
MPU aur MMU ke beech key difference kya hai? :: MPU sirf physical addresses ke saath kaam karta hai (no virtual memory, no page tables). MMU virtual addresses ko physical mein translate karta hai. MPU simpler, deterministic, real-time embedded systems ke liye ideal hai.
RTOS mein MPU stack overflow kaise rokta hai?
MPU region base addresses region size ke saath align kyun hone chahiye?
ARM Cortex-M par do MPU regions overlap karen toh kya hota hai?
Privileged aur unprivileged code dono ke liye read-only access kaun sa AP value deta hai, aur kaun si nearby value se bachna chahiye?
AP = 0b101 (5 << 24) = dono ke liye RO. Bachao AP = 0b110 (6 << 24) se, jo Cortex-M par reserved hai.XN (execute-never) bit kis liye use hota hai?
MPU enable karne ke baad __DSB() aur __ISB() kyun call karte hain?
__DSB() (data sync barrier) ensure karta hai ki MPU config writes complete hon. __ISB() (instruction sync barrier) pipeline flush karta hai taaki agla instruction nayi MPU rules respect kare. Inke bina, weakly-ordered ARM core MPU active hone se pehle instructions fetch kar sakta hai.Mnemonic
Feynman Explanation (12 Saal ke Bachche ko Samjhao)
Recall MPU ko aise explain karo jaise main baara saal ka hoon
Socho tumhare computer ki memory ek bada mohalla hai jisme ghar hain (memory addresses). Har program (task) ko rehne ke liye ek ghar milta hai. Rules ke bina, ek buggy program tumhare ghar mein aa sakta hai aur tumhara saman bigaad sakta hai (tumhari memory mein write kar sakta hai).
MPU har gali ke kone par ek security guard ki tarah hai. Tum guard ko batate ho: "Program A sirf ghar #3 mein ja sakta hai, read aur write kar sakta hai. Program B sirf ghar #5 mein ja sakta hai, lekin sirf living room read kar sakta hai." Agar Program A ghar #5 mein ghusne ki koshish kare, toh guard seeti bajata hai (fault interrupt) aur use kuch todne se pehle rok deta hai.
Stack overflow tab hota hai jab kisi program ke kagzon ka dhera (call stack) itna zyada bada ho jaata hai ki woh padosi ke yard mein gir jaata hai. Guard yard ki kinaare par ek tripwire (no-access ke saath guard region) lagata hai. Jis pal ek kagaz line cross karta hai, guard use pakad leta hai. Koi gandagi nahi, koi silent corruption nahi, bas ek clear alarm: "Program A overflow hua!"
Bina guard ke yeh kyun kharab hai? MPU ke bina, Program A, Program B ka ghar tabah kar sakta hai, aur tumhe ghanton baad pata nahi chalega jab Program B apna toota hua furniture use karne ki koshish karega. MPU ke saath, tum mujrim ko rang-e-haath, fauran pakad lete ho.
Connections
- Stack memory layout — stack kaise grow karta hai aur overflow kyun hota hai
- ARM Cortex-M privilege levels — user vs privileged mode, MPU ise kaise enforce karta hai
- RTOS task switching — har task ko isolated memory chahiye; MPU context switch par reconfigure hota hai
- Memory faults and exception handling — MPU fault trigger kare toh kya hota hai
- Memory-mapped IO — peripherals fixed addresses par rehte hain; MPU unhe user code se protect karta hai
- Buffer overflow attacks — MPU (XN bit) code injection mitigate karta hai
- Real-time system determinism — MPU faults deterministic hain (no paging, no TLB miss), hard real-time ke liye critical
Summary
Memory Protection Unit embedded systems ke liye hardware-enforced memory access control hai bina virtual memory ke. Tum address space ko regions mein base, size, aur permissions (RW, RO, no-access, XN, privileged/user) ke saath divide karte ho. MPU har access check karta hai; violations ek fault trigger karte hain bad write complete hone se pehle.
Stack overflow protection: Stack bottom par ek no-access guard region lagao (ek zyada-numbered overlapping region ke roop mein). Overflow writes guard se takraati hain → MMFAR mein fault address ke saath instant fault → tum jaante ho kaun sa task aur exactly kahan.
Access fault prevention: Peripherals ko privileged-only mark karo, data ko XN (execute-never) mark karo, task memory isolate karo. Bugs aur attacks us instruction par pakde jaate hain jo rule violate karta hai, silent corruption ke baad nahi.
Critical details: Base addresses ko region size se align karo (hardware requirement). Overlap par zyada region number jeeeta hai. Sahi AP encoding use karo (0b101 for RO both; reserved 0b110 avoid karo). Config ke baad __DSB aur __ISB use karo. Debug build mein deliberately overflow karke test karo — tumhe fault handler dikhna chahiye, random crash nahi.
MPU "mera system kahin, kabhie crash hua" ko "Task A ne 0x2000_0010 par overflow kiya, yeh raha call stack" mein badal deta hai. Yeh dinon tak debug karne aur minutes mein fix karne ka fark hai.