ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Multithreaded Kernel] 1. Real Mode
    OS/Multi-threaded Kernel from Scratch 2021. 8. 1. 23:18

    서론

    이번 글에서는 16bit real mode 개발에 대해 다루겠습니다. Bootloader, Segmentation, BPB, Interrupt Vector Table, Disk I/O에 대해 알아보겠습니다.


    이론

    Bios & Bootloader

    Bios는 ROM(Read Only Memory)에 상주하는 프로그램으로써 하드웨어들을 초기화/점검하고 Bootloader을 불러오며, Bootloader는 Kernel을 불러옵니다.

    • 컴퓨터가 켜지면서 Bios는 스스로 RAM위에 올려져 실행됩니다.
      • Bios는 16bit code만 실행 가능
    • Bios는 Bootloader를 불러오기 위해 모든 저장장치(하드디스크, USB, Floppu Disk etc)들의 첫 번째 Sector를 확인하면서 Boot Signature(0x55AA)가 있는지 확인합니다.
      • Sector: 저장 장치의 한 구역; 크기는 512byte
    • Bios는 Bootloader을 RAM의 0x7c00 주소에 불러오고 Bios는 바로 0x7c00에서 프로세스를 시작하게 하여 Bootloader가 실행되게 합니다.

    Real Mode

    Real Mode는 Compatibility Mode이다. Real Mode일 때는 다음과 같은 성질을 가집니다.

    • 최대 1Mb의 Ram만 사용 가능
    • Original x86 디자인 사용
      • Intel 8086 프로세서 다루듯이 사용
      • 16bit 사용
    • 보안 기능 없음
    • 한번에 16bit만 접근 가능 (최대 65545까지 접근 가능)

    Segmentation Memory Model

    • 8086 Segment Register
      • CS: Code Segment
      • SS: Stack Segment
      • DS: Data Segment
    • 절대 주소 계산 (Absolute Offset)
      • (Segment Register)*16 + offset
      • Ex) CS=0x7c0, Assembly ORG(offset)=0: (0x7c0*16)+0 = 0x7c00
    • 서로 다른 Insturcution은 서로 다른 Segment 레지스터 사용
      • Ex) lodsb: DS:SI 레지스터 조합
    • Stack Segment
      • Stack에 Push 할 때마다 SP(Stack Pointer) 2 감소

    BPB (Bios Parameter Block)

    일부 Bios는 디스크에 BPB를 덮어써 bootsector 데이터가 손상되는 현상이 발생합니다. 따라서 이러한 작업을 하지 않도록 미리 BPB를 초기화해야 합니다. 그러기 위해서는 불필요한 BPB 부분들은 0으로 채워 넣으면 됩니다. 이때 첫 3byte는 코드가 있는 메모리로 점프해서 코드를 실행하는 역할을 하므로 필요하고, 나머지 33byte는 불필요해 0으로 초기화합니다.

    Interrupts

    Interrupt는 코드를 메모리 주소로 부르는 대신 Interrupt Number로 호출하게 합니다. 예를 들어 interrupt 0x32를 특정 코드를 가리키게 한 다음 'int 0x32'를 하면 해당 interrupt 코드가 실행되게 됩니다.

    Interrrupt을 발생하면

    1. Processer가 interrupt 됨
    2. Stack에 현재 상태가 저장
    3. Interrupt 실행

    Interrupt Vector Table

    Interrupt Vector Table은 Interrupt가 메모리 어디에 있는지 나타내는 table입니다.

    • 각 항은 offset:segment(2byte + 2byte)로 된 4byte
    • 각 항은 순서대로 정렬됨

    Disk Access

    • 데이터는 Sector(512byte block)에 일고 씀
    • CHS(Cylinder Head Sector): Sector 접근하기 위해 특정 head, track, sector 참조 (old) 
      CHS
    • LBA(Logical Block Address): CHS와 달리 0부터 시작하는 수를 이용해 sector 참조 (current)
      • Ex) 디스크의 123456번째 위치 참조하려면 LBA=123456/512=241, offset=123456%512=64로 접근
    • 16bit real mode에서는 Interrupt 13h로 디스크 접근 가능 설명
      • 디스크 읽기
        • ah: 0x02
        • al: 읽을 sector 개수
        • ch: cylinder lower byte
        • cl: sector number
        • dh: head number
        • es:bs: data buffer
        • dl(drive number)는 자동으로 설정

    코드

    전체 코드는 https://github.com/jschang0215/Multithreaded-Kernel/tree/master/01-Real-Mode에서 확인하시길 바랍니다.

    boot.asm

    ORG 0 ; Offset 설정
    BITS 16 ; 16bit 아키텍처 사용
    
    ; BPB 첫 3byte
    __start:
        jmp short _start
        nop
    
    ; Bios Parameter Block 초기화 부분
    times 33 db 0
    
    _start:
        jmp 0x7c0:start ; Code Segment 0x7c0 설정하면서 start로 점프
    
    handle_zero:
        mov ah, 0eh
        mov al, 'A'
        mov bx, 0x00
        int 0x10
        iret
    
    handle_one:
        mov ah, 0eh
        mov al, 'B'
        mov bx, 0x00
        int 0x10
        iret
    
    start:
        cli ; Interrupt Clear
        mov ax, 0x7c0
        mov ds, ax
        mov es, ax
        mov ax, 0x0
        mov ss, ax
        mov sp, 0x7c00 ; Stack 포인터 설정
        sti ; Interrupt 활성화
    
        ; Interrupt Vector Table 설정
        mov word [ss:0x00], handle_zero ; offset
        mov word [ss:0x02], 0x7c0 ; segment
        mov word [ss:0x04], handle_one
        mov word [ss:0x06], 0x7c0
    
        int 0 ; 0번째 interrupt 발생
        int 1 ; 1번째 interrupt 발생
    
        mov ah, 02h
        mov al, 1 ; 읽을 sector 개수
        mov ch, 0 ; cylinder number lower byte
        mov cl, 2 ; sector number
        mov dh, 0 ; head number
        mov bx, buffer ; sector에서 읽은 내용 buffer label(메모리 주소)에 저장
        int 0x13
    
        jc error ; 에러 발생했을 시 carry flag 변화
        mov si, buffer
        call _print
    
        jmp $
    
    error:
        mov si, error_message
        call _print
        jmp $ ; Infinte Loop
    
    ; 문자열 출력
    print_char:
        mov ah, 0eh
        int 10h
        ret
    
    _print:
        _loop:
            lodsb
            cmp al, 0
            je _done
            call print_char
            jmp _loop
        ret
    
    _done:
        ret
    
    message: db "Hello World", 0
    error_message: db "Failed loading sector", 0
    
    times 510-($-$$) db 0 ; 최소 512byte 돼야 함
    dw 0xAA55 ; Little Endian에 의해 0x55AA 됨; 바로 binary로 저장 
    
    ; 이후 코드 덮어씌어지지 않도록 주의
    buffer:

    Makefile

    all:
    	nasm -f bin boot.asm -o boot.bin
    	dd if=message.txt >> boot.bin
    	dd if=/dev/zero bs=612 count=1 >> boot.bin
    	qemu-system-x86_64 -hda boot.bin

     

     

Designed by Tistory.