ฉันได้อ่านและติดตามบทช่วยสอนเกี่ยวกับการเขียนระบบปฏิบัติการตั้งแต่เริ่มต้นโดย Nick Blundell ซึ่งสามารถพบได้ที่ https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf
ฉันเขียนบูตโหลดเดอร์ที่สามารถเรียกโค้ด C ได้สำเร็จ ดังนั้นฉันจึงเริ่มเขียนเคอร์เนลในภาษา C ตอนนี้ฉันกำลังพยายามเขียนฟังก์ชันที่สามารถพิมพ์อักขระและสตริงบนหน้าจอได้ เมื่อถึงเวลาที่ฉันเริ่มรันโค้ด C ฉันอยู่ในโหมดป้องกันแบบ 32 บิต ดังนั้นฉันจึงพยายามคำนวณออฟเซ็ตหน่วยความจำจากที่อยู่หน่วยความจำวิดีโอ 0xb8000 อย่างถูกต้อง
ปัญหาของฉันเริ่มต้นเมื่อฉันพยายามเข้าถึงพื้นที่เฉพาะของหน่วยความจำวิดีโอโดยใช้ออฟเซ็ตที่คำนวณได้ เนื่องจากพื้นที่ข้อความคือ 25 แถวคูณ 80 คอลัมน์ ฉันจึงใช้สูตร ((แถว * 80) + คอลัมน์) * 2 เนื่องจากฉันต้องมีไบต์อักขระและไบต์แอตทริบิวต์ เมื่อฉันตั้งค่าแถว = 0 และคอลัมน์ = 0 แสดงว่า X ที่ฉันพยายามพิมพ์หายไป การตั้งค่าแถว = 0 และคอลัมน์ = 1 จะมีเครื่องหมาย X ปรากฏที่มุมซ้ายบน
การเริ่มต้นด้วย char* video_memory = 0xb8000 และการออก video_memory++ ซ้ำๆ ช่วยให้ฉันสามารถเยี่ยมชมแต่ละไบต์ได้อย่างถูกต้องและพิมพ์ช่องว่างบนพื้นหลังสีดำ
นี่คือรหัสหลักของฉัน:
#include "../drivers/screen.h"
void main() {
//clear_screen();
//print_character('X', 0, 0, 0);
// Helper variables.
int row;
int column;
// We need to point at 0xB8000, where video memory resides.
unsigned char* video_memory = (unsigned char*)0xB8000;
for(row = 0; row < 25; row++) {
for(column = 0; column < 80; column++) {
// Clear the screen by printing a space on a black background.
*video_memory = ' ';
video_memory += 1;
*video_memory = 0x0F;
video_memory += 1;
}
}
// Test the offset calculation by printing at row 0, column 0 (the upper
// left corner of the screen).
row = 0;
column = 0;
// For an 80 by 25 grid. Multiply by 2 to account for the need of two bytes
// to display a character with given attributes.
int offset = ((row * 80) + column) * 2;
// Reset memory location after the loop.
video_memory = (unsigned char*)0xB8000;
// Add the offset to get the desired cell.
// THIS IS WHERE THE PROBLEM IS! Setting column = 1 prints in the first cell
// of video memory instead of the second.
video_memory += offset;
// Set character and its attributes.
*video_memory = 'X';
video_memory++;
*video_memory = 0x0F;
}
นี่คือคอนโซลที่แสดงเมื่อแถว = 0 และคอลัมน์ = 0: คอนโซลเมื่อแถวและคอลัมน์เป็น 0 ไม่มี X ปรากฏขึ้น
นี่คือคอนโซลเมื่อแถว = 0 และคอลัมน์ = 1: คอนโซลเมื่อแถวเป็น 0 และคอลัมน์เป็น 1 . เครื่องหมาย X ปรากฏขึ้น
นี่คือ objdump ของไฟล์ kernel.c ของฉันด้านบน:
kernel.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
#include "../drivers/screen.h"
void main() {
0: 55 push rbp
1: 48 89 e5 mov rbp,rsp
// Helper variables.
int row;
int column;
// We need to point at 0xB8000, where video memory resides.
unsigned char* video_memory = (unsigned char*)0xB8000;
4: 48 c7 45 f8 00 80 0b mov QWORD PTR [rbp-0x8],0xb8000
b: 00
for(row = 0; row < 25; row++) {
c: c7 45 ec 00 00 00 00 mov DWORD PTR [rbp-0x14],0x0
13: eb 2f jmp 44 <main+0x44>
for(column = 0; column < 80; column++) {
15: c7 45 f0 00 00 00 00 mov DWORD PTR [rbp-0x10],0x0
1c: eb 1c jmp 3a <main+0x3a>
// Clear the screen by printing a space on a black background.
*video_memory = ' ';
1e: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
22: c6 00 20 mov BYTE PTR [rax],0x20
video_memory += 1;
25: 48 83 45 f8 01 add QWORD PTR [rbp-0x8],0x1
*video_memory = 0x0F;
2a: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
2e: c6 00 0f mov BYTE PTR [rax],0xf
video_memory += 1;
31: 48 83 45 f8 01 add QWORD PTR [rbp-0x8],0x1
int column;
// We need to point at 0xB8000, where video memory resides.
unsigned char* video_memory = (unsigned char*)0xB8000;
for(row = 0; row < 25; row++) {
for(column = 0; column < 80; column++) {
36: 83 45 f0 01 add DWORD PTR [rbp-0x10],0x1
3a: 83 7d f0 4f cmp DWORD PTR [rbp-0x10],0x4f
3e: 7e de jle 1e <main+0x1e>
int row;
int column;
// We need to point at 0xB8000, where video memory resides.
unsigned char* video_memory = (unsigned char*)0xB8000;
for(row = 0; row < 25; row++) {
40: 83 45 ec 01 add DWORD PTR [rbp-0x14],0x1
44: 83 7d ec 18 cmp DWORD PTR [rbp-0x14],0x18
48: 7e cb jle 15 <main+0x15>
}
}
// Test the offset calculation by printing at row 0, column 0 (the upper
// left corner of the screen).
row = 0;
4a: c7 45 ec 00 00 00 00 mov DWORD PTR [rbp-0x14],0x0
column = 0;
51: c7 45 f0 00 00 00 00 mov DWORD PTR [rbp-0x10],0x0
// For an 80 by 25 grid. Multiply by 2 to account for the need of two bytes
// to display a character with given attributes.
int offset = ((row * 80) + column) * 2;
58: 8b 55 ec mov edx,DWORD PTR [rbp-0x14]
5b: 89 d0 mov eax,edx
5d: c1 e0 02 shl eax,0x2
60: 01 d0 add eax,edx
62: c1 e0 04 shl eax,0x4
65: 89 c2 mov edx,eax
67: 8b 45 f0 mov eax,DWORD PTR [rbp-0x10]
6a: 01 d0 add eax,edx
6c: 01 c0 add eax,eax
6e: 89 45 f4 mov DWORD PTR [rbp-0xc],eax
// Reset memory location after the loop.
video_memory = (unsigned char*)0xB8000;
71: 48 c7 45 f8 00 80 0b mov QWORD PTR [rbp-0x8],0xb8000
78: 00
// Add the offset to get the desired cell.
// THIS IS WHERE THE PROBLEM IS! Setting column = 1 prints in the first cell
// of video memory instead of the second.
video_memory += offset;
79: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
7c: 48 98 cdqe
7e: 48 01 45 f8 add QWORD PTR [rbp-0x8],rax
// Set character and its attributes.
*video_memory = 'X';
82: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
86: c6 00 58 mov BYTE PTR [rax],0x58
video_memory++;
89: 48 83 45 f8 01 add QWORD PTR [rbp-0x8],0x1
*video_memory = 0x0F;
8e: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
92: c6 00 0f mov BYTE PTR [rax],0xf
}
95: 90 nop
96: 5d pop rbp
97: c3 ret
ฉันได้ตรวจสอบคำแนะนำในการประกอบจริงสำหรับการคำนวณออฟเซ็ตของฉันแล้ว และดูเหมือนว่าจะถูกต้อง ฉันสงสัยว่าปัญหาเกิดขึ้นเมื่อฉันพยายามเพิ่มออฟเซ็ต (พิมพ์ int) ไปยังที่อยู่หน่วยความจำวิดีโอของฉัน (พิมพ์อักขระถ่าน*) แต่ฉันก็ไม่แน่ใจอีกครั้ง
นอกจากนี้ ฉันยังลองฮาร์ดโค้ดเฉพาะตัวเลขสำหรับการชดเชยด้วย การใช้ video_memory += 0 แทน video_memory += offset ทำงานได้ตามต้องการ
video_memory
และตำแหน่งของปัญหา ใช้การจัดทำดัชนีอาร์เรย์ปกติแทน เช่นเดียวกับในvideo_memory[row * 80 + column] = 'X';
- person Some programmer dude   schedule 22.05.2018