728x90

현황

- 검은 화면이 뜨도록 만듬

- 뭔가 띄우려면 VRAM 비디오 램에 올바른 값을 써야함

 

문제

- c언어에서는 VRAM 등 직접 메모리 지정해서 쓰는 명령 없음 => 함수 작성

 * 사실 포인터를 이용해서 쓸수 있기하나 넘어가자

 

메모리에 쓰기 함수 추가하기

- naskfunc.nas에 write_mem8함수 추가(8비트 값을 쓰기)

- 사용법 : write_mem8(0x1234, 0x56)

 => 의미 : MOVE BYTE[0x1234], 0x56 -> 0x1234 번지에 바이트 크기(8비트)로 0x56이란 값을 쓴다.

- 사용 과정 : c언어에서 write_mem8() 함수 호출 -> naskfunc.nas의 _write_mem로 점프

- 아래의 코드에서 +4를 하는 이유 32비트 모드(4 x 8비트)이므로 한칸씩 이동하기 위함

 

 

INSTRSET

- 이 프로그램이 486용임을 nask에 알려줌.

 => nask는 EAX(32비트 레지스터)라는 단어를 만나면 레지스터로 해석함

 => 이걸 안해주면 8086 CPU 명령어로 생각해서 레이블 중 하나로 인식



 

 

 

인텔 CPU 아키텍처 흐름

- 8086 -> 80186 -> 286 -> 386 -> 486 -> Pentium -> PentiumPro -> Pentium2 -> Pentium3 -> Pentium4 ...

- 286까지 16비트 CPU, 386부터 32비트 CPU

 

 

 

bootpack.c  부트 프로그램 패키지 수정

- 변수 초기화 해주고

- VRAM에 값을 저어주는 명령을 써보자

 => 아래의 코드에선 0xa0000 ~ 0xaffff 번지에 15라는 값을 입력해줌

 

 

 

실행 결과

 

 

 

 

줄무늬 쓰기

- write_mem8(i, i & 0x0f);로 수정

- i와 0x0f를 and연산한 결과를 반환

- 정리

  0x0f = 0x0000 000f

     i     = 0x000a 0000

     i     = 0x000a  f f f f

=> i의 최하위 비트 LSB(Least Significant bit) 가 f인 경우 

    i번지에 0x0000 000f 쓰기

=> 이외의 경우

    i번지에 0x0000 0000 쓰기

- 결론 : 0x0000 0000 을 쓰다가   일정 구간이 지나서 0x0000 000f쓰기를 반복한다.

 

 

 

 

 

줄무늬 쓰기 실행결과

 

 

 

 

300x250
728x90

하리보테OS를 만드는 중에

힘들어 죽는줄 알았다.

 

친숙하지 않은 기계어 어셈블리어 가지고

부팅 가능하게 만들고 화면 띄우게 만들고

처음 하는 입장이라 상당히 시간이 오래걸렸다.

 

내일부터는 C언어 위주라 조금 수월해질듯한데,

최적화, 영상처리보다 이게 정리하는데 훨씬 오래걸렸다.

 

앞으로 조금 수월해질지는 모르겠는데 이것만 올인하기 보다는

다른 학문이랑 조금씩 병행하면서 해야되겠다.

하나만 하니 질리기도 하고

300x250
728x90
; haribote-os
; TAB=4

; BOOT_INFO 관계
CYLS	EQU		0x0ff0			; 부트섹터 설정
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 색상 갯수에 관한 정의, 몇비트 컬러인지
SCRNX	EQU		0x0ff4			; 해상도 x
SCRNY	EQU		0x0ff6			; 해상도 y
VRAM	EQU		0x0ff8			; 그래픽 버퍼 개시번지
		
		ORG		0xc200			; harybote.sys가 로딩되는 메모리 주소

		MOV		AL,0x10			; VGA 그래픽스, 320x200x8bit 컬러
		MOV		AH,0x00
		MOV		BYTE [VMODE],8	; 화면 모드를 기록함.
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; 키보드 LED 상태를 BIOS가 알려줌

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

fin:
		HLT
		JMP		fin

 

CPU의 모드

- 16비트모드, 32비트 모드가 존재

- 16비트 모드로 부팅시 AX, CX와 같은 16비트 레지스터 사용 가능하나 EAX같은 32비트 레지스터는 불가

- 기계어 명령 번호도 다르고, 해석 방법과 동작이 달라 호환 불가

 

 

32비트 모드 장단점

- 장점 : 메모리 1MB 이상 사용 가능. 이상한 기계어 만나도 오동작하는 보호 기능 사용 가능

- 단점 : BIOS 사용불가. BIOS는 16비트 기계어로 작성됨 => 32비트 쓰기전에 마음것 해보자

 

 

할일

- 키보드 상태를 BIOS가 알려주는것 확인

 

 

작업

- 화면 모드 설정후 관련 정보를 메모리에 저장. 이후 필요할것을 고려 => 부팅시 정보로 BOOT_INFO로 명명

- vRAM 비디오램 : 값을 저장할수도 있지만 번지와 화소가 매칭되어 그림 표현 가능

  * VRAM은 메모리 맵 상에 여러개 존재. 화면 모드가 여러가지가 존재하기 때문

 * BOOT_INFO에 어느 VRAM 사용하는지 기록(현재 0x000a 0000 ~ 0x000a fffff로 64kb)

- 기타 정보(화소수, 컬러수, 키보드 상태 등)은 0x0ff0 주변에 저장

 

 

 

 

 

 

 

 

C언어 사용하기 

- 기존의 haribote.nas -> asmhead.nas로 이름 변경

- bootpack.c c언어 파트 추가. 앞으로 OS 부팅에 필요한 처리들을 패키지로 작성 예정

 

bootpack.c를 기계어로 만들기

1. cc1.exe : bootpack.c -> bootpack.gas

 => cc1.exe는 gcc 개조한 것. gas 어셈블리어 파일 출력

2. gas2nask.exe : bootpack.gas -> bootpack.nas

 => gas를 nask로 번역

3. nask.exe : bootpack.nas -> bootpack.obj

  => nask 파일로 우선 목적 파일 작성(기계어)

4. ob2bim.exe : bootkpack.obj -> bootpack.bim

  => 서로 다른 목적파일들을 연결해야함 obj2bim : 오브젝트 파일들을 binary image file로

5. bim2hrb.exe -> bootpack.bim -> bootpack.hrb

  => 기계어를 붙여 정리한것으로 완성 x. 각 OS에 맞게 수정 필요 하리보테 os에 맞게 bim을 번역

  * 하리보테 os c언어는 harimain()에서 시작함

6. asmhead.bin과 bootpack.hrb를 붙여 haribote.sys 만듬

 

 

 

* 이미지란 단어

- 영상의 image라기 보다는 상상하는 무언가, 가짜로 된 것을 의미

 

 

 

 

 

HLT 하기

- hlt 명령어를 어셈블러로 함수 만듦

- 함수명은 io_hlt

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 오브젝트 파일 만드는 모드
[BITS 32]						; 32비트 모드용 기계어 만듬


; 오브젝트 파일을 위한 정보

[FILE "naskfunc.nas"]			; 소스 파일명 정보

		GLOBAL	_io_hlt			; 이 프로그램에 포함된 함수명


; 아래는 실제 함수

[SECTION .text]		; 오브젝트 파일에서 다음의 함수가 있으면 어셈블리어로 작성

_io_hlt:	; void io_hlt(void);
		HLT
		RET

 

HLT 함수 파일 naskfunc.nas 설명

- bootpack.obj와 링크하기 위해 오브젝트 파일로 만들어야 함

 => 출력 포맷을 WCOFF

- 32비트용 기계어로 만들기 위해 [BITS 32] 설정

- C언어 함수와 연계할수 있도록 앞에 _를 붙여 GLOBAL 명령으로 선언

- 실제 함수 내용 작성 : 함수명과 동일한 레이블에 작성. RET는 return;

- bootpack.c에서 io_hlt는 naskfunc.nas 상에 정의되어 있으므로 선언만 해둠

void io_hlt(void);

void HariMain(void)
{

fin:
	io_hlt(); /* c언어에선 HLT 할수 없음 */
	goto fin;

}

 

실행 결과

- 실행해보면 hlt 처리되서 바로 종료되는듯 하다.

300x250
728x90
; haribote-ipl
; TAB=4

CYLS	EQU		10				; CYLS를 10으로 정의

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880			; 디스크 총섹터수
		DB		0xf0			; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880			; 드라이브 크기 한번더씀
		DB		0,0,0x29		; 필요하다고함
		DD		0xffffffff		; 볼륨 시리얼 번호
		DB		"HARIBOTEOS "	; 디스크 이름
		DB		"FAT12   "		; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX

; 디스크 읽기

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 실린더 0
		MOV		DH,0			; 헤드 0
		MOV		CL,2			; 섹터 2 
readloop:
		MOV		SI,0			; 실패 횟수를 세는 레지스터
		
retry:
		MOV		AH,0x02			; AH=0x02 : 디스크 읽기
		MOV		AL,1			; 1 섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 바이오스 호출
		JNC		next			; 에러가 없으면 next로
		ADD		SI,1			; SI에 1더하기
		CMP		SI,5			; SI와 5비교
		JAE		error			; SI >= 5 이면 에러로
		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로
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		; DH < 2 read loop로
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		; CH < CYLS read loop로

; 0xc200번지(hribote.sys)로 점프. 10실린더까지 다 읽어 로드되면 본프로그램 점프

		JMP		0xc200

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"load error"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa
; haribote-os
; TAB=4

		ORG		0xc200			; harybote.sys가 로딩되는 메모리 주소

		MOV		AL,0x10			; VGA 그래픽스, 320x200x8bit 컬러
		MOV		AH,0x00
		INT		0x10
fin:
		HLT
		JMP		fin

 

 

현황

- 부트 섹터 완성

- 본 프로그램 실행하도록 수정

- 목표 : 실제 화면을 띄어 동작하는지 확인해보자

 

 

화면 모드로 전환하기

- 화면모드로 전환 : 비디오 BIOS의 AH = 0x00으로 할 수 있음

- 현재 설정에 따라 320x200x8bit 모드로 부팅됨

 

비디오 모드

- AH = 0x00

- AL = 모드

       0x03 : 16색 텍스트, 80x25

       0x12 : VGA 그래픽스, 640x480x4bit 컬러, 독자 영역 액세스

       0x13 : VGA 그래픽스, 320x200x8bit 컬러, 팩드 픽셀

       0x6a : 확장 VGA 그래픽스, 800x600x4bit 컬러 독자  영역 액세스(비디오카드에 의해 지원 x)

- 리턴값 : x

* AX = 누산기 레지스터

 

 

 

실행결과

- make run 한 결과 화면 모드로 전환되어 커서가 사라짐

 

300x250
728x90
; haribote-ipl
; TAB=4

CYLS	EQU		10				; CYLS를 10으로 정의

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880			; 디스크 총섹터수
		DB		0xf0			; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880			; 드라이브 크기 한번더씀
		DB		0,0,0x29		; 필요하다고함
		DD		0xffffffff		; 볼륨 시리얼 번호
		DB		"HARIBOTEOS "	; 디스크 이름
		DB		"FAT12   "		; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX

; 디스크 읽기

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 실린더 0
		MOV		DH,0			; 헤드 0
		MOV		CL,2			; 섹터 2 
readloop:
		MOV		SI,0			; 실패 횟수를 세는 레지스터
		
retry:
		MOV		AH,0x02			; AH=0x02 : 디스크 읽기
		MOV		AL,1			; 1 섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 바이오스 호출
		JNC		next			; 에러가 없으면 next로
		ADD		SI,1			; SI에 1더하기
		CMP		SI,5			; SI와 5비교
		JAE		error			; SI >= 5 이면 에러로
		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로
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		; DH < 2 read loop로
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		; CH < CYLS read loop로

; 0xc200번지(hribote.sys)로 점프. 10실린더까지 다 읽어 로드되면 본프로그램 점프

		JMP		0xc200

fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"load error"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa

복습

- 이전에 버퍼 세그먼트가 ES = 0x0820, BX =0으로 설정되어 데이터가 로드되는 지점이 0x8200 ~ 0x83ff번지가 됨

- 여기서 0x8000 ~ 0x81ff는 512바이트의 부트섹터 내용이 들어감

 

 

부트섹터에서 OS 본 프로그램 실행하기

- 부트 섹터 맨 앞이 0x8000 번지에 로드되도록 하여 읽어들인 상태

- 디스크를 메모리에 읽어들인 상태로 img의 0x4200(본체 어드레스)는 pc 메모리의 0x8000 + 0x4200 = 0xc200에 위치

 

 

ORG 명령

- 기계어가 실행시 PC 메모리의 어디에 로드 되어야 하는지를 nask에게 알림

- 이 프로그램들을 메모리의 어느 번지에 로드하도록 요청

 

 

부트섹터 완료 후 OS 본 프로그램으로 넘어가기

- ipl.nas 처리 후 next의 맨 아래에 0xc200으로 점프

- haribote.sys의 첫번째 데이터로 넘어감(바이너리 데이터로 haribote.sys의 실제 내용이 어디있는지확인함)

 

본 프로그램 동작

- ipl.nas에서 JMP 0xc200으로 현재 sys파일로 넘어옴

- org 0xc200을 만나 이제 0xc200 지점에서부터 로드하는걸로 설정

; haribote-os
; TAB=4

		ORG		0xc200			; 이 프로그램이 로딩되는 위치?
fin:
		HLT
		JMP		fin

 

make run

- make run 하면 부팅은 되는데 동작하는지는 잘모르겠다.

300x250
728x90

os 본프로그램(본체?) 만들기

- 이전에 만든 어셈블리코드는 부트섹터

- 부트섹터를 제외한 실제 프로그램을 구현해보자

=> HLT하는 단순 프로그램

- 이름은 haribote.nas => nask로 어셈블하여 haribote.sys 만들기

TOOLPATH = ../z_tools/
MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
EDIMG    = $(TOOLPATH)edimg.exe
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = cp
DEL      = rm


default :
	$(MAKE) img


ipl.bin : ipl.nas Makefile
	$(NASK) ipl.nas ipl.bin ipl.lst

haribote.sys : haribote.nas Makefile
	$(NASK) haribote.nas haribote.sys haribote.lst

haribote.img : ipl.bin haribote.sys Makefile
	$(EDIMG)   imgin:../z_tools/fdimg0at.tek \
		wbinimg src:ipl.bin len:512 from:0 to:0 \
		copy from:haribote.sys to:@: \
		imgout:haribote.img


img :
	$(MAKE) haribote.img

run :
	$(MAKE) img
	$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
	$(MAKE) -C ../z_tools/qemu

install :
	$(MAKE) img
	$(IMGTOL) w a: haribote.img

clean :
	-$(DEL) ipl.bin
	-$(DEL) ipl.lst
	-$(DEL) haribote.sys
	-$(DEL) haribote.lst

src_only :
	$(MAKE) clean
	-$(DEL) haribote.img

메이크파일코드

- 부트섹터는 ipl.nas, 본 프로그램은 haribote.sys 로 출력

- 처음 512바이트는 ipl.bin으로 이후 영역에 haribote.sys 추가

- 출력 프로그램은 ipl.bin + haribote.sys = haribote.img

- make img 명령으로 파일 작성 완료

 

바이너리 에디터로 보기(어셈블리 코드와 매칭해서 보기)

- 맨 첫 두바이트는 매직 코드

- 다음 바이트는 DB 0x90

- 다음 바이트들은 "HARIBOTE"

- 다음 워드 DW 512 => 0x0200 => 표기는 00 02(리틀엔디언 방식)

...

 

본 프로그램은 어디에 있을까

- haribote.img에서 본 프로그램 haribote.sys 파일명은 0x002600 부근에서 보임

- 파일 내용은 0x004200이후에 나오는듯

 

본프로그램 동작 방법

1. 부트 섹터 로드

2. 부트섹터가 본프로그램 haribote.sys를 실행하면 됨

 

 

300x250
728x90

이번에 할일

이전의 과정으로 C0-H0-S2(0x8200)에서 C0-H0-S18섹터(~0x3aff) 까지 읽음

-> 이제 C0-H1-S1로 0xa400부터 읽음.

-> C0-H1-S18까지 읽고 다음 실린더 C1-H0-S1으로 넘어가자

-> 이를 반복해서 C9-H1-S18까지 읽자

 

 

1.5mb 플로피 디스크 구성

- 디스크 1장 : 80 실린더, 2헤드

- 실린더 1개 : 18 섹터

- 섹터 1개 : 512바이트

=> 총 1,440kb

 

 

; haribote-ipl
; TAB=4

CYLS	EQU		10				; CYLS를 10으로 정의

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880			; 디스크 총섹터수
		DB		0xf0			; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880			; 드라이브 크기 한번더씀
		DB		0,0,0x29		; 필요하다고함
		DD		0xffffffff		; 볼륨 시리얼 번호
		DB		"HARIBOTEOS "	; 디스크 이름
		DB		"FAT12   "		; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX

; 디스크 읽기

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 실린더 0
		MOV		DH,0			; 헤드 0
		MOV		CL,2			; 섹터 2 
readloop:
		MOV		SI,0			; 실패 횟수를 세는 레지스터
		
retry:
		MOV		AH,0x02			; AH=0x02 : 디스크 읽기
		MOV		AL,1			; 1 섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 바이오스 호출
		JNC		next			; 에러가 없으면 next로
		ADD		SI,1			; SI에 1더하기
		CMP		SI,5			; SI와 5비교
		JAE		error			; SI >= 5 이면 에러로
		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로
		MOV		CL,1
		ADD		DH,1
		CMP		DH,2
		JB		readloop		; DH < 2 read loop로
		MOV		DH,0
		ADD		CH,1
		CMP		CH,CYLS
		JB		readloop		; CH < CYLS read loop로

fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"load error"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa

 

 

 

추가된 내용

1. 섹터 18까지 리드 루프

2. 섹터 18 넘어가면 섹터 =1, 헤더++, 헤더가 2인지 확인 => 헤더가 1이면 리드루프로

3. 섹터 18 넘고, 헤더도 2가 되면 => 헤더 = 0,  실린더++

4. 실린더가 10(CYLS)보다 작은 경우에만 read loop

5. 실린더가 10이되면 fin 레이블로 넘어가 종료

 

 

EQU 명령

- C언어의 #define과 동일

- EQU 는 equal의 약어

- CYLS EQU 10 => CYLS = 10

 

 

현황

- 부트섹터 코드 대부분 완성

- 10(실린더) x 2(헤더) x 18(섹터) x 512(바이트) = 184,320(바이트) = 180KB까지 읽을수 있게됨

- PC 메모리의 0x8200~0x34ffff는 디스크에서 읽은 데이터들로 꽉 차게됨

 

300x250
728x90

현재 코드

- 부트 섹터 생성 + 메시지 출력 + putloop 코드에 한번 진입하면 다음 섹터로 넘어감 + 플로피가 안읽히면 다시 시도

- 목표 : 18섹터 까지 읽도록 개선하자

 

 

; haribote-ipl
; TAB=4

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880			; 디스크 총섹터수
		DB		0xf0			; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880			; 드라이브 크기 한번더씀
		DB		0,0,0x29		; 필요하다고함
		DD		0xffffffff		; 볼륨 시리얼 번호
		DB		"HARIBOTEOS "	; 디스크 이름
		DB		"FAT12   "		; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX

; 디스크 읽기

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 실린더 0
		MOV		DH,0			; 헤드 0
		MOV		CL,2			; 섹터 2 
readloop:
		MOV		SI,0			; 실패 횟수를 세는 레지스터
		
retry:
		MOV		AH,0x02			; AH=0x02 : 디스크 읽기
		MOV		AL,1			; 1 섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 바이오스 호출
		JNC		next			; 에러가 없으면 next로
		ADD		SI,1			; SI에 1더하기
		CMP		SI,5			; SI와 5비교
		JAE		error			; SI >= 5 이면 에러로
		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로



fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"load error"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa

 

 

수정된 부분

- retry 레이블에 JNC next와 next 레이블이 추가됨

 

JBE

- jump if below or equal

- CL이 18보다 같거나 작으면 readLoop로 진입

 

이 코드가 하는일

1. 섹터 이동

 - CL 섹터 번호

2. 번지 지정

 - ES 읽어낼 번지 

  * 0x20은 512/16으로 512를 16진수 표현

 => ES = ES + 0x20로 다음 번지 주소를 가리킴

 

 

정리해보자

1. 0x7c00(부트섹터)에서 로드 시작 -> entry로 점프

 

2. 레지스터들 초기화

2.1 레지스터 초기화

 ss 스텍세그먼트, ds 데이터세그먼트 0 입력

 sp 스택 포인터 0x7c00 입력

2.2 디스크 읽기 준비

 es 버퍼 어드레스 0x0820 읽을 데이터 주소

 (es가 0x0820인경우, 세그먼트 레지스터이므로 * 16 => 0x8200을 가리킴)

 ch 실린더 해더 0, 해드 0, 섹터 2 선택

 si 소스 인덱스 0, 실패 횟수 저장 

 

3. 디스크 읽기 및 에러 검사

3.1 인터럽트 준비

 AH = 0x02 디스크 읽기 모드 설정

 AL = 1 1번 섹터

 BX = 0 세그먼트 레지스터 0(주소 세부 조정용)

 DL = 0x00 0번 드라이브 -> 드라이브 A 설정

3.2 인터럽트 호출

 INT 0x13 위 인터럽트 관련 값에따라 동작 수행 -> 값읽기 수행

 에러가 안뜨면 next로 점프

3.3 next 구문

 버퍼 레지스터 주소를 0x0820 + 0x0020. 20씩 이동

 add cl,1 섹터 번호++, 다음 섹터번호 지정

 cl이 18번을 초과하면 아래의 fin으로 내려감

 

 

4. 에러 발생시

4.1 에러 발생시 내려가기

 

 에러 발생시 레지스터 0으로 초기화 후 드라이브 리셋 수행

 => 다시 retry 레이블로 점프

4.2 에러 횟수 5회 초과시

 error 레이블로 점프 및 load 에러 출력

 

 

haribote00c 정리

1. 부트 섹터 로드

2. 18번 섹터까지 값읽기

3. 에러 발생시 5번 반복. 횟수 초과시 에러 문자 출력

 

 

접근한 메모리 번지 범위

- C0-H0-S2 에서 C0-H0-S18까지 접근

- 섹터 1개당 512바이트 => 512 x 17 = 8,704바이트

=> 0x8200 ~ 0xa3ff번지까지 값이 읽혀짐

 

 

 

 

 

 

300x250
728x90
; haribote-ipl
; TAB=4

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HELLOIPL"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880				; 디스크 총섹터수
		DW		0xf0				; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880				; 드라이브 크기 한번더씀
		DB		0, 0, 0x29			; 필요하다고함
		DD		0xffffffff			; 볼륨 시리얼 번호
		DB		"HELLO-OS  "		; 디스크 이름
		DB		"FAT12   "			; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX

; 디스크 읽기

		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 : 디스크 읽기
		MOV		AL,1			; 1 섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 바이오스 호출
		JNC		fin				; 에러 없으면 fin으로
		ADD		SI,1			; SI에 1더하기
		CMP		SI,5			; SI와 5비교
		JAE		error			; SI >= 5 이면 에러로
		MOV		AH,0x00
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 드라이브 리셋
		JMP		retry


fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"good i e yo you good good good"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa

 

추가한 부분 harib00b

- 플로피 디스크가 읽지 못하는 경우 발생할수 있으므로 5번 정도 다시 읽도록 루프문 추가

 

 

JNC 명려어

- JUMP if not carry

- 위 코드에 에러가 발생하지 않으면(캐리가 없으면) fin을 호출하도록 사용

 

 

JAE

- jump if above or equal

- 같거나 크면 점프

 => SI가 5와 같거나 큰경우 에러 루틴으로 점프

 

 

INT 0x13

- AT-BIOS에 따르면 INT 0x13은 드라이브 리셋을 호출

 

300x250
728x90

 

; haribote-ipl
; TAB=4

		ORG		0x7c00			; 메모리 안에서 로딩되는 곳

; 아래는 표준 FAT12 포맷 플로피 디스켓을 위한 내용들

		JMP		entry
		DB		0x90
		DB		"HELLOIPL"		; 부트섹터 이름. 마음대로해도 ok
		DW		512				; 1섹터 크기(바이트 단위, 512)
		DB		1				; 클러스터 크기(1로 해야됨)
		DW		1				; 예약된 섹터수 
		DB		2				; 디스크 FAT 테이블 수
		DW		224				; 루트 디렉토리 엔트리 수 (보통 224엔트리)
		DW		2880				; 디스크 총섹터수
		DW		0xf0				; 미디어 타입
		DW		9				; 하나의 FAT 테이블 섹터 수
		DW		18				; 1트랙에 몇 색터가있는지
		DW		2				; 헤드의 수
		DD		0				; 파티션 없으므로 0
		DD		2880				; 드라이브 크기 한번더씀
		DB		0, 0, 0x29			; 필요하다고함
		DD		0xffffffff			; 볼륨 시리얼 번호
		DB		"HELLO-OS  "		; 디스크 이름
		DB		"FAT12   "			; 포멧이름
		RESB	18				; 18바이트 남김

; 프로그램 본체

entry:
		MOV		AX,0			; 레지스터 초기화
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX
		MOV		ES,AX

		MOV		SI,msg


; 추가된 부분

		MOV		AX,0x0820
		MOV		ES,AX
		MOV		CH,0			; 실린더 0
		MOV		DH,0			; 헤드 0
		MOV		CL,2			; 섹터 2 

		MOV		AH,0x02			; AH=0x02 :디스크 읽기
		MOV		AL,1			; 1섹터
		MOV		BX,0
		MOV		DL,0x00			; A 드라이브
		INT		0x13			; 디스크 BIOS 추출
		JC		error




fin:
		HLT						; CPU 정지 시킴
		JMP		fin				; 무한 루프

error:
		MOV		SI,msg

putloop:
		MOV		AL,[SI]
		ADD		SI,1			; SI에 1 더함
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 한 문자 표시 기능
		MOV		BX,15			; 컬러 코드
		INT		0x10			; 비디오 BIOS 호출
		JMP		putloop

msg:
		DB		0x0a, 0x0a		; 줄바꿈 문자 2개
		DB		"good i e yo you good good good"
		DB		0x0a			; 줄바꿈
		DB		0

		RESB	0x7dfe-$		; 나머지칸 0채우기

		DB		0x55, 0xaa

버퍼 어드레스

- 디스크서 읽은 데이터를 메모리 어디다가 저장할지 나타내는 주소값

- 1개의 레지스터로 나타내자니 (16비트 컴퓨터에선) 0x0000 ~ 0xFFFF 밖에 표현하지 못함

 => 0 ~ 65,535번지(1번지당 1바이트)로 64KB밖에 사용하지 못한다는 예기

 * 32비트 컴퓨터에선 0x0000 0000 ~ 0xFFFF FFFF로 최대 4GB까지 다룰수 있으나. 16비트 컴터에선 불가

 

세그먼트 레지스터

- 16비트 컴퓨터에서 메모리 지정할때 사용하는 레지스터

ex. ES:BX 같은 것들

 

 

세그먼트 레지스터 사용 에시

-  MOV AL, [ES:BX] 

=> AL = ES * 16 + BX . AL레지스터에 다음 값이 대입됨

- 즉, ES로 대략적인 메모리 위치를 조절하고 BX로 세세하게 조정

 

 

16비트 컴퓨터의 메모리 주소 범위와 세그먼트 레지스터를 사용하여 확장한 주소 범위

- 16비트 컴퓨터 : 0x0000 ~ 0xFFFF => 64KB

- 16비트 컴퓨터 + 세그먼트 레지스터 

  ES도 0x0000 ~ 0xFFFF, BX도 0x0000 ~ 0xFFFF까지 가능하므로,

  => 64KB x 16 = 640 + 360 + 24 = 1024 => 1024KB = 1MB까지 주소 지정 가능해짐

* 64KB에서 세그먼트 레지스터 덕분에  1MB로 쓸수 있는 공간이 많이 커지긴 했다.

 

 

 

모든 주소와 세그먼트 레지스터

- 모든 메모리 주소는 항상 세그먼트 레지스터도 같이 지정해야함.

- 하지만 세그먼트 레지스터가 생략된 경우( [DS:숫자]) DS가 보통 0임.

- 예시

MOV AL, [SI] => MOV AL, [DS:SI]

MOV CX,[1234] => MOV CX, [DS:1234]

* 위 경우 DS가 0이라면 ? => MOV CX, [1234] => MOV CX, [0x04d2] => 0x04d2번지의 값을 CX에 대입하라

* 위 경우 DS가 0x00ff라면? => 16 x 0x00ff + 1234(=0x04d2) = 16 x 255 + 1234 = 4080 + 1234 = 5314 = 0x14c2

=> MOV CX, [0x14c2]  : 0x14c2번지에 존재하는 값을 CX에다가 대입하라

 

 

 

 

 

 

 

 

300x250

+ Recent posts