assembly - Habilite el gestor de arranque para cargar el segundo sector de un USB
x86-16 bootloader (1)
Estoy aprendiendo el lenguaje ensamblador. Escribí un gestor de arranque simple. Después de probarlo, no funcionó. Aquí está mi código:
[bits 16]
[org 0x7c00]
jmp start
data:
wolf_wel_msg db ''Welcome to Bootloader!!!'',0x0D,0x0A,0
wolf_kernel_load db ''Loading kernel....'',0x0D,0x0A,0
wolf_error_msg db ''Kernel.bin not found!'',0x0D,0x0A,0
wolf_error_msg1 db ''Press any key to restart..'',0
start:
mov si, wolf_wel_msg
call wolf_print
mov si, wolf_kernel_load
call wolf_print
pushf
stc
mov ah,00
mov dl,00
int 13h
read_sector:
mov ax, 0x0
mov es, ax
xor bx, bx
mov ah, 02
mov al, 01
mov ch, 01
mov cl, 02
mov dh, 00
mov dl, 00
int 13h
jc wolf_error
popf
jmp 0x0:0x1000
cli
hlt
wolf_error:
mov si, wolf_error_msg
call wolf_print
mov si, wolf_error_msg1
call wolf_print
mov ah,00
int 16h
xor ax,ax
int 19h
wolf_print:
lodsb
or al,al
jz exit
mov ah,0x0e
int 10h
jmp wolf_print
exit:
ret
times 510-($-$$) db 0
dw 0xAA55
Este código se coloca en el primer sector del USB usando este comando:
dd if=f:/boot.bin of=//./d: bs=512 count=1
Se carga un programa simple en el segundo sector del USB usando este comando:
dd if=f:/hello.bin of=//./d: bs=512 seek=1 count=1
Este es el código del programa cargado en el segundo sector:
[bits 16]
[org 0x1000]
jmp start
data:
msg db ''Hello'',0
start:
mov si, msg
jmp print
cli
hlt
print:
lodsb
or al, al
jz exit
mov ah,0x0e
int 10h
jmp print
exit:
ret
¿Por qué mi cargador de arranque no funciona? ¿Hice algo malo? ¿Alguna sugerencia?
Su código asume que DS está configurado en 0. No puede asumir eso. La primera parte de su código debe establecer explícitamente DS en 0 si está utilizando org 0x7c00
.
Deberías considerar seriamente definir tu pila configurando SS: SP . No sabe dónde está el existente o si es lo suficientemente grande como para manejar lo que pretende hacer.
Justo antes de que se llame al gestor de arranque, el BIOS configurará el registro DL con el número de dispositivo de arranque. No debe establecer DL en 0 en su código al realizar solicitudes de unidad desde la unidad de arranque. Debería utilizar el valor que existía en DL cuando se llamó a su gestor de arranque.
Debe usar la instrucción CLD para borrar el indicador de dirección ya que está usando la instrucción LODSB esperando avanzar en la memoria. No hay garantía de que el indicador de dirección esté correctamente configurado, por lo que debe establecerlo explícitamente en la dirección que necesite con CLD (avance) o STD (hacia atrás).
Tengo más información sobre los problemas anteriores en mi respuesta de con las sugerencias generales de Bootloader .
Como no está utilizando un BPB , le recomiendo eliminar el jmp start
como la primera instrucción de su gestor de arranque. En su lugar, mueva los datos después del código pero antes de la firma del sector de arranque ( 0xAA55
). La razón de esto es que algunos BIOS intentarán encontrar un BPB basado en una instrucción JMP que aparezca como la primera instrucción del gestor de arranque, y si se encuentra sobreescribe partes de su gestor de arranque en la memoria causando un comportamiento potencialmente indefinido.
Su gestor de arranque usa esta instrucción para iniciar su segunda etapa cargada desde el segundo sector:
jmp 0x0:0x1000
El problema es que cuando lees el sector configurando ES: BX de esta manera:
read_sector:
mov ax, 0x0
mov es, ax
xor bx, bx
Esto establece ES: BX a 0x0000: 0x0000, que claramente no es donde su JMP espera que el código sea. Debe configurar ES: BX en la ubicación de la memoria en la que desea que INT 13 / AH = 02h lea los sectores del disco.
INT 13h / AH = 02h requiere que el Cilindro / Cabezal / Número de Sector se configure correctamente. Los sectores comienzan a numerar en 1, pero los Cilindros y Cabezales están basados en cero. El segundo sector del disco está en Cilindro 0, Cabecera 0, Sector 2. Su código establece Cilindro a 1 en lugar de 0. Este código es incorrecto ya que realmente debería establecerlo en 0:
mov ch, 01
En su segunda etapa, creó la print
como una función, ya que termina con una instrucción RET
. jmp print
debe cambiarse para call print
.
Con todos los cambios recomendados anteriormente, incluidos los de mis sugerencias generales de cargador de arranque, su código podría modificarse para que sea:
boot.asm
[bits 16]
[org 0x7c00]
; Use the boot drive number passed to us by BIOS in register DL
start:
xor ax,ax ; We want a segment of 0 for DS for this question
mov ds,ax ; Set AX to appropriate segment value for your situation
mov es,ax ; In this case we''ll default to ES=DS
mov bx,0x8000 ; Stack segment can be any usable memory
mov ss,bx ; This places it with the top of the stack @ 0x80000.
mov sp,ax ; Set SP=0 so the bottom of stack will be @ 0x8FFFF
cld ; Set the direction flag to be positive direction
mov si, wolf_wel_msg
call wolf_print
mov si, wolf_kernel_load
call wolf_print
pushf
stc
mov ah,00
int 13h
read_sector:
mov ax, 0x0
mov es, ax ; ES = 0
mov bx, 0x1000 ; BX = 0x1000. ES:BX=0x0:0x1000
; ES:BX = starting address to read sector(s) into
mov ah, 02 ; Int 13h/AH=2 = Read Sectors From Drive
mov al, 01 ; Sectors to read = 1
mov ch, 00 ; CH=Cylinder. Second sector of disk
; is at Cylinder 0 not 1
mov cl, 02 ; Sector to read = 2
mov dh, 00 ; Head to read = 0
; DL hasn''t been destroyed by our bootloader code and still
; contains boot drive # passed to our bootloader by the BIOS
int 13h
jc wolf_error
popf
jmp 0x0:0x1000
cli
hlt
wolf_error:
mov si, wolf_error_msg
call wolf_print
mov si, wolf_error_msg1
call wolf_print
mov ah,00
int 16h
xor ax,ax
int 19h
wolf_print:
lodsb
or al,al
jz exit
mov ah,0x0e
int 10h
jmp wolf_print
exit:
ret
; Moved the data before the boot signature but after the code
wolf_wel_msg db ''Welcome to Bootloader!!!'',0x0D,0x0A,0
wolf_kernel_load db ''Loading kernel....'',0x0D,0x0A,0
wolf_error_msg db ''Kernel.bin not found!'',0x0D,0x0A,0
wolf_error_msg1 db ''Press any key to restart..'',0
times 510-($-$$) db 0
dw 0xAA55
hello.asm
[org 0x1000]
jmp start
data:
msg db ''Hello'',0
start:
mov si, msg
call print ; print is a function, use CALL instead of JMP
cli
hlt
print:
lodsb
or al, al
jz exit
mov ah,0x0e
int 10h
jmp print
exit:
ret
Dado que parece que está utilizando Windows según la información proporcionada en su comando DD , es posible que se encuentre con otro problema. No sé qué DD está utilizando pero of=//./d:
no escribe al principio del disco (unidad USB), escribirá en la partición en la que D: reside, no al principio de el disco en sí
Te recomiendo que uses el último DD de Chrysocome . A partir de hoy, el último es 0.6beta3 . Recomiendo esta versión porque te permite acceder correctamente al disco (o memoria USB) relativo al comienzo de la unidad, no relativo al comienzo de una partición en particular. Esto podría causar serios problemas al tratar de almacenar el 1er y 2do sector adecuadamente. Con la última versión usaría estos comandos con privilegios de administrador para escribir en la unidad USB:
dd if=f:/boot.bin od=d: bs=512 count=1
dd if=f:/hello.bin od=d: bs=512 seek=1 count=1
Esto supone que su unidad USB está en la Unidad D: como se sugiere en su pregunta. ADVERTENCIA: ¡Si no se utiliza la unidad correcta, es posible que se pierdan datos y se dañen en otro dispositivo!
Si estos comandos funcionan correctamente, la salida debería verse de la siguiente manera:
dd if=boot.bin od=d: bs=512 count=1 rawwrite dd for windows version 0.6beta3. Written by John Newbigin <[email protected]> This program is covered by terms of the GPL Version 2. Device d: is a link to //?/Device/HarddiskVolume5 //?/Device/HarddiskVolume5 is a partition on /Device/Harddisk1 512 100% 1+0 records in 1+0 records out dd if=hello.bin od=d: bs=512 seek=1 count=1 rawwrite dd for windows version 0.6beta3. Written by John Newbigin <[email protected]> This program is covered by terms of the GPL Version 2. Device d: is a link to //?/Device/HarddiskVolume5 //?/Device/HarddiskVolume5 is a partition on /Device/Harddisk1 28 5% 0+1 records in 0+1 records out
Una vez que haya emitido estos comandos, Windows puede detectar automáticamente que la unidad ya no está formateada correctamente. No permita que Windows formatee la unidad. Si permite formatear la unidad, la volverá a particionar y formateará. Al hacerlo, destruirá el sector de arranque que usted escribió. Cuando se le solicite, simplemente cancele el cuadro de diálogo de formato que puede aparecer.
Recuerde desmontar / expulsar correctamente su unidad USB antes de extraerla de su sistema. Si no se desmonta correctamente, es posible que los datos no se escriban correctamente / por completo en la unidad.
Si desea crear una imagen de disco para Bochs, QEMU, DOSbox, etc., podría crear un disquete de 720k con estos comandos en un símbolo del sistema:
dd if=/dev/zero of=disk.img bs=1024 count=720
dd if=f:/boot.bin of=disk.img bs=512 count=1 conv=notrunc
dd if=f:/hello.bin of=disk.img bs=512 seek=1 count=1 conv=notrunc
El archivo de imagen disk.img
debe ser utilizado por Bochs, QEMU, DOSbox, etc. o escrito en un disquete de 720k para su uso en una computadora real.
/dev/zero
parece un dispositivo Unix / Linux típico. El comando DD para Windows que sugerí que utiliza entiende /dev/zero
como un dispositivo de entrada especial que solo genera ceros. Windows no tiene dispositivo /dev/zero
, pero DD lo ve como un dispositivo interno especial y lo simula.
Cuando se ejecuta con Bochs 2.6.8 en MS Windows, esto es lo que vi:
En mi computadora portátil Lenovo L520 (que no es EFI BIOS) con una memoria USB de 16 GB, esto es lo que vi: