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

Real machine vs bochs

Post by Ahmed »

Hello Everyone !
I am experiencing the same problem. My code runs great Bochs no problems at all.
On a test laptop (Lenovo T61), the code starts booting (ie print messages ect .. ) I can read and write to USB stick no problem, However, the laptop hangs (or enters the FAILURE routine in the code) every time I try to access memory outside the initial 512 bytes of the boot sector the BIOS loaded for me. I can perform the same exact code if I overwrite the zeros at the end of the boot sector, but outside the range 0x7c00 <->0x7E00 I can only write to the memory (ie load FAT or root directory) but never read it (ie jmp or mov ax, WORD[OutOfRange] ).

One thing I have also noticed was that the Laptop NEVER NEVER NEVER Triple Faults and restarts ... regardless of the code (even when I actively try to do so) , it just hangs or quits booting and looks for other devices then says cant find a bootable device.

is there some sort of built in security/protection thingy with Lenovo laptops ? or do I need to enable something like the A20 line ?
I really need help on this one, I am going nuts here !! ANY help is appreciated!!
Ahmed
stlw
Member
Member
Posts: 357
Joined: Fri Apr 04, 2008 6:43 am
Contact:

Re: real machine vs bochs

Post by stlw »

One thing I have also noticed was that the Laptop NEVER NEVER NEVER Triple Faults and restarts ... regardless of the code (even when I actively try to do so) , it just hangs or quits booting and looks for other devices then says cant find a bootable device
normally hardware goes to shutdwn state after repple fault and not rebooting. shutdown state is more similar to HALT with no interrupts enabled so oly NMI could take you out of it ...
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,
Ahmed wrote:is there some sort of built in security/protection thingy with Lenovo laptops ? or do I need to enable something like the A20 line ?
I doubt it.

More likely is that you're making assumption/s that are wrong, or there's some sort of bug in your code somewhere. For example, maybe you're assuming that the BIOS leaves DS set to 0x0000 and different BIOSs leave it set to different things, and this works on Bochs which does leave DS set to 0x0000 but fails on your laptop because its BIOS leaves DS set to ROM or something.

Of course I haven't seen your code so I can't know what your code does. If I did see your code it might help... ;)


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.
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 »

As long as you're in real mode, getting an actual triple fault is exceptionally difficult to do. Typically if you screw up there, it goes into a Exception-IRET loop or cycling around garbage code, where you might be able to toss a ctrl+alt+del in between depending on the setting of IF and the degree of damage you inflicted on the IVT.

So, my educated guess is that your code is sufficiently broken that it never reaches the code to set PE=1 on actual hardware, and any attempts to worsen the situation obviously won't add back that functionality.
"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 ]
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Real machine vs bochs

Post by rdos »

Personally, I prefer to run most of my testing on a range of real machines. As soon as you have a kernel that boots, and that can trap exceptions and display them, it seems like a good idea to test on both real hardware and on emulators.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Hi everyone !!
I am sorry but I have been away for a while on work.
I believe I have the segments setup right ( like the tutorial at least) here is the beginning of the code
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
;----------------------------------------------------


mov BYTE [bsDriveNumber],dl ;Save Drive Number from BIOS

LOAD_ROOT:
; compute size of root directory and store in "cx"

mov ax, 0x0020 ; 32 byte directory entry
mul WORD [bpbRootEntries] ; total size of directory
div WORD [bpbBytesPerSector] ; sectors used by directory
mov WORD [DAP.Sectors], ax
add WORD [datasector],ax

; compute location of root directory and store in "ax"
xor ax,ax
mov al, BYTE [bpbNumberOfFATs] ; number of FATs
mul WORD [bpbSectorsPerFAT] ; sectors used by FATs
add ax, WORD [bpbReservedSectors] ; adjust for bootsector
mov WORD [rootsector], ax ; Start of root directory
add WORD [datasector], ax


; read root directory into memory
mov WORD [DAP.LBA], ax
mov WORD[DAP.Offset], 0x7E00 ; copy root dir below bootcode
mov WORD[DAP.Segment], 0x0000
call ReadDisk ; ReadDisk routine has a print success message that confirms it has been executed well, so I know it goes this far

;----------------------------------------------------
; Find stage 2 @ 0x7CDC
;----------------------------------------------------

mov cx, WORD [bpbRootEntries] ; load loop counter
mov di, 0x0200 ; locate first root entry
.LOOP:
push cx
mov cx, 0x000B ; eleven character name
mov si, ImageName ; image name to find
push di
repe cmpsb ; test for entry match
pop di
je LOAD_FAT
pop cx
add di, 0x0020 ; queue next directory entry
loop .LOOP
jmp FAILURE1 ; This is the point where the Failure routine is triggered. Prints the message specific for this routine entry. Honestly I cannot tell whether the computer cannot access the memory locations so when cx runs out it just enters here, or if there is a problem with reading the disk routine, so this loop is working fine but the string I am looking for is not there.

; ReadDisk Routine
ReadDisk:
mov dl, [bsDriveNumber]
mov si,DAP
mov ah, 42h
int 13h
jnc .success
call FAILURE
ret
.success:
mov si,msgReadSuccess
call Print
ret

DAP:
.Size DB 0x0010 ; first byte of DAP gives the DAP total size = 16 bytes
.NULL DB 0x0000 ; Second byte Reserved
.Sectors DW 0x0002 ; Number of Sectors to READ
.Offset DW 0x0500 ; off set pointer to the memory location in which the read sectors will be transfered
.Segment DW 0x0000
.LBA DQ 34; ;absolute number of the start of sectors to be read. Note: First sector of the drive (boot sector) is numbered as 0

Other than that it works like a charm on Bochs which is very frustrating
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

also please ignore the @0xxxxx in the comments, these are break points I used for debugging in bochs, they change each time I change the code so I dont think any of them matter now
User avatar
Yoda
Member
Member
Posts: 255
Joined: Tue Mar 09, 2010 8:57 am
Location: Moscow, Russia

Re: Real machine vs bochs

Post by Yoda »

1. You initialized all segment registers except CS. This is you problem.
2. I don't see ORG instruction. It is needed to know the correct values for CS and addresses.
3. You set different values for stack segment and data. This is not problem but it is harder to address the same data through different segments. Better to initialize all segments to 0.
4. There is no need to disable interrupts at the start of you code.
5. You have misaligned stack. Load 0 to SP too to start the stack from the top of segment.
Yet Other Developer of Architecture.
OS Boot Tools.
Russian national OSDev forum.
User avatar
Griwes
Member
Member
Posts: 374
Joined: Sat Jul 30, 2011 10:07 am
Libera.chat IRC: Griwes
Location: Wrocław/Racibórz, Poland
Contact:

Re: Real machine vs bochs

Post by Griwes »

6. You used colors in a post, which is forbidden here.
Reaver Project :: Repository :: Ohloh project page
<klange> This is a horror story about what happens when you need a hammer and all you have is the skulls of the damned.
<drake1> as long as the lock is read and modified by atomic operations
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Thanks alot guys for all the help I really appreciate it.

as you can probably tell, I am not a SC guy (as in I didnt study any of this, all is self taught so please be a bit more patient). I am really a bit lost when it comes to the segments part. I get how the Virtual addressing works , the shift and add thingy (thats how I made it work on Bochs, I would just debug, find out what the SI or DI value at the particular cmp operation going on, find the Physical address of memory using bochs and then subtract, but really I have no clue what CS is used for, I know CS is for code segment and DS is for data segment, but thats it)

Here is the whole thing is black and white !!

Code: Select all

[bits 16]						
org 0						

start: 
jmp main					; jump to start of bootloader

;*********************************************
;	BIOS Parameter Block
;*********************************************
bpbOEM					db "XYZXYZXY"
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
bsDriveNumber: 	        DB 0
bsUnused: 				DB 0
bsExtBootSignature: 	DB 0x29
bsSerialNumber:	        DD 0xa0a1a2a3
bsVolumeLabel: 	        DB "MOS FLOPPY "
bsFileSystem: 	        DB "FAT16   "

;*********************************************
;		End of FAT32 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

;************************************************;
; Read Disk Function (LBA)
;************************************************;

 ReadDisk: 
		mov dl, [bsDriveNumber]
		mov si,DAP
		mov ah, 42h
		int 13h
		jnc .success
		call FAILURE
		ret
	.success:
		mov si,msgReadSuccess
		call Print		
ret    
		
;************************************************;
; Convert CHS to LBA
; LBA = (cluster - 2) * sectors per cluster
;************************************************;

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
;************************************************;
; 			Reset Disk Function
;************************************************;			
		

;*********************************************
;	Bootloader Entry Point
;*********************************************

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
	 ;----------------------------------------------------
		  
		mov BYTE [bsDriveNumber],dl		;Save Drive Number from BIOS
					
		LOAD_ROOT:
     
     ; compute size of root directory and store in "cx"
     
          
          mov   ax, 0x0020                           ; 32 byte directory entry
          mul   WORD [bpbRootEntries]                ; total size of directory
          div   WORD [bpbBytesPerSector]             ; sectors used by directory
          mov	WORD [DAP.Sectors], ax
		  add 	WORD [datasector],ax
          
     ; compute location of root directory and store in "ax"
		  xor 		ax,ax
          mov     	al, BYTE [bpbNumberOfFATs]            	; number of FATs
          mul     	WORD [bpbSectorsPerFAT]               	; sectors used by FATs
          add     	ax, WORD [bpbReservedSectors]         	; adjust for bootsector
          mov     	WORD [rootsector], ax                 	; Start of root directory
          add     	WORD [datasector], ax 				
		  
		
	 ; read root directory into memory 
		  mov 		WORD [DAP.LBA], ax
          mov     	WORD[DAP.Offset], 0x7E00                            ; copy root dir below bootcode
		  mov 		WORD[DAP.Segment], 0x0000
          call 		ReadDisk
		
;----------------------------------------------------
; 				Find stage 2 @ 0x7CDC
;----------------------------------------------------

		 
		  mov     cx, WORD [bpbRootEntries]             ; load loop counter
          mov     di, 0x0200                            ; locate first root entry
     .LOOP:
          push    cx
          mov     cx, 0x000B                            ; eleven character name
          mov     si, ImageName                         ; image name to find
          push    di
     repe cmpsb                                         ; test for entry match
          pop     di
          je      LOAD_FAT
          pop     cx
          add     di, 0x0020                            ; queue next directory entry
          loop    .LOOP
          jmp     FAILURE
		  
     ;----------------------------------------------------
     ; Load FAT
     ;----------------------------------------------------

     LOAD_FAT: ; at this point, di contains the adress of the matached string containing the File name I am looking for, now we find the Starting Cluster @ offset 26 from the Root Entry 
     
          mov     dx, WORD [di + 0x001A]
          mov     WORD [cluster], dx                  ; file's first cluster			@0x7CEA
          
     ; compute size of FAT and store in "cx"
	 ; This is a bad practice, but for my purpose I will just Load 2 sectors from the Fat and that should be more than enough for booting to get all the required files
	 ; Fat is too Large (494 Sectors)
     
          mov     WORD[DAP.Sectors], 0x0002

     ; compute location of FAT and store in "ax"
		  xor 	  ax,ax
		  mov	  ax , WORD[bpbReservedSectors]
		  mov     WORD[DAP.LBA], ax       						; adjust for bootsector  @0x7D01
          
     ; read FAT into memory (0x1000:0x0000) ie right after the Root directory
		  mov 		ax, WORD[FatMemLoc]
		  mov     	WORD[DAP.Offset], ax                          ; copy FAT above bootcode
		  mov		WORD[DAP.Segment], 0x0000
		  call    	ReadDisk
		  mov     si, msgPointer							;@0x7D16
          call    Print
          
		  
	;----------------------------------------------------
     ; Load Stage 2
     ;----------------------------------------------------
		  mov     WORD[DAP.Offset], 0x8040
		  mov	  WORD[DAP.Segment], 0x0000
		  mov	  WORD[DAP.Sectors], 0x0001
     LOAD_IMAGE:
	 ; read image file into memory (0070:0000)
		  
		  mov     ax, WORD [cluster]                  ; cluster to read
          call    ClusterLBA                          ; convert cluster to LBA
		  
		  mov	  WORD[DAP.LBA] , ax
          call    ReadDisk
         
          
     ; compute next cluster
     
          inc 	  WORD [cluster] ;							@0x7D37
		  mov     bx, 0x0400
		  mov 	  cx, 0x0200
		  .LOOP2:
		  mov 	  dx, WORD[bx];								@0x7D42
		  cmp 	  dx, WORD [cluster];						@0x7D44
		  je	  .Match;									@0x7D48
		  add	  bx,0x0002;								@0x7D4A
		  loop	  .LOOP2;									@0x7D4D
		  jmp 	  FAILURE;									@0x7D4F
          
	 .Match:
		
		
		  add 	  bx, 0x0002;@0x7D52
		  mov 	  dx, WORD[bx];@0x7D55
		  cmp     dx, 0xFFFF                          ;     @0x7D57
		  je      DONE
		  add 	  WORD[DAP.Offset], 0x0200
          jmp 	  LOAD_IMAGE
          
     DONE:
		  add 	  WORD[DAP.Offset], 0x0200
		  mov     ax, WORD [cluster]                  ; cluster to read
          call    ClusterLBA                          ; convert cluster to LBA
		  mov	  WORD[DAP.LBA] , ax
          call    ReadDisk
          mov     si, msgCRLF
          call    Print
		  
		  mov si, msgPointer
		  call Print
		  
		  
    	  
          jmp 0x0000:0x8040
		  	  
;*********************************************
;		Messages Section
;*********************************************



msgPointer				 				db 0x0D, 0x0A, "***", 0x0D, 0x0A, 0x00 
msgReadSuccess 							db 0x0D, 0x0A, "Krnl Rd Suc", 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
;*********************************************
	DAP:
   .Size      	DB 0x0010			; first byte of DAP gives the DAP total size = 16 bytes
   .NULL      	DB 0x0000			; Second byte Reserved
   .Sectors   	DW 0x0002			; Number of Sectors to READ
   .Offset      DW 0x0500			; off set pointer to the memory location in which the read sectors will be transfered
   .Segment   	DW 0x0000		
   .LBA      	DQ 34; 				;USB 65537 Bochs 34 : absolute number of the start of sectors to be read. Note: First sector of the drive (boot sector) is numbered as 0
  
	
    datasector  dw 0x0000
	rootsector  dw 0x0000
	FatMemLoc	dw 0x8000
    cluster     dw 0x0000
    ImageName   db "KRNLDR  SYS"
    msgCRLF     db 0x0D, 0x0A, 0x00
    msgProgress db ".", 0x00
     

 

;*********************************************
;		Boot Sector Signature
;*********************************************

	 TIMES 510-($-$$) DB 0
     DW 0xAA55
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,

The "repe cmpsb" depends on the CPU's direction flag, which hasn't been set to anything. If this flag happens to be left set by the BIOS, the CPU will decrement SI and DI after each comparison and the string comparison will fail to find a match.

Also; normally hard drives are partitioned, but you aren't using any "start of partition" or anything anywhere so this code can't be for a partitioned hard drive. The "extended disk read" BIOS function normally doesn't work for floppies, so this code can't be for a floppy disk either.

This makes me think it's designed for an unpartitioned hard drive, which is extremely rare. In this case maybe the laptop's BIOS gets all confused (e.g. checks if there's a sane partition table, doesn't find one and decides the USB flash should emulate a floppy disk, and ends up getting the "emulated LBA -> floppy CHS -> actual LBA" conversions all wrong because the laptop manufacturer didn't test parts of the BIOS that should never be needed).


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.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

First off Thanks alot !
Second, so would you recommend that I stick to the CHS scheme ??? I really thought it was rather stupid given the LBA extended read option, all I need (at least during booting, not a File System driver) is to know the correct file size and location from the Root and Fat and just plug in. CHS seemed stupid at that point, however, not testing is a good reason. I am glad to know that the code might be ok and I am not just going crazy.

As for the flags, I wasnt aware of that so thanks !! I looked up how to clear and set flags and came up with this
http://stackoverflow.com/questions/1406 ... m-directly

so I added
CLC
CLD

right after the STI instruction in the code to clear all the flags and make sure that SI and DI increment. Is that all there is to setting up flags and directions, or am I missing something ??

Thanks alot for all the help guys !!!
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

btw after adding the CLC and CLD still same problem ... working on Bochs but not the laptop
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,
Ahmed wrote:so I added
CLC
CLD
The carry flag is changed by lots of instructions so there's no real reason to clear it (it's an "arithmetic results" flag, rather than a control flag like the interrupt enable/disable flag or the direction up/down flag).
Ahmed wrote:btw after adding the CLC and CLD still same problem ... working on Bochs but not the laptop
I'm guessing it's still in the "not a partitioned hard drive and not a floppy" state, where no BIOS developer cares if such an obscure scenario works or not?


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.
Ahmed
Posts: 20
Joined: Sun Jan 20, 2013 9:04 am

Re: Real machine vs bochs

Post by Ahmed »

Ok guys I think I have been able to narrow down the problem. For some reason like Mr. Brendan suggested, the extended Write functionality is not working on the Laptop. (int 13, ah=43h + DAP). I double checked by a hexdumping the USB drive after testing writing something to it. LBA addressing is not wrong (like it doesnt get the wrong address), it writes absolutely nothing!! Its all zeros.The funny thing is, it reports back the carry flag clear and no error code in ax ( ax=00h ) which is what is expected of a successful write operation. Consequently, it is only sensible to assume that the extended read (int 13, ah=42h + DAP) doesnt work as well and I have been looping through zeros all that time. The thing is, how does the bios actually access the USB stick in the first place if its not a partitioned HD and get the boot sector ? Also I have used diskpart on the disk to create a partition primary and everything, and in hexden it appears with the sectors well defined (as in the allocation unit size) unlike a binary disk image where its just a continuous flow of addresses not defined in sectors.
like which interrupt routine is a fail safe option. This has been taking up so much of my time and I just want to get it done with !!
Post Reply