๐๐ป ์ด ๋ถ๋ถ์ ๋ฏธ๋OS ํ
์คํธ ๋ชจ๋ ์์ ๋ถ๋ถ์
๋๋ค.
This section marks the beginning of the MiniOS text mode.
๐๐ป 32๋นํธ ๋ณดํธ ๋ชจ๋ ์ง์
๋ฐ C์ธ์ด kernel_maiin()ํจ์๋ก๋ ๊น์ง ์
๋๋ค.
This covers the transition into 32-bit protected mode and the loading of the C-language kernel_main() function.
๐๐ป32๋นํธ ๋ณดํธ ๋ชจ๋์์๋ ๋จ์ 4๊ธฐ๊ฐ๊น์ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
In 32-bit protected mode, up to 4 GB of RAM can be used.
๐boot.asm
โ๏ธ ๋์คํฌ์ฝ๊ธฐ / Disk read
mov ah, 0x02 ; ๋์คํฌ ์ฝ๊ธฐ ๊ธฐ๋ฅ / Disk reading capability
mov al, 12 ; ์ฝ์ด์ฌ ์นํฐ ๊ฐ์(12๊ฐ) / Number of sectors to read (12)
mov ch, 0 ; ์ค๋ฆฐ๋ 0 / Cylinder 0
mov cl, 2 ; ์์ ์นํฐ 2 / Starting sector 2
mov dh, 0 ; ํค๋ 0 / Head 0
mov bx, 0x8000 ; ๋ฉ๋ชจ๋ฆฌ 0x8000์ ๋ก๋ / Loaded into memory 0x8000
int 0x13
1)์ค์ ๋ก ํ๋กํผ ๋์คํฌ๋ฅผ ์ฝ์ด ๋ณด๋ ๋ถ๋ถ์
์ด๋ค.
This is the part where the floppy disk is actually read.
โ๏ธ sector2.asm์ผ๋ก ์ ํํด์ ์ฝ๋ ์คํ
Jump to sector2.asm and execute the code
jmp 0x0000:0x8000
โ๏ธ ๋ถํธ ์๊ทธ๋์ฒ
Boot signature
; 1๋ฒ ์นํฐ(MBR) ๋น ๊ณต๊ฐ์ 0์ผ๋ก ์ฑ์ฐ๊ณ ๋ถํธ ์๊ทธ๋์ฒ ์ถ๊ฐ
; Fill remaining space of sector 1 (MBR) with 0 and add boot signature
times 510 - ($ - $$) db 0
dw 0xaa55
1)์ด ์ฝ๋๊ฐ ์์ผ๋ฉด ๋ถํ ํ ์ ์์ / Without this code, it cannot boot.
๐ sector2.asm
โ๏ธ sector2.asm์ด 0x8000ย ์ด ์ฃผ์์์ ์คํ๋ ์ ์๋ ์ด์ ๋ boot.asm์์ ์ ํํ๊ณ ์ปดํ์ผ์ ๋ง์ปค์ต์
์ ํตํด์ ์ฃผ์๋ฅผ ์ง์ ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
The reason sector2.asm can execute at the address 0x8000 is that the code jumps there from boot.asm, and the address was specified using linker options during compilation.
# 1. boot.asm์ ์ ํ ์ฝ๋ / Jump code in boot.asm
jmp 0x0000:0x8000
# 2.์ปดํ์ผ์ ๋จ์ผ ๋ฐ์ด๋๋ฆฌ๋ก ๊ฒฐํฉ์ ์ต์
์ผ๋ก ์ฃผ์๋ฅผ ์ง์
# Specify addresses as an option when combining into a single binary during compilation.
i686-elf-ld -m elf_i386 -Ttext 0x8000 -e start sector2.o kernel.o -o kernel.bin --oformat binary
1) -e start๋ sector2.asm์ global start ์์น๋ฅผ ์๋ฏธํจ.
-e start refers to the global start location in sector2.asm.
โ๏ธ A20 ๊ฒ์ดํธ ํ์ฑํ (๋ฉ๋ชจ๋ฆฌ 1MB ์ด์ ์ ๊ทผ ํ์ฉ)
A20 gate activation (enables access to memory beyond 1MB)
in al, 0x92
or al, 2
out 0x92, al
1) in al, 0x92 :
๋ง๋๋ณด๋์ ์์คํ
์ ์ด ํฌํธ ์ค ํ๋์ธ 0x92๋ฒ ํฌํธ(System Control Port A)์ ํ์ฌ ํ๋์จ์ด ์ํ ๊ฐ์ ์ฝ์ด์์ al ๋ ์ง์คํฐ์ ์ ์ฅ
Read the current hardware status value of port 0x92 (System Control Port A)โone of the motherboard’s system control portsโand store it in the AL register.
2)or al, 2:
al ๋ ์ง์คํฐ์ ๋ค์ด ์๋ ๊ฐ๊ณผ ์ซ์ 2(์ด์ง์๋ก 00000010)๋ฅผ ๋นํธ OR ์ฐ์ฐ
Perform a bitwise OR operation between the value in the al register and the number 2 (00000010 in binary).
0x92 ํฌํธ์ 2๋ฒ ๋นํธ๊ฐ ๋ฐ๋ก A20 ๊ฒ์ดํธ๋ฅผ ์ผ๊ณ ๋๋ ์ค์์น ์ญํ ์ ํจ.
Bit 2 of port 0x92 acts as a switch for enabling and disabling the A20 gate.
or al, 2๋ฅผ ์ํํ๋ฉด ๊ธฐ์กด์ ์ด๋ค ๊ฐ์ด ๋ค์ด ์์๋ ์๊ด์์ด ๋ค๋ฅธ ๋นํธ๋ ๊ทธ๋๋ก ์ ์งํ ์ฑ 2๋ฒ ๋นํธ๋ง ๋ฌด์กฐ๊ฑด 1(์ฐธ)๋ก ๋ฐ๋๊ฒ ๋จ.
Performing an OR operation with 2 will force the 2nd bit to become 1 (true), regardless of its previous value, while leaving all other bits unchanged.
3)out 0x92, al
2๋ฒ ๋นํธ๊ฐ 1๋ก ์กฐ์๋ al ๋ ์ง์คํฐ์ ๊ฐ์ ๋ค์ 0x92๋ฒ ํฌํธ์ ์ถ๋ ฅ(์ ์ฅ)
Output (store) the value of the AL registerโwith its 2nd bit set to 1โback to port 0x92.
์ด ๋ช
๋ น์ด๊ฐ ์คํ๋๋ ์๊ฐ ๋ง๋๋ณด๋์ ํ๋์จ์ด ํ๋ก๊ฐ ๋ฐ์ํ์ฌ A20 ๋ผ์ธ(์ฃผ์์ )์ด ๊ฐ์ ๋ก ์ด๋ฆฌ๊ฒ ๋จ.
The moment this instruction is executed, the motherboard’s hardware circuitry responds, forcing the A20 line (address line) to open.
โ๏ธ GDT ๋ก๋
Loading the GDT
lgdt [gdt_pointer]
1)lgdt [gdt_pointer] (Load Global Descriptor Table)
๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ๊ท์น๊ณผ ๊ถํ์ ์ ์ํด ๋ GDT(Global Descriptor Table)์ ์์น์ ํฌ๊ธฐ ์ ๋ณด๋ฅผ CPU์๊ฒ ์๋ ค์ฃผ๊ณ ๋ฑ๋กํ๋ ๋ช
๋ น์ด์
๋๋ค.
This is an instruction that informs the CPU of the location and size of the Global Descriptor Table (GDT)โwhich defines memory access rules and permissionsโand registers it.
16๋นํธ ๋ชจ๋์์๋ ๋จ์ํ ์ธ๊ทธ๋จผํธ ร 16 + ์คํ์
๊ณ์ฐ์ผ๋ก ์ค์ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ(RAM)์ ์ง์ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ์ต๋๋ค. ์ด ๋ฐฉ์์ ๋ฉ๋ชจ๋ฆฌ์ ๋ํ ๋ณดํธ์ฒด๊ณ๊ฐ ์๊ณ ์ด์์ฒด์ ์์ญ์ด๋ ์๋ฌด๊ณณ์๋ ๋ฉ๋ชจ๋ฆด ์ฌ์ฉ ํ ์ ์์ด์ ์์คํ
์ด ๋ค์ด๋ ์ ์์ต๋๋ค.
n 16-bit mode, a method was used to access actual physical memory (RAM) directly by simply calculating “segment ร 16 + offset.”
This approach lacks a memory protection mechanism, allowing memory to be accessed anywhereโincluding within the operating system’s own spaceโwhich can cause the system to crash.
32๋นํธ ๋ณดํธ๋ชจ๋์์๋ ์ฒ ์ ํ ๊ท์น๊ณผ ๊ฒ์ฌ์ฒด๊ณ๋ฅผ ๋์
ํจ์ผ๋ก CPU๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉ์ ๋งค๋ฒ ์๊ฒฉํ๊ฒ ๊ฒ์ฌํฉ๋๋ค.
In 32-bit protected mode, a system of rigorous rules and checks is implemented, ensuring that every instance of CPU memory access is strictly verified.
โ๏ธ GDT ํ ์ด๋ธ / GDT Table
; GDT(Global Descriptor Table) ์ ์
; Definition of Global Descriptor Table (GDT)
align 4
gdt_start:
dd 0, 0 ; 1. ๋ ๋์คํฌ๋ฆฝํฐ / Null descriptor
dw 0xFFFF, 0x0000 ; 2. ์ฝ๋ ์ธ๊ทธ๋จผํธ (0x08) / Code segment (0x08)
db 0x00, 0x9A, 0xCF, 0x00
dw 0xFFFF, 0x0000 ; 3. ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ (0x10) / Data Segment (0x10)
db 0x00, 0x92, 0xCF, 0x00
gdt_end:
gdt_pointer:
dw gdt_end - gdt_start - 1
dd gdt_start
1)๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๋ฐฐ์น / Memory address layout
๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ 4๋ก ๋๋์ด ๋จ์ด์ง๋ ์์น์ GDT์ฃผ์ ๋ฐฐ์น(๋ฐ์ดํฐ๋ฅผ ์ฝ์๋ 4๋ฐ์ดํธ ๋จ์๋ก ์ฝ์)
CPU๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ด๊ณ ๋น ๋ฅด๊ฒ ์ฝ๊ฒ ํ๊ธฐ ์ํ ์ฃผ์๋ฐฐ์น
Place the GDT address at a memory location that is a multiple of 4 (since data is read in 4-byte units).
Address arrangement to enable the CPU to read memory efficiently and quickly
align 4
2)๋ ๋์คํฌ๋ฆฝํฐ / Null descriptor
GDT์ ๋งจ ์ฒซ ๋ฒ์งธ ์นธ(์ธ๋ฑ์ค 0๋ฒ)์ ๋ฐ๋์ 0์ผ๋ก ์ฑ์์ง ๋น ์นธ(Null)์ด์ด์ผ ํ๋ค๋ CPU ๊ธฐ์ค
CPU specification requiring the very first entry (index 0) of the GDT to be a null entry (filled with zeros).
dd 0, 0
3)์ฝ๋ ์ธ๊ทธ๋จผํธ (์ด 8๋ฐ์ดํธ) โ ์๋ ๋ ์ค์ด ํฉ์ณ์ ธ์ 1๊ฐ ์ธ๊ทธ๋จผํธ
Code segment (8 bytes total) โ the two lines below combine to form a single segment
— 0xFFFF = 65535 ,์ปดํจํฐ๊ฐ ์คํํ ๋ช
๋ น์ด(์ฝ๋)๊ฐ ๋ด๊ธด ์์ญ์ ๊ท์น์ ์ ์
Define the rules for the area containing the instructions (code) that a computer will execute.
— dw(Define word) 2๋ฐ์ดํธ(16๋นํธ) ํฌ๊ธฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋น
Allocate 2 bytes (16 bits) of data in memory
— db(Define byte) 1๋ฐ์ดํธ(8๋นํธ) ํฌ๊ธฐ์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋น
Allocate 1 byte (8 bits) of data in memory
dw 0xFFFF, 0x0000 ; ์ 4๋ฐ์ดํธ (๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ ๋ฐ ์์ ์ฃผ์ ์ผ๋ถ)
; First 4 bytes (memory size and part of the start address)
db 0x00, 0x9A, 0xCF, 0x00 ; ๋ค 4๋ฐ์ดํธ (๊ถํ ์์ฑ ๋ฐ ๋๋จธ์ง ์ฃผ์)
; Last 4 bytes (permission attributes and remaining address)
4)๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ (์ด 8๋ฐ์ดํธ) โ ์๋ ๋ ์ค์ด ํฉ์ณ์ ธ์ ๋ ๋ค๋ฅธ 1๊ฐ ์ธ๊ทธ๋จผํธ
Data segment (8 bytes total) โ the two lines below combine to form another single segment
— ์ 4๋ฐ์ดํธ๋ ๊ฐ๊ณ ๋ค 4๋ฐ์ดํธ์ค 0x92 ์ด๊ฒ๋ง ๋ค๋ฆ.
The first 4 bytes are the same, and among the last 4 bytes, only the 0x92 value differs.
dw 0xFFFF, 0x0000 ; ์ 4๋ฐ์ดํธ (๋ฉ๋ชจ๋ฆฌ ํฌ๊ธฐ ๋ฐ ์์ ์ฃผ์ ์ผ๋ถ)
; ; First 4 bytes (memory size and part of the start address)
db 0x00, 0x92, 0xCF, 0x00 ; ๋ค 4๋ฐ์ดํธ (๊ถํ ์์ฑ ๋ฐ ๋๋จธ์ง ์ฃผ์)
; Last 4 bytes (permission attributes and remaining address)
๐ก
์ฝ๋ ์ธ๊ทธ๋จผํธ : ๊ธฐ๊ณ์ด ์ฝ๋ ์ ์ฅ๊ตฌ์ญ(์ด์
๋ธ๋ฌ + C์ธ์ด)
Code segment: A storage area for machine code (assembler + C language)
๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ(์คํ ์ธ๊ทธ๋จผํธ) : ๋ณ์์ ์ฅ๊ตฌ์ญ
Data segment (stack segment): Storage area for variables
5)gdt_pointer
— GDTํ
์ด๋ธ์ด ์์นํ๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์์ ์์๊ณผ ๋์ ๊ธฐ๋กํจ.
Records the start and end memory addresses where the GDT table is located.
— dd(Define Doubleword) 4๋ฐ์ดํธ(32๋นํธ) ํฌ๊ธฐ์ ๋ฐ์ดํฐ(์ ์๋ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์)๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ํ ๋น
Allocate 4-byte (32-bit) data (integers or memory addresses) in memory
gdt_pointer:
dw gdt_end - gdt_start - 1
dd gdt_start
1)gdt_end,gdt_start์ ๊ฐ์ ๋ผ๋ฒจ์ ๋ง๋ค๋ฉด ๋ผ๋ฒจ์ ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์์น ๊ฐ์ด ์ ์ฅ๋จ
Creating labels such as gdt_end and gdt_start causes the current memory location value to be stored in those labels.
2)dw gdt_end – gdt_start – 1 ์ด์ ๋ ์ฃผ์๊ฐ 1๋ฒ์ด ์๋ 0๋ฒ ๋ถํฐ ์์ํ๊ธฐ ๋๋ฌธ์ -1์ ํด์ฃผ์ด์ผ ์ ํํ ์ฃผ์ ํ์ธ์ด ๊ฐ๋ฅํจ
The reason for dw gdt_end - gdt_start - 1 is that addresses begin at 0 rather than 1; therefore, subtracting 1 is necessary to obtain the correct address.
# ์ ํํ ์ฃผ์๊ฐ ์๋ / Not an accurate address
(0x8000 + gtd_end) - (gdt_start) = 24
# ์ ํํ ์ฃผ์ / Exact address
(0x8000 + gtd_end) - (gdt_start) - 1 = 23
๐ก
sector2.asm์ ๋ฉ๋ชจ๋ฆฌ์ 0x8000๋ฒ์ง ์
๋๋ค.(๋ง์ปค์์ ์ง์ ํจ.)
sector2.asm is located at memory address 0x8000 (as specified in the linker).
์ด๋ GDTํ
์ด๋ธ์ ์์ ์ฃผ์๋ถํฐ ์ฐจ๋ก๋๋ก ์ซ์ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋กํฉ๋๋ค.
At this point, the GDT table records numerical data into memory, starting from the aforementioned address and proceeding sequentially.
๊ธฐ๋ก์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
The order of the records is as follows.
๋๋์คํฌ๋ฆฝํฐ,์ฝ๋์ธ๊ทธ๋จผํธ,๋ฐ์ดํฐ์ธ๊ทธ๋จผํธ gdt_pointer์ dw,dd๋ถ๋ถ
The `dw` and `dd` components of the `gdt_pointer` for the null descriptor, code segment, and data segment.
โ๏ธ32 ๋นํธ ๋ณดํธ ๋ชจ๋ ์ง์ / Entering 32-bit protected mode
jmp 0x08:protected_start
โ๏ธC์ธ์ด์คํ / Executing C code
— C์ธ์ด ํจ์๋ฅผ ์ด์ ๋ธ๋ฌ๋ก ๊ฐ์ ธ์ค๊ธฐ / Importing C Functions into Assembly
extern kernel_main
— ๋ถ๋ฌ์จ C์ธ์ด ํจ์ ์คํ / Execute the imported C function
call kernel_main
โ๏ธ ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ ์ด๊ธฐํ / Initialization of data segment registers
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
1)GDTํ
์ด๋ธ์ ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋ ์ง์คํฐ ์ด๊ธฐํ 0x10(=16)
Initializing registers to use data segments from the GDT table
2)์ฝ๋ ์ธ๊ทธ๋จผํธ๋ 0x08
The code segment is 0x08
โ๏ธ 32๋นํธ CPU์ ์คํ ํฌ์ธํฐ ๋ ์ง์คํฐ(esp)์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ 0x90000์ ๋์
Assign memory address 0x90000 to the stack pointer register (esp) of a 32-bit CPU
mov esp, 0x90000
1)์์ผ๋ก ํ๋ก๊ทธ๋จ(ํนํ C์ธ์ด ์ปค๋)์ด ์ฌ์ฉํ ์คํ(Stack)์ ์์น๋ฅผ ์ง์
Specifies the location of the stack that the program (especially the C language kernel) will use in the future.
2)์คํ์ ์ฃผ์๋ฅผ 0x90000๋ก ์ง์ ํด์ ์ปค๋ ์ฝ๋๊ฐ ์๋ 0x8000์ ๊ฒน์น์ง ์๊ณ ์ฌ์ฉ๊ฐ๋ฅ
By setting the stack address to 0x90000, it can be used without overlapping with the 0x8000 address where the kernel code resides.
3)C์ธ์ด๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ฐ๋์ ์คํ๊ณต๊ฐ์ ์ค์ ํด์ผํจ
To use the C language, you must configure stack space.
๐kernel.c
โ๏ธ ๋น๋์ค ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ์ง์ / Video Memory Addressing (0xB8000)
volatile char *vram = (volatile char *)0xB8000;
1)VGA ํ
์คํธ ๋ชจ๋ ๋น๋์ค ๋ฉ๋ชจ๋ฆฌ ์ฃผ์
VGA text mode video memory address
0xB8000
2)volatile
์ธ๋ถ ์์ธ(ํ๋์จ์ด ๋ฑ)์ ์ํด ๊ฐ์ด ๋ณํ ์ ์์ผ๋ ๋งค๋ฒ ์ง์ง ๋ฉ๋ชจ๋ฆฌ์ ์ง์ ์ ๊ทผ ํ๋๋กํ๋ ์ต์ ํ ๋ฐฉ์ง ๊ฒฝ๊ณ
A warning to prevent optimization, ensuring that the value is accessed directly from actual memory every time, as it may be altered by external factors (such as hardware).
ํ๋ก๊ทธ๋จ ๋ฐ๊นฅ์ ํ๋์จ์ด์ ์ง์ ์ํตํ๋ ๋ชจ๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ํ์์ ์ผ๋ก ์ฌ์ฉ
Essentially used in all memory spaces that communicate directly with hardware outside the program
โ๏ธ ํ๋ฉด์ ๊ธ์ ์ถ๋ ฅ
Display text on the screen
const char *msg = "Shell Version = 1.0.2!";
int i = 0;
while (msg[i] != '\0') {
vram[i * 2] = msg[i]; // ์ง์ ๋ฐ์ดํธ: ASCII ๋ฌธ์ / Even-numbered bytes: ASCII characters
vram[i * 2 + 1] = 0x0F; // ํ์ ๋ฐ์ดํธ: ํฐ์ ๊ธ์, ๊ฒ์ ๋ฐฐ๊ฒฝ ์์ฑ / Odd-numbered bytes: white text, black background attribute
i++;
}
1)*msg๋ ๋ฌธ์์ด ํฌ์ธํฐ์ด์ง๋ง C์ธ์ด์์ ๋ฐฐ์ด๊ณผ ๋์ผํ๊ฒ ์ฌ์ฉ๊ฐ๋ฅ(๋ด๋ถ์ ์ผ๋ก ๋์ผํ๊ฒ ๋์ํจ)
*Although msg is a string pointer, it can be used in the same way as an array in C (it functions identically under the hood).
2)๋น๋์ค ๋ฉ๋ชจ๋ฆฌ ํ๋์จ์ด ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ์์ ์ง์ ๋ฒ์ง์๋ ๊ธ์,ํ์๋ฒ์ง์๋ ์์ ์์ฑ์ ์ ์ฅํจ.
In the video memory hardware architecture, even-numbered addresses store characters, while odd-numbered addresses store color attributes.
vram[i * 2] = msg[i];
vram[i * 2 + 1] = 0x0F;
3)VGAํ
์คํธ ๋ชจ๋์ ๊ธฐ๋ณธ์ค์ ์ ๊ฒ์ ๋ฐํ์ ํฐ์ ๊ธ์
The default setting for VGA Text Mode is white text on a black background.
๐ ํ ์คํธ / Test
โ๏ธ ์ปดํ์ผ
% rm -f *.bin *.o *.img temp.bin sector2.bin
nasm -f bin boot.asm -o boot.bin
nasm -f elf32 sector2.asm -o sector2.o
i686-elf-gcc -m32 -c kernel.c -o kernel.o -nostdlib -fno-builtin -fno-stack-protector -fno-pic -fno-PIE
i686-elf-ld -m elf_i386 -Ttext 0x8000 -e start -o sector2.bin sector2.o kernel.o --oformat binary
cat boot.bin sector2.bin > temp.bin
dd if=temp.bin of=os.img bs=512 count=2880 conv=sync
qemu-system-x86_64 -drive file=os.img,format=raw,if=floppy -boot a
โ๏ธ ์คํฌ๋ฆฐ ์ท / ScreenShot

๋งํ๋ณต์ 21์ฅ 22์ / Matthew 21: 22
“๋ํฌ๊ฐ ๊ธฐ๋ํ ๋์ ๋ฌด์์ด๋ ์ง ๋ฏฟ๊ณ ๊ตฌํ๋ ๊ฒ์ ๋ค ๋ฐ์ผ๋ฆฌ๋ผ ํ์๋๋ผ”
“And everything you ask in prayer, believing, you will receive.”