我正在尝试在 C 中开发内核。我的内核应该显示一个非常简单的欢迎消息。我的引导加载程序的第二阶段将内核加载到0x8000,并将内核移动到0x100000。我的内核由两部分组成。 third_stage.asm
调用os.c
中的主要功能。问题是我一直在 guru meditation 错误。
我的引导程序代码( boot )可以在我以前的StackOverflow question中找到。
我的第二阶段的代码:
org 0x7E00
bits 16
;;;;;;;;;;;;;stack;;;;;;;;;;
Setup:
cli
xor ax , ax
mov ds , ax
mov es , ax
mov ax , 0x9000
mov ss , ax
mov sp , 0x0000
sti
;;;;;;;;;;;;;video;;;;;;;;;;;
Set:
mov al , 03h
mov ah , 00h
int 10h
mov ah , 09h
mov al , 'A'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
jmp loadgdt
;;;;;;;;;;;;gdt;;;;;;;;;;;;;;;
gdt_start:
null:
dd 0
dd 0
code:
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
data:
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
end:
load: dw end - gdt_start -1
dd null
;;;;;;;;;;;;;loadgdt;;;;;;;;;;
loadgdt:
lgdt [load]
;;;;;;;;;;;;A20;;;;;;;;;;;;;;;
A20:
mov ax , 0x2401
int 0x15
jc A20
;;;;;;;;;;;;;floppy;;;;;;;;;;;
Reset:
mov ah , 00h
mov dl , [0x500]
int 13h
jc Reset
Read:
mov ax , 0x800
mov es , ax ; Setup ES=0x800
mov ah , 02h ; Setup AH
mov al , 0fh ; Setup AL
mov ch , 00h
mov cl , 03h
mov dh , 00h
mov dl , [0x500]
xor bx , bx
int 13h
jc Read
Begin:
mov ah , 09h
mov al , 'G'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
;;;;;;;;;;;switching to protected;;;;
protected:
mov ah , 09h
mov al , 'P'
mov bh , 00h
mov bl , 0x0F
mov cx , 01h
int 10h
xor ax, ax
mov ds, ax
cli
mov eax, cr0
or eax , 1
mov cr0 , eax
jmp (code-gdt_start):transfer_control
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bits 32
transfer_control:
mov ax, (data-gdt_start)
mov ds, ax
mov ss, ax
mov es, ax
mov esp, 90000h
mov [0xB8000], word 0x0F58 ; Print 'X'
CopyImage:
mov eax , dword 0x0f
mov ebx , dword 0x200
mul ebx
mov ebx , 4
div ebx
cld
mov esi , 0x8000
mov edi , 0x100000
mov ecx , eax
rep movsd
jmp 0x100000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
times 512-($-$$) db 0
third_stage的代码:
bits 32
global _start
extern main
_start:
mov ax , 0x10
mov ds , ax
mov ss, ax
mov es, ax
mov esp, 90000h
mov [0xB8002], word 0x0F58 ; Print 'X'
call main
hlt
os.c的代码:
//reserved - 0x500(drive number), 0x501(keyboard buffer), 0x502(screen X) , 0x503(screen y)
volatile char * buffer = (volatile char*)0x501 ;
volatile char * x = (volatile char*)0x502 ;
volatile char * y = (volatile char*)0x503 ;
void newline() {
if(*y < 24) {
*y++ ;
*x = 0 ;
}
else {
*y = 25 ;
*x = 80 ;
}
}
void clrscr() {
volatile char * display = (volatile char*)0xb8000 ;
for(display = 0xb8000 ; display <= 0xbffff;display++) {
*display = 0 ;
}
}
void println(char output[]) {
char * x = (char*)0x502 ;
char * y = (char*)0x503 ;
int arg = 0 ;
if(*x == 80 && *y == 25) {
clrscr() ;
*x = 0 ;
*y = 0 ;
}
volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
while(output[arg] != '\0') {
if(*x == 80 && *y == 25) {
clrscr() ;
*x = 0 ;
*y = 0 ;
arg = 0 ;
display = 0xb8000 ;
}
else if(*x == 80) {
*y++ ;
*x = 0 ;
}
*display = output[arg] ;
display++ ;
*display = 0x0f ;
display++ ;
arg++ ;
*x++ ;
}
newline() ;
}
void print(char output[]) {
int arg = 0 ;
if(*x == 80 && *y == 25) {
clrscr() ;
*x = 0 ;
*y = 0 ;
}
volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
while(output[arg] != '\0') {
if(*x == 80 && *y == 25) {
clrscr() ;
*x = 0 ;
*y = 0 ;
arg = 0 ;
display = 0xb8000 ;
}
else if(*x == 80) {
*y++ ;
*x = 0 ;
}
*display = output[arg] ;
display++ ;
*display = 0x0f ;
display++ ;
arg++ ;
*x++ ;
}
}
void printc(char output) {
char * x = (char*)0x502 ;
char * y = (char*)0x503 ;
if(*x == 80 && *y == 25) {
clrscr() ;
*x = 0 ;
*y = 0 ;
}
else if(*x == 80) {
*y++ ;
*x = 0 ;
}
volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
*display = output ;
display++ ;
*display = 0x0f ;
display++ ;
*x++ ;
if(*x == 80) {
*y++ ;
*x = 0 ;
}
}
void backspace() {
if(*x == 0 && *y == 0) {
}
else if(*x == 0) {
*x = 79 ;
*y-- ;
volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
*display = 0 ;
display++ ;
*display = 0 ;
}
else {
*x-- ;
volatile char * display = (volatile char*)0xb8000 + (((*y * 80) + *x) * 2) ;
*display = 0 ;
display++ ;
*display = 0 ;
}
}
char * scanln() {
static char input[512] ;
char scancode[0xd9] ;
char shift_scancode[0xd9] ;
*buffer = 0 ;
int arg = 0 ;
scancode[0x1c] = 'a' ;
scancode[0x32] = 'b' ;
scancode[0x21] = 'c' ;
scancode[0x23] = 'd' ;
scancode[0x24] = 'e' ;
scancode[0x2b] = 'f' ;
scancode[0x34] = 'g' ;
scancode[0x33] = 'h' ;
scancode[0x43] = 'i' ;
scancode[0x3b] = 'j' ;
scancode[0x42] = 'k' ;
scancode[0x4b] = 'l' ;
scancode[0x3a] = 'm' ;
scancode[0x31] = 'n' ;
scancode[0x44] = 'o' ;
scancode[0x4d] = 'p' ;
scancode[0x15] = 'q' ;
scancode[0x2d] = 'r' ;
scancode[0x1b] = 's' ;
scancode[0x2c] = 't' ;
scancode[0x3c] = 'u' ;
scancode[0x2a] = 'v' ;
scancode[0x1d] = 'w' ;
scancode[0x22] = 'x' ;
scancode[0x35] = 'y' ;
scancode[0x1a] = 'z' ;
scancode[0x45] = '0' ;
scancode[0x16] = '1' ;
scancode[0x1e] = '2' ;
scancode[0x26] = '3' ;
scancode[0x25] = '4' ;
scancode[0x2e] = '5' ;
scancode[0x36] = '6' ;
scancode[0x3d] = '7' ;
scancode[0x3e] = '8' ;
scancode[0x46] = '9' ;
scancode[0x0e] = '`' ;
scancode[0x4e] = '-' ;
scancode[0x55] = '=' ;
scancode[0x5d] = '\\' ;
scancode[0x54] = '[' ;
scancode[0x5b] = ']' ;
scancode[0x4c] = ';' ;
scancode[0x52] = '\'' ;
scancode[0x41] = ',' ;
scancode[0x49] = '.' ;
scancode[0x4a] = '/' ;
scancode[0x29] = ' ' ;
shift_scancode[0x1c] = 'A' ;
shift_scancode[0x32] = 'B' ;
shift_scancode[0x21] = 'C' ;
shift_scancode[0x23] = 'D' ;
shift_scancode[0x24] = 'E' ;
shift_scancode[0x2b] = 'F' ;
shift_scancode[0x34] = 'G' ;
shift_scancode[0x33] = 'H' ;
shift_scancode[0x43] = 'I' ;
shift_scancode[0x3b] = 'J' ;
shift_scancode[0x42] = 'K' ;
shift_scancode[0x4b] = 'L' ;
shift_scancode[0x3a] = 'M' ;
shift_scancode[0x31] = 'N' ;
shift_scancode[0x44] = 'O' ;
shift_scancode[0x4d] = 'P' ;
shift_scancode[0x15] = 'Q' ;
shift_scancode[0x2d] = 'R' ;
shift_scancode[0x1b] = 'S' ;
shift_scancode[0x2c] = 'T' ;
shift_scancode[0x3c] = 'U' ;
shift_scancode[0x2a] = 'V' ;
shift_scancode[0x1d] = 'W' ;
shift_scancode[0x22] = 'X' ;
shift_scancode[0x35] = 'Y' ;
shift_scancode[0x1a] = 'Z' ;
shift_scancode[0x45] = ')' ;
shift_scancode[0x16] = '!' ;
shift_scancode[0x1e] = '@' ;
shift_scancode[0x26] = '#' ;
shift_scancode[0x25] = '$' ;
shift_scancode[0x2e] = '%' ;
shift_scancode[0x36] = '^' ;
shift_scancode[0x3d] = '&' ;
shift_scancode[0x3e] = '*' ;
shift_scancode[0x46] = '(' ;
shift_scancode[0x0e] = '~' ;
shift_scancode[0x4e] = '_' ;
shift_scancode[0x55] = '+' ;
shift_scancode[0x5d] = '|' ;
shift_scancode[0x54] = '{' ;
shift_scancode[0x5b] = '}' ;
shift_scancode[0x4c] = ':' ;
shift_scancode[0x52] = '"' ;
shift_scancode[0x41] = '<' ;
shift_scancode[0x49] = '>' ;
shift_scancode[0x4a] = '?' ;
shift_scancode[0x29] = ' ' ;
while(*buffer != 0x5a) {
if(*buffer == 0x12) {
*buffer = 0 ;
if(shift_scancode[(int)*buffer] != 0) {
input[arg] = shift_scancode[(int)*buffer] ;
printc(shift_scancode[(int)*buffer]) ;
*buffer = 0 ;
arg++ ;
}
if(*buffer == 0xf0) {
*buffer = 0 ;
*buffer = 0 ;
}
}
else if(*buffer == 0xf0) {
*buffer = 0 ;
*buffer = 0 ;
}
else if(*buffer == 0x66) {
arg-- ;
if(arg >= 0) {
backspace() ;
}
else {
arg = 0 ;
}
}
else if(scancode[(int)*buffer] != 0) {
input[arg] = scancode[(int)*buffer] ;
printc(scancode[(int)*buffer]) ;
*buffer = 0 ;
arg++ ;
}
}
input[arg] = '\0' ;
*buffer = 0 ;
*buffer = 0 ;
return input ;
}
void main() {
char * x = (char*)0x502 ;
char * y = (char*)0x503 ;
*x = 0 ;
*y = 0 ;
println("------------------------------Welcome to Skull OS------------------------------") ;
println("Boot Successful") ;
}
用于制作操作系统的命令是:
nasm third_stage.asm -f elf -o third_stage.o
gcc -m32 -ffreestanding -c os.c -o os.o
ld -m elf_i386 -o os.bin -Ttext 0x100000 os.o third_stage.o --oformat binary
dd seek=0 if=boot of=os.img
dd seek=1 if=second_stage of=os.img
dd seek=2 if=os.bin of=os.img
dd seek=17 if=/dev/zero of=os.img count=1 bs=512
一开始我尝试将操作系统加载到0x8000,但执行只是中途停止。我的操作系统正在VirtualBox下进行测试。
答案 0 :(得分:4)
第2阶段的一个潜在问题是此代码:
CopyImage:
mov eax , dword 0x0f
mov ebx , dword 0x200
mul ebx
mov ebx , 4
div ebx
DIV EBX通过 EBX 划分 EDX:EAX 中的64位整数。您没有正确初始化 EDX 。 EDX 是 EDX 中的64位数字的高32位: EAX ,因此您可能想要设置 EDX 到0.您可以在计算 EAX 的值后通过添加xor edx, edx
指令来修复它。这将零置于 EDX 中。所以代码看起来像这样:
CopyImage:
mov eax , dword 0x0f
mov ebx , dword 0x200
mul ebx
xor edx, edx ; zero extend EAX into EDX
mov ebx , 4
div ebx
而不是使用 DIV ,你可以将 EAX 向右移2位,这与除以4相同。像shr eax, 2
这样的命令会工作过。但这都是矫枉过正的。汇编程序可以在汇编时计算此值。上面的所有代码都可以简化为这条指令:
mov eax, (0x0f * 0x200)/4
这会将值0x780移动到 EAX 。
我认为您的一个更重要的问题是如何将内核链接到os.bin
。你这样做:
ld -m elf_i386 -o os.bin -Ttext 0x100000 os.o third_stage.o --oformat binary
不幸的是,当使用--oformat binary
时,_start
标签将不会用于确定出现在最终二进制文件中的第一条指令。同样,对象将按照它们出现的顺序由 LD 处理。在您的情况下,os.o third_stage.o
会将代码放在os.o
中的third_stage.o
中的代码之前的二进制文件中。您需要首先显示third_stage.o
中的代码,因为这些是您希望在0x100000处加载的指令。你应该这样做:
ld -m elf_i386 -o os.bin -Ttext 0x100000 third_stage.o os.o --oformat binary
此错误似乎与VirtualBox的Guru Meditation错误有关。如果没有这个修复,我可以重现错误,并且内核确实加载了修复,并说它是成功的启动。