assembly - ruta - ¿Cómo ingreso al modo protegido de 32 bits en el ensamblado NASM?
ruta gacutil exe (1)
La programación de un sistema operativo es una tarea avanzada. Al menos se espera que pueda usar un depurador para encontrar sus propios errores y comprender las cosas básicas. Es posible que desee reconsiderar si tiene todos los requisitos previos para este esfuerzo.
Dicho esto, tienes los siguientes problemas:
- Usted asume que el código está cargado en
0x7c00:0
debido a laorg 0
, pero ese podría no ser el caso. Lo único garantizado es la dirección física. Debe usar un salto lejano a su punto de entrada para queCS
esté configurado correctamente. - Por alguna razón, configura
DS
a0x2000
para que su código no encuentre ningún dato. Debe configurarDS
para que coincida conCS
, o utilizar una anulación deCS
todas partes (no recomendado). - El código de modo protegido asume un segmento basado en cero, lo que a su vez significa que espera que
org 0x7c00
por supuesto, entre en conflicto con su configuración. Deberías cambiar aorg 0x7c00
y segmentos0
. - El segmento de modo de texto VGA está en
0xb8000
no en0xb80000
(uno menos cero). - No tiene los bytes de firma de inicio
0x55 0xaa
al final del sector de inicio.
El código fijo:
[bits 16]
[org 0x7c00]
jmp 0:kernel_start
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
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
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
print:
pusha
mov ah, 14
mov bh, 0
.loop:
lodsb
cmp al, 0
je .done
int 0x10
jmp .loop
.done:
popa
ret
uzenet16 db ''uzenet16'', 0
uzenet32 db ''uzenet32'', 0
kernel_start:
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov si, uzenet16
call print
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x2000
mov esp, ebp
mov ebx, uzenet32
call print32
jmp $
[SECTION signature start=0x7dfe]
dw 0AA55h
Su pregunta actualizada todavía parece estar confundida acerca de dónde se carga el código: usted dice offset 0x2000
pero luego habla sobre Executes the kernel using a far jump jmp 0x2000:0x0000
que es por supuesto incorrecto, porque tiene un cero más en el segmento, y debe ser un salto lejano de cero segmento de todos modos: jmp 0:0x2000
. Aparte de eso, verifique que su código efectivamente está cargado en la memoria en el lugar correcto. Aprende a usar un depurador.
Aquí hay un pequeño sector de arranque que carga el código anterior del segundo sector para dirigirse a 0x2000
. Funciona bien, el problema no está en las cosas de GDT, especialmente si ni siquiera se imprime el mensaje en modo real (tampoco estaba claro al respecto).
[bits 16]
[org 0x7c00]
mov ax, 0201h
mov cx, 0002h
mov dh, 0
mov bx, 0
mov es, bx
mov bx, 2000h
int 13h
jmp 0:2000h
[SECTION signature start=0x7dfe]
dw 0AA55h
Estoy aprendiendo ensamblaje x86, y estoy tratando de hacer un sistema operativo de juguete en NASM, pero no entiendo algunas cosas.
Hice un gestor de arranque que arranca con éxito mi kernel:
- Carga 14 sectores desde el disquete que contiene el archivo kernel;
- Busque un archivo en estos sectores etiquetados
kernel.feo
; - Carga ese archivo en la memoria en el desplazamiento
0x2000
; - Ejecuta el kernel usando un salto de
jmp 0x2000:0x0000
.
Así que tengo el código del kernel ubicado en 0x2000:0
en la memoria. CS
podría estar configurado correctamente debido al uso de un salto lejano. En este código del kernel, quiero ingresar al modo protegido de 32 bits, pero no estoy seguro de cómo funcionan los GDT. Cuando ejecuto el código siguiente en una máquina virtual (QEMU)
, no hago nada.
¡Quiero complacerte por ayudarme a ingresar al modo protegido de 32 bits!
Dicho esto, tienes los siguientes problemas:
- Usted asume que el código está cargado en
0x7c00:0
debido a laorg 0
, pero ese podría no ser el caso. Lo único garantizado es la dirección física. Debe usar un salto lejano a su punto de entrada para queCS
esté configurado correctamente.- Por alguna razón, configura
DS
a0x2000
para que su código no encuentre ningún dato. Debe configurarDS
para que coincida conCS
, o utilizar una anulación deCS
todas partes (no recomendado).- El código de modo protegido asume un segmento basado en cero, lo que a su vez significa que espera que
org 0x7c00
por supuesto, entre en conflicto con su configuración. Deberías cambiar aorg 0x7c00
y segmentos0
.- El segmento de modo de texto VGA está en
0xb8000
no en0xb80000
(uno menos cero).- No tiene los bytes de firma de inicio
0x55 0xaa
al final del sector de inicio.
He corregido estas cosas en mi código:
-
[org 0x0]
se corrige en[org 0x2000]
y los segmentos se establecen en0
; -
DS
se corrige a0
lugar de0x2000
, por lo que ahora coincide conCS
; - El segmento del modo de texto VGA está corregido a
0xb8000
;
Pero el código no funcionará con estas correcciones, debería imprimir dos cadenas pero ¡no hace nada!
Tenga en cuenta que este código de kernel no debe terminar con una firma de inicio 0x55 0xAA
, porque no es un sector de arranque.
Aquí está el código corregido del kernel (que no funciona):
[bits 16]
[org 0x2000]
jmp 0:kernel_start
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0
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
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
print:
mov ah, 14
mov bh, 0
lodsb
cmp al, 0
je .done
int 0x10
jmp print
.done:
ret
uzenet_real db ''uzenet16'', 0
uzenet_prot db ''uzenet32'', 0
kernel_start:
mov ax, 0
mov ss, ax
mov sp, 0xFFFC
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov si, uzenet_real
call print
cli
lgdt[gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:b32
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print32:
pusha
mov edx, VIDEO_MEMORY
.loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je .done
mov [edx], ax
add ebx, 1
add edx, 2
jmp .loop
.done:
popa
ret
b32:
mov ax, DATA_SEG
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov ebp, 0x90000
mov esp, ebp
mov ebx, uzenet_prot
call print32
jmp $