2014-07-05 10 views
-2

운영 체제의 일부로이 섹터 읽기 기능을 작성했습니다.조립 : 첫 번째 트랙 이후 섹터를 읽을 수 없습니다.

BIOS 장치 ID에서 읽을 때 섹터 주소가 필요합니다. 그러나 섹터 19 (헤드 : 0, 트랙 : 1, 섹터 2)에서 읽으려고하면 0x1000 : 0x0000의 결과가 해당 섹터를 지나칠 가능성이 큽니다 (16 진수 뷰어로 여러 번 확인).

또한 위에서 언급 한 주소에 섹터 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로 놓여 있어도 틀린 것으로 보입니다. 사실 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

드웨인이 언급 한 것 이외에, 정말로은 그런 식으로 작성하면 안됩니다.

문서 인용 : volatile 한정자를 사용하는 경우에도 컴파일 후에 asm 문의 순서가 완벽하게 유지되는 것을 기대하지 마십시오. 특정 명령을 출력에서 ​​연속적으로 유지해야하는 경우 단일 명령문 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.