Interrupt Handlers의 관리와 양육
I’m happy to translate the article for you, but I don’t have the full text of the post available. Could you please paste the content you’d like translated (excluding any code blocks or URLs you want to keep unchanged)? Once I have the text, I’ll provide a Korean translation while preserving the original formatting and the source link at the top.
Source: (source link remains unchanged)
Dear diary
오늘 나는 내 초기 운영 체제에 목소리를 주기로 결심했다. 문자 그대로는 아니지만—그건 무섭겠지만—실시간으로 자신의 존재에 대해 불평할 수 있는 인터랙티브 쉘을 만들겠다는 뜻이다. 순수한 오후 프로젝트로 시작했지만, 하드웨어와 나는 치료사라면 “신뢰 문제” 라고 부를 만한 또 다른 상황에 직면하게 되었다.
계획은 충분히 합리적으로 보였다: 시스템 하드웨어를 살펴볼 수 있는 간단한 명령 프롬프트를 만드는 것. 예를 들어 “PCI 장치는 뭐가 있지?” 혹은 “내 메모리는 어디로 갔지?” 같은 기본적인 진단 도구다. 이런 도구가 바로 제대로 된 OS 커널과 사실상 비싼 화면 보호기 사이를 구분한다.
나는 이미 화면에 픽셀을 그리는 거대한 과업을 정복했으며—지금까지 가장 자랑스러운 성과—키보드 입력을 추가하는 것이 그리 어렵지 않을 것이라고 생각했다. UEFI 사양에는 이런 작업을 위한 멋진 추상화가 제공된다. ConIn에서 읽고, 문자를 에코하고, 몇 가지 특수 키를 처리하면 된다. 얼마나 어려울 수 있겠는가?
Narrator: 그는 예상했던 만큼 어려웠고, 그 때문에 상황은 더욱 악화되었다.
쉘 구현은 기대에 차 시작되었다. 나는 키보드 이벤트를 기다리고, 출력 가능한 문자를 에코하며, 백스페이스를 처리하는 깔끔한 입력 루프를 만들었다. 이 루프는 CS 교수님들을 눈물 흘리게 할 정도로 신중한 버퍼 관리를 수행한다. 명령 파서는 공백을 기준으로 입력을 분리하고, 각 핸들러 함수에 전달한다. 깔끔하고, 단순하며, 유지 보수가 쉬운 코드다.
첫 번째로 구현한 명령은 **help**였는데, 나는 근본적으로 독창적이지 않기 때문이다. 그 다음은 clear—텍스트가 사라지는 모습을 보는 것이 존재론적으로 불편하기 때문이다. 그리고 **reboot**와 halt—때때로 창조물이 거대한 망상을 품게 될 때 탈출구가 필요하기 때문이다.
하지만 진짜 핵심은 하드웨어 검사였다. 나는 내 OS가 새 집주인처럼 지하실에 뭐가 있는지 조사하길 원했다. 이는 PCI 버스 스캔을 구현하는 것을 의미했으며, 이는 모든 캐비닛과 서랍을 열어 안을 확인하는 디지털 버전과 같다.
PCI 스캔은 인상적이지만 사실상 체계적인 무차별 탐색이다. 가능한 모든 버스, 디바이스, 함수 조합을 순회하면서 I/O 포트 0xCF8와 0xCFC에 접근해 응답이 있는지 확인한다. 거의 텅 빈 대형 아파트 건물의 문을 두드리는 것과 비슷하지만, 일부 거주자는 화가 난 그래픽 카드일 수도 있다.
PCI의 아름다움은 완전히 표준화되어 있다는 점이다. 모든 장치는 벤더 ID, 디바이스 ID, 클래스 코드를 통해 자신을 알린다. 나는 Intel 칩셋, NVIDIA 그래픽, Realtek 네트워크 컨트롤러 등 알려진 하드웨어의 작은 데이터베이스를 구축했으며, 이를 통해 OS가 새로운 디지털 이웃의 주민들을 인식할 수 있게 했다.
Aorus X3 노트북에서 이를 테스트한 결과는 마치 파티에서 두 명의 어색한 사람을 소개시켜 주는 듯했다. 커널이 정중히 PCI 장치 목록을 요청했고, 하드웨어는 마치 마더보드 위 모든 칩의 포괄적인 이력서처럼 응답했다:
Intel Haswell DRAM controller at 00:00.0
HD Graphics 4600 at 00:02.0
SATA controller at 00:1F.2
— 실리콘 시민들의 완전한 인구 조사다.
Memory‑map inspection
내가 복잡함을 즐기는 것 같아, 메모리 맵 검사를 추가로 구현했다. UEFI는 GetMemoryMap 함수를 친절히 제공하는데, 이 함수는 시스템 RAM이 어떻게 나뉘어 있는지 정확히 알려준다. 여기서는 일반 메모리, 저기엔 부팅 서비스, 저쪽엔 런타임 서비스, 그리고 의심스러울 정도로 큰 “Reserved” 영역이 표시되어 중요한 무언가를 숨기고 있을 가능성이 있다.
메모리 표시를 보면 현대 컴퓨팅의 냉혹한 현실이 드러난다: 몇 기가바이트의 RAM 중 이미 OS가 첫 번째 베이스에 도달하기 전에 상당량이 사용 중이다. 부팅 서비스 코드, ACPI 테이블, MMIO 영역—마치 집을 사서 이전 소유자가 모든 가구에 “이동 금지” 라는 메모를 붙여 놓은 것을 발견한 듯한 상황이다.
”*
Build output
전체를 마침내 빌드했을 때, 그 출력은 개발자만의 독특한 방식으로 만족스러웠다:
[CC] src/lib/shell.c
[CC] src/lib/pci.c
[LD] deploy/BOOTX64.EFI
Build complete. Output: deploy/BOOTX64.EFI (27,648 bytes)
From 21KB to 27KB. My kernel was growing up, developing personality. Or at least the ability to introspect about its own existential crisis.
Source:
First boot
진짜 하드웨어에서 USB 드라이브를 부팅했을 때가 바로 결정적인 순간이었다. 익숙한 ChronOS 배너가 나타났고, 콘솔이 정상적으로 초기화된 뒤… 명령 프롬프트가 뜨고 깜박이는 커서가 입력을 기다렸다.
help 를 입력하고 숨을 죽였다.
명령 목록이 즉시 표시되었다. 크래시도, 트리플 폴트도, 알 수 없는 재부팅도 없었다. 마치 정상적인 운영 체제가 보여줄 법한 깔끔한 명령 목록만 있었다. x86 하드웨어와 성공적으로 상호작용했을 때 느끼는 특유의 안도감과 믿을 수 없다는 감정이 동시에 들었다.
pci command
pci 명령이 진짜 시험이었다. Enter 를 누르자 커널이 PCI 주소 공간의 모든 문을 차례로 두드리는 소리가 들릴 정도였다. 잠시 뒤 깔끔한 표가 나타났다:
| Bus:Dev.Fn | Vendor:Device | Class | Description |
|---|---|---|---|
| 00:00.0 | 8086:0C00 | 06:00 | Intel Haswell DRAM |
| 00:02.0 | 8086:0416 | 03:00 | Intel HD Graphics 4600 |
| 00:1F.2 | 8086:8C03 | 01:06 | Intel 8 Series SATA (AHCI) |
내 OS가 실제로 하드웨어와 대화하고 의미 있는 응답을 받아냈다. 통합 그래픽, SATA 컨트롤러, 심지어 무선 어댑터까지 알 수 있었는데, 마치 복도에서 어색하게 고개만 끄덕였던 사람과 드디어 제대로 대화를 나누는 느낌이었다.
mem command
mem 명령은 시스템 메모리의 가혹한 현실을 드러냈다:
| Type | Start | Pages | Size |
|---|---|---|---|
| Conventional | 00100000 | 156 238 | 629 MB |
| BootServicesData | 26F64000 | 8 | 32 KB |
| Reserved | FED00000 | 1 024 | 4 MB |
수십 기가바이트 중 629 MB 정도만 “Conventional” 으로 표시되어 OS가 자유롭게 사용할 수 있었다. 나머지는 예약, 런타임 서비스, 하드웨어 매핑 등 복잡한 얽힘으로 이루어져 있었다.
일기 끝.
새 아파트를 발견하면 17가지 서로 다른 HOA 비용이 따라온다.
로그 시스템은 모든 내용을 USB 드라이브에 UTF‑16 형식으로 충실히 기록했다. 나중에 BOOTLOG_002.txt 를 디코딩했을 때, 쉘과 하드웨어 사이의 전체 대화를 확인할 수 있었는데, 이는 마치 인류가 외계 문명과 첫 접촉을 기록한 전사와도 같았다. 다만 외계인은 PCI 장치였고, 그들이 주로 얘기하고 싶어 하는 것은 벤더 ID였다.
가장 인상 깊었던 점은 모든 것이 정상적으로 동작했을 때 느껴지는 일상의 편안함이었다. 쉘은 명령을 받아들이고, 올바르게 파싱하며, 적절한 함수를 실행하고 결과를 표시했다—즉 “예정대로 작동한다”는 정의 그 자체였다. 드라마도, 새벽 2시의 긴급 디버깅 세션도, 알 수 없는 크래시도 없었다.
이것이 아마도 OS 개발에서 가장 이상한 부분일 것이다: 평범한 것이 실제로 동작할 때 느끼는 깊은 만족감. 나는 하드웨어 환경을 검사할 수 있는 인터랙티브 쉘을 만들었다. 혁신적이라고는 할 수 없지만—1970년대 이후 모든 운영 체제가 이 기능을 가지고 있었지만—내 OS도 그것을 수행했고, 그 자체만으로도 매우 독점적인 클럽에 가입한 느낌이었다.
- PCI 스캐너가 마더보드에 있는 모든 장치를 찾아냈다.
- 메모리 매퍼가 UEFI의 메모리 레이아웃을 정확히 해석했다.
- 명령 파서는 엣지 케이스를 우아하게 처리했다.
모든 세심한 버퍼 관리와 입력 검증이 지루하지만 신뢰할 수 있는 기능으로 결실을 맺었다.
halt 를 입력해 세션을 종료하고, OS가 로그 파일을 정중히 저장하고 CPU를 끄는 모습을 보면서, 나는 이 괴짜 같은 프로젝트에서 또 다른 작은 문턱을 넘었다는 생각이 들었다. 이제 내 커널은 대화를 할 수 있다—비록 주로 하드웨어 사양과 메모리 주소에 관한 이야기일지라도.
다음 과제는 실제 저장이다. SATA 컨트롤러가 00:1F.2 에 바로 자리 잡고 AHCI 기능을 이력서처럼 내세우고 있다. 이제 내 OS가 실제 데이터를 읽고 쓰도록 가르쳐, 시스템 재부팅이라는 연약한 경계 너머까지 정보를 영구히 보관하게 해야 할 때다.
하지만
그것은 내일의 문제다. 오늘 밤, 나는 작동하는 쉘을 가지고 있고, 2026년에 운영 체제를 만드는 것이 내 정신을 완전히 잃지 않았다는 조심스러운 낙관을 느낀다.
깜빡이는 커서가 기다리고 있다.
osdev #programming #interrupts #lowlevel #bootloader #uefi #memorymanagement #assembly #x86_64 #debugging