Page 4 of 4

Re: Bootloader fails on a real pc

Posted: Thu May 12, 2011 5:37 pm
by Bietje
I think we're a bit closer again. I have three machines here. And at first it never worked on any of them. Now it works on one of them. I think that the working one emulates it as an hard disk and the other two as something else, or the other way around.

Re: Bootloader fails on a real pc

Posted: Thu May 12, 2011 5:41 pm
by DavidCooper
Let's sleep on it then and hope that someone else will inject some wisdom in the meantime.

It's good to know it works on one machine.

Re: Bootloader fails on a real pc

Posted: Thu May 12, 2011 8:18 pm
by Minoto
Hi, Bietje -- here's something to consider. From the earlier posts, I can't tell for sure if your USB drive is formatted and used like a simple floppy disk, or if it's partitioned like a hard drive, but if it's the latter, then (unless you're wiping out the MBR and following sector) your bootloader and second stage are most likely stored as the first and second sectors of the active partition, not as the first couple sectors on the actual device. However, int 13h reads sectors from the beginning of the device, not any particular partition...so it could be that your code is working fine, and reading in whatever is in the second sector of the drive just like it's being asked to, with the real problem being that your second stage is located elsewhere.

Try this: instead of reading in the second sector, read in the first sector and dump it. If what you've read in is your own bootloader, then ignore what I've said; it doesn't apply. If you get a normal MBR, on the other hand, then look at the partition table contained in it, figure out where the active partition starts, and try reading from there instead.

Re: Bootloader fails on a real pc

Posted: Fri May 13, 2011 1:53 am
by Bietje
Minoto wrote:Hi, Bietje -- here's something to consider. From the earlier posts, I can't tell for sure if your USB drive is formatted and used like a simple floppy disk, or if it's partitioned like a hard drive, but if it's the latter, then (unless you're wiping out the MBR and following sector) your bootloader and second stage are most likely stored as the first and second sectors of the active partition, not as the first couple sectors on the actual device. However, int 13h reads sectors from the beginning of the device, not any particular partition...so it could be that your code is working fine, and reading in whatever is in the second sector of the drive just like it's being asked to, with the real problem being that your second stage is located elsewhere.

Try this: instead of reading in the second sector, read in the first sector and dump it. If what you've read in is your own bootloader, then ignore what I've said; it doesn't apply. If you get a normal MBR, on the other hand, then look at the partition table contained in it, figure out where the active partition starts, and try reading from there instead.
It is formatted as one partition in FAT16 (that last should not matter at all..). If I read sector 1 I do not get another MBR.. But when I try this on the machine where it works like it should, the activity light on my usb keeps blinking. On the other PC's the light blinks once and stops then.

Re: Bootloader fails on a real pc

Posted: Fri May 13, 2011 11:54 am
by Bietje
The problem seems to be hard disk emulation. The reason it works only on one machine, is that that one emulates it as a floppy disk. All other bioses seem to use hard disk emulation. So now I have to figure out (your help would be appriciated!) how I get this thing to work with hard disk emulation..

Re: Bootloader fails on a real pc

Posted: Fri May 13, 2011 3:12 pm
by DavidCooper
Five options:-

1. Join the other forum and post a question about this there - Mike Gonta might be willing to look at your source code, and he'll probably know in an instant what the problem is.

2. Send Turdus a PM (p114 of members list) and hope he might be able to help - he may not have read this thread, but he's keen on booting with USB flash drives.

3. Keep trying lots of experiments in the hope that it'll reveal what the problem is.

4. Wait for someone to turn up who knows how to solve this.

5. Search the Wiki and Google the Web to try and find the answer without relying on anyone else, even if that results in you having to spend days trawling through stuff that doesn't help. On the other hand, the answer might be easy to find if you manage to get the search terms right.

I think it might be worth doing a few more experiments first, just to get a bit more information. The first thing I'd do is something I suggested you should do some time back, and that's to send DL to the screen to try to see what the drive number is. Next, I'd write more sectors on the flash drive and start each with the ASCII value for a different letter (followed by 511 zeros), then read the byte at 7E00 and send it to the screen to try and find out which actual sector is being loaded in.

Edit: I meant to suggest another couple of things, but forgot. Firstly, have you tried using Mike Gonta's code directly to see if it works on all your machines? If it doesn't work, he'll be interested to hear about it. Secondly, it strikes me that his code doesn't worry about whether the initial jump is a 235 or 233 instruction, which means the table may work even if it's out of position by one byte, using the nop byte to indicate to the BIOS where it starts. It might be worth trying it again with the nop, and maybe replacing the jump with a direct 235 byte followed by the right value to jump past the table to the start of your actual code. If you can't be bothered calculating the exact jump distance, you can start the actual code with a string of nops and aim to hit it about half way through them.

Re: Bootloader fails on a real pc

Posted: Fri May 13, 2011 8:08 pm
by Minoto
Bietje wrote:
Minoto wrote:Try this: instead of reading in the second sector, read in the first sector and dump it. If what you've read in is your own bootloader, then ignore what I've said; it doesn't apply. If you get a normal MBR, on the other hand, then look at the partition table contained in it, figure out where the active partition starts, and try reading from there instead.
It is formatted as one partition in FAT16 (that last should not matter at all..). If I read sector 1 I do not get another MBR.. But when I try this on the machine where it works like it should, the activity light on my usb keeps blinking. On the other PC's the light blinks once and stops then.
Just be sure we're talking about the same thing here -- did you read in the first sector, or sector #1? Remember, the extended read and write calls use a zero-based sector number, or an offset from the first sector if you prefer to think of it that way. To read the first sector on the drive, the final quadword in your disk access packet should be 0.

And I should have asked this before, but what tool are you using to write to your USB drive? Do you know for sure whether you're writing your bootloader to the first sector of the drive, or to the first sector of the active partition? The more facts that we know for certain, the more guesswork we can eliminate as we try to get this working.

I second DavidCooper's recommendation of displaying the contents of DL at boot time, so you can know for sure what your computer thinks it's booting from, as well as writing known data to known locations on your drive and then looking for it. I also recommend, again, reading in the first sector and dumping it, if not in hex and ASCII then at least in hex, and paying attention to what's there. If you have two machines that are treating your USB drive like a hard drive, then they should be going through the normal hard drive boot process -- loading the MBR from the first sector, after which it locates the active partition, loads the first sector of that partition, and passes control to that code. From what I've read, it really sounds to me like your bootloader is stored in the first sector of the partition, and is being loaded successfully by the MBR, and that your attempt to read in the second stage is also working properly (the int 13h call returns with the carry flag clear, right?); it's just not reading the right location.

Re: Bootloader fails on a real pc

Posted: Sat May 14, 2011 12:47 am
by Bietje
From what I've read, it really sounds to me like your bootlwithoader is stored in the first sector of the partition, and is being loaded successfully by the MBR, and that your attempt to read in the second stage is also working properly (the int 13h call returns with the carry flag clear, right?); it's just not reading the right location.
That seems to be the exact problem.

I write to my usb with 'dd':

Code: Select all

dd if=loader.bin of=/dev/xxxx seek=0
I will try Mike Gonta's code and which 'other' forum do you mean David? I keep searching google and I will also PM turdus if nothing turns out to work..

Today I won't have time to work on it due to other stuff, but tomorrow I can do some work again.

Thanks for the help so far!

Re: Bootloader fails on a real pc

Posted: Sat May 14, 2011 5:07 pm
by DavidCooper
Bietje wrote:I will try Mike Gonta's code and which 'other' forum do you mean David? I keep searching google and I will also PM turdus if nothing turns out to work..
The other forum is the one with Mike Gonta's code on it: http://board.flatassembler.net/topic.php?t=12389. But before you bother him, you probably should try running his code on all your machines in case we've all missed something obvious.

I've no idea how to deal with partitions on USB flash drives, but it does sound as if the way you're storing your code on yours may be putting it in the wrong place due to a partition issue. Minoto's idea of loading in the first sector and then displaying its content is an excellent one, so you'll need some code to display it. Here's my idea of how it could be done with twenty six hex numbers per row and twenty rows, but you'll have to tidy up my code in places to get the syntax right (and I'm sorry about all the decimal values):-

Code: Select all

mov ax, 176*256      ; segment value for B0000
mov es, ax
mov di, 128*256       ; screen address to hit B8000
mov ax, 0                ; segment value for bottom of machine memory
mov ds, ax
mov si, 126*256       ; address where sector should have been loaded in
mov cx, 20              ; count for 20 rows

; outer loop starts here - you'll need to put a name here so that you can loop back to it

push cx                  ; put row count on the stack
mov cx, 26              ; count for 26 columns

; inner loop starts here - you'll need to put another name in here to loop back to it

lodsb                     ; fetch a byte from loaded sector
mov bl, al               ; copy it to bl
and bl, 15               ; isolate 4 lowest bits of bl
shr al, 4                 ; shift bits in al 4 places to the right, losing the four smallest
add al, 48               ; add 48 to convert to ASCII
cmp al, 58              ; check to see if it's a digit or letter
jc 2                      ; jump two bytes on - you'll need to replace this with a jump to a name
add al, 39               ; add 39 if its a letter (the jump bypasses this single line of code)
mov ah, 15             ; colour value for white
stosw                    ; send result and colour value to screen
mov al, bl               ; now for the second part of the number
add al, 48
cmp al, 58
jc 2                      ; jump over next two bytes - again you'll need to use a name instead
add al, 39               ; (the jump bypasses this single line)
stosw                    ; send second part of number to screen
mov al, 32
stosw                    ; send a space to the screen
loop ...                  ; loop back to start of inner loop - use the loop instruction and a name

inc di
inc di
inc di
inc di                     ; set di to start of next screen line

pop cx                   ; recover row count
loop ...                   ; loop back to start of outer loop - use loop instruction and a name
I haven't run that code, so you'll need to check it carefully and debug it if necessary. Once you've got it to work, photograph the screen with a digital camera and post the results here.

Re: Bootloader fails on a real pc

Posted: Sun May 15, 2011 2:43 pm
by DavidCooper
I forgot to say yesterday, but there's a link on Mike Gonta's thread to this:-

http://board.flatassembler.net/topic.php?t=12405
It is important to transfer the image to the physical drive and not the volume drive letter. If the flash drive is partitioned the volume will not start at LBA 0.
The answer to your problem may be in the stuff that follows.

Re: Bootloader fails on a real pc

Posted: Mon May 16, 2011 10:29 am
by Bietje
Problem solved. I will post the solution this evening or tommorow.

Everyone who helped me, THANK YOU.

Re: Bootloader fails on a real pc

Posted: Mon May 16, 2011 3:14 pm
by DavidCooper
The solution may be of great help to other people who are reading this thread and who wish to boot a PC the same way. It might also be worth writing it up in a suitable form for the wiki which, so far as I can see, doesn't cover this. Many people don't want to mess with the hard drive in their machine and USB floppy drives won't be around forever. CDs are slow to start up and slow to write, so they aren't hugely attractive, and they're absolutely no use for booting a netbook on the move. The main problem I can see with USB flash drives is that if a BIOS only lets you treat them as a floppy disk, you're only going to be able to access a tiny amount of their capacity (unless you write your own USB code to access them directly), but I don't know how common that is - it may be that most BIOSes can treat them as hard drives, and if that's the case then it automatically becomes a much more attractive option. Having said that, there is also the question of how you're supposed to organise a sensible directory for a flash drive so that you can not only boot your machine with it, but load and save files as well without having to switch to a different drive, preferably using the same code as you would use to load and save files to another flash drive which you don't use for booting.

By the way, remember to edit your original post to change the thread title to include the word: [solved].

Re: Bootloader fails on a real pc

Posted: Mon May 16, 2011 7:23 pm
by Minoto
Excellent! I'll be looking forward to reading what it turned out to be in the end.

Re: Bootloader fails on a real pc

Posted: Tue May 17, 2011 6:27 am
by Bietje
So, here is the solution.

There were actually two erros. One programming error and one error in the way I stored it onto the usb device.

When an bios emulates an USB pendrive it seems to look in the BPB. An example of a BPB:

Code: Select all

jmp short main
nop
  db '        ' 
  dw 512                        ; bytes per sector 
  db 1                          ; sectors per cluster 
  dw 2                         ; reserved sector count 
  db 2                          ; number of FATs 
  dw 16*14                      ; root directory entries 
  dw 18*2*80                    ; sector count 
  db 0F0h                       ; media byte 
  dw 9                          ; sectors per fat 
  dw 18                         ; sectors per track 
  dw 2                          ; number of heads 
  dd 0                          ; hidden sector count 
  dd 0                          ; number of sectors huge 
bootdisk  db 0                          ; drive number 
  db 0                          ; reserved 
  db 29h                        ; signature 
  dd 0                          ; volume ID 
  db '           '              ; volume label 
  db 'FAT12   '                 ; file system typ
It is importent that the bytes per sector is placed at an offset of 0xB.

The second problem was the way I stored it on my USB device.

When you push the power button of your pc the bios will do alot and after that it will run through all first sectors of all partitions on the first harddisk untill it found the magic word at 0x1FE. So lets asume that there is mounted on /dev/sdb and that it has one partition. If you want the bios to emulate it as harddisk you should do the following:

Code: Select all

dd if=bootstrap.bin of=/dev/sdb1 seek=0
dd if=stage2 of=/dev/sdb seek=1
What does that do?
It puts the bootstrap at the start of the first partition which makes the bios think its an harddisk and you put the second stage at absolute sector 2. That is because bios int 0x13 also uses absolute sector numbers.

If you want to put the entire bootloader (include stage2) in the first partition, then you should use the partition table to calculate the starting sector of the first partition.

If you want the bios to emulate a floppy then you should put the entire bootloader at the first absolute sector:

Code: Select all

dd if=bootloader.bin of=/dev/sdb seek=0
So now you want some working code I think. I added a third stage to simulate chainloading.

The bootstrap:

Code: Select all

[bits 16]
[org 0x7c00]
	
jmp short _start		; 2 byte jump
nop
  db '        ' 		; offset to bytes/sector must be 0xb
  dw 512                        ; bytes per sector 
  db 1                          ; sectors per cluster 
  dw 3                         ; reserved sector count 
  db 2                          ; number of FATs 
  dw 16*14                      ; root directory entries 
  dw 18*2*80                    ; sector count 
  db 0F0h                       ; media byte 
  dw 9                          ; sectors per fat 
  dw 18                         ; sectors per track 
  dw 2                          ; number of heads 
  dd 0                          ; hidden sector count 
  dd 0                          ; number of sectors huge 
bootdisk  db 0                          ; drive number 
  db 0                          ; reserved 
  db 29h                        ; signature 
  dd 0                          ; volume ID 
  db '           '              ; volume label 
  db 'FAT12   '                 ; file system type 

_start: ; entry point
	jmp 0x0:.flush
.flush:
	xor ax, ax
	mov ds, ax
	mov es, ax
	cli
	mov ss, ax
	mov sp, 0x7c00		; stack setup
	sti

	mov [bootdisk], dl ; boot drive number given by the bios in dl

.pokecode:

	mov ax, 0x7e0
	mov es, ax
	xor di, di
	
	mov [es:di], byte 191          ; this code proves that my far jump does its work
	mov [es:di+1], byte 160       ; if you would like to test, comment it out.
	mov [es:di+2], byte 128
	mov [es:di+3], byte 184
	mov [es:di+4], byte 0
	mov [es:di+5], byte 176
	mov [es:di+6], byte  142
	mov [es:di+7], byte 192
	mov [es:di+8], byte 184
	mov [es:di+9], byte 88
	mov [es:di+10], byte 14
	mov [es:di+11], byte 171

.reset:
	xor ax, ax		; reset the disk
	mov dl, [bootdisk]
	int 0x13
	jc .reset

.read:
	mov ah, 0x2
	mov al, 1 ; read 1 sector
	xor cx, cx ; cylinder 0
	mov cl, 2 ; sector 2
	mov dl, [bootdisk]
	xor dh, dh ; head 0
	
	
	; setup buffer
	xor bx, bx
	mov es, bx
	mov bx, 0x7e00
	int 0x13
	jc .read

	test ah, ah
	jnz .reset

	cmp al, 0x1 ; is there one and only one sector loaded?
	jne .reset

	mov ax, 0xb800
	mov es, ax
	xor di, di
	mov al, 65 ; capital A
	mov ah, 0xc 
	stosw


	mov dl, byte [bootdisk]
	jmp 0x0:0x7e00		; execute the loaded sector

times 510 - ($ - $$) db 0
dw 0xAA55
Stage 2:

Code: Select all

[ORG 0x7e00]
[BITS 16]

stage2:
	mov [bootdisk], dl
	mov ax, 0xb800
	mov es, ax
	xor di, di
	mov al, 70
	mov ah, 0xc
	stosw

.reset:
	xor ax, ax		; reset the disk
	mov dl, [bootdisk]
	int 0x13
	jc .reset

.read:
	mov ah, 0x2
	mov al, 1 ; read 1 sector
	xor cx, cx ; cylinder 0
	mov cl, 3 ; sector 3
	mov dl, [bootdisk]
	xor dh, dh ; head 0
	
	
	; setup buffer
	xor bx, bx
	mov es, bx
	mov bx, 0x8000  
	int 0x13
	jc .read

	test ah, ah
	jnz .reset

	cmp al, 0x1 ; is there one and only one sector loaded?
	jne .reset

	mov ax, 0xb800
	mov es, ax
	xor di, di
	mov al, 71
	mov ah, 0xc
	stosw

	jmp 0x0:0x8000
	jmp $

	bootdisk db 0
times 512 - ($ - $$) db 0
Stage 3:

Code: Select all

[ORG 0x8000]
[BITS 16]

stage3:
	mov ax, 0xb800
	mov es, ax
	xor di, di
	mov al, 72
	mov ah, 0xc
	stosw

times 512 - ($-$$) db 0

Re: Bootloader fails on a real pc

Posted: Tue May 17, 2011 5:52 pm
by DavidCooper
I thought the table had a name but couldn't remember what it was: BIOS Parameter Block. So you have to use "jmp short" to get the jump instruction that takes a single byte jump distance, and yet Mike Gonta just uses "jmp" on its own - I can only imagine that he must be using a species of assembler which works differently, automatically using the shorter jumps when it can.
Bietje wrote:When you push the power button of your pc the bios will do a lot and after that it will run through all first sectors of all partitions on the first harddisk until it found the magic word at 0x1FE. So lets asume that there is mounted on /dev/sdb and that it has one partition. If you want the bios to emulate it as harddisk you should do the following:

Code: Select all

dd if=bootstrap.bin of=/dev/sdb1 seek=0
dd if=stage2 of=/dev/sdb seek=1
What does that do?
It puts the bootstrap at the start of the first partition which makes the bios think its a harddisk and you put the second stage at absolute sector 2. That is because bios int 0x13 also uses absolute sector numbers.
I'm a bit confused when it comes to partitions, because if you divide a disk into two parts you would have two partitions on it, one of them starting at absolute sector 1 and the other starting somewhere else. It looks as if what you're calling the "first partition" is what I would think of as the second partition. ...Or am I wrong? Yes, I've just read up on partitions to find out how they work. I was wrong. It looks as if you might be able to have zones of sectors that aren't official partitions at all if you define the standard one/two/three/four partitions in the MBR in such a way as to leave gaps in front of, between and after them. One of those unofficial partitions would include the MBR, and I'm guessing that there might sometimes be a few more sectors at the start of the disk which also don't fall into the first official partition. So the first partition can't start at the start of the storage device and could even be miles away from it, although it could also start at absolute sector 2.
If you want the bios to emulate a floppy then you should put the entire bootloader at the first absolute sector:

Code: Select all

dd if=bootloader.bin of=/dev/sdb seek=0
So that means replacing the MBR and destroying any partitioning that might already have been on the device. If you do this, are you then restricted to using 1.4MB of its capacity, or can you change the way you read it to access sectors far above that limit? It would be worth doing some experiments to find that out now, because if it does restrict you to 1.4MB, you're obviously going to be better off getting it to emulate a hard drive from the outset. I would imagine that all the more recent BIOSes should be able to treat USB flash drives as if they're hard drives, so there's probably no downside to that. It would then be easy to put a loader into its own partition where it doesn't need a directory and then have everything else stored as files within a standard filesystem (or one of your own design) in a separate partition which the loader can access to load them in. The loader could also be written in such a way as to offer you a choice of which version of your OS to load so that you can make modifications to it, save the new version, boot that new version to test it, and then if it crashes you can simply try again and boot the old version from the same device and have another go at creating a new version: you would be able to load, modify and save your OS without ever having to use any external software, running it all off a single USB flash drive (though you'd obviously make frequent backup copies onto other flash drives as well). I'm going to have to try all that myself, so thanks for encouraging me to explore this option. I wonder if it can also be done with micro SD cards - you can get tiny card readers for them which make them behave like ultra-compact USB flash drives which are less likely to damage the USB port if you accidentally lean on them, and with the added option of swapping the cards just like floppy disks in a USB floppy drive without upsetting the BIOS (although the BPB may have to be in the same place, and maybe the boot partition as well - could be complications).