内核级命令实现示例

问题

内核级命令如何实现?

通过系统调用

内核级命令的本质

命令所对应的功能需要内核协助才能实现

  • 在内核中实现命令的功能 (如:获取硬件信息)
  • 创建系统调用接口连接内核功能
  • Shell 任务通过系统调用实现命令

命令示例:获取系统物理内存容量 (mem)

解决方案

1. 在系统启动时,在实模式下获取物理内存容量 (int 0x15)

2. 将物理内存容量暂存于共享内存区

3. 内核执行时,从共享内存区获取物理内存容量 (存入全局变量)

4. 实现系统调用 uint GetMemSize()

5. Shell 任务通过 uint GetMemSize() 实现命令 mem 并打印容量大小

物理内存容量大小获取 (回顾)

物理内存容量大小修正 (回顾)

uint GetMemSize() 的实现

mem 命令的实现

 

内核级命令的实现

common.asm

BaseOfSharedMemory   equ    0xA000

; Shared Value Address

GdtEntry             equ       BaseOfSharedMemory + 0
GdtSize              equ       BaseOfSharedMemory + 4
IdtEntry             equ       BaseOfSharedMemory + 8
IdtSize              equ       BaseOfSharedMemory + 12
RunTaskEntry         equ       BaseOfSharedMemory + 16
InitInterruptEntry   equ       BaseOfSharedMemory + 20
MemSize              equ       BaseOfSharedMemory + 24
SendEOIEntry         equ       BaseOfSharedMemory + 28
LoadTaskEntry        equ       BaseOfSharedMemory + 32
AppMainEntry         equ       BaseOfSharedMemory + 36

loader.asm

;
;
GetMemSize:
	mov dword [MemSize], 0
	xor eax, eax
	mov ax, 0xE801
	
	int 0x15
	
	jc geterr
	
	shl eax, 10       ; eax = eax * 1024
	shl ebx, 6 + 10   ; ebx = ebx * 64 * 1024
	
	mov ecx, 1
	shl ecx, 20       ; ecx = 1024 * 1024
	
	add dword[MemSize], eax
	add dword[MemSize], ebx
	add dword[MemSize], ecx
	
	jmp getok

geterr:
	mov dword [MemSize], 0
	
getok:
	ret

kentry.asm

;
;    
InitGlobal:
    push ebp
    mov ebp, esp
    
    mov eax, dword [GdtEntry]
    mov [gGdtInfo], eax
    mov eax, dword [GdtSize]
    mov [gGdtInfo + 4], eax
    
    mov eax, dword [IdtEntry]
    mov [gIdtInfo], eax
    mov eax, dword [IdtSize]
    mov [gIdtInfo + 4], eax
    
    mov eax, dword [RunTaskEntry]
    mov dword [RunTask], eax
    
    mov eax, dword [InitInterruptEntry]
    mov dword [InitInterrupt], eax
    
    mov eax, dword [SendEOIEntry]
    mov dword [SendEOI], eax
    
    mov eax, dword [LoadTaskEntry]
    mov dword [LoadTask], eax
    
    mov eax, dword [MemSize]
    mov dword [gMemSize], eax
    
    leave
    
    ret

syscall.c

uint GetMemSize()
{
	uint ret = 0;
	
	SysCall(3, 0, &ret, 0);
	
	return ret;
}

ihandler.c

void SysCallHandler(uint type, uint cmd, uint param1, uint param2)    // __cdcel__
{
	switch(type)
	{
		case 0:
			TaskCallHandler(cmd, param1, param2);
			break;
		case 1:
			MutexCallHandler(cmd, param1, param2);
			break;
		case 2:
			KeyCallHandler(cmd, param1, param2);
		case 3:
			SysInfoHandler(cmd, param1, param2);
			break;
		default:
			break;
	}
}

sysinfo.c

uint gMemSize = 0;

void SysInfoHandler(uint cmd, uint param1, uint param2)
{
	if(cmd == 0)
	{
		uint* pRet = (uint*)param1;
		
		*pRet = gMemSize;
	}
}

shell.c

static void Mem()
{
	uint ms = GetMemSize() >> 20;
	
	ClearCmdInfo();
	
	SetPrintPos(CMD_START_W, CMD_START_H + 1);
	PrintString("Physical Memory: ");
	PrintIntDec(ms);
	PrintString(" MB\n");
}

void Shell()
{
	List_Init(&gCmdList);

	AddCmdEntry("clear", Clear);
	AddCmdEntry("demo1", Demo1);
	AddCmdEntry("demo2", Demo2);
	AddCmdEntry("mem", Mem);

	SetPrintPos(CMD_START_W, CMD_START_H);
	
	PrintString(PROMPT);
	
	while(1)
	{
		uint key = ReadKey();
		
		if(IsKeyDown(key))
		{
			char ch = GetChar(key);
			byte vc = GetKeyCode(key);
			
			Handler(ch, vc);
		}
	}
}

GetMemSize 函数中获取到的内存容量的单位为 Byte,我们把它显示为 MB,所以需要将获取到的内存大小右移20位。

执行 mem 命令结果如下图所示

 该系统中物理内存大小为 128MB

小结

Shell 的本质是一个任务 (执行于用户态)

Shell 是命令解释器,解释用户输入的命令

Shell 命令可分为3种类型:

  • 启动型命令:启动其他任务 (一个或多个) 实现功能
  • 应用级命令:Shell 任务自身实现命令功能
  • 内核级命令:Shell 任务依赖内核实现命令功能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值