ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [OS] 15. Video Ports
    OS/OS from Scratch 2021. 6. 30. 20:19

    서론

    이번 강의에서는 VGA와 Data Ports의 사용법에 대해 공부하겠습니다. 해당 Github 강의는 다음과 같습니다.

    https://github.com/cfenollosa/os-tutorial/tree/master/15-video-ports

     

    cfenollosa/os-tutorial

    How to create an OS from scratch. Contribute to cfenollosa/os-tutorial development by creating an account on GitHub.

    github.com


    이론

    I/O Programming

    Input/Output을 담당하는 하드웨어 장치는  Controller Chip을 통해 CPU와 상호작용합니다. Controller Chip에는 CPU가 읽고 쓸 수 있는 레지스터들이 있으며, 해당 레지스터들의 상태로 장치에게 무엇을 해야 할지 명령하게 합니다. Controller의 레지스터들은 메모리의 I/O Address Space에 맵핑되어 있어 Assembly의 in, out 명령어를 통해 I/O Address에 데이터를 일고 쓸 수 있습니다.

    예를 들어 Floppy Disk를 회전시키게 하는 DOR레지스터는 0x3F2 I/O Address에 맵핑되어 있는데, Floppy Disk을 회전시키기 위한 Assembly 코드는 다음과 같습니다.

    mov dx, 0x3f2
    ; DOR port의 값을 AL레지스터에 읽음
    in al, dx
    ; motor bit 킴
    or al, 00001000b
    ; DOR 레지스터 값 업데이트
    out dx, al

    Inline Assembly

    C Code에서 Assembly를 사용하기 위해서는 다음과 같은 Inline Assembly를 이용합니다.

    __asm__( "assembly code" : 출력변수 : 입력변수);

    GCC 컴파일러에서는 지금까지 사용한 NASM과 달리 GAS 문법을 사용합니다. GAS에서는 target과 desitination operand가 바뀐 형태로 표기됩니다. 또한, ':'를 기준으로 출력 변수와 입력되는 변수를 넣어줄 수 있습니다. 실제 코드를 예를 들어보겠습니다.

    unsigned char result;
    unsigned short port;
    __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));

     Inline Assembly에서는 레지스터를 표현하기 위해서는 %%al과 같이 사용하며, %%dx는 EDX레지스터를 의미합니다. "=a" (result)는 명령어 실행 후 AL레지스터의 값을 result변수에 대입하라는 의미이고, "d" (port)는 EDX레지스터의 값을 port변수 값으로 설정하라는 의미입니다. 즉, 위 코드의 의미는 다음과 같습니다.

    1. EDX레지스터의 값을 port 변수 값으로 설정한다.
    2. (NASM 기준) in al, edx: EDX레지스터가 가리키는 port의 값을 AL레지스터에 읽는다.
    3. AL레지스터의 값을 result 변수에 저장한다.

    코드

    ports.h

    unsigned char port_byte_in(unsigned short port);
    void port_byte_out(unsigned short port, unsigned char data);
    unsigned short port_word_in(unsigned short port);
    void port_word_out(unsigned short port, unsigned short data);

    ports.c

    port_byte_out 함수는 port에서 원하는 데이터를 조회하는 함수이고,  port_byte_in 함수는 port_byte_out함수를 실행한 후 port에서 출력된 결과를 읽어 읽은 값을 리턴하는 함수입니다.

    // 특정 포트에서 byte읽음
    unsigned char port_byte_in(unsigned short port) {
        unsigned char result;
        __asm__("in %%dx, %%al" : "=a" (result) : "d" (port));
        return result;
    }
    
    // 레지스터 출력
    void port_byte_out(unsigned short port, unsigned char data) {
        __asm__("out %%al, %%dx" : : "a" (data), "d" (port));
    }
    
    unsigned short port_word_in(unsigned short port) {
        unsigned short result;
        __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port));
    }
    
    void port_word_ourt(unsigned short port, unsigned short data) {
        __asm__("out %%ax, %%dx" : : "a" (data), "d" (port));
    }

    kernel.c

    kernel.c에서는 현재 스크린에서 커서의 위치를 VGA Control Register를 이용해 조회하고, 해당 위치에 'X'문자를 출력합니다.

    커서의 위치를 알아내기 위해 port_byte_out함수에서 VGA Control Register 맵핑된 0x3d4를 조회하는데, 이때 14는 커서 위치의 높은 자리 바이트, 15는 커서 위치의 낮은 자리 바이트를 리턴합니다. 따라서 14, 15의 경우에 대해 0x3d4를 조회하고, 이를 통해 커서의 위치를 계산할 수 있습니다.

    VGA 셀들을 (화면에 출력될 위치)+(화면에 출력하기 위한 설정)의 형태로 저장됩니다. 따라서 vga에 조회하기 위한 인덱스는 position의 2배를 해주어야 합니다.

    #include "../drivers/ports.h"
    
    void main() {
        // 스크린에서 커서의 위치
        // VGA Control Register: 0x3d4
        // 14: cursor high byte
        // 15: curosr low byte
        port_byte_out(0x3d4, 14);
        // 0x3d5에 데이터 리턴됨
        int position = port_byte_in(0x3d5);
        position = position << 8;
        // low byte조회 
        port_byte_out(0x3d4, 14);
        position += port_byte_in(0x3d4);
    
        // VGA의 셀들은 (위치)+(설정 ex 검은 바탕에 흰글씨) 형태로 저장됨
        int offset_from_vga = position*2;
        char *vga = 0xb8000;
        vga[offset_from_vga] = 'X';
        // 검은 바탕에 흰글씨
        vga[offset_from_vga+1] = 0x0f;
    }

    실행 결과

    make로 실행하면, 커서 끝쪽에 X가 출력된 것을 확인할 수 있습니다.

    실행결과

    'OS > OS from Scratch' 카테고리의 다른 글

    [OS] 17. Video Scroll  (0) 2021.07.02
    [OS] 16. Video Driver  (0) 2021.07.02
    [OS] 14. Checkpoint  (0) 2021.06.28
    [OS] 13. Kernel Barebones  (0) 2021.06.27
    [OS] 12. Kernel C  (0) 2021.06.26
Designed by Tistory.