๐๐ป ๋ฆฌ๋
์ค๋ฅผ ์ดํดํ๊ธฐ ์ํด์ ๊ฐ๋จํ OS๋ฅผ ๋ง๋๋ ํ๋ก์ ํธ๋ฅผ ์์ํฉ๋๋ค.
To understand Linux, I am starting a project to build a simple operating system.
๐๐ป OS๊ฐ๋ฐ์ ์ํด์ ์ฌ์ฉ๋๋ ์ด์์ฒด์ ๋ ์ฐ๋ถํฌ ๊ณ์ด์ธ Xubuntu๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
Xubuntu, a variant of Ubuntu, was used as the operating system for OS development.
๐๐ป CPU๋ x86 cpu์
๋๋ค.
The CPU is an x86 CPU.
๐๐ป1.ํ์ ๋๊ตฌ ๋ฐ ๊ฐ์ ๋จธ์ ์ค์น
Installing Essential Tools and Virtual Machines
โ๏ธ ํฐ๋ฏธ๋์ ์ด๊ณ ์๋ ๋ช
๋ น์ด๋ฅผ ์
๋ ฅํ์ฌ ์ปดํ์ผ๋ฌ์ ์๋ฎฌ๋ ์ดํฐ๋ฅผ ์ค์นํฉ๋๋ค.
Open the terminal and enter the command below to install the compiler and emulator.
sudo apt update
sudo apt install nasm qemu-system-x86 build-essential gdb
- nasm:
- — ์ด์
๋ธ๋ฆฌ์ด ์ฝ๋๋ฅผ ๊ธฐ๊ณ์ด๋ก ๋ฒ์ญํด ์ฃผ๋ ์ด์
๋ธ๋ฌ์
๋๋ค.
— It is an assembler that translates assembly language code into machine code. - qemu-system-x86:
- — ์ฐ๋ฆฌ๊ฐ ๋ง๋ OS ๋ฐ์ด๋๋ฆฌ๋ฅผ ์์ ํ๊ฒ ์คํํด ๋ณผ ๊ฐ์ ๋จธ์ (์๋ฎฌ๋ ์ดํฐ)์
๋๋ค.
— This is a virtual machine (emulator) where we can safely run the OS binary we created. - build-essential:
- — ๋์ค์ C ์ธ์ด ์ปค๋์ ๋ง๋ค ๋ ํ์ํ
gcc,make๋ฑ์ ์ปดํ์ผ ๋๊ตฌ ๋ชจ์์ ๋๋ค.
— This is a collection of compilation tools, such as gcc and make, that will be needed later when creating a C-language kernel.
๐๐ป2.์ฒซ ๋ฒ์งธ ๋ถํธ๋ก๋ ์ฝ๋ ์์ฑ
Writing the first bootloader code
โ๏ธ ์ํ๋ ๋๋ ํ ๋ฆฌ์ ์์
ํด๋๋ฅผ ๋ง๋ค๊ณ , ํ
์คํธ ์๋ํฐ(Mousepad, VS Code ๋ฑ)๋ก boot.asm ํ์ผ์ ์์ฑํฉ๋๋ค.
Create a working folder in your desired directory and create a boot.asm file using a text editor (such as Mousepad or VS Code).
mkdir ~/miniOS && cd ~/miniOS
nano boot.asm
โ๏ธ ์ด๋ฆฐ ํ์ผ์ ์๋์ 16๋นํธ x86 ๋ถํ
์ฝ๋๋ฅผ ๋ณต์ฌํด์ ๋ถ์ฌ๋ฃ๊ณ ์ ์ฅํฉ๋๋ค.
Copy and paste the 16-bit x86 boot code below into the open file and save it.
; BIOS๊ฐ ์ด ์ฝ๋๋ฅผ ๋ฉ๋ชจ๋ฆฌ 0x7C00์ ๋ก๋ํฉ๋๋ค.
; The BIOS loads this code into memory at 0x7C00.
[org 0x7c00]
; 16๋นํธ ๋ฆฌ์ผ ๋ชจ๋๋ก ์คํํฉ๋๋ค.
; Executes in 16-bit real mode.
bits 16
start:
; BIOS์ 'ํ ๊ธ์ ์ถ๋ ฅ' ๊ธฐ๋ฅ์ ์ ํํฉ๋๋ค.
; Select the BIOS 'print single character' function.
mov ah, 0x0e
; ํ๋ฉด์ ์ฐ์ ๋ฌธ์ 'X'
; Character 'X' to display on the screen
mov al, 'X'
; BIOS ๋น๋์ค ์ธํฐ๋ฝํธ๋ฅผ ํธ์ถํ์ฌ ๋ฌธ์๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
; Calls the BIOS video interrupt to output a character.
int 0x10
; ํ์ฌ ์์น($)์์ ๋ฌดํ ๋ฃจํ๋ฅผ ๋๋ฉฐ ๋๊ธฐํฉ๋๋ค.
; Waits in an infinite loop at the current location ($).
jmp $
; 512๋ฐ์ดํธ ์ค ๋น ๊ณต๊ฐ์ ๋ชจ๋ 0์ผ๋ก ์ฑ์๋๋ค.
; Fill all remaining space within the 512 bytes with zeros.
times 510 - ($ - $$) db 0
; ์ด ๋์คํฌ๊ฐ ๋ถํ
๊ฐ๋ฅํ๋ค๋ ๊ฒ์ ์๋ฆฌ๋ ๊ฐ์ ์ ์ฅ.
; Stores a value indicating that this disk is bootable.
dw 0xaa55
๐๐ป3.๋น๋ ๋ฐ QEMU๋ก ๋ถํ
์คํ
Build and boot using QEMU
โ๏ธ ํฐ๋ฏธ๋์์ ์๋์ ๋ ์ค์ ์คํํ๋ฉด ์ฆ์ OS๊ฐ ๊ฐ์ ๋จธ์ ์์ ๊ตฌ๋๋ฉ๋๋ค.
Running the two lines below in the terminal will immediately launch the OS on the virtual machine.
# 1. ์ด์
๋ธ๋ฆฌ์ด ์ฝ๋๋ฅผ ์์ํ ๋ฐ์ด๋๋ฆฌ ํ์ผ(.bin)๋ก ์ปดํ์ผ
# Compile assembly code into a pure binary file (.bin)
nasm -f bin boot.asm -o boot.bin
# 2. QEMU ์๋ฎฌ๋ ์ดํฐ์ ์ด ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋์คํฌ๋ก ๋ฃ์ด ๊ฐ์ ์ปดํจํฐ ๋ถํ
# Put this binary on a disk and boot the virtual machine in the QEMU emulator
qemu-system-x86_64 -drive format=raw,file=boot.bin
โ๏ธ ์คํํ๋ฉด / Execution Screen

๐๐ป3.์ข ๋ฃํ๊ธฐ / Exit
— ์๋ก ๋ง๋ ์ด์์ฒด์ ๊ฐ ์คํ๋๋ฉด QEMU๊ฐ ๋ง์ฐ์ค ์ ์ด๊ถ์ ๋
์ ํด์ ๋ง์ฐ์ค๊ฐ ์๋ ์๋ ์ ์์ต๋๋ค.(์ ์๋์)
When the newly created operating system runs, QEMU may capture exclusive control of the mouse, causing it to stop working (this is normal behavior).
— ์ด๋ฐ ๊ฒฝ์ฐ ํค๋ณด๋์์ ์๋ํค๋ฅผ ์คํํ๋ฉด ํ๋ก๊ทธ๋จ์ ์ข
๋ฃ ํ ์ ์์ต๋๋ค.
In this case, you can exit the program by pressing the Down arrow key on your keyboard.
Ctrl+Alt+G
๐๐ป ์ฝ๋์ค๋ช / Code Explanation
โ๏ธ [org 0x7c00]
— [org 0x7c00]์์ [ ]์ ์๋ฏธ์ org ๋ป
1)org (Origin)๋ ์์์ ์ด๋ผ๋ ๋ป์ผ๋ก ๋ฉ๋ชจ๋ฆฌ(RAM)์ ๋ฐฐ์น๋ ํ๋ก๊ทธ๋จ์ ์ฃผ์์์น๋ฅผ ์ปดํ์ผ๋ฌ(nasm)์๊ฒ ์๋ ค์ฃผ๋ ์ง์์ด์
๋๋ค.org (Origin) signifies a starting point; it is a directive that informs the compiler (nasm) of the memory address where the program is to be placed.
2)NASM(Netwide Assembler)์์๋[org 0x7c00]๋ฅผ org 0x7c00 ์ด๋ ๊ฒ ์จ๋ ๋ฉ๋๋ค.
In NASM (Netwide Assembler), you can write [org 0x7c00] simply as org 0x7c00.
3)0x7c00๋ ๋ถํ
์ ์ฉ ์ฃผ์์
๋๋ค.1981๋
IBM์ด ์ต์ด์ ๊ฐ์ธ์ฉ ์ปดํจํฐ(IBM PC 5150)๋ฅผ ๋ง๋ค ๋ ๊ฐ๋ฐ์๋ค์ด “๋ถํ
์ ์ฉ ์ฝ๋๋ ๋ฌด์กฐ๊ฑด RAM์ 0x7C00 ์ฃผ์์ ์ฌ๋ ค๋๊ณ ์คํํ์”๊ณ ๊ท์น์ ์ ํ์ต๋๋ค.
0x7c00 is a boot-specific address. When IBM created its first personal computer (the IBM PC 5150) in 1981, developers established a rule to always load and execute boot-specific code at the 0x7C00 address in RAM.
4)BIOS๋ ๋์คํฌ(SSD, HDD, USB ๋ฑ)์ ๋งจ ์ฒซ ๋ฒ์งธ ์นํฐ(512๋ฐ์ดํธ)๋ฅผ ์ฝ์ด์ ๋ฐฉ๊ธ ๋งํ RAM์ 0x7C00 ์ฃผ์๋ก ๋ณต์ฌํฉ๋๋ค.(์ฌ๊ธฐ์๋ QEMU์์ BIOS๋ฅผ ์๋ฏธํฉ๋๋ค.)
The BIOS reads the very first sector (512 bytes) of a disk (such as an SSD, HDD, or USB drive) and copies it to address 0x7C00 in RAM (referring here to the BIOS within QEMU).
โ๏ธ bits 16
— ์ฒ์์๋ ๋ฌด์กฐ๊ฑด 16๋นํธ ๋ชจ๋๋ฅผ ์ฌ์ฉํ๋ฉฐ C์ธ์ด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ bits 32๋ก 32๋นํธ ๋ชจ๋์ ํ์ ํด์ผํฉ๋๋ค.
You start in 16-bit mode by default, and to use C, you must switch to 32-bit mode using the bits 32 directive.
โ๏ธ start:
— ๋ผ๋ฒจ์
๋๋ค. begin:์ด๋ main:๋ฑ์ผ๋ก ๋ค๋ฅธ ์ด๋ฆ์ผ๋ก ์ ํ ์ ์์ต๋๋ค.
This is a label. You can assign it a different name, such as begin: or main:.
— ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ณ ๋ฐ๋ณต,์กฐ๊ฑด,์ ํ๋ฅผ ์ํด์ ์ฌ์ฉ๋ฉ๋๋ค.
It is used when code becomes lengthy and requires loops, conditional statements, and jumps.
โ๏ธ mov ah, 0x0e
— mov ah, 0x0e๋ AH ๋ ์ง์คํฐ์ 0x0e๋ผ๋ ๊ฐ์ ๋ฃ๋(๋์
ํ๋) ๋ช
๋ น์ด์
๋๋ค.mov ah, 0x0e is an instruction that loads (assigns) the value 0x0e into the AH register.
— AH๋ 16๋นํธ CPU์์ ์ฌ์ฉํ๋ AX ๋ ์ง์คํฐ์ ์์ 8๋นํธ ๋ถ๋ถ์ ๋๋ค.
— AX = [AH : AL] (์์ 8๋นํธ AH, ํ์ 8๋นํธ AL) –> 16๋นํธ
AH is the upper 8-bit portion of the AX register used in 16-bit CPUs.
— AH๋ CPU ๋ช
๋ น์ด์ ๋ฐ๋ผ ํน์ ๊ธฐ๋ฅ์ ์ํํ ๋, ๊ธฐ๋ฅ ๋ฒํธ ํน์ ์ํ ๊ฐ์ ์ ์ฅํ๋ ์ฉ๋๋ก ๋ง์ด ์ฐ์
๋๋ค.
AH is frequently used to store function numbers or status values โโwhen performing specific functions based on CPU instructions.
— mov ah, 0x0e(10์ง์๋ก 14๋ฒ)๋ BIOS ๋น๋์ค ์ธํฐ๋ฝํธ์ ๋ฌธ์ ์ถ๋ ฅ ๊ธฐ๋ฅ์ ์ ํํ๋ ์ฝ๋์
๋๋ค.mov ah, 0x0e (decimal 14) is the code that selects the character output function of the BIOS video interrupt.
— ์ฆ, AH = 0x0e๋ BIOS ๋น๋์ค ์๋น์ค ์ค์์ ๋ฌธ์ ์ถ๋ ฅ ๊ธฐ๋ฅ์ ์ง์ ํ๋ ์ฝ๋์
๋๋ค.
In other words, AH = 0x0e is the code that specifies the character output function within the BIOS video services.
— ์ดํ AL ๋ ์ง์คํฐ์ ์ถ๋ ฅํ ๋ฌธ์๋ฅผ ๋ด๊ณ , int 0x10์ ํธ์ถํ๋ฉด ์ปค์ ์์น์ ๊ทธ ๋ฌธ์๊ฐ ํ๋ฉด์ ์ถ๋ ฅ๋ฉ๋๋ค.
Afterward, if you place the character to be displayed into the AL register and call int 0x10, that character is displayed on the screen at the cursor’s position.
โ๏ธ mov al, ‘X’
— AL ๋ ์ง์คํฐ์ ๋ฌธ์ ‘X’๋ฅผ 1๋ฐ์ดํธ ํฌ๊ธฐ๋ก ์ ์ฅํฉ๋๋ค.
Store the character ‘X’ in the AL register as a 1-byte value.
— ‘X’์ ASCII ์ฝ๋(16์ง์ 0x58)๋ฅผ AL์ ์ ์ฅํ์ฌ ์ดํ ๋ช
๋ น์ด์์ ์ด ๊ฐ์ ์ฌ์ฉํ ์ ์๊ฒ ํฉ๋๋ค.
Store the ASCII code for ‘X’ (hexadecimal 0x58) in AL so that this value can be used in subsequent instructions.
โ๏ธ int 0x10
— int์ธํฐ๋ฝํธ๋ฅผ ์๋ฏธํฉ๋๋ค.
It refers to the ‘int’ interrupt.
— ์ปดํจํฐ์์ ์ธํฐ๋ฝํธ๋ ํ๋ก๊ทธ๋จ์ ํ๋ฆ์ ์ ์ ๋ฉ์ถ๊ณ , ํน์ ํ ํ๋์จ์ด๋ ์ํํธ์จ์ด๊ฐ ๋ฏธ๋ฆฌ ์ ํด์ง ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋๋ก ํ๋ ๋ฉ์ปค๋์ฆ์
๋๋ค.
In computing, an interrupt is a mechanism that temporarily pauses the flow of a program, allowing specific hardware or software to perform a predefined task.
— ์ค์ ๋ก ๋น๋์ค ์๋น์ค๋ฅผ ํธ์ถํด์ ์ค์ ๋ก ‘X’๋ผ๋ ๋ฌธ์๋ฅผ ํ๋ฉด์ ํ์ํฉ๋๋ค.
It actually calls the video service and displays the character ‘X’ on the screen.
— ์ธํฐ๋ฝํธ 0x10๋ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ๋ด๋นํฉ๋๋ค.
Interrupt 0x10 handles the following functions.
ํ๋ฉด ๋ชจ๋ ์ค์ (ํ
์คํธ/๊ทธ๋ํฝ ๋ชจ๋ ์ ํ)
Screen Mode Setting (Switching between Text and Graphics Modes)
๋ฌธ์ ๋๋ ๊ทธ๋ํฝ ์ถ๋ ฅ
Text or graphic output
ํ๋ฉด ํด๋ฆฌ์ด, ์ปค์ ์์น ์กฐ์
Clear screen, adjust cursor position
ํฐํธ ์ค์ , ํ๋ ํธ ์กฐ์ ๋ฑ
Font settings, palette adjustments, etc.
โญ๏ธ mov ah, mov al, int ๋ ํ๋์ ๋ก์ง์ผ๋ก ์ดํดํ๋ฉด๋ฉ๋๋ค.
You can understand mov ah, mov al, and int as a single piece of logic.
โ๏ธ jmp $
— $๋ ์ด์
๋ธ๋ฆฌ์ด์์ ํ์ฌ ๋ช
๋ น์ด ์ฃผ์ ๋๋ ํ์ฌ ์์น(์ฃผ์ ๋ ์ด๋ธ)๋ฅผ ๋ํ๋ด๋ ๊ธฐํธ์
๋๋ค.
In assembly language, $ is a symbol representing the current instruction address or the current location (address label).
— jmp $๋ ํ๋ก๊ทธ๋จ์ด ์ข
๋ฃ๋์ง ์๊ณ ํน์ ์์น์์ ๋ฌดํํ ๋จธ๋ฌด๋ฅด๋ฉด์ ๊ธฐ๋ค๋ฆฌ๋๋ก ๋ง๋๋ ์ฉ๋๋ก ์ฐ์
๋๋ค.jmp $ is used to make the program wait by remaining indefinitely at a specific location instead of terminating.
โ๏ธ times 510 – ($ – $$) db 0
— ๊ณ์ฐ๋ ํ์๋งํผ ๋ฐ์ดํธ(db) ๊ณต๊ฐ์ ์ ๋ถ 0์ผ๋ก ์ฑ์ฐ๋ผ๋ ๋ช
๋ น์ด์
๋๋ค.
This command fills the specified number of bytes (db) with zeros.
— 512๋ฐ์ดํธ์์ 510๋ฐ์ดํธ๋ ๋ถํธ๋ก๋ ๋ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ณต๊ฐ์
๋๋ค.
Of the 512 bytes, 510 bytes are used to store the bootloader and data.
— ๋๋จธ์ง ๋ง์ง๋ง 2๋ฐ์ดํธ๋ ๋ถํ
๊ฐ๋ฅ ์ฌ๋ถ๋ฅผ ํ๋ณํ๊ธฐ ์ํ ์๊ทธ๋์ฒ๋ก ์ฌ์ฉ๋๋ฉฐ ๋ณดํต 16์ง์ 0xAA55๊ฐ ๋ค์ด๊ฐ๋๋ค.
The final two bytes serve as a signature to determine bootability and typically contain the hexadecimal value 0xAA55.
— ์ด๊ธฐ IBM PC ํธํ ์ปดํจํฐ์ ํ๋๋์คํฌ ๋ฐ ํ๋กํผ๋์คํฌ ๋๋ผ์ด๋ธ๋ ์นํฐ ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ผ์ต๋๋ค.
Hard disk and floppy disk drives in early IBM PC-compatible computers read and wrote data in sector units.
— $๋ ํ์ฌ ์์น์ ์ฃผ์๋ฅผ ์๋ฏธํฉ๋๋ค.
$ represents the address of the current location.
— $$๋ ์์ ์์น์์ฃผ์๋ฅผ ์๋ฏธํฉ๋๋ค.
$$ refers to the address of the starting position.
— ($ – $$)๋ (ํ์ฌ์์น – ์์์์น์
๋๋ค.)
($ – $$) represents (current position – starting position).
— ๊ฐ๋จํ ์๋ก 10๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค๋ฉด ์๋์ฒ๋ผ ๊ณ์ฐ๋ฉ๋๋ค.
As a simple example, if 10 bytes of data are stored, the calculation is performed as shown below.
0x7C10 โ 0x7C00 = 0x10(10์ง์๋ก 10 / 10 in decimal)
— times N db 0์ N๋งํผ 0 ๋ฐ์ดํธ(๋น ๊ณต๊ฐ)๋ฅผ ์ฑ์ฐ๋ผ๋ ๋ป์
๋๋ค.times N db 0 means to fill N bytes with zeros (empty space).
โ๏ธ dw 0xaa55
— dw๋ “define word”์ ์ฝ์๋ก, 2๋ฐ์ดํธ(16๋นํธ) ๋ฐ์ดํฐ๋ฅผ ์ ์ธํ๊ฑฐ๋ ์ ์ฅํ ๋ ์ฌ์ฉํฉ๋๋ค.dw stands for “define word” and is used to declare or store 2-byte (16-bit) data.
— ๋ถํธ ์นํฐ์ 0xaa55๊ฐ์ ๋ง์ง๋ง์ ๊ธฐ๋กํฉ๋๋ค.
Write the value 0xaa55 to the end of the boot sector.
— ์ด ๊ฐ์ด ์์ด์ผ BIOS๊ฐ ํด๋น ์นํฐ๋ฅผ ๋ถํ
๊ฐ๋ฅํ ๊ฒ์ผ๋ก ์ธ์ํฉ๋๋ค.
The BIOS requires this value to recognize the sector as bootable.