728x90
20강 소스코드입니다.
--------------------------------------------------------------------------------
안녕하세요
오늘은 하드디스크에 쓰는 함수를 구현해봅시다.
논리는 하드디스크를 읽었을 때와 똑같습니다. 다른 점은 하드디스크에 내릴 명령이 읽기(0x20) 이 아니라 쓰기(0x30)인 점, 그리고 쓸 때 명령어 "rep outsw " 를 사용할 것이라는 점입니다.
바로 코드를 봅시다. 19강에 짰던 코드와 거의 차이가 없음을 알 수 있을 겁니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
void HDDwrite(unsigned int sector, char* buffer)
{
unsigned char LBA_a = sector & 0xFF; // sector의 [7:0] 비트 추출
unsigned char LBA_b = (sector >> 8) & 0xFF; // sector의 [15:8] 비트 추출
unsigned char LBA_c = (sector >> 16) & 0xFF; // sector의 [23:16] 비트 추출
unsigned char LBA_d = ((sector >> 24) & 0x0F) | 0xE0; // sector의 [27:24] 비트 추출
// HDD INT 활성화
__asm__ __volatile__
(
"mov al, 0;"
"mov dx, 0x3F6;"
"out dx, al;"
);
while (HDD_BSY() == 1); // HDD가 busy 하다면 계속 대기
/////////////////////////////////////////////////
// 하드디스크 셋팅 시작
/////////////////////////////////////////////////
// 드라이브/헤드 레지스터 초기화 + LBA 주소 [27:24] 4비트
__asm__ __volatile__
(
"mov al, %0;"
"mov dx, 0x1F6;"
"out dx, al;"::"r"(LBA_d)
);
__asm__ __volatile__
(
"mov al, 0x01;"
"mov dx,0x1F2;"
"out dx, al;"
); // 섹터 1개 쓴다
__asm__ __volatile__
(
"mov al, %0;"
"mov dx,0x1F3;"
"out dx, al;" ::"r"(LBA_a)
); // LBA 주소 [7:0] 8비트
__asm__ __volatile__
(
"mov al, %0;"
"mov dx,0x1F4;"
"out dx, al;" ::"r"(LBA_b)
); // LBA 주소 [15:8] 8비트
__asm__ __volatile__
(
"mov al, %0;"
"mov dx,0x1F5;"
"out dx, al;" ::"r"(LBA_c)
); // LBA 주소 [23:16] 8비트
/////////////////////////////////////////////////
// 하드디스크 셋팅 끝
/////////////////////////////////////////////////
// 쓰기(0x30) 내리기 전 하드디스크 드라이버가 명령을 받을 수 있는지 체크
while ((HDD_BSY() == 1) || (HDD_DRDY() == 0));
// 쓰기(0x30) 명령 내리기
__asm__ __volatile__
(
"mov al, 0x30;"
"mov dx,0x1F7;"
"out dx, al;"
);
// 명령 내렸는데 오류가 발생했다면 쓰기를 중단한다.
if (HDD_ERR() == 1)
{
kprintf("Error!!", videomaxline - 1, 0);
return;
}
while (HDD_DRQ() == 0); // 데이터를 쓸 때까지 대기
// Buffer의 512바이트만큼 데이터를 메모리(0x1F0)에 쓴다
__asm__ __volatile__("mov dx,0x1F0;");
__asm__ __volatile__("mov esi, %0;" : : "r"(buffer));
__asm__ __volatile__("mov ecx, 256");
__asm__ __volatile__("rep outsw");
}
|
cs |
좋습니다! 읽기때와 마찬가지로 제대로 실행되는지 알 수가 없으니 이를 검증하는 간단한 Shell 명령어를 추가합시다.
1
2
3
4
5
6
7
8
9
10
|
// shell.c 에 추가
void sh_HDDwrite()
{
unsigned char test[512] = "Hello world!";
HDDwrite(2, test);
HDDwrite(3, test);
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
|
// main.c의 함수 수정
void translate_shell()
{
if (keyboard[0] == 0) { return; } // 명령어 없이 그냥 ENTER 침
if (kstrcmp(keyboard, "clear")) { sh_clear(); return; }
if (kstrcmp(keyboard, "version")) { sh_version(); return; }
if (kstrcmp(keyboard, "read")) { sh_HDDread(); return; }
if (kstrcmp(keyboard, "write")) { sh_HDDwrite(); return; }
kprintf("There is no such command.",++curline, 0);
}
|
cs |
이렇게 함수를 추가하면 "write" 입력시 하드디스크의 2번째 섹터와 3번째 섹터에 각각 Hello world 가 저장될 겁니다.
좋습니다! 이제 바로 컴파일해보고 Qemu로 돌려봅시다. 그 전에 하드디스크에 해당하는 hdd.img의 섹터 2, 섹터 3을 먼저 체크해봅시다.

보다시피 아무것도 없습니다. 이제 Qemu 상에 write 명령을 입력합시다. 하드디스크를 읽었을 때와 마찬가지로 쓸 때도 인터럽트가 발생합니다. 따라서 idt_ignore 가 아래에 찍혀나옵니다. 그리고 아무것도 출력하지 않게 해놓았으니 아무 반응 없을 겁니다.

좋습니다. 이제 환경을 끄고 다시 hdd.img를 확인합시다!

예상대로 섹터 2와 섹터 3의 첫 줄에 Hello world! 가 저장되어 있는 것을 확인할 수 있습니다. 이렇게 간단하게 하드디스크에 쓰는 함수를 구현했습니다!! 드디어 HoGoS 에서도 자료를 하드디스크에 저장할 수 있게 된 겁니다.
이를 극대화하기 위해선 파일시스템이 절대적으로 필요합니다. 다음 강의에서는 이를 다뤄보도록 하겠습니다. 파일시스템이 완성된다면 손쉽게 파일을 읽고 쓸 수 있게 됩니다!
감사합니다.
728x90
'소프트웨어 (과거) > C & 자료구조 & 커널 & DB' 카테고리의 다른 글
임베디드 내일 마무리 (0) | 2022.06.22 |
---|---|
21. 부트 스트랩 정리 (0) | 2022.06.14 |
19. 하드디스크 드라이버 읽기 (0) | 2022.06.14 |
18. 하드디스크 드라이버 - Q Menu (0) | 2022.06.14 |
17. 하드디스크 드라이버 (0) | 2022.06.14 |