Chinaunix

标题: 基于X86写的一个操作系统,有兴趣的一起开发[长期维护贴] [打印本页]

作者: Buddy_Zhang1    时间: 2017-05-21 15:53
标题: 基于X86写的一个操作系统,有兴趣的一起开发[长期维护贴]
本帖最后由 Buddy_Zhang1 于 2017-05-21 21:11 编辑

For All Friends
  目前基于 Intel X86 写了一个操作系统,内核的基本框架还在开发中,希望有兴趣的一起加入开发。
  这只是我的个人兴趣而开发并开源的一个项目,目的通过动手写一个操作系统去了解更深层次的知识。

  这是一个基于 Intel X86 的 32 位操作系统, 这个操作系统名叫 BiscuitOS,该系统包含了一个操作系统的必要元素:
  1. 进程管理子系统
      就目前开发进度而言, 系统还只支持单进程,但有基本的调度管理机制,以及 TSS,系统门,中断门,陷阱门等机制。
      进程调度子系统还在开发中,目前使用的基本的长调度和短调度,以后会引入完全公平调度。 对进程子系统的朋友可以
      做这个子系统的开发者。
  2. 内存管理子系统
      就目前的开发进度而言,系统还不支持虚拟内存,内存大小被限制在 16M 之内,但后期要实现虚拟内存的支持。
      支持分段保护机制,支持分页保护机制。支持 GDT,LDT,以及全局页目录,支持高速缓存和cache。支持缺页处理。
      后期的目标是实现虚拟内存和主流的内存分配器: Buddy,slab,slub,高端内存分配器和 DMA。
  3. 文件管理子系统
      就目前的开发进度, 系统还不支持虚拟文件系统, rootfs 还未移植完成。该子系统还在开发中。
      后期的目标是实现虚拟文件系统,并至少支持一个 ext 的文件系统,并结合一个 rootfs 制作出完整的发行版系统。
  4. 设备驱动
      就目前开发进度,系统支持 tty 串口驱动, 一个 EGA 彩屏驱动, 以及硬盘驱动和软盘驱动,基本的驱动框架还未建立。
      后期的目标,基于虚拟文件系统构建多种驱动框架。

使用 BiscuitOS
  
      BiscuitOS 是基于 Intel X86 开发的操作系统,所以运行这个操作系统之前需要 Intel X86 的硬件平台。
      由于目前每个开发者有一个 X86 的硬件开发平台是不现实的, 为了解决这个问题以及降低开发门槛,
      各位开发者可以使用 QEMU 进行开发。 QEMU 是一个开源的处理器模拟软件,它支持 X86 CPU 的模拟。
      QEMU 运行 BiscuitOS 的效果图如下:
      
      [attach]701571[/attach]
            
如何加入开发

     BiscuitOS 的源码我已经同步到 github 上,各位开发者可以在自己的 Linux 主机上(推荐使用 Ubuntu1604),按如下步骤:
     1. 获取源码
  1. git clone https://github.com/BuddyZhang1/BiscuitOS.git
复制代码
    2. 使用前的准备
         由于系统运行之前需要安装必要的开发工具,开发者可以按如下步骤进行安装:
  1. sudo apt-get install qemu
  2. sudo apt-get install figlet gcc make gdb git
  3. sudo apt-get install cflow graphviz gawk
复制代码
        如果你的 Linux 主机是 64 位系统, 那么你还需要安装 32 位的系统库, 开发者可以按如下步骤进行安装:
  1. sudo apt-get install lib32z1 lib32z1-dev
复制代码
    3. 编译并运行 BiscuitOS
         运行之前我们先编译这个系统,以保持系统是最新的,请按如下步骤:
  1. cd */BiscuitOS/
  2. make
  3. make start
复制代码
    4. 添加您的代码并进行调试
         各位开发者可以根据你的想法,对这个系统进行修改,但修改之后要遵循 GPL(大家可以去 google 里搜索 “GNU 通用公共授权条款”)。
         添加好你的源码之后就是调试代码,开发者可以使用如下步骤进行调试:
         1) 在你的源码目录下打开两个终端,第一个终端输入如下命令:
  1. cd */BiscuitOS/
  2. make clean
  3. make
  4. make debug
复制代码
            另外一个终端输入如下命令:
  1. cd */BiscuitOS/tools/build/
  2. gdb system
  3. (>gdb) target remote :1234
  4. (>gdb) b function_name
  5. (>gdb) c
  6. (>gdb) n
复制代码
            内核的调试基于 GDB,具体的调试命令可以查看下面关于调试的章节。 function_name 为你要调试函数的名字。 实际调试如下图:
            
             GDB Host
            
             GDB Target
            
             Qemu

     6. 提交您的代码
         提交代码的方式有两种,第一种,如果您熟悉 github 提交补丁,你可以通过 github 提交给我,这里我不做更多关于 github 提交补丁的方法,自行 google。
         第二种是使用邮件进行提交,你可以将你的补丁,通过邮件发给我,这是我的邮箱 buddy.zhang@aliyun.com.提交之后,我要进行验证,在确认无误之后,我会将您的补丁合入到主线里。

系统特色


    正如开头介绍的,这个系统只是我的兴趣爱好,我不会把它变成一个很复杂的系统, 系统的开发借鉴于 Linux,UNIX,FreeBSD。
    为了让更多的想学内核而不能实践的开发者准备了几个比较有用的功能:
    1. 全部代码都在自己的掌控之中
       在这个操作系统中,你可以调试所有的代码,包括系统一上电, CPU 跳转到 0x7c00 之后的第一条指令。
       具体如何调试,我会继续回帖分享给大家。
   
    2. 系统所有的汇编代码统一使用 ATT 汇编进行编写。
    3. 系统支持 GDT,LDT,分段,分页,IDT,全局目录等,各种主流功能正在开发中。
    4. 支持自动画函数调用图功能
        这个功能很有意思,开发者只需使用命令,输入要画函数的名字,系统就会自动将该函数的调用图画出来。 开发者可以按如下步骤进行操作   
  1. cd */BiscuitOS/
  2. make
  3. make draw FUN=xxx
复制代码
      xxx 为函数的名字,如我使用这个工具画 “die” 这个函数的调用图,如下:
      
        

交流

     BiscuitOS 的开发中,如果遇到任何不懂的问题或疑惑,可以发邮件或在 ChinaCU 的论坛发帖,我很高兴帮你解答您的疑问和问题
     这是我经常使用的邮箱
  1. buddy.zhang@aliyun.com
复制代码
  
     欢迎各位喜欢操作系统的朋友,一起交流学习,共同促进操作系统在中国的发展。
     
     Good Luck!






BiscuitARM_SmallLogo.png (101.56 KB, 下载次数: 151)

BiscuitARM_SmallLogo.png

作者: Buddy_Zhang1    时间: 2017-05-21 15:54
本帖最后由 Buddy_Zhang1 于 2017-06-04 23:40 编辑

系统更新日志

  [2017-06-04] 添加 kmalloc() 和 kfree(),以及相应的测试程序
  [2017-06-04] 添加 interrupt6 - interrupt45 测试程序
  [2017-06-03] 添加 interrupt0 - interrupt5 测试程序
  [2017-05-30] 添加 string library
  [2017-05-30] 添加 .config & CONFIG_ 机制
  [2017-05-30] 添加测试代码机制
  [2017-05-25] 添加 fork() 系统调用和基本的内存分配器,支持 get_free_page() 和 free_page() 例程。
  [2017-05-22] 添加 Coding Style 检测机制



作者: Buddy_Zhang1    时间: 2017-05-21 15:54
本帖最后由 Buddy_Zhang1 于 2017-05-21 20:54 编辑

调试 BiscuitOS 内核

   BiscuitOS 支持 GDB 调试,开发可以使用 GDB 调试 BiscuitOS 的所有代码。
   BiscuitOS 的调试分为两部分,根据 Intel X86 的使用手册,系统上电之后,会将磁盘的第一个扇区加载到内存的 0x7C00 的位置进行运行。
   此时, 系统处于实时模式,实时模式下,寻址的长度 16 位。 实时模式下,系统为内核的加载做准备,但准备好条件之后,
   系统将进入保护模式,保护模式运行在 32 bit 上,因此,两部分由于指令长度不同, GDB 调试的情况不同。
   因此,本节将介绍两种模式下,如何使用 GDB 调试内核。

   调试内核源码之前,请先准备好如下工具:
   gdbobjdump
   请确保源码树中顶层的 Makefile 中, DEBUG 选项已经打开
  1. vi */BiscuitOS/Makefile
  2. ---    DEBUG :=
  3. +++ DEBUG := 1
复制代码
1. 实时模式下内核调试
       系统在上电之后,会将启动磁盘的第一个扇区加载到内存 0x7c00 处开始运行, 所以开发者可以使用 gdb,在地址 0x7c00 处设置一个断点,
       然后从这个断点处开始调试。 具体步骤如下:
       1) 在 PC 机上准备两个终端,第一个终端作为 DEBUG HOST 使用,如下     
  1. cd */BiscuitOS/
  2. make
  3. make debug
复制代码
          运行上面的命令之后,该终端会进入等待状态,等待 DEBUG TARGET 的相应,如下图
           
       2) 在另一个终端作为 DEBUG TARGET 使用,如下:   
  1. cd */BiscuitOS/tools/build
  2. gdb .debug_bootsect
复制代码
          执行上面的命令之后,终端会进入 GDB 的 debug 模式, 在 debug 模式下,使用如下命令:
  1. (gdb) target remote :1234
  2. (gdb) b *0x7C00
  3. (gdb) c
  4. (gdb) d
  5. Delete all breakpoints? (y or n) y
  6. (gdb) ni
复制代码
          执行完上面的命令之后,终端就进入 debug 模式,你可以使用 gdb 命令对代码进行调试,如下图, 使用 “info reg” 打印寄存器的信息
           
           在实时模式进行单步调试应该使用 ni 命令,跳转到函数内部,应该使用 si
      3) 实时模式下如何调试中断
          在实时模式下,如果使用单步进行调试,如果遇到 int 中断,估计单步一直下去,永远跳不出这个坑,那么如何调试中断呢?我这里举个例子
          例如在 */BiscuitOS/boot/bootsect.s 中有一段关于中断的代码片段:
         
  1.     mov $0x0000, %dx      # head 0
  2.     mov $DEVICE_NR, %dl   # dirve 0
  3.     mov $0x0002, %cx   # sector 2, track 0
  4.     mov $0x0200, %bx   # address = 512, in INITSEG
  5.     .equ     AX, 0x200+SETUPLEN
  6.     mov     $AX, %ax   # service 2, nr of sectors
  7.     int $0x13          # read it
  8.     mov %ax, %ax
复制代码
         在上面的代码中,内核会通过调用 0x13 中断去读扇区的数据,判断一个中断是否成功,我们必须通过 EFLAGS 寄存器进行判断,
          但是如果使用单步进行调试的话,单步执行到 “int $0x13” 之后,一直无法跳出中断,为此我们可以使用如下的方法进行调试。
          > 首先在 “int $0x13” 之后添加一条汇编指令 “mov %ax, %ax”, 这条汇编指令没有任何实际意义,只是用于调试。
             添加完之后,重新编译系统            
  1. cd */BiscuitOS
  2. make clean
  3. make
  4. make debug
复制代码
        > 此时使用第三个终端,在终端中执行如下命令:            
  1. cd */BiscuitOS/tools/build
  2. objdump -x -s -S -dh .debug_bootsect
复制代码
           此时会将 .debug_bootsect 反汇编出来, .debug_bootsect 是 */BiscuitOS/boot/bootsect.s 的链接文件,
            然后我们在导出的信息中找到上面代码对应的反汇编代码,如下:
            
  1.   28:                 ba 00 00 b2 00               mov    $0xb20000,%edx
  2.                       mov $DEVICE_NR, %dl   # dirve 0
  3.                       mov $0x0002, %cx   # sector 2, track 0
  4.   2d:                 b9 02 00 bb 00               mov    $0xbb0002,%ecx
  5.                       mov $0x0200, %bx   # address = 512, in INITSEG
  6.   32:                 02 b8 04 02 cd 13            add    0x13cd0204(%eax),%bh
  7.                       .equ     AX, 0x200+SETUPLEN
  8.                       mov     $AX, %ax   # service 2, nr of sectors
  9.                       int $0x13          # read it
  10.                       mov %ax, %ax
  11.   38:                 89 c0                        mov    %eax,%eax
  12.                jnc ok_load_setup  # ok -continue
复制代码
           通过上面的信息,可知,我们之前添加的 “mov %ax, %ax” 对应的链接地址是 0x38
            由于下面的步骤需要对链接器和加载器有一定的认识,才知道为什么这么做,这里我不做过多的解释,大家参照我的方法做
            接着,通过系统原来我们知道,系统启动的过程中,将启动磁盘的第一个扇区加载到内存 0x7c00 处,
            根据 Linux 系统的实现逻辑,代码会将代码段加载到内存地址 0x90000 处,此时 CS 寄存器的值也是 0x9000
            因此,我们在打断点时候,段地的地址应该是: 0x90000 + 0x38 = 0x90038.
            此时在第二个终端中输入如下命令:   
  1. cd */BiscuitOS/tools/build/
  2. gdb .debug_bootsect
  3. (gdb) target remote :1234
  4. (gdb) b *0x90038
  5. (gdb) c
  6. (gdb) d
  7. Delete all breakpoints? (y or n) y
  8. (gdb) info reg
复制代码
            此时会将系统寄存器的值都答应出来,我们重点查看 eflags 的值,通过它的值来确定中断的执行是成功或失败。

  2. 保护模式下的调试
      系统在实时模式下初始化完毕之后,就要开始加载内核,保护模式下, gdb 的调试和实时模式下有不同之处,至于原因
      可以归咎与 GDT 段描述符表的机制,此时段寄存器不像实时模式下简单的做地址偏移,保护模式下,段寄存器做为段选择子,
      以此在 GDTLDT 选择描述符来进行代码跳转,因此,调试方法可以按如下步骤,(该调试时候除 boot/bootsect.s 和 boot/setup.s 之外的所有代码)
      1) 一个终端中作为 DEBUG HOST,输入如下命令
  1. cd */BiscuitOS
  2. make
  3. make debug
复制代码
    2) 另外一个终端作为 DEBUG TARGET, 输入如下命令   
  1. cd */BiscuitOS/tools/build
  2. gdb system
  3. (gdb) target remote :1234
  4. (gdb) b main
  5. (gdb) c
  6. (gdb) n
  7. (gdb) s
复制代码
        在保护模式下,可以使用 n 进行单步调试,进入函数内部可以使用 s
         更多 gdb 调试方法可以参考 gdbUser Manual
     3) 调试保护模式下的汇编代码
         我们可以采用和实时模式下的套路,使用 objdump 工具进行反汇编分析, 如下面的例子
         内核加载后执行的第一条命令是从物理地址 0 开始的,汇编代码如下:      
  1. pg_dir:
  2.     .globl startup_32

  3. startup_32:
  4.     movl $0x10, %eax  # 0x10, Global data segment.
  5.     mov %ax, %ds
  6.     mov %ax, %es
  7.     mov %ax, %fs
  8.     mov %ax, %gs
复制代码

         我们使用 objdump 工具,如下:  
  1. cd */BiscuitOS/tools/build
  2. objdump -x -s -S -dh system
复制代码
        从中我们可以获得:
  1. 00000000 <pg_dir>:

  2. pg_dir:
  3.               .globl startup_32

  4. startup_32:
  5.               movl $0x10, %eax  # 0x10, Global data segment.
  6.        0:         b8 10 00 00 00          mov    $0x10,%eax
  7.               mov %ax, %ds
  8.        5:          8e d8                   mov    %eax,%ds
  9.               mov %ax, %es
  10.        7:         8e c0                   mov    %eax,%es
  11.               mov %ax, %fs
  12.        9:         8e e0                   mov    %eax,%fs
复制代码
        由于保护模式下第一行代码是从物理地址开始,所以 startup_32 的断点地址为: 0x0 + 0,
         在 DEBUG TARGET 终端中输入如下命令:   
  1. cd */BiscuitOS/tools/build
  2. gdb system
  3. (gdb) target remote :1234
  4. (gdb) b *0x0
  5. (gdb) c
  6. (gdb) info reg
复制代码
        执行上面的代码,我们就可以单步调试保护模式的汇编代码。      
作者: Buddy_Zhang1    时间: 2017-05-21 15:54
本帖最后由 Buddy_Zhang1 于 2017-05-22 23:00 编辑

编码风格

    一个高效的项目应该是一个既灵活又遵循一定规则。 BiscuitOS 的开发目前已经支持编码风格控制机制。
    开发者在提交补丁之前,使用编码风格控制机制,可以轻松将自己的代码转换成符合 BiscuitOS 编码风格的代码。
    本节重点介绍如何在 BiscuitOS 中使用编码风格控制机制。

    在 BiscuitOS 0.0.2 版本之后加入 Linux 内核的编码风格控制机制,开发者同样也可以在 Linux 内核中使用。
    具体使用步骤如下:
    1. 安装必要的工具
  1. sudo apt-get install indent
复制代码
   2. 编写开发者自己的代码
    3. 提交补丁前的准备
        1) 删除掉文件中多余的空格和 TAB,开发者可以使用如下命令
  1. ./*/BiscuitOS/scripts/checkTB.sh file_name.c
复制代码
           checkTB.sh 脚本主要用来完成该任务, file_name.c 是要修改的文件,这个脚本使用于任何文件。
        2) 调整源码的风格为系统默认推荐的风格,开发者可以使用下面命令           
  1. ./*/BiscuitOS/scripts/Lindent file_name.c
复制代码
           Lindent 脚本会对 C 或头文件进行自动缩进处理。 file_name 是要修改文件的名字
        3) 经过上面两部,消除基本的编码问题,最后使用 Linux 提供的编码风格检测脚本            
  1. ./*/BiscuitOS/scripts/checkpatch.pl --no-tree -f file_name
复制代码
           该脚本会将源码中不符合规定的语句提示出来,并给出相应的修改建议,开发者在根据提示的建议修改完之后,
            再执行第一步和第二部,源码的代码风格就得到认证,开发者就可以提交您的补丁。
    4. 提交补丁         
作者: Buddy_Zhang1    时间: 2017-05-21 15:54
Reserved Page
作者: Buddy_Zhang1    时间: 2017-05-21 15:54
Reserved Page
作者: Buddy_Zhang1    时间: 2017-05-21 15:54
Reserved Page
作者: qianguozheng    时间: 2017-05-22 10:35
如何通过qemu运行呢
作者: Buddy_Zhang1    时间: 2017-05-22 12:29
回复 8# qianguozheng
  
    hi friends
        如何使用 qemu ,我已经在这个贴的开头详细介绍了,您可以参考一下 :-)




作者: Buddy_Zhang1    时间: 2017-05-26 08:56
添加 fork() 系统调用和基本的内存分配器,支持 get_free_page() 和 free_page() 例程
作者: qianguozheng    时间: 2017-05-28 16:15
没多少热度啊

作者: sditmaner    时间: 2017-05-29 11:17
谢谢分享 赞一个

作者: Buddy_Zhang1    时间: 2017-05-30 22:11
添加 string library
添加 .config & CONFIG_ 机制
添加测试代码机制
作者: nswcfd    时间: 2017-05-31 09:58
本帖最后由 nswcfd 于 2017-05-31 09:59 编辑

除了赞还能说啥呢 &#128077;&#128077;&#128077;赞赞赞
作者: Buddy_Zhang1    时间: 2017-06-01 12:29
回复 14# nswcfd

有兴趣的话一起开发

作者: Buddy_Zhang1    时间: 2017-06-03 20:14
添加 interrupt0 - interrupt5 测试程序

interrupt0 - divide zero
interrupt1 - debug
interrupt2 - NMI
interrupt3 - breakpoint
interrupt4 - overflow
interrupt5 - bound error
作者: Buddy_Zhang1    时间: 2017-06-04 16:18
kernel interrupt 0 - interrupt 45 测试程序

  1. /*
  2. * Test code for Interrupt table
  3. * Maintainer: Buddy <buddy.zhang@aliyun.com>
  4. *
  5. * Copyright (C) 2017 BiscuitOS
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */

  11. #include <linux/kernel.h>


  12. #ifdef CONFIG_TESTCODE

  13. /*
  14. * Test interrupt 0 - divide zero
  15. * The processor generates a type 0 interrupt whenever executing a divide
  16. * instruction—either 'div' (divide) or 'idiv' (integer divide)—results in
  17. * a quotient that is larger than the destination specified. The default
  18. * interrupt handler on Linux displays a Floating point exception message
  19. * and terminates the program.
  20. */
  21. void test_interrupt0_divide_error(void)
  22. {
  23. #ifndef CONFIG_SOFT_INTERRUPT
  24. #ifdef CONFIG_DIVIDE_ERROR0
  25.         int a;
  26.         int b = 0;
  27. #else
  28.         unsigned short _rax = 0xFFF;
  29.         unsigned short _res;
  30. #endif
  31.        
  32. #ifdef CONFIG_DIVIDE_ERROR0
  33.         /* case 0 */
  34.         /* divide error -> interrupt0 */
  35.         a = 3 / b;       
  36.         b = a;
  37. #else
  38.         /* case 1 */
  39.         /*
  40.          * EAX or AX can't store a rightful result-value
  41.          * eg, _rax / 0x01 = 0xFFF, and "AL" can't store result '0xFFF'.
  42.          */

  43.         __asm__("mov %1, %%ax\n\t"
  44.                         "movb $0x1, %%bl\n\t"
  45.                         "div %%bl\n\t"
  46.                         "movb %%al, %0"
  47.                         : "=m" (_res) : "m" (_rax));
  48.         printk("The result %#x\n", _res);
  49. #endif /* CONFIG_DIVIDE_ERROR0 */
  50. #else
  51.         __asm__("int $0");
  52. #endif /* CONFIG_SOFT_INTERRUPT */
  53. }

  54. /*
  55. * Test interrupt 1 - debug
  56. * Single-Step Interrupt Single-stepping is a useful debugging tool to
  57. * observe the behavior of a program instruction by instruction. To start
  58. * single-stepping, the trap flag (TF) bit in the flags register should
  59. * be set (i.e., TF = 1). When TF is set, the CPU automatically generates
  60. * a type 1 interrupt after executing each instruction. Some exceptions
  61. * do exist, but we do not worry about them here.
  62. * The interrupt handler for the type 1 interrupt can be used to display
  63. * relevant information about the state of the program. For example,
  64. * the contents of all registers could be displayed.
  65. * To end single stepping, the TF should be cleared. The instruction set,
  66. * however, does not have instructions to directly manipulate the TF bit.
  67. * Instead, we have to resort to an indirect means. You have to push flags
  68. * register using pushf and manipulate the TF bit and use popf to store this
  69. * value back in the flags register. Here is an example code fragment that
  70. * sets the trap flag.
  71. */
  72. void test_interrupt1_debug(void)
  73. {
  74. #ifndef CONFIG_SOFT_INTERRUPT
  75.         /* case 0 */
  76.         /*
  77.          * Set TF on EFLAGS will invoke interrupt 1 (debug).
  78.          */
  79.         __asm__("pushl %%eax\n\t"
  80.                         "pushf\n\t"
  81.                         "movl %%esp, %%eax\n\t"
  82.                         "orl $0x0100, (%%eax)\n\t" // set TF bit.
  83.                         "popf\n\t"
  84.                         "popl %%eax"
  85.                         ::);
  86. #else
  87.         __asm__("int $1");
  88. #endif
  89. }

  90. /*
  91. * Test Interrupt 3 - NMI
  92. * In computing, a non-maskable interrupt (NMI) is a hardware interrupt
  93. * that standard interrupt-masking techniques in the system cannot ignore.
  94. * It typically occurs to signal attention for non-recoverable hardware
  95. * errors. (Some NMIs may be masked, but only by using proprietary methods
  96. * specific to the particular NMI.)
  97. * An NMI is often used when response time is critical or when an interrupt
  98. * should never be disabled during normal system operation. Such uses
  99. * include reporting non-recoverable hardware errors, system debugging
  100. * and profiling, and handling of special cases like system resets.
  101. */
  102. void test_interrupt2_nmi(void)
  103. {
  104. #ifdef CONFIG_SOFT_INTERRUPT
  105.         __asm__("int $2");       
  106. #endif
  107. }

  108. /*
  109. * Test Interrupt 3 - int3
  110. * Breakpoint Interrupt If you have used a debugger, which you should
  111. * have by now, you already know the usefulness of inserting breakpoints
  112. * while debugging a program. The type 3 interrupt is dedicated to the
  113. * breakpoint processing. This type of interrupt can be generated by
  114. * using the special single-byte form of 'int3' (opcode CCH). Using the
  115. * 'int3' instruction automatically causes the assembler to encode the
  116. * instruction into the single-byte version. Note that the standard encoding
  117. * for the 'int' instruction is two bytes long.
  118. * Inserting a breakpoint in a program involves replacing the program
  119. * code byte by CCH while saving the program byte for later restoration
  120. * to remove the breakpoint. The standard 2-byte version of 'int3' can
  121. * cause problems in certain situations, as there are instructions that
  122. * require only a single byte to encode.
  123. */
  124. void test_interrupt3_int3(void)
  125. {
  126. #ifndef CONFIG_SOFT_INTERRUPT
  127.         /* general interrupt entry */
  128.         __asm__("pushl %%eax\n\t"
  129.                         "pushf\n\t"
  130.                         "movl %%esp, %%eax\n\t"
  131.                         "orl $0x0100, (%%eax)\n\t"
  132.                         "popf\n\t"
  133.                         "popl %%eax"
  134.                         ::);       
  135. #else
  136.         __asm__("int $3");
  137. #endif
  138. }

  139. /*
  140. * Test Interrupt 4 - overflow error
  141. * The type 4 interrupt is dedicated to handle overflow conditions.
  142. * There are two ways by which a type 4 interrupt can be generated:
  143. * either by 'int4' or by 'into' . Like the breakpoint interrupt,
  144. * 'into' requires only one byte to encode, as it does not require
  145. * the specification of the interrupt type number as part of the
  146. * instruction. Unlike 'int4', which unconditionally generates a
  147. * type 4 interrupt, 'into' generates a type 4 interrupt only if the
  148. * overflow flag is set. We do not normally use 'into' , as the
  149. * overflow condition is usually detected and processed by using
  150. * the conditional jump instructions 'jo' and 'jno'.
  151. */
  152. void test_interrupt4_overflow(void)
  153. {
  154. #ifndef CONFIG_SOFT_INTERRUPT
  155.         /* case 0 */
  156.         /*
  157.          * 'OF' set and call 'into'
  158.          */
  159.         __asm__("pushl %%ebx\n\t"
  160.                         "movb $0x7f, %%bl\n\t"
  161.                         "addb $10, %%bl\n\t"
  162.                         "into\n\t"
  163.                         "popl %%ebx"
  164.                         ::);
  165. #else
  166.         /* case 1 */
  167.         __asm__("int $4");
  168. #endif
  169. }

  170. /*
  171. * Test Interrupt 5 - Bound error
  172. * Determines if the first operand (array index) is within the bounds of
  173. * an array specified the second operand (bounds operand). The array
  174. * index is a signed integer located in a register. The bounds operand
  175. * is a memory location that contains a pair of signed doubleword-integers
  176. * (when the operand-size attribute is 32) or a pair of signed word-integers
  177. * (when the operand-size attribute is 16). The first doubleword (or word)
  178. * is the lower bound of the array and the second doubleword (or word)
  179. * is the upper bound of the array. The array index must be greater than
  180. * or equal to the lower bound and less than or equal to the upper bound
  181. * plus the operand size in bytes.
  182. * If the index is not within bounds, a BOUND range exceeded exception
  183. * (#BR) is signaled. When this exception is generated, the saved return
  184. * instruction pointer points to the BOUND instruction.
  185. * The bounds limit data structure (two words or doublewords containing
  186. * the lower and upper limits of the array) is usually placed just before
  187. * the array itself, making the limits addressable via a constant offset
  188. * from the beginning of the array. Because the address of the array already
  189. * will be present in a register, this practice avoids extra bus cycles
  190. * to obtain the effective address of the array bounds.
  191. */
  192. void test_interrupt5_bound(void)
  193. {
  194. #ifndef CONFIG_SOFT_INTERRUPT
  195.         int buffer[2] = { 0, 6 };
  196.         int index = 7; /* safe value: 0, 1, 2, 3, 4, 5, 6 */

  197.         /* case 0 */
  198.         /*
  199.          * Upper = buffer[1]
  200.          * lower = buffer[0]
  201.          * if index < lower || index > upper
  202.          * Invoke Bound interrupt.
  203.          */
  204.         __asm__("lea %0, %%edx\n\t"
  205.                         "movl %1, %%eax\n\t"
  206.                         "boundl %%eax, (%%edx)"
  207.                         :: "m" (buffer), "m" (index));
  208. #else
  209.         __asm__("int $5");
  210. #endif
  211. }

  212. /*
  213. * Test Interrupt 6 - Invalid operand
  214. */
  215. void test_interrupt6_invalid_op(void)
  216. {
  217. #ifdef CONFIG_SOFT_INTERRUPT
  218.         __asm__("int $6");
  219. #endif
  220. }

  221. /*
  222. * Test Interrupt 7 - device not available.
  223. * Not used - 20170603
  224. */
  225. void test_interrupt7_device_not_available(void)
  226. {
  227. #ifdef CONFIG_SOFT_INTERRUPT
  228.         __asm__("int $7");
  229. #endif
  230. }

  231. /*
  232. * Test Interrupt 8 - double fault
  233. * On the x86 architecture, a double fault exception occurs if the
  234. * processor encounters a problem while trying to service a pending
  235. * interrupt or exception. An example situation when a double fault
  236. * would occur is when an interrupt is triggered but the segment in
  237. * which the interrupt handler resides is invalid. If the processor
  238. * encounters a problem when calling the double fault handler, a triple
  239. * fault is generated and the processor shuts down.
  240. * As double faults can only happen due to kernel bugs, they are rarely
  241. * caused by user space programs in a modern protected mode operating
  242. * system, unless the program somehow gains kernel access (some viruses
  243. * and also some low-level DOS programs). Other processors like PowerPC
  244. * or SPARC generally save state to predefined and reserved machine
  245. * registers. A double fault will then be a situation where another
  246. * exception happens while the processor is still using the contents of
  247. * these registers to process the exception. SPARC processors have four
  248. * levels of such registers, i.e. they have a 4-window register system.
  249. */
  250. void test_interrupt8_double_fault(void)
  251. {
  252. #ifdef CONFIG_SOFT_INTERRUPT
  253.         __asm__("int $8");
  254. #endif
  255. }

  256. /*
  257. * Test Interrupt 9 - Coprocessor segment overrun
  258. */
  259. void test_interrupt9_coprocessor_segment_overrun(void)
  260. {
  261. #ifdef CONFIG_SOFT_INTERRUPT
  262.         __asm__("int $9");
  263. #endif
  264. }

  265. /*
  266. * Test Interrupt 10 - invalid TSS segment
  267. */
  268. void test_interrupt10_invalid_TSS(void)
  269. {
  270. #ifdef CONFIG_SOFT_INTERRUPT
  271.         __asm__("int $10");
  272. #endif
  273. }

  274. /*
  275. * Test Interrupt 11 - Segment not present.
  276. */
  277. void test_interrupt11_segment_not_present(void)
  278. {
  279. #ifdef CONFIG_SOFT_INTERRUPT
  280.         __asm__("int $11");
  281. #endif
  282. }

  283. /*
  284. * Test Interrupt 12 - Stack segment
  285. */
  286. void test_interrupt12_task_segment(void)
  287. {
  288. #ifdef CONFIG_SOFT_INTERRUPT
  289.         __asm__("int $12");
  290. #endif
  291. }

  292. /*
  293. * Test Interrupt 13 - General protection
  294. */
  295. void test_interrupt13_general_protection(void)
  296. {
  297. #ifdef CONFIG_SOFT_INTERRUPT
  298.         __asm__("int $13");
  299. #endif
  300. }

  301. /*
  302. * Test Interrupt 14 - page fault
  303. * Cannot use
  304. */
  305. void test_interrupt14_page_fault(void)
  306. {
  307. #ifdef CONFIG_SOFT_INTERRUPT
  308.         __asm__("int $14");
  309. #endif
  310. }

  311. /*
  312. * Test Interrupt 15 - Intel reserved
  313. */
  314. void test_interrupt15_intel_reserved(void)
  315. {
  316. #ifdef CONFIG_SOFT_INTERRUPT
  317.         __asm__("int $15");
  318. #endif
  319. }

  320. /*
  321. * Test Interrupt 16 - Coprocessor error
  322. * Cannot use
  323. */
  324. void test_interrupt16_coprocessor_error(void)
  325. {
  326. #ifdef CONFIG_SOFT_INTERRUPT
  327.         __asm__("int $16");       
  328. #endif
  329. }

  330. /*
  331. * Test Interrupt 17-48 - Intel Reserved
  332. */
  333. void test_interrupt17_47_Reserved(void)
  334. {
  335. #ifdef CONFIG_SOFT_INTERRUPT
  336.         //__asm__("int $17");
  337.         __asm__("int $47");
  338. #endif
  339. }

  340. /*
  341. * Test Interrupt 39 - parallel interrupt
  342. */
  343. void test_interrupt39_parallel_interrupt(void)
  344. {
  345. #ifdef CONFIG_SOFT_INTERRUPT
  346.         __asm__("int $39");
  347. #endif
  348. }

  349. /*
  350. * Test Interrupt 45 - irq13
  351. * Cannot use
  352. */
  353. void test_interrupt45_irq13(void)
  354. {
  355. #ifdef CONFIG_SOFT_INTERRUPT
  356.         __asm__("int $45");
  357. #endif
  358. }
  359. #endif
复制代码

作者: lmarsin    时间: 2017-06-20 18:06
支持下楼主
作者: anenbupt    时间: 2017-06-20 22:29
工作没时间了。要是还在大学一定搞起。。。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2