xv6 系统启动过程

2024-05-27 22:20
文章标签 过程 系统启动 xv6

本文主要是介绍xv6 系统启动过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1、硬件上电
  • 2、执行 _entry_ 代码
  • 3、_entry_ 跳转到/kernel/start.c
  • 4、start函数跳转到/kernel/main.c
  • 5、main函数跳转到/user/initcode.S
  • 6、initcode.S跳转到/kernel/syscall.c
  • 7、syscall.c跳转到/kernel/exec.c
  • 8、exec.c返回到/user/init.c
  • 系统启动完成

1、硬件上电

硬件上电后,将会运行一个只读的boot loader 程序,这个程序会将xv6的内核加载进内存中。
程序将会被加载到物理地址0x80000000处,前面的物理地址被IO设备占用。

2、执行 entry 代码

进入机器模式,xv6将从 entry 处开始执行。

//kernel/_entry.S1         # qemu -kernel loads the kernel at 0x800000002         # and causes each hart (i.e. CPU) to jump there.3         # kernel.ld causes the following code to4         # be placed at 0x80000000.5 .section .text6 .global _entry7 _entry:8         # set up a stack for C.9         # stack0 is declared in start.c,10         # with a 4096-byte stack per CPU.11         # sp = stack0 + (hartid * 4096)12         la sp, stack013         li a0, 1024*414         csrr a1, mhartid15         addi a1, a1, 116         mul a0, a0, a117         add sp, sp, a018         # jump to start() in start.c19         call start20 spin:21         j spin
  • entry 将设置一个栈stack0以供xv6运行C代码
  • csrr a1, mhartid,//将当前硬件线程的 ID(hartid)加载到寄存器 a1 中。mhartid 是 RISC-V 中的一个特权级 CSR(Control and Status Register)寄存器,用于获取硬件线程 ID。
  • addi a1, a1, 1,这行代码将寄存器 a1 中的值增加 1。
  • mul a0, a0, a1,这行代码将寄存器 a0 中的值与寄存器 a1 中的值相乘,结果保存在寄存器 a0 中。
  • add sp, sp, a0,这行代码将栈指针 sp 向上移动,移动的距离是寄存器 a0 中的值。

3、entry 跳转到/kernel/start.c

执行start()函数,该函数执行一些机器模式下的配置任务。

 19 // entry.S jumps here in machine mode on stack0.20 void21 start()22 {23   // set M Previous Privilege mode to Supervisor, for mret.24   unsigned long x = r_mstatus();  //读取状态25   x &= ~MSTATUS_MPP_MASK;      //将 `x` 中表示 Previous Privilege Mode 的位清零。26   x |= MSTATUS_MPP_S;          //将 `x` 中表示 Previous Privilege Mode 的位设置为 Supervisor Mode。27   w_mstatus(x);                //将修改后的状态值写回 `mstatus` CSR 寄存器。2829   // set M Exception Program Counter to main, for mret.30   // requires gcc -mcmodel=medany31   w_mepc((uint64)main); //将 `main` 函数的地址写入 Exception Program Counter (EPC) 寄存器,以便在异常处理完成后跳转到 `main` 函数执行。3233   // disable paging for now.34   w_satp(0);   //将页表寄存器(SATP)设置为零,暂时禁用分页机制。3536   // 将所有的中断和异常委托给 Supervisor Mode 处理。37   w_medeleg(0xffff);38   w_mideleg(0xffff);39   w_sie(r_sie() | SIE_SEIE | SIE_STIE | SIE_SSIE);4041   // configure Physical Memory Protection to give supervisor mode42   // access to all of physical memory.43   w_pmpaddr0(0x3fffffffffffffull);44   w_pmpcfg0(0xf);4546   // ask for clock interrupts.初始化时钟中断。47   timerinit();4849   // keep each CPU's hartid in its tp register, for cpuid().50   int id = r_mhartid();51   w_tp(id);5253   // switch to supervisor mode and jump to main().54   asm volatile("mret"); //执行 `mret` 汇编指令,将处理器从机器模式切换到 supervisor 模式,并跳转到 `main()` 函数执行。55 }

4、start函数跳转到/kernel/main.c

main执行一些初始化工作

  9 // start() jumps here in supervisor mode on all CPUs.10 void11 main()12 {13   if(cpuid() == 0){14     consoleinit();15     printfinit();16     printf("\n");17     printf("xv6 kernel is booting\n");18     printf("\n");19     kinit();         // physical page allocator20     kvminit();       // create kernel page table21     kvminithart();   // turn on paging22     procinit();      // process table23     trapinit();      // trap vectors24     trapinithart();  // install kernel trap vector25     plicinit();      // set up interrupt controller26     plicinithart();  // ask PLIC for device interrupts27     binit();         // buffer cache28     iinit();         // inode table29     fileinit();      // file table30     virtio_disk_init(); // emulated hard disk31     userinit();      // 产生第一个用户进程,第一个进程执行用RISCV汇编写的,将产生第一个系统调用initcode.S32     __sync_synchronize();  //同步内存,确保之前的操作在多核环境中可见。33     started = 1;   //代表前述初始化完成34   } else {35     while(started == 0)  //等待初始化完成36       ;37     __sync_synchronize(); 38     printf("hart %d starting\n", cpuid());39     kvminithart();    // turn on paging40     trapinithart();   // install kernel trap vector41     plicinithart();   // ask PLIC for device interrupts42   }4344   scheduler();   //进入调度器,开始调度进程。45 }

5、main函数跳转到/user/initcode.S

首先准备好执行 /init 程序的参数,然后调用 exec 系统调用执行 /init。(即执行sys_exec系统调用)

  1 # Initial process that execs /init.2 # This code runs in user space.34 #include "syscall.h"56 # exec(init, argv)7 .globl start    //定义全局标签 `start`,表示程序的入口点。8 start:9         la a0, init   //将字符串 `/init` 的地址加载到寄存器 `a0` 中。10         la a1, argv   //将参数数组 `argv` 的地址加载到寄存器 `a1` 中。11         li a7, SYS_exec  //将 `exec` 系统调用编号加载到寄存器 `a7` 中。12         ecall   //触发系统调用 `exec`,执行 `/init` 程序。1314 # for(;;) exit();15 exit:16         li a7, SYS_exit  //将 `exit` 系统调用编号加载到寄存器 `a7` 中。17         ecall    //触发系统调用 `exit`,退出当前进程。18         jal exit   //跳转并链接到 `exit` 标签,形成一个无限循环以防止进程返回到调用者。1920 # char init[] = "/init\0";21 init:   //定义字符串 `init`:22   .string "/init\0"2324 # char *argv[] = { init, 0 };25 .p2align 226 argv:   //定义参数数组 `argv`:27   .long init28   .long 0

6、initcode.S跳转到/kernel/syscall.c

(sys_exec系统调用)

//syscall.h#define SYS_exec    7
//syscall.c
[SYS_exec]    sys_exec,extern uint64 sys_exec(void);
//通过defs.h 查找,可知位于exec.c文件中26 // exec.c27 int             exec(char*, char**);

7、syscall.c跳转到/kernel/exec.c

  • exec() 函数的作用是在当前进程的上下文中执行一个新的程序。具体来说,exec() 会用指定的程序替换当前进程的地址空间,包括代码段、数据段、堆和栈,从而执行新的程序。

8、exec.c返回到/user/init.c

  • exec()结束后,将返回到 /init进程(user/init.c)(若有需要产生一个新的控制台设备文件并以描述符0,1,2打开这个文件)
  • 最后在控制台上启动shell

系统启动完成

这篇关于xv6 系统启动过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1008756

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

Solr 使用Facet分组过程中与分词的矛盾解决办法

对于一般查询而言  ,  分词和存储都是必要的  .  比如  CPU  类型  ”Intel  酷睿  2  双核  P7570”,  拆分成  ”Intel”,”  酷睿  ”,”P7570”  这样一些关键字并分别索引  ,  可能提供更好的搜索体验  .  但是如果将  CPU  作为 Facet  字段  ,  最好不进行分词  .  这样就造成了矛盾  ,  解决方法

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

ORACLE语法-包(package)、存储过程(procedure)、游标(cursor)以及java对Result结果集的处理

陈科肇 示例: 包规范 CREATE OR REPLACE PACKAGE PACK_WMS_YX IS-- Author : CKZ-- Created : 2015/8/28 9:52:29-- Purpose : 同步数据-- Public type declarations,游标 退休订单TYPE retCursor IS REF CURSOR;-- RETURN vi_co_co

OpenStack创建虚拟机过程

OpenStack创建虚拟机过程 一、在分析OpenStack创建虚拟机的过程之前,先来梳理一下需要用用到哪些组件。 二、每一步都需要去keystone去进行验证,下图有详细的流程。 登录界面或命令行通过RESTful API向keystone获取认证信息。keystone通过用户请求认证信息,并生成auth-token返回给对应的认证请求。界面或命令行通过RESTful API

Maven生命周期:深入理解构建过程

目录 1. Maven生命周期简介 2. 默认生命周期的阶段 3. 清理生命周期 4. 站点生命周期 5. Maven生命周期的灵活性 6. 结论         在Java开发中,Maven是一个不可或缺的工具,它通过自动化项目的构建、依赖管理和文档生成等任务,极大地提高了开发效率。Maven的核心之一是其构建生命周期,它定义了项目构建过程中的一系列阶段。在这篇文章中,我们将深

JVM工作过程

将JVM工作过程粗略分为5个阶段,包括加载阶段、链接阶段、初始化阶段、执行阶段、回收阶段 其中, (1)加载阶段、链接阶段的解析部分主要由类加载器完成 (2)初始化阶段是由JVM的类加载机制在类加载过程的最后阶段自动触发的。 (3)执行阶段主要由执行引擎负责 (4)回收阶段主要是垃圾收集器(Garbage Collector)负责。 所以,在Java虚拟机(JVM)中,读取字节码文件、解析字节码

【QNX+Android虚拟化方案】120 - Android 侧 USB2.0 插拔过程

【QNX+Android虚拟化方案】120 - Android 侧 USB2.0 插拔过程 基于原生纯净代码,自学总结 纯技术分享,不会也不敢涉项目、不泄密、不传播代码文档!!! 本文禁止转载分享 !!! 汇总链接:《【QNX+Android虚拟化方案】00 - 系列文章链接汇总》 本文链接:《【QNX+Android虚拟化方案】120 - Android 侧 USB2.0