MacOS环境-手写操作系统-48-让内核从错误中恢复

简介: MacOS环境-手写操作系统-48-让内核从错误中恢复

让内核从错误中恢复

1.简介

微软早期的DOS系统 存在一个严重的问题是


如果应用程序运行出现问题 它会导致整个系统完全奔溃掉


我们当前的系统内核也存在这一的问题


例如打开api_call.asm,其内容如下

[SECTION .s32]
BITS 32
call main
retf
api_putchar:
  mov edx, 1
  mov al, [esp + 4]
  int 02Dh
  ret
%include "app.asm"


call main 时CPU控制权会提交给应用程序


执行应用程序的代码 应用程序执行完毕后


返回到call main语句的下一条指令继续执行


call main 的下一条语句是retf


它的作用是从堆栈上得到内核代码的全局描述符


把该描述符在描述符表中的下标赋值给寄存器cs


同时把内核要执行语句的地址从堆栈上取得 并赋值给寄存器ip


这样CPU的控制器会重新交还给内核


假设我们对上面代码做一个修改如下


[SECTION .s32]
BITS 32
call main
pop  eax ;故意让返回地址出错造成异常保护中断
retf
....


我们在执行retf语句时 把存储在堆栈上的内核要执行的语句地址弹出


这样要返回的内核地址就会遭遇破坏


当执行retf语句后 ip指针会执行内存的任意一个无法确定的地方


于是CPU在接下来的执行中就会遇到错误


上面代码修改后运行起来 就会出现报错


点击确定之后 系统就被关闭了


出现这种现象的原因


由于ip指针指向了无效地址 致使CPU执行了无效指令进而导致系统的整体奔溃


接下来我们看看如何处理让系统从这种严重错误中恢复回来


这样就可以防止应用程序执行恶意代码而对系统造成伤害


当CPU在执行指令出现错误时


例如遇到了无效指令 那么CPU会出发0Dh号中断


让该中断来处理当前所出现的异常局面


如果该中断无法处理 那么CPU就会停止运行


于是就出现了上面的情况


为了让系统能从错误中恢复 我们需要实现0Dh号中断


在中断中 我们直接结束掉当前正在运行的应用程序 直接把CPU的控制全交还给内核


2.代码

kernel.asm中注册0Dh号中断


代码修改如下

LABEL_IDT:
%rep  13
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep
.0Dh:
    Gate SelectorCode32, exceptionHandler,0, DA_386IGate
%rep  18
    Gate  SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep


上面代码在中断描述符表中注册了一个0Dh号中断


当中断发送时 CPU会调用exceptionHandler函数


看看该函数的实现 同样也是在kernel.asm中

_exceptionHandler:
exceptionHandler equ _exceptionHandler - $$
    cli
    ;把内存段切换到内核
    mov  ax, SelectorVram
    mov  ds, ax
    mov  es, ax 
    mov  ax, SelectorStack ;切换到内核堆栈段
    mov  ss, ax
    
    mov  ecx, [0xfe4];获取内核堆栈指针
    add  ecx, -8
    mov  [ecx+4], ss ;保存中断时的堆栈段
    mov  [ecx], esp  ;保存中断时堆栈指针

    mov  esp, ecx ;切换内核指针

    call intHandlerForException
    
.kill:  ;通过把CPU交给内核的方式直接杀掉应用程序
     mov  esp, [0xfe4]
     sti
     popad
     ret

中断运行时


先把内核专有内存段的描述符赋值给寄存器ds,es


这样代码运行时可以直接读写内核的数据 同时把内核的堆栈描述符赋值给寄存器ss


这样代码运行时使用的堆栈就是内核的专有堆栈


然后把错误发生时的应用程序使用的堆栈段描述符和堆栈指针存入内核堆栈


接着调用函数intHandlerForException进行错误处理


该函数实现在内核的C语言部分 也就是在write_vga_desktop.c中


void intHandlerForException(int *esp) {
    g_Console.cur_x = 8;
    cons_putstr("INT 0D ");
    g_Console.cur_x = 8;
    g_Console.cur_y += 16;
    cons_putstr("General Protected Exception");         
    g_Console.cur_y += 16;
    g_Console.cur_x = 8;
    return 1;
}


它的做法很简单 只是在控制台上打印出两行字符串


分别是"INT OD" 和 “General Protected Exception”


然后就返回了


回到中断实现部分 也就是.kill对应的代码


在内核把控制权交给应用程序时 会把它当时的堆栈指针存储到内存[0xfe4]处


内核时通过start_app把控制权交给应用程序的 我们再看看start_app的代码


start_app:  ;void start_app(int eip, int cs,int esp, int ds)
    cli
    pushad
    ...
    mov  [0xfe4], esp
    ...


start_app在执行时 通过指令把当时所有通用寄存器的数据存储到堆栈上


同时把esp指针的值 也就是当时的内核堆栈指针存储到内存0xfe4这个地方


因此.kill 的指令 mov esp [0xfe4]实际上就是对上面指令mov [0xfe4], esp 的逆操作


同时popad也是对上面指令pushad的逆操作


我们再看看start_app是如何被调用的 在write_vga_desktop.c中

void cmd_hlt() {
    ....
    start_app(0, 11*8,64*1024, 12*8);
    char *pApp = (char*)(q + 0x100);
    showString(shtctl, sht_back, 0, 179, COL8_FFFFFF, pApp);
    memman_free_4k(memman, buffer.pBuffer, buffer.length);
    memman_free_4k(memman, q, 64 * 1024);
}


start_app是在cmd_hlt中被调用的


我们知道C语言在调用子函数时


会把调用子函数后要执行的下一条指令的地址压入堆栈


因此当上面代码在调用start_app函数时


下一条指令 也就是char pApp=(char)这条语句的地址会被压入到堆栈上


当.kill处的代码执行完语句popad后


此时堆栈上存储的恰好就是语句char pApp=(char)的地址


于是当我们执行指令ret的时候 该语句的地址会赋值给ip寄存器


这样CPU就会直接从char pApp=(char)这条语句开始执行


这就类似与应用程序正常执行完毕后 CPU控制权正常返还给内核的情况是一样的


这样 当应用程序执行出现严重错误时 CPU触发0Dh号异常处理中断


在该中断中 代码会把CPU控制权直接交还给内核


就相当于把出现异常的应用程序毁尸灭迹


内核就好像什么事都没发生过一样 继续按照老样子运行


3.运行

相关文章
|
13小时前
|
存储 Java C语言
MacOS环境-手写操作系统-04-实模式进入保护模式
MacOS环境-手写操作系统-04-实模式进入保护模式
6 1
|
13小时前
|
存储 Java iOS开发
MacOS环境-手写操作系统-02-读写软盘
MacOS环境-手写操作系统-02-读写软盘
9 3
|
12小时前
|
缓存 Java iOS开发
MacOS环境-手写操作系统-13-鼠标中断
MacOS环境-手写操作系统-13-鼠标中断
8 1
|
12小时前
|
存储 算法 C语言
MacOS环境-手写操作系统-15-内核管理 检测可用内存
MacOS环境-手写操作系统-15-内核管理 检测可用内存
8 0
|
11小时前
|
算法 调度 iOS开发
MacOS环境-手写操作系统-31-进程自动切换
MacOS环境-手写操作系统-31-进程自动切换
6 0
|
10小时前
|
小程序 iOS开发 MacOS
MacOS环境-手写操作系统-44-运行简单的程序
MacOS环境-手写操作系统-44-运行简单的程序
7 0
|
11小时前
|
存储 算法 调度
MacOS环境-手写操作系统-29-进程切换
MacOS环境-手写操作系统-29-进程切换
5 0
|
13小时前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-01-最小操作系统
MacOS环境-手写操作系统-01-最小操作系统
5 0
|
12小时前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-11-建立中断机制
本文详细介绍了如何为内核建立中断机制,涉及8259A中断控制器的初始化、中断信号的传递过程以及中断描述符表的设置。通过汇编和C语言代码展示了如何处理中断,特别是键盘和鼠标中断,最后给出了编译和运行的步骤。 摘要由CSDN通过智能技术生成
7 0
|
11小时前
|
存储 调度 iOS开发
MacOS环境-手写操作系统-32-进程挂起和恢复
MacOS环境-手写操作系统-32-进程挂起和恢复
6 0