๐๏ธ ์๋ฌธ์ ์ถ๊ฐ,์ซ์ ๋ฐ ํน์๋ฌธ์๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
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