【发布时间】:2017-12-16 21:46:55
【问题描述】:
我正在尝试学习低级的东西,所以我认为也许学习操作系统的工作原理将是最好的选择,我开始学习: https://github.com/cfenollosa/os-tutorial
这是代码:
main.asm
[org 0x7c00]
mov bp, 0x9000
mov sp, bp
mov bx,0x1000
mov dh,1
call disk_load
call switch_to_pm
%include "print.asm"
%include "gdt.asm"
%include "32print.asm"
%include "32switch.asm"
%include "disk_func.asm"
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
mov eax,0
mov ch,1
mov cl,0
call print_string
mov ch,0
call print_string
mov ebx,MSG_LOADED_Kernel
mov eax,30
mov cl,1
mov ch,0
call print_string
jmp 0x1000
MSG_PROT_MODE db "Test White ... ",0
MSG_LOADED_Kernel db " Test Red ... ",0
; bootsector
times 510-($-$$) db 0
dw 0xaa55
test_load:
mov ebx,MSG_PROMPT
sub ebx,test_load
add ebx,0x1000
mov cl,2
mov ch,0
mov eax,58
call CODE_SEG:print_string
jmp $
MSG_PROMPT db "Test Green ... ",0
times 512-($-test_load) db 0
打印.asm
print:
pusha
mov ah,0x0e
start:
mov al,[bx]
cmp al,0
je done
int 0x10
add bx,1
jmp start
done:
popa
ret
disk_func.asm
disk_load:
pusha
mov ah,0x02 ;<= Read
mov al,dh ;<= Sectors to read
mov cl,0x02 ;<= Sector
mov ch,0x00 ;<= Cylinder
push edx
mov dh,0x00 ;<= Head number
int 0x13
pop edx
jc disk_error
cmp al, dh
jne sectors_error
popa
ret
disk_error:
mov ecx, DISK_ERROR
call print
mov dh, ah
jmp disk_loop
sectors_error:
mov ecx, SECTORS_ERROR
call print
disk_loop:
jmp $
DISK_ERROR:
db "Disk read error", 0
SECTORS_ERROR:
db "Incorrect number of sectors read", 0
gdt.asm
gdt_start:
dd 0x0
dd 0x0
;8 null bytes
; GDT for code segment. base = 0x00000000, length = 0xfffff
gdt_code:
dw 0xffff ; segment length, bits 0-15
dw 0x0 ; segment base, bits 0-15
db 0x0 ; segment base, bits 16-23
db 10011010b ; flags (8 bits)
db 11001111b ; flags (4 bits) + segment length, bits 16-19
db 0x0 ; segment base, bits 24-31
; GDT for data segment. base and length identical to code segment
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_desc:
dw gdt_end - gdt_start - 1 ; size (16 bit)
dd gdt_start ; address (32 bit)
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
32switch.asm
[bits 16]
switch_to_pm:
cli
lgdt [gdt_desc]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:init_pm
[bits 32]
init_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 BEGIN_PM
32print.asm
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
RED_ON_BLACK equ 0x0c
GREEN_ON_BLACK equ 0x0a
print_string:
pusha
cmp cl,1
je skip_print32_red
cmp cl,2
je skip_print32_red
mov cl,0
skip_print32_red:
mov edx, VIDEO_MEMORY
add edx,eax
cmp ch,1
je clear_scrn
print_string_loop:
mov al, [ebx] ; [ebx] is the address of our character
print32_color:
cmp cl,1
je print_with_red
cmp cl,2
je print_with_green
mov ah, WHITE_ON_BLACK
jmp print32_skip_red
print_with_red:
mov ah, RED_ON_BLACK
jmp print32_skip_red
print_with_green:
mov ah, GREEN_ON_BLACK
print32_skip_red:
cmp al, 0 ; check if end of string
je print_string_done
mov [edx], ax ; store character + attribute in video memory
add ebx, 1 ; next char
add edx, 2 ; next video memory position
jmp print_string_loop
print_string_done:
popa
ret
clear_scrn:
mov al, 0x20
mov ah, WHITE_ON_BLACK
mov [edx], ax ; store character + attribute in video memory
add edx, 2 ; next video memory position
cmp edx, 0xb8492
je print_string_done
jmp clear_scrn
make_32print_red:
mov cl, 1
jmp print32_color
在 32switch.asm 文件中,我知道因为 init_pm 以 [bits 32] 开头并使用 32 位寄存器,所以跳转到它需要 CODE_SEG,因为 CODE_SEG 启用 32 位,但我不明白为什么它不需要调用 BEGIN_PM CODE_SEG 因为 BEGIN_PM 也使用 32 位寄存器。还调用 BEGIN_PM 中的 print_string 并跳转到 test_load 也不需要 CODE_SEG 但在 test_load 中必须使用 CODE_SEG 来调用 print_string 否则它不会做任何事情
"test_load 将从 hdd 读取到内存并跳转到 BEGIN_PM 中的 0x1000 是跳转到 test_load"
这真的让我很困惑,有人可以向我解释为什么在这些地方需要它而在其他地方不需要它吗? 还有为什么从 test_load 调用打印字符串需要 CODE_SEG 而从 BEGIN_PM 调用不需要?
我使用 nasm 进行组装,使用 qemu 运行二进制文件
我不熟悉汇编和低级的东西,所以我可能理解错了
编辑: 我试图以某种方式解决它并理解它,我发现在 test_load 如果我这样做了
mov edx,print_string
call edx
它可以工作,但是
call print_string
没有
【问题讨论】:
-
如果你的 cpu 有 32 位寄存器,你也可以在实模式下使用它们。模式开关正在改变内存管理和默认操作数大小。
-
CODE_SEG不“启用 32 位模式”它只是gdt_code - gdt_start的占位符,即它是代码开始位置的偏移量(我认为..)你永远不会跳转到 test_load,所以不知道你的意思是什么? -
@JeffUK :
WithCODE_SEG equ gdt_code - gdt_start,CODE_SEL` 将用作 GDT 的选择器,该选择器指向描述符条目,该条目用于描述内存的可执行区域(连同其他属性)
标签: assembly operating-system memory-segmentation