Page 1 of 1

[Solved]Unable to obtain disk identify info on qemu

Posted: Thu Dec 23, 2021 5:24 pm
by michael
First, I use

Code: Select all

qemu-img create -f qcow2 80m.img 80m
to create a 80m img file as hard disk. Then I use

Code: Select all

-hdb 80m.img
to plug in the disk and start the qemu.

And here is my full command to start qemu:

Code: Select all

qemu-system-x86_64 -cpu Nehalem,+x2apic -m 512 -enable-kvm -s -S -fda a.img -hdb 80m.img
I want to get the identify information of my disk, and here is my code to do that:

Code: Select all

//send command to the primary disk of slave controller to get identify info 
   io_out8(PORT_DISK1_ALT_STA_CTL,0);	
	io_out8(PORT_DISK1_ERR_FEATURE,0);
	io_out8(PORT_DISK1_SECTOR_CNT,0);
	io_out8(PORT_DISK1_SECTOR_LOW,0);
	io_out8(PORT_DISK1_SECTOR_MID,0);
	io_out8(PORT_DISK1_SECTOR_HIGH,0);
	io_out8(PORT_DISK1_DEVICE,0xe0);
	io_out8(PORT_DISK1_STATUS_CMD,0xec);
Definition of all macros used above

Code: Select all

#define PORT_DISK1_DATA		0x170
#define PORT_DISK1_ERR_FEATURE	0x171
#define PORT_DISK1_SECTOR_CNT	0x172
#define PORT_DISK1_SECTOR_LOW	0x173
#define PORT_DISK1_SECTOR_MID	0x174
#define PORT_DISK1_SECTOR_HIGH	0x175
#define PORT_DISK1_DEVICE		0x176
#define PORT_DISK1_STATUS_CMD	0x177

#define PORT_DISK1_ALT_STA_CTL	0x376
But the data I've got from the port is nothing but 0. Here is the code I've used to get return data from port:

Code: Select all

   struct Disk_Identify_Info a;
	unsigned short *p = NULL;
	port_insw(PORT_DISK1_DATA,&a,256);
   p = (unsigned short *)&a;
	for(int i = 0;i<256;i++){
      printk(ORANGE,WHITE,"%x ",*(p+i));
   }
Here is the definition of port_insw:

Code: Select all

#define port_insw(port,buffer,nr)	\
__asm__ __volatile__("rep;insw;mfence;"::"d"(port),"D"(buffer),"c"(nr):"memory")
Structure "Disk_Identify_Info" is nothing but a 256 bits struct to store disk identify info. It is kind of long so I cannot post it on this quote.
(Definition of Disk_Identify_Info: https://github.com/bigjr-mkkong/OStest/blob/main/disk.h)

However, I want to know how can I fix this problem or it is normal to get a full 0 identify info in qemu.

Re: Unable to obtain disk identify info on qemu

Posted: Thu Dec 23, 2021 9:08 pm
by Octocontrabass
michael wrote:hdb
You're attaching your image as the second hard drive, but you're trying to identify the first hard drive.

You're not checking if the drive is ready before you begin accessing it. This is unlikely to be a problem in QEMU, but it can cause trouble on bare metal.
michael wrote:

Code: Select all

   io_out8(PORT_DISK1_ALT_STA_CTL,0);
Modern drives don't care, but ancient drives might misbehave if you don't set bit 3 in the drive control register.
michael wrote:

Code: Select all

	io_out8(PORT_DISK1_DEVICE,0xe0);
Each drive has its own command block registers. If writing to the drive/head register changes which drive is selected, you need to write it before you write the other command block registers. IDENTIFY DEVICE doesn't use any of the command block registers aside from the command register, so this isn't the reason why it's not working right now, but it will cause problems for other commands.
michael wrote:

Code: Select all

#define port_insw(port,buffer,nr)	\
__asm__ __volatile__("rep;insw;mfence;"::"d"(port),"D"(buffer),"c"(nr):"memory")
Be aware that if REP INSW causes certain corrected exceptions (e.g. demand paging) it will silently discard data. You're clobbering RCX and RDI because you didn't specify them as output operands. You don't need the MFENCE instruction. If you provide the destination buffer as an output operand, you don't need a "memory" clobber.

If you fix all of the above issues, you should end up with something like this:

Code: Select all

void rep_insw( uint16_t port, void * dest, size_t count )
{
    asm volatile( "rep insw" : "+D"(dest), "+c"(count), "=m"(*(char (*)[count*2])dest) : "d"(port) );
}