Page 1 of 1

Triple fault while reading disk data in x64 OS

Posted: Wed Nov 20, 2013 11:50 am
by ashishtanwer
HI All,
I ma trying to read hard disk data with AHCI interface as explained in the OSDEV tutorial. For x64, i am setting both dba and dbau. It is working fine for N-1 times. but for last entry it gives triple fault.
#############

Code: Select all

 int read(HBA_PORT *port, DWORD startl, DWORD starth, DWORD count, QWORD buf)
{
        printk("\nInside read");
        int i;
        port->is = (DWORD)-1;           // Clear pending interrupt bits
        int spin = 0; // Spin lock timeout counter
        int slot = find_cmdslot(port);
        printk("\nCommand Slot %d\n",slot);
        if (slot == -1){
                printk("\n slot==-1..i.e. no command slot");
                return 0;
        }
        uint64_t addres=0;
        addres=(((addres | port->clbu)<<32)|port->clb);
                addres =  addres+ kernmem1;
        HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER *)addres;
        cmdheader += slot;
        cmdheader->cfl = sizeof(FIS_REG_H2D)/sizeof(DWORD);     // Command FIS size
        cmdheader->w = 0;               // Read from device
        cmdheader->prdtl = (WORD)((count-1)>>4) + 1;    // PRDT entries count
        printk("\nPRDT ENTRIES COUNT[%d]",cmdheader->prdtl);

        addres=(((addres | cmdheader->ctbau)<<32)|cmdheader->ctba);
        addres =  addres+ kernmem1;
        HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)(addres);
        //memset(cmdtbl, 0, sizeof(HBA_CMD_TBL) + (cmdheader->prdtl-1)*sizeof(HBA_PRDT_ENTRY));

        // 8K bytes (16 sectors) per PRDT
        for (i=0; i<cmdheader->prdtl-1; i++)
        {
                cmdtbl->prdt_entry[i].dba = (DWORD)(buf & 0xffffffff);
                cmdtbl->prdt_entry[i].dbau = (DWORD)((buf>>32) & 0xffffffff);
                cmdtbl->prdt_entry[i].dbc = 8*1024;     // 8K bytes
                cmdtbl->prdt_entry[i].i = 1;
                buf += (4*1024)/4;      // 4K words
                count -= 16;    // 16 sectors
        }
        // Last entry
        printk("\nshashank cmtbkl [%d]",i);
        printf("%x", cmdtbl->prdt_entry[i]);
        while(1);
        cmdtbl->prdt_entry[i].dba = (DWORD)(buf & 0xffffffff);
        cmdtbl->prdt_entry[i].dbau = (DWORD)((buf>>32) & 0xffffffff);
        while(1);
##########

Triple Fault
cmdtbl->prdt_entry.dba = (DWORD)buf;
cmdtbl->prdt_entry.dbc = count<<9; // 512 bytes per sector

Please help me by telling my mistake.

Re: Triple fault while reading disk data in x64 OS

Posted: Wed Nov 20, 2013 9:17 pm
by mrstobbe
Your code is much harder to read than if it were surrounded by a

Code: Select all

[code]code block
[/code]. You may get better help if you do that, as I look at that and think, "that's a mess to try and read", and move on.

Re: Triple fault while reading disk data in x64 OS

Posted: Wed Nov 20, 2013 10:15 pm
by mrstobbe
A couple of things...
ashishtanwer wrote:It is working fine for N-1 times. but for last entry it gives triple fault.
Immediately I think, "that's a stack/buffer overflow". Do you mean that you're looping 0...n-1 or 0...n and have a structure allocation that's n size?
ashishtanwer wrote:Triple Fault
What type of fault? GP? PF? etc. I presume PF... Have you actually debugged anything? Are register states what you expect? Is the stack state what you expect? Is the IP what you expect? etc.

Finally, I just pulled up the wiki entry on AHCI and that code is potentially doggy (the for loop defines the int i itself so the scope change might invalidate i). What C standard are you compiling against? Do you have warnings turned on? Have you tried simply replacing that final prdt_entry with prdt_entry[cmdheader->prdtl-1]? Why did you comment out the memory initialization?

Just random thoughts... hope one of them points you in the right direction.

EDIT: Another thought... is prdtl a zero-based count (aka, actually n-1), or a standard 1 based count?