自制能使用U盘引导的程序(二)

有了前面的基础铺垫,下面就要开始写代码了。

开发环境是Ubuntu,理由是Win7下面没有类似于dd的好用的绝对扇区写入工具,Win7由于一些安全方面的限制,自己编写程序写U盘MBR总是失败,可能是我水平太菜了吧^_^


二、要写入U盘MBR的程序boot.asm

这段代码的功能就是加载kernel.bin到地址0x7e00处,然后跳转到0x7e00。写这段程序,还是乖乖的使用汇编吧。也就那么四百来个字节。

    ; boot.bin max size is 440

    org 07c00h
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov ax, 0x7c00
    mov sp, ax

    call LoadKernel

    jmp $

LoadKernel:
    mov ax, [0x7c00+0x1c6]          ;store first sector No of partition
    mov word [PartitionStartSect], ax

    mov cx, 1                       ;read first sector of partition to 0x7e00
    mov bx, 0x7e00
    mov dx, 0
    mov si, DiskAddressPacket
    call ReadSects

    mov al, byte [0x7e00+0x0d]      ;store number of sectors per cluster
    mov byte [SectorsPerCluster], al
    mov ax, word [0x7e00+0x0e]      ;store number of reserved sectors
    mov word [ReservedSectors], ax
    mov al, byte [0x7e00+0x10]      ;store number of FAT table
    mov byte [FatNumber], al
    mov ax, word [0x7e00+0x24]      ;store number of sectors per FAT table
    mov word [SectorsPerFat], ax

    mov bh, 0                       ;calculate the sector No of data area
    mov bl, [FatNumber]
    mul bx
    add ax, [ReservedSectors]
    add ax, [PartitionStartSect]
    mov word [SectIndexOfData], ax

    mov bx, 0x7e00                  ;read a cluster from data area to 0x7e00
    mov ch, 0
    mov cl, [SectorsPerCluster]
    mov dx, 0
    call ReadSects
                                     
    call GetKernelFirstCluster      ;search for kernel name and get the first cluster No in data area

    cmp dx, 0                       ;if or not success
    jnz failed_to_load
    
    sub ax, 2                       ;if success, calculate the sector No of kernel and read it to RAM(only 4KB)
    mov bh, 0
    mov bl, [SectorsPerCluster]
    mul bx
    add ax, word [SectIndexOfData]
    mov bx, 0x7e00
    call ReadSects

    jmp 0x7e00
   
failed_to_load:
    mov bp, FailedMsg
    mov cx, FailedMsgEnd-FailedMsg
    call DispStr
    ret

;read sectors function
;Input:
;1. Disk Address Packet pointer, ds:si
;2. Disk sector offset low 16 bits, ax
;3. Disk sector offset high 16 bits, dx
;4. number of sectors to read, cx
;5. buffer of data read, ds:bx
ReadSects:
    push ax
    push dx
    mov word [si + 2], cx
    mov word [si + 4], bx
    mov word [si + 8], ax
    mov word [si + 10],dx
    mov ax, 0x4200
    mov dx, 0x80
    int 13h
    pop dx
    pop ax
    ret

;Search for kernel
;Output:
;1. find kernel file or not(0 for success, 1 for failed), dx
;2. low 16 bits of first cluster, ax
GetKernelFirstCluster:
    push bx
    push si
    push di
    push cx
    mov cx, 128 ;FAT32 Directory entrys of one cluster
travel_entry:
    push cx
    xor si, si
    mov cx, 11  ;file name length
    xor di, di
strcmp:
    mov al, [bx+si]
    cmp al, [KernelName+di]
    jnz break
    inc si
    inc di
    loop strcmp
    mov dx, 0
    add bx, 0x1a
    mov ax, [bx]
    pop cx
    jmp complete
break:
    add bx, 32  ;size of directory entry
    pop cx
    loop travel_entry
    mov dx, 1
complete:
    pop cx
    pop di
    pop si
    pop bx
    ret

;Display a character
;Input:
;1. Charater to display, al
DispChar:
    push ax
    push bx
    mov ah, 0x0e
    mov bx, 0x000c
    int 10h
    pop bx
    pop ax
    ret

;Display a string
;Input:
;1. Pointer to string, bp
;2. string length, cx
DispStr:
    push ax
    push cx
    push bp
dc:
    mov al, [bp]
    call DispChar
    inc bp
    loop dc

    pop bp
    pop cx
    pop ax
    ret

PartitionStartSect  dw 0
SectorsPerCluster   db 0
ReservedSectors     dw 0
FatNumber           db 0
SectorsPerFat       dd 0
SectIndexOfData     dw 0

KernelName          db "KERNEL  BIN"
FailedMsg           db "failed to load kernel..."
FailedMsgEnd:

DiskAddressPacket:
    db 16   ;packet size
    db 0    ;reserved
    dw 0    ;block count(sector)
    dw 0    ;buffer offset
    dw 0    ;buffer segment address
    dw 0    ;block number
    dw 0
    dw 0
    dw 0


这个程序要说明的是,我使用扩展int 13h bios中断来读取U盘扇区的。

编译方式 nasm boot.asm -o boot.bin,编译出来的boot.bin不能超过440字节

写入MBR dd if=boot.bin of=/dev/sdb

然后附带一个调试时用的以16进制打印整数的函数

;Display a Integer in hex format
;Input:
;1. Low 16 bits of Integer, ax
;2. High 16 bits of Integer, dx
DispInt:
    push ax
    push bx
    push cx
    push dx

    xor cx, cx
d:
    mov bx, 16
    div bx
    cmp dx, 9
    ja char
    add dx, '0'
    jmp over

char:
    sub dx, 10
    add dx, 'A'

over:
    push dx
    inc cx
    cmp ax, 0
    jz end
    xor dx, dx
    jmp d

end:
    mov bx, 000ch
l:
    pop ax
    mov ah, 0x0e
    int 10h
    loop l

    pop dx
    pop cx
    pop bx
    pop ax
    ret


三、编写kernel.bin

kernel.bin由两个文件编译连接而成,entry.asm和main.c,entry.asm仍旧使用汇编,作用是进入保护模式,然后调用main.c中的main函数。main.c中就是清了下屏然后打印了一句问候语。

entry.asm:

global begin
begin:
    jmp start_e
[section .s16]
[bits 16]
start_e:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax

    lgdt [GdtPtr]    ;load gdt

    cli              ;disable interrupt

    in al, 0x92      ;enable A20
    or al, 0x2
    out 0x92, al
    
    mov eax, cr0     ;enable protected mode
    or al, 1
    mov cr0, eax
    jmp dword (gdt_code-GdtTable):enter_pm    ;far jump to 32 bits code
    
[section .s32]
[bits 32]
extern main
enter_pm:
    mov ax, 16
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov ax, 0
    mov fs, ax
    mov gs, ax

    call main

[section .gdt]
GdtTable:
    dd 0
    dd 0
gdt_code:
    dw 0xffff
    dw 0x0000
    db 0x00
    db 0x9a
    db 0xcf
    db 0x00
gdt_data:
    dw 0xffff
    dw 0x0000
    db 0x00
    db 0x92
    db 0xcf
    db 0x00

GdtPtr:
    dw GdtPtr-GdtTable-1
    dd GdtTable




main.c

void main()
{
    char *str = "hello world from C";
    char *p = (char *)(0xb8000);
    int i;
    for (i = 0; i < 25 * 80; i ++, p += 2)
        *p = ' ';
    for (p = (char *)(0xb8000); *str; str ++, p += 2)
        *p = *str;
    while (1);
}


最后附带一个Makefile

kernel.bin:entry.o main.o
	ld entry.o main.o -o kernel.bin -Ttext 0x7e00 -e begin --oformat binary
entry.o:entry.asm
	nasm -f elf entry.asm -o entry.o
main.o:main.c
	gcc -c main.c
cp:
	sudo cp kernel.bin /media/tao/
u:
	sudo umount /media/tao/
m:
	sudo mount /dev/sdb1 /media/tao/
run:
	sudo qemu -hda /dev/sdb -boot c
clean:
	rm *.o *.bin

从Makefile中可以看出,每次得到kernel.bin后,先把它复制到U盘,然后要卸载U盘再挂载,然后使用qemu测试才能得到结果,如过不卸载再挂载,qemu运行的结果是上一次生成的kernel.bin。可能是因为操作系统没有及时写盘,所以要卸载一下。当然这个U盘也可以拿到真机上直接启动。


(完)

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: gd32f450vxt6芯片可以通过USB接口来实现使用U盘烧写程序的功能。下面是具体步骤: 1. 首先,需要准备一个带有所需程序U盘,确保程序已经按照gd32f450vxt6的规定格式进行编写,并将其文件格式设置为支持固件升级。 2. 将准备好的U盘插入到gd32f450vxt6芯片的USB接口上。 3. 在gd32f450vxt6芯片中,通过配置寄存器来使能USB功能,并将其设置为USB设备模式。 4. 在程序中,通过使用相关的USB库函数来初始化USB接口,并注册设备插入和拔出的中断处理函数。 5. 当U盘插入芯片的USB接口时,系统会自动调用设备插入的中断处理函数。在该函数中,可以检测到U盘的插入,并进行相关的处理。可以通过USB库函数来获取U盘的相关信息,如文件名、文件大小等。 6. 接下来,可以使用文件系统库函数来读取U盘中的程序文件,并将其编程到gd32f450vxt6的内部闪存中。可以通过调用库函数来控制闪存编程过程,如擦除、写入等操作。 7. 如果需要监测U盘的拔出事件,可以在相应的中断处理函数中进行处理。在设备拔出中断处理函数中,可以进行相应的资源清理和处理。 通过上述步骤,gd32f450vxt6芯片可以实现使用U盘烧写程序的功能。这个过程利用了USB接口作为通信通道,通过中断处理函数来监测U盘的插入和拔出事件,并使用相关的库函数来实现U盘和芯片之间的数据交互和程序编程。这种方法简单方便,适用于需要频繁更换程序的应用场景。 ### 回答2: gd32f450vxt6芯片如何实现使用u盘烧写程序? gd32f450vxt6芯片是一款高性能的ARM Cortex-M4微控制器,它具有丰富的外设、较大的存储容量和灵活的引脚配置,可以广泛应用于各种嵌入式系统中。 要实现使用U盘烧写程序,首先需要确保芯片上的USB功能可以充当USB主机。gd32f450vxt6芯片的USB功能可以支持USB主机模式,因此可以用来读取U盘的数据。 下面是大致的步骤: 1. 配置GPIO引脚:将USB功能的引脚配置为USB功能,使其可以与U盘进行通信。 2. 初始化USB模块:启动USB功能,并配置为主机模式。 3. 检测U盘插入:通过轮询或中断方式检测是否有U盘插入,如果有插入,则执行下一步操作。 4. 读取U盘的文件:使用USB主机模式读取U盘中的文件,并将其加载到芯片的存储器中。 5. 执行烧写操作:根据读取到的文件内容,执行相应的烧写操作,将程序写入到芯片的Flash或其他存储器中。 6. 完成烧写:烧写完成后,可以执行一些后续操作,例如重启芯片以使新程序生效。 需要注意的是,具体的实现细节和代码可能会根据具体的开发环境和需求有所不同。以上步骤只是一个基本的流程示例,可以根据实际情况进行适当的调整和扩展。 ### 回答3: GD32F450VXT6芯片是一款基于ARM Cortex-M4内核的微控制器,它内置了USB OTG(On-The-Go)功能,可以实现使用U盘烧写程序的功能。 要实现使用U盘烧写程序,首先需要在GD32F450VXT6芯片上实现USB设备功能。通过连接U盘和芯片的USB接口,将芯片配置为USB设备模式,使其可以被外部设备(如PC)识别为一个可移动存储设备(U盘)。 其次,需要在GD32F450VXT6的编程代码中添加相关的USB OTG驱动程序。该驱动程序负责处理USB设备模式的初始化、数据传输和中断处理等功能,以便与PC进行通信。 接着,将预先编写好的程序文件保存在U盘中(通常为.bin或.hex格式),将U盘插入GD32F450VXT6芯片的USB接口上。芯片会自动识别U盘的插拔操作,并通过USB OTG驱动程序U盘进行数据交互。 当芯片检测到U盘插入后,可以通过访问U盘的文件系统,将需要烧写的程序文件复制到芯片的存储器中。复制完成后,芯片可以关闭USB设备功能,并根据程序文件的内容进行烧写操作。 最后,芯片进行程序烧写后,可以重新启动并运行新烧写的程序。 总之,GD32F450VXT6芯片通过实现USB设备功能和添加USB OTG驱动程序,可以与U盘进行数据交互,从而实现使用U盘烧写程序的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值