跟我一起写操作系统

    返回首页    发表留言
本文作者:李德强
          第三节 创建进程
 
 

        有了可执行程序的地址和程序入口地址,就可以根据它们来创建进程。先修改进程控制块的数据结构:

typedef struct process_control_block
{
        //进程号
        u32 process_id;
        //任务描述段
        s_tss tss;
        //代码段和数据段的局部描述符
        s_gdt ldt[2];
        //程序地址
        void *run;
        //程序大小
        u32 run_size;
        //页目录
        void *page_dir;
        //页表
        void *page_tbl;
        //程序0级栈
        void *stack0;
} s_pcb;

        创建进程,并为页目录、页表及0级栈申请内存空间:

//进程控制块
s_pcb *pcb = alloc_page(process_id, pages_of_pcb(), 0, 0);
if (pcb == NULL)
{
        free_mm(run, run_pages);
        return NULL;
}
//申请页目录
pcb->page_dir = alloc_page(process_id, P_PAGE_DIR_NUM, 0, 0);        
//申请页表
pcb->page_tbl = alloc_page(process_id, P_PAGE_TBL_NUM, 0, 0);
//申请0级栈
pcb->stack0 = alloc_page(process_id, P_STACK0_P_NUM, 0, 0);
//初始化pcb
init_process(pcb, process_id, run, entry_point, run_size);
//将此进程加入链表
pcb_insert(pcb);
//进程号加一
process_id++;        
//进程号
pcb->process_id = pid;
//程序地址
pcb->run = run;
//程序大小
pcb->run_size = run_size;
//程序入口地址
pcb->tss.eip = (u32) run + run_offset;
//永远是4G,但为了4K对齐保留了最后一个0x1000
pcb->tss.esp = 0xfffff000;
//程序0级栈
pcb->tss.esp0 = (u32) pcb->stack0 + P_STACK0_SIZE;
//页目录存入到cr3中
pcb->tss.cr3 = (u32) pcb->page_dir;
//地址
u32 address = 0;
u32 *page_dir = ((u32 *) pcb->page_dir);
u32 *page_tbl = ((u32 *) pcb->page_tbl);
/*
 * 前16M系统内存为已使用并且为只读
 */
for (int i = 0; i < 1024; i++)
{
        for (int j = 0; j < 1024; j++)
        {
                if (i < 4)
                {
                        page_tbl[j] = address | 5;
                }
                else
                {
                        page_tbl[j] = 6;
                }
                address += 0x1000;
        }
        page_dir[i] = (u32) page_tbl | 7;
        page_tbl += 1024;
}
//初始化pcb所在的内存页
init_process_page((u32) pcb, pages_of_pcb(), pcb->page_dir);
//初始化pcb->stack0所在的内存页
init_process_page((u32) pcb->stack0, pages_of_pcb(), pcb->page_dir);

        将一个使用地址加入到页表中:

void init_process_page(u32 address, u32 pages, u32 *page_dir)
{
        //mm_pcb所在内存页目录索引
        u32 page_dir_index = (address >> 22) & 0x3ff;
        //mm_pcb所在内存页表索引
        u32 page_table_index = (address >> 12) & 0x3ff;
        address &= 0xFFC00000;
        u32 *page_tbl = (u32 *) (page_dir[page_dir_index] & 0xfffff000);
        //mm_pcb所在内存页表
        for (int i = 0; i < 1024; i++)
        {
                //设置mm_pcb所在内存的页表
                if (i >= page_table_index && i <= (page_table_index + 16))
                {
                        page_tbl[i] = address | 7;
                }
                address += 0x1000;
        }
        //设置mm_pcb所在内存的页目录
        page_dir[page_dir_index] = (u32) page_tbl | 7;
        //设置pages个页面剩余页
        if (page_table_index + pages >= 1024)
        {
                page_dir_index++;
                page_tbl += 1024;
                for (int i = 0; i < 1024; i++)
                {
                        if (i < (pages - (1024 - page_table_index)))
                        {
                                page_tbl[i] = address | 7;
                        }
                        address += 0x1000;
                }
                page_dir[page_dir_index] = (u32) page_tbl | 7;
        }
}

        至此,我们就可以载入并执行一个可执行程序了,但还有最后一个问题,就是进程的调度。目前采用的是链表,按平均时间片执行所有程序。链表的内部实现是一个单向链表,如下:

/*
 * 为列表插入一个新节点
 */
s_list* list_insert_node(s_list *list, s_list *p_list)
{
        if (p_list == NULL)
        {
                return list;
        }
        p_list->next = NULL;
        s_list* header = list;
        if (header == NULL)
        {
                header = p_list;
        }
        else
        {
                p_list->next = header;
                header = p_list;
        }
        return header;
}
/*
 * 移除一个节点
 */
s_list* list_remove_node(s_list *list, s_list *p_list)
{
        if (p_list == NULL)
        {
                return list;
        }
        s_list* header = list;
        s_list* p = header;
        s_list* fp = p;
        while (p != NULL)
        {
                if (p == p_list)
                {
                        if (p == fp)
                        {
                                header = p->next;
                                p->next = NULL;
                                return header;
                        }
                        else
                        {
                                if (p->next == NULL)
                                {
                                        fp->next = NULL;
                                        return header;
                                }
                                else
                                {
                                        fp->next = p->next;
                                        p->next = NULL;
                                        return header;
                                }
                        }
                }
                if (p == fp)
                {
                        p = p->next;
                }
                else
                {
                        p = p->next;
                        fp = fp->next;
                }
        }
        return header;
}
/*
 * 将链表的头节点移动到尾部,即链表
 */
s_list* list_header2footer(s_list *list)
{
        s_list* header = list;
        if (header == NULL)
        {
                return NULL;
        }
        if (header->next == NULL)
        {
                return header;
        }
        s_list *fst = header;
        s_list *p = header;
        header = header->next;
        while (p->next != NULL)
        {
                p = p->next;
        }
        p->next = fst;
        fst->next = NULL;
        return header;
}
/*
 * 将进程加入到链表中
 */
void pcb_insert(s_pcb *pcb)
{
        if (pcb == NULL)
        {
                return;
        }
        s_list *p_list = alloc_mm(sizeof(s_list));
        p_list->node = pcb;
        list_pcb = list_insert_node(list_pcb, p_list);
}

        最后修改进程调度算法:

//进程链表
s_list *list_pcb = NULL;
//当前正在运行的进程
s_pcb *pcb_cur = NULL;
//上一次运行的进程
s_pcb *pcb_last_run = NULL;
/*
 * 进程调度,目前只使用平均时间片轮转的算法
 */
void schedule()
{
        //取得链表头
        s_list *list_header = list_pcb;
        if (list_header == NULL)
        {
                return;
        }
        //取得链表头的进程
        pcb_cur = (s_pcb *) (list_header->node);
        /*
         * 如果当前进程不是上一次运行的进程,说明链表中有两个或两个以上的进程
         * 链表中只有一个进程,不需要切换。
         * 链表中有两个或两个以上的进程,需要切换。
         */
        if (pcb_cur != pcb_last_run)
        {
                //将链表头移动到链表尾,链表
                list_pcb = list_header2footer(list_pcb);
                //设置tss和ldt
                addr_to_gdt(GDT_TYPE_TSS, (u32) &(pcb_cur->tss), &gdts[4], GDT_G_BYTE, sizeof(s_tss) * 8);
                addr_to_gdt(GDT_TYPE_LDT, (u32) (pcb_cur->ldt), &gdts[5], GDT_G_BYTE, sizeof(s_gdt) * 2 * 8);
                //将上一次运行进程设置为当前进程
                pcb_last_run = pcb_cur;
                //在时钟中断时并没有切换ds和cr3寄存器
                //但是在call tss时cr3会被修改为tss中的cr3
                set_ds(0xf);
                //切换进程
                call_tss();
        }
}

        在start_kernel()函数中加入install_system();安装系统进程。在Makefile中为内核程序加入进程调度算法文件sche.c和system程序的编译链接代码。编译并运行:


        源代码的下载地址为:

https           https://github.com/magicworldos/lidqos.git 
git             git@github.com:magicworldos/lidqos.git 
subverion       https://github.com/magicworldos/lidqos 
branch          v0.18

 

    返回首页    返回顶部
#1楼  小白  于 2018年05月20日20:58:40 发表
 
大哥这一节死活调不出来,报错应该是打开文件失败,【用的vbox,512M内存,20G虚拟存储(第一IDE主通道),载入系统映像第一IDE从通道】求救~mail:2433124411@qq.com
  看不清?点击刷新

 

  Copyright © 2015-2023 问渠网 辽ICP备15013245号