因此,我構建了一個簡單的操作系統,並且在從引導扇區調用內核代碼時遇到上述錯誤。我花了幾天的時間掙扎,仍然處於死衚衕。load_seg_reg(ES,0xfffc):嘗試從引導扇區運行內核代碼時出現無效段
代碼在調用KERNEL_OFFSET時失敗。我知道它的失敗,因爲我試圖跳到一個無效的部分,但我不知道如何以及在哪裏。 我也注意到它並不是真的讀取磁盤。我的load_kernel代碼要求讀取10個扇區,但似乎只有讀取。 該程序能夠進入保護模式,並能夠加載我需要從磁盤加載的內容,儘管加載行爲很奇怪。
我也顯示我的生成文件,因爲我懷疑也許我沒有正確地鏈接的東西。我正在運行OSX btw所以idk,如果shell命令即時使用是正確的。
我已經在這幾天了,任何幫助將不勝感激。由於
boot_sector
;
; A simple boot sector program.
; BIOS stores the boot drive in DL
;
[org 0x7c00]
[bits 16]
mov [BOOT_DRIVE], dl ; Move boot drive info to memory.
; Setup stack to a position we know is free.
mov bp, 0x9000
mov sp, bp
; Output a nice message.
mov dx, REAL_MODE_MSG
call PrintString16
; Load the kernel.
mov dx, [BOOT_DRIVE]
call LoadKernel
mov dx, LOADED_KERNEL_MSG
call PrintString16
; Switch to protected mode.
; Note, we never break from Protected mode.
call SwitchToProtectedMode
jmp $
; Including some useful routines.
%include "string_utils_16.s"
%include "gdt.s"
%include "string_utils.s"
%include "load_kernel.s"
%include "switch_to_pm.s"
[bits 32]
BeginProtectedMode:
mov edx, PROT_MODE_MSG
call PrintString
; This call should, theoritecally, run the instructions we just loaded.
; AKA, the C code.
; KERNEL_OFFSET is defined in load_kernel.s
call KERNEL_OFFSET
jmp $
BOOT_DRIVE db 0
LOADED_KERNEL_MSG db "Loaded kernel with no errors!", 0
REAL_MODE_MSG db "Welcome! Started in 16-bit Real Mode!", 0
PROT_MODE_MSG db "Now running in 32-bit Protected Mode", 0
times 510 -($ - $$) db 0
dw 0xaa55
switch_to_pm
[bits 16]
SwitchToProtectedMode:
cli
lgdt [gdt_descriptor]
; To actually switch to 32 bit mode, set LSB of cr0 to 1
; Can't touch the cr0 register directly so gotta do it the hard way.
mov eax, cr0
or eax, 0x1
mov cr0, eax
; Technically, after that last move instruction, we're in 32 bit mode BUT
; the CPU may have been doing work in between all this, since, the CPU can do
; certain things in parallel if its got different circuitry to do those things,
; which it probably does. Few of the things the CPU could do in parallel is
; fetch, decode and execute. We dont want the CPU to be fetching the next
; instruction while our stuff is happening (those next things that will be
; fetched probably wont work in 32 bit mode) and we want it to finish whatever
; it is currently executing. so, we're going to do a far jump to
; somewhere so that the CPU cannot make any extrapolations on what to fetch next
; and anything being executed can finish executing.
jmp CODE_SEGMENT:init_pm
[bits 32]
; Initialize segment registers. In 32 bit mode, they all point to an entry in
; the GDT.
init_pm:
mov ax, DATA_SEGMENT
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
; Define the stack somewhere we're sure has free memory.
mov ebp, 0x90000
mov esp, ebp
call BeginProtectedMode
load_kernel
[bits 16]
KERNEL_OFFSET equ 0x1000
; Will load the kernel into memory.
; dl will contain the boot drive.
LoadKernel:
push dx ; Save the boot drive info
mov dx, LOAD_KERNEL_MSG
call PrintString16
pop dx ; Get it back. DL contains boot drive.
mov bx, KERNEL_OFFSET ; Where we want kernel to be loaded to.
mov dh, 10 ; How many sectors to load
; dl is also a parameter but we already have it.
call LoadFromDisk
ret
%include "disk_load.s"
LOAD_KERNEL_MSG db "Loading kernel...", 0
內核
// Simple kernel.
#include "screen.h"
void main() {
print("It worked!");
// char* video = (char*) 0xb800;
// video[0] = 'S';
}
的makefile
INCLUDE = include/
# List is expanded when used not when declared.
OBJECTS = $(wildcard temp/*.o)
# -------------------- Build the os_image
os_image.bin : temp/boot_sect.bin temp/kernel.bin
cat temp/boot_sect.bin temp/kernel.bin > os_image.bin
# -------------------- Build the boot sector image
temp/boot_sect.bin : boot/boot_sect.s
nasm boot/boot_sect.s -i boot/ -f bin -o temp/boot_sect.bin
# -------------------- Build kernel image
temp/kernel.bin : kernel.o kernel_entry.o
clang -ffreestanding -m32 kernel_entry.o $(OBJECTS) kernel.o -o temp/kernel.bin
# -------------------- Build object files
kernel.o : kernel/kernel.c temp/screen.o
clang -ffreestanding -m32 -c -I $(INCLUDE) kernel/kernel.c -o kernel.o
kernel_entry.o : kernel/kernel_entry.s
nasm -f macho -o kernel_entry.o kernel/kernel_entry.s
# -------------------- Build driver objects
temp/screen.o : include/screen.h drivers/screen.c temp/low_level.o
clang -ffreestanding -m32 -c -I $(INCLUDE) drivers/screen.c -o temp/screen.o
temp/low_level.o : include/low_level.h kernel/low_level.c
clang -ffreestanding -m32 -c -I $(INCLUDE) kernel/low_level.c -o temp/low_level.o
clean :
rm *.o
rm ./temp/*.o
rm ./temp/*.bin
rm *.bin
相關Bochs的控制檯轉儲
00014040953i[BIOS ] Booting from 0000:7c00
00014479618i[FDD ] partial read() on floppy image returns 172/512
00014561257i[MEM0 ] allocate_block: block=0x10 used 0x3 of 0x20
00014561312e[CPU0 ] load_seg_reg(ES, 0xfffc): invalid segment
00014561312e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00014561312e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00014561312i[CPU0 ] CPU is in protected mode (active)
00014561312i[CPU0 ] CS.mode = 32 bit
00014561312i[CPU0 ] SS.mode = 32 bit
00014561312i[CPU0 ] EFER = 0x00000000
00014561312i[CPU0 ] | EAX=0008fffc EBX=00001000 ECX=00090003 EDX=ffff0136
00014561312i[CPU0 ] | ESP=0008fff8 EBP=00090003 ESI=000e0000 EDI=00007d2d
00014561312i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf AF pf CF
00014561312i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00014561312i[CPU0 ] | CS:0008(0001| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | DS:0010(0002| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | SS:0010(0002| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | ES:0010(0002| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | FS:0010(0002| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | GS:0010(0002| 0| 0) 00000000 ffffffff 1 1
00014561312i[CPU0 ] | EIP=0000107c (0000107c)
00014561312i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00014561312i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[14561312] [0x000000000000107c] 0008:000000000000107c (unk. ctxt): pop es ; 07
00014561312e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting