[OS]miniOS-10

๐Ÿ‘‰๏ธ ํ•จ์ˆ˜๋กœ ๋ฌธ์ž์—ด ์ „์ฒด๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
This is code that outputs the entire string to the screen using a function.

๐Ÿ‘‰๏ธ ์ด์ „ ์ฝ”๋“œ์—์„œ draw_string()ํ•จ์ˆ˜๊ฐ€ ์ถ”๊ฐ€๋์Šต๋‹ˆ๋‹ค.
The draw_string() function has been added to the previous code.

๐Ÿ‘‰๏ธ A~Z๊นŒ์ง€ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๋„๋ก ๋ฌธ์ž๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
We have added characters to support the full range from A to Z.

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

boot.asm    kernel.c   sector2.asm

๐Ÿ‘‰๏ธ boot.asm๊ณผ sector2.asm์€ miniOS-9์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
boot.asm and sector2.asm are identical to those of miniOS-9.

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

typedef unsigned char byte;

// ------------------------------------------------------------------------
// 1. ๊ธฐ๋ณธ ๊ทธ๋ž˜ํ”ฝ ํ•จ์ˆ˜ (volatile ์ ์šฉ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ๊ฐ•์ œ ์“ฐ๊ธฐ)
// Basic graphics functions (forced memory write via volatile)
// ------------------------------------------------------------------------
void draw_pixel(int x, int y, byte color) {
    volatile byte *vram = (volatile byte *)0xA0000;
    vram[(y * 320) + x] = color;
}

void clear_screen(byte color) {
    for (int y = 0; y < 200; y++) {
        for (int x = 0; x < 320; x++) {
            draw_pixel(x, y, color);
        }
    }
}

// ------------------------------------------------------------------------
// 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) {
    // A๋ถ€ํ„ฐ Z๊นŒ์ง€ ์ด 26๊ฐœ์˜ ์•ŒํŒŒ๋ฒณ ๋Œ€๋ฌธ์ž 8x8 ํฐํŠธ ๋ฐ์ดํ„ฐ ์„ธํŠธ
    byte font_8x8[26][8] = {
        {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}, // 'A' (index 0)
        {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}, // 'B' (index 1)
        {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}, // 'C' (index 2)
        {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}, // 'D' (index 3)
        {0x7E, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7E, 0x00}, // 'E' (index 4)
        {0x7E, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00}, // 'F' (index 5)
        {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}, // 'G' (index 6)
        {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}, // 'H' (index 7)
        {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}, // 'I' (index 8)
        {0x03, 0x01, 0x01, 0x01, 0x41, 0x41, 0x3E, 0x00}, // 'J' (index 9)
        {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}, // 'K' (index 10)
        {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}, // 'L' (index 11)
        {0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x42, 0x00}, // 'M' (index 12)
        {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}, // 'N' (index 13)
        {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}, // 'O' (index 14)
        {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}, // 'P' (index 15)
        {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}, // 'Q' (index 16)
        {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}, // 'R' (index 17)
        {0x3C, 0x40, 0x40, 0x3C, 0x02, 0x02, 0x3C, 0x00}, // 'S' (index 18)
        {0x7E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 'T' (index 19)
        {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}, // 'U' (index 20)
        {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}, // 'V' (index 21)
        {0x42, 0x42, 0x42, 0x42, 0x5A, 0x66, 0x42, 0x00}, // 'W' (index 22)
        {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}, // 'X' (index 23)
        {0x42, 0x42, 0x24, 0x18, 0x18, 0x18, 0x18, 0x00}, // 'Y' (index 24)
        {0x7E, 0x02, 0x04, 0x08, 0x16, 0x20, 0x7E, 0x00}  // 'Z' (index 25)
    };

    // ๋ฌธ์ž์— ๋งž๋Š” ํฐํŠธ ์ธ๋ฑ์Šค ๊ณ„์‚ฐ ('A'๋ฅผ ๋นผ์„œ 0~25๋กœ ๋ณ€ํ™˜)
    // Calculate the font index for the character (subtract 'A' to convert to a range of 0โ€“25)
    int font_index = 0;

    //  'A'์—์„œ 'Z'๊นŒ์ง€ ๋ฒ”์œ„ ๊ฒ€์‚ฌ
    // Check range from 'A' to 'Z'
    if (c >= 'A' && c <= 'Z') { 
        font_index = c - 'A';
    } else {
        return; 
    }

    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);
            }
        }
    }
}


// ------------------------------------------------------------------------
// 3. [์ƒˆ๋กœ ์ถ”๊ฐ€] ๋ฌธ์ž์—ด์„ ํ†ต์งธ๋กœ ๋„˜๊ธฐ๋ฉด ๊ฐ€๋กœ๋กœ ์ •๋ ฌํ•ด ๊ทธ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜
// [New Addition] A function that draws a string horizontally when passed as a whole.
// ------------------------------------------------------------------------
void draw_string(int start_x, int start_y, const char *str, byte color) {
    int current_x = start_x;
    
    // ๋ฌธ์ž์—ด์˜ ๋('\0')์„ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€ ํ•œ ๊ธ€์ž์”ฉ ๋ฐ˜๋ณต์ˆ˜ํ–‰
    // Iterate character by character until the end of the string ('\0') is reached
    for (int i = 0; str[i] != '\0'; i++) {

        // ๊ณต๋ฐฑ ๋ฌธ์ž(' ') ์ฒ˜๋ฆฌ: ๊ธ€์ž๋ฅผ ๊ทธ๋ฆฌ์ง€๋Š” ์•Š๊ณ  ๊ฐ€๋กœ๋กœ 8ํ”ฝ์…€ ๊ฑด๋„ˆ๋œ€
        // Handle space character (' '): Skip 8 pixels horizontally without drawing a character.
        if (str[i] == ' ') {
            current_x += 8;
            continue;
        }

        // ํ˜„์žฌ ๊ธ€์ž ๊ทธ๋ฆฌ๊ธฐ / Drawing current characters
        draw_char(current_x, start_y, str[i], color);
        
        // ๋‹ค์Œ ๊ธ€์ž๋Š” ๊ฐ€๋กœ๋กœ 8ํ”ฝ์…€ ๋’ค์— ๊ทธ๋ ค์ง€๋„๋ก ์ขŒํ‘œ ์ด๋™ (๊ธ€์ž ํฌ๊ธฐ๊ฐ€ 8x8์ด๋ฏ€๋กœ)
        // Shift the coordinates to draw the next character 8 pixels to the right (since the character size is 8x8).
        current_x += 8;
    }
}

// ------------------------------------------------------------------------
// 4. ์ปค๋„ ๋ฉ”์ธ ํ•จ์ˆ˜
// Kernel main function
// ------------------------------------------------------------------------
void kernel_main(void) {
    clear_screen(1); // ํŒŒ๋ž€ ๋ฐฐ๊ฒฝ / Blue background

    // -- ํ•จ์ˆ˜ ํ•œ ์ค„๋กœ ๋ฌธ์ž์—ด ํ†ต์งธ๋กœ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๊ธฐ! (ํ˜„์žฌ ํฐํŠธ๋Š” A~F์™€ ๊ณต๋ฐฑ๋งŒ ์ธ์‹ ๊ฐ€๋Šฅ)  -- //
    // -- Print an entire string to the screen with a single function call! (The current font only supports Aโ€“F and spaces.) -- //

    // ๋…ธ๋ž€์ƒ‰(14)์œผ๋กœ "I WANT TO" ์ถœ๋ ฅ / Output "BAD CAFE" in yellow (14).
    draw_string(80, 70, "I WANT TO", 14);  

    // ํฐ์ƒ‰(15)์œผ๋กœ "BREAKE FREE" ์ถœ๋ ฅ / Print "DECADE FACE" in white (15).
    draw_string(80, 90, "BREAKE FREE", 15); 

    // ๋นจ๊ฐ„์ƒ‰(12)์œผ๋กœ "QUEEN" ์ถœ๋ ฅ / Output "FADE" in red (12).
    draw_string(80, 110, "QUEEN", 12);        

    while (1) {
        __asm__ __volatile__("hlt");
    }
}

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

โœ”๏ธ A~Z๊นŒ์ง€ ๋ฌธ์ž ๋ฒ”์œ„ ๊ฒ€์‚ฌ(๋Œ€๋ฌธ์ž)
Check character range from A to Z (uppercase)

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

โœ”๏ธ A~Z๊นŒ์ง€ ๋ฌธ์ž ๋ฒ”์œ„ ๊ฒ€์‚ฌ(๋Œ€๋ฌธ์ž)
Check character range from A to Z (uppercase)

1)draw_charํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ์ž…๋ ฅ๋œ ๋ณ€์ˆ˜(char c)๊ฐ€ A~Z๊นŒ์ง€ ๋ฒ”์œ„๋‚ด์— ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
It checks whether the variable (char c) passed as a parameter to the draw_char function falls within the range of A to Z.

2) ๋Œ€๋ฌธ์ž ์•„์Šคํ‚ค ์ฝ”๋“œ ‘A’ (65) ~ ‘Z’ (90) ์ž…๋‹ˆ๋‹ค.
These are the uppercase ASCII codes ‘A’ (65) through ‘Z’ (90).

3)if (c >= ‘A’ && c <= ‘Z’) { } ๋Š” if (c >= 65 && c <= 90) {}๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
if (c >= 'A' && c <= 'Z') { } is equivalent to if (c >= 65 && c <= 90) {}.

โœ”๏ธ draw_string()ํ•จ์ˆ˜ ์‹คํ–‰
Execute the draw_string() function.

— kernel_mainํ•จ์ˆ˜์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด draw_string()ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
In the kernel_main function, execute the draw_string() function as shown below.

draw_string(80, 70, "I WANT TO", 14);   

1) draw_string(x,y,”character”,color number)ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.
It takes the form draw_string(x, y, "character", color number).

2) kernel_mainํ•จ์ˆ˜ ๋‚ด์—์„œ ์•„๋ž˜์ฒ˜๋Ÿผ draw_stringํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ž๋ฅผ ์ถœ๋ ฅ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
You can output characters by calling the draw_string function within the kernel_main function, as shown below.

draw_string(80, 70, "I WANT TO", 14); 

โœ”๏ธ draw_string()ํ•จ์ˆ˜
draw_string() function

— draw_stringํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์˜ ๋ฐ˜๋ณต๋ฌธ ๋กœ์ง์œผ๋กœ ์ž…๋ ฅ๋œ ๋ฌธ์ž๋ฅผ ๋ฐฐ์—ด๋กœ ๊บผ๋‚ด์„œ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
When the draw_string function is executed, the loop logic below extracts the input characters into an array and outputs them.

    // ๋ฌธ์ž์—ด์˜ ๋('\0')์„ ๋งŒ๋‚  ๋•Œ๊นŒ์ง€ ํ•œ ๊ธ€์ž์”ฉ ๋ฐ˜๋ณต์ˆ˜ํ–‰
    // Iterate character by character until the end of the string ('\0') is reached
    for (int i = 0; str[i] != '\0'; i++) {

        // ๊ณต๋ฐฑ ๋ฌธ์ž(' ') ์ฒ˜๋ฆฌ: ๊ธ€์ž๋ฅผ ๊ทธ๋ฆฌ์ง€๋Š” ์•Š๊ณ  ๊ฐ€๋กœ๋กœ 8ํ”ฝ์…€ ๊ฑด๋„ˆ๋œ€
        // Handle space character (' '): Skip 8 pixels horizontally without drawing a character.
        if (str[i] == ' ') {
            current_x += 8;
            continue;
        }

        // ํ˜„์žฌ ๊ธ€์ž ๊ทธ๋ฆฌ๊ธฐ / Drawing current characters
        draw_char(current_x, start_y, str[i], color);
        
        // ๋‹ค์Œ ๊ธ€์ž๋Š” ๊ฐ€๋กœ๋กœ 8ํ”ฝ์…€ ๋’ค์— ๊ทธ๋ ค์ง€๋„๋ก ์ขŒํ‘œ ์ด๋™ (๊ธ€์ž ํฌ๊ธฐ๊ฐ€ 8x8์ด๋ฏ€๋กœ)
        // Shift the coordinates to draw the next character 8 pixels to the right (since the character size is 8x8).
        current_x += 8;
    }

1)๋ฐฐ์—ด ๋‚ด์˜ ๋ฌธ์ž์— ๊ณต๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์šฐ์ธก์œผ๋กœ ํ•œ์นธ ๋„์šฐ๊ธฐ ์œ„ํ•ด current_x์— 8(ํ”ฝ์…€)์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
If there is a space character in the array, 8 (pixels) are added to current_x to shift the position one space to the right.

        if (str[i] == ' ') {
            current_x += 8;
            continue;
        }

2)๊ธ€์ž๋ฅผ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค.
Draw the characters.

draw_char(current_x, start_y, str[i], color);

3)๊ธ€์ž๊ฐ€ ๊ทธ๋ ค์ง€๋ฉด ๋‹ค์Œ๊ธ€์ž๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•ด ์šฐ์ธก์œผ๋กœ 8ํ”ฝ์…€ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
Once a character is drawn, the position shifts 8 pixels to the right to draw the next character.

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