[OS]miniOS-8

๐Ÿ‘‰๏ธ 32๋น„ํŠธ ๋ณดํ˜ธ๋ชจ๋“œ(๊ทธ๋ž˜ํ”ฝ๋ชจ๋“œ)์—์„œ ํ™”๋ฉด์— ์‚ฌ๊ฐํ˜•์„ ๋ณด์—ฌ์ฃผ๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
This is code that displays a rectangle on the screen in 32-bit protected mode (graphics mode).

๐Ÿ‘‰๐Ÿป ์ด์ „ miniOS-7์—์„œ ์ฝ”๋“œ์—์„œ ๋ฐ”๋€ ๋ถ€๋ถ„๋งŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
This section explains only the changes made to the code from the previous miniOS-7.

๐Ÿ‘‰๐Ÿป ์ฝ”๋“œ / Code

โœ”๏ธ boot.asm

— boot.asm์—์„œ 2๋ฒˆ ์„นํ„ฐ ์ฝ”๋“œ๋ฅผ 1์—์„œ 10์œผ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.
In boot.asm, change the sector code from 1 to 10.

    mov al, 10          ; โœ… 1์—์„œ 10์œผ๋กœ ์ˆ˜์ • (๋„‰๋„‰ํ•˜๊ฒŒ ์ฝ์–ด์˜ด)
                        ; Adjusted from 1 to 10 (read with a generous margin)

1)๊ธฐ์กด ์–ด์…ˆ๋ธ”๋ฆฌ ์ฝ”๋“œ์™ธ์— c์–ธ์–ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— c์–ธ์–ด ์ฝ”๋“œ์šฉ๋Ÿ‰๊นŒ์ง€ ๊ณ ๋ คํ•ด์„œ 10์„นํ„ฐ๊นŒ์ง€ ์ฝ์–ด ์˜ค๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
Since adding C code alongside the existing assembly code increases the total size, the system is configured to read up to 10 sectors to accommodate the C code.

10๊ฐœ ์„นํ„ฐ ํฌ๊ธฐ: 512๋ฐ”์ดํŠธ ร— 10 = 5,120๋ฐ”์ดํŠธ (์•ฝ 5KB)
Size of 10 sectors: 512 bytes ร— 10 = 5,120 bytes (approx. 5 KB)

2) 10๊ฐœ ์„นํ„ฐ๋กœ ๋„‰๋„‰ํ•˜๊ฒŒ ์ง€์ •ํ•ด ๋‘๋ฉด ์ฝ”๋“œ๊ฐ€ ์ž˜๋ฆฌ๋Š” ์ผ ์—†์ด ์•ˆ์ •์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ๋‹ค ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.
By generously allocating 10 sectors, the code loads reliably into memory in its entirety without being truncated.

โœ”๏ธ sector2.asm

— [org 0x8000]๋ฅผ ์ฃผ์„์ฒ˜๋ฆฌ ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
Comment out or remove [org 0x8000].

; โœ… ์ฝ”๋“œ ์ œ๊ฑฐ / Remove code
;[org 0x8000] 

1)[org 0x8000] ์ด ์ฝ”๋“œ๋Š” ์ˆœ์ˆ˜ ๋ฐ”์ด๋„ˆ๋ฆฌ์šฉ ์ž…๋‹ˆ๋‹ค.
[org 0x8000] This code is for a raw binary.

2) ๊ทธ๋ž˜์„œ ์ฝ”๋“œ ์•ˆ์— ์žˆ๋Š” ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜๋“ค์˜ ์ฃผ์†Œ๋ฅผ ๋ฏธ๋ฆฌ 0x8000 ๊ธฐ์ค€์œผ๋กœ ์ „๋ถ€ ๊ณ ์ •ํ•ด์„œ ํ•˜๋‚˜์˜ ์™„์„ฑ๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ(.bin) ํŒŒ์ผ๋กœ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.
Therefore, the addresses of all variables and functions within the code are fixed in advance based on the 0x8000 address, and the code is compiled into a single, complete binary (.bin) file.

3)C์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด C์–ธ์–ด ํŒŒ์ผ(kernel.c)๊ณผ ์–ด์…ˆ๋ธ”๋ฆฌ ํŒŒ์ผ(sector2.asm)์„ ํ•จ๊ป˜ ๋ฌถ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
When using the C language, you must combine the C source file (kernel.c) and the assembly file (sector2.asm).

4)๊ทธ๋ž˜์„œ ์ˆœ์ˆ˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์•„๋‹Œ, ์กฐ๋ฆฝ์šฉ ๋ถ€ํ’ˆ ์ƒํƒœ์ธ ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ(.o)๋กœ ์ปดํŒŒ์ผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
Therefore, instead of a pure binary, it is compiled into object files (.o)โ€”components intended for assembly.

5) ๊ทธ๋Ÿฌ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
Then, run the compilation as follows.

ld -m elf_i386 -Ttext 0x8000 -o sector2.bin sector2.o kernel.o --oformat binary

6)์ด๋•Œ ์ด๋ฏธ ์ปดํŒŒ์ผํ–ˆ๋˜ sector2.o์™€ kernel.o๋ฅผ ๋ฌถ์–ด์„œ sector2.binํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋ฉฐ text ์„น์…˜ 0x8000 ์ฃผ์†Œ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
At this stage, the previously compiled sector2.o and kernel.o are linked to generate the sector2.bin file, with the text section aligned to address 0x8000.

— text ์„น์…˜์€ sector2.bin์ƒ์„ฑ์‹œ -Ttext 0x8000 ์ด๋ถ€๋ถ„์—์„œ text๋กœ ์„น์…˜ ๋„ค์ž„์„ ์ง€์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
The ‘text’ section is named as such because ‘text’ was specified as the section name using -Ttext 0x8000 when generating sector2.bin.

section .text           ;  ELF ํฌ๋งท ์ปดํŒŒ์ผ์„ ์œ„ํ•ด ์ฝ”๋“œ ์„น์…˜์ž„์„ ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
                        ;  Specifies that it is a code section for ELF format compilation.

— ld๋ช…๋ น์„ ์‚ฌ์šฉํ• ๋•Œ ๋ง์ปค๊ฐ€ ์ธ์‹ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด global๋กœ ์„ ์–ธํ•ด์„œ ์™ธ๋ถ€์— ๊ณต๊ฐœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
To ensure the linker recognizes it when using the ld command, you must declare it as global to make it externally visible.

global start            ;  ๋ง์ปค๊ฐ€ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก start ๋ ˆ์ด๋ธ”์„ ์™ธ๋ถ€์— ๊ณต๊ฐœํ•ฉ๋‹ˆ๋‹ค.
                        ;  Expose the `start` label so that the linker can recognize it.
global protected_start  ;  ๋ฉ€๋ฆฌ๋›ฐ๊ธฐ ๋ชฉ์ ์ง€ ๋ ˆ์ด๋ธ”๋„ ์™ธ๋ถ€์— ๊ณต๊ฐœํ•ฉ๋‹ˆ๋‹ค.
                        ;  We are also making the long-jump destination labels publicly available

— C์–ธ์–ด ๋ณ€์ˆ˜ ๋ฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์œ„ํ•œ ์Šคํƒ์˜์—ญ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
It designates the stack area for C language variables and function calls.

mov esp, 0x90000

— C์–ธ์–ด์˜ kernel_mainํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
It calls the C language’s kernel_main function.

call kernel_main    ; โœ… kernel_main์œผ๋กœ ์ ํ”„!
                    ; Jump to kernel_main!

โœ”๏ธ kernel.c

–์ด ์ฝ”๋“œ์—์„œ ์‹ค์ œ๋กœ ์‚ฌ๊ฐํ˜•์„ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
This code actually draws the rectangle.

typedef unsigned char byte;

// 1. ์›ํ•˜๋Š” ์œ„์น˜(x, y)์— ์›ํ•˜๋Š” ์ƒ‰์ƒ(color)์˜ ์ ์„ ์ฐ๋Š” ํ•จ์ˆ˜
// 1. A function that plots a point of a specified color at a desired location (x, y).
void draw_pixel(int x, int y, byte color) {
    byte *vram = (byte *)0xA0000;
    // 320x200 ํ•ด์ƒ๋„์˜ 1์ฐจ์› ๋ฐฐ์—ด ์œ„์น˜ ๊ณ„์‚ฐ: (y * 320) + x
    // Calculation of 1D array position for 320x200 resolution: (y * 320) + x
    vram[(y * 320) + x] = color;
}

// 2. ์›ํ•˜๋Š” ์œ„์น˜, ํฌ๊ธฐ, ์ƒ‰์ƒ์œผ๋กœ ์‚ฌ๊ฐํ˜•์„ ๊ทธ๋ฆฌ๋Š” ํ•จ์ˆ˜
// 2. Function to draw a rectangle at a desired position, size, and color
void draw_rect(int start_x, int start_y, int width, int height, byte color) {
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            // ์œ„์—์„œ ๋งŒ๋“  ์  ์ฐ๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉ
            // Utilize the point-plotting function created above
            draw_pixel(start_x + x, start_y + y, color);
        }
    }
}

// 3. ์ปค๋„ ๋ฉ”์ธ ํ•จ์ˆ˜
// 3. Kernel main function
void kernel_main(void) {
    // ์˜ˆ์‹œ 1: X=100, Y=50 ์œ„์น˜์— ๊ฐ€๋กœ 50, ์„ธ๋กœ 30 ํฌ๊ธฐ์˜ ๊ฐˆ์ƒ‰(6) ์‚ฌ๊ฐํ˜•
    // Example 1: A brown (6) rectangle with a width of 50 and a height of 30 at position X=100, Y=50
    draw_rect(100, 50, 50, 30, 6);

    // ์˜ˆ์‹œ 2: ๋‹ค๋ฅธ ์œ„์น˜์— ํŒŒ๋ž€์ƒ‰(9) ์‚ฌ๊ฐํ˜• ์ถ”๊ฐ€๋กœ ๊ทธ๋ฆฌ๊ธฐ (์ƒ‰์ƒ ๋ณ€๊ฒฝ ํ…Œ์ŠคํŠธ)
    // Example 2: Draw an additional blue (9) rectangle at a different location (color change test)
    draw_rect(200, 100, 40, 40, 9);
    
    // ์˜ˆ์‹œ 3: ๋‹ค๋ฅธ ์œ„์น˜์— ์ดˆ๋ก์ƒ‰(10) ์‚ฌ๊ฐํ˜• ์ถ”๊ฐ€๋กœ ๊ทธ๋ฆฌ๊ธฐ
    // Example 3: Draw an additional green (10) rectangle at a different location.
    draw_rect(30, 120, 60, 20, 10);

    // ์ž‘์—… ์™„๋ฃŒ ํ›„ CPU ๋Œ€๊ธฐ
    // Wait for CPU after task completion
    while (1) {
        __asm__ __volatile__("hlt");
    }
}

๐Ÿ‘‰๏ธ ์ปดํŒŒ์ผ / Compiling

# 1. 1๋ฒˆ ์„นํ„ฐ ๋ถ€ํŠธ๋กœ๋” ์ปดํŒŒ์ผ
# Compile Sector 1 Bootloader

nasm -f bin boot.asm -o boot.bin

# 2. 2๋ฒˆ ์„นํ„ฐ ๋ณดํ˜ธ๋ชจ๋“œ ์ง„์ž…๋ถ€ ์ปดํŒŒ์ผ
# Compiling the Sector 2 protection mode entry section

nasm -f elf32 sector2.asm -o sector2.o

# 3. GCC ์ปดํŒŒ์ผ ์‹œ ์œ„์น˜ ๋…๋ฆฝ์  ์ฝ”๋“œ(PIC)๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋„๋ก ์˜ต์…˜ ์ถ”๊ฐ€
# Add an option to prevent the generation of position-independent code (PIC) when compiling with GCC.

gcc -m32 -c kernel.c -o kernel.o -nostdlib -fno-builtin -fno-stack-protector -fno-pic -fno-PIE

# 4. ๋ง์ปค(ld)์—๊ฒŒ ์ฝ”๋“œ์˜ ์‹œ์ž‘์ (Entry)์ด '_start'๊ฐ€ ์•„๋‹ˆ๋ผ 'start' ์ž„์„ ๋ช…์‹œ
# Specify to the linker (ld) that the code entry point is 'start' instead of '_start'

ld -m elf_i386 -Ttext 0x8000 -e start -o sector2.bin sector2.o kernel.o --oformat binary

# 5. ๊ธฐ์กด ๋ฐฉ์‹๋Œ€๋กœ ๋””์Šคํฌ ์ด๋ฏธ์ง€ ๋ณ‘ํ•ฉ ๋ฐ QEMU ์‹คํ–‰
# # 5. Merging Disk Images and Running QEMU Using the Existing Method

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

Leave a Reply