1. 程式人生 > >《30天自制作業系統》讀書筆記Day19

《30天自制作業系統》讀書筆記Day19

GitHub地址:https://github.com/scusjs/

1.cat(type)命令

前面實現列出檔案目錄命令,這裡該實現顯示檔案內容命令了,即cat(windows下為type)。
回憶前面的FILEINFO結構體,其中clustno表示檔案從磁碟上哪個扇區開始存放。
通過觀察系統檔案發現如下規律:
磁碟映象中的地址 = clustno * 512 + 0x003e00
接著就開始實現函數了。
先新增一個指標:
char *p;
然後具體實現命令:
else if ((strncmp(cmdline,"cat ",4) == 0) || (strncmp(cmdline,"type ",5) == 0))
{
	//準備檔名
	for (y = 0; y < 11; y++)
	{
		s[y] = ' ';
	}
	y = 0;
	if (strncmp(cmdline,"cat ",4) == 0)
	{
		x = 4;							
	}
	else
	{
		x = 5;
	}
	for (; y < 11 && cmdline[x] != 0; x++)
	{
		if (cmdline[x] == '.' && y <= 8)
		{
			y = 8;
		}
		else
		{
			s[y] = cmdline[x];
			if ('a' <= s[y] && s[y] <= 'z')//全部轉換為大寫
			{
				s[y] -= 0x20;
			}
			y++;
		}
	}
	//尋找檔案
	for (x = 0; x < 224; x++)
	{
		if (finfo[x].name[0] == 0x00)
		{
			break;
		}
		if ((finfo[x].type & 0x18) == 0)
		{
			for (y = 0; y < 11; y ++)
			{
				if (finfo[x].name[y] != s[y])
				{
					break;
				}
			}
			if (y >= 11)
				break;//找到檔案
		}
	}
	if (x < 244 && finfo[x].name[0] != 0x00)
	{
		y = finfo[x].size;
		p = (char *) (finfo[x].clustno * 512 + 0x003e00 + ADR_DISKIMG);
		cursor_x = 8;
		for (x = 0; x < y; x++)//逐字輸出
		{
			s[0] = p[x];
			s[1] = 0;
			if (s[0] == 0x09)//製表符
			{
				for (;;)
				{
					putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", 1);
					cursor_x += 8;
					if (cursor_x == 8 + 240)
					{
						cursor_x = 8;
						cursor_y = cons_newline(cursor_y, sheet);
					}
					if (((cursor_x - 8) & 0x1f) == 0)	//被32整除則break
					{
						break;
					}
				}
			}
			else if (s[0] == 0x0a)//換行
			{
				cursor_x = 8;
				cursor_y = cons_newline(cursor_y, sheet);
			}
			else if (s[0] == 0x0d)//回車
			{
				
			}
			else
			{
				putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s, 1);
				cursor_x += 8;
				if (cursor_x == 8 + 240)
				{
					cursor_x = 8;
					cursor_y = cons_newline(cursor_y, sheet);
				}
			}							
		}
	}
	else
	{
		putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
		cursor_y = cons_newline(cursor_y, sheet);
	}
	cursor_y = cons_newline(cursor_y, sheet);
}
2.FAT的支援
前面的程式雖然能夠顯示檔案內容了,但是對於大於一個扇區(512位元組)的內容的顯示還是有問題的。
在FAT(file allocation table)中,第0柱面、0磁頭、2扇區開始的9個扇區(0x000200~0x0013ff)會記錄大於一扇區檔案的內容記錄在哪些位置。
簡單說下FAT:
FAT中記錄下一部分內容在哪個位置。其中資料會進行處理,其實就是進行移位操作,比如磁碟上:
ab cd ef,處理後得到FAT真實資料:dab efc,其中,dab與efc分別表示數字。讀檔案時,例如clustno=2,讀取0x004200~0x0043ff資料,接下來檢視FAT第二個記錄,如果其為003,則下一部分在clustno=3,即讀取0x004400~0x0045ff,這樣下去直到FAT中記錄為FF8~FFF。
開始寫程式碼:
int *fat = (int *) memman_alloc_4k(memman, 4*2880);
。。。
file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));
。。。
if (x < 244 && finfo[x].name[0] != 0x00)
{
	p = (char *) memman_alloc_4k(memman, finfo[x].size);
	file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
	cursor_x = 8;
	for (y = 0; y < finfo[x].size; y++)//逐字輸出
	{
		...
	}
	...
	memman_free(memman, (int) p, finfo[x].size);
}
執行即可。
3.程式碼整理
視窗相關函式——>window.c
命令列視窗相關函式——>console.c
檔案相關函式——>file.c
在Makefile中新增相應的obj即可。
4.第一個應用程式
現在開始嘗試編寫第一個應用程式。試試第三天的那個程式:
[BITS 32]
fin:
	HLT
	JMP fin
輸入命令:..\z_tools\nask.exe hlt.nas hlt.dog
將其編譯,並在Makefile中將其編譯進入系統。
然後在console.c中對其進行支援:
else if (strcmp(cmdline,"hlt") == 0)
{
	for (y = 0; y < 11; y++)
	{
		s[y] = ' ';
	}
	s[0] = 'H';
	s[1] = 'L';
	s[2] = 'T';
	s[8] = 'D';
	s[9] = 'O';
	s[10]= 'G';
	for (x = 0; x < 224; x++)
	{
		if (finfo[x].name[0] == 0x00)
		{
			break;
		}
		if ((finfo[x].type & 0x18) == 0)
		{
			for (y = 0; y < 11; y ++)
			{
				if (finfo[x].name[y] != s[y])
				{
					break;
				}
			}
			if (y >= 11)
				break;//找到檔案
		}
	}
	if (x < 224 && finfo[x].name[0] != 0x00)
	{
		p = (char *) memman_alloc_4k(memman, finfo[x].size);
		file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
		set_segmdesc(gdt + 1003, finfo[x].size - 1, (int) p, AR_CODE32_ER);//將其註冊到GDT的1003號
		farjmp(0, 1003*8);
		memman_free_4k(memman, (int) p, finfo[x].size);
	}
	else
	{
		putfonts8_asc_sht(sheet, 8, cursor_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
		cursor_y = cons_newline(cursor_y, sheet);
	}
	cursor_y = cons_newline(cursor_y, sheet);
}
執行系統,然後在命令列中輸入hlt,發現命令列卡死,說明程式正確執行。