assembly x86-16 bootloader osdev bochs
0.6beta3

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: