[OS]miniOS-11

๐Ÿ‘‰๏ธ ์†Œ๋ฌธ์ž ์ถ”๊ฐ€,์ˆซ์ž ๋ฐ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
Lowercase letters, numbers, and special characters have been added.

๐Ÿ‘‰๏ธ ์ฝ”๋“œ ๋‚ด์šฉ์ด ๋งŽ์•„์„œ ์ „์ฒด์ฝ”๋“œ๋Š” github์— ์žˆ๋Š” ์ž๋ฃŒ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”
As the code is extensive, please refer to the materials on GitHub for the full code.

https://github.com/gideonslife01/minios

๐Ÿ‘‰๏ธ ํŒŒ์ผ / files

boot.asm   sector2.asm   kernel.c

๐Ÿ‘‰๏ธ ์ฝ”๋“œ์„ค๋ช… / Code Explanation

โœ”๏ธboot.asm

— boot.asm์—์„œ ๊ฐ’์ด 12๋กœ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
The value has been changed to 12 in boot.asm.

๐Ÿ‘‰๏ธ ์ฝ”๋“œ์„ค๋ช… / Code Explanation

โœ”๏ธboot.asm

— boot.asm์—์„œ ๊ฐ’์ด 12๋กœ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
The value has been changed to 12 in boot.asm.

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

1)ls -ls๋ช…๋ น์–ด๋กœ sector2.binํŒŒ์ผ ์šฉ๋Ÿ‰์„ ํ™•์ธํ•˜๋ฉด ํ˜„์žฌ 5.4Kbyte์ž…๋‹ˆ๋‹ค.
Checking the size of the sector2.bin file with the ls -ls command shows that it is currently 5.4 KB.

$ ls -lh sector2.bin
-rwxrwxr-x 1 daekyeongkim daekyeongkim 5.4K Sep  11 11:11 sector2.bin

2) 1์„นํ„ฐ๋Š” 512๋ฐ”์ดํŠธ์ด๊ณ  ์ƒ์„ฑ๋œ sector2.bin ํŒŒ์ผ์˜ ์šฉ๋Ÿ‰์€ 5.4Kbyte์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋ž˜์ฒ˜๋Ÿผ5.4Kbyte๋ฅผ 512byte๋กœ ๋‚˜๋ˆ„๋ฉด ์ฝ์–ด์•ผ ํ•  ๊ฐ’์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
A single sector is 512 bytes, and the generated sector2.bin file is 5.4 KB in size. Therefore, by dividing 5.4 KB by 512 bytes as shown below, you can determine the value that needs to be read.

 5400 % 512 = 10.546875

3)๊ฒฐ๊ตญ 11์„นํ„ฐ๋Š” ์ฝ์–ด์•ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜๋ฆฌ์ง€ ์•Š์ง€๋งŒ ๋„‰๋„‰ํ•˜๊ฒŒ 12์„นํ„ฐ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
Ultimately, reading 11 sectors prevents data truncation, but I am setting it to 12 sectors to be safe.

4)์„นํ„ฐ๋ฅผ ์ถฉ๋ถ„ํžˆ ์ฝ์ง€ ์•Š์œผ๋ฉด ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์‹œ ํ™”๋ฉด์— ์•„๋ฌด๊ฒƒ๋„ ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
If the sectors are not read sufficiently, nothing will appear on the screen or an error will occur when the program runs.

โœ”๏ธ kernel.c

— ๊ธ€์ž ์ถœ๋ ฅํ•จ์ˆ˜ / Character output function

// ------------------------------------------------------------------------
// 2. ๊ธ€์ž ์ถœ๋ ฅ ํ•จ์ˆ˜ (ํฐํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ์ˆ˜ ๋‚ด๋ถ€๋กœ ์ด๋™ํ•˜์—ฌ ๋งํ‚น ์˜ค๋ฅ˜ ํ•ด๊ฒฐ)
// Character output function (resolved linking errors by moving font data inside the function)
// ------------------------------------------------------------------------
void draw_char(int start_x, int start_y, char c, byte color) {

    // ๋ถ€ํ˜ธ ์—†๋Š” 1๋ฐ”์ดํŠธ ์ •์ˆ˜๋กœ ํ˜•๋ณ€ํ™˜ํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฒ”์œ„๋ฅผ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    // Safely check the range by casting to an unsigned 1-byte integer.
    unsigned char ascii_code = (unsigned char)c;
    if (ascii_code >= 128) return;

    // 128(0~127)๊ฐœ ๋ฌธ์ž / 128 (0โ€“127) characters
    static const byte font_8x8[128][8] = {
        {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0: NULL
        {0x7E,0x81,0xA5,0x81,0xBD,0x99,0x81,0x7E}, // 1: โ˜บ
        {0x7E,0xFF,0xDB,0xFF,0xC3,0xE7,0xFF,0x7E}, // 2: โ˜ป
        {0x6C,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00}, // 3: โ™ฅ

                       ... ์ค‘๋žต/[Omitted] ...

        {0x08,0x08,0x08,0x00,0x08,0x08,0x08,0x00}, // 124: |
        {0x30,0x08,0x08,0x04,0x08,0x08,0x30,0x00}, // 125: }
        {0x00,0x00,0x32,0x4C,0x00,0x00,0x00,0x00}, // 126: ~
        {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}  // 127: DEL
    };

    // ์ •๋ฐฉํ–ฅ ๋‹ค์ด๋ ‰ํŠธ ๋งคํ•‘: ํ˜•๋ณ€ํ™˜๋œ ๊ฐ’์ด ๊ณง ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
    // Forward direct mapping: The converted value becomes the index number.
    int font_index = (int)ascii_code;

    for (int y = 0; y < 8; y++) {
        byte row_data = font_8x8[font_index][y];

        for (int x = 0; x < 8; x++) {
            if ((row_data & (0x80 >> x)) != 0) {
                draw_pixel(start_x + x, start_y + y, color);
            }
        }
    }
}

1) ์ด ํ•จ์ˆ˜์˜ ๋ฐฐ์—ด ๋ฒˆํ˜ธ์™€ ์•„์Šคํ‚ค ์ฝ”๋“œ ๊ฐ’์€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.
The array index and the ASCII code value in this function correspond to each other.

2) ์†Œ๋ฌธ์ž ‘u’์˜ ์•„์Šคํ‚ค ์ฝ”๋“œ ๊ฐ’์€ 117๋ฒˆ์ด๊ณ  ๋ฐฐ์—ด ๋ฒˆํ˜ธ๋„ 117๋ฒˆ ์ž…๋‹ˆ๋‹ค.
The ASCII code value for the lowercase letter ‘u’ is 117, and its array index is also 117.

 {0x00,0x00,0x42,0x42,0x42,0x46,0x3A,0x00}, // 117: u

4)ํ™”๋ฉด์— ์†Œ๋ฌธ์ž’u’๋ฅผ ์ถœ๋ ฅํ•  ๊ฒฝ์šฐ font_indexr๊ฐ€ 117๋ฒˆ์ด ๋˜๊ณ  117๋ฒˆ ๋ฐฐ์—ด์— ํ•ด๋‹นํ•˜๋Š” 16์ง„์ˆ˜ ๊ฐ’์„ row_data์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
When the lowercase letter ‘u’ is displayed on the screen, font_indexr becomes 117, and the hexadecimal value corresponding to index 117 of the array is stored in row_data.

byte row_data = font_8x8[font_index][y];

5)๋ฐ˜๋ณต๋ฌธ์„ ์‹คํ–‰ํ•ด์„œ start_x,start_y๊ฐ’ ์ขŒํ‘œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ 1ํ”ฝ์…€์”ฉ ์ ์„์ฐ์Šต๋‹ˆ๋‹ค.
Execute a loop to plot points one pixel at a time, based on the start_x and start_y coordinates.

6)0x80 >> x ์ด ๊ฐ’๊ณผ ์œ„์—์„œ ์•„๋ž˜๋กœ 1ํ”ฝ์…€์”ฉ ํ™•์ธํ•˜๊ณ  ์ขŒ์—์„œ ์šฐ๋กœ 1ํ”ฝ์…€์”ฉ ๋ฐฐ์—ด์˜ ๊ฐ’๊ณผ ํ™•์ธํ•ด์„œ ์ด์ง„์ˆ˜๋กœ ๋ณ€ํ™˜์‹œ ๋‘˜๋‹ค 1์ธ ์œ„์น˜์— ์ ๋“ค ์ฐ์Šต๋‹ˆ๋‹ค.
Using the value 0x80 >> x, we check the array values โ€‹โ€‹pixel by pixel moving from top to bottom and left to right and plot a point wherever both values โ€‹โ€‹are 1 when converted to binary.

3) u์˜ ์•„์Šคํ‚ค ์ฝ”๋“œ ๊ฐ’์€ 117์ž…๋‹ˆ๋‹ค. kernal_mainํ•จ์ˆ˜ ๋‚ด์—์„œ draw_charํ•จ์ˆ˜์— ์•„์Šคํ‚ค ์ฝ”๋“œ ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด ํ™”๋ฉด์— u๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
The ASCII code value for ‘u’ is 117. You can verify that ‘u’ is displayed on the screen by passing this ASCII code value to the draw_char function within the kernel_main function.

draw_char(20,20,117,15);

— ๋ฌธ์ž์—ด ์ถœ๋ ฅํ•จ์ˆ˜ / String output function

// ------------------------------------------------------------------------
// 3. ๋ฌธ์ž์—ด ์ถœ๋ ฅ ํ•จ์ˆ˜ (์ค„๋ฐ”๊ฟˆ ๋ฐ ์ž๋™ ๊ฐœํ–‰ ํƒ‘์žฌ)
//    String output function (includes line breaks and automatic newline insertion)
// ------------------------------------------------------------------------
void draw_string(int start_x, int start_y, const char *str, byte color) {

    //draw_char(0,0,'X',15);
    int current_x = start_x;
    int current_y = start_y;
    
    for (int i = 0; str[i] != '\0'; i++) {
        
        // 1. \n ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ
        // Line break handling
        if (str[i] == '\n') {
            current_x = start_x;
            current_y += 10;
            continue;
        }

        // 2. ํ™”๋ฉด ๋ ์ž๋™ ๊ฐœํ–‰
        // Automatic line break at screen edge
        if (current_x + 8 > 320) {
            current_x = start_x;
            current_y += 10;
        }

        // 3. ์ง„์งœ ์ŠคํŽ˜์ด์Šค๋ฐ” ๊ณต๋ฐฑ(' ')๋งŒ ๊ฑธ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค.
        // It filters out only the actual space character (' ').
        if (str[i] == ' ') { 
            current_x += 8;
            continue;
        }

        // 4. ๊ธ€์ž ๊ทธ๋ฆฌ๊ธฐ 
        // Drawing Characters
        draw_char(current_x, current_y, str[i], color);
        current_x += 8;
    }
}

1)ํ˜„์žฌ ๋ฐฐ์—ด์˜ ๋ฌธ์ž๊ฐ€ 0์•„๋‹ˆ๋ฉด ๋ฐ˜๋ณต์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
The loop continues to execute as long as the character in the current array is not 0.

    for (int i = 0; str[i] != '\0'; i++) { ... }

2) ๋ฌธ์ž์—์„œ \n์ด ์žˆ์œผ๋ฉด ํ˜„์žฌ ์œ„์น˜์—์„œ ์•„๋ž˜๋กœ ์ค„๋ฐ”๊ฟˆํ•ฉ๋‹ˆ๋‹ค.(10ํ”ฝ์…€ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค).
If \n appears in the text, a line break occurs downward from the current position (moving 10 pixels).

        // 1. \n ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ
        // Line break handling
        if (str[i] == '\n') {
            current_x = start_x;
            current_y += 10;
            continue;
        }

3)์ง€๊ธˆํ˜„์žฌ ํ™”๋ฉด์˜ ๊ฐ€๋กœ ํฌ๊ธฐ๊ฐ€ 320ํ”ฝ์…€์ž…๋‹ˆ๋‹ค.๊ธ€์ž์ˆ˜๊ฐ€ 320ํ”ฝ์…€ ์ดˆ๊ณผํ•˜๋ฉด ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ(current_y += 10;)ํ•ฉ๋‹ˆ๋‹ค.
The current screen width is 320 pixels. If the text exceeds 320 pixels, a line break is applied (current_y += 10;).

4) ๋ฌธ์žํ•˜๋‚˜์˜ ํฌ๊ธฐ๊ฐ€ ๊ฐ€๋กœ 8ํ”ฝ์…€ ์„ธ๋กœ8ํ”ฝ์…€์ด๊ธฐ ๋•Œ๋ฌธ์— current_x + 8 > 320 ์ด๋ ‡๊ฒŒ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
Since the size of a single character is 8 pixels wide by 8 pixels high, we check using the condition current_x + 8 > 320.

        // 2. ํ™”๋ฉด ๋ ์ž๋™ ๊ฐœํ–‰
        // Automatic line break at screen edge
        if (current_x + 8 > 320) {
            current_x = start_x;
            current_y += 10;
        }

5) ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ์ž…๋ ฅ๋œ ๋ฌธ์ž์— ๊ณต๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ๋ฌธ์ž ํ•˜๋‚˜๋งŒํผ(8ํ”ฝ์…€) ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
If the input character contains a space, it shifts to the right by the width of one character (8 pixels).

        // 3. ์ง„์งœ ์ŠคํŽ˜์ด์Šค๋ฐ” ๊ณต๋ฐฑ(' ')๋งŒ ๊ฑธ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค.
        // It filters out only the actual space character (' ').
        if (str[i] == ' ') { 
            current_x += 8;
            continue;
        }

6)๊ธ€์ž๋ฅผ ๊ทธ๋ฆฌ๊ณ  ์˜ค๋ฅธ์ชฝ์œผ๋กœ 8ํ”ฝ์…€ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
Draw the text and move it 8 pixels to the right.

        // 4. ๊ธ€์ž ๊ทธ๋ฆฌ๊ธฐ 
        // Drawing Characters
        draw_char(current_x, current_y, str[i], color);
        current_x += 8;

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

# 1. ๋ถ€ํŠธ์„นํ„ฐ ๋ฐ ๋ณดํ˜ธ๋ชจ๋“œ ์ง„์ž…๋ถ€ ์ปดํŒŒ์ผ
# Compiling the Boot Sector and Protected Mode Entry Code
nasm -f bin boot.asm -o boot.bin
nasm -f elf32 sector2.asm -o sector2.o

# 2. ์ƒˆ๋กœ ์ˆ˜์ •ํ•œ kernel.c ์ปดํŒŒ์ผ
# Compiling the newly modified kernel.c
gcc -m32 -c kernel.c -o kernel.o -nostdlib -fno-builtin -fno-stack-protector -fno-pic -fno-PIE

# 3. ํ•˜๋‚˜์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ๊ฒฐํ•ฉ
# Combining into a single binary
ld -m elf_i386 -Ttext 0x8000 -e start -o sector2.bin sector2.o kernel.o --oformat binary

# 4. ์ด๋ฏธ์ง€ ์ƒ์„ฑ ๋ฐ ์‹คํ–‰
# Image Creation and Execution
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