Real machine vs bochs

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Dear Brendan

I have been going over this for a while now and still nothing promising. CHS (int 13 ah = 02h) also only works on bochs but not the real Laptop.
I have looked into your comment concerning a properly formatted USB and used Diskpart to properly clean, create partition, make it active and format and assign letter. Still not working ... The last thing was I dont set any value to the CS register. Its always left as is. you said that you needed to see the ORG value to determine the correct value for CS, I have tried to search for how does the CS and ORG work and I cant really find any thing ( all results talk about how to use the ORG as a place to load and padding and stuff). Any clarification would be greatly appreciated.

Thank you very much
Ahmed
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Real machine vs bochs

Post by rdos »

The code should not assume it is invoked at 07C0:0000. Rather, to play it safe, it should only assume that it's loaded at linear address 7C00. To fix this problem, it should do a far jmp before accessing labels or variables like this:

Code: Select all

jmp 7C0h:main

main:
Alternatively, if you want to keep the BPB: (make sure the jmp to Startup is a relative jmp, not an absolute, otherwise it will still break)

Code: Select all

jmp Startup
nop

; put BPB here

Startup:
    jmp 7C0h:main

main:
In case the assembler doesn't support the direct far jmp coding, you can do it with dbs and dws like this:

Code: Select all

    db 0EAh
    dw OFFSET main
    dw 7C0h
The above code uses MASM/WASM/TASM syntax. I leave it up to you to translate that to NASM if you use that.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Dear rdos

Thank you very much for your input. However, I have tried everything you mentioned but still no luck. Can you please take a look at the code and tell me if there is anything I am missing ( btw, the code with and before your modifications work great on bochs, but still only boots the laptop but doesnt load the second stage for some reason)

Here is the complete code and setup

Code: Select all

[bits 16]						
org 0x0000						
jmp Startup
nop

;*********************************************
;	BIOS Parameter Block
;*********************************************
bpbOEM					db "ATLAM OS"
bpbBytesPerSector:  	DW 512
bpbSectorsPerCluster: 	DB 1
bpbReservedSectors: 	DW 2
bpbNumberOfFATs: 		DB 1
bpbRootEntries: 		DW 512
bpbTotalSectors: 		DW 0xFFFF
bpbMedia: 				DB 0xf8  ;; 0xF1
bpbSectorsPerFAT: 		DW 494
bpbSectorsPerTrack: 	DW 18
bpbHeadsPerCylinder: 	DW 2
bpbHiddenSectors: 		DD 0
bpbTotalSectorsBig:     DD 0
DRIVE_NUMBER            equ 7C24h
DRIVE_TYPE              equ 7C3Eh
NUMBER_OF_HEADS         equ 7C1Ah
NUMBER_OF_DRIVES        equ 7C3Fh
SECTORS_PER_TRACK       equ 7C18h
bsExtBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT16   "

;*********************************************
;		End of BIOS PARAMETER BLOCK
;*********************************************

;************************************************;
;	Prints a string
;************************************************;
Print: 
			lodsb				; load next byte from string from SI to AL
			or	al, al			; Does AL=0?
			jz	PrintDone		; Yep, null terminator found-bail out
			mov	ah, 0eh			; Nope-Print the character
			int	10h
			jmp	Print			; Repeat until null terminator found
	PrintDone:
ret								; we are done, so return

;************************************************;
; Convert CHS to LBA
;************************************************;

ClusterLBA:
          sub     ax, 0x0002                          ; zero base cluster number
          xor     cx, cx
          mov     cl, BYTE [bpbSectorsPerCluster]     ; convert byte to word
          mul     cx
          add     ax, WORD [datasector]               ; base data sector
          ret
     
;************************************************;
; 			Failing to Load Proceedure
;************************************************;		
		
FAILURE:
		
        mov     si, msgFailure
        call    Print
        mov     ah, 0x00
        int     0x16                                ; await keypress
        int     0x19                                ; warm boot computer
;************************************************;
; Convert LBA to CHS
; AX=>LBA Address to convert
;
; absolute sector = (logical sector / sectors per track) + 1
; absolute head   = (logical sector / sectors per track) MOD number of heads
; absolute track  = logical sector / (sectors per track * number of heads)
;
;************************************************;

LBACHS:
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [SECTORS_PER_TRACK]           ; calculate
          inc     dl                                  ; adjust for sector 0
          mov     BYTE [absoluteSector], dl
          xor     dx, dx                              ; prepare dx:ax for operation
          div     WORD [NUMBER_OF_HEADS]          ; calculate
          mov     BYTE [absoluteHead], dl
          mov     BYTE [absoluteTrack], al
          ret
;************************************************;
; Reads a series of sectors
; CX=>Number of sectors to read
; AX=>Starting sector
; ES:BX=>Buffer to read to
;************************************************;

ReadSectors:
     .MAIN
          mov     di, 0x0005                          ; five retries for error
     .SECTORLOOP
          push    ax
          push    bx
          push    cx
          call    LBACHS                              ; convert starting sector to CHS
          mov     ah, 0x02                            ; BIOS read sector
          mov     al, 0x01                     	      ; read one sector
          mov     ch, BYTE [absoluteTrack]            ; track
          mov     cl, BYTE [absoluteSector]           ; sector
          mov     dh, BYTE [absoluteHead]             ; head
          mov     dl, BYTE [DRIVE_NUMBER]            ; drive
          int     0x13                                ; invoke BIOS
          jnc     .SUCCESS                            ; test for read error
          xor     ax, ax                              ; BIOS reset disk
          int     0x13                                ; invoke BIOS
          dec     di                                  ; decrement error counter
          pop     cx
          pop     bx
          pop     ax
          jnz     .SECTORLOOP                         ; attempt to read again
          int     0x18
     .SUCCESS
          mov     si, msgReadSuccess
          call    Print
          pop     cx
          pop     bx
          pop     ax
          add     bx, WORD [bpbBytesPerSector]        ; queue next buffer
		  inc     ax                                  ; queue next sector
          loop    .MAIN                               ; read next sector
          ret

;*********************************************
;	Bootloader Entry Point
;*********************************************
Startup:
jmp 0x07C0:main

main:
;----------------------------------------------------
     ; code located at 0000:7C00, adjust segment registers
     ;----------------------------------------------------
		 cli						; disable interrupts
		 
         mov     ax, 0x07C0				; setup registers to point to our segment
		 mov     ds, ax
         mov     es, ax
         mov     fs, ax
         mov     gs, ax

     ;----------------------------------------------------
     ; create stack
     ;----------------------------------------------------
     
      mov     ax, 0x0000				; set the stack
      mov     ss, ax
      mov     sp, 0xFFFF
      sti								; restore interrupts
	 ;----------------------------------------------------
	 CLD
	 
DiskParam:
	 
push dx 
push es 
mov ah, 8 
int 13h                                                        ; get drive parameters 
mov [DRIVE_TYPE], bl 
and cx, 3Fh                                                  ; maximum sector number 
mov [SECTORS_PER_TRACK], cx 
mov [NUMBER_OF_DRIVES], dl 
movzx dx, dh                                                 ; maximum head number 
add dx, 1 
mov [NUMBER_OF_HEADS], dx 
pop es 
pop dx 
mov [DRIVE_NUMBER], dl

LOAD:
          xor 	  cx,cx
          xor 	  ax,ax
	  xor     bx,bx
          mov    ax, 0x0210     				       ; LBA of Sector to read
          mov    bx, 0x0440                                     ; Address to Load to
	  mov    cx, 0x0002				       ; Number of sectors to read
	  call     ReadSectors
		  
	mov     cx, 0x000D                 	                ; Counter String length
	mov		di,0x05A3					; Expected String Location in RAM
	mov     si, String 					        ; String requiring matching
    repe cmpsb                                                     ; test for entry match
	je      KERNL
	jmp     FAILURE
    
KERNL:
mov     si, msgConfirmString
call    Print

jmp 	0x07C0:0x0440
;*********************************************
;		Messages Section
;*********************************************



String 									db "Searching for Operating System"
msgReadSuccess 							db 0x0D, 0x0A, "Krnl Rd Suc", 0x0D, 0x0A, 0x00
msgConfirmString 						db 0x0D, 0x0A, "Kernel Confirmed in Memory", 0x0D, 0x0A, 0x00
msgReadFail 							db 0x0D, 0x0A, "Krnl Rd Fld", 0x0D, 0x0A, 0x00
msgFailure  							db 0x0D, 0x0A, "ERR:Pres Key Rbt", 0x0A, 0x00
;*********************************************
;			Data Section
;*********************************************
absoluteSector 						db 0x00
absoluteHead   						db 0x00
absoluteTrack  						db 0x00     
datasector  						dw 0x0000
cluster    							dw 0x0000
 

;*********************************************
;		Boot Sector Signature
;*********************************************
TIMES 510-($-$$) DB 0
DW 0xAA55


Second Stage is found in sector 528 and 529 (Decimal) in the USB. This has been confirmed using HxD. (Please see attached picture to confirm I am using the correct addressing)

At this point I have abandoned any attempts for reading FAT and Root and looking for the file and stuff (excuse me for the stupid code) I just need to be able to load ANYTHING in to the laptops RAM beyond what the BIOS does for me by loading the boot sector. Please take a look and let me know.

Thank you very much for your help
Ahmed
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Real machine vs bochs

Post by rdos »

Can you provide a list file? Are you sure that the initial jmp is short and not near? Especially since you didn't locate the code for jumping to 7c0:main directly after the BPB.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Real machine vs bochs

Post by Combuster »

On a test laptop (Lenovo T61), the code starts booting (ie print messages ect .. ) I can read and write to USB stick
bpbSectorsPerTrack: DW 18
bpbHeadsPerCylinder: DW 2
An USB stick that's configured as if it were a stack of floppies... that sounds really really kludgy...

I wouldn't try using what used to be a FAT12 bootloader for a CHS medium on something that's not CHS at all - instead you'll have to write a new boootsector that's LBA capable and matches the actual filesystem on the medium. The part that says "fat16" will always be ignored by windows as it'll compute the total sector count and decides which FAT entry size to use based on that.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Real machine vs bochs

Post by Brendan »

Hi,

As far as I can tell this code tries to read a sector that can't exist (sector 0), and after 5 attempts it tries "int 0x18" which probably does nothing at all, and after int 0x18 has done nothing the code displays "success" even though nothing worked.

Notes:
  • For the older "int 0x13" BIOS functions that use CHS, sectors are numbered starting from sector 1, and there is no sector 0 because that would be "the sector before the first sector".
  • Once upon a time there used to be a BASIC interpreter in ROM, and "int 0x18" was used to start this BASIC interpreter. The BASIC interpreter hasn't existed for about 30 years, so now all you get from "int 0x18" is undefined behaviour.
  • Good code tells the user that an error occurred and also tells the user what the problem was (e.g. "BIOS returned 'bad sector detected' error when trying to read boot loader" or "BIOS returned 'no media in drive' when trying to read boot loader" or whatever else). Crappy code just says that an error occurred and doesn't help the user figure out what happened or give the user any idea of how to fix the problem (e.g. "Failed to read boot loader"). Of course sometimes the end user is you (the programmer) and acceptable error handling/reporting is a massive advantage for debugging. The BIOS disk functions return a status code in AH that should be used to tell the user what the problem is (see this web page for a list of what the different status codes mean).

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Real machine vs bochs

Post by egos »

Ahmed wrote:Here is the complete code and setup...
Uh...

Code: Select all

						
org 0x0000 ; in many cases org 7C00h will be more suitable
jmp Startup ; you use non-standard Startup location,
nop ; so are you sure that jump instruction is really short?
...
bpbReservedSectors: 	DW 2 ; for FAT12/16 recommendable value of this field is 1
...
bpbHiddenSectors: 		DD 0 ; for partitions this field should hold non-zero value
bpbTotalSectorsBig:     DD 0
DRIVE_NUMBER            equ 7C24h ; where is drive number field?
DRIVE_TYPE              equ 7C3Eh ; these offsets are valid only in segments with zero base
NUMBER_OF_HEADS         equ 7C1Ah
NUMBER_OF_DRIVES        equ 7C3Fh
SECTORS_PER_TRACK       equ 7C18h
bsExtBootSignature: 	DB 0x29
...
Startup:
jmp 0x07C0:main ; this technique is necessary only if you use absolute addressing in jump/call instructions later

         mov     ax, 0x07C0 ; save the space, use mov ax,cs
...
         mov     fs, ax ; are you really need these registers?
         mov     gs, ax
...
      mov     ax, 0x0000 ; save the space, use xor ax,ax
      mov     ss, ax
      mov     sp, 0xFFFF ; it is very, very bad; try mov sp,7C00h
...and so on. Do you understand what I mean?
Second Stage is found in sector 528 and 529 (Decimal) in the USB. This has been confirmed using HxD. (Please see attached picture to confirm I am using the correct addressing)
BIOS can hide all sectors before partition, so use HiddenSectors field to get the "base".
If you have seen bad English in my words, tell me what's wrong, please.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Ok
so I added this right after the INT 0x13

cmp ah,00h
jne Failure

and it doesnt go to failure routine, so the last operation code indicates a successful read.

also the obsolete INT 0x18 ( which was a part of some tutorial) never gets to see the light. the code jumps to the success (to my surprise) routine every time. This is verified as it only prints the read success message 2 times (once for each sector) then hangs when it jumps to an empty memory location


I have also tried an LBA version as opposed to the current CHS version we are discussing ( posted the code earlier) still not working.

what I dont understand and no body seems to be answering that question is WHY DOES THE BIOS THINK AND BEHAVE LIKE IT JUST HAD A SUCCESSFUL READ AND THEN THERE IS NOTHING IN THE MEMORY. like for example, am I loading the code at an address different than the address I jump to? am I actually reading sectors 528 and 529 (from the USB LBA notation with the boot sector being sector 0) ?

Because other than that I really dont think that any good or bad coding practices ( like BPB values ... I get the BIOS emulated disk geometry with the IN0x13 at the beginning so no assumptions and I dont calculate anything else, I am just trying to load anything from the direct location of sectors 528 and 529 ) can severely affect a BIOS function like that. The fact is that my stupid BIOS executes an INT 0x13 (Both CHS & LBA versions) with correct addressing ( as far as I know and these addresses worked well on Bochs, but please DO correct me if you spot anything with the addressing) , returns a successful read code (ah = 00h) and no carry flag is set and YET THERE IS NOTHING IN THE MEMORY (people please address this phenomenon, I will clean up the code as I gain experience but this is very fundamental and just needs a straight up answer. Also please please please include the required changes or how you would do it if possible rather than pointing out the mistake). I am starting to feel like I am the only idiot who had to deal with this problem or has a broken BIOS on his laptop

egos wrote:BIOS can hide all sectors before partition, so use HiddenSectors field to get the "base".
Thank you very much Egos. Now this potentially looks promising but I really dont know what you mean here so can you please kindly elaborate more
Brendan wrote: As far as I can tell this code tries to read a sector that can't exist (sector 0)
Thank you very much Brendan. However, I am not sure what you mean here by doesnt exist. If so, why does it return a successful read code and why does an exact disk image on bochs find the sectors and read them no problem and I never tried to read sector 0 anyway (thats the boot sector which is already in RAM) so can you please elaborate more on that.

Thank you very much
Ahmed
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Dear Rdos
can you please explain what do you mean with a file list ?? Like do you want me to post all the source files and a disk image to see if the addressing is correct ??

best regards
Ahmed
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Real machine vs bochs

Post by egos »

Ahmed wrote:Thank you very much Egos. Now this potentially looks promising but I really dont know what you mean here so can you please kindly elaborate more
If your partition starts at LBA N then BIOS can hide sectors 0...N-1 and put zero into HiddenSectors. In this case to read sector N, N+1, ... you should read sector 0, 1, ... through BIOS. To read USB drive correctly in any case you should put N into HiddenSectors and then use current value of this field in your code as the "base", i.e. you should calculate absolute number of the sector to read: HiddenSectors value + relative number of the sector to read.
Thank you very much Brendan. However, I am not sure what you mean here by doesnt exist. If so, why does it return a successful read code and why does an exact disk image on bochs find the sectors and read them no problem and I never tried to read sector 0 anyway (thats the boot sector which is already in RAM) so can you please elaborate more on that.
Brendan means that in CHS S=0 is incorrect value.
If you have seen bad English in my words, tell me what's wrong, please.
User avatar
Minoto
Member
Member
Posts: 89
Joined: Thu May 12, 2011 7:24 pm

Re: Real machine vs bochs

Post by Minoto »

Ahmed wrote:Second Stage is found in sector 528 and 529 (Decimal) in the USB. This has been confirmed using HxD. (Please see attached picture to confirm I am using the correct addressing)

At this point I have abandoned any attempts for reading FAT and Root and looking for the file and stuff (excuse me for the stupid code) I just need to be able to load ANYTHING in to the laptops RAM beyond what the BIOS does for me by loading the boot sector. Please take a look and let me know.
Hi, Ahmed -- you've mentioned using diskpart to clean and create a partition on your USB device, so I'm assuming that it's set up like a normal hard disk, with an MBR containing a partition table at LBA 0, probably followed by some reserved space, and then the actual partition. You've also mentioned confirming the location of your second stage at sectors 528 and 529 using HxD -- the picture you mentioned attaching to that post didn't make it, so this is a guess, but I'm assuming that you meant HxD showed your data in sectors 528 and 529 when you used it to view that partition. If that's the case, then reading the sectors at LBA 528 and 529 is not going to load your second stage, because the sector numbers displayed by HxD are relative to the start of the partition, while the extended read / write functions of int 13h use sector numbers relative to the start of the device. (And even if you translate to CHS, 0 / 0 / 1 is still going to get you the first sector of the device, not the first sector of the partition.)

For example, I have a 4GB thumb drive with a single FAT32 partition on it. Reading sector 0 of the device via int 13h gets me the MBR and partition table, which shows one active partition starting at LBA 128. Reading sector 128 of the device gets me my bootsector, which HxD shows at sector 0 of the partition. That bootsector loads a few more sectors starting at sector 144 of the device, which HxD shows at sector 16 of the partition. And so on -- if you've already taken this into consideration, then my apologies, but in reading through the thread, I didn't see anything that completely ruled it out in my mind, and it's the sort of thing that would explain your reads not returning an error code (because they did work just fine) and also returning zeroes (because you were reading empty sectors some offset away from the ones you meant to read.)
Those who understand Unix are doomed to copy it, poorly.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Thanks alot guys !! I appreciate your input !!

Now we are on to something !! No I did not account for any partitioning, i set up the USB using HxD the same way I set up a disk Image for Bochs! I am a newbie and I wasnt aware of the partition table thingy ( so that could very well explain why there are always zeros in the RAM)

I am going to look into how to setup partitions and where they are in the disk and let you know how things work out !!!

@ Minoto : Thanks for the tip and yes you are right the picture should have showed the Hexdump of Stage 2 located at sectors 528 and 529, so I guess given the fact that there is a partition table which I need to worry about, they are not physically @ 528 and 529 (which is how LBA addressing works by targeting PHYSICAL location) which means I am loading empty sectors from the FAT , hence the zeros !!!

@Egos : Thanks alot for the hiding sectors tip, just let me make sure that I understand this correctly, so if I need to load 528 and 529

(if not too much to ask please correct my steps if I am mistaken !!)

1) account for the Partition table ( ie translate 528 and 529 to their ACTUAL physical location on the disk including the partition table not just assume MBR is 0) (minotos tip for accounting for the partition table)

2) put (value translated - 1) in the hidden sectors (egos tip for reading the disk correctly to avoid the bios hiding the sectors)

3) execute an INT 0x13 with LBA value = value translated, and sectors to read = 2

4) jmp to the segment: offset value I read the sectors to

and that should work ?

Thanks alot guys !! appreciate it !!!

Also to who ever else that may be reading this and is involved in creating/maintaining a tutorial I think this is a very very very important thing to mention and clarify the difference between bochs (or what ever else emulator) and the real thing. It was only possible for me to realize this by the efforts of this great community and non of the online tutorials mention this !!

I will let you guys know how things work out
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Real machine vs bochs

Post by Combuster »

I think this is a very very very important thing to mention and clarify the difference between bochs (or what ever else emulator) and the real thing.
That difference is less important than the one between an USB stick and a floppy, a MBR scheme and a lack of partitions, and between FAT12 and FAT16/32 though, as it's not the emulators that are responsible for those...
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Real machine vs bochs

Post by egos »

Ahmed, show dump of your PHYSICAL disk up to last sector of your "stage 2".
If you have seen bad English in my words, tell me what's wrong, please.
User avatar
Minoto
Member
Member
Posts: 89
Joined: Thu May 12, 2011 7:24 pm

Re: Real machine vs bochs

Post by Minoto »

Ahmed wrote:(if not too much to ask please correct my steps if I am mistaken !!)

1) account for the Partition table ( ie translate 528 and 529 to their ACTUAL physical location on the disk including the partition table not just assume MBR is 0) (minotos tip for accounting for the partition table)

2) put (value translated - 1) in the hidden sectors (egos tip for reading the disk correctly to avoid the bios hiding the sectors)
I'm not sure about that explanation of the hidden sectors field...every reference I've checked just describes it as the number of sectors before the start of the partition. If the BPB is accurate, it should already contain the number you need for your step 1, and there would be no reason to change it. It gives you the LBA of the start of the partition, so you can determine the LBA of a partition-relative sector by just adding the number of "hidden" sectors. In your example, if it was 128, the LBA of the first sector of your second stage would be 128 + 528 = 656. This is your translated value for step 3.
Ahmed wrote: 3) execute an INT 0x13 with LBA value = value translated, and sectors to read = 2

4) jmp to the segment: offset value I read the sectors to

and that should work ?
Yes.
Those who understand Unix are doomed to copy it, poorly.
Post Reply