OSDev.org https://forum.osdev.org/ |
|
Making a bootable image https://forum.osdev.org/viewtopic.php?f=1&t=37405 |
Page 4 of 7 |
Author: | PeterX [ Mon Nov 02, 2020 4:23 am ] |
Post subject: | Re: Making a bootable image |
Bonfra wrote: But the carry flag is set by the BIOS function so it fails and I don't understand the reason I'm not sure about the CHS values. But your code looks good to me. (Except that you comment "head 0" but you set it really to 0x20.) Maybe you first must init the drive? (int 0x13 ah=0) Or maybe your bootdrive value gots corrupted (because of wrong DS value or something else). You could do a hexdump of the AH register after the disk read interrupt. Greetings Peter |
Author: | Bonfra [ Mon Nov 02, 2020 6:55 am ] |
Post subject: | Re: Making a bootable image |
PeterX wrote: Maybe you first must init the drive? (int 0x13 ah=0) Just tried with this other version of the function: Code: ReadSectors: mov ah, 0x00 int 0x13 mov bx, 0x7C00 ; address mov al, 1 ; Number of Sectors mov dl, [bootDrive] mov ch, 0x00 ; cylinder 0x00 mov dh, 0x20 ; head 0x20 mov cl, 0x21 ; disk sector number clc ; clear the flag to be sure mov ah, 0x02 int 0x13 ; Invoke BIOS ret PeterX wrote: Or maybe your bootdrive value gots corrupted (because of wrong DS value or something else). I add the bootloader to the disk with this command: Code: dd if=bin/boot/mbr.bin of=disk.dd seek=0 count=1 conv=notrunc bs=436 Just to be sure that the problem is actually in the read sectors and not somewhere else I used this template from the wiki and implemented the ReadSector function (and the error label), removing the parameter part since they are hard coded in the function: Code: .ReadVBR: call ReadSectors ; Read Sector jc error.diskReadFailed Still nothing the readdisk interrupt return an error. |
Author: | PeterX [ Mon Nov 02, 2020 7:41 am ] |
Post subject: | Re: Making a bootable image |
Try something like this: Code: ReadSectors: .init: mov dl, [bootDrive] ;!!! mov ah, 0x00 int 0x13 jc .init .readSec: mov bx, 0x7C00 ; address mov al, 1 ; Number of Sectors mov dl, [bootDrive] mov ch, 0x00 ; cylinder 0x00 mov dh, 0x20 ; head 0x20 mov cl, 0x21 ; disk sector number clc ; clear the flag to be sure -> not neccessary mov ah, 0x02 int 0x13 ; Invoke BIOS jc .readSec ret EDIT: For the disk interrupts: http://www.ctyme.com/intr/int-13.htm https://wiki.osdev.org/BIOS |
Author: | Bonfra [ Mon Nov 02, 2020 10:09 am ] |
Post subject: | Re: Making a bootable image |
The interrupt keeps throwing the error and the function never returns. I tried burning the image on a USB to run it on a real device and the function returns, the partition bootloader still does not run but we'll think about it later. Maybe is the way I launch QEMU? I use this line: Code: qemu-system-x86_64 disk.dd -m 512M -no-reboot -no-shutdown Also tried with -hda but it doesn't change. |
Author: | PeterX [ Mon Nov 02, 2020 10:55 am ] |
Post subject: | Re: Making a bootable image |
Maybe you debug a bit. I debug usually by printing characters or registers. For example printing an 'A' after the disk reset. So you know if it is hanging in the reset or in the read code. And directly after the read int you could print the content of ah which is a status info. Others prefer using a debugger. Perhaps this helps: https://wiki.osdev.org/How_Do_I_Use_A_D ... With_My_OS Greetings Peter |
Author: | MichaelPetch [ Mon Nov 02, 2020 3:59 pm ] |
Post subject: | Re: Making a bootable image |
The reason it will be failing is because QEMU is likely using a disk geometry that is 16 heads maximum and your partitioning tool used a drive geometry with heads > 16. This is a big reason why using Int 13h/AH=42h is preferred because you can then use LBA addressing rather than CHS. But if you wish to use Int 13h/AH=2 to read using CHS then you will have to query the BIOS to determine the Sectors per Track and the Max number of Heads. With those 2 values you can compute CHS from any given LBA. You will then have to write some kind of conversion function that can take an LBA and convert it to CHS. I have some sample code here that can do just that: https://stackoverflow.com/a/47127909/3857942 . Using CHS is far more complex than using LBA and CHS can't access large drives. Int 13/AH=42h LBA disk reads were meant to deal with this. Unless you are on some ancient equipment that doesn't have support for MS Disk Extensions, using LBA address for hard disk is preferred. Your disk image is 2048+65536 sectors and it is likely that QEMU used 16 heads (0-15), 63 sectors per track (1-63) and 68 cylinders (0-67) to cover all those sectors. If you read a head, sector, or cylinder starting beyond any of those limits it will likely fail. What happens will be dependent on the BIOS and may differ from what you see on real hardware. I have a GCC program that also converts LBA to CHS that you can find here: https://stackoverflow.com/a/59416266/3857942 . You specify the Sectors Per Track (SPT) and the number of heads and the LBA and it will compute CHS. If I have a drive presenting as media with an SPT of 63 and 16 heads, and want to know the CHS of the LBA 2048 I'd run it this way: Code: lba2chs 16 63 2048 and the output would be:Code: SPT = 63, Heads = 16
LBA = 2048 is CHS = (2, 0, 33) DH = 0x00, CH = 0x02, CL = 0x21 |
Author: | BenLunt [ Mon Nov 02, 2020 6:29 pm ] |
Post subject: | Re: Making a bootable image |
Bonfra wrote: I believe you are still getting bad results with your writes to the file. The above ending CHS values are wrong. Using a starting LBA of 2048 with a sector count of 65536, the ending CHS values should be 0x43/0x00/0x31 respectively. Why does your partition entry have 0x04/0x34/0x30? 0x34 for a head value is, as MechaelPetch has stated, a wrong value. When using my utility, click on the button to the right of these values, and it will fill the CHS fields with correct values per your Starting LBA and Sector Count values. Same goes for your Starting CHS values. They should be 0x02/0x00/0x21 respectively. Ben |
Author: | MichaelPetch [ Mon Nov 02, 2020 6:51 pm ] |
Post subject: | Re: Making a bootable image |
Ben, I did notice that fdisk which he is using is computing these values does in fact populate the partition table with those values (I see the same behaviour here). Based on these numbers I suspect 255 heads and 63 SPT is being used by FDISK in this case and it is assuming BIOS translation: Code: Disk disk.dd: 33 MiB, 34603008 bytes, 67584 sectors Some of the values that I think apply:Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xfe110584 Device Boot Start End Sectors Size Id Type disk.dd1 * 2048 67583 65536 32M 6 FAT16 Command (m for help): i Selected partition 1 Device: disk.dd1 Boot: * Start: 2048 End: 67583 Sectors: 65536 Cylinders: 26 Size: 32M Id: 6 Type: FAT16 Start-C/H/S: 0/32/33 End-C/H/S: 4/52/48 Attrs: 80 Code: lba2chs 255 63 2048 It appears one can use SPT = 63, Heads = 255 LBA = 2048 is CHS = (0, 32, 33) DH = 0x20, CH = 0x00, CL = 0x21 lba2chs 255 63 67583 SPT = 63, Heads = 255 LBA = 67583 is CHS = (4, 52, 48) DH = 0x34, CH = 0x04, CL = 0x30 lba2chs 16 63 2048 SPT = 63, Heads = 16 LBA = 2048 is CHS = (2, 0, 33) DH = 0x00, CH = 0x02, CL = 0x21 lba2chs 16 63 67583 SPT = 63, Heads = 16 LBA = 67583 is CHS = (67, 0, 48) DH = 0x00, CH = 0x43, CL = 0x30 Code: fdisk -H 16 -S 63 when running FDISK to get it to use 16 heads and 63 SPT.
|
Author: | Bonfra [ Tue Nov 03, 2020 1:57 am ] |
Post subject: | Re: Making a bootable image |
Ok finally it works and the partition bootloader is loaded correctly and runs. I'd like to summarize the whole process in one post for any future readers. First I created a partition image and add any needed file with this lines: Code: dd if=/dev/zero of=partition.dd bs=512 count=65536 # count = [ K = megabyte; K*(1024)^2/512 ] mkfs.vfat -F 16 -n "MyOS" partition.dd #mcopy -i partition.dd path/to/file.eg ::/ Then I loaded the bootloader in the partition paying attention to not override the BPB: Code: dd if=bin/boot/boot.bin of=partition.dd seek=0 count=1 conv=notrunc bs=3 dd if=bin/boot/boot.bin of=partition.dd seek=83 seek=83 skip=83 count=$[512-83] conv=notrunc bs=1 # 83 is the end address of the 7.1 FAT32 BPB Then I create the actual disk image: Code: dd if=/dev/zero of=disk.dd bs=512 count=$[2048+65536] #65536 is the K value from above echo -e "n \n p \n \n \n \n t \n 6\n a \n w" | fdisk -H 16 -S 63 disk.dd Then I added the MBR to the image paying attention to not override the partition table: Code: dd if=bin/boot/mbr.bin of=disk.dd seek=0 count=1 conv=notrunc bs=436 And finally add the partition to the disk: Code: dd if=partition.dd of=disk.dd conv=notrunc bs=512 seek=2048 I'll also post the minimal code for the MBR and the partition bootloader: MBR code: (This code make some assumption in the ReadSectors function so it should be changed for a normal use) Code: bits 16 org 0x0600 start: cli ; We do not want to be interrupted xor ax, ax ; 0 AX mov ds, ax ; Set Data Segment to 0 mov es, ax ; Set Extra Segment to 0 mov ss, ax ; Set Stack Segment to 0 mov sp, ax ; Set Stack Pointer to 0 .CopyLower: mov cx, 0x0100 ; 256 WORDs in MBR mov si, 0x7C00 ; Current MBR Address mov di, 0x0600 ; New MBR Address rep movsw ; Copy MBR jmp 0:LowStart ; Jump to new Address LowStart: sti ; Start interrupts mov BYTE [bootDrive], dl ; Save BootDrive .CheckPartitions: ; Check Partition Table For Bootable Partition mov bx, PT1 ; Base = Partition Table Entry 1 mov cx, 4 ; There are 4 Partition Table Entries .CKPTloop: mov al, BYTE [bx] ; Get Boot indicator bit flag test al, 0x80 ; Check For Active Bit jnz .CKPTFound ; We Found an Active Partition add bx, 0x10 ; Partition Table Entry is 16 Bytes dec cx ; Decrement Counter jnz .CKPTloop ; Loop jmp error.noBootablePartition ; ERROR! .CKPTFound: mov WORD [PToff], bx ; Save Offset add bx, 8 ; Increment Base to LBA Address .ReadVBR: call ReadSectors ; Read Sector jc error.diskReadFailed mov si, Message.Status.VBRLoaded call BiosPrint .jumpToVBR: cmp WORD [0x7DFE], 0xAA55 ; Check Boot Signature jne error ; Error if not Boot Signature mov si, WORD [PToff] ; Set DS:SI to Partition Table Entry mov dl, BYTE [bootDrive] ; Set DL to Drive Number jmp 0x7C00 ; Jump To VBR error: jmp hang .diskReadFailed: mov si, Message.Error.DiskReadFailed call BiosPrint jmp hang .noBootablePartition: mov si, Message.Error.NoBootablePartition call BiosPrint jmp hang hang: cli hlt jmp hang ;***********************************; ; Reads a series of sectors ; ; Returns: ; ; cf => set if error ; ;***********************************; ReadSectors: .init: mov dl, [bootDrive] mov ah, 0x00 int 0x13 jc .init .readSec: mov bx, 0x7C00 ; address mov al, 1 ; Number of Sectors mov dl, [bootDrive] mov ch, 0x02 ; cylinder 0x02 mov dh, 0x00 ; head 0x00 mov cl, 0x21 ; disk sector number mov ah, 0x02 int 0x13 ; Invoke BIOS jc .readSec ret ;************************; ; Parameters: ; ; si => string pointer ; ;************************; BiosPrint: pusha .loop: lodsb or al, al jz .done mov ah, 0x0E int 0x10 jmp .loop .done: popa ret times (218 - ($-$$)) nop ; Pad for disk time stamp DiskTimeStamp times 8 db 0 ; Disk Time Stamp Message.Error.NoBootablePartition db "No bootable partition found.", 13, 10, 0 Message.Error.DiskReadFailed db "Disk read failed", 13, 10, 0 Message.Status.VBRLoaded db "VBR loaded!", 13, 10, 0 bootDrive db 0 ; Our Drive Number Variable PToff dw 0 ; Our Partition Table Entry Offset times (0x1b4 - ($-$$)) nop ; Pad For MBR Partition Table UID times 10 db 0 ; Unique Disk ID PT1 times 16 db 0 ; First Partition Entry PT2 times 16 db 0 ; Second Partition Entry PT3 times 16 db 0 ; Third Partition Entry PT4 times 16 db 0 ; Fourth Partition Entry dw 0xAA55 ; Boot Signature Partition bootloader code: Code: org 0x7C00 bits 16 jmp short boot nop biosParameterBlock: times 0x52-($-$$) db 0 ; BPB 7.1 FAT32 ends at 0x52. boot: .init: cli ; adjust segment registers mov ax, cs mov ds, ax mov es, ax mov fs, ax mov gs, ax ; create stack xor ax, ax mov ss, ax mov sp, 0x7C00 sti mov si, String.HelloWorld call BiosPrint hang: cli hlt jmp hang String.HelloWorld db "Hello, World!", 13, 10, 0 BiosPrint: pusha .loop: lodsb or al, al jz .done mov ah, 0x0E int 0x10 jmp .loop .done: popa ret times 510-($-$$) db 0 dw 0xAA55 Finally I'd like to thank PeterX, MichaelPetch, BenLunt (and his tool) and bzt for helping me out. |
Author: | Bonfra [ Tue Nov 03, 2020 4:58 am ] |
Post subject: | Re: Making a bootable image |
Actually... It boots from QEMU and prints "Hello, World!" from the partition bootloader, if I boot the image on a real device via USB stick it does not print it. I think that the problem is the geometry of the usb stick. This can be a solution: MichaelPetch wrote: using Int 13h/AH=42h is preferred I read this page about it but I'm not sure about the disk address packet content. It is indicated as so: Code: 00h BYTE size of packet (10h or 18h) 01h BYTE reserved (0) 02h WORD number of blocks to transfer (max 007Fh for Phoenix EDD) 04h DWORD -> transfer buffer 08h QWORD starting absolute block number 10h QWORD (EDD-3.0, optional) 64-bit flat address of transfer buffer; I've setted this values as so: Code: LBA_Packet: .packet_size db 0x10 ; use_transfer_64 ? 10h : 18h .reserved db 0x00 ; always zero .block_cout dw 0x01 ; number of sectors to read .transfer_buffer dd 0x7C00 ; address to load in ram .lba_value dq 0x0 ; LBA addres value Then moving LBA_Packet in SI before calling int 13h/AH=42h. In QEMU this works and I get the "Hello, World!" printed but on the real machine it does not. What have I done wrong? |
Author: | MichaelPetch [ Tue Nov 03, 2020 9:36 am ] |
Post subject: | Re: Making a bootable image |
When it fails what is the status code in AH from Int 13h/AH=42h? I'd also like to know what the value in DL is (The drive number) on the real hardware. I assume your bootloader was still relocated to 0x600. Make sure that DS is set to 0x0000 so that DS:SI points to the DAP in memory. I believe you did do this in your code already, just making sure since I can't see the code you are currently testing as you didn't seem to update GitHub repository with it. Some people have said that there are BIOSes out there where ES must be set to the value of the segment in the Disk Address Packet (DAP). In your case that is zero. Make sure ES has zero in before calling int 13h/ah=42h. You don't show the code where you modify the LBA value in the disk packet either. Can't tell if there is a problem there. What type of computer are you using (real hardware)? How old? It may be possible the Extended BIOS functions aren't available on the BIOS/Drive but that wouldn't be very typical these days, although it is usually a reason people check that Extended BIOS drive functions are available and also that the drive supports them and then fall back to CHS if they aren't supported. Are you booting the USB stick as Floppy Drive Emulation (FDD) or Hard Drive Emulation (HDD)? This is usually setting in the BIOS that you can adjust. If you have it set to FDD it is possible that Int 13h/Ah=42h and the other extended disk functions are not available for what appears to be floppy media. The extended disk functions are generally not available on floppy devices (or on devices appearing as a floppy device). Knowing the drive letter in DL might give us a hint if it is being seen as a floppy or hard drive device. There are some BIOSes out there that when booting with partitioned USB media will look in the MBR for an active partition and load the VBR directly. Did you print anything out in your MBR so you know your MBR was actually loaded and executed before loading the VBR? |
Author: | Bonfra [ Tue Nov 03, 2020 10:24 am ] |
Post subject: | Re: Making a bootable image |
MichaelPetch wrote: When it fails what is the status code in AH from Int 13h/AH=42h? It doesn't properly fail, the MBR print that the reading was succesfull but when it jumps to the bootloader does nothing (QEMU insteads print "Hello, World!") MichaelPetch wrote: Make sure that DS is set to 0x0000 so that DS:SI [...] ES must be set to the value of the segment. In your case that is zero. It is (code from mbr.asm): Code: xor ax, ax ; 0 AX mov ds, ax ; Set Data Segment to 0 mov es, ax ; Set Extra Segment to 0 mov ss, ax ; Set Stack Segment to 0 mov sp, ax ; Set Stack Pointer to 0 MichaelPetch wrote: I believe you did do this in your code already, just making sure since I can't see the code you are currently testing as you didn't seem to update GitHub repository with it Yes, I pushed to the wrong branch, now the code is in the one I've linked to you (testing branch). MichaelPetch wrote: What type of computer are you using (real hardware)? How old? It's an Acer from 2009. MichaelPetch wrote: There are some BIOSes out there that when booting with partitioned USB media will look in the MBR for an active partition and load the VBR directly. Did you print anything out in your MBR so you know your MBR was actually loaded and executed before loading the VBR? Yes, the MBR after loading from the disk the bootloader prints "VBR loaded!", and then "Hello, World!" should appear. MichaelPetch wrote: Are you booting the USB stick as Floppy Drive Emulation (FDD) or Hard Drive Emulation (HDD) The USB stick is booted as HDD, anyway I'm posting some images of the BIOS to be sure about the version of it and that it supports LBA. |
Author: | MichaelPetch [ Tue Nov 03, 2020 10:50 am ] |
Post subject: | Re: Making a bootable image |
What does this command give as output: Code: file disk.dd
|
Author: | Bonfra [ Tue Nov 03, 2020 10:53 am ] |
Post subject: | Re: Making a bootable image |
MichaelPetch wrote: What does this command give as output: Code: file disk.dd The file is now called BonsOS.img, anyway this is the output: Code: file BonsOS.img
BonsOS.img: DOS/MBR boot sector; partition 1 : ID=0x6, active, start-CHS (0x0,32,33), end-CHS (0x4,52,48), startsector 2048, 65536 sectors |
Author: | MichaelPetch [ Tue Nov 03, 2020 11:25 am ] |
Post subject: | Re: Making a bootable image |
You don't actually print out an error message if you load a sector successfully but don't find the disk signature. You do this: Code: .jumpToVBR: My guess is that for whatever reason you are not reading data/code from the VBR you expect and it gets stuck in the `hang` loop. It might help if you print an error message.cmp WORD [0x7DFE], 0xAA55 ; Check Boot Signature jne error ; Error if not Boot Signature mov si, WORD [PToff] ; Set DS:SI to Partition Table Entry mov dl, BYTE [bootDrive] ; Set DL to Drive Number jmp 0x7C00 ; Jump To VBR error: jmp hang If this in fact what is going on then the only thing I can think of is that the process you are using to write the image to the USB stick is the problem and somehow the VBR isn't in the place on disk that is expected; it somehow got clobbered; or wasn't written at all. This is just a guess, I don't actually see anything wrong except it might be a good idea to use `CLD` instruction before you start using string instructions in the MBR (This isn't a problem for you currently), The direction flag isn't guaranteed to be cleared as your code expect. Just giving you a heads-up. How do you write your image to the USB stick? |
Page 4 of 7 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |