⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loader.asm

📁 一个加载OS内核的源代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
	ret
	
;--------------------------------------------------------------------
; 函数名: GetFATEntry
;--------------------------------------------------------------------
; 作用:
;	找到序号为 ax 的 Sector 在 FAT 中的条目, 结果放在 ax 中需要注意的是,
;	中间需要读 FAT 的扇区到 es:bx 处, 所以函数一开始保存了 es 和 bx
GetFATEntry:
	push	es
	push	bx
	push	ax
	mov	ax, BaseOfKernelFile	; ┓
	sub	ax, 0100h							; ┣ 在 BaseOfKernelFile 后面留出 4K 
	mov	es, ax								; ┛ 空间用于存放 FAT
	pop	ax
	mov	byte [bOdd], 0
	mov	bx, 3
	mul	bx										; dx:ax = ax * 3
	mov	bx, 2
	div	bx										; dx:ax / 2  ==>  ax <- 商, dx <- 余数
	cmp	dx, 0
	jz	LABEL_NEXT
	mov	byte [bOdd], 1
LABEL_NEXT:									;偶数
	xor	dx, dx								; 现在 ax 中是 FATEntry 在 FAT 中的偏
	mov	bx, [BPB_BytsPerSec]	;移量. 下面来计算 FATEntry 在哪个扇区中
														;(FAT占用不止一个扇区)
	div	bx										; dx:ax / BPB_BytsPerSec  ==>	ax <- 商 
														;(FATEntry 所在的扇区相对于 FAT 来说的扇区号)
														;	dx <- 余数 (FATEntry 在扇区内的偏移)。
	push	dx									;保存在扇区内的偏移
	mov	bx, 0									; bx <- 0	于是, 
	;es:bx = (BaseOfKernelFile - 100):00 = (BaseOfKernelFile - 100) * 10h
	
	add	ax, SectorNoOfFAT1		; 此句执行之后的 ax 就是 FATEntry 所在的扇区号
	mov	cl, 2
	call	ReadSector					; 读取 FATEntry 所在的扇区, 一次读两个, 
	pop	dx				;避免在边界发生错误, 因为一个 FATEntry 可能跨越两个扇区
	add	bx, dx
	mov	ax, [es:bx]
	cmp	byte [bOdd], 1
	jnz	LABEL_EVEN
	shr	ax, 4
LABEL_EVEN:
	and	ax, 0FFFh

LABEL_GET_FAT_ENRY_OK:

	pop	bx
	pop	es
	ret
;------------------------------------------------------------------

;------------------------------------------------------------------
; 函数名: KillMotor
;------------------------------------------------------------------
; 作用:
;	关闭软驱马达
KillMotor:
	push	dx
	mov	dx, 03F2h
	mov	al, 0
	out	dx, al
	pop	dx
	ret
;---------------------------------------------------------------

;---------------------------------------------------------------
[section .data1]
align	32
LABEL_STACK:
		stackspace:	times 1000h db 0
		TopOfStack	equ		BaseOfLoaderPhyAddr + $

;--------------------------------------------------------------
[section .s32]
align 32
[bits 32]
LABEL_PM_START:
		mov ax, SelectorVideo
		mov gs, ax
		mov ax, SelectorFlatRW
		mov ds, ax
		mov es, ax
		mov fs, ax
		mov ss, ax
		mov esp, TopOfStack
		
		;显示一个字符'P',表示进入保护模式
		mov ah, 0Fh
		mov al, 'P'
		mov [gs:((80 * 0 + 39) * 2)], ax
		
		push szMemChkTitle
		call DispStr
		add	 esp, 4
		call DispMemInfo
		call SetupPaging		
	
		call InitKernel
		jmp SelectorFlatC:KernelEntryPointPhyAddr		
		
		; 显示内存信息 --------------------------------------
	DispMemInfo:
		push	esi
		push	edi
		push	ecx
	
		mov	esi, MemChkBuf
		mov	ecx, [dwMCRNumber]	;for(int i=0;i<[MCRNumber];i++) 
	.loop:										;{// 每次得到一个ARDS结构
		mov	edx, 5								;	for(int j=0;j<5;j++)	
		mov	edi, ARDStruct				;	{	// 每次得到一个ARDS中的成员,共5个成员
	.1:													;// 依次显示:BaseAddrLow,BaseAddrHigh,
		push	dword [esi]					;							LengthLow,LengthHigh,Type
		call	DispInt							;		DispInt(MemChkBuf[j*4]); //显示一个成员
		pop	eax										;
		stosd											;		ARDStruct[j*4] = MemChkBuf[j*4];
		add	esi, 4								;
		dec	edx										;
		cmp	edx, 0								;
		jnz	.1										;	}
		call	DispReturn					;	printf("\n");
		cmp	dword [dwType], 1			;	if(Type == AddressRangeMemory) 
		jne	.2										;	{// AddressRangeMemory : 1, 
		mov	eax, [dwBaseAddrLow]	;     AddressRangeReserved : 2
		add	eax, [dwLengthLow]		;
		cmp	eax, [dwMemSize]			;		if(BaseAddrLow + LengthLow > MemSize)
		jb	.2										;
		mov	[dwMemSize], eax			;			MemSize = BaseAddrLow + LengthLow;
	.2:													;	}
		loop	.loop							;}
															;
		call	DispReturn								;printf("\n");
		push	szRAMSize									;
		call	DispStr										;printf("RAM size:");
		add	esp, 4				
																		;
		push	dword [dwMemSize]					;
		call	DispInt										;DispInt(MemSize);
		add	esp, 4											;
	
		pop	ecx
		pop	edi
		pop	esi
		ret
		
		; 启动分页机制 --------------------------------------------------------------
	SetupPaging:
		; 根据内存大小计算应初始化多少PDE以及多少页表
		xor	edx, edx
		mov	eax, [dwMemSize]
		mov	ebx, 400000h		 ; 400000h = 4M = 4096 * 1024, 
		div	ebx							 ; 一个页表对应的内存大小
		mov	ecx, eax				 ; 此时 ecx 为页表的个数,也即 PDE 应该的个数
		test	edx, edx
		jz	.no_remainder
		inc	ecx							 ; 如果余数不为 0 就需增加一个页表
	.no_remainder:
		push	ecx						 ; 暂存页表个数
	
		; 为简化处理, 所有线性地址对应相等的物理地址. 并且不考虑内存空洞.
	
		; 首先初始化页目录
		mov	ax, SelectorFlatRW					; 此段首地址为 PageDirBase
		mov	es, ax
		mov	edi, PageDirBase
		xor	eax, eax
		mov	eax, PageTblBase | PG_P  | PG_USU | PG_RWW
	.1:
		stosd
		add	eax, 4096		; 为了简化, 所有页表在内存中是连续的.
		loop	.1
	
		; 再初始化所有页表
		pop	eax					; 页表个数
		mov	ebx, 1024		; 每个页表 1024 个 PTE
		mul	ebx
		mov	ecx, eax		; PTE个数 = 页表个数 * 1024
		mov	edi, PageTblBase
		xor	eax, eax
		mov	eax, PG_P  | PG_USU | PG_RWW
	.2:
		stosd
		add	eax, 4096		; 每一个页表项指向 4K 的空间
		loop	.2
	
		mov	eax, PageDirBase
		mov	cr3, eax
		mov	eax, cr0
		or	eax, 80000000h
		mov	cr0, eax
		jmp	short .3
	.3:
		nop
	
		ret
; 分页机制启动完毕 ----------------------------------------------------------


;---------------------------------------------------------------------------
		InitKernel:
			xor esi, esi
			mov cx, word [BaseOfKernelFilePhyAddr + 2Ch] ;获取节头表的数目
			movzx ecx, cx
			mov esi, [BaseOfKernelFilePhyAddr + 1Ch]		 ;获取头节表的偏移
			add esi, BaseOfKernelFilePhyAddr					   ;获取头节表的位置
		.Begin:
			mov eax, [esi + 0]
			cmp eax, 0
			jz .NoAction
			
			push dword [esi + 010h]									 ;把段在文件中的长度入栈
			mov  eax, [esi + 04h]										 ;获取段在文件中的偏移
			add  eax, BaseOfKernelFilePhyAddr				 ;获取段在内存中的位置
			push eax																 ;把源地址入栈
			push dword [esi + 08h]									 ;把目的地址入栈
			call MemCpy
			add esp, 12
			
		.NoAction:
			add esi, 020h													  ;指向下一个头节表项
			dec ecx
			jnz .Begin
			
			ret		

		
		%include	"lib.inc"	; 库函数
		
		
;***************************************************** 
[SECTION .data1]	 ; 数据段
ALIGN	32
[BITS	32]
LABEL_DATA:
; 实模式下使用这些符号
; 字符串
_szPMMessage: db	"In Protect Mode now. ^-^", 0Ah, 0Ah, 0	 
_szMemChkTitle:db "BaseAddrL BaseAddrH LengthLow LengthHigh   Type", 0Ah,0	 
_szRAMSize			db	"RAM size:", 0
_szReturn			db	0Ah, 0
; 变量
_wSPValueInRealMode		dw	0
_dwMCRNumber:			dd	0	; Memory Check Result
_dwDispPos:			dd	(80 * 6 + 0) * 2	; 屏幕第 6 行, 第 0 列。
_dwMemSize:			dd	0
_ARDStruct:			; Address Range Descriptor Structure
	_dwBaseAddrLow:		dd	0
	_dwBaseAddrHigh:	dd	0
	_dwLengthLow:		dd	0
	_dwLengthHigh:		dd	0
	_dwType:		dd	0
_PageTableNumber		dd	0

_MemChkBuf:	times	256	db	0

; 保护模式下使用这些符号
szPMMessage		equ	_szPMMessage	+ BaseOfLoaderPhyAddr
szMemChkTitle		equ	_szMemChkTitle	+ BaseOfLoaderPhyAddr
szRAMSize		equ	_szRAMSize	+ BaseOfLoaderPhyAddr
szReturn		equ	_szReturn	+ BaseOfLoaderPhyAddr
dwDispPos		equ	_dwDispPos	+ BaseOfLoaderPhyAddr
dwMemSize		equ	_dwMemSize	+ BaseOfLoaderPhyAddr
dwMCRNumber		equ	_dwMCRNumber	+ BaseOfLoaderPhyAddr
ARDStruct		equ	_ARDStruct	+ BaseOfLoaderPhyAddr
	dwBaseAddrLow	equ	_dwBaseAddrLow	+ BaseOfLoaderPhyAddr
	dwBaseAddrHigh	equ	_dwBaseAddrHigh	+ BaseOfLoaderPhyAddr
	dwLengthLow	equ	_dwLengthLow	+ BaseOfLoaderPhyAddr
	dwLengthHigh	equ	_dwLengthHigh	+ BaseOfLoaderPhyAddr
	dwType		equ	_dwType		+ BaseOfLoaderPhyAddr
MemChkBuf		equ	_MemChkBuf	+ BaseOfLoaderPhyAddr
PageTableNumber		equ	_PageTableNumber + BaseOfLoaderPhyAddr
DataLen			equ	$ - LABEL_DATA
; END of [SECTION .data1]
;*************************************************************** 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -