ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [OS] 21. Shell
    OS/OS from Scratch 2021. 7. 23. 16:30

    서론

    이번 강의에서는 작성했던 코드를 정리하고 가장 기본적인 Shell을 구현하겠습니다. 해당 Github 강의는 다음과 같습니다.

    https://github.com/cfenollosa/os-tutorial/tree/master/21-shell

     

    GitHub - cfenollosa/os-tutorial: How to create an OS from scratch

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

    github.com


    코드

    이번 강의에서는 위 Github 링크에서 설명하는 대로 파일의 경로들을 재설정하고, 단순 구현을 진행합니다. 코드를 컴파일하면서 Warning이 발생하는 지점들을 수정하시길 바랍니다. 간단한 입력을 지원하는 Shell 창은 keyboard.c에서 구현했습니다.

    drivers/keyboard.c

    #include "keyboard.h"
    #include "../cpu/ports.h"
    #include "../cpu/isr.h"
    #include "../libc/string.h"
    #include "../libc/function.h"
    #include "screen.h"
    #include "../kernel/kernel.h"
    
    #define BACKSPACE 0x0E
    #define ENTER 0x1C
    
    static char key_buffer[256];
    
    #define SC_MAX 0x39
    
    const char *sc_name[] = { "ERROR", "Esc", "1", "2", "3", "4", "5", "6", 
        "7", "8", "9", "0", "-", "=", "Backspace", "Tab", "Q", "W", "E", 
            "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Lctrl", 
            "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "`", 
            "LShift", "\\", "Z", "X", "C", "V", "B", "N", "M", ",", ".", 
            "/", "RShift", "Keypad *", "LAlt", "Spacebar"};
    const char sc_ascii[] = { '?', '?', '1', '2', '3', '4', '5', '6',     
        '7', '8', '9', '0', '-', '=', '?', '?', 'Q', 'W', 'E', 'R', 'T', 'Y', 
            'U', 'I', 'O', 'P', '[', ']', '?', '?', 'A', 'S', 'D', 'F', 'G', 
            'H', 'J', 'K', 'L', ';', '\'', '`', '?', '\\', 'Z', 'X', 'C', 'V', 
            'B', 'N', 'M', ',', '.', '/', '?', '?', '?', ' '};
    
    static void keyboard_callback(registers_t regs) {
        // PIC가 scancode를 0x60 port에 저장
        u8 scancode = port_byte_in(0x60);
        
        if(scancode>SC_MAX) {
            return;
        } else if(scancode==BACKSPACE) {
            backspace(key_buffer);
            kprint_backspace();
        } else if(scancode==ENTER) {
            kprint("\n");
            // 특정 명령어인지 확인
            user_input(key_buffer);
            key_buffer[0] = '\0';
        } else {
            char letter = sc_ascii[(int)scancode];
            char str[2] = {letter, '\0'};
            append(key_buffer, letter);
            kprint(str);
        }
        // Compilter Warning 제거
        UNUSED(regs);
    }
    
    void init_keyboard() {
        register_interrupt_handler(IRQ1, keyboard_callback);
    }

    Backspace을 입력한 경우 화면에서 출력되었던 문자를 지우는 기능은 screen.c에서 다음과 같이 설정합니다.

    drivers/screen.c

    // Backspace 입력된 경우
    void kprint_backspace() {
    	// 마지막으로 출력된 문자 위치
        int offset = get_cursor_offset()-2;
        int row = get_offset_row(offset);
        int col = get_offset_col(offset);
        // 0x08: Backspace
        print_char(0x08, col, row, WHITE_ON_BLACK);
    }
    
    // print_char 수정
    int print_char(char c, int col, int row, char attr) {
        unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS;
        if(!attr) {
            attr = WHITE_ON_BLACK;
        }
    
        // 좌표가 범위 밖일 때 경고 문자 출력
        if(col>=MAX_COLS || row>=MAX_ROWS) {
            vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
            vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
            return get_offset(col, row);
        }
    
        int offset;
        if(col>=0 && row>=0) {
            offset = get_offset(col, row);
        } else {
            offset = get_cursor_offset();
        }
    
        // 줄바꿈일때는 현재 row에 +1
        if(c=='\n') {
            row = get_offset_row(offset);
            offset = get_offset(0, row+1);
        } else if(c==0x08) {
            vidmem[offset] = ' ';
            vidmem[offset+1] = attr;
        } else {
            vidmem[offset] = c;
            vidmem[offset+1] = attr;
            offset += 2;
        }
    
        // offset이 화면 크기보다 크면 스크롤함
        if(offset>=MAX_ROWS*MAX_COLS*2) {
            int i;
            // 현재 라인을 이전 라인으로 하나씩 밀음 
            for(i=1; i<MAX_ROWS; i++) {
                memory_copy((u8 *)(get_offset(0, i)+VIDEO_ADDRESS), (u8 *)(get_offset(0, i-1)+VIDEO_ADDRESS), MAX_COLS*2);
            }
            // 마지막 줄을 빈칸으로
            char *last_line = (char *)(get_offset(0, MAX_ROWS-1) + VIDEO_ADDRESS);
            for(i=0; i<MAX_COLS*2; i++) {
                last_line[i] = 0;
            }
            // 범위 넘은 offset을 스크롤 다음 줄로 밀음
            offset -= 2*MAX_COLS;
        }
    
        set_cursor_offset(offset);
        return offset;
    }

    다음으로 간단한 명령어를 지원하는 함수를 kernel.c에 추가하겠습니다.

    kernel/kernel.c

    void user_input(char *input) {
        if(strcmp(input, "END")==0) {
            kprint("Stop System...\n");
            // hlt: halt CPU
            asm volatile("hlt");
        }
        kprint("> Typed: ");
        kprint(input);
        kprint("\n");
    }

    실행 결과

    실행 결과 입력을 할 수 있는 Shell을 만들었습니다.

    Shell

     

     

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

    [OS] 23. Finish  (0) 2021.07.29
    [OS] 22. Malloc  (0) 2021.07.24
    [OS] 20. Interrupt-timer  (0) 2021.07.18
    [OS] 19. Interrupt-irqs  (0) 2021.07.12
    [OS] 18. Interrupts  (0) 2021.07.03
Designed by Tistory.