问题
内核级命令如何实现?
通过系统调用
内核级命令的本质
命令所对应的功能需要内核协助才能实现
- 在内核中实现命令的功能 (如:获取硬件信息)
- 创建系统调用接口连接内核功能
- 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 任务依赖内核实现命令功能