鱼C论坛

 找回密码
 立即注册
查看: 2753|回复: 7

[汇编作业] 编写程序,读两个扇区,显示到屏幕Hello world

[复制链接]
发表于 2021-11-23 10:22:47 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
将“ hello”和 world”两个字符串分别写到第 100和 101扇区,编写程序 test13-3.asm读取这二个扇区,并将两个字符串显示到屏幕上。程序运行后如图:

                               
登录/注册后可看大图



ps:有没有学汇编的一起来交流一下!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-11-23 11:07:02 | 显示全部楼层
        绝对写磁盘扇区是一件非常危险事情,必须十分慎重,闹不好,会破坏磁盘关键数据,例如,FAT 扇区、目录扇区等内容,从而对磁盘的安全健康状态造成不可逆的损害。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-11-23 20:05:23 | 显示全部楼层
jackz007 发表于 2021-11-23 11:07
绝对写磁盘扇区是一件非常危险事情,必须十分慎重,闹不好,会破坏磁盘关键数据,例如,FAT 扇区、 ...

在Ubuntu构建的虚拟硬盘,和虚拟机,这只是学习所需。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-23 20:46:24 | 显示全部楼层
read.s
    .code16
    .globl  _start
_start:
    lgdtw   gdtr + 0x7c00

    # 打开A20地址线
    inb     $0x92, %al
    orb     $0x02, %al
    outb    %al, $0x92

    cli         # bootsect不打算建立保护模式下的中断机制

    # 进入保护模式
    movl    %cr0, %eax
    orl     $1, %eax
    movl    %eax, %cr0
    ljmpl   $8, $flush + 0x7c00

    .code32
flush:
    movw    $16, %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %fs
    movw    %ax, %gs
    movw    %ax, %ss
    movl    $0xa0000, %esp

    movl    %esp, %ebp
    subl    $512, %esp
    subl    $8, %esp

    leal    -512(%ebp), %eax
    movl    $100, %ebx
    movl    %eax, (%esp)
    movl    %ebx, 4(%esp)
    calll   read_sect

    leal    -512(%ebp), %ebx
    movb    (%ebx), %al
    movb    %al, 0xb8000
    movb    1(%ebx), %al
    movb    %al, 0xb8002
    movb    2(%ebx), %al
    movb    %al, 0xb8004
    movb    3(%ebx), %al
    movb    %al, 0xb8006
    movb    4(%ebx), %al
    movb    %al, 0xb8008

    leal    -512(%ebp), %eax
    movl    $101, %ebx
    movl    %eax, (%esp)
    movl    %ebx, 4(%esp)
    calll   read_sect

    leal    -512(%ebp), %ebx
    movb    (%ebx), %al
    movb    %al, 0xb80a0
    movb    1(%ebx), %al
    movb    %al, 0xb80a2
    movb    2(%ebx), %al
    movb    %al, 0xb80a4
    movb    3(%ebx), %al
    movb    %al, 0xb80a6
    movb    4(%ebx), %al
    movb    %al, 0xb80a8

1:
    hlt
    jmp 1b

#void read_sect(uint8_t *buf, size_t start_sect);
read_sect:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %edi

    # 读取1个扇区
    movb    $1, %al
    movl    $0x1f2, %edx
    outb    %al, %dx

    # 下面发送逻辑扇区号
    # 0~7
    movl    12(%ebp), %ecx
    movl    %ecx, %eax
    movl    $0x1f3, %edx
    outb    %al, %dx

    # 8~15
    movl    %ecx, %eax
    shrl    $8, %eax
    movl    $0x1f4, %edx
    outb    %al, %dx

    # 16~23
    movl    %ecx, %eax
    shrl    $16, %eax
    movl    $0x1f5, %edx
    outb    %al, %dx

    # LBA28模式, 主盘
    # LBA地址24~27
    movl    %ecx, %eax
    shrl    $24, %eax
    andl    $0x0f, %eax
    orl     $0xe0, %eax
    movl    $0x1f6, %edx
    outb    %al, %dx

    # 发送读命令
    movb    $0x20, %al
    movl    $0x1f7, %edx
    outb    %al, %dx

    # 等待硬盘准备好
.L1:
    inb     %dx, %al
    andb    $0x88, %al
    cmpb    $0x08, %al
    jne     .L1

    # 从硬盘读取数据
    movl    8(%ebp), %edi
    movl    $256, %ecx
    movl    $0x1f0, %edx
    cld
    rep     insw

    popl    %edi
    popl    %ebp
    retl

    .align  4
gdt:
    # 空描述符
    .int    0, 0

    # 代码段描述符
    # 段基地址: 0
    # 段界限:   4GB
    .int    0x0000ffff, 0x00cf9a00

    # 数据段描述符
    # 段基地址: 0
    # 段界限:   4GB
    .int    0x0000ffff, 0x00cf9200
gdtr:
    .short  (. - gdt - 1)
    .int    (gdt + 0x7c00)

write.s
    .code16
    .globl  _start
_start:
    lgdtw   gdtr + 0x7c00

    # 打开A20地址线
    inb     $0x92, %al
    orb     $0x02, %al
    outb    %al, $0x92

    cli         # bootsect不打算建立保护模式下的中断机制

    # 进入保护模式
    movl    %cr0, %eax
    orl     $1, %eax
    movl    %eax, %cr0
    ljmpl   $8, $flush + 0x7c00

    .code32
flush:
    movw    $16, %ax
    movw    %ax, %ds
    movw    %ax, %es
    movw    %ax, %fs
    movw    %ax, %gs
    movw    %ax, %ss
    movl    $0xa0000, %esp

    movl    %esp, %ebp
    subl    $512, %esp
    subl    $8, %esp

    leal    -512(%ebp), %ebx
    movb    $'h', (%ebx)
    movb    $'e', 1(%ebx)
    movb    $'l', 2(%ebx)
    movb    $'l', 3(%ebx)
    movb    $'o', 4(%ebx)

    leal    -512(%ebp), %eax
    movl    $100, %ebx
    movl    %eax, (%esp)
    movl    %ebx, 4(%esp)
    calll   write_sect

    leal    -512(%ebp), %ebx
    movb    $'w', (%ebx)
    movb    $'o', 1(%ebx)
    movb    $'r', 2(%ebx)
    movb    $'l', 3(%ebx)
    movb    $'d', 4(%ebx)

    leal    -512(%ebp), %eax
    movl    $101, %ebx
    movl    %eax, (%esp)
    movl    %ebx, 4(%esp)
    calll   write_sect

1:
    hlt
    jmp 1b

#void write_sect(const uint8_t *buf, size_t start_sect);
write_sect:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %esi

    # 写入1个扇区
    movb    $1, %al
    movl    $0x1f2, %edx
    outb    %al, %dx

    # 下面发送逻辑扇区号
    # 0~7
    movl    12(%ebp), %ecx
    movl    %ecx, %eax
    movl    $0x1f3, %edx
    outb    %al, %dx

    # 8~15
    movl    %ecx, %eax
    shrl    $8, %eax
    movl    $0x1f4, %edx
    outb    %al, %dx

    # 16~23
    movl    %ecx, %eax
    shrl    $16, %eax
    movl    $0x1f5, %edx
    outb    %al, %dx

    # LBA28模式, 主盘
    # LBA地址24~27
    movl    %ecx, %eax
    shrl    $24, %eax
    andl    $0x0f, %eax
    orl     $0xe0, %eax
    movl    $0x1f6, %edx
    outb    %al, %dx

    # 发送写命令
    movb    $0x30, %al
    movl    $0x1f7, %edx
    outb    %al, %dx

    # 等待硬盘准备好
.L1:
    inb     %dx, %al
    andb    $0x88, %al
    cmpb    $0x08, %al
    jne     .L1

    # 把数据写入硬盘
    movl    8(%ebp), %esi
    movl    $256, %ecx
    movl    $0x1f0, %edx
    cld
    rep     outsw

    popl    %esi
    popl    %ebp
    retl

    .align  4
gdt:
    # 空描述符
    .int    0, 0

    # 代码段描述符
    # 段基地址: 0
    # 段界限:   4GB
    .int    0x0000ffff, 0x00cf9a00

    # 数据段描述符
    # 段基地址: 0
    # 段界限:   4GB
    .int    0x0000ffff, 0x00cf9200
gdtr:
    .short  (. - gdt - 1)
    .int    (gdt + 0x7c00)

1.bmp
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 2 反对 0

使用道具 举报

 楼主| 发表于 2021-11-24 21:34:06 | 显示全部楼层
                        ;文件名:port_hd_hello.asm
                        ;功能:1.读取硬盘逻辑扇区号100处的1个扇区到物理内存0x10000处
                        ;      2.并显示扇区开头的‘hello'
                        ;           3.MBR程序
                        ;目的:练习对硬盘的端口访问
                        ;说明:本末终始2020-11-24,参考李忠c08_mbr.asm
                        app_lba_start equ 100                ;'hello'在第100扇区(LBA)
SECTION hello align=16 vstart=0x7c00
                        ;设置堆栈段和栈指令
                        xor ax,ax
                        mov ss,ax
                        mov sp,ax
                       
                        ;设置DS和ES
                        mov ax,0x1000                                ;0x10000的段地址,接收扇区来的数据
                        mov ds,ax
                        mov es,ax
                       
                        ;调用call及参数设置:扇区号和装载内存偏移地址
                        xor di,di
                        mov si,app_lba_start                ;di:si:逻辑扇区号100
                        xor bx,bx                                        ;装载扇区的内存区偏移地址0
                        call read_hard_disk_0                ;从硬盘读取一个逻辑扇区,到DS:BX(内存0x10000)。引自李忠c08_mbr.asm
                       
                        ;显示'hello'5个字符到0xb8000
                        mov ax,0xb800
                        mov es,ax
                        xor si,si
                        xor di,di
                        mov cx,5                                        ;显示'hello'5个字符
disp:
                        mov al,[si]
                        mov ah,0x07
                        mov [es:di],ax
                        inc si
                        inc di
                        inc di
                        loop disp
                       
                        jmp $                                                ;程序结束
                       
;-----------------------------------------------------------------------------

read_hard_disk_0:                        ;从硬盘读取一个逻辑扇区
                                         ;输入:DI:SI=起始逻辑扇区号
                                         ;      DS:BX=目标缓冲区地址
                         push ax                                                ;过程中使用,端口数据
                         push bx                                                ;过程中使用,退出后需恢复
                         push cx                                                ;过程中使用,计数
                         push dx                                                ;过程中使用,端口号
                  
                         mov dx,0x1f2
                         mov al,1
                         out dx,al                       ;读取的扇区数

                         inc dx                          ;0x1f3
                         mov ax,si
                         out dx,al                       ;LBA地址7~0

                         inc dx                          ;0x1f4
                         mov al,ah
                         out dx,al                       ;LBA地址15~8

                         inc dx                          ;0x1f5
                         mov ax,di
                         out dx,al                       ;LBA地址23~16

                         inc dx                          ;0x1f6
                         mov al,0xe0                     ;LBA28模式,主盘
                         or al,ah                        ;LBA地址27~24
                         out dx,al

                         inc dx                          ;0x1f7
                         mov al,0x20                     ;读命令
                         out dx,al

          .waits:
                         in al,dx
                         and al,0b1000_1000                                ;BSY:1--硬盘忙,DRQ:1--准备好
                         cmp al,0x08
                         jnz .waits                      ;不忙,且硬盘已准备好数据传输
                                                                                        ;BSY:0--不忙,DRQ:1--准备好

                         mov cx,256                      ;总共要读取的字数,一个扇区
                         mov dx,0x1f0
          .readw:
                         in ax,dx
                         mov [bx],ax
                         add bx,2
                         loop .readw

                         pop dx
                         pop cx
                         pop bx
                         pop ax
                  
                         ret                       
                       
;--------------------------------------------------------------------------------
                        times 510-($-$$) db 0
                        db 0x55,0xaa
                       
                       

看不太懂你的,这是我们老师给的示例代码,但是这只读入一个扇区。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-24 21:50:11 | 显示全部楼层
15218524174 发表于 2021-11-24 21:34
;文件名:port_hd_hello.asm
                        ;功能:1.读取硬盘逻辑扇区号100处的1个扇区到物理内存0x10000处
                        ; ...

1. 我没有你的这个写代码环境,没办法调试你的程序,就像你没办法使用我写的程序一样
2. 也就是说还差一个写 hello world 到 101 扇区的程序?
硬盘读取命令是 0x20
写入命令是 0x30
其他基本一样
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-24 21:50:44 | 显示全部楼层
#void read_sect(uint8_t *buf, size_t start_sect);
read_sect:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %edi

    # 读取1个扇区
    movb    $1, %al
    movl    $0x1f2, %edx
    outb    %al, %dx

    # 下面发送逻辑扇区号
    # 0~7
    movl    12(%ebp), %ecx
    movl    %ecx, %eax
    movl    $0x1f3, %edx
    outb    %al, %dx

    # 8~15
    movl    %ecx, %eax
    shrl    $8, %eax
    movl    $0x1f4, %edx
    outb    %al, %dx

    # 16~23
    movl    %ecx, %eax
    shrl    $16, %eax
    movl    $0x1f5, %edx
    outb    %al, %dx

    # LBA28模式, 主盘
    # LBA地址24~27
    movl    %ecx, %eax
    shrl    $24, %eax
    andl    $0x0f, %eax
    orl     $0xe0, %eax
    movl    $0x1f6, %edx
    outb    %al, %dx

    # 发送读命令
    movb    $0x20, %al
    movl    $0x1f7, %edx
    outb    %al, %dx

    # 等待硬盘准备好
.L1:
    inb     %dx, %al
    andb    $0x88, %al
    cmpb    $0x08, %al
    jne     .L1

    # 从硬盘读取数据
    movl    8(%ebp), %edi
    movl    $256, %ecx
    movl    $0x1f0, %edx
    cld
    rep     insw

    popl    %edi
    popl    %ebp
    retl
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-24 21:51:17 | 显示全部楼层
#void write_sect(const uint8_t *buf, size_t start_sect);
write_sect:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   %esi

    # 写入1个扇区
    movb    $1, %al
    movl    $0x1f2, %edx
    outb    %al, %dx

    # 下面发送逻辑扇区号
    # 0~7
    movl    12(%ebp), %ecx
    movl    %ecx, %eax
    movl    $0x1f3, %edx
    outb    %al, %dx

    # 8~15
    movl    %ecx, %eax
    shrl    $8, %eax
    movl    $0x1f4, %edx
    outb    %al, %dx

    # 16~23
    movl    %ecx, %eax
    shrl    $16, %eax
    movl    $0x1f5, %edx
    outb    %al, %dx

    # LBA28模式, 主盘
    # LBA地址24~27
    movl    %ecx, %eax
    shrl    $24, %eax
    andl    $0x0f, %eax
    orl     $0xe0, %eax
    movl    $0x1f6, %edx
    outb    %al, %dx

    # 发送写命令
    movb    $0x30, %al
    movl    $0x1f7, %edx
    outb    %al, %dx

    # 等待硬盘准备好
.L1:
    inb     %dx, %al
    andb    $0x88, %al
    cmpb    $0x08, %al
    jne     .L1

    # 把数据写入硬盘
    movl    8(%ebp), %esi
    movl    $256, %ecx
    movl    $0x1f0, %edx
    cld
    rep     outsw

    popl    %esi
    popl    %ebp
    retl
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 22:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表