KIMBIBLE / MakitOS

Make OS Project
BSD 3-Clause "New" or "Revised" License
0 stars 2 forks source link

IPL 제작2(디스크 읽기) #9

Open KIMBIBLE opened 7 years ago

KIMBIBLE commented 7 years ago

초반 OS 제작 과정 자체에서 많은부분 Makefile을 활용한 툴 사용이 중점적으로 이루어져 제작 과정에 사용하는 툴들을 관리하기 위한 디렉토리 z_tools 추가를 통해 Makefile에서 툴 경로 설정 용이하게 만듬 (아니면 Makefile 수정해야 할 부분이 너무 많아짐)

KIMBIBLE commented 7 years ago

INTRO

이전에 제작한 IPL은 실제로 프로그램을 로드하지 않았음. 해당 장에서는 실제로 프로그램을 로드하는 부분까지 진행 할 예정.

KIMBIBLE commented 7 years ago

이전 ipl과의 차이

helloos5 까지의 ipl과 bbkimos_00a 부터의 ipl의 차이

  1. helloos5 : 단순히 비디오 BIOS 호출을 통해 화면에 문자 출력하는 기능
  2. bbkimos_00a : 디스크 읽고 이를 에러 발생 시 결과 화면에 출력하는 기능

error:

  MOV     AX,0
  MOV     ES,AX
  MOV     SI,msg

msg:

  DB      0x0a, 0x0a      ; 개행을 2개
  DB      "load error"
  DB      0x0a            ; 개행
  DB      0

  RESB    0x7dfe-$            ; 0x7dfe까지를 0x00로 채우는 명령

  DB      0x55, 0xaa
KIMBIBLE commented 7 years ago

일반적인 BIOS 인터럽트 목록

https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%EC%98%A4%EC%8A%A4%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8%ED%98%B8%EC%B6%9C

KIMBIBLE commented 7 years ago

img 파일 생성 과정 정리

KIMBIBLE commented 7 years ago

실행 결과(bbkimos_00a)

배치 파일을 알맞게 수정하고 make run 을 입력하여 실행하게 되면 플로피 디스크에서 이미지를 읽어올 때 오류가 발생하기 않았기 때문에 기본 QEMU 출력 문자를 제외한 아무런 문자 출력이 없는 화면 상태로 정상적으로 동작하는 것을 확인할 수 있다.

KIMBIBLE commented 7 years ago

디스크 읽기 코드 분석

바이오스 인터럽트 호출

https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%EC%98%A4%EC%8A%A4%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8%ED%98%B8%EC%B6%9C

AH 설명 00h >>> 디스크 드라이브 초기화 01h >>> 드라이브 상태 검사 02h >>> 섹터 읽기 03h >>> 섹터 쓰기 04h >>> 섹터 유효 여부 확인 05h >>> 트랙 포맷 08h >>> 드라이브 변수 가져오기 09h >>> 고정 드라이브 변수 초기화 0Ch >>> 지정된 트랙으로 찾기 0Dh >>> 고정 디스크 컨트롤러 초기화 15h >>> 드라이브 종류 가져오기 16h >>> 플로피 드라이브 미디어 변경 상태 가져오기 17h >>> 디스크 종류 설정 18h >>> 플로피 드라이브 미디어 종류 설정 41h >>> 확장 디스크 드라이브 (EDO) 설치 검사 42h >>> 섹터 확장 읽기 43h >>> 섹터 확장 쓰기 44h >>> 섹터 확장 유효 여부 확인 45h >>> 드라이브 잠금/잠금 해제 46h >>> 미디어 꺼내기 47h >>> 확장 찾기 48h >>> 드라이브 변수 확장 가져오기 49h >>> 미디어 변경 상태 확장 가져오기 4Eh >>> 하드웨어 구성 확장 설정

디스크 읽기 코드 분석

  1. ES 레지스터 : BX레지스터와 함께 사용 디스크에서 읽은 데이터를 메모리의 어디에 저장할지 나타내는 주소 값. 계산 : ES * 16 + BX (최대 1MB정도)
  MOV     AX,0x0820
  MOV     ES,AX

  MOV     BX,0

위 코드에 따르면 ES : 0x0820, BX: 0x00 이므로 0x8200 + 0x00인 0x8200이 디스크에서 읽은 데이터를 저장할 메모리의 위치가 된다. 0x8000이후의 메모리를 사용한 이유는 AT 메모리 맵에 의하면 사용하지 않고 있는 메모리 영역이기 때문,

  1. CHS 방식으로 디스크를 읽을 부분 레지스터에 설정.
  MOV     CH, 0           ; 실린더 0
  MOV     DH, 0           ; 헤드 0
  MOV     CL, 2           ; 섹터 2 (MBR 1번 섹터 이후의 섹터)

실린더 번호 : 디스크 바깥(외부)부터 세어 몇 번째 트랙인지. (한면에 0 ~ 79 : 80개) 섹터 번호 : 트랙 안의 몇 번째 블록인가. (각 실린더 내에 1 ~ 18번 : 18개) 헤드 번호 : 헤드0(위), 헤드(아래)

  1. 디스크 동작 레지스터에 설정
  MOV     AH, 0x02        ; AH=0x02 : 디스크 read
  MOV     AL, 1           ; 1섹터
  MOV     BX,0
  MOV     DL, 0x00        ; A드라이브

AH레지스터에 0x02를 저장해 디스크 읽기 방식을 설정하고 읽을 디스크의 단위를 1섹터로 설정한 후 (BX레지스터는 버퍼 어드레스로 위에 설명) DL레지스터에 드라이버 번호를 설정(드라이브를 1개만 사용중이므로 0x00 설정)

  1. INT 0x13 명령 실행
  INT     0x13            ; 디스크 BIOS 호출
  JC      error

위에서 설정한 레지스터를 토대로 인터럽트 INT 0x13을 호출해 디스크 BIOS를 호출한다. 디스크 READ 에러 발생 시 CF 레지스터에 1이 저장된다. INT 13 호출 결과 CF 레지스터의 값은 아래의 값이 리턴된다. 에러 발생 시 : 1 정상 동작 시 : 0

INT 0x13 호출 결과 CF 레지스터에 리턴되는 에러 코드를 통해 정상 동작 시 JC error 이후 부분을 실행하고 에러 발생 시 error 레이블로 점프한다.

Parameters: AH >>> 02h AL >>> Sectors To Read Count CH >>> Cylinder CL >>> Sector DH >>> Head DL >>> Drive ES:BX >>> Buffer Address Pointer

Results: CF >>> Set On Error, Clear If No Error AH >>> Return Code AL >>> Actual Sectors Read Count

https://en.wikipedia.org/wiki/INT_13H

KIMBIBLE commented 7 years ago

디스크 정리

하드 디스크의 두 가지 접근 방식(Addressing Mode)

CHS-Adressierung(Cylinder, Header, Sector)

LBA-Adressierung (Logical Block Addressing)

변환

CHS -> LBA

LBA = ( ( CYLINDER heads per cylinder + HEAD ) sectors per track ) + SECTOR – 1

LBA -> CHS

CYLINDER = LBA / ( heads per cylinder * sectors per track ) HEAD = ( LBA / sectors per track ) % heads per cylinder SECTOR = ( LBA % sectors per track ) + 1

KIMBIBLE commented 7 years ago

에러 발생 시 재 동작 처리

코드 분석

; 디스크를 읽는다 MOV AX,0x0820 MOV ES,AX MOV CH, 0 ; 실린더 0 MOV DH, 0 ; 헤드 0 MOV CL, 2 ; 섹터 2 MOV SI, 0 ; 실패 회수를 세는 레지스터 retry: MOV AH, 0x02 ; AH=0x02 : 디스크 read MOV AL, 1 ; 1섹터 MOV BX,0 MOV DL, 0x00 ; A드라이브 INT 0x13 ; 디스크 BIOS 호출 JNC fin ; 에러가 일어나지 않으면 fin에 ADD SI, 1 ; SI에 1을 더한다 CMP SI, 5 ; SI와 5를 비교 JAE error ; SI >= 5이면 error에 MOV AH,0x00 MOV DL, 0x00 ; A드라이브 INT 0x13 ; 드라이브의 리셋트 JMP retry

  1. 실패 횟수 카운트

      MOV     SI, 0           ; 실패 회수를 세는 레지스터

    SI 레지스터를 0으로 초기화하여 실패 횟수를 카운트합니다. 에러 발생 시 5회 반복을 하기 위해 이후 CMP SI, 5 명령을 통해 실패 횟수를 체크합니다.

  2. retry 레이블

    retry: retry 레이블을 정의해 조건에 만족하지 않을 경우(에러 발생 && 에러 발생 횟수<5) 마지막의 JMP retry를 통해 retry 레이블로 점프해 다시 명령을 수행하도록 합니다.

retry 레이블에서 조건을 통해 반복을 제어하는 부분은 아래와 같습니다.

  JNC     fin         ; 에러가 일어나지 않으면 fin에
  ADD     SI, 1           ; SI에 1을 더한다
  CMP SI, 5           ; SI와 5를 비교
  JAE     error           ; SI >= 5이면 error에

위 명령을 통해 에러가 5회 미만 발생할 경우 다시 retry 레이블로 점프하여 다시 반복을 수행하고 반복 결과 에러가 5회 이상 발생할 경우 error 레이블로 점프, 정상 수행 시 fin레이블로 점프 동작을 하게 됩니다.

  1. 드라이브 리셋
  MOV     AH,0x00
  MOV     DL, 0x00        ; A드라이브
  INT     0x13            ; 드라이브의 리셋트

위와 같이 AH 레지스터와 DL 레지스터를 0으로 초기화하여 INT 0x13 인터럽트를 호출하면 드라이브가 리셋되어 처음부터 다시 시작할 수 있습니다. (AT-BIOS에서 시스템 리셋)

KIMBIBLE commented 7 years ago

디스크를 18섹터까지 읽기

retry: MOV AH, 0x02 ; AH=0x02 : 디스크 read MOV AL, 1 ; 1섹터 MOV BX,0 MOV DL, 0x00 ; A드라이브 INT 0x13 ; 디스크 BIOS 호출 JNC next ; 에러가 일어나지 않으면 next에 ADD SI, 1 ; SI에 1을 더한다 CMP SI, 5 ; SI와 5를 비교 JAE error ; SI >= 5 이면 error에 MOV AH,0x00 MOV DL, 0x00 ; A드라이브 INT 0x13 ; 드라이브의 리셋트 JMP retry next:

  MOV     AX, ES          ; 주소를 0x200 진행한다
  ADD     AX,0x0020
  MOV     ES, AX          ; ADD ES, 0x020라고 하는 명령이 없기 때문에 이렇게 하고 있다
  ADD     CL, 1           ; CL에 1을 더한다
  CMP     CL, 18          ; CL와 18을 비교
  JBE     readloop        ; CL <= 18 이라면 readloop에

; 다 읽었지만 우선 할일이 없기 때문에 sleeve

이렇게 섹터의 수를 증가시키는 방법으로 디스크의 모든 섹터를 다 읽을 수 있을까?

한번에 여러 섹터를 읽을 수 없을까??

KIMBIBLE commented 7 years ago

디스크를 10 실린더만큼 읽어보기

코드 추가

아래는 이와 같은 동작을 수행하도록 코드를 변경한 부분이다.

CYLS EQU 10 ; 어디까지 Read할까

  ORG     0x7c00          ; 이 프로그램이 어디에 Read되는가

먼저 EQU 명령을 통해 literal 상수 10를 CYLS라는 이름으로 사용할 것을 명시한다.

next: MOV AX, ES ; 주소를 0x200 진행한다 ADD AX,0x0020 MOV ES, AX ; ADD ES, 0x020 라고 하는 명령이 없기 때문에 이렇게 하고 있다 ADD CL, 1 ; CL에 1을 더한다 CMP CL, 18 ; CL와 18을 비교 JBE readloop ; CL <= 18 이라면 readloop에 MOV CL,1 ADD DH,1 CMP DH,2 JB readloop ; DH < 2 라면 readloop에 MOV DH,0 ADD CH,1 CMP CH,CYLS JB readloop ; CH < CYLS 라면 readloop에 ; 다 읽었지만 우선 할일이 없기 때문에 sleeve

KIMBIBLE commented 7 years ago

어셈블리 조건 점프 명령들 정리

http://pyrasis.com/blog/entry/ReverseEngineeringForNewbieAssemblyOperation