免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 29537 | 回复: 26
打印 上一主题 下一主题

mouseOS 项目 -- x64 体系的实验品(10.13 更新 -- 实现新的分页管理) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-28 23:56 |只看该作者 |倒序浏览
目   录

--------------------------------------------------
1、序言
2、编写 loader
3、loader & OS 初始化的搬运大法
4、开启保护模式
5、增加 interrupt/ecxption handler
6、可运行的最小规模的 OS
7、x64os 的系统数据结构
8、进入 protected mode 前的 16 位代码
9、protected mode 入口代码
10、OS 核心代码
11、开启分页机制(paging)
12、开启 long mode, 让 kernel 运行在 64 bit 模式
13、加入定时中断机制,为以后的任务切换做准备
14、增加系统调用,并使用 int 30 进行系统调用
15、使用 sysenter/sysexit 进行系统调用
16、将用 sysenter/sysexit 去掉,改用 syscall/sysret 进行系统调用
17、内存管理1 --- 检测系统内存数量
18、内存管理2 --- 地址空间的规划
19、内存管理3 --- 实现地址空间的规划
----------------------------------------------------------------



项目正式更名为 mouseOS

完整的源代码和磁盘映象 mouse.img 见附件
这个磁盘映象可以用 vmware 等虚拟机运行,或写入软盘,放入真实机器运行



更新列表
7.5     遭遇 #DF 异常
7.18 解决 #DF 异常问题 和加入 TSS
7.19   加入分页模式(paging)
7.29 开启 long mode,kernel 运行在 64 bit 模式下
8.9     加入定时中断
8.27 增加一个系统调用
8.30 将 sysenter/sysexit 改为 syscall/sysret 进行系统调用
9.6  加入检测系统的内存数量代码
9.20 更新分页机制
9.20 项目更名为 mosue 或者 mouse OS,mouseOS

10.13  我已经花时间全部重写了整个代码,mouseOS 的整个结构都起了很大的变化

我将不再在这里发布更新情况!!!

有兴趣的朋友,请访问我个人的网站:
http://www.mouseos.com

(网站现在在建设中...)  请见谅 ^_^







下图是,在 bochs 调试运行时的截图:

kernel 运行在 0xffff8000_40000000 开始的 kernel 空间里
user  代码运行在 0x00001000_40000000 开始的 user code 空间里


[ 本帖最后由 mik 于 2009-10-14 00:56 编辑 ]

mouseOS.jpg (71.78 KB, 下载次数: 363)

mouseOS.jpg

mouseOS.rar

12.38 KB, 下载次数: 490

评分

参与人数 1可用积分 +30 收起 理由
prolj + 30 期待详细教程,让我们照葫芦画瓢

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2009-06-29 00:08 |只看该作者
1、序言



一、目的
  搞这个 x64os 实验的目的是为了更好地深入了解 x64 体系,从实际的项目入手,加深对 x64 体系的了解



二、工具

1、nasm 汇编器
  说实在,我很讨厌 nasm 的语法,但是没办法,目前来说,还是 nasm 较为好用。只能去接受和摸索它。
  本来,我打算用自己写的 a64 来作为开发工具,但是 a64 是几年前的作品,还没有完善。现在没心思去写它了。


2、bochs 模拟器
  bochs 可以说是仿真器,方便调试。在目前为止,还是它这方面最为强大,虽然很慢。


3、hex 编辑器
  随便找一个 hex 的编辑器,用来改写目标程序



三、计划
  逐步做成一个可运行的学习品,从 loader 开始到最后的 os shell

论坛徽章:
0
3 [报告]
发表于 2009-06-29 00:34 |只看该作者
2、x64os 的 loader



一、x64os 结构

  将 x64os 安装在 floppy 盘上,现在主要分三个部分:loader、lib 和 kernel。


1、loader 在 floppy 盘上的第 1 个扇区,启动后被加载到 0x7c00 区域。

2、lib 在 floppy 盘上的第 2 个扇区开始,共 2 个扇区大小,主要是 x64os 启动时用到的一些例程

3、kernel 在 floopy 盘上的第 4 个扇区开始。  




二、 loader 代码


下面是 x64os 的 loader 代码。



%include "x64os.inc"

        bits 16
        
        org 0x7c00                 ; 被加载到 0x7c00
        
start:
        mov ax, cs
        mov es, ax
        mov ss, ax
        mov sp, 0x7c00
        

/* 以下这部分是 lib */

        mov ax, 0202h             ; 读 2 个扇区
        mov bx, 0xa000            ; 读到 0xa000 处
        mov cx, 02h                ; 从第 2 个扇区开始,0-cylinder
        mov dx, 00h                ; 0-header,0-floppy
        int 13h
        
        jc failure


/* 以下部分是 kernel */

        mov ax, 0202h
        mov bx, 0xb000            ; 读到 0xb000 处
        mov cx, 04h          ; 从第 4 扇区开始
        mov dx, 00h
        int 13h                  
        
        jc failure
        
        
      
        mov si, message             ; 显示 "x64 os" 信息
        call far [libseg+puts]     ; 调用 lib 例程 puts()
        
failure:
        jmp $                        ; 死循环
        
message:
        db 'x64 os ... ...'
        
times 510-($-$$) db 0
        
        dw 0xaa55



上面这个 loader 代码只是简单地调用了 lib 里的 puts() 例程,显示信息,然后死机。


但是,这里用两个 loader 的常用手法:

1、从磁盘上加载 lib 组件
2、从磁盘上加载 kernel 组件。



三、 lib 组件

代码如下:


        org 0xa000
        
fun_table:
        dw putc
        dw 0
        dw puts
        dw 0
        dw 0
        
putc:
        mov ah,0eh
        xor bh,bh
        int 10h
        ret
        

puts:
        lodsb
        test al,al
        jz puts_done
        call putc
        jmp puts
puts_done:
        ret


在这个组件里,面目只有 2 个例程,就是 putc 和 puts,分别打印一个字符,和打印一串字符。


fun_table:
  可以算是例程导出表格,供其它模块使用,这里只是做了一个变通,因为 nasm 不支持同时编译两个源文件,没办法,只好使用这种手法来实现其它模块调用。


  

四、 kernel 组件

  kernel 组件现在是空的,还没实现。


五、头文件 x64os.inc

下面是 x64os.inc 的代码

kernelseg equ 0xb000
libseg equ 0xa000

putc equ 0
puts equ 4


x64os.inc 现在只定义了几个常量而已:libseg 定义在 0xa000 处,kernelseg 定义在 0xb000 处。

putc 和 puts 是 lib 组件导出的例程指针值。

论坛徽章:
0
4 [报告]
发表于 2009-07-02 00:25 |只看该作者
3、loader 的搬运大法


  OS 在 loader 或 初始化阶段都会经历从这里搬到那里,然后再跳过去执行的过程。

  在这里,我在 kernel 代码里作一个演示



上面的 kernel 组件是空的,现在我在里面加些代码:



kernel.asm 的代码如下:

        bits 16
        
        org 0x6000
        
        jmp code16_entry

null16        dq 0
               
code_sel        dw 0xffff               ; limit
                        dw 0                     ; base 15 ~ 0
                        db 0                ; base 23 ~ 16
                        db 0x9a                ; 1 00 11010 : p=1,c=0,r=1
                        db 0xc0                ; G=1,D=1,base=00
                        db 0
               
data_sel        dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xc0
                        db 0
                        

gdt:
gdt_limit dw $-$$-3
gdt_base dd null16
               

code16_entry:

        
        push 0x1000
        pop es
        cld
        xor edi,edi
        lea esi,[next]
        mov ecx, 512*2
    sub ecx,esi
        add ecx,0x6000
        rep movsb                            ; 将 next 后面的代码搬运到 0x10000 处

        push 0x1000                       ; 跳到 0x10000 处继续执行下去
        push 0
        retf
        

; 下面代码转为 protected mode

next:

        lgdt [gdt]
        
        mov eax,cr0
        or eax,1
        mov cr0,eax
        
        mov eax, 0x10000
        add eax, code32_entry - next
        mov [code32_sel], eax
        
        db 0x66
        jmp far [code32_sel]                  ; jmp into proected mode ... ...
        
code32_sel   dd 0
                        dw 0x08
                        
        bits 32
code32_entry:
        mov ax,0x10
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov esp, 0x7b000000
        
        mov edi, (80*20)*2
        add edi, 0xb8000
        
        lea esi,[message]
        
        mov ah,0fh
ll:
        lodsb
        test al, al
        jz done
        stosw
        jmp ll

done:
        jmp $
        

message db "... protected mode... ..."



这个 kernel.asm 加了一点点代码,只是作一个演示目的,

1、kernel 组件被 loader 加载到 0x6000 处,
2、loader 跳到 0x6000 处执行 kernel 组件的代码
3、kernel 组件代码中,将 next 后面的执行自已复制到 0x10000 处
4、跳到 0x10000 处继续执行
5、跳到 0x10000 后,prcessor 从 real mode 转化 protected mode
6、在 proected mode 模式下,显示信息“..proected mode .....“ 
7、然后,死循环
--------------------------------------------------------------

这里的转到 protected mode 意义不大,只是作为一种演示。



现在,loader、lib、kernel 都加了一点代码。

论坛徽章:
0
5 [报告]
发表于 2009-07-06 00:37 |只看该作者
4、开启保护模式


%include "x64os.inc"


        org 0x6000
        
        jmp code16_entry

null                dq 0
               
code                dw 0xffff               ; limit
                        dw 0                     ; base 15 ~ 0
                        db 0                      ; base 23 ~ 16
                        db 0x9a                 ; 1 00 11010 : p=1,c=0,r=1
                        db 0xcf                  ; G=1,D=1,base=00
                        db 0
               
data                dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0
                        
gdt:
gdt_limit dw $-$$-3
gdt_base dd null

display_postion dd 0xb8000

        bits 16
        
code16_entry:

        lgdt [gdt]                                  ; 临时加载 gdt
        
        mov eax,cr0
        or eax,1
        mov cr0,eax
        
        jmp 0x08:code32_entry              ; 跳入 32 位保护模式
        
        bits 32

code32_entry:        

        mov ax,0x10
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov esp, 0x20000

        cld
        mov edi,0x10000
        lea esi,[next]
        mov ecx, 512*2
    sub ecx,esi
        add ecx,0x6000
        rep movsb

        push 0x10000
        ret

next:
        call init_gdt
        lgdt [gdt32]                              ; 重新加载 gdt
        call init_idt
        lidt [idt32]                                ; 加载 idt
        
        mov eax,0
        div al                                        ; fault- exception: divide 0


        
done:

        jmp $
        

message db "... protected mode... ..."
exception0 db " exception: divide by zero..."


init_gdt:
        mov dword [gdt32_entry+NULL_SEL],0                        ; NULL - descriptor
        mov dword [gdt32_entry+NULL_SEL+4], 0                        ; NULL - descriptor
        
        mov dword [gdt32_entry+CODE0_SEL], CODE0_DESC0
        mov dword [gdt32_entry+CODE0_SEL+4], CODE0_DESC1
        
        mov dword [gdt32_entry+CODE1_SEL], CODE1_DESC0
        mov dword [gdt32_entry+CODE1_SEL+4], CODE1_DESC1
        
        mov dword [gdt32_entry+CODE2_SEL], CODE2_DESC0
        mov dword [gdt32_entry+CODE2_SEL+4], CODE2_DESC1
        
        mov dword [gdt32_entry+CODE3_SEL], CODE3_DESC0
        mov dword [gdt32_entry+CODE3_SEL+4], CODE3_DESC1
        
        mov dword [gdt32_entry+DATA0_SEL], DATA0_DESC0
        mov dword [gdt32_entry+DATA0_SEL+4], DATA0_DESC1
        
        mov dword [gdt32_entry+DATA1_SEL], DATA1_DESC0
        mov dword [gdt32_entry+DATA1_SEL+4], DATA1_DESC1
        
        mov dword [gdt32_entry+DATA2_SEL], DATA2_DESC0
        mov dword [gdt32_entry+DATA2_SEL+4], DATA2_DESC1
        
        mov dword [gdt32_entry+DATA3_SEL], DATA3_DESC0
        mov dword [gdt32_entry+DATA3_SEL+4], DATA3_DESC1

        mov dword [gdt32_entry+KERNEL_CODE], KERNEL_CODE0
        mov dword [gdt32_entry+KERNEL_CODE+4], KERNEL_CODE1

        mov dword [gdt32_entry+USER_CODE], USER_CODE0
        mov dword [gdt32_entry+USER_CODE+4], USER_CODE1
        
        mov dword [gdt32_entry+KERNEL_DATA], KERNEL_DATA0
        mov dword [gdt32_entry+KERNEL_DATA+4], KERNEL_DATA1

        mov dword [gdt32_entry+USER_DATA], USER_DATA0
        mov dword [gdt32_entry+USER_DATA+4], USER_DATA1        
        
        
        mov word [gdt32], 0xffff                                ; limit
        mov dword [gdt32+2],gdt32_entry                        ; base address
        
        ret
        

init_idt:
        lea edx, [exception_div0]
        mov word [idt32_entry+0], dx                   ; offset 15 ~ 0
        mov word [idt32_entry+2], KERNEL_CODE        ; selector
        mov word [idt32_entry+4], 0x8e00
        shr edx,16
        mov word [idt32_entry+6], dx
        
        mov word [idt32], 0xff
        mov dword [idt32+2], idt32_entry
        ret
        

        

exception_div0:
        push exception0
        push 1
        push 25
        call display_message

        iret

        
display_message:
        push ebp
        mov ebp,esp
        mov edi,[ebp+0x8]              ; row
        mov ecx, [ebp+0x0c]                ; cow
        mov esi, [ebp+0x10]                ; message
        
        imul edi,0x80
        add edi, dword [display_postion]
        
        xor eax,eax
        mov ah,0x0f
l1:
        lodsb
        test al,al
        jz l2
        mov word [edi + ecx*2], ax
        inc ecx
        jmp l1
        
l2:
        mov esp, ebp
        pop ebp
        
        ret 0x0c


1、在 init_gdt 过程里,重新定义了 gdt 里面的 descriptor, 定义了多个权限级别的 code segment descriptor,目的用来使用段式内管理,而不是现在 OS 常用的平坦模式。(此举学习之用)

2、重新加载 gdt 表格

3、在 init_idt 过程里,只定义了 0 号异常,即:除 0 异常。

4、定义了一个 0 号异常的 handler: exception_div0(),用来 除0 的后续处理

5、在 exception_div0 handler 里,只是简单地显示一条信息,就返回。

[ 本帖最后由 mik 于 2009-7-6 00:45 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2009-07-06 00:55 |只看该作者
5、增加 interrupt/exception handler



exception_div0:
        push exception0
        push 1
        push 25
        call display_message

        iret


这个就是简单的除 0 的处理例程,只是调用 display_message 例程来显示一条信息而已


init_idt:
        lea edx, [exception_div0]
        mov word [idt32_entry+0], dx                   ; offset 15 ~ 0
        mov word [idt32_entry+2], KERNEL_CODE        ; selector
        mov word [idt32_entry+4], 0x8e00
        shr edx,16
        mov word [idt32_entry+6], dx
        
        mov word [idt32], 0xff
        mov dword [idt32+2], idt32_entry
        ret

这是 idt 的设置,只设置了一个 interrupt gate descriptor,就是 0 号异常的 interrupt 向量

将 exception_div0 用来作它的 handler


        lidt [idt32]
        
        mov eax,0
        div al                                        ; fault- exception: divide 0

加载 idt

然后,有意执行 div 0,从而产生 0 号异常

结果是,跳入到 exception_div0 这个例程里,显示一条信息: “exception: divide by zero..."


注意:
   由于 div 0 异常是属于 fault 类型的异常,所以,中断返回到出现异常的指令上,因此,这里会不断地执行 div al,然后不断地跳入 exception_div0 中

   若在 exception_div0 中断例程里,重新将 eax 的值置为非 0 的话,processor 会继续往下执行。

论坛徽章:
0
7 [报告]
发表于 2009-07-18 15:41 |只看该作者
6、可运行的最小规模的 OS


在这个版本里,修正了一些bug,加入了 TSS,和较完整的 idt

看看 kernel.asm 的源码:

--------------------------------------------------------------------------------------------


%include "x64os.inc"


        org 0x6000
        
        jmp code16_entry


gdt32:
null                dq 0

; cs:        limit = fffff*10000+ffff (4g)
;                base = 0x00000000
;                DPL=0,G=1,D=1,C=0,P=1,r=1
cs0                   dw 0xffff               ; limit
                        dw 0                     ; base 15 ~ 0
                        db 0                      ; base 23 ~ 16
                        db 0x9a                 ; 1 00 11010 : p=1,c=0,r=1
                        db 0xcf                  ; G=1,D=1,base=00
                        db 0

cs0_sel                equ 0x08                        
                        
; cs1: limit = 7ffff*10000+ffff (2g)
;      base = 0x80000000
;      DPL  = 1
;      G = 1, D = 1,C = 0               
cs1                    dw 0xffff
                        dw 0
                        db 0
                        db 0xba
                        db 0xc7
                        db 0x80
                        
cs1_sel                equ cs0_sel + 8
                        
; cs2: limit = 3ffff*10000+ffff (1g)
;                base = 0xd0000000
;                DPL = 2
;                G=1,D=1,C=0,P=1,R=1
cs2                   dw 0xffff
                        dw 0
                        db 0
                        db 0xda
                        db 0xc3
                        db 0xd0

cs2_sel                equ        cs1_sel + 8
                        
; cs3:        limit = 7ffff*10000+ffff (2g)
;                base = 0x00000000
;                DPL = 3
;                G=1,D=1,C=0,P=1,R=1        
cs3                    dw 0xffff
                        dw 0
                        db 0
                        db 0xfa
                        db 0xc7
                        db 0

cs3_sel                equ cs2_sel + 8
                        
; ds0:        limit = fffff*1000+ffff (4g)
;                base = 0x00000000
;                DPL = 0
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds0                   dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

ds0_sel                equ cs3_sel + 8
        
; ds1:        limit = 7ffff*10000+ffff (2g)
;                 base = 0x80000000                        
;                DPL = 1
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds1                   dw 0xffff
                        dw 0
                        db 0
                        db 0xb2
                        db 0xc7
                        db 0x80

ds1_sel                equ ds0_sel + 8
        
; ds2:        limit = 3ffff*10000+ffff (1g)
;                base = 0xd0000000
;                DPL=2
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds2                    dw 0xffff
                        dw 0
                        db 0
                        db 0xd2
                        db 0xc3
                        db 0xd0

ds2_sel                equ ds1_sel + 8
               
; ds3:        limit = 7ffff*10000+ffff(2g)
;                base = 0x00000000
;                DPL=3
;                G=1,D/B=1,P=1,E=0,W=1,A=1                        
ds3                    dw 0xffff
                        dw 0
                        db 0
                        db 0xf2
                        db 0xc7
                        db 0
                        

ds3_sel                equ ds2_sel + 8
                        
; kernel_cs:        limit = fffff*1000+ffff (4g)
;                                base = 0x00000000
;                                DPL = 0
;                                G=1,D=1,C=0,R=1,P=1,A=1
kernel_cs        dw 0xffff
                        dw 0
                        db 0
                        db 0x9a
                        db 0xcf
                        db 0

kernel_cs_sel        equ ds3_sel + 8
                        
; user_cs:        limit = fffff*1000+ffff (4g)
;                        base = 0x00000000
;                        DPL = 3
;                        G=1,D=1,C=0,R=1,P=1
user_cs                dw 0xffff
                        dw 0
                        db 0
                        db 0xfa
                        db 0xcf
                        db 0               
               

user_cs_sel                equ kernel_cs_sel + 8
               
ss0                    dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

ss0_sel                equ user_cs_sel + 8
                        
; kernel_ds:        limit = fffff*1000+ffff (4g)
;                                base = 0x00000000
;                                DPL = 0
;                                G=1,D/B=1,P=1,E=0,W=1,A=1
kernel_ds        dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

kernel_ds_sel        equ ss0_sel + 8
                        
; user_ds:        limit = fffff*10000+ffff(4g)
;                        base = 0x00000000
;                        DPL=3
;                        G=1,D/B=1,P=1,E=0,W=1,A=1                        
user_ds                dw 0xffff
                        dw 0
                        db 0
                        db 0xf2
                        db 0xcf
                        db 0
                        
user_ds_sel        equ kernel_ds_sel + 8

                        
tss_selector:
tss1                dw 0x67                                ; limit               
                        dw tss32                        ; base15-0
                        db 0                                ; base23-16
                        db 0xe9                                ; DPL=3,type=32-bit available tss
                        db 0                                ; G=0
                        db 0                                ; base31-24
                        
tss1_sel        equ user_ds_sel + 8
                        
ldt_selector:
ldt1                dw 0                                ; limit
                        dw 0                                ; base15-0
                        db 0                                ; base23-16
                        db 0x82                                ; DPL=0,type=ldt
                        db 0x80                                ; G=1
                        db 0                                ; base31-24

gdt32_end:                        
        
ldt1_sel        equ tss1_sel + 8        


;-----------------------------------------------------------
idt32:
_DE                        dw exception_DE                                 ; offset15-0
                        dw kernel_cs_sel                                ; selector
                        db 0                                ; resever
                        db 0x8e                                ; DPL=0,type=interrup-gate
                        dw 0                                ; offset31-16
_DB                        dq 0
_NMI                dq 0
_BP                        dq 0
_OF                        dq 0
_BR                        dq 0
_UD                        dq 0
_NM                        dq 0
_DF                        dw exception_DF
                        dw kernel_cs_sel
                        db 0
                        db 0x8e
                        dw 0

                        dq 0                                ; reserved
_TS                        dq 0
_NP                        dq 0
_SS                        dq 0
_GP                        dw exception_GP
                        dw kernel_cs_sel
                        db 0
                        db 0x8e
                        dw 0
                        dq 0                                ; reserved
_MF                        dq 0               
_AC                        dq 0
_MC                        dq 0
_XF                        dq 0
times 10        dq 0                                ; reserved
_SX                        dq 0               

idt32_end:


;-----------------------------------------------------------
tss32:
                        dd 0                        ; link=0
                        dd 0x3fff0000        ; esp0
                        dd ds0_sel                 ; ss0 = 0x0028, ds0-selector
                        dd 0x2fff0000        ; esp1
                        dd ds1_sel                ; ss1
                        dd 0x1fff000        ; esp2
                        dd ds2_sel                ; ss2
                        dd 0                        ; cr3
                        dd 0                        ; eip
                        dd 0                        ; eflags
                        dd 0                        ; eax
                        dd 0                        ; ecx
                        dd 0                        ; edx
                        dd 0                        ; ebx
                        dd 0                         ; esp
                        dd 0                        ; ebp
                        dd 0                         ; esi
                        dd 0                         ; edi
                        dd 0x00000058        ; es:   kernel_ds
                        dd 0x00000048        ; cs:   kernel_cs
                        dd 0x00000058        ; ss:   kernel_ds
                        dd 0x00000058        ; ds:   kernel_ds                        
                        dd 0                        ; fs
                        dd 0                        ; gs
                        dd 0                        ; ldt-selector
                        db 0                        ; T=0
                        db tss32_end-tss32
tss32_end:                        
                                


                                
gdt:
gdt_limit dw gdt32_end-gdt32
gdt_base dd gdt32

idt:
idt_limit dw idt32_end-idt32
idt_base  dd idt32


cursor dd 0xb8000
        
code16_entry:
        mov ax,cs
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov sp,0x6000
        
        cli

        lidt [idt]
        lgdt [gdt]                        ; load from ds:[gdt] into gdtr


        mov eax,cr0
        or eax,1

        mov cr0,eax


        jmp dword kernel_cs_sel:code32_entry
        
        bits 32

code32_entry:        
        mov ax,ds0_sel
        mov ds,ax
        mov es,ax
        mov ax,ss0_sel
        mov ss,ax
        mov esp, 0x10000


        sti


        lea esi,[message]
        push esi
        push dword 0
        push dword 0
        call display_message
        
        cld
        mov edi,0x10000
        lea esi,[next]
        mov ecx, kernel_end-next
        rep movsb


        push dword 0x10000
        ret

        
; 0x10000:
next:
;        call init_tss
        mov ax, tss1_sel
        ltr ax

        mov eax,0
        div al        
        mov ax, ds3_sel|0x03
        mov ds, ax
        mov es, ax
        
        push (ds3_sel) | 0x03                ; stack 3
        push 0x1fff0000                                ; stack 3
        push (user_cs_sel)|0x03
        push os_main
        retf
        
done:

        jmp $
        

message db "... protected mode... ...",0
exception0 db " exception: divide by zero...",0



os_main:
        jmp os_next
os_msg db 'Shell > ',0
os_next:
        call clear
        push os_msg
        push 0
        push 0
        call display_message
        
        jmp $






init_gdt:
        
        ret
        

init_idt:
        lea edx, [exception_DE]
        mov word [_DE+0], dx                                ; offset15-0
        mov word [_DE+2], kernel_cs_sel                ; selector: kernel_cs
        shr edx,16
        mov word [_DE+6], dx                                ; offset31-16
        
        
        lea edx, [exception_GP]
        mov word [_GP+0], dx                                ; offset15-0
        mov word [_GP+2], kernel_cs_sel                ; selector: kernel_cs
        shr edx,16
        mov word [_GP+6], dx                                ; offset31-16        
        ret
        
init_tss:
        
        lea edx, [tss32]
        mov word [tss1+0], 0x68                        ; limit
        mov word [tss1+2], dx
        shr edx, 16
        mov byte [tss1+4], dl
        mov byte [tss1+7], dh
        
        mov ax, tss1_sel                ; tss1 selector
        ltr ax

        ret
        

;------------------ exception handler --------------------------
exception_DE:
        push ebp
        mov  ebp,esp
        mov edi, [ebp+4]                ; eip
        mov esi, [ebp+8]                ; cs

        jmp DE_next
DE_msg1 db 'exception instruction at 0x',0
DE_msg2 db 'continue at 0x',0
        
DE_next:
        push DE_msg1
        push 1
        push 40
        call display_message

        push edi
        push eax
        push 40
        call print_hex
        
        mov ax,1
        
        mov esp, ebp
        pop ebp
        
        iret

;---------- #GP exception handler ----------------        
exception_GP:
        iret
        
        
;----------- #TS exception handler ---------------        
exception_TS:
        iret
        
        
;------------ #DF exception handler ---------------        
exception_DF:
        iret
        

        
;---------------------- kernel routune --------------------
clear:
        mov edi, 0xb8000
        mov ecx, 40*80
        xor eax,eax
rep stosw
        ret

; print_hex(row, column, value)
print_hex:
        push ebp
        mov ebp,esp
        push edi
        push esi
        push ebx
        
        mov edi, [ebp+8]                ; row
        mov esi, [ebp+0xc]                ; column
        mov ebx, [ebp+0x10]                ; value
        mov edx, ebx

        imul edi, 80                        ; row * 80
        add edi, 0xb8000
        mov ecx, 32
        jmp pl
hex_table db '0123456789ABCDEF',0
        
pl:        
        mov ebx, edx
        sub ecx,4

        shr ebx, cl
        and ebx,0x0f
        mov al, [ebx+hex_table]
        mov ah,0x0f
        mov word [edi+esi*2], ax
        inc esi
        cmp ecx, 0
        jz pd
        jmp pl

pd:
        mov eax, esi
        
        pop ebx
        pop esi
        pop edi

        mov esp,ebp
        pop ebp
        ret 12


; printf()
printf:
        ret
        
        
; display_message(row, column, message)        
display_message:
        push ebp
        mov ebp,esp
        push edi
        push ecx
        push esi
        
        mov edi,[ebp+0x8]       ; row
        mov ecx, [ebp+0x0c]                ; column
        mov esi, [ebp+0x10]                ; message
        
        imul edi,80
        add edi,0xb8000
        
        xor eax,eax
        mov ah,0x0f
l1:
        lodsb
        test al,al
        jz l2
        mov word [edi + ecx*2], ax
        inc ecx
        jmp l1
        
l2:
        mov eax, ecx
        pop esi
        pop ecx
        pop edi
        mov esp, ebp
        pop ebp
        
        ret 0x0c
        
kernel_end:

论坛徽章:
0
8 [报告]
发表于 2009-07-18 16:03 |只看该作者
7、x64os 的系统数据结构


下面的数据结构只是临时性的,并非最终OS 的数据结构

gdt32:
null                dq 0

; cs:        limit = fffff*10000+ffff (4g)
;                base = 0x00000000
;                DPL=0,G=1,D=1,C=0,P=1,r=1
cs0                   dw 0xffff               ; limit
                        dw 0                     ; base 15 ~ 0
                        db 0                      ; base 23 ~ 16
                        db 0x9a                 ; 1 00 11010 : p=1,c=0,r=1
                        db 0xcf                  ; G=1,D=1,base=00
                        db 0

cs0_sel                equ 0x08                        
                        
; cs1: limit = 7ffff*10000+ffff (2g)
;      base = 0x80000000
;      DPL  = 1
;      G = 1, D = 1,C = 0               
cs1                    dw 0xffff
                        dw 0
                        db 0
                        db 0xba
                        db 0xc7
                        db 0x80
                        
cs1_sel                equ cs0_sel + 8
                        
; cs2: limit = 3ffff*10000+ffff (1g)
;                base = 0xd0000000
;                DPL = 2
;                G=1,D=1,C=0,P=1,R=1
cs2                   dw 0xffff
                        dw 0
                        db 0
                        db 0xda
                        db 0xc3
                        db 0xd0

cs2_sel                equ        cs1_sel + 8
                        
; cs3:        limit = 7ffff*10000+ffff (2g)
;                base = 0x00000000
;                DPL = 3
;                G=1,D=1,C=0,P=1,R=1        
cs3                    dw 0xffff
                        dw 0
                        db 0
                        db 0xfa
                        db 0xc7
                        db 0

cs3_sel                equ cs2_sel + 8
                        
; ds0:        limit = fffff*1000+ffff (4g)
;                base = 0x00000000
;                DPL = 0
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds0                   dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

ds0_sel                equ cs3_sel + 8
        
; ds1:        limit = 7ffff*10000+ffff (2g)
;                 base = 0x80000000                        
;                DPL = 1
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds1                   dw 0xffff
                        dw 0
                        db 0
                        db 0xb2
                        db 0xc7
                        db 0x80

ds1_sel                equ ds0_sel + 8
        
; ds2:        limit = 3ffff*10000+ffff (1g)
;                base = 0xd0000000
;                DPL=2
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds2                    dw 0xffff
                        dw 0
                        db 0
                        db 0xd2
                        db 0xc3
                        db 0xd0

ds2_sel                equ ds1_sel + 8
               
; ds3:        limit = 7ffff*10000+ffff(2g)
;                base = 0x00000000
;                DPL=3
;                G=1,D/B=1,P=1,E=0,W=1,A=1                        
ds3                    dw 0xffff
                        dw 0
                        db 0
                        db 0xf2
                        db 0xc7
                        db 0
                        

ds3_sel                equ ds2_sel + 8
                        
; kernel_cs:        limit = fffff*1000+ffff (4g)
;                                base = 0x00000000
;                                DPL = 0
;                                G=1,D=1,C=0,R=1,P=1,A=1
kernel_cs        dw 0xffff
                        dw 0
                        db 0
                        db 0x9a
                        db 0xcf
                        db 0

kernel_cs_sel        equ ds3_sel + 8
                        
; user_cs:        limit = fffff*1000+ffff (4g)
;                        base = 0x00000000
;                        DPL = 3
;                        G=1,D=1,C=0,R=1,P=1
user_cs                dw 0xffff
                        dw 0
                        db 0
                        db 0xfa
                        db 0xcf
                        db 0               
               

user_cs_sel                equ kernel_cs_sel + 8
               
ss0                    dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

ss0_sel                equ user_cs_sel + 8
                        
; kernel_ds:        limit = fffff*1000+ffff (4g)
;                                base = 0x00000000
;                                DPL = 0
;                                G=1,D/B=1,P=1,E=0,W=1,A=1
kernel_ds        dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

kernel_ds_sel        equ ss0_sel + 8
                        
; user_ds:        limit = fffff*10000+ffff(4g)
;                        base = 0x00000000
;                        DPL=3
;                        G=1,D/B=1,P=1,E=0,W=1,A=1                        
user_ds                dw 0xffff
                        dw 0
                        db 0
                        db 0xf2
                        db 0xcf
                        db 0
                        
user_ds_sel        equ kernel_ds_sel + 8

                        
tss_selector:
tss1                dw 0x67                                ; limit               
                        dw tss32                        ; base15-0
                        db 0                                ; base23-16
                        db 0xe9                                ; DPL=3,type=32-bit available tss
                        db 0                                ; G=0
                        db 0                                ; base31-24
                        
tss1_sel        equ user_ds_sel + 8
                        
ldt_selector:
ldt1                dw 0                                ; limit
                        dw 0                                ; base15-0
                        db 0                                ; base23-16
                        db 0x82                                ; DPL=0,type=ldt
                        db 0x80                                ; G=1
                        db 0                                ; base31-24

gdt32_end:                        
        
ldt1_sel        equ tss1_sel + 8        


;-----------------------------------------------------------
idt32:
_DE                        dw exception_DE                                 ; offset15-0
                        dw kernel_cs_sel                                ; selector
                        db 0                                ; resever
                        db 0x8e                                ; DPL=0,type=interrup-gate
                        dw 0                                ; offset31-16
_DB                        dq 0
_NMI                dq 0
_BP                        dq 0
_OF                        dq 0
_BR                        dq 0
_UD                        dq 0
_NM                        dq 0
_DF                        dw exception_DF
                        dw kernel_cs_sel
                        db 0
                        db 0x8e
                        dw 0

                        dq 0                                ; reserved
_TS                        dq 0
_NP                        dq 0
_SS                        dq 0
_GP                        dw exception_GP
                        dw kernel_cs_sel
                        db 0
                        db 0x8e
                        dw 0
                        dq 0                                ; reserved
_MF                        dq 0               
_AC                        dq 0
_MC                        dq 0
_XF                        dq 0
times 10        dq 0                                ; reserved
_SX                        dq 0               

idt32_end:


;-----------------------------------------------------------
tss32:
                        dd 0                        ; link=0
                        dd 0x3fff0000        ; esp0
                        dd ds0_sel                 ; ss0 = 0x0028, ds0-selector
                        dd 0x2fff0000        ; esp1
                        dd ds1_sel                ; ss1
                        dd 0x1fff000        ; esp2
                        dd ds2_sel                ; ss2
                        dd 0                        ; cr3
                        dd 0                        ; eip
                        dd 0                        ; eflags
                        dd 0                        ; eax
                        dd 0                        ; ecx
                        dd 0                        ; edx
                        dd 0                        ; ebx
                        dd 0                         ; esp
                        dd 0                        ; ebp
                        dd 0                         ; esi
                        dd 0                         ; edi
                        dd 0x00000058        ; es:   kernel_ds
                        dd 0x00000048        ; cs:   kernel_cs
                        dd 0x00000058        ; ss:   kernel_ds
                        dd 0x00000058        ; ds:   kernel_ds                        
                        dd 0                        ; fs
                        dd 0                        ; gs
                        dd 0                        ; ldt-selector
                        db 0                        ; T=0
                        db tss32_end-tss32
tss32_end:                        
                                


                                
gdt:
gdt_limit dw gdt32_end-gdt32
gdt_base dd gdt32

idt:
idt_limit dw idt32_end-idt32
idt_base  dd idt32



1) 定义了3个级别的 code segment descriptor

; cs: limit = fffff*10000+ffff (4g)
;      base = 0x00000000
;      DPL=0,G=1,D=1,C=0,P=1,r=1


cs0  dw 0xffff        ; limit
      dw 0              ; base 15 ~ 0
      db 0             ; base 23 ~ 16
      db 0x9a          ; 1 00 11010 : p=1,c=0,r=1
      db 0xcf          ; G=1,D=1,base=00
      db 0

cs0_sel  equ 0x08


cs0 表示 0 级的 code segment descriptor

它的 limit 是 4G,即:fffff * 10000 (4K) + ffff
      base 是 0
      DPL 为 0,是 non-conforming 类型的代码


cs1 表示 1 级的 code segment descriptor
它的 limit 是 2g ,即:7ffff * 10000(4K) + ffff
       base 设为 0x80000000
       DPL 是 1,non-conforming 代码


cs2 表示 2 级的 code segment descriptor
limit 是 1g,即:3ffff * 10000 + ffff
base  是 0xd0000000
DPL 是 2, non-conforming 代码


cs3 表示 3 级的 code segment descriptor
limit 2g 即:7ffff * 10000 + ffff
base 设为 0
DPL 是 1, non-conforming 代码



2) 定义了 3 个 data segment descritpor

; ds0:        limit = fffff*1000+ffff (4g)
;                base = 0x00000000
;                DPL = 0
;                G=1,D/B=1,P=1,E=0,W=1,A=1
ds0                      dw 0xffff
                        dw 0
                        db 0
                        db 0x92
                        db 0xcf
                        db 0

ds0 表示 0 级别的 data segment descriptor,同理 ds1~ds3 表示1~3 级的 data segment descriptor



3) 分别 kernel 与 user 的 cs 和 ds

kernel 的 cs 与 ds 是 0 级权限,4g 空间
user 的 cs 与 ds 是 3 级权限,4g 空间



4) 1 个 32-TSS descriptor

tss1               dw 0x67                          ; limit               
                   dw tss32                        ; base15-0
                   db 0                              ; base23-16
                   db 0xe9                          ; DPL=3,type=32-bit available tss
                   db 0                              ; G=0
                   db 0                              ; base31-24

limit 是 0x67: 范围从 0 ~ 104 的区域
base 定义为 tss 块的起始地址



5) 1 个 LDT descritpor

ldt1                dw 0                                ; limit
                      dw 0                                ; base15-0
                      db 0                                ; base23-16
                      db 0x82                              ; DPL=0,type=ldt
                      db 0x80                              ; G=1
                      db 0                                ; base31-24

除了 type 外,其它暂时保留

[ 本帖最后由 mik 于 2009-7-18 16:04 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2009-07-18 16:06 |只看该作者
8、进入 protected mode 前的 16 位代码

code16_entry:
        mov ax,cs
        mov ds,ax
        mov es,ax
        mov ss,ax
        mov sp,0x6000
       
        cli

        lidt [idt]
        lgdt [gdt]                        ; load from ds:[gdt] into gdtr


        mov eax,cr0
        or eax,1

        mov cr0,eax


        jmp dword kernel_cs_sel:code32_entry


很简单:
* 初始环境的设定
* cli 进行 加载 idt 和 gdt 表
* 打开保护模式
* 跳到保护模式下的代码处执行



1)、在这里就开始加载了 idt ,这一步很重要,为以后的排错 debug 很有用。加载了 idt 就可以观察以后代码中发生什么异常,可以跟踪代码。

2)在跳入保护模式入口点处执行。
    kerenl_cs_sel 是 0 级别的代码的。code32_entry 就是保护模式代码的入口点

这里必须使用 0 级的 selector,在实模式下,CPL = 0,因此只能转向 0 级。

[ 本帖最后由 mik 于 2009-7-18 16:13 编辑 ]

论坛徽章:
0
10 [报告]
发表于 2009-07-18 16:55 |只看该作者
9、保护模式入口代码



code32_entry:        
        mov ax,ds0_sel
        mov ds,ax
        mov es,ax
        mov ax,ss0_sel
        mov ss,ax
        mov esp, 0x10000


        sti

        call clear
        lea esi,[message]
        push esi
        push dword 0
        push dword 0
        call display_message
        
        cld
        mov edi,0x10000
        lea esi,[next]
        mov ecx, kernel_end-next
        rep movsb


        push dword 0x10000
        ret



显示信息,然后,将自已剩余代码复制到 0x10000
然后跳到  0x10000 处继续执行
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP