C 内核 - 在 VM 上运行良好但在实际计算机上运行不正常?
C Kernel - Works fine on VM but not actual computer?
我正在制作一个基本的 C 内核。 (由汇编程序加载)我正在使用 windows 的 i686-elf 交叉编译器对其进行编译。我的C代码如下:
void cls();
void drawhappy();
void main(){
char *vidptr = (char *)0xb8000;
cls();
drawhappy();
}
void cls(){
char *vidptr = (char *)0xb8000;
unsigned int j = 0;
while(j < 80*2*25){
vidptr[j] = ' ';
vidptr[j+1] = 0x07;
j = j+2;
}
}
void drawhappy(){
char *vidptr = (char *)0xb8000;
const unsigned int linewidth = 80*2;
vidptr[3] = 0xa7;
vidptr[5] = 0xa7;
vidptr[7] = 0xa7;
vidptr[9] = 0xa7;
vidptr[1+linewidth] = 0xa7;
vidptr[5+linewidth] = 0xa7;
vidptr[7+linewidth] = 0xa7;
vidptr[11+linewidth] = 0xa7;
vidptr[1+linewidth*2] = 0xa7;
vidptr[3+linewidth*2] = 0xa7;
vidptr[5+linewidth*2] = 0xa7;
vidptr[7+linewidth*2] = 0xa7;
vidptr[9+linewidth*2] = 0xa7;
vidptr[11+linewidth*2] = 0xa7;
vidptr[1+linewidth*3] = 0xa7;
vidptr[5+linewidth*3] = 0xa7;
vidptr[7+linewidth*3] = 0xa7;
vidptr[11+linewidth*3] = 0xa7;
vidptr[1+linewidth*4] = 0xa7;
vidptr[11+linewidth*4] = 0xa7;
vidptr[3+linewidth*5] = 0xa7;
vidptr[5+linewidth*5] = 0xa7;
vidptr[7+linewidth*5] = 0xa7;
vidptr[9+linewidth*5] = 0xa7;
}
在 bochs 中,它给了我预期的输出:
如果我使用 bootice 将 bin 文件写入引导扇区并 运行 它作为 virtualbox 上的 VM,它也可以工作。但如果我真的从 USB 记忆棒启动,它就会变得有点疯狂,然后在我的屏幕右下角放一个奇怪的符号。 (没有截图因为我显然不能)我有一个 i7-3770K CPU。为什么会这样?
编辑:这是我的汇编代码:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call load_kernel
call switch_to_pm
jmp $
%include "C:/Users/Aaron/Desktop/CODE_OS/print_string.asm"
; load DH sectors to ES:BX from drive DL
disk_load:
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc disk_error
pop dx
cmp dh, al
jne disk_error
ret
disk_error:
mov bx, DISK_ERROR_MSG
call print_string
jmp $
DISK_ERROR_MSG: db "Disk read error!", 0
%include "C:/Users/Aaron/Desktop/CODE_OS/print_string_pm.asm"
%include "C:/Users/Aaron/Desktop/CODE_OS/switch_to_pm.asm"
; GDT
gdt_start:
gdt_null: ; the mandatory null descriptor
dd 0x0
dd 0x0
gdt_code: ; the code segment descriptor
dw 0xffff ; limit
dw 0x0 ; base
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
[bits 16]
load_kernel:
mov bx, MSG_LOAD_KERNEL
call print_string
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_load
ret
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
call print_string_pm
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
MSG_REAL_MODE db 'Started in 16-bit Real Mode',0
MSG_PROT_MODE db 'Successfully booted to 32-bit Protected Mode',0
MSG_LOAD_KERNEL db "Loading Kernel...",0
times 510-($-$$) db 0 ; Pad the boot sector out with zeros
dw 0xaa55 ; Last two bytes form the magic number
(Print-string.asm只打印字符串,switch_to_pm.asm切换到保护模式,print_string_pm.asm在保护模式下打印字符串。)
您没有初始化段寄存器。尝试将引导扇区的开头更改为如下内容:
xor ax, ax
mov bp, 0x9000
mov ds, ax
mov es, ax
mov ss, ax ; disables interrupts until the end of the next instruction
mov sp, bp
mov [BOOT_DRIVE], dl
我正在制作一个基本的 C 内核。 (由汇编程序加载)我正在使用 windows 的 i686-elf 交叉编译器对其进行编译。我的C代码如下:
void cls();
void drawhappy();
void main(){
char *vidptr = (char *)0xb8000;
cls();
drawhappy();
}
void cls(){
char *vidptr = (char *)0xb8000;
unsigned int j = 0;
while(j < 80*2*25){
vidptr[j] = ' ';
vidptr[j+1] = 0x07;
j = j+2;
}
}
void drawhappy(){
char *vidptr = (char *)0xb8000;
const unsigned int linewidth = 80*2;
vidptr[3] = 0xa7;
vidptr[5] = 0xa7;
vidptr[7] = 0xa7;
vidptr[9] = 0xa7;
vidptr[1+linewidth] = 0xa7;
vidptr[5+linewidth] = 0xa7;
vidptr[7+linewidth] = 0xa7;
vidptr[11+linewidth] = 0xa7;
vidptr[1+linewidth*2] = 0xa7;
vidptr[3+linewidth*2] = 0xa7;
vidptr[5+linewidth*2] = 0xa7;
vidptr[7+linewidth*2] = 0xa7;
vidptr[9+linewidth*2] = 0xa7;
vidptr[11+linewidth*2] = 0xa7;
vidptr[1+linewidth*3] = 0xa7;
vidptr[5+linewidth*3] = 0xa7;
vidptr[7+linewidth*3] = 0xa7;
vidptr[11+linewidth*3] = 0xa7;
vidptr[1+linewidth*4] = 0xa7;
vidptr[11+linewidth*4] = 0xa7;
vidptr[3+linewidth*5] = 0xa7;
vidptr[5+linewidth*5] = 0xa7;
vidptr[7+linewidth*5] = 0xa7;
vidptr[9+linewidth*5] = 0xa7;
}
在 bochs 中,它给了我预期的输出:
编辑:这是我的汇编代码:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call load_kernel
call switch_to_pm
jmp $
%include "C:/Users/Aaron/Desktop/CODE_OS/print_string.asm"
; load DH sectors to ES:BX from drive DL
disk_load:
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc disk_error
pop dx
cmp dh, al
jne disk_error
ret
disk_error:
mov bx, DISK_ERROR_MSG
call print_string
jmp $
DISK_ERROR_MSG: db "Disk read error!", 0
%include "C:/Users/Aaron/Desktop/CODE_OS/print_string_pm.asm"
%include "C:/Users/Aaron/Desktop/CODE_OS/switch_to_pm.asm"
; GDT
gdt_start:
gdt_null: ; the mandatory null descriptor
dd 0x0
dd 0x0
gdt_code: ; the code segment descriptor
dw 0xffff ; limit
dw 0x0 ; base
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
[bits 16]
load_kernel:
mov bx, MSG_LOAD_KERNEL
call print_string
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_load
ret
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
call print_string_pm
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
MSG_REAL_MODE db 'Started in 16-bit Real Mode',0
MSG_PROT_MODE db 'Successfully booted to 32-bit Protected Mode',0
MSG_LOAD_KERNEL db "Loading Kernel...",0
times 510-($-$$) db 0 ; Pad the boot sector out with zeros
dw 0xaa55 ; Last two bytes form the magic number
(Print-string.asm只打印字符串,switch_to_pm.asm切换到保护模式,print_string_pm.asm在保护模式下打印字符串。)
您没有初始化段寄存器。尝试将引导扇区的开头更改为如下内容:
xor ax, ax
mov bp, 0x9000
mov ds, ax
mov es, ax
mov ss, ax ; disables interrupts until the end of the next instruction
mov sp, bp
mov [BOOT_DRIVE], dl