메모리 구역별로 접근 권한을 검사하는 하드웨어(Memory Protection Unit). 주소 변환은 하지 않는다.
동작
CPU가 주소 0x20005000 에 쓰기를 시도
↓
MPU: 이 주소가 속한 구역의 권한은?
↓
읽기 전용 구역이다 → MemManage Fault 발생 → 예외 핸들러로
허용되지 않으면 예외를 발생시키는 것이 전부다. 단순하지만 강력하다.
설정 항목
MPU_Region_InitTypeDef r = {
.Number = 0,
.BaseAddress = 0x20000000,
.Size = MPU_REGION_SIZE_64KB,
.AccessPermission = MPU_REGION_FULL_ACCESS,
.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE, // XN
.IsCacheable = 1,
.IsBufferable = 1,
.IsShareable = 0,
};
| 속성 | 뜻 |
|---|---|
| 접근 권한 | 특권/비특권 각각 없음·읽기전용·읽기쓰기 |
| XN (eXecute Never) | 코드 실행 금지 |
| Cacheable | 캐시 사용 여부 ★ |
| Bufferable | 쓰기 버퍼 사용 여부 |
| Shareable | 다중 마스터 공유 |
★ Cacheable 설정이 실무에서 특히 중요하다 — DMA 버퍼 영역을 non-cacheable로 만들어 캐시 일관성 문제를 원천 제거하는 데 쓴다.
제약 — MMU보다 훨씬 단순하다
-
구역 개수: 보통 8개 또는 16개 — ← 하드웨어 레지스터 수만큼 크기: 32바이트 이상, 2의 거듭제곱
-
정렬: 시작 주소가 크기의 배수여야 한다 — ← 이것이 까다롭다 겹침: 허용. 번호가 큰 구역이 우선
정렬 제약 때문에 링커 스크립트와 함께 설계해야 한다. "64KB 구역을 만들려면 시작 주소가 64KB의 배수" 여야 한다.
임베디드에서의 활용 — 네 가지
① 스택 오버플로 검출 (가장 유용)
- 스택 바로 아래에 접근 금지 구역(가드)을 둔다
- 스택이 넘치는 순간 MemManage Fault
- 조용히 데이터가 깨지는 대신 즉시 잡힌다
스택 오버플로는 임베디드 최악의 버그다. 넘친 스택이 전역 변수를 덮어써 전혀 상관없는 곳에서 이상 동작하기 때문이다. MPU 가드가 있으면 넘치는 순간 잡혀 원인이 명확해진다.
RTOS에서는 태스크별 스택에 가드를 둘 수 있다.
② NULL 포인터 역참조 검출
- 0x00000000 ~ 0x000000FF 를 접근 금지로 설정
- NULL 포인터 접근 시 즉시 폴트
이것을 안 하면 주소 0에 있는 벡터 테이블 값을 읽어 엉뚱한 값으로 계속 동작한다. 플래시가 0번지에 매핑된 경우 특히 위험하다.
③ 코드 영역 쓰기 금지 / 데이터 영역 실행 금지
- .text — → 읽기 + 실행, 쓰기 금지
- .data — → 읽기 + 쓰기, 실행 금지 (XN) 버퍼 오버플로로 스택에 심어진 코드가 실행되는 것을 막는다. 보안 인증(IEC 62443 등)에서 요구되기도 한다.
④ DMA 버퍼 non-cacheable 설정
Cortex-M7에서 캐시 관리 실수를 없애는 가장 확실한 방법이다.
RTOS와 함께 — 태스크 격리
FreeRTOS-MPU, Zephyr 의 사용자 모드 스레드
- 각 태스크가 자기 스택과 허용된 데이터만 접근 가능
- 한 태스크의 버그가 다른 태스크를 오염시키지 못한다
태스크 전환 시 MPU 설정도 바꿔야 하므로 컨텍스트 스위칭 비용이 조금 는다. 안전이 중요한 의료·자동차 기기에서 쓴다.
왜 항상 켜지 않나
- ① 설정이 번거롭다 (구역 수 제한, 정렬 제약)
- ② 잘못 설정하면 정상 동작이 폴트로 막힌다
- ③ 개발 중에는 오히려 방해가 될 수 있다
실무 절충 — 개발 단계에서는 ①②(스택 가드, NULL 검출)만 켜서 버그를 조기에 잡고, 양산 펌웨어에서 필요에 따라 확장한다.
폴트가 났을 때
void MemManage_Handler(void) {
uint32_t cfsr = SCB->CFSR; // Configurable Fault Status
uint32_t addr = SCB->MMFAR; // 어느 주소에서 났나
// MMARVALID 비트가 1이면 MMFAR 값이 유효
}
MMFAR에 위반한 주소가 들어 있어 원인 파악이 빠르다. HardFault보다 훨씬 친절한 정보를 준다.