[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