После нескольких месяцев исследований я выполнил свою задачу по переходу на 32-битный режим, теперь мне было интересно, смогу ли я go вернуться назад, следуя: Страница реального режима OSDevWiki Мне нужен 16-битный селектор данных защищенного режима, но я не знаю, как его сделать. Может кто-нибудь сказать мне, как?
Код:
bootloader.asm:
; A boot sector that enters 32-bit protected mode.
[org 0x7c00]
mov bp, 0x9000 ; Set the stack.
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call switch_to_pm
jmp $
%include "print_string.asm"
%include "gdt.asm"
%include "print_string_pm.asm"
%include "switch_to_pm.asm"
[bits 32]
; This is where we arrive after switching to and initialising protected mode.
BEGIN_PM:
mov ebx , MSG_PROT_MODE
call print_string_pm ; Use our 32-bit print routine.
jmp $ ; Hang.
; Global variables
MSG_REAL_MODE db "Started in 16-bit Real Mode",
MSG_PROT_MODE db "Successfully landed in 32-bit Protected Mode", 0
; Bootsector padding
times 510-($-$$) db 0
dw 0xaa55
switch_to_pm.asm:
[bits 16]
; Switch to protected
switch_to_pm:
cli ; We must switch of interrupts until we have
; set -up the protected mode interrupt vector
; otherwise interrupts will run riot.
lgdt [gdt_descriptor] ; Load our global descriptor table , which defines
; the protected mode segments (e.g. for code and data)
mov eax , cr0 ; To make the switch to protected mode , we set
or eax , 0x1 ; the first bit of CR0 , a control register
mov cr0 ,eax
jmp CODE_SEG:init_pm ; Make a far jump (i.e. to a new segment) to our 32-bit
; code. This also forces the CPU to flush its cache of
; pre -fetched and real -mode decoded instructions , which can
; cause problems.
[bits 32]
; Initialise registers and the stack once in PM.
init_pm:
mov ax, DATA_SEG ; Now in PM, our old segments are meaningless ,
mov ds, ax ; so we point our segment registers to the
mov ss, ax ; data selector we defined in our GDT
mov es, ax
mov fs, ax
mov gs, ax
mov ebp , 0x90000 ; Update our stack position so it is right
mov esp , ebp ; at the top of the free space.
call BEGIN_PM ; Finally , call some well -known label
GDT.asm:
; GDT
gdt_start:
gdt_null: ; the mandatory null descriptor
dd 0x0 ; ’dd’ means define double word (i.e. 4 bytes)
dd 0x0
gdt_code: ; the code segment descriptor
; base=0x0, limit=0xfffff ,
; 1st flags: (present )1 (privilege )00 (descriptor type)1 -> 1001b
; type flags: (code)1 (conforming )0 (readable )1 (accessed )0 -> 1010b
; 2nd flags: (granularity )1 (32-bit default )1 (64-bit seg)0 (AVL)0 -> 1100b
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: ;the data segment descriptor
; Same as code segment except for the type flags:
; type flags: (code)0 (expand down)0 (writable )1 (accessed )0 -> 0010b
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: ; The reason for putting a label at the end of the
; GDT is so we can have the assembler calculate
; the size of the GDT for the GDT decriptor (below)
; GDT descriptior
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; Size of our GDT , always less one
; of the true size
dd gdt_start ; Start address of our GDT
; Define some handy constants for the GDT segment descriptor offsets , which
; are what segment registers must contain when in protected mode. For example ,
; when we set DS = 0x10 in PM , the CPU knows that we mean it to use the
; segment described at offset 0x10 (i.e. 16 bytes) in our GDT , which in our
; case is the DATA segment (0x0 -> NULL; 0x08 -> CODE; 0x10 -> DATA)
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
print_string_pm.asm:
[bits 32]
; Define some constants
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
; prints a null -terminated string pointed to by EDX
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 ; Return from the function
print_string.asm:
[bits 16]
print_string: ; Routine: output string in SI to screen
mov si, bx ; Put string position into SI
mov ah, 0Eh ; int 10h 'print char' function
repeat_loop:
lodsb ; Get character from string
cmp al, 0
je print_string_done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp repeat_loop
print_string_done :
popa
ret ; Return from the function