OS 开发:切换到 32 位模式会破坏我的代码
OS development : switching to 32bit mode breaks my code
编辑:当我将 BITS 32 之后的所有内容移动到 disk_double_error 时,我的问题就解决了,但现在它仍然坏了,是的,它显示消息,但是当我点击 Y 时,它只是 restarts/reboots 系统什么可能是这个原因?
(对不起英语不好)你好我正在尝试写一个简单的 os 只是为了好玩我制作了我的引导加载程序并显示了一些消息并读取了磁盘但是当涉及到切换到 32 位保护时模式我做的所有事情都不起作用它正常显示
`> `
`>succesfully loaded = if loaded succesfully > failed = if not `
`>Do you want to boot kernel mode Y/N then gets input`
`>Booting in kernel mode = if Y null = if no`
但是在我将 lgdt 和其他开关添加到 32 位之后它根本不显示任何东西所以我认为切换是以某种方式清除屏幕所以我尝试在下午用 print_string_pm 功能打印东西但仍然我什么都没用
nasm -fbin bootload.asm -o bootload.bin
编译bootloader
我的代码可能有什么问题请帮忙?
代码如下:
BITS 16
[ORG 0x7c00]
global _boot_start
_boot_start:
cli
mov bx,0x9000
mov bp,bx
mov sp,bx
sti
pusha
mov ax, 0x0000
mov ds, ax
mov es, ax
popa
mov [bootdev], dl
mov bx, MSG_START
call print_string
mov dl, [bootdev]
mov dh, 1
mov bx, 0x1000
call disk_load
mov bx, MSG_YESNO
call print_string
call get_yes_no
mov bx, MSG_BOOT_KERNEL
call print_string
lgdt [gdt_descriptor]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:pm
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
;******************************************************************
print_string:
.loop:
mov al,[bx]
cmp al,0
je return
push bx
mov ah,0Eh
int 10h
pop bx
inc bx
jmp .loop
return:
ret
;******************************************************************
get_yes_no:
pusha
.loop:
mov ah, 00h
int 16h
cmp ah, 15h
je .yes
cmp ah, 31h
je .no
jmp .loop
ret
.no:
mov bx, No
call print_string
mov ah, 00h
int 13h
jmp $
.yes:
mov bx, Yes
call print_string
jmp .done
.done:
popa
ret
;******************************************************************
disk_load:
push dx
mov ah, 02h
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
pop dx
jc disk_error
cmp dh, al
jne disk_error_double
mov bx,MSG_LOAD_SUCC
call print_string
ret
disk_error:
mov bx,MSG_LOAD_FAIL
call print_string
jmp $
disk_error_double:
mov bx,MSG_LOAD_FAIL_C
call print_string
jmp $
;******************************************************************
print_string_pm :
pusha
mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem.
.print_string_pm_loop :
mov al , [ ebx ] ; Store the char at EBX in AL
mov ah , WHITE_ON_BLACK ; Store the attributes in AH
cmp al , 0 ; if (al == 0), at end of string , so
je .print_string_pm_done ; jump to done
mov [edx], ax ; Store char and attributes at current
; character cell.
add ebx , 1 ; Increment EBX to the next char in string.
add edx , 2 ; Move to next character cell in vid mem.
jmp .print_string_pm_loop ; loop around to print the next char.
.print_string_pm_done :
popa
ret
; Global Descriptor table
; GDT
gdt_start :
gdt_null : ; the mandatory null descriptor
dd 0x0 ; 'dd ' means define double word ( i.e. 4 bytes )
dd 0x0
gdt_code :
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10011010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_data :
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10010010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
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
MSG_START DB ">",13,10,0
MSG_LOAD_SUCC DB "> Succesfully loaded",13,10,0
MSG_LOAD_FAIL DB "> Failed to load Please try to restart the system",13,10,0
MSG_LOAD_FAIL_C DB "> Error while loading",13,10,0
MSG_YESNO DB "> Do you want to boot up in kernel mode Y/N :",0
MSG_BOOT_KERNEL DB 13,10,"> Booting in kernel mode",0
MSG_BOOT_32 DB "32 bit pm",13,10,0
Yes db "Y",0
No db "N",0
bootdev: db 0
KERNEL_OFFSET equ 0x1000
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
times 510-($-$$) db 0
dw 0xaa55
这是我的内核代码:
int kmain()
{
char* vm = 0xb8000;
*vm = 'X';
}
和我的内核条目
[BITS 32]
[extern _kmain]
call _kmain
jmp $
我使用以下几行来构建我的磁盘映像:
nasm -fbin bootload.asm -o bootload.bin
gcc -ffreestanding -c kernel.c -o kernel.o
nasm kernel_entry.asm -f elf -o k_entry.o
ld -T NUL -o kernel.tmp -Ttext 0x1000 k_entry.o kernel.o
objcopy -O binary -j .text kernel.tmp kernel.bin
copy /b bootload.bin+kernel.bin os-image.bin
我将忽略在没有 SS 的情况下设置 SP 的问题和其他问题。请参阅问题下的评论,了解您可以做些什么来清理代码。
您的主要问题是使用 bits 32
切换到 32 位指令编码。一旦您将编码设置为 32 位,之后的所有指令都将被编码为 32 位,直到您更改(使用 bits 16
)。您可以做的最简单的事情是将标签 pm
的代码移动到超过所有 16 位代码的位置。移动所有这些行(删除原来的):
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
到您拥有的 32 位代码的开头。这似乎是 print_string_pm
标签。所以当移动时它看起来像:
[snip]
disk_error_double:
mov bx,MSG_LOAD_FAIL_C
call print_string
jmp $
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
;******************************************************************
print_string_pm :
pusha
[snip]
disk_error_double
的代码是 16 位代码的最后一个,print_string_pm
是 32 位代码的开头。我们只需将 pm
代码放在 disk_error_double
之后和 print_string_pm
.
之前
在进入保护模式之前,您需要关闭中断,直到您设置中断描述符 Table (IDT)。在 mov cr0 , eax
之前放置一个 cli
指令。如果不这样做,将导致三重故障并在保护模式下发生第一个中断时重新启动。
编辑:当我将 BITS 32 之后的所有内容移动到 disk_double_error 时,我的问题就解决了,但现在它仍然坏了,是的,它显示消息,但是当我点击 Y 时,它只是 restarts/reboots 系统什么可能是这个原因?
(对不起英语不好)你好我正在尝试写一个简单的 os 只是为了好玩我制作了我的引导加载程序并显示了一些消息并读取了磁盘但是当涉及到切换到 32 位保护时模式我做的所有事情都不起作用它正常显示
`> `
`>succesfully loaded = if loaded succesfully > failed = if not `
`>Do you want to boot kernel mode Y/N then gets input`
`>Booting in kernel mode = if Y null = if no`
但是在我将 lgdt 和其他开关添加到 32 位之后它根本不显示任何东西所以我认为切换是以某种方式清除屏幕所以我尝试在下午用 print_string_pm 功能打印东西但仍然我什么都没用
nasm -fbin bootload.asm -o bootload.bin
编译bootloader
我的代码可能有什么问题请帮忙?
代码如下:
BITS 16
[ORG 0x7c00]
global _boot_start
_boot_start:
cli
mov bx,0x9000
mov bp,bx
mov sp,bx
sti
pusha
mov ax, 0x0000
mov ds, ax
mov es, ax
popa
mov [bootdev], dl
mov bx, MSG_START
call print_string
mov dl, [bootdev]
mov dh, 1
mov bx, 0x1000
call disk_load
mov bx, MSG_YESNO
call print_string
call get_yes_no
mov bx, MSG_BOOT_KERNEL
call print_string
lgdt [gdt_descriptor]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:pm
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
;******************************************************************
print_string:
.loop:
mov al,[bx]
cmp al,0
je return
push bx
mov ah,0Eh
int 10h
pop bx
inc bx
jmp .loop
return:
ret
;******************************************************************
get_yes_no:
pusha
.loop:
mov ah, 00h
int 16h
cmp ah, 15h
je .yes
cmp ah, 31h
je .no
jmp .loop
ret
.no:
mov bx, No
call print_string
mov ah, 00h
int 13h
jmp $
.yes:
mov bx, Yes
call print_string
jmp .done
.done:
popa
ret
;******************************************************************
disk_load:
push dx
mov ah, 02h
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
pop dx
jc disk_error
cmp dh, al
jne disk_error_double
mov bx,MSG_LOAD_SUCC
call print_string
ret
disk_error:
mov bx,MSG_LOAD_FAIL
call print_string
jmp $
disk_error_double:
mov bx,MSG_LOAD_FAIL_C
call print_string
jmp $
;******************************************************************
print_string_pm :
pusha
mov edx , VIDEO_MEMORY ; Set edx to the start of vid mem.
.print_string_pm_loop :
mov al , [ ebx ] ; Store the char at EBX in AL
mov ah , WHITE_ON_BLACK ; Store the attributes in AH
cmp al , 0 ; if (al == 0), at end of string , so
je .print_string_pm_done ; jump to done
mov [edx], ax ; Store char and attributes at current
; character cell.
add ebx , 1 ; Increment EBX to the next char in string.
add edx , 2 ; Move to next character cell in vid mem.
jmp .print_string_pm_loop ; loop around to print the next char.
.print_string_pm_done :
popa
ret
; Global Descriptor table
; GDT
gdt_start :
gdt_null : ; the mandatory null descriptor
dd 0x0 ; 'dd ' means define double word ( i.e. 4 bytes )
dd 0x0
gdt_code :
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10011010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
gdt_data :
dw 0xffff ; Limit ( bits 0 -15)
dw 0x0 ; Base ( bits 0 -15)
db 0x0 ; Base ( bits 16 -23)
db 10010010b ; 1st flags , type flags
db 11001111b ; 2nd flags , Limit ( bits 16 -19)
db 0x0 ; Base ( bits 24 -31)
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
MSG_START DB ">",13,10,0
MSG_LOAD_SUCC DB "> Succesfully loaded",13,10,0
MSG_LOAD_FAIL DB "> Failed to load Please try to restart the system",13,10,0
MSG_LOAD_FAIL_C DB "> Error while loading",13,10,0
MSG_YESNO DB "> Do you want to boot up in kernel mode Y/N :",0
MSG_BOOT_KERNEL DB 13,10,"> Booting in kernel mode",0
MSG_BOOT_32 DB "32 bit pm",13,10,0
Yes db "Y",0
No db "N",0
bootdev: db 0
KERNEL_OFFSET equ 0x1000
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
times 510-($-$$) db 0
dw 0xaa55
这是我的内核代码:
int kmain()
{
char* vm = 0xb8000;
*vm = 'X';
}
和我的内核条目
[BITS 32]
[extern _kmain]
call _kmain
jmp $
我使用以下几行来构建我的磁盘映像:
nasm -fbin bootload.asm -o bootload.bin
gcc -ffreestanding -c kernel.c -o kernel.o
nasm kernel_entry.asm -f elf -o k_entry.o
ld -T NUL -o kernel.tmp -Ttext 0x1000 k_entry.o kernel.o
objcopy -O binary -j .text kernel.tmp kernel.bin
copy /b bootload.bin+kernel.bin os-image.bin
我将忽略在没有 SS 的情况下设置 SP 的问题和其他问题。请参阅问题下的评论,了解您可以做些什么来清理代码。
您的主要问题是使用 bits 32
切换到 32 位指令编码。一旦您将编码设置为 32 位,之后的所有指令都将被编码为 32 位,直到您更改(使用 bits 16
)。您可以做的最简单的事情是将标签 pm
的代码移动到超过所有 16 位代码的位置。移动所有这些行(删除原来的):
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
到您拥有的 32 位代码的开头。这似乎是 print_string_pm
标签。所以当移动时它看起来像:
[snip]
disk_error_double:
mov bx,MSG_LOAD_FAIL_C
call print_string
jmp $
BITS 32
pm:
mov ax , DATA_SEG
mov ds , ax
mov ss , ax
mov es , ax
mov fs , ax
mov gs , ax
mov ebp , 0x90000
mov esp , ebp
call beg_pm
beg_pm:
mov ebx,MSG_BOOT_32
call print_string_pm
call KERNEL_OFFSET
jmp $
;******************************************************************
print_string_pm :
pusha
[snip]
disk_error_double
的代码是 16 位代码的最后一个,print_string_pm
是 32 位代码的开头。我们只需将 pm
代码放在 disk_error_double
之后和 print_string_pm
.
在进入保护模式之前,您需要关闭中断,直到您设置中断描述符 Table (IDT)。在 mov cr0 , eax
之前放置一个 cli
指令。如果不这样做,将导致三重故障并在保护模式下发生第一个中断时重新启动。