2014-07-05 83 views
-2

作爲我操作系統的一部分,我編寫了這個讀取扇區函數。程序集:無法在第一個軌道後讀取扇區

它需要一個扇區地址從BIOS設備ID讀取。但是當我設置從扇區19(頭:0,軌道:1,扇區2)讀取時,0x1000:0x0000的結果很可能超過了扇區(我用十六進制查看器多次檢查過)。另外,當我讀取多於一個扇區時,因此扇區19被包含在上述地址中,我可以讀取在0x1000:(512 * 19)處複製的扇區19,沒有問題。

void __NOINLINE resetDisk(const int device_id) { 
    __asm__ __volatile__("" : : "d"(0x0000|device_id)); //set device id 
    __asm__ __volatile__("mov $0x0000,%ax"); //function 0x02 
    __asm__ __volatile__("int $0x13"); 
} 

void __NOINLINE readDiskSector(const int sector, const int device_id) { 
    resetDisk(device_id); 

    int sector_count = 2880; 
    int heads = 2; 
    int tracks = 18; 

    int h = sector/(sector_count/heads); 
    int c = (sector-h*(sector_count/heads))/tracks; 
    int s = sector-c*tracks-h*(sector_count/heads)+1; 

    __asm__ __volatile__("push %es"); 

    __asm__ __volatile__("" : : "a"(c)); 
    __asm__ __volatile__("" : : "b"(s)); 
    __asm__ __volatile__("mov %al,%ch"); 
    __asm__ __volatile__("mov %bl,%cl"); 
    __asm__ __volatile__("" : : "a"(h)); 
    __asm__ __volatile__("" : : "b"(device_id)); 
    __asm__ __volatile__("mov %al,%dh"); 
    __asm__ __volatile__("mov %bl,%dl"); 

    __asm__ __volatile__("mov $0x03,%si"); 
    __asm__ __volatile__("try_again_reading:"); 
    __asm__ __volatile__("cmp $0x00,%si"); 
    __asm__ __volatile__("je stop_trying"); 
    __asm__ __volatile__("mov $0x1000,%bx"); 
    __asm__ __volatile__("mov %bx,%es"); 
    __asm__ __volatile__("mov $0x0000,%bx"); 
    __asm__ __volatile__("mov $0x02,%ah"); 
    __asm__ __volatile__("mov $0x01,%al"); 
    __asm__ __volatile__("int $0x13"); 
    __asm__ __volatile__("dec %si"); 
    __asm__ __volatile__("jc try_again_reading"); 
    __asm__ __volatile__("stop_trying:"); 
    __asm__ __volatile__("pop %es"); 
} 

回答

0

好吧,我終於找到了問題。它與編碼風格無關,但與寄存器的圓柱體,磁頭和扇區值應放入。似乎是錯誤的,即使在http://en.wikipedia.org/wiki/INT_13H上的圓柱體值被放在通道。其實ch和dh必須被替換,然後一切都會正常工作。 ; d

以下各行應改爲:

__asm__ __volatile__("" : : "a"(c)); 
__asm__ __volatile__("" : : "b"(s)); 
__asm__ __volatile__("mov %al,%dh"); 
__asm__ __volatile__("mov %bl,%cl"); 
__asm__ __volatile__("" : : "a"(h)); 
__asm__ __volatile__("" : : "b"(device_id)); 
__asm__ __volatile__("mov %al,%ch"); 
__asm__ __volatile__("mov %bl,%dl"); 
1

如果操作失敗,在ah值將被改變。你的代碼假設它不會被改變。

1

除了什麼Dwayne提到,你真的不應該寫這樣的asm。

引用文檔:不要指望一系列的asm語句在編譯後保持完全連續,即使在使用volatile限定符時也是如此。如果某些指令需要在輸出中保持連續,請將它們放在一條多指令asm語句中。

特別是,使用一個asm語句來加載一個寄存器,然後嘗試訪問該寄存器的另一個asm語句是一個非常糟糕的主意。

我已經採取了一次重新工作這一點。不幸的是,我正在運行64位Windows,所以我實際上無法運行此代碼。 gcc -S看起來是正確的,但理想情況下,我會設置中斷調用的斷點並檢查寄存器的值。不過,我希望你會發現這個有用:

int __NOINLINE resetDisk(const unsigned char device_id) { 

    unsigned char ret; 
    __asm__ __volatile__("mov $0x00,%%ah \n\t" // function 0 (Reset Disk) 
         "int $0x13  \n\t" // Call the interrupt 
         "mov $0x00,%%al \n\t" // Assume success 
         "jnc exit%=  \n\t" // Check status flag 
         "mov $0x01,%%ah \n\t" // function 1 (Get Status) 
         "int $0x13  \n" // Call the interrupt 
         "exit%=:" 
         : "=a" (ret) // Contains error number (0 = success) 
         : "d" (device_id) // deviceid into dl 
         : "cc"); // Flags get overwritten 
    return ret; 
} 

int __NOINLINE readDiskSector(const int sector, 
           const unsigned char device_id, 
           int *sectorsread) { 
    resetDisk(device_id); 

    const int sector_count = 2880; 
    const int heads = 2; 
    const int tracks = 18; 

    const unsigned char h = sector/(sector_count/heads); 
    unsigned char c = (sector-h*(sector_count/heads))/tracks; 
    unsigned char s = sector-c*tracks-h*(sector_count/heads)+1; 

    const unsigned char function = 0x02; 
    const unsigned char sectorstoread = 1; 
    const int bytespersector = 512; 

    int retries = 3; 
    int error; 
    int ret; 

    __asm__ __volatile__(
     "push %%es   \n" // save es 

     "tryagain%=:   \n\t" // Come back here on error 
     "mov %[savedax],%%ax \n\t" // Move the computed value into ax 
     "mov %[buffer],%%bx \n\t" // Move the read address into bx 
     "mov %%bx,%%es  \n\t" // Copy the read address into es 
     "mov $0x0000,%%bx  \n\t" // Set the read offset to zero 
     "int $0x13   \n\t" // Call the interrupt 
     "jc done%=   \n\t" // If there was no error, jump to done 
     "sub $1,%[retries] \n\t" // One less retry 
     "jnz tryagain%=  \n" // If not out of retries, try again 

     "done%=:    \n\t" // On exit, ah contains the return code 
     "pop %%es"     // and al is the number of sectors read 


    : "=a" (ret), // The return value from the interrupt in ax 
    [retries] "+R" (retries) // # retries; must be i+o since it changes 
    : [savedax] "R" ((function << 8) | sectorstoread), // stored value for ax 
    "c" ((c << 8) | s), // calculated value for cx 
    "d" ((h << 8) | device_id), // calculated value for dx 
    [buffer] "i" (0x1000) // buffer segment address (offset will be zero) 
    : "bx", "cc", "memory"); // bx gets clobbered, flags and memory get written 

    error = ret >> 8; 
    *sectorsread = ret & 0xff; 

    return error;   
} 

FWIW。