콘텐츠로 바로가기

Bare-metal Memory Mapping

운영체제 없이 하드웨어 레지스터와 주변 장치를 CPU 주소 공간에 직접 사상하고 제어하는 베어메탈 환경의 물리적 메모리 관리 기법을 다루는 학습 노드입니다.

sys.entry
M

Me

hyunyoun's Blog

posts6 min read

1. Overview

베어메탈 메모리 매핑(Bare-metal Memory Mapping, BMM)은 소프트웨어가 운영체제라는 추상화 막 없이 하드웨어 전선(Bus)과 직접 대화하는 가장 원초적이고 강력한 제어 기술입니다.

현대 CPU는 모든 주변 장치(LED, 센서, 통신 모듈 등)를 가상의 주소 공간에 배치합니다. 학습자는 특정 메모리 주소에 값을 쓰는 행위가 어떻게 실제 하드웨어 핀의 전압을 바꾸는지 **Memory-Mapped I/O (MMIO)**의 물리적 원리를 배웁니다. 또한, 프로그램의 각 섹션(Text, Data, BSS)이 칩 내부의 유한한 RAM/Flash 공간 어디에 안착해야 하는지 결정하는 링커 스크립트(Linker Scripts) 작성법을 익힙니다. 이를 통해 '추상적인 코드'가 '물리적인 전기 신호'로 전환되는 첫 번째 관문을 완벽히 장악합니다.

2. Scope & Boundaries

In-Scope

  • MMIO Physics: 주소 버스(Address Bus)와 장치 선택(Device Select) 로직 사상
  • Register Manipulation: 비트 필드(Bit-fields), 마스킹, 볼라타일(Volatile) 키워드 활용
  • Linker Script Layout: 메모리 영역(MEMORY) 및 섹션(SECTIONS) 정의 물리
  • Boundary Checks: 스택(Stack)과 힙(Heap)의 물리적 충돌 방지 전략

Out-of-Scope

  • OS 수준의 가상 메모리 페이징 및 TLB 관리 (02-02-01 CDL 영역으로 위임)
  • 고급 하드웨어 추상화 계층(HAL) 라이브러리 사용법 (BMM은 Low-level 지향)

Boundaries

  • BMM vs. Virtual Memory: 가상 메모리가 '추상적 주소'를 다룬다면, BMM은 실제 칩 데이터시트에 명시된 '물리적 주소'를 다룹니다.

3. Counterexample

  • 단순히 "C언어로 레지스터를 건드린다"는 설명은 BMM 학습이 아닙니다. 왜 레지스터 변수에 volatile 키워드를 붙이지 않았을 때 컴파일러의 최적화가 하드웨어 제어 신호를 '삭제'해버리는지 물리적 인과관계를 설명할 수 있어야 하며, 링커 스크립트의 섹션 정렬(Alignment)이 하드웨어의 버스 폭(32/64비트)과 일치하지 않을 때 발생하는 Alignment Fault를 데이터시트 기반으로 진단하지 못한다면 베어메탈의 핵심을 놓친 것입니다.

4. Prerequisites

  • Digital Logic & Boolean Algebra (Basic): 비트 연산(AND, OR, XOR) 능력이 필수입니다. (02-01-01 DLB)
  • ALU & Data Path Design (Recommended): CPU 제어 버스와 데이터 버스의 상호작용 이해가 권장됩니다. (02-01-03 ADP)

5. Learning Map

  1. Address Blueprint: 제조사 데이터시트를 보고 하드웨어가 주소 공간 어디에 박혀있는지 파악합니다.
  2. Volatile Protocol: 컴파일러가 내 제어 명령을 가로채지 못하도록 선언 규칙을 세웁니다.
  3. Linker Sculpting: 칩의 물리 RAM 크기에 맞춰 코드와 변수의 자리를 조각합니다.
  4. Hardware Handshake: 메모리에 숫자를 써서 실제 LED를 켜거나 센서를 깨우는 상호작용을 완성합니다.

6. Learning Topics

Basic

Core: MMIO와 주소 디코딩 (Memory-Mapped I/O)

  • Why to Learn: CPU에게 주변 장치는 단지 '특정한 주소의 메모리'로 보이기 때문입니다.
  • What to Learn:
    • MMIO 원리: 주소 버스의 상위 비트를 보고 특정 장치를 활성화하는 물리
    • Peripheral Registers: 상태(Status), 제어(Control), 데이터(Data) 레지스터의 역할
    • 비트 마스킹(Bit Masking): 특정 핀 하나만 제어하기 위한 수리적 연산
  • How to Learn:
    • 가상의 8비트 주소 공간에서 상위 2비트가 10일 때 출력 장치로 연결되는 회로도 분석 실습
    • 데이터시트의 레지스터 맵을 보고 특정 기능을 켜기 위해 어떤 16진수 값을 써야 하는지 암산 연습
  • Implement: 특정 비트를 켜거나(Set) 끄는(Clear) 매크로 함수 세트 작성

Core: C언어의 물리적 선언과 Volatile (Embedded C Semantics)

  • Why to Learn: 소프트웨어의 논리가 하드웨어의 실시간 상태 변화를 무시하지 않게 하기 위함입니다.
  • What to Learn:
    • volatile 키워드: 메모리 접근을 매번 물리적으로 수행하도록 강제하는 하드웨어 친화적 지시어
    • 비트 필드(Bit-fields) 구조체: 레지스터의 세부 비트 단위를 이름으로 접근하는 기법
    • 포인터 타입 캐스팅: 정수형 주소를 하드웨어 제어 구조체로 변환하는 물리적 사상
  • How to Learn:
    • volatile이 있을 때와 없을 때의 생성된 어셈블리 코드를 비교하여 루프 최적화 거동 분석 실습
    • 하드웨어 레지스터와 1<1> 대응되는 struct를 설계하고 메모리 정렬(Padding) 문제 확인
  • Implement: 특정 하드웨어 기기(예: 타이머)의 레지스터 맵을 표현하는 구조체 헤더 파일 설계

Practical

Core: 링커 스크립트와 섹션 배치 (Linker Script Mastery)

  • Why to Learn: 프로그램이 전원이 꺼져도 유지되는 Flash와 실행 중 기록되는 RAM 사이를 올바르게 오가게 하기 위함입니다.
  • What to Learn:
    • MEMORY 명령: 칩의 물리적인 ROM/RAM 경계 확정
    • SECTIONS 명령: .text (코드), .data (초기값 있는 변수), .bss (0으로 초기화할 변수) 배치
    • LMA vs VMA: 데이터가 구워진 주소(Load)와 실행될 때의 주소(Virtual/Runtime)의 차이
  • How to Learn:
    • .data 섹션을 Flash에서 RAM으로 복사(Startup code)하지 않았을 때 전역 변수 수정이 왜 안 되는지 입증 실습
    • Stack과 Heap이 서로를 향해 자라나다 충돌하는 지점을 탐지하는 링커 심볼(_end\_end) 활용법 실습
  • Implement: 코드 크기와 데이터 크기를 계산하여 칩의 용량을 초과하면 오류를 내는 간단한 배치 리포트 도구

Advanced

Core: 부트 스트랩과 런타임 환경 (Zero-stage Bootstrap)

  • Why to Learn: 전원이 들어온 직후 CPU가 main() 함수에 도달하기까지의 물리적 여정을 이해하기 위해서입니다.
  • What to Learn:
    • Reset Vector: 전원 인가 시 CPU가 처음 읽는 물리적 주소의 비밀
    • C-Runtime (CRT) 초기화: 스택 포인터 설정, BSS 영역 0채우기 로직
    • Vector Table: 인터럽트 발생 시 점프할 주소 목록의 하드웨어 사상
  • How to Learn:
    • 어셈블리로 작성된 Startup 코드를 한 줄씩 분석하며 레지스터가 초기화되는 과정 추적 실습
    • 인터럽트 벡터 테이블의 위치를 런타임에 RAM으로 옮기는(Vector Relocation) 물리적 이유 탐구
  • Implement: 최소한의 스택 설정과 BSS 초기화를 수행하고 main으로 점프하는 어셈블리 스타트업 코드

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
MMIO 하드웨어 장치의 레지스터를 메모리 주소 공간에 할당하여 표준 메모리 명령어로 제어하는 기법입니다. 기본 제어 방식 Bus Port-mapped IO '일반 RAM'과 물리적 다름 P1:CS2023/ES core
volatile 컴파일러에게 해당 변수의 값이 외부(하드웨어)에 의해 언제든 변할 수 있음을 알려 최적화를 금지하는 키워드입니다. 추천 최적화 제약 Register Atomic '멀티스레드 동기화'와 혼동 Industry C core
Linker Script 목적 파일들의 섹션을 칩의 실제 물리 메모리 주소에 어떻게 배치할지 명시하는 설계도 파일입니다. 실무 메모리 배치 Section Makefile '소스 코드'가 아닌 빌드 설정 Industry Binutils core
Reset Vector CPU 하드웨어가 리셋 후 가장 먼저 실행할 명령어를 찾기 위해 하드웨어적으로 고정된 물리 주소입니다. 심화 시작점 Bootstrap Entry point main()과 시작점이 다름 P1:CS2023/ES core

8. References

Primary

Secondary

  • [Making Embedded Systems] Elecia White — Practical guide to BMM.
  • [The Definitive Guide to ARM Cortex-M3/M4 Processors] Joseph Yiu — Linker & Startup details.

Industry

  • [STMicroelectronics: RM0090 Reference Manual] — Real-world register maps.
  • [GNU Linker (ld) Documentation - Linker Scripts] — The industry tool standard.

9. Final Checklist

Primary

  • 데이터시트의 특정 주소(예: 0x40021000)에 값을 썼을 때, 왜 이 요청이 RAM으로 가지 않고 통신 장치(UART)로 가는지 물리적 원리를 설명 가능한가? (P1)
  • 링커 스크립트에서 .bss 섹션을 명시적으로 정의하지 않았을 때, 초기화되지 않은 전역 변수가 왜 쓰레기 값을 갖게 되는지 물리적 인과관계를 입증할 수 있는 가? (P1)

Secondary

  • volatile uint32_t *reg 선언에서 volatile이 빠졌을 때, 반복적으로 상태를 확인하는 'Busy-wait' 루프가 왜 무한 루프나 삭제로 이어지는지 어셈블리 수준에서 소통 가능한가?
  • 칩의 SRAM 영역이 0x20000000부터 64KB라면, 스택 포인터(SP)를 최초에 어느 주소로 설정해야 메모리를 최대한 활용할 수 있는지 수리적으로 도출할 수 있는 가?

Industry

  • 신규 하드웨어 보드 브링업(Bring-up) 시, 링커 스크립트의 메모리 맵 오류로 인한 HardFault 발생 시점을 디버거 심볼을 통해 찾아낼 수 있는 가? (SFIA)
  • 펌웨어 보안 요구사항에 따라 실행 코드 영역(.text)을 'Read-Only' 물리 영역으로 강제 배치하는 링커 설정을 제안할 수 있는 가?