bootloader从硬盘装载启动的试验


  
读京山游侠《使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码》一文之后,进行了从硬盘载入系统的试验。
参照的是这篇网文
试验在bochs下以硬盘启动通过:(环境为Ubuntu18(64bit),apt-get install bochs bochs-x hexedit)
mbr.asm( for bochs ):
;mbr程序,加载用户程序
;日期:2020年1月5日


bits 16

LOADER_LBA_START equ 1 ; 用户程序在硬盘的扇区

;SECTION mbr align=16 

;[section .data]
;msg_fail:  db "Fail!",0x0d,0x0a,0

;[section .text align=16] 
SECTION mbr align=16 vstart=0x7c00

global _start

_start:


 ;读取硬盘中的loader
 xor ax, ax ;ax寄存器清零
 mov ss, ax ;堆栈段
 mov sp, ax ;栈顶指针

 mov ax, LOADER_LBA_START ;低16位LBA地址
 push ax
 xor ax, ax; 清零
 push ax ; 高16位地址

 push ax; 偏移地址为0
 mov ax, [boot_loader_memory_start_base_address]
 push ax


call readDataFromHDD




 ; 为了能够验证是否读取了硬盘中的数据
 mov ds, ax
 xor bx, bx
 add bx, 4
 mov cx, [bx]

 jmp  0x1000:0x0
jmp $

 


readDataFromHDD:
 ; 输入参数1 LBA地址低16位
 ; 输入参数2 LBA地址高16位
 ; 输入参数3 目的起始位置的偏移地址
 ; 输入参数4 目的起始位置的段基地址

 push ax
 push bx
 push cx
 push dx
 push ds

 mov dx, 0x1f2 ;硬盘控制命令字
 mov al, 1 ; 读取的扇区数目
 out dx, al
 
 ; 取出参数
 ; 从栈中取出LBA地址低16位
 mov bp, sp
 add bp, 18
 mov ax, [bp]

 inc dx ; 端口 0x1f3
 out dx, al

 inc dx ; 端口自增 0x1f4
 mov al, ah ; 输出只能用al
 out dx, al

 ; 从栈中取出LBA地址高16位
 sub bp, 2
 mov ax, [bp]

 ; 输入高16位地址
 inc dx ; 0x1f5
 out dx, al

 inc dx ; 0x1f6
 mov al, 0xe0 ; LBA28模式,主盘
 or al, ah
 out dx, al

 inc dx ;0x1f7
 mov al, 0x20 ; 读扇区控制命令字
 out dx, al

;=========================================
; 等待硬盘准备阶段
.wait:
 in al, dx ; 读取硬盘是否忙碌状态
 and al, 0x88 ; 只关心这几位
 cmp al, 0x08 ; 比较忙碌标志位是否忙碌
 jnz .wait ; 忙碌则跳转


;=========================================
; 读取数据阶段 
 mov cx, 256 ; 256个字
 mov dx, 0x1f0 ; 硬盘的输出端口

 ; 从栈中获取目标位置的偏移地址
 sub bp, 2
 mov bx, [bp] ; 偏移地址保存到基址寄存器中

 ; 从栈中读取目标位置的段基地址
 sub bp, 2
 mov ax, [bp]
 mov ds, ax

.readw:
; 读取字
 in ax, dx
 mov [bx], ax
 add bx, 2
 loop .readw

 pop ds
 pop dx
 pop cx
 pop bx
 pop ax

ret 5

;boot loader 加载到内存的位置
boot_loader_memory_start_base_address dw  0x1000 ; 将用户程序加载到内存的段基地址

msg:       db "OK!",0x0d,0x0a,0
len      equ 3
len_fail equ 5
DispOK:
   mov ax, msg
   mov bp, ax
   mov cx, len
   mov dh, 0x00
   mov dl, 0x00
   mov ah, 0x13
   mov al, 0x1
   mov bh, 0x00
   
   mov bl, 0x0a
   int 0x10
  ret


;DispFail:
   ;movw ax, msg_fail
   ;movw bp, ax
   ;movw $len_fail, %cx
   ;movb $18, %dh
   ;movb $70, %dl
   ;movb $0x13, %ah
   ;movb $0x1, %al
   ;movb $0x00,%bh
   ;movb $0x0c,%bl
  ;int $0x10
  ;ret



times 510-($-$$) db 0
   db 0x55, 0xaa
 
data2.s( for bochs ):

#bits 16
.code16


#LOADER_LBA_START equ 1 ; 用户程序在硬盘的扇区



.text 

.global _start

_start:

mov %cs, %ax
mov %ax, %ds
mov %ax, %es

call DispFail
jmp .





.set  len,       3
.set  len_fail,   5
#len      equ 3
#len_fail equ 5
#DispOK:
#   mov ax, msg
#   mov bp, ax
#   mov cx, len
#   mov dh, 0x00
#   mov dl, 0x00
#   mov ah, 0x13
#   mov al, 0x1
#   mov bh, 0x00
   
#   mov bl, 0x0a
#   int 0x10
#  ret


DispFail:
   pushw %bp
   movw  %sp, %bp

   pushw %ax
   pushw %bp
   pushw %cx
   pushw %dx
   pushw %bx

   movw  $msg_fail, %ax
   movw  %ax, %bp
   movw $len_fail, %cx
   movb $18, %dh
   movb $70, %dl
   movb $0x13, %ah
   movb $0x1, %al
   movb $0x00,%bh
   movb $0x0c,%bl
   int $0x10

   popw %bx
   popw %dx
   popw %cx
   popw %bp
   popw %ax

   leave
   ret


#msg:       .asciz "OK!"
msg_fail:  .asciz "Fail!"

.org 510
   .word 0xaa55

 
编译脚本如下:
make_HDD.sh(for bochs):
#!/bin/bash


rm -f *.o *.bin *.elf *.out disassem*.asm


nasm -o mbr.bin     mbr.asm
     nasm -f elf32 -o mbr.elf  mbr.asm
     objdump -D -m i8086   mbr.elf  >  disassem1.asm
   as --32 data2.s -o data2.o
   ld  -e _start -Ttext 0x0  -m elf_i386  data2.o   -o  boot.elf
   #ld -e _start -T boot_HDD.lds  -m elf_i386  data2.o   -o  boot.elf
   objcopy -R .pdr -R .comment -R .note -S  -O binary  boot.elf  data2.bin
     objdump -D -m i8086   boot.elf  >  disassem2.asm

dd if=mbr.bin   of=boot_HDD.img bs=512 count=1 conv=notrunc
dd if=data2.bin of=boot_HDD.img bs=512 seek=1 count=1 conv=notrunc

 
运行bochs配置文件如下:
bochsrc_HDD(for bochs):
config_interface: textconfig
#display_library: sdl
#romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
romimage: file=/usr/share/bochs/BIOS-bochs-latest
megs: 32
vgaromimage: file=/usr/share/vgabios/vgabios.bin
#floppya: type=1_44, 1_44="boot.img", status=inserted
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
ata0-master: type=disk, path="boot_HDD.img", mode=flat, cylinders=121, heads=16, spt=63
ata0-slave: type=cdrom, path="/dev/cdrom", status=inserted

boot: disk

#ips: 1000000
floppy_bootsig_check: disabled=0
log: /dev/stdout
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
debugger_log: -
com1: enabled=1, dev=/dev/ttyS0
parport1: enabled=1, file="/dev/lp0"
sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=/dev/stdout, dmatimer=600000
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
#floppy_command_delay: 500
mouse: enabled=1
private_colormap: enabled=0
#ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
#keyboard_mapping: enabled=0, map=/usr/share/bochs/keymaps/x11-pc-de.map
#keyboard_type: mf
#user_shortcut: keys=ctrlaltdel
#magic_break: enabled=1
#cmosimage: cmos.img
#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
#i440fxsupport: enabled=1
#usb1: enabled=1, ioaddr=0xFF80, irq=10
#text_snapshot_check: enable
 
运行命令:bochs -f ./bochsrc_HDD
(虚拟硬盘boot_HDD.img是用bximage生成的60M硬盘。)

至此试验初步就告完成。感谢上面网文作者。
源文件打包在此:test_my_HDD_0.99.tgz

  

More powered by