zoukankan      html  css  js  c++  java
  • ExpOS:一个从0开始的中文OS

    Windows下编译、运行演示:
    1.到sf.linuxfourm.net下载编译工具包, ExpOS编译工具包
    2.解压缩到c:根目录, 改名为djgpp.
    3.下载一个0.0.7.2, 双击build目录的osgo.bat.
    4.在控制台下输入make就可以编译.
    5.编译完成后build目录生成一个 flp文件, 把vmware的a驱设置为这个文件, 就可以使用vmware启动.




    开发进展(按时间顺序整理):

    03-05-03 21:47
    source insight 是不支持At&T的汇编解析的.给linux的源码阅读造
    成了一定的障碍.
    这个clf 文件是为source insight 写的coustom language
    script file. 导入到source insight 然后简单配置就可以解析at&t的
    汇编语法了(i386).

    虽然有所缺陷, 但是暂时够用.

    这为再ExpOS中使用gas奠定了基础.
     

    03-05-14 10:07
    发布了Windows下的版本0.0.7.2


    03-12-08 19:43
    好久没有作些什么了, 但是还没有停滞. dgjpp 已经影响到了写更好的makefile, 下一版推出在linux下的, 强大的makefile支持. 采用搜索方式工作的makefile, 当你添加一个c文件,将无需维护任何makefile! 在最大限度上减少工程维护的工作量. 比<<永远的unix>>哈少的Gnu make 指南的那个例子还要牛啊, 还是感谢哈少以及原作者给予我们的灵感和方法.


    03-12-08 21:35
    在linux下开发的版本已经发布----0.0.7.6
    makefile支持!
    只要不添加目录:
    make dep
    make
    就可以编译, 更换编译目录,增加.s, .c文件无需维护makefile.

    03-12-11 12:49
    -------提供简单的硬盘驱动
    硬盘启动, fs,大概都需要一个硬盘驱动.

    -------提供一个 keshell
    kernel embed shell. 提供调试内核, 查看内核状态用的keshell命令, 直接嵌入内核. 将来会支持在keshell下直接调用内核函数,查看内核变量的功能,方便内核调试和研究.

    03-12-15 20:14
    1.ekshell Demo 版本: 简单的命令书写方式, 支持参数传递,拥有几个demo命令.
    使用 man 获取帮助信息
    2. Demo版硬盘驱动发布.
    3. 加快显示速度
    声明: 使用本系统,稍有不慎就会造成硬盘数据破坏, 后果自负.(建议使用虚拟机运行本系统!!)

    2003.12.15
    终于知道在中断处理函数中为什么不能保存恢复fs,gs 了:
    这两个寄存器没有初始化(head.asm), pop 时候会引起异常.
    2003.12.17
    尽量将汇编编码移入c 文件, 最大程度上减少汇编代码
    将idt, _lidt 从entry.asm 移入i386.c .
    2003.12.18
    将irq_table 从 entry.asm 移入i386.c.
    2003.12.19
    制作c 文件内的中断门处理例程. 见i8259.c
    2003.12.20
    把entry.asm 换成 entry.c ,减少.s 文件.
    2003.12.20
    trap 试验 -- 修改context 中的eip, 见entry.c 代码. 就是0.0.7.8beta

    03-12-22 14:25
    1.调整并增强中断和异常处理.
    2. entry.asm 换成 entry.c, 尽量不使用asm文件,减少汇编码.
    3. 搭建中断和异常处理框架,包括传递完整的pt_reg和error code.
    4. 处理几个常见异常,给出demo代码.

    2003.12.23
    增加tread.c(dump_regs,dump_stack) ptrace.h.
    2003.12.26
    增加fixup 支持,trap.c, fault.c. 简单page falut , div0 处理.

    03-12-29 19:12
    1. 映射所有可管理内存
    2.简化linux的页面管理(内含buddy)算法,弄来 一用(当然不用自己coding buddy)

    04-01-14 19:20
    支持VESA VBE2.0 设备信息获取
    使用命令 vesa vbemode


    2004.4.9 多任务
    1. 初始化tss, tss 描述符
    2. 加载tr
    3. 初始化init 进程堆栈

    task 结构,tss结构定义编译通过.
    ---> 8k 边界--> +----------+ | 堆栈 |
    | ... |
    | task |
    +----------+
    基本属于linux 的设计.

    2004.4.24 补齐cr0-4 的简单说明(i386.h i386.c)
    2004.4.26 添加tss dump 命令

    2004.5.6 增加内核线程支持。

    1. 首先企图使用linux 的方法,搞出一个init任务: 首先定义初始化一个init 任务结构, tss, init thread (宏 INIT_TSS, INIT_TASK ,INIT_THREAD), 然后写swap, 最后利用 linux 的_switch_to 宏进行切换. 问题是这样走的弯路远, 只想迅速做出一个原型. 而linux的方法(必须) 通过系统调用完成又不直观-- 比如一个进程都没有的时候linux 的
    fork如何进行的复制(init 的创建也是通过fork).

    2. 所以采用另外的方法, 直接创建线程: 构造一个调用栈pt_regs (见函数 create_task create_thread switch_to schedu)
    首先, 系统对中断和异常的调用栈进行了统一, 无论何时任务的内核 堆栈都是和pt_regs 一致的, 这为统一操作创造了有利条件. create_task create_thread 创建了这个系统堆栈结构使新的任务从中断返回时 执行线程指定的函数----entry. create_thread 还指定了从switch_to 宏返回地址为ret_from_shedu (entry.c), 所以新创建 的任务直接从entry.c " 恢复"执行环境执行任务入口函数----entry.

    3. 有几个问题在写代码的时候要注意 1) create_thread 要初始化完整pt_regs, 包括xds,xss,xgs等, 否则 entry.c iret 的时候 就会异常. 2) create_thread 特别要注意pt_regs 的变量eflags 的设置, 现在置为2 , 这是cpu 复位以后的初始状态, 但是这个值是禁止中断的, 导致切换到此
    任务后cpu中断关闭, 从而失去系统的动力. ========这个bug还没有 改正, 以留做纪念. init_b 调用sti(), 就是这个目的.========= 这个问题 没有被注意到之前, 现象很奇怪, init_b init_t 在任务入口调用一下
    kprintf 系统才可以工作, 百思不解. 后来发现是因为其中有对sti 的调用.

    4. init_b 值得分析一下 { static unsigned long jiold = 0;
    //jiold=jiffies;
    //kprintf("");
    sti();
    while(1)
    {
    //if((jiffies-jiold)>240)
    {
    //putchar('b');
    char_color = char_color++%16;
    barrier(); ------------------------------------>如果没有这句话, 导致gcc 将修改以后的 变量char_color 存入一个寄存器没有真正写入内存,
    后果是此任务没有达到目的: init_b 对文本颜色的 修改没有影响到任务init_t.(jiffies 工作正常,因为jiffies 是
    一个volatile 类型的变量.
    // jiold = jiffies;
    }
    }
    }

    5. schedu 中if(current!=_kernel) p = _kernel; /* 调度kernel 运行 */ 说明如下: 系统将main (main.c)也设计为一个隐含的任务, 称为_kernel 其堆栈 在编译期间定为8k对齐(见head.asm 的变量_k_stack, _k_top) 并且 无需初始化其struct task_struct 和 pt_regs. _kernel 任务只在 switch_to 宏中使用其thread 结构 , 而pt_regs 在中断发生时 已经自动构造完成.


    2204.5.14 在中断中加入几个logo 作为演示.
    2004.9.7 添加一个统计schedu 嵌套深度的代码. 并验证是否在每一个任务中都可以 使用schedu. 结果是, 在_kernel 任务中无法使用此函数进行任务调度. 经测试, 对switch_to 的调用加上保

    2004.9.8
    试着将时钟频率提高到1000Hz, 然后expsh 停止 响应。
    2004-9-9
    支持 expshell 的历史功能 (very simply
    2004.9.10
    只要不在 timer 中断中,schedu 可以在中断处理中调用:

    2004.9.18
    VESA 调试中, vmware 就是8位色不能使用, 而我恰恰用了这个模式。

    一个是没有仔细看模式属性,另一个是一开始vbemode 只探测了30个模式,漏掉了32bits 的几个模式。

    04-09-18 16:27
    开始移植linux 的frame buffer . 所有移植的文件都在 include /fb (已经被废弃)
    release 0.0.8.5 --- VESA DEMO+switch_to加强
    1. VESA Linear Frame Buffer 调试成功 早就说要使用更高的分辨率。。。。。
    2. 调试中遇到的几个问题: 2003.9.15 综述: schedu 可以任意使用,但不能滥用。 1.) 为何timer 中断中不可以调用schedu 而kbd 就可以呢? 2.) 为何纪录下来的schedu 嵌套次数不低于3 ? 3.) 为什么switch_to 要锁中断, 而linux 则不用? 4.) gcc 使用寄存器有约定的,所以switch_to 切换的时候不用保存所有的regs. 但是这个约定是什么? 到底必须保存那些寄存器?
    3. 2004.9.13 92 )的问题查明了。vmware 编译的时候时间对不上。 ./up 没有起作用。 总之是编译的问题。在锁定switch_to 的时候, 可以随意使用schedu. 为何必须锁定,原因再查。

    2004.9.19 vesa lfb
     字符显示。准备做一个简单的接口界面将内核的显示输出同显示设备分开。

    要支持汉字,内核简单搞个驱动,本来可以以后作模块的。

    2004.9.27 vga lfb
    vga lfb 模拟驱动. mode13是fb的,而mode12只能模拟成lfb,
    速度比较慢.
    fill_rect 的变量vram 不小心定成了unsigned *
    结果工作一直不正常,费了不少力气.

    2004.9.29
    把vga12模拟成fb, 只使用其中的一个pixel plane, 速度就快了不少.
    并且可以和vesa的操作统一起来.

    目前只支持vga12, vesa (800x600) 32 bpp.

    可以作些其他的了.



    2004.10.10
    将显示模式改为自动探测. 现在只支持32bpp 800x?.
    如果启动的时候按住ctrl键,则强制使用vga 模式启动. 否则使用自动探测值. 

    2004.10.11
    简单看看fat32 文件系统和partition.

    2004.10.14
    决定将setup程序用as写, 一步步来,慢慢都换成as, 这样方便写,
    可以和C 共享头文件.
    detectmem.asm -> ram.S ok!

    2004.10.17
    加上周六周日阅读FAT32 的文档, 搞定大硬盘读文件不正常的问题.是因为没有使用BPB.SectorPerCluster
    计算cluster 的位置.
    为了支持超过8.3GB 的硬盘, 采用了LBA 模式访问.
    修正读文件错误, 以BPB 的cluster 大小为准. 

    2004.10.22 发布kernel 0.0.9.0
    读fat32 文件系统问题少多了. 也搞了个inode. 完全参考文档FAT: General Overview of On-Disk
    Format.
    inode对应文件或者目录, super 是本文件系统的基本信息. ref linux, 但是不是完全相同.

    04-10-22 13:56
    release 0.0.9.0 surport LFB,FAT32
    1. vesa/vga LFB surported
    2. fat32 surported(read), surport harddisk < 137G
    (看到lingix有fat32, 有个简单的参考, linux的太多了. 大家应该多多交流)
    3.在根目录放一个24bpp的bmp文件,比如 x.bmp , 使用命令bmf x 浏览此文件(<2M). 

    2004.10.23
    看看vm86 模式. 先把ptrace.h 的寄存器pt_regs 加上vm86 特有的寄存器.

    2004.10.24
    尝试切换到vm86模式(vm86.c ), 但是总是异常导致vmware复位.
    找不到原因. 所以考虑使用bochdeg进行调试.

    使用vga启动系统, 去掉文件系统(boch不知持vesa2.0,
    文件系统有缺陷), 就可以使用boch进行调试了. make debug
    可以获取系统的汇编码, 可以找到do_vm86_int 的地址. 使用 break
    设上断点.(help "break" 可以获取帮助).
    使用si 1 进行单步跟踪, 发现确实能够进入vm86 模式, 但是执行第一句
    代码就不行了. boch 输出为:

    00027036668p[CPU ] >>PANIC<< exception(): 3rd (14) exception with no resolution

    00027036668i[SYS ] Last time is 1098519385
    00027036668i[CPU ] v8086 mode
    00027036668i[CPU ] CS.d_b = 16 bit
    00027036668i[CPU ] SS.d_b = 16 bit
    00027036668i[CPU ] | EAX=00004f02 EBX=0000c121 ECX=00000000 EDX=c0155f8c
    00027036668i[CPU ] | ESP=00008000 EBP=00000000 ESI=c01031f2 EDI=c1ffbfb4
    00027036668i[CPU ] | IOPL=3 NV UP DI PL NZ NA PO NC
    00027036668i[CPU ] | SEG selector base limit G D
    00027036668i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
    00027036668i[CPU ] | DS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027036668i[CPU ] | ES:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027036668i[CPU ] | FS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027036668i[CPU ] | GS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027036668i[CPU ] | SS:9000( 0002| 0| 3) 00090000 0000ffff 0 0
    00027036668i[CPU ] | CS:c000( 0001| 0| 3) 000c0000 0000ffff 0 0
    00027036668i[CPU ] | EIP=000000e6 (000000e6)
    00027036668i[CPU ] | CR0=0xe0000019 CR1=0x00000000 CR2=0xfffffffc
    00027036668i[CPU ] | CR3=0x00150000 CR4=0x00000000
    00027036668i[CPU ] >> cd
    00027036668i[CPU ] >> 6d
    00027036668i[CPU ] >> : int 6d
    00027036668i[CTRL ] quit_sim called

    信息显示在vm86 模式下执行int 6d 就完蛋 (int 0x10). 后来换成执行
    int 0x13, 还是不行. 第一句指令是 jmp xxxx. 心理比较奇怪. 怎么这个都
    不行?
    goole >>PANIC<< exception(): 3rd (14) exception with no resolution 发现是triple fault的意思
    奥, page table 是kernel的, 终于找到原因所在了, 哈哈.

    临时做了一个函数map_ram_user 临时映射0 - 1M 为user 模式, 结果变成:
    00027166041i[CPU ] allow_io(): CPL > IOPL: no IO bitmap defined #GP(0)
    00027166041p[CPU ] >>PANIC<< exception(): 3rd (14) exception with no resolution
    00027166041i[SYS ] Last time is 1098670943
    00027166041i[CPU ] v8086 mode
    00027166041i[CPU ] CS.d_b = 16 bit
    00027166041i[CPU ] SS.d_b = 16 bit
    00027166041i[CPU ] | EAX=00000469 EBX=00007fbe ECX=00000010 EDX=c0150402
    00027166041i[CPU ] | ESP=00007f92 EBP=00007f96 ESI=c010338e EDI=c1ffbfb4
    00027166041i[CPU ] | IOPL=3 NV UP DI PL ZR NA PE NC
    00027166041i[CPU ] | SEG selector base limit G D
    00027166041i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
    00027166041i[CPU ] | DS:8000( 0002| 0| 3) 00080000 0000ffff 0 0
    00027166041i[CPU ] | ES:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027166041i[CPU ] | FS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027166041i[CPU ] | GS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00027166041i[CPU ] | SS:8000( 0002| 0| 3) 00080000 0000ffff 0 0
    00027166041i[CPU ] | CS:f000( 0001| 0| 3) 000f0000 0000ffff 0 0
    00027166041i[CPU ] | EIP=0000045d (0000045d)
    00027166041i[CPU ] | CR0=0xe0000019 CR1=0x00000000 CR2=0xfffffffc
    00027166041i[CPU ] | CR3=0x00150000 CR4=0x00000000
    00027166041i[CPU ] >> ee
    00027166041i[CPU ] >> : out DX, AL
    00027166041i[CTRL ] quit_sim called

    虽然还是triple fault , 但是已经是一个io 错误了, IOPL: no IO bitmap defined #GP(0).
    再单步跟踪可以看到可以执行很多命令了.

    2004.10.24
    设置tss 的io bitmap, 不过还是调用vm86 int 10h 的时候无法正常运行, 直接triple fault.

    查ia32的手册第三卷, 说当IOPL < 3 的时候vm86下的中断,如现在的int 6d, 被重定向到
    #GP. 将iopl设置为0, 仍然是triple fault. 按说应该回到PMODE 然后出现一个#GP异常的.

    google, thinking , 啊...., 会到PMODE 应该设置好tss.esp0,
    tss.ss0. set it. 仍然triple fault! ...........
    不过看boch调试信息, 已经回到PMODE , 并且已经到trap_service_routine.

    然而有大量的如下信息:

    00033821545e[CPU ] seg->selector.value = 0000
    00033821566e[CPU ] seg = DS
    00033821566e[CPU ] seg->selector.value = 0000
    00033821587e[CPU ] seg = DS
    00033821587e[CPU ] seg->selector.value = 0000
    00033821608e[CPU ] seg = DS
    00033821608e[CPU ] seg->selector.value = 0000
    00033821629e[CPU ] seg = DS
    00033821629e[CPU ] seg->selector.value = 0000
    00033821650e[CPU ] seg = DS
    00033821650e[CPU ] seg->selector.value = 0000
    00033821671e[CPU ] seg = DS
    00033821671e[CPU ] seg->selector.value = 0000
    00033821692e[CPU ] seg = DS
    00033821692e[CPU ] seg->selector.value = 0000
    00033821713e[CPU ] seg = DS
    00033821713e[CPU ] seg->selector.value = 0000
    00033821734e[CPU ] seg = DS
    00033821734e[CPU ] seg->selector.value = 0000
    00033821734p[CPU ] >>PANIC<< exception(): 3rd (11) exception with no
    resolution

    00033821734i[SYS ] Last time is 1098685740
    00033821734i[CPU ] protected mode
    00033821734i[CPU ] CS.d_b = 32 bit
    00033821734i[CPU ] SS.d_b = 32 bit
    00033821734i[CPU ] | EAX=00004f02 EBX=00000008 ECX=00000010 EDX=c0155f9c
    00033821734i[CPU ] | ESP=c015f698 EBP=c015f6a0 ESI=c0103456 EDI=c1ffbfb4
    00033821734i[CPU ] | IOPL=0 NV UP DI NG NZ NA PE CY
    00033821734i[CPU ] | SEG selector base limit G D
    00033821734i[CPU ] | SEG sltr(index|ti|rpl) base limit G D
    00033821734i[CPU ] | DS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00033821734i[CPU ] | ES:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00033821734i[CPU ] | FS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00033821734i[CPU ] | GS:0000( 0002| 0| 3) 00000000 0000ffff 0 0
    00033821734i[CPU ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
    00033821734i[CPU ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
    00033821734i[CPU ] | EIP=c0101c91 (c0101c91)
    00033821734i[CPU ] | CR0=0xe0000019 CR1=0x00000000 CR2=0x00000000
    00033821734i[CPU ] | CR3=0x00150000 CR4=0x00000000
    00033821734i[CPU ] >> 8b
    00033821734i[CPU ] >> 14
    00033821734i[CPU ] >> 9d
    00033821734i[CPU ] >> a0
    00033821734i[CPU ] >> f2
    00033821734i[CPU ] >> 15
    00033821734i[CPU ] >> c0
    00033821734i[CPU ] >> : mov EDX, DS:[c015f2a0 + EBX<<2]
    00033821734i[CTRL ] quit_sim called

    看来esp0 设置是有问题的, 在任务切换或者异常过程中有没有考虑到的地方.

    2004.10.24
    00033821545e[CPU ] seg->selector.value = 0000
    00033821566e[CPU ] seg = DS
    当然猜想ds没有设置对, 参考了linux, ia32,
    发现应该在会到内核的时候重新设置ds, es 等选择子.
    因为没有用户态的线程所以从来没有考虑这种事情. 在SAVE_ALL
    中恢复ds, es.

    看起来正常了, 可以执行do_vm86_int 并返回到内核了.

    切换到demo 任务的时候可能还不正常, 并且demo 任务无法返回到32bit 模式.

    go on .................

    2004.10.24
    vm86 先停一下. 想到一个注意.
    所写的代码最好方便移植. 把一个可移植单位的头文件和c 文件放到一
    起移植应该就方便多了. 但是如此以来头文件的包含极为不爽了, 所以:

    1. 在include 下面设置一个叫h的子目录, 在编译的时候将所有这种模块的
    头文件拷贝到这个目录下.

    2. 改动了一下makefile 实现了这个功能. 即tagert cph

    3. 将make debug 的输出放到了debug 目录下, bochsrc 也放到这个目录

    4. 实现cph的时候为了让cp 总有一个文件可以拷贝, 在scripts下有个.h.h 的文件.

    2004.10.25
    改为按住crtl 键启动vbe, 否则只启动vga, 这样调试方便.

    2004.10.27
    vm86 下执行 int 0x10中断, 不断emulate io 指令, 但是没有成功的切换显示模.
    现在调用vm86模式中断的任务还不能返回32bits 模式.

    需要搞一下.

    为了使调用do_vm86_int 的任务可以返回32bit 模式, 先看了看linux的实现. linux
    下返回用户模式的指定函数,不准备使用这种方式. 希望一种能够象任务切换
    的方式. 于是加入如下代码:

    #define switch_to_vm86(regs,current) do {\
    asm __volatile__( \
    "pushfl \n\t" \
    "pushl %%esi\n\t" \
    "pushl %%edi\n\t" \
    "pushl %%ebp\n\t" \
    "pushal \n\t" \
    /*当前任务从这里结束 */ \
    "movl %%esp,%0\n\t" /* save ret ESP */ \
    "movl $1f,%1\n\t" /* save ret EIP (ret from vm86)*/ \
    "movl %2,%%esp\n\t" /*switch to vm86 regs frame */\
    "jmp start_vm86_iret \n\t" /* "ret" to vm86 */\
    /* vm_i32_reload return address*/\
    "1:\n\t" \
    "popal \n\t" \
    "popl %%ebp\n\t" \
    "popl %%edi\n\t" \
    "popl %%esi\n\t" \
    "popfl" \
    :"=m" (current->thread.vmretesp),"=m" (current->thread.vmreteip) \
    :"r" (regs)); \
    }while(0);

    /*same as enty.c iret stack frame*/
    __inline_asm__
    ".global start_vm86_iret \n\t"
    ".align 4 \n\t"
    "start_vm86_iret: \n\t"
    RESTORE_ALL
    /* bypass err code */
    " addl $4, %esp \n\t"
    " iret \n\t");

    void FASTCALL(vm_i32_reload());

    void vm_i32_reload()
    {

    }
    #define ret_to_32(current) do {\
    asm __volatile__( \
    "movl %0, %%esp\n\t" /* restore ret ESP */ \
    "pushl %1\n\t" /* restore ret EIP (ret from vm86)*/ \
    "jmp vm_i32_reload\n" /* return to 32bits */ \
    /*NEVER run here*/\
    ::"m" (current->thread.vmretesp),"m" (current->thread.vmreteip) \
    ); \
    }while(0);

    void return_to_32bit()
    {
    kprintf("Return to 32bit esp %08x, eip %08x \n", v_cr->thread.vmretesp,v_cr->thread.vmreteip);
    ret_to_32(current);
    BUG();
    }

    可惜总是在32bit 模式trap fault. 仔细分析了一下. 在切换到vm86模式的时候
    堆栈如下:
    ____________________________
    | vm86 iret stack frame |
    +------------------------------------+
    | 32 bits frame when reach |
    | to macro switch_to_vm86 |
    +-------------------------------------+ <---- switch_to_vm86
    | pushf |
    | pusha |
    | |
    +------------------------------------+ <---- ret_to_32 frame

    trap fault 原因之一应该是tss->esp0:
    +------------------------------------+ <------ tss->esp0
    | vm86 iret stack frame |
    +------------------------------------+
    | 32 bits frame when reach |
    | to macro switch_to_vm86 |
    +-------------------------------------+ <---- switch_to_vm86 frame
    | pushf |
    | pusha |
    | |
    +------------------------------------+ <---- ret_to_32 frame

    这样的设置将破坏到达switch_to_vm86 macro 之前的32bits frame 以及ret_to_32 的stack frame .
    当然就异常百出, 什么非法指令什么的.
    后来参考了linux 将tss->esp0 修改成如下样子
    +------------------------------------+
    | vm86 iret stack frame |
    +------------------------------------+ <------ tss->esp0
    | 32 bits frame when reach |
    | to macro switch_to_vm86 |
    +-------------------------------------+ <---- switch_to_vm86 frame
    | pushf |
    | pusha |
    | |
    +------------------------------------+ <---- ret_to_32 frame

    当时没有想明白, 这样还是破坏了一些stack frame.
    一着急干脆另起一个堆栈:
    char xst[1024];, 将tss-> esp0 指向这个数组顶部.
    结果仍旧triple fault. 打印出来的信息显示在返回32bits的时候在task 结构中保存的
    vmretesp , vmreteip全都是0.

    ...................

    对了, current 宏依赖于tss->esp0!!!!
    哼哼, 再搞一个变量,!!!!
    在iret 到vm86的时候记录一下current
    tss->esp0 = xst+512; //&vstack->VM86_TSS_ESP0;
    // dump_ptreg(regs);

    v_cr = current;
    返回32bit的时候使用v_cr.
    void return_to_32bit()
    {
    kprintf("Return to 32bit esp %08x, eip %08x \n", v_cr->thread.vmretesp,v_cr->thread.vmreteip);
    ret_to_32(v_cr);
    BUG();
    }

    now, 可以进而vm86, 执行中断, 然后再返回到32bits 模式了. 不过,返回的时机没有
    仔细安排,中断也没有起到任何作用, vm86模式下还有非法指令等错误. 这些以后
    再说吧.

    框架和机制已经可以了.

    2004.10.29
    整理代码, 内存分配的全局变量隐藏.

    2004.11.1
    移植slab.
    add file percpu.h(only none smp). add /kernel/timer/jiffers.h

    发生一件事情, 无论如何无法编译通过, 提示:

    two types specified in one empty declare (一个typdef 或者struct 定义)

    short , long , unsigned invalid for jiffers (或者其他变量)


    2004.11.3
    准备搞定这个编译问题. 很久没有遇到过编译问题了.

    没有思路, 错误处前后皆无问题. google , 有人怀疑这个是gcc
    的一个bug. ???

    郁闷!, 所以整理头文件包含关系, 搞了很久, 还是有问题.

    今天把slab.c 一点一点的去掉看看是那里的问题.
    将代码去完了, 还是不行.

    最后才怀疑是不是某个头文件?
    排除了一下, 发现是sem.h. 进去一看,
    struct semaphore{
    spinlock_t spin;
    int x; /* temp for irq dis haha!!!*/
    }


    少了一个分号. !!!!!!!!!!!!!


    2004.11.5
    休息了两天, 今天把代码整理了一通. 移动头文件, 重命名头文件等.
    include目录少了几个子目录.

    记得一开始, 在virtural pc 下面可以使用vesa, 后来怎么都搞不定.现在居然
    又可以了...?

    2004.11.8
    又过了一个星期天. 把driver/onsole 改名为console, 当初还不了解phone target,
    现在好了.

    2004.11.10
    分离出一个e820.c , make it clear&clean.
    if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW))
    BUG(); dead here. because origin SLAB_LEVEL_MASK == SLAB_KERNEL, but here ,not equal.


    2004.11.16
    开始研究一下floppy driver. 先读一下data sheet, 虽然不是pc-at标准但是
    确符合at标准.
    intel 的82077A, NEC 8272A.
    阅读datasheet,将寄存器地址用宏记录下来,并给出寄存器的描述.
    做完寄存器描述后准备阅读programming Considerations, 同时记录到floppy.c.
    然后就可以编码了.

    为了使用DMA, 顺便研究一下8273.

    2004.11.17
    DMA 研究了一下, 成果记录于dma.h 备忘.
    demo 了一下floppy reading. 发现fdc_out 总是报告有数据无法写入fdc. 经过
    仔细查找, 是一个垃圾命令没有读完所有的result , 导致fdc 状态处于0xd0,
    即有数据需要输出.

    阅读linux的floppy, 同时剥离繁杂处理,实现一个pure hardware driver.

    感想: 难道在制造 一个容易阅读和移植的仓库?当你若干岁月以后
    回头来看, 仍然能够区分这里只是硬件要求的逻辑, 还能在代码中
    找到相关寄存器简单的描述, 能够找到当初参考的文档和代码.
    最后, 可以轻易的找到并复用实现功能的这几个文件, 还有一个
    接口的简单指导.
    物理驱动仅仅是一个最小实现, 在特定的os, 也许应该对应写一个
    设备驱动, 处理和os的接口?

    2004.11.17 20:28.
    floppy driver 确实需要一个结构保存状态, 因为几个寄存器只写, 如重要的
    dor(digital out register).
    Seat down writing os, or go home?

    2004.11.18
    minix floppy driver 比较适合做一个demo.


  • 相关阅读:
    LeetCode 476 数字的补数
    MySQL与Java 整型数据映射
    TINYINT[M]、INT[M]和BIGINT[M]中M值的意义
    git删除本地分支
    git 初始化项目、创建本地分支、本地分支与远程分支关联
    Java 当文件不存在时自动创建文件目录和文件
    Java 在文件末尾追加内容
    免密自动登陆SAPGui
    SAP GUI770下载及安装
    notepad++格式化json,无法安装json插件
  • 原文地址:https://www.cnblogs.com/huqingyu/p/105349.html
Copyright © 2011-2022 走看看