Why isn't VMWare copying the content of my drive to 0x7C00?

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.
Post Reply
paikuhan
Posts: 7
Joined: Tue Apr 06, 2021 10:36 am

Why isn't VMWare copying the content of my drive to 0x7C00?

Post by paikuhan »

Hi fellow OSDeverz,

I created a simple "Master Boot Record" for my future toy OS. The first sector (MBR) loads perfectly to memory address 0x7C00. At first I didn't know why, but I was finally able to use pointer to other memory addresses by adding these few line at the start of my nasm code:

Code: Select all

CLI
MOV AX,CS ; Copy code segment
MOV DS,AX ; Make DS correct
MOV ES,AX ; Make ES correct
MOV SS,AX ; Make SS correct
MOV BP,0x7C00
MOV SP,0x7C00 ; SETUP A STACK
STI
Note that I don't need them with Bochs Emulator (I'm guessing because it's outdated?), but need them in both VMWare Player and Oracle VirtualBox. Then what I made my MBR do is to load itself at memory address 0x600 and jump to that address + skipping previously executed instructions. Up to this point everything is fine. Now to my issue: The next thing the code is supposed to do is load the partition's first sector to memory address 0x7C00 (where the old copy of the MBR resides) and jump back there but this doesn't happen. the old copy of the MBR is not overwritten and thus VMWare Player is looping between 0x7C00 and 0x600.

Here is my full code:

Code: Select all

;********************************************************************;
;* START OF CODE *;
;********************************************************************;

%define SIZE 512 ; MBR sector size (512 bytes)
%define BASE 0x7C00 ; Address at which BIOS will load MBR
%define DEST 0x0600 ; Address at which MBR should be copied


;********************************************************************;
;* NASM settings *;
;********************************************************************;

[BITS 16] ; Enable 16-bit real mode
[ORG BASE] ; Set the base address for MBR


;********************************************************************;
;* Setup segment registers *;
;********************************************************************;
CLI
MOV AX,CS ; Copy code segment
MOV DS,AX ; Make DS correct
MOV ES,AX ; Make ES correct
MOV SS,AX ; Make SS correct
MOV BP,0x7C00
MOV SP,0x7C00 ; SETUP A STACK
STI ;IT WAS ORIGINALLY PUBLISHED ON HTTPS://WWW.APRIORIT.COM/

 


;********************************************************************;
;* Prepare registers *;
;********************************************************************;
MOV BX,Prepare
CALL print_string ; function that prints a string whose pointer is loaded in BX

XOR AX,AX
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV SP,BASE

;********************************************************************;
;* Copy MBR to DEST and jump there *;
;********************************************************************;
MOV BX,Copy
CALL print_string ; function that prints a string whose pointer is loaded in BX

MOV SI,BASE
MOV DI,DEST
MOV CX,SIZE
CLD
REP MOVSB

JMP DEST + SKIP ; When you ask to jump somewhere it will jump in absolute address
; For instance JMP 0x05 will jump to memory address 0x05 instead
; of 0x7C05

SKIP: EQU ($ - $$) ; Go here in copied code

 

MOV BX,Loading
CALL print_string ; function that prints a string whose pointer is loaded in BX

;Extended Read
MOV AH, 0x42
MOV AL, 3
;MOV DL,
MOV BX, 0
MOV DS, BX
MOV SI, DAP
MOV BX, 0x7C00
INT 0x13

JMP 0x7600 + 0x7C00

DAP:
DAP_SIZE: DB 0x10
UNUSED: DB 0x00
SECTOR_COUNT: DW 3 ; int 13 resets this to # of blocks actually read/written
SEGMENT_OFFSET: DD 0x7C00 ; memory buffer destination address (0:7c00)
LBA: DQ 2048 ; put the lba to read in this spot


%include "../../inc/chapter3/print_string.inc.asm" ; print string function is in an external file

Prepare: DB "Prepare registers.",10,13,0
Copy: DB "Copy MBR to DEST and jump there.",10,13,0
Loading: DB "Loading the partition bootsector.",10,13,0


TIMES 446-($-$$) DB 0

 

;********************************************************************;
;* END OF CODE *;
;********************************************************************;


Note that on the Bochs Emulator and on Oracle Virtualbox the old MBR is overwritten and there is no endless loop. What should I do to make VMWare Player copy the partition's first sector to memory 0x7C00.

Thanks in advance.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Why isn't VMWare copying the content of my drive to 0x7C

Post by nullplan »

paikuhan wrote:I created a simple "Master Boot Record" for my future toy OS. The first sector (MBR) loads perfectly to memory address 0x7C00. At first I didn't know why, but I was finally able to use pointer to other memory addresses by adding these few line at the start of my nasm code:
I suggest you replace the second instruction with "xor ax,ax". Reason is that you don't really know the value of CS. You know your code will be loaded to 0x7c00, but not whether it will be executed as 0:7C00 or 07C0:0000. Moreover, it does not matter to the code. Relative jumps and calls still work as expected. However, to access memory you need your DS/ES to have known addresses. It is usually the best to just keep them at 0 until you really can't anymore.
paikuhan wrote:Note that I don't need them with Bochs Emulator (I'm guessing because it's outdated?), but need them in both VMWare Player and Oracle VirtualBox.
Bochs initializes all memory, and all registers, before executing your code. Other BIOSes do not have to do the same. In general, never assume the value of anything unless there is some kind of interface contract that something must have a certain value. In this case, you can assume that DL contains the BIOS drive number of the drive being booted, and that CS:IP will combine to form the linear address 7C00, and that is about it.


Your code contains exactly the code I suggested after the first call to print_string. Why? Memory is tight, doing unnecessary work uses it up.

The normal way to do a relocating MBR is something like this:

Code: Select all

org 600h ;eventually, we end up there
cli
xor ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,7c00h
sti
cld
mov si,7c00h
mov di,600h
mov cx,256
rep movsw
jmp 0:start
start:
This will use a far jump to jump to an absolute address to actually start the MBR at the correct address.

Beyond that I see you are using INT 13 extensions, but do not check whether INT 13 extensions are available on the drive you are using, or whether INT 13 returned an error. The behavior you are seeing is consistent with something being not to the BIOSes liking. For something as simple as this, might I suggest foregoing the INT 13 extensions and just using the normal functions? Way less to do wrong there.
Carpe diem!
paikuhan
Posts: 7
Joined: Tue Apr 06, 2021 10:36 am

Re: Why isn't VMWare copying the content of my drive to 0x7C

Post by paikuhan »

nullplan wrote:Your code contains exactly the code I suggested after the first call to print_string. Why?
You are right I added it again on top because my print_string wasn't working and forgot to add remove it after.
nullplan wrote: The normal way to do a relocating MBR is something like this:

Code: Select all

org 600h ;eventually, we end up there
cli
xor ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,7c00h
sti
cld
mov si,7c00h
mov di,600h
mov cx,256
rep movsw
jmp 0:start
start:
This will use a far jump to jump to an absolute address to actually start the MBR at the correct address.
That looks like what I did only I used MOVSB instead of MOVSW and for 7C00H and 600H I used defined constant instead but that pretty much the same thing.
nullplan wrote:Beyond that I see you are using INT 13 extensions, but do not check whether INT 13 extensions are available on the drive you are using, or whether INT 13 returned an error. The behavior you are seeing is consistent with something being not to the BIOSes liking. For something as simple as this, might I suggest foregoing the INT 13 extensions and just using the normal functions? Way less to do wrong there.
Thanks this comment helped a lot! I used a virtual Floppy drive and loaded as Floppy disk a 256 MB raw binary (that represents the disk). I guess because the raw binary was too big to be a floppy disk, VMWare didn't want to do a thing. (According to Wikipedia and OSDev's Wiki, INT 13H is the only game in town when it comes to loading data from HDD, Floppy and USB so I am not sure what you are talking about when you say :
nullplan wrote:and just using the normal functions
Anyway, I was able to fix my issue by telling VMWare to use a *.vmdk as SATA HDD instead of a raw *.bin as floppy disk. I'm curious still... What other way are you talking about when it comes to reading data from something that is not RAM?
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Why isn't VMWare copying the content of my drive to 0x7C

Post by bzt »

paikuhan wrote:That looks like what I did only I used MOVSB instead of MOVSW and for 7C00H and 600H I used defined constant instead but that pretty much the same thing.
Nope, you haven't used the ORG directive correctly. If you had, then you couldn't access string and the print function, and there would be no need for adjusting the JMP. Also as nullplan pointed out, you should set CS too with a far jump. Here's how I do it (Note that I locate the actual position dynamically, and I do not access any variables nor functions before the relocation, except with a relative address near call):

Code: Select all

bootboot_record:
            jmp         short .skipid
            nop
            ;skip BPB area so that we can use this
            ;boot code on a FAT / exFAT volume if needed
            db          120-($-$$) dup 0
.skipid:    ;relocate our code to offset 0h:600h
            cli
            cld
            xor         ax, ax
            mov         ss, ax
            mov         sp, 600h
            push        ax
            pop         es
            push        cs
            pop         ds
            ;find our position in memory.
            call        .getaddr
.getaddr:   pop         si
            sub         si, .getaddr-bootboot_record
            mov         di, sp
            ;clear data area 500h-600h
            sub         di, 100h
            mov         cx, 80h
            repnz       stosw
            ;and copy ourselves to 600h
            mov         cx, 100h
            repnz       movsw
            ;have to clear ds, because cs is set to 7c0 when booted from El Torito
            push        es
            pop         ds
            jmp         0:.start
.start:
Notes: I set DS to CS before the copy and I autodetect the location because I also support ROM boot (code is "loaded" somewhere above C8000h), you probably won't need that part. I also clear both DS and CS when I jump to ".start" but not before (movsb/movsw in the copy implicitly uses DS/ES), and no address adjustments needed for the far jump.
paikuhan wrote:Anyway, I was able to fix my issue by telling VMWare to use a *.vmdk as SATA HDD instead of a raw *.bin as floppy disk. I'm curious still... What other way are you talking about when it comes to reading data from something that is not RAM?
The extended read AH=42h uses LBA addressing mode, not available for floppies (not on all BIOS that is). That's why it worked with HDD but not with floppy. In general, you can only assume LBA addressing if the drive code is 80h or above. You can use AH=41h, BX=55AAh function to check for support, it returns BX=AA55h if the device in DL does support the extended read function. Take a look at my boot sector, which works as MBR, VBR and CDROM boot sector too.

Cheers,
bzt
Post Reply