Page 1 of 3
Real machine vs bochs
Posted: Sun Jan 20, 2013 9:19 am
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
Re: real machine vs bochs
Posted: Sun Jan 20, 2013 12:05 pm
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 ...
Re: Real machine vs bochs
Posted: Sun Jan 20, 2013 3:49 pm
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
Re: Real machine vs bochs
Posted: Mon Jan 21, 2013 3:21 am
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.
Re: Real machine vs bochs
Posted: Mon Jan 21, 2013 4:28 am
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.
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 11:40 am
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
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 11:44 am
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
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 1:06 pm
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.
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 2:51 pm
by Griwes
6. You used colors in a post, which is forbidden here.
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 8:00 pm
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
Re: Real machine vs bochs
Posted: Thu Feb 07, 2013 8:04 pm
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
Re: Real machine vs bochs
Posted: Fri Feb 08, 2013 6:11 am
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 !!!
Re: Real machine vs bochs
Posted: Fri Feb 08, 2013 6:13 am
by Ahmed
btw after adding the CLC and CLD still same problem ... working on Bochs but not the laptop
Re: Real machine vs bochs
Posted: Fri Feb 08, 2013 8:34 am
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
Re: Real machine vs bochs
Posted: Fri Feb 08, 2013 8:59 am
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 !!