当引导加载程序写入循环设备上的文件系统时,Linux 无法识别该文件系统

2023-11-29

我目前正在 x86 NASM 程序集中编写一个引导加载程序,旨在从 FAT16 文件系统加载内核 (R.BIN) 并跳转到它。我一直在将引导加载程序写入使用安装的空白映像sudo losetup loop21 image.img。我会使用写图像sudo dd if=LOADER.BIN of=/dev/loop21。当然,引导加载程序并没有立即工作(我将其基于 FAT12 引导加载程序,但忘记更改一些内容)。经过数十次编辑后,在某个时刻,Linux 停止识别我正在写入的循环设备,并表示内容“未知”。

当我删除引导加载程序本身的全部内容(不包括磁盘描述符等)时,Linux 会将驱动器识别为 FAT12。然而,正如我所说,使用加载 R.BIN 的代码,Linux 将无法识别该文件系统。

这是我的代码:

BITS 16

jmp main                            ; Jump to main bootloader
nop                                 ; Pad out remaining bytes until boot descriptor

; Disk descriptor

OEM_name            db "HOUSE   "   ; OEM label
bytes_sector        dw 0x0200       ; Bytes per sector
sectors_cluster     db 0x01         ; Sectors per cluster
sectors_record      dw 0x0001       ; Sectors reserved for boot record
fats                db 0x02         ; Number of file allocation tables
max_root_entries    dw 0x0200       ; Max number of root entries
sectors             dw 0x0FF5       ; Number of sectors
medium_type         db 0xF0         ; Type of medium (removable or fixed?)
sectors_fat         dw 0x0010       ; Sectors per file allocation table
sectors_track       dw 0x0012       ; Sectors per track
heads               dw 0x0002       ; Number of heads
hidden_sectors      dd 0x00000000   ; Number of sectors before partition
total_sectors       dd 0x00000000   ; Number of sectors in medium (zero because it was already set in the allocated word above)
drive_number        db 0x00         ; Drive number (for BIOS int 0x13)
drive_signature     db 0x00         ; NOT USED
ext_signature       db 0x29         ; Extended boot signature
volume_serial       dd 0x00000000   ; Volume's serial number
volume_label        db "HOUSEHOUSES"; Volume label
fs_type             db "FAT16   "   ; Filesystem type

main:
    mov ax, 0x07C0
    add ax, 0x0220
    mov ss, ax
    mov sp, 0x1000                  ; 4K of stack
    mov ax, 0x07C0
    mov ds, ax
    mov byte [drive_num], dl        ; Save boot drive number

    mov bx, ds
    mov es, bx                      ; Set ES to Data Segment
    mov bx, disk_buffer             ; Set BX to disk buffer
    mov ax, 0x21                    ; Start of root = sectors_record + fats * sectors_fat = 1 + 2 * 16 = logical 33
    call ls_chs                     ; Convert logical 33 to head, track and sector
    mov al, 0x20                    ; Number of sectors in root = max_root_entries * 32 / bytes_sector = 512 * 32 / 512 = 32
    mov si, a                       ; Read root dir message*
    call print_str                  ; Print!*

.read_disk:
    int 0x13                        ; BIOS disk interrupt
    jnc .search_init                ; If successful, get ready to search the disk
    call reset_disk                 ; Otherwise, reset the disk
    jmp .read_disk                  ; And retry

.search_init:
    mov si, success                 ; Success message*
    call print_str                  ; Print!*
    mov ax, ds
    mov es, ax                      ; Move data segment to extra segment
    mov di, disk_buffer             ; Location of disk buffer (ES:DI will be the location of the root entry we will be checking)
    mov si, r_name                  ; Location of filename of R (DS:SI will be the location of the string to compare to the root entry)
    mov bx, 0x00                    ; Start at root entry 0
    push si                         ; Push*
    mov si, b                       ; Search message*
    call print_str                  ; Print!
    pop si                          ; Pop*

.check_entry:
    mov cx, 0x0B                    ; Compare the first 11 bytes
    push si                         ; Push filename location to stack
    push di                         ; Push entry location to stack
    repe cmpsb                      ; Compare the two strings
    pop di                          ; Restore entry location
    pop si                          ; Restore filename location
    je .found_entry                 ; If equal, we found the root entry!
    add di, 0x20                    ; Otherwise, move to next entry
    inc bx                          ; Number of next entry
    cmp bx, [max_root_entries]      ; Have we gone through all root entries?
    jg .missing                     ; If so, R is missing
    jmp .check_entry                ; Otherwise, look at this next entry

.found_entry:
    mov si, success                 ; Success message*
    call print_str                  ; Print!*
    mov ax, word [es:di+0x1A]
    mov word [cluster], ax          ; Move starting cluster number to our spot in memory

    mov bx, disk_buffer             ; ES:BX points to disk buffer
    mov ax, 0x01                    ; 1st FAT begins at logical sector 1
    call ls_chs                     ; Convert to head, track and sector
    mov al, [sectors_fat]           ; Read all sectors in FAT
    mov si, c                       ; Read FAT message*
    call print_str                  ; Print!*

.read_fat:
    int 0x13                        ; BIOS disk interrupt
    jnc .read_cluster               ; If successful, load the first cluster of the file
    call reset_disk                 ; Otherwise, reset the disk
    jmp .read_fat                   ; And try again

.read_cluster:
    mov si, d                       ; Attempt to read cluster message*
    call print_str                  ; Print!*
    mov ax, 0x4200          ; End of disk_buffer = (sectors_record + max_root_entries * 32 / bytes_sector) * bytes_sector = 16,896
    mov es, ax                      ; Segment into which we will load R
    mov bx, word [buffer_pointer]   ; Spot into which we will load this cluster
    mov ax, word [cluster]          ; Cluster to read
    add ax, 0x1F                    ; Convert to logical sector
    call ls_chs                     ; Convert to head, track and sector
    mov al, [sectors_cluster]       ; Read the number of sectors in 1 cluster
    int 0x13                        ; BIOS disk interrupt
    jnc .find_next_cluster          ; If successful, find the next cluster
    call reset_disk                 ; Otherwise, reset the disk
    jmp .read_cluster               ; And try again

.find_next_cluster:
    mov si, success                 ; Success message*
    call print_str                  ; Print!*
    mov ax, word [cluster]          ; Location of current cluster
    mov bx, 0x02                    ; There are two bytes per entry in FAT16
    mul bx                          ; The memory location of CLUSTER should fit in AL
    mov si, disk_buffer             ; Location of start of FAT
    add si, ax                      ; Add the number of bytes until current cluster
    mov ax, word [ds:si]            ; Number of next cluster
    mov word [cluster], ax          ; Store this
    cmp ax, 0xFFF8                  ; Check whether this next cluster is an end-of-file marker
    jae .jump                       ; If it is, we have fully loaded the kernel
    add word [buffer_pointer], 0x0200 ; Otherwise, increment the buffer pointer a sector length
    jmp .read_cluster               ; And load it into memory

.jump:
    mov si, loaded                  ; Print a J
    call print_str                  ; Print!
    mov ah, 0x00                    ; Read keyboard buffer
    int 0x16                        ; BIOS keyboard interrupt
    mov dl, byte [drive_num]        ; Make the boot drive number accessible to R
    jmp 0x4200:0x0000               ; Jump to R's location!

.missing:
    mov si, m_r_missing             ; Display the missing message
    call rsod                       ; Display it in a Red Screen of Death

reset_disk:
    pusha                           ; Push register states to stack
    mov ax, 0x00                    ; RESET disk
    mov dl, byte [drive_num]        ; Boot drive number
    int 0x13                        ; BIOS disk interrupt
    jc .disk_fail                   ; If failed, fatal error and reboot
    popa                            ; Restore register states
    ret                             ; And retry

.disk_fail:
    mov si, m_disk_error            ; Display the disk error message
    call rsod                       ; Display it in a Red Screen of Death

print_str:                          ; Prints string pointed to by REGISTER SI to cursor location (si=str)
    pusha                           ; Push register states to stack
    mov ah, 0x0E                    ; BIOS will PRINT

.repeat:
    lodsb                           ; Load next character from SI
    cmp al, 0x00                    ; Is this a null character?
    je .ret                         ; If it is, return to caller
    int 0x10                        ; Otherwise, BIOS interrupt
    jmp .repeat                     ; Do this again

.ret:
    mov ah, 0x00                    ; Read keyboard buffer
    int 0x16                        ; BIOS keyboard interrupt      
    popa                            ; Restore register states
    ret                             ; Return to caller

ls_chs:                             ; Convert logical sector to head, track, and sector configuration for int 0x13 (AX = logical sector)
    mov dx, 0x00                    ; Upper word of dividend is 0
    div word [sectors_track]        ; Divide to find the number of tracks before this
    mov cl, dl                      ; The remainder is the number of the sector within the track
    add cl, 0x01                    ; Sectors start at 1, not 0
    mov dx, 0x00                    ; Upper word of dividend is 0
    div word [heads]                ; Divide by number of heads/sides
    mov dh, dl                      ; The remainder is the head number (it should only take up the lower half of DX)
    mov ch, al                      ; The quotient is the track number (it should only take up the lower half of CX)
    mov dl, byte [drive_num]        ; Boot drive number
    mov ah, 0x02                    ; READ disk sectors
    ret                             ; Return to caller

rsod:                               ; Red Screen of Death (SI = line to print)
    mov al, 0x20                    ; SPACE
    mov bh, 0x00                    ; Page 0
    mov bl, 0x40                    ; Red background
    mov cx, 0x50                    ; Enough to fit the screen width

.repeat:
    mov ah, 0x09                    ; Write character and attribute
    int 0x10                        ; BIOS VGA interrupt
    mov ah, 0x03                    ; Get cursor position
    int 0x10                        ; BIOS VGA interrupt
    cmp dh, 0x1A                    ; Have we gone all the way down the screen?
    jge .write                      ; If we have, return to caller
    inc dh                          ; Otherwise, next row down
    mov ah, 0x02                    ; Set cursor position
    int 0x10                        ; BIOS VGA interrupt
    jmp .repeat                     ; Do this again for the next line

.write:
    mov ah, 0x02                    ; Set cursor position
    mov dh, 0x01                    ; Row 1
    mov dl, 0x03                    ; Col 3
    int 0x10                        ; BIOS VGA interrupt
    push si                         ; Push line to stack
    mov si, fatal                   ; Prepare to display "FATAL" message
    call print_str                  ; Print!
    pop si                          ; Restore line and prepare to print it
    call print_str                  ; Print!
    mov si, press_a_key             ; Prepare to display prompt
    call print_str                  ; Print!
    mov ah, 0x00                    ; Wait for keyboard input
    int 0x16                        ; BIOS keyboard input
    int 0x19                        ; Reboot

data:
    r_name          db "R       BIN"        ; Filename of R
    cluster         dw 0x0000               ; Cluster that we are working with
    buffer_pointer  dw 0x0000               ; Pointer to offset of buffer
    drive_num       db 0x00                 ; Boot drive number
    fatal           db "FATAL: ", 0x00      ; Fatal error message
    press_a_key     db "! Press a key", 0x00; Instruct the user to press a key and reboot
    m_r_missing     db "R missing", 0x00    ; Missing message
    m_disk_error    db "Disk failed", 0x00  ; Disk error message
    a               db "A", 0x00            ; About to read root dir*
    b               db "B", 0x00            ; About to search root dir*
    c               db "C", 0x00            ; About to read FAT*
    d               db "D", 0x00            ; About to attempt cluster read*
    success         db "!", 0x00            ; Success!*
    loaded          db "J", 0x00            ; Loaded R message*

    times 510-($-$$) db 0x00        ; Pad remainder of boot sector
    sig             dw 0xAA55       ; Boot signature

disk_buffer:                        ; Space in memory for loading disk contents

我希望 Linux 将文件系统识别为 FAT16,并将其写入引导扇区,但它根本无法识别它,因此不允许我复制 R.BIN。


以下是我如何将自定义引导扇区加载器安装到映像中并使其随后正常工作。在我的例子中,这是一个 FAT12 映像,长度为 1440 KiB,但 BPB + BPB 新字段的大小与 FAT16 相同。请报告这是否解决了您的问题。

$ dd if=bldbg12.bin of=floppy.img bs=1 count=11 conv=notrunc
11+0 records in
11+0 records out
11 bytes copied, 0.000161134 s, 68.3 kB/s
$ dd if=bldbg12.bin of=floppy.img bs=1 count=$((512 - 0x3e)) seek=$((0x3e)) skip=$((0x3e)) conv=notrunc
450+0 records in
450+0 records out
450 bytes copied, 0.00150799 s, 298 kB/s
$

一个很可能不会导致您的错误的小问题是jmp main应该jmp strict short main.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当引导加载程序写入循环设备上的文件系统时,Linux 无法识别该文件系统 的相关文章

  • AVX-512 指令编码 - {er} 含义

    在 Intel x86 指令集参考中 有许多 AVX 512 指令在指令中具有可选的 er 例如 VADDPD 的一种形式定义为 EVEX NDS 512 66 0F W1 58 r VADDPD zmm1 k1 z zmm2 zmm3 m
  • 设置 IRQ 映射

    我正在遵循一些教程和参考文献来尝试设置我的内核 我在教程中遇到了一些不熟悉的代码 但根本没有解释它 这是我被告知映射的代码16 IRQs 0 15 到 ISR 地点32 47 void irq remap void outportb 0x2
  • GCC的sqrt()编译后如何工作?使用哪种root方法?牛顿-拉夫森?

    只是对标准感到好奇sqrt 来自 GCC 上的 math h 我自己编码的sqrt 使用牛顿拉夫森来做到这一点 是的 我知道 fsqrt 但CPU是如何做到这一点的呢 我无法调试硬件 现代 CPU 中的典型 div sqrt 硬件使用 2
  • 为什么我的代码显示垃圾?

    当我也想打印列表中的每个数字时 我的代码显示垃圾 有什么问题吗 输出应如下所示 给定的数组是 2G 4 PT为什么这是垃圾总数是 7 Code ASSUME CS CODE DS DATA SS STK ORG 0000H DATA SEG
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • NASM 中的 equ 和 db 有什么区别?

    len equ 2 len db 2 它们是否相同 产生可以用来代替的标签2 如果不是 那么每种申报表的优点或缺点是什么 它们可以互换使用吗 第一个是equate 与 C 类似 define len 2 因为它实际上并没有在最终代码中分配任
  • 将字段中的位扩展到掩码中所有(重叠+相邻)集位的最快方法?

    假设我有 2 个名为 IN 和 MASK 的二进制输入 实际字段大小可能是 32 到 256 位 具体取决于用于完成任务的指令集 每次调用时两个输入都会改变 Inputs IN 1100010010010100 MASK 000111101
  • Intel:序列化指令和分支预测

    英特尔架构开发人员手册 http www intel com content www us en architecture and technology 64 ia 32 architectures software developer v
  • 如何在 GCC C++ 中编写多行内联汇编代码?

    这看起来不太友好 asm command 1 command 2 command 3 我真的必须在每一行加上双引号吗 另外 由于多行字符串文字在 GCC 中不起作用 我也无法欺骗它 我总是在互联网上找到一些例子 该人手动插入制表符和换行符而
  • 如何编译一个简单的 multiboot2 裸机可执行文件?

    我想开始写一个操作系统内核 然后 我找到了一个document http nongnu askapache com grub phcoder multiboot pdf引入 multiboot2 规范 有三个示例代码文件 名为boot S
  • 学习 (N)ASM 的最佳资源是什么? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想学习汇编已经有一段时间了 尽管我之前尝试过几次 但我还没有真正能够超越 Hello world 有
  • 从 DX:AX 寄存器转移到单个 32 位寄存器

    我在添加 16 位乘法的乘积时遇到问题 我想将一年 例如 2015 年 乘以 365 为此 我 mov dx 0 to clear the register mov ax cx cx holds the year such as 2015
  • 如何计算汇编中的内存位移?

    我一直在研究 yasm 汇编语言 并生成了一个包含以下内容的列表文件 我需要帮助理解第一列中的内存位移是如何计算的 提前致谢 1 line 1 1 memory asm 2 section data 3 00000000 04000000
  • 比“add esp, 4”更小的指令

    又是我 我的程序中有很多 add esp 4 我正在尝试减小它的大小 是否有任何更小的指令可以替代 add esp 4 pop edx 或者您不介意破坏的任何其他整数寄存器 这就是现代编译器实际上所做的 https stackoverflo
  • 什么是“Javascript 引导加载程序”?

    我主要在Facebook的源码中看到过这个Bootloader setResourceMap bMxb7 name javascript 中的引导加载程序到底是什么 它的用途和目的是什么 Bootloader 是 Facebook 前端代码
  • 汇编语言程序中连续两次相乘

    我正在使用 8086 模拟器以及 DOSBOX 和 MASM 我知道当我们将 8 位与 8 位相乘时 答案将是 16 位 al 8 bit ax 当我们将 16 位与 16 位相乘时 答案将是 32 位 ax 16 bit dx ax 但如
  • 将以下机器语言代码(0x2237FFF1)翻译成MIPS汇编

    到目前为止我已经翻译了这段代码 但我不明白的是如何计算 计算 16 位立即地址的数量 0x2237FFF1 转为二进制 0010 0010 0011 0111 1111 1111 1111 0001 现在我正在读取操作码 001000 并知
  • 如何恢复 x86-64 寄存器保存约定

    fibonacci cmpq 1 rdi ja recursive movl 1 eax ret recursive push rbp push r10 movq rdi r10 leaq 2 rdi rdi call fibonacci
  • NASM:如何正确访问SSD驱动器?

    我需要使用 NASM 16 位代码访问 SSD 驱动器 访问普通硬盘时 需要设置寄存器AX DX CX来选择柱面 磁道 扇区 扇区数 AH 选择读扇区功能 DL 选择驱动器号 CH 选择气缸 DH 选择磁盘上的一侧 CL 选择步入正轨的部门
  • 如何在 AVX/AVX2 中递增向量

    我想使用内在函数来增加 SIMD 向量的元素 最简单的方法似乎是为每个元素加 1 如下所示 note vec inc之前已设置为1 vec mm256 add epi16 vec vec inc 但是是否有任何特殊指令来增加向量 类似于in

随机推荐

  • 在 iPhone 上迁移大型 CoreData 数据存储时出现内存问题

    我的应用程序下面有一个可能非常大的 CoreData 数据存储 很容易就超过 30MB 使用自动迁移时我开始注意到内存问题 addPersistentStoreWithType configuration URL options error
  • 如何减少 R 中的分钟数?

    我在 R 中有一个 DateTime 对象 tempDateTime lt as POSIXct 2017 07 13 01 40 00 MDT class tempDateTime 1 POSIXct POSIXt 我想从 DateTim
  • 如何在不使用 gulp 工具的情况下在 Angular 中使用 pdfmake 自定义字体?

    安装自定义字体文件的标准方法是通过 gulp 工具 如下所述 https pdfmake github io docs fonts custom fonts client side 但如果这对你和我在 Windows 上失败了 这似乎是一个
  • 是否可以将图例添加到 JFreeChart 的绘图中?

    我正在尝试在分散图表中的绘图下添加图例 如下所示 有人知道这是否可能吗 Before After 这是我创建的自定义标签生成器 public class LegendXYItemLabelGenerator extends Standard
  • Xampp 中的 Zend 框架

    我最近下载了 ZendFramework 2 0 5 的完整包版本 推荐 并尝试在 xampp 版本 1 7 4 中安装但失败 我的 php 版本是 5 3 5 我几乎做了所有据说要做的事情 比如 1 找到php ini并添加路径 incl
  • 标签栏顶部的 Qt 样式表奇怪的线

    我设计了 QTabWidget 样式 并在选项卡栏顶部出现了一条奇怪的线 仅当它具有多个选项卡时才会发生 QTabWidget pane border top 1px solid c4c4c4 top 1px QTabWidget tab
  • 如何在 emacs 中“链接”非组织模式缓冲区[重复]

    这个问题在这里已经有答案了 可能的重复 如何使任何 emacs 缓冲区中的 org 语法链接看起来像在 org 模式中 我不介意使用组织模式 但使用非星号标题 我在中问过这个问题如何在组织模式下使用其他标题样式 例如 twiki 或 med
  • DexOverflowException:无法在 main-dex 文件中容纳请求的类

    我有相当大的多模块 多风味 multidex 项目 但最近我在尝试进行命令行构建 assemble flavor Release 时遇到错误 消息是 DexOverflowException Cannot fit requested cla
  • 如何在Android上执行JavaScript?

    我的代码使用 ScriptEngineManager ScriptEngine 类来使用 Java 执行 JavaScript 代码 但它在 Java SE 中工作正常 但在 Android 中不起作用 SDK 显示缺少类的错误 Andro
  • 使用 RVM 安装 ruby​​ 失败,无痕迹

    好的 我安装了RVM 我测试使用 type rvm head n1 输出 rvm 是一个函数 到目前为止 一切都很好 然后我尝试 rvm install 1 8 7 p302 一切都很顺利 但是接下来 ruby v The program
  • 虚拟主机站点上的 Java Applet 错误

    当我将小程序文件上传到我的网站时 我在尝试运行它时遇到问题 它一直给我错误 但在我的电脑上运行得很好 我正在使用 NetBeans 创建我的 Applet 并且使用了标签 因为我记得使用过它并且它有效 但 NetBeans 确实发出了一条警
  • 另一个 enum 与 int

    我需要命名空间范围的内容 所以我可以选择使用枚举 例如 public enum Token INFORMATIONAL WARNING ABORT FATAL 但缺点是 例如在 WPF 中 我需要时不时地将它们转换为 int 所以我想 为什
  • Android 如何测量应用程序插入时的功耗

    当我的设备与电脑连接时 如何测量应用程序的功耗 我读过关于电池统计来自 Android Studio 我已按照说明操作并获取了电池统计转储系统 但是 我不能不让我的设备始终插入 USB 端口 因为 dumpsys 的结果将缺少一个名为 估计
  • 从客户端隐藏 API 密钥

    我正在尝试与 Zendesk 进行 API 集成 我有很多问题 您可以在下面看到我迄今为止提出的有关它的问题 如何在 ajax 调用中传递访问令牌 使用 Javascript 提交 ZenDesk API 票证 授权 现在是好消息 我已经在
  • 将 char 指针数组传递给函数

    我编写了以下示例代码来演示我的问题 include
  • SQL“SCRIPT”命令备份 h2 数据库

    我有一个申请h2数据库 我想创建 sql文件使用SCRIPTJava 中的命令 如果我使用准备好的语句执行它 PreparedStatement stmt con prepareStatement SCRIPT ResultSet rs s
  • 如何将 ComboBoxTableCell 放入 TableView 中?

    我试图将组合框放入表格单元格中 但我不能 代码如下 private void cargaTablaDesglose TableColumn
  • 不再需要 Class.forName(JDBC_DRIVER) ?

    我在这里读到 从 java 6 开始 您不再需要使用以下方式注册 JDBC 驱动程序 Class forName JDBC DRIVER 因为 DriverManager 使用位于系统属性中的路径 jdbc 驱动程序 以检索正确的驱动程序
  • 如何在 Windows 上后台运行命令?

    在Linux中你可以使用command 在后台运行命令 shell 离线后同样会继续 我想知道 Windows 上有类似的东西吗 我相信您正在寻找的命令是start b command 对于unix来说 nohup代表 无挂断 这与后台作业
  • 当引导加载程序写入循环设备上的文件系统时,Linux 无法识别该文件系统

    我目前正在 x86 NASM 程序集中编写一个引导加载程序 旨在从 FAT16 文件系统加载内核 R BIN 并跳转到它 我一直在将引导加载程序写入使用安装的空白映像sudo losetup loop21 image img 我会使用写图像