Project/OStrial in AMAZON

#n+3 하드디스크 드라이버 - 읽기

NONE_31D 2019. 12. 8. 20:54

지난번까지 QEMU 환경으로 변환했고, 하드디스크를 구현할 차례이다. 

 

#interrupt.c

 


    __asm__ __volatile__("mov eax, %0"::"r"(&idtr));
    __asm__ __volatile__("lidt [eax]");
    __asm__ __volatile__
    (
        "mov al, 0x00;" 
        "out 0xA1, al;" 
        "mov al, 0x00;"
        "out 0x21, al;" 
    );
    __asm__ __volatile__("sti");

    return;


}

 

mov al,, 0x00

out 0xA1, al

- 슬레이브 PIC의 모든 인터럽트를 열어둔다. 

 

mov al,, 0x00

out 0x21, al

- 마스터 PIC의 모든 인터럽트를 열어둔다.

 

이렇게 모든 인터럽트를 해방하고 나서 하드디스크의 인터럽트(자신에게 떨어진 명령을 수행한 후 CPU에게 날리는 인터럽트)를 받을 수 있음. 

 

 

#function.c - HDDstatus()~

 

unsigned char HDDstatus()
{
    unsigned char value;

    __asm__ __volatile__
    (
        "mov dx,0x1F7;"
        "in al, dx;"
    );
    __asm__ __volatile__("mov %0, al;" :"=r"(value));

    return value;

}

int HDD_BSY()
{
    unsigned char status = HDDstatus();

    if ( (status & 0x80) == 0x80return 1;
    else return 0

}

int HDD_DRDY()
{
    unsigned char status = HDDstatus();

    if ((status & 0x40) == 0x40return 1
    else return 0
}

int HDD_DRQ()
{
    unsigned char status = HDDstatus();

    if ((status & 0x08) == 0x08return 1
    else return 0;
}

int HDD_ERR()
{
    unsigned char status = HDDstatus();

    if ((status & 0x01) == 0x01return 1
    else return 0
}

 

- 하드디스크의 현재 상태를 읽어오는 함수 구현

- HDD_BSY() : if문 : busy 상태

- HDD_DRDY() : if문 : 준비 상태

- HDD_DRQ() : if문 내부에서 데이터 리퀘스트. 아닐 경우 논 데이터 리퀘스트.

- HDD_ERR() : if문 진입시 에러상태. 

 

 

#function.c - HDDread()

 

void HDDread(unsigned int sectorcharbuffer)
{
    
    unsigned char LBA_a = sector & 0xFF
    unsigned char LBA_b = ( sector >> 8 ) & 0xFF;
    unsigned char LBA_c = ( sector >> 16) & 0xFF;
    unsigned char LBA_d = ( ( sector >> 24) & 0x0F ) | 0xE0 ; 
 
    /*
* sector 변수를 분해. 각 포트별로 비트를 분해해서 넣기 위함
*
    * LBA_a : sector의 [7:0] 부분의 비트 추출
    * LBA_b : sector의 [15:8] 비트 추출
    * LBA_c : sector의 [23:16] 비트 추출
    * LBA_d : sector의 [27:24] 비트 추출
    */
 
 
    // HDD INT 활성화
    __asm__ __volatile__
    (
        "mov al, 0;"
        "mov dx, 0x3F6;"
        "out dx, al;"
    );

    while ( HDD_BSY() == 1); // HDD가 busy 하다면 계속 대기
    
    // ========== 하드디스크 Setting
// 각 포트가 요구하는 값에 맞게 값 저장
 
 
    // 드라이브/헤드 레지스터 초기화 + LBA 주소 [27:24] 4비트
    __asm__ __volatile__
    (
        "mov al, %0;"
        "mov dx, 0x1F6;"
        "out dx, al;"::"r"(LBA_d)
    );

    __asm__ __volatile__
    (
        "mov al, 0x01;"
        "mov dx,0x1F2;"
        "out dx, al;"
    ); // 섹터 1개 읽어오기

    __asm__ __volatile__
    (
        "mov al, %0;"
        "mov dx,0x1F3;"
        "out dx, al;" ::"r"(LBA_a)
    ); 

    __asm__ __volatile__
    (
        "mov al, %0;"
        "mov dx,0x1F4;"
        "out dx, al;" ::"r"(LBA_b)
    );

    __asm__ __volatile__
    (
        "mov al, %0;"
        "mov dx,0x1F5;"
        "out dx, al;" ::"r"(LBA_c)
    ); 

 

    // 하드디스크 드라이버가 명령을 받을 수 있는지 체크
    while ((HDD_BSY() ==1 )|| (HDD_DRDY()==0));


    // 0x20 : 읽기 명령
    __asm__ __volatile__
    (
        "mov al, 0x20;"
        "mov dx,0x1F7;"
        "out dx, al;"
    );

    // order 후 error 발생 시 read 중단.
    if (HDD_ERR() == 1)
    {
        kprintf("Error!!", videomaxline - 10);
        return;
    }

    while (HDD_DRQ() == 0); // 데이터를 다 읽을 때까지 대기


    // 읽기가 성공 -> Buffer에 데이터를 512바이트만큼 옮김
 
    __asm__ __volatile__("mov dx,0x1F0;");
    __asm__ __volatile__("mov edi, %0;" : : "r"(buffer));
    __asm__ __volatile__("mov ecx, 256");
    __asm__ __volatile__("rep insw");
// ds:edi 주소에 dx포트의 값을 2바이트 읽는 명령어. 한번 실행 시 0x1F0에 담긴 정보를 buffer에 저장하게 됨.


}

 

 

 

하드웨어 구현이 끝났지만 이대로는 제대로 구현이 되었는지 어렵기 때문에 hdd.img에 각 섹터의 시작 부분에 여기가 어떤 섹터인지 알리는 데이터를 저장한다. 

- 0x000 : "This is sector 0"

- 0x200 : "This is sector 1"

 

이 문자열을 확인하기 위해 shell 명령어를 하나 추가한다.

 

#shell.c - sh_HDDread()

 

void sh_HDDread()
{
    HDDread(0, diskbuffer);
    kprintf(diskbuffer, ++curline, 0);

    HDDread(1, diskbuffer);
    kprintf(diskbuffer, ++curline, 0);
}

 

- diskbuffer를 data.h에 unsigned char diskbuffer[512]; 로 수정

 

 

#main.c - translate_shell()

 

void translate_shell()
{
    if (keyboard[0] == 0) { return; } 
    if (kstrcmp(keyboard, "clear")) { sh_clear(); return; }
    if (kstrcmp(keyboard, "version")) { sh_version(); return; }
    if (kstrcmp(keyboard, "read")) { sh_HDDread(); return; }
    
    kprintf("There is no such command.",++curline, 0);
}

 

- 방금 추가한 sh_HDDread() 함수를 실행할 수 있도록 read 명령어를 추가해준다. 

 

 

컴파일 후 실행할 경우, 다음과 같이 정상적으로 실행한다.