操作系统——底层结构与设计原理知识汇总

 


JOS源文件安排:

inc/     这个文件夹是一些include文件,即各种类型的头文件。

            env.h       Public definitions for user-mode environments

            trap.h      Public definitions for trap handling

            syscall.h   Public definitions for system calls from user environments to the kernel

            lib.h       Public definitions for the user-mode support library

kern/   env.h       Kernel-private definitions for user-mode environments

            env.c       Kernel code implementing user-mode environments

            trap.h      Kernel-private trap handling definitions

            trap.c      Trap handling code

            trapentry.S Assembly-language trap handler entry-points

            syscall.h   Kernel-private definitions for system call handling

            syscall.c   System call implementation code

lib/       Makefrag    Makefile fragment to build user-mode library, obj/lib/libjos.a

            entry.S     Assembly-language entry-point for user environments

            libmain.c   User-mode library setup code called from entry.S

            syscall.c   User-mode system call stub functions

            console.c   User-mode implementations of putchar and getchar, providing console I/O

            exit.c      User-mode implementation of exit

            panic.c     User-mode implementation of panic

user/   *           Various test programs to check kernel lab 3 code


8086与80386寄存器对比:

  8086寄存器 80386寄存器
通用寄存器

ax(accumulator), bx(base), cx(count), dx(data), 

bp(base pointer), sp(stack pointer), di(des index), si(src index)

eax, ebx, ecx, edx,

ebp, esp, edi, esi

段寄存器 cs(code seg), ds(data seg), ss(stack seg), es(extra seg) cs, ds, ss, es, fs, gs
段描述符寄存器 对程序员不可见
状态和控制寄存器 flags, ip

eflags, eip,

cr0, cr1, cr2, cr3

系统地址寄存器 gdtr, idtr, tr, ldtr
调试寄存器 dr0-dr7
测试寄存器 tr0-tr7

“访存”指令中给定地址值(16位),CPU将其送往地址线(20位)。在8086时代,在把地址送往地址线之前,CPU会把它与某个段寄存器中的值相加:实际物理地址 = (段寄存器 << 4) + 偏移地址——从而实现了从16位内存地址到20位实际地址的映射。

到80286时代,引入了一个全新理念:“保护模式”,它的引入给寻址方式、中断管理都带来了变化。从此,我们把之前的段式管理方法称为“实模式”。

1)实模式下段的管理

实模式下一共有8种寻址方式:

立即数寻址  
寄存器寻址  
直接寻址  
寄存器间接寻址  
基址寻址  
变址寻址  
基址加变址  
带位移的基址加变址寻址  

本质上实模式下的寻址方式都是段基址左移4位加上偏移。

2)保护模式下段的管理

在保护模式下,利用一个段选择子(本质上是在一组段描述符数组中的下标或者说索引)到全局描述符表(一组段描述符构成的数组)中找到所需的段描述符(本质上是个结构体,它有三个成员变量:段物理首地址、段界限、段属性),而这个段描述符中就存放着真正的段的物理首地址,然后再加上偏移量得到最后的物理地址。

实际物理地址 = selector + offset,其中selector是16位的用于在GDT中索引,offset是32位的。

当发生内存寻址与定位时,处理器通过GDTR寄存器找到GDT,并通过selector找到对应的描述符,今儿得到该段的起始地址,最后加上偏移得到实际地址。 

 

kern/init.c:
入口:
void i386_init(void){

    cons_init();    //命令台初始化 
       kern/console.c:
       {
        cga_init();
        kbd_init();
        serial_init();
       }
     
    mem_init();     //内存管理初始化
       kern/pmap.c:
       {
        i386_detect_memory();
        kern_pgdir = boot_alloc();
        pages = boot_alloc();
        envs = boot_alloc();
        page_init();
        boot_map_region( .pages. );
        boot_map_region( .envs. );
        boot_map_region( .bootstack. );
        boot_map_region( .0. );
        lcr3(PADDR(kern_pgdir));
       }

    env_init();     //进程管理初始化
       kern/env.c:
       {
        ...                  //建立envs数组
        env_init_percpu();   //载入GDT和段描述符
       }

    trap_init();    //进程管理初始化:中断处理
       kern/trap.c:
       {
        SETGATE();           //建立中断描述符表
        trap_init_percpu();  
       }

    //创建进程,等同于env_create(_binary_obj_user_hello_start, ENV_TYPE_USER);
    //这里的符号名‘_binary_obj_user_hello_start’是链接器在链接内核镜像时自动生成的
    ENV_CREATE(user_hello, ENV_TYPE_USER);  
       kern/env.c:
       {
        env_alloc();
           {
            env_setup_vm(e);    //为进程分配并建立页目录
            ...                 //生成env_id
            ...                 //设置基本状态变量
            ...                 //设置段寄存器初值
           }
        load_icode();
           {
            lcr3(PADDR(e->env_pgdir));
            region_alloc();             //分配一定字节物理内存并映射到进程地址空间的某虚地址
               {
                page_alloc();
                page_insert();
               }
            memmove();
            memset();
            lcr3(PADDR(kern_pgdir));
            region_alloc();
           }
       }

    env_run(&envs[0]);    //运行进程,此函数不会返回,将不断循环直到销毁进程并退出
       {
        ...                              //设置(需要时切换)当前curenv
        lcr3(PADDR(curenv->env_pgdir));
        env_pop_tf();     //这是进入用户模式前的最后一个函数
       }

    while(1)              //陷入内核监控器
        monitor(NULL);
}

env_pop_tf()函数的作用就是按Trapframe的结构将其从栈中恢复到各寄存器中去,最后执行iret指令,从而从内核退出并开始执行用户进程代码。

执行完 iret 后进入用户模式,跳往lib/entry.S中定义的 _start: 处,执行完一些准备工作后执行 call libmain。  

libmain()定义在lib/libmain.c中,在其中调用用户主程序:umain(),执行完用户程序后exit()。

umain()定义在user/hello.c中,在其中可能执行一些如cprintf()之类的库函数,这些函数本质上最终都会执行系统调用。

上述调用过程发生在用户态下,调用过程如下:

kern/env.c:
void env_pop_tf()
{
    ...      //从栈中弹出Trapframe,恢复寄存器的值
    iret     //退出内核态,进入用户程序
}
--------------------内核态用户态分界线-------------------
lib/entry.S:
.text
.global _start
_start:
    ...
args_exist:
    call libmain    //调用库函数libmain
    ...

lib/libmain.c:
void libmain()
{
    ...
    umain();        //调用用户主函数umain
    exit();
}

user/hello.c:
void umain()
{
    cprintf("hello world\n");
}

 

你可能感兴趣的:(操作系统——底层结构与设计原理知识汇总)