플로피 디스크에서 OS 이미지를 로딩하자

BIOS 서비스와 소프트웨어 인터럽트

OS 이미지 로딩 기능 구현

최종 부트 로더 소스 코드 (BootLoader.asm)

  [ ORG 0x00 ]
  [ BITS 16 ]

  SECTION .text

  jmp 0x07C0:START

  ; MINT64 OS에 관련된 환경 설정 값
  TOTALSECTORCOUNT: dw 1024

  ; 코드 영역
  START:
      mov ax, 0x07C0
      mov ds, ax

      mov ax, 0xB800
      mov es, ax

      mov ax, 0x0000
      mov ss, ax
      mov sp, 0xFFFE
      mov bp, 0xFFFE

      ; 화면을 지우고, 속성값을 녹색으로 설정
      mov si, 0

  .SCREENCLEARLOOP:
      mov byte [ es:si ], 0
      mov byte [ es:si + 1 ], 0x0A

      add si, 2

      cmp si, 80 * 25 * 2
      jl .SCREENCLEARLOOP

      ; 화면 상단에 메시지 출력
      push MESSAGE1
      push 0
      push 0
      call PRINTMESSAGE
      add sp, 6

      ; OS 이미지를 로딩한다는 메시지 출력
      push IMAGELOADINGMESSAGE
      push 1
      push 0
      call PRINTMESSAGE
      add sp, 6

      ; 디스크에서 OS 이미지를 로딩

      ; 디스크를 읽기 전에 먼저 리셋
  RESETDISK:
      ; BIOS Reset Function 호출
      mov ax, 0
      mov dl, 0
      int 0x13
      jc HANDLEDISKERROR

      ; 디스크에서 섹터를 읽음
      mov si, 0x1000
      mov es, si
      mov bx, 0x0000

      mov di, word [ TOTALSECTORCOUNT ]
  READDATA:
      cmp di, 0
      je READEND
      sub di, 0x01

      ; BIOS Read Function 호출
      mov ah, 0x02
      mov al, 0x1
      mov ch, byte [ TRACKNUMBER ]
      mov cl,    byte [ SECTORNUMBER ]
      mov dh, byte [ HEADNUMBER ]
      mov dl, 0x00
      int 0x13
      jc HANDLEDISKERROR

      ; 복사할 어드레스와 트랙, 헤더, 섹터 에드레스 계산
      add si, 0x0020
      mov es, si

      mov al, byte [ SECTORNUMBER ]
      add al, 0x01
      mov byte [ SECTORNUMBER ], al
      cmp al, 19
      jl READDATA

      xor byte [ HEADNUMBER ], 0x01
      mov byte [ SECTORNUMBER ], 0x01

      cmp byte [ HEADNUMBER ], 0x00
      jne READDATA

      add byte [ TRACKNUMBER ], 0x01
      jmp READDATA
  READEND:

      ; OS 이미지가 완료괴었다는 메시지 출력
      push LOADINGCOMPLETEMESSAGE
      push 1
      push 20
      call PRINTMESSAGE
      add sp, 6

      ; 로딩한 가상 OS 이미지 실행
      jmp 0x1000:0x0000

  ; 함수 코드 영역
  HANDLEDISKERROR:
      push DISKERRORMESSAGE
      push 1
      push 20
      call PRINTMESSAGE

      jmp $

  PRINTMESSAGE:
      push bp
      mov bp, sp

      push es
      push si
      push di
      push ax
      push cx
      push dx

      mov ax, 0xB800
      mov es, ax

      ; X, Y의 좌표로 비디오 메모리의 어드레스를 계산함
      mov ax, word [ bp + 6 ]
      mov si, 160
      mul si
      mov di, ax

      mov ax, word [ bp + 4 ]
      mov si, 2
      mul si
      add di, ax

      mov si, word [ bp + 8 ]

  .MESSAGELOOP:
      mov cl, byte [ si ]

      cmp cl, 0
      je .MESSAGEEND

      mov byte [ es:di ], cl

      add si, 1
      add di, 2

      jmp .MESSAGELOOP
  .MESSAGEEND:
      pop dx
      pop cx
      pop ax
      pop di
      pop si
      pop es
      pop bp
      ret

  ; 데이터 영역
  MESSAGE1: db 'MINT64 OS Boot Loader Start~!!', 0
  DISKERRORMESSAGE: db 'Disk Error~!!', 0
  IMAGELOADINGMESSAGE: db 'OS Image Loading...', 0
  LOADINGCOMPLETEMESSAGE: db 'Complete~!!', 0

  SECTORNUMBER: db 0x02
  HEADNUMBER: db 0x00
  TRACKNUMBER: db 0x00

  times 510 - ( $ - $$ ) db 0x00

  db 0x55
  db 0xAA

테스트를 위한 가상 OS 이미지 생성

1024섹터 크기의 가상 OS 이미지

  [ ORG 0x00 ]
  [ BITS 16 ]

  SECTION .text

  jmp 0x1000:START

  SECTORCOUNT: dw 0x0000
  TOTALSECTORCOUNT equ 1024

  ; 코드 영역
  START:
      mov ax, cs
      mov ds, ax

      mov ax, 0xB800
      mov es, ax

      ; 각 섹터 별로 코드를 생성
      %assign i  0
      %rep TOTALSECTORCOUNT
          %assign i  i + 1

          mov ax, 2

          mul word [ SECTORCOUNT ]
          mov si, ax

          mov byte [ es:si + ( 160 * 2 )], '0' + ( i % 10 )
          add word [ SECTORCOUNT ], 1

          %if i == TOTALSECTORCOUNT
              jmp $
          %else
              jmp ( 0x1000 + i * 0x20 ):0x0000
          %endif

          times ( 512 - ( $ - $$ ) % 512 ) db 0x00
      %endrep

macOS 환경에서 가상 OS 이미지를 로딩하여 실행한 결과는 다음과 같다. 예상된 결과와 다르게 나온다.

Linux Ubuntu 환경에서 실행한 결과이다. 원하는 결과가 나온다.

OS 이미지가 로딩되는 어드레스가 0x10000이고 0xA0000 이후 영역은 비디오 메모리로 사용하기 때문에 OS를 로딩할 수 있는 전체 크기는 0x90000B 이다. 섹터 크기는 최대 1152섹터가 된다. 그래서 1153 섹터 이상으로 설정하면 비디오 메모리를 침범하기 때문에 qemu에 오류가 발생하면서 종료된다.

Ubuntu 환경에서 1153섹터로 설정했을 때 발생한 오류

그러나 macOS에서 1153섹터를 설정해도 정상적으로 작동한다.

results matching ""

    No results matching ""