OSDev.org https://forum.osdev.org/ |
|
My bootloader does not load my stage 2 https://forum.osdev.org/viewtopic.php?f=1&t=33337 |
Page 1 of 1 |
Author: | Korek [ Sun Nov 25, 2018 6:51 am ] |
Post subject: | My bootloader does not load my stage 2 |
Hello, I wanted to write a small kernel but I failed at the bootloader. I created a img file formatted as FAT12 which contains my bootloader and the stage 2 called KRNLDR.SYS I used the following commands: Code: nasm -fbin -o boot.bin boot.asm dd if=/dev/zero of=test.img bs=512 count=2880 sudo losetup /dev/loop0 test.img sudo mkdosfs -F 12 /dev/loop0 Now my system recognizes and mounts the device and I put my KRNLDR.SYS on it Then I executed: Code: sudo dd if=boot.bin of=/dev/loop0 bs=512 count=1 conv=notrunc sudo umount /dev/loop0 sudo losetup -d /dev/loop0 Now the file looks like a FAT12 floppy with a bootsector and the file KRNLDR.SYS Now I execute it in QEMU: Code: qemu-system-i386 -device format=raw,file=test.img And the output: Code: Operating System not found Press any key to reboot This is the output my bootloader prints to the screen if the file KRNLDR.SYS cannot be found by my bootloader My Code: Code: org 0x0 bits 16 jmp word loader bsOEMName: db "TestOS " bpbBytesPerSector: dw 512 bpbSectorsPerCluster: db 1 bpbReservedSectors: dw 1 bpbNumberOfFATs: db 2 bpbNumberOfRootEntries: dw 224 bpbTotalSectors: dw 2880 bpbMedia: db 0xf0 bpbSectorsPerFAT: dw 9 bpbSectorsPerTrack: dw 18 bpbNumberOfHeads: dw 2 bpbHiddenSectors: dd 0 bpbTotalSectorsBig: dd 0 bsDriveNumber: db 0 bsReserved: db 0 bsExtendedBootSignature: db 0x29 bsVolumeID: dd 0x12345678 bsVolumeLabel: db "TestOS " bsFileSystem: db "FAT12 " ;------------------------------------------------------------------------------- ; SI = Zero terminated string to print ;------------------------------------------------------------------------------- printMsg: push ax .printStart: lodsb or al, al jz .printEnd mov ah, 0x0e int 0x10 jmp .printStart .printEnd: pop ax ret ;------------------------------------------------------------------------------- ; AX = Starting sector ; CX = Number of sectors to read ; ES:BX = Buffer ;------------------------------------------------------------------------------- readSectors: mov di, 0x0005 .readLoop: push ax push bx push cx call lbaToChs mov ah, 0x02 mov al, 0x01 mov ch, byte [track] mov cl, byte [sector] mov dh, byte [head] mov dl, byte [bsDriveNumber] int 0x13 jnc .success dec di pop cx pop bx pop ax jnz .readLoop .success: pop cx pop bx pop ax inc ax add bx, word [bpbBytesPerSector] loop readSectors ret track: db 0 head: db 0 sector: db 0 ;------------------------------------------------------------------------------- ; AX = Logical sector ;------------------------------------------------------------------------------- lbaToChs: xor dx, dx div word [bpbSectorsPerTrack] inc dl mov byte [sector], dl xor dx, dx div word [bpbNumberOfHeads] mov byte [head], dl mov byte [track], al ret ;------------------------------------------------------------------------------- ; AX = Cluster number ;------------------------------------------------------------------------------- clusterToLba: sub ax, 0x0002 xor cx, cx mov cl, byte [bpbSectorsPerCluster] mul cx ret ;------------------------------------------------------------------------------- loader: cli mov ax, 0x07c0 mov es, ax mov gs, ax mov fs, ax mov ds, ax mov ax, 0x0000 mov ss, ax mov sp, 0xffff sti mov byte [bsDriveNumber], dl xor dx, dx xor cx, cx mov ax, 0x0020 mul word [bpbNumberOfRootEntries] div word [bpbBytesPerSector] xchg cx, ax ; Number of sectors of the root directory mov al, byte [bpbNumberOfFATs] mul word [bpbSectorsPerFAT] add ax, word [bpbReservedSectors] ; Starting sector of the root directory mov bx, 0x0200 call readSectors mov cx, word [bpbNumberOfRootEntries] mov di, 0x0200 searchRoot: push cx mov cx, 0x000b mov si, stage2 push di rep cmpsb pop di je loadFat pop cx add di, 0x0020 loop searchRoot jmp failure loadFat: mov dx, [di + 26] ; Starting address of entry xor ax, ax mov al, byte [bpbNumberOfFATs] mul word [bpbSectorsPerFAT] ; Number of sectors used by the FATs mov word [cluster], dx mov cx, ax mov ax, word [bpbReservedSectors] mov bx, 0x0200 call readSectors mov ax, 0x0050 mov es, ax mov bx, 0x0000 push bx loadFile: mov ax, word [cluster] pop bx call clusterToLba xor cx, cx mov cl, byte [bpbSectorsPerCluster] call readSectors push bx mov ax, word [cluster] mov cx, ax mov dx, ax shr dx, 1 add cx, dx mov bx, 0x0200 add bx, cx mov dx, [bx] test ax, 1 jnz oddCluster evenCluster: and dx, 0b0000111111111111 jmp next oddCluster: shr dx, 4 next: mov word [cluster], dx cmp dx, 0x0ff0 jb loadFile jmp 0x0050:0 ; Far jmp to KRNLDR.SYS failure: mov si, fail call printMsg mov si, anykey call printMsg mov ah, 0x00 int 0x16 ; Await key press jmp 0xffff:0 ; Reboot with far jmp to BIOS stage2: db "KRNLDR SYS" fail: db "Operating system not found", 0xd, 0xa, 0x0 anykey: db "Press any key to reboot", 0xd, 0xa, 0x0 cluster: dw 0 times 510 - ($ - $$) db 0 dw 0xaa55 What have I done wrong? Thanks for any help |
Author: | nakst [ Sun Nov 25, 2018 7:02 am ] |
Post subject: | Re: My bootloader does not load my stage 2 |
Korek wrote: mov ax, 0x0000 mov ss, ax mov sp, 0xffff Your stack should be aligned to a 2-byte boundary in 16-bit mode. Korek wrote: What have I done wrong? Thanks for any help Looking at the output of your program, it isn't finding the entry in the root directory. How have you tried to debug this? There are several places where it could be going wrong:
I highly recommend you run your bootloader in Bochs, and learn to use its debugger. You'll be able to step through your code, and inspect memory. When you can use the available debugging tools, you should be able to solve problems like this yourself. |
Author: | Korek [ Sun Nov 25, 2018 8:45 am ] |
Post subject: | Re: My bootloader does not load my stage 2 |
You're right. I should have used Bochs from the beginning and had to check if my code works instead of writing it completely without debugging |
Author: | nullplan [ Sun Nov 25, 2018 12:45 pm ] |
Post subject: | Re: My bootloader does not load my stage 2 |
Oh god, so much wrong here. Your stack overlaps your entire code area. And your read buffer. Your read buffer starts at 0x7e00, so that's good, but where it ends is dependent on the BPB fields. With your defaults in the fields, the root directory is 14 sectors. So the root directory buffer is from 0x7e00 to 0x9a00. So you have about 26kB of stack before it clobbers your root directory. Speaking of that, your algorithm for calculating the number of root directory sectors is inefficient and wrong. You take the number of root directory entries, mutiply them with 32 and divide them with the number of bytes per sector. But that last one is rounding down. Unless your number of root directory entries happens to be divisible by 16, your result will be 1 too low. Also, both the mul and the div can be replaced by a shift. In fact, you can combine the shift count beforehand, so there is no possibility of overflow: "Bytes per sector" must be a power of 2, right? So you can use "bsf" to log2 it, in all cases. Then subtract 5 and you have your right shift count. Take the number of root directory entries, add (1 << count), subtract 1, and >> count the result. That implements the division, but rounding up. Also, you assume the root directory to be perfectly defragmented. It needn't be; that is sort of the purpose of the whole operation. The pseudo code for finding anything in any directory on any kind of FAT file system is: Code: cluster = startcluster; /* read from dir entry or BPB, for the root directory */ while (!found && cluster != endcluster) { readcluster(cluster); /* handle errors yourself here */ for (i = 0; !found && i < clustersize/32; i++) if (!strncmp(buffer + i * 32, filename, 12)) found = 1; cluster = FAT[cluster]; } After that, you'll have the directory entry at buffer + i * 32. Of course, the indexing into the FAT is a bit of a problem. And the readcluster function is left as an exercise to the reader. Also, please check if your memory allocation works out. From what I've seen, you are using the buffer at 7E00 both for the root directory and the FAT. I haven't read enough to know if this is a bug, but it is a code smell. Also, why use segment 0x07c0? Isn't it easier to use segment 0? And what CPU are you targeting? The FS and GS references put it past the 8086 for sure (weren't these added with the 386 or even later?), but no 32-bit regs or variable shifts suggest otherwise As for error handling: Why not let the user reboot, themselves? Just print "Press CTRL-ALT-DEL to reboot", then hang yourself into a loop that runs the HLT instruction with interrupts enabled. User can press CTRL-ALT-DEL, or they can turn of the computer. No int 16h required at all. As long as you have a stack set up, it'll work. Also, might want to think about continuous tone on error, in case the user of the code has no monitor and no keyboard (e.g. a server). |
Author: | Korek [ Mon Nov 26, 2018 8:33 am ] |
Post subject: | Re: My bootloader does not load my stage 2 |
I think my tutorial is bad. I learned this stuff from http://www.brokenthorn.com/Resources/OSDevIndex.html The demo bootloader from this website doesn't even run. I'll try to fix my errors. Thanks for help |
Author: | neon [ Mon Nov 26, 2018 5:56 pm ] |
Post subject: | Re: My bootloader does not load my stage 2 |
Hi, Due to differences between the provided code and the code as presented in the tutorials, in addition to some questionable control flow logic pertaining to the starting file cluster and data sector start in the presented code, we will ignore the presented code for the duration of this response. Instead, this response will be directed for the code as presented in the tutorials. Regarding the stack location... The code loads the stack to 0:ffff which provides a safe 26k window. For performance, it would be better on a 2 byte boundary, however this is not a requirement. The code assumes this stack space is sufficient for the execution environment (the firmware.) We are not currently aware of any reported problems on this assumption not being met. However, you can relocate the stack for more space to be more cautious. Regarding the buffer at 7e00... The original code as presented in the tutorials loads the root directory to 7e00. After finding the file, it copies the start cluster for later use. Since the root directory is no longer needed, we overwrite it when loading the FAT. This was intentional in order to conserve memory use. A note on ReadSectors... There is a known error on the original implementation not supporting multi-segment reads. This occurs when the file being loaded exceeds 64k in size. If you are using a custom boot loader that exceeds this size, this could be the problem. We can provide an updated version if you believe it might help. If possible, please provide a disk image of the demo for testing here. |
Author: | Korek [ Fri Dec 07, 2018 10:20 am ] |
Post subject: | Re: My bootloader does not load my stage 2 |
I just made it work. Thanks for help |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |