问题
I am currently writing a bootloader in x86 NASM assembly designed to load a kernel (R.BIN) from a FAT16 filesystem and jump to it. I have been writing the bootloader to a blank image that I have mounted by using sudo losetup loop21 image.img
. I would write the image using sudo dd if=LOADER.BIN of=/dev/loop21
. Of course, the bootloader didn't work immediately (I was basing it off of a FAT12 bootloader and forgot to change a few things). After making dozens of edits, at some point, Linux stopped recognizing the loop device I was writing it to, saying the contents were "Unknown".
When I delete the entire contents of the bootloader itself (not including the disk descriptor etc.), Linux recognizes the drive as FAT12. However, as I said, with the code to load R.BIN, Linux will not recognize the filesystem.
This is the code I have:
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
I expect Linux to recognize the filesystem as FAT16 with this written to the boot sector, but it is not recognizing it at all and therefore not allowing me to copy R.BIN.
回答1:
Here's how I just installed a custom boot sector loader into an image and have it work afterwards. This is a FAT12 image that is 1440 KiB long in my case, but the size of the BPB + BPB new fields is the same for FAT16. Please report whether this solves your problem.
$ 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
$
A minor issue that most likely does not cause your error is that jmp main
should be jmp strict short main
.
来源:https://stackoverflow.com/questions/57154972/filesystem-on-loop-device-not-recognized-by-linux-when-bootloader-is-written-to