Lecture 33: VM II: Page Faults, Multilevel, Interrupts/Exceptions

VM II:页面错误、多级、中断/异常

内存应该被共享 (Memory Should Be Shared)

在现代计算机系统中,内存是一个关键的共享资源,通常被多个进程同时使用。虽然每个进程可能运行在不同的处理器核心上,但它们都需要访问相同的物理内存(DRAM)。这要求系统能够有效管理多个进程对内存的共享和访问,以确保系统性能和数据一致性。

image-20240811101223324

  • 多个进程共享内存
    • 系统中可能同时运行数百个进程,操作系统通过多路复用技术在不同的处理器核心之间分配这些进程。如果系统只有一个处理器核心,操作系统则通过上下文切换在不同进程之间切换执行。这种机制确保了系统能够同时运行多个任务,而不会因为资源竞争导致明显的性能下降。
  • 内存共享的挑战
    • 处理器的上下文切换可以在不同进程之间切换处理器的状态,但内存是一个全局资源,无法像寄存器一样在上下文切换时被保存和恢复。直接保存和恢复整个内存的内容在上下文切换时会产生过大的开销。因此,系统需要一种高效的机制,使得内存能够在多个进程之间安全且高效地共享,同时确保各进程的操作不会互相干扰,这就是虚拟内存机制的重要性。

虚拟内存:页表 (Virtual Memory: Page Tables)

虚拟内存是现代操作系统管理内存的核心机制,它通过页表实现虚拟地址到物理地址的映射,使得每个进程都拥有独立的地址空间。

  • 专用页表
    • 每个进程都有一个独立的页表,操作系统通过维护这些页表来跟踪和管理每个进程的内存使用情况。页表是虚拟地址到物理地址映射的核心工具,确保了各进程在各自的虚拟地址空间中独立运行,同时能够共享物理内存。
  • 地址空间的概念
    • 在虚拟内存系统中,系统引入了虚拟地址空间和物理地址空间。虚拟地址空间是每个进程独有的,而物理地址空间是计算机实际的内存地址。例如,在32位系统中,虚拟地址空间通常由虚拟页号(VPN)和页内偏移(offset)组成。操作系统通过页表将虚拟地址映射到物理地址,使得每个进程可以在独立的虚拟地址空间中运行,同时共享物理内存。
  • 地址转换
    • 当进程需要访问内存时,虚拟地址首先通过页表转换为物理地址。虚拟页号(VPN)通过查找页表映射到物理页号(PPN),然后与页内偏移量组合形成最终的物理地址。这一过程确保了进程在使用虚拟地址空间的同时,能够安全地访问实际的物理内存。

image-20240811101640726

页表的作用与内存隔离

页表不仅是地址转换的核心组件,还在内存隔离中起到了关键作用。

  • 内存隔离机制
    • 页表通过分配不同的物理页面给不同的进程,实现了内存隔离。这样,进程之间的内存访问不会互相干扰,一个进程无法随意访问或修改另一个进程的数据,从而保障了系统的安全性和稳定性。
  • 共享页面的可能性
    • 尽管默认情况下,虚拟内存确保了进程的内存是隔离的,但在某些情况下,操作系统允许多个进程共享同一个物理页面。例如,多个进程可能需要访问相同的库文件或系统数据。为实现这种共享,操作系统可以在页表中为这些页面设置特定的权限,如只读或写保护,确保多个进程在共享页面时不会破坏数据的完整性。

虚拟内存的优势

虚拟内存不仅解决了内存共享的挑战,还带来了许多其他优势:

  • 扩展内存使用范围
    • 虚拟内存允许进程使用比实际物理内存更多的地址空间,这对于运行大型应用程序特别重要。系统通过将不常用的数据分页到磁盘上,使得内存可以被更加有效地利用。
  • 简化编程模型
    • 程序员可以编写假设拥有大内存的程序,而不需要关心实际的物理内存布局。操作系统通过虚拟内存机制自动处理地址映射和分页。
  • 增强系统安全性
    • 虚拟内存机制提供的内存隔离确保了进程间的数据安全,防止恶意进程窃取或篡改其他进程的数据。

通过虚拟内存和页表的结合,现代操作系统能够高效地管理内存资源,确保多任务处理环境下系统的稳定性和安全性。

继续假设不存在缓存 (Continue Assuming That Caches Don’t Exist)

image-20240810140003753

为了深入理解虚拟内存的工作机制,我们先假设系统中没有缓存的存在。这种假设能简化对虚拟内存基本概念的理解,特别是页表和内存管理的原理。

  • 存储层次结构金字塔
    • 存储系统被组织成一个层次结构,从快速但容量小的存储器(如寄存器)到容量大但速度慢的存储器(如磁盘)。这个金字塔展示了不同存储层次的速度和容量关系:
      • 寄存器:位于金字塔的顶端,速度最快,但容量极小。
      • 物理内存(DRAM):位于中间,速度和容量适中,是运行时的主要存储空间。
      • 虚拟内存:通过使用较慢的磁盘存储来扩展物理内存的容量,使得系统能够支持更大的地址空间。
  • 忽略缓存的原因
    • 在学习虚拟内存的初期阶段,忽略缓存的存在可以让我们专注于虚拟内存和页表的基本工作原理。缓存用于加速数据访问,但也增加了系统的复杂性。先理解基础概念,后续再引入缓存的讨论,会更有助于理解整个存储系统的工作机制。
  • 后续讨论缓存
    • 一旦我们理解了虚拟内存的基本原理,将会重新引入缓存的概念,特别是它与虚拟内存的结合,例如通过使用翻译后备缓冲器(TLB)来优化内存访问性能。

Page Table Details II: Page Faults, Write Policy

页表详细信息 II:页面错误与写策略

在虚拟内存的管理中,页面错误和写策略是两个至关重要的概念,它们直接影响系统的性能和数据一致性。

  • 页面错误(Page Faults)
    • 当进程尝试访问的页面不在物理内存中时,系统会触发页面错误。操作系统需要将缺失的页面从磁盘加载到内存中,并更新页表。这个过程会引起显著的性能开销。因此,减少页面错误的频率是优化系统性能的重要措施。
  • 写策略(Write Policy)
    • 写策略决定了在缓存系统中,如何以及何时将数据写回到主存。主要的写策略有两种:
      • 写回(Write-Back):只有在数据从缓存中被移除时,才会将修改的数据写回到主存。这种策略提高了写操作的性能,但在系统崩溃时可能导致数据丢失。
      • 写穿(Write-Through):每次写操作都立即更新主存,确保数据的一致性,但可能增加写操作的延迟。

页表存储在内存中 (Page Tables Are Stored in Memory)

在32位虚拟地址空间、4GiB DRAM和4KiB页面的配置下,页表的管理需要特别注意,以避免性能下降。

  • 页表大小
    • 在这种配置下,虚拟地址空间被分为虚拟页号(VPN)和页内偏移(offset)。对于4KiB页面和32位虚拟地址,虚拟页号有20位,因此有2^20个页表项,每个页表项占用4字节。整个页表的大小为4MiB,占据了4GiB物理内存的0.1%。虽然这个比例看起来不大,但4MiB的页表大小已经超出了可以有效缓存的范围。
  • 页表存储在主存(DRAM)中
    • 由于页表通常存储在主存中,每次需要进行地址翻译时都必须访问主存中的页表。如果发生缓存未命中,意味着每次加载或存储操作可能需要两次内存访问,从而显著影响系统性能。

性能优化措施

为了减少访问页表带来的性能开销,系统可以采用以下优化策略:

  • 块传输而非逐字传输
    • 在DRAM与处理器缓存之间传输较大的数据块,而不是逐字传输,可以有效减少内存访问的延迟。这样可以更好地利用内存带宽,减少缓存未命中的影响。
  • 缓存页表项
    • 使用翻译后备缓冲器(TLB)来缓存经常访问的页表项是提高内存访问效率的重要手段。TLB可以减少对主存的访问次数,加速虚拟地址到物理地址的转换,从而提高整体系统性能。

页面错误 (Page Faults)

页面错误是指当进程试图访问的页面不在物理内存中时触发的情况。页表中的每个条目都包含一个状态位,用于指示页面是否在内存中。

image-20240811104438567

  • 有效位(Valid Bit)
    • 如果有效位为1,表示页面当前在物理内存中,系统可以直接从DRAM中读取或写入数据。
    • 如果有效位为0,表示页面不在物理内存中,而在磁盘上,此时会触发页面错误(Page Fault)。
  • 页面错误处理过程
    1. 触发页面错误后,操作系统介入,准备将所需页面加载到物理内存中。
    2. 如果内存已满,首先需要将一个页面从DRAM中移出,并将其存储到磁盘上(如果页面已修改)。
    3. 然后,将所需的页面从磁盘读取到内存中,并更新页表中的有效位。
    4. 最后,操作系统可以继续从内存中读取或写入数据。
  • 页面替换策略
    • 操作系统使用页面替换策略来决定哪个页面应该被移出内存。常见的策略包括LRU(最近最少使用)、FIFO(先进先出)和随机策略。这些策略通常在操作系统或软件中实现,其开销远小于磁盘访问时间。

页表元数据:状态位 (Page Table Metadata: Status Bits)

在页表中,每个条目不仅包含虚拟页号和物理页号的映射,还包含若干状态位,用于管理和保护内存访问。

  • 写保护位(Write Protection Bit)
    • 如果写保护位被设置,当进程试图写入这个页面时,系统会触发异常,从而防止未经授权的写入。这通常用于保护关键的系统代码和数据。
  • 有效位(Valid Bit)
    • 有效位指示页面是否在物理内存中。如果该位为1,页面在内存中,可以直接访问;如果为0,则页面在磁盘上,访问该页面会触发页面错误。
  • 脏位(Dirty Bit)
    • 脏位指示页面在内存中的内容是否已被修改而未同步到磁盘。如果脏位为1,表示内存中的页面比磁盘上的页面更新;如果需要将该页面移出内存,系统需要先将其写回到磁盘。

内存的写策略 (Memory’s Write Policy)

在虚拟内存系统中,DRAM充当了磁盘的“缓存”,用于存储经常访问的数据。

  • 写策略的选择
    • 写穿(Write-Through):每次写操作都直接写入磁盘。虽然这种方式保证了磁盘数据的及时更新,但代价是频繁的磁盘访问,性能较低。
    • 写回(Write-Back):数据仅在页面被驱逐出内存时才写入磁盘。这种策略减少了磁盘的写入次数,提高了系统性能。
  • 虚拟内存系统的策略
    • 所有虚拟内存系统都使用写回策略,因为磁盘访问的时间成本太高,直接写入磁盘会严重影响系统性能。

Hierarchical/Multilevel Page Tables

页表存储在内存中 (Page Tables Are Stored in Memory)

在虚拟内存系统中,页表必须存储在内存中以便随时访问。这一页详细讨论了页表在32位虚拟地址空间、4GiB内存和4KiB页面的配置下的存储需求和挑战。

  • 页表大小计算
    • 在32位虚拟地址空间中,每个虚拟页号(VPN)有2^20个可能的值。如果每个页表项占用4字节(包括物理页号和状态位),那么整个页表的大小就是4MiB。相对于4GiB的DRAM,这占用了0.1%的内存空间,表面上看并不算多。
  • 每个程序需要自己的页表
    • 每个运行的程序都有自己独立的页表,这意味着如果系统中有256个进程,那么总的页表存储需求将达到1GiB,相当于占用了25%的内存空间。这种情况下,页表占用了大量的内存资源,可能导致内存不足。
  • 页表必须存储在内存中
    • 由于页表需要被频繁访问,因此它们必须常驻内存。虽然可以将部分数据页换出到磁盘上,但整个页表不能被换出,否则系统将无法有效进行地址转换。

进入页表层次结构 (Enter the Page Table Hierarchy)

image-20240811104541184

为了应对内存中巨大的页表存储需求,操作系统引入了多级页表的层次结构。多级页表的核心思想是利用虚拟地址空间的稀疏性,减少实际使用的内存。

  • 页表的页表
    • 多级页表的关键在于将一个大页表分解成多个小的页表。第一级页表始终保留在内存中,而第二级页表可以存储在磁盘上,仅在需要时加载到内存中。这样,只有那些实际使用的虚拟地址空间部分需要在内存中保留页表,而未使用的部分可以保持在磁盘中。
  • 多级页表的优点
    • 由于大多数程序仅使用其虚拟地址空间的一小部分,因此通过多级页表,可以显著减少内存中实际保留的页表数量。第一级页表始终在内存中,以便快速访问,而第二级页表则根据需要动态加载。这种结构极大地提高了内存利用率,减少了不必要的内存占用。

通过引入多级页表的层次结构,操作系统能够更有效地管理页表,减少内存消耗,同时保持高效的地址转换。这种设计使得虚拟内存系统能够在有限的内存资源下支持大量的进程运行。

多级页表翻译 (Multilevel Page Table Translation)

image-20240811104634636

在32位虚拟地址空间、4GiB DRAM和4KiB页面的环境中,操作系统通常使用多级页表来管理虚拟地址到物理地址的映射。

  • 页表结构
    • 在RV32I架构中,虚拟地址被划分为三个部分:前10位作为一级页表索引(L1 index),中间10位作为二级页表索引(L2 index),最后12位是页内偏移量(offset)。
    • 一级页表:包含2^10个条目,每个条目指向一个二级页表或磁盘位置。
    • 二级页表:每个二级页表也包含2^10个条目,指向实际的数据页面。
  • 页表的存储
    • 一级页表总是保存在DRAM中,以确保快速访问。
    • 二级页表可以根据需要从磁盘加载到内存中,从而优化内存使用。

单级页表与两级页表 (1-Level vs. 2-Level Page Tables)

在页表的管理中,采用单级页表或多级页表的设计会显著影响系统的内存消耗和性能。

  1. 单级页表的内存消耗
    • 对于32位虚拟地址空间,每个页表项占用4字节。如果我们运行16个进程,每个进程都需要2^20个页表项(因为2^32虚拟地址空间被4KiB页面分割后有2^20个页面)。
    • 因此,单级页表总共需要消耗16 x 4MiB = 64MiB的内存。
  2. 两级页表的内存消耗
    • 在两级页表结构中,一级页表有2^10个条目,每个条目指向一个二级页表。二级页表的条目数同样为2^10
    • 一级页表需要占用2^10 x 4B = 4KiB的内存。每个进程都需要一个一级页表,因此16个进程需要16 x 4KiB = 64KiB的内存。

image-20240811104811557

总结

  • 使用两级页表可以显著减少内存的消耗,尤其是在大量进程运行的情况下。这种结构通过分层管理页表,将虚拟地址空间的稀疏性利用到极致,避免了单级页表需要为每个虚拟页面分配内存的问题。两级页表结构在现代计算机系统中广泛使用,因为它在性能和内存效率之间取得了良好的平衡。

多级页表遍历 (Multilevel Page Table Walk)

在这部分内容中,我们通过一个具体的例子来说明多级页表是如何工作的。给定32位虚拟地址空间,4GiB DRAM,4KiB页面大小的系统,我们将解析虚拟地址0x00402450是如何转换为物理地址的。

image-20240811105400295

  • 虚拟地址结构
    • 虚拟地址被分为三级:前10位(0x001)用于一级页表索引(L1 index),中间10位(0x002)用于二级页表索引(L2 index),最后12位(0x450)是页内偏移量(offset)。
  • 一级页表查找
    • 从一级页表中,使用0x001作为索引找到对应的页表项。该项指向一个二级页表的地址,地址为0x00020
  • 二级页表查找
    • 在一级页表中找到的二级页表中,使用0x002作为索引。这个索引指向物理页号0x00060
  • 物理地址的构建
    • 最后,将物理页号0x00060与页内偏移量0x450组合,形成最终的物理地址0x00060450。页内偏移量保持不变,只需将其附加到物理页号的末尾。

操作系统如何管理虚拟内存? (How does the OS manage Virtual Memory?)

关于操作系统如何管理虚拟内存的问题,特别是页面错误(Page Faults)的处理。

  • 异常处理机制
    • 当程序访问一个不在内存中的页面时,会触发一个页面错误。操作系统的异常处理机制会捕捉这个错误,并负责将所需页面从磁盘加载到内存中,然后继续执行程序。这种异常处理是操作系统管理虚拟内存的核心机制之一,确保了系统的稳定性和连续性。

这些步骤展示了多级页表在实际内存管理中的运作过程,尤其是如何通过多级索引逐步缩小虚拟地址的范围,最终找到物理内存中的实际数据位置。这种机制极大地提高了内存的利用效率,并确保系统可以处理大规模的虚拟地址空间。

OS: Supervisor Mode, Exceptions

监督模式 vs 用户模式

在现代计算机系统中,操作系统和应用程序的执行被分为两种模式:监督模式(也称为内核模式)和用户模式。这种区分是为了保护系统的核心资源和确保操作系统的稳定性。

  • 监督模式(Supervisor Mode)
    • 监督模式是CPU的一种硬件级别的模式,通常用于操作系统内核的执行。它允许操作系统对内存、设备和其他进程进行全面的控制。
    • 当系统处于监督模式时,可以执行所有的CPU指令,包括那些可能影响系统稳定性的指令。因此,监督模式类似于超级用户的权限,能够执行对系统有重大影响的操作。
    • 由于监督模式的高权限,任何错误都会导致灾难性的后果,例如系统崩溃(蓝屏)或数据损坏。
  • 用户模式(User Mode)
    • 用户模式限制了进程对系统资源的访问,只允许它们执行一部分指令,并只能访问特定的内存区域。这是为了保护系统不受应用程序错误或恶意软件的影响。
    • 用户模式的进程无法直接切换到监督模式。通常,只有通过硬件中断或异常处理机制,操作系统才会进入监督模式。
    • 操作系统的大部分时间运行在用户模式下,只有在需要进行关键系统操作时才进入监督模式。

异常和中断 (Exceptions and Interrupts)

在程序的执行过程中,可能会出现各种需要立即处理的事件。这些事件被分为异常(Exceptions)和中断(Interrupts)。

  • 异常(Exceptions)
    • 异常是在当前程序执行过程中,由程序内部事件触发的。例如,当程序尝试执行非法指令、除以零、或访问未加载到内存中的页面时,会触发异常。
    • 异常是同步事件,这意味着它们必须立即处理,以防止程序继续执行可能导致系统崩溃的操作。
    • 常见的异常包括非法指令、除零错误、页面错误(Page Fault)以及写保护违规。
  • 中断(Interrupts)
    • 中断是由外部事件触发的,例如按下键盘键或磁盘I/O操作。中断是异步的,它们与当前正在执行的程序无关,因此不需要立即处理,但通常会在适当的时机处理。
    • 中断允许操作系统在不打断当前程序执行的情况下,响应外部设备的请求。
    • 常见的中断包括按键输入和磁盘I/O操作。

通过理解监督模式和用户模式之间的区别,以及异常和中断的处理机制,我们可以更好地理解操作系统如何保护系统资源并确保系统的稳定性和响应性。

陷阱处理异常/中断 (Traps Handle Exceptions/Interrupts)

陷阱(Trap)是指操作系统在处理异常和中断时使用的一种机制。陷阱处理程序是专门用于服务中断和异常的代码。

  • 陷阱处理流程
    1. 完成出错指令之前的所有指令:在处理异常时,系统会首先确保所有在出错指令之前的指令都已经完成执行。这是为了保持程序的状态一致性。

    2. 清空出错指令之后的所有指令:系统会将出错指令之后的所有指令清空,这些指令会被转换为空操作(noops)或称为“气泡”(bubbles),甚至出错指令本身也会被清除。这样可以防止错误影响后续指令的执行。

    3. 将执行转移到陷阱处理程序:执行将转移到在监督模式下运行的陷阱处理程序。陷阱处理程序可以选择处理完异常后返回原程序,并重新执行之前失败的指令。对于程序而言,如果陷阱处理程序成功返回,它就像什么都没发生过一样。

五级流水线中的异常处理 (Exceptions in a 5-Stage Pipeline)

在现代处理器中,特别是在具有五级流水线的架构(如RISC-V)中,异常的处理与流水线中的数据冒险类似。

image-20240811110642316

  • 陷阱和流水线冒险的相似性
    • 陷阱的处理方式与流水线冒险非常相似。当处理器检测到异常时,它会停止流水线中的某些操作,并进行适当的调整,以确保系统的稳定性和一致性。
  • 在RISC-V中的异常处理
    • 在RISC-V架构中,异常的原因可以通过当前出错指令及其在流水线中的阶段来推断。例如:
      • PC地址异常:发生在指令获取阶段(IF)。
      • 非法操作码异常:发生在指令解码阶段(ID)。
      • 数据地址异常:发生在数据访问阶段(MEM)。

通过在流水线中不同阶段捕捉异常,处理器能够准确识别并处理不同类型的错误,从而确保程序的正确执行。这种机制在提高处理器性能的同时,也保持了系统的稳定性和安全性。

陷阱处理程序 (The Trap Handler)

陷阱处理程序是操作系统中用于处理异常和中断的重要机制。当一个程序在运行时发生异常或中断,系统将暂时中止该程序的执行,并将控制权转移给陷阱处理程序,以决定下一步的操作。

陷阱处理程序的执行流程

  1. 保存当前程序的状态
    • 在处理异常或中断之前,陷阱处理程序首先会保存当前程序的状态。这包括所有寄存器的内容,以确保在处理完异常后,程序能够继续执行而不丢失任何状态信息。
  2. 确定异常或中断的原因
    • 系统需要识别导致异常或中断的具体原因。这可能是由于非法指令、页面错误、外部中断等不同的原因。
  3. 处理异常/中断
    • 根据确定的原因,陷阱处理程序执行相应的处理操作。根据处理的结果,系统可能会采取以下两种行动之一:

image-20240811111250848

继续执行程序

  1. 恢复程序状态
    • 如果异常或中断被成功处理,且没有严重影响程序的继续执行,陷阱处理程序会恢复程序之前保存的状态。
  2. 将控制权返回给程序
    • 最后,系统将控制权返回给程序,使其继续从中断或异常发生的位置往下执行。这种情况下,对程序而言,发生的异常或中断处理就像什么都没发生一样,程序可以继续正常运行。

终止程序

  1. 释放程序资源
    • 如果异常或中断处理后,系统判断程序不能继续安全运行,陷阱处理程序将会终止该程序。首先,它会释放程序占用的所有资源,例如内存、打开的文件句柄等。
  2. 调度新程序
    • 在终止当前程序后,操作系统会调度其他的程序继续运行,确保系统资源能够被有效利用。

通过理解陷阱处理程序的流程,我们可以更清楚地看到操作系统如何有效地管理程序执行中的意外情况。陷阱处理程序不仅能够帮助系统从异常状态中恢复,还能在必要时安全地终止有问题的程序,防止其对系统造成更大的影响。

处理上下文切换 (Handling Context Switches)

上下文切换是操作系统管理多任务的重要机制,它允许一个处理器“同时”运行多个程序。上下文切换的核心在于操作系统切换处理器的内部状态,使得不同的进程能够在同一处理器上交替运行。

  • 上下文切换的回顾
    • 操作系统通过改变处理器的内部状态来在进程之间切换。这包括保存当前进程的所有寄存器状态(如程序计数器PC、页表寄存器SPTBR),然后加载下一个进程的寄存器状态。
    • 通过这种方式,即使处理器实际上一次只能执行一个进程,但看起来多个进程在“同时”运行。
  • 上下文切换的高级步骤
    • 操作系统设置一个定时器,当定时器到期时,会触发硬件中断。此时,陷阱处理程序保存当前进程的所有寄存器值,包括程序计数器(PC)和页表寄存器(SPTBR),然后加载下一个进程的寄存器状态,最终返回到用户模式继续执行新进程。

处理页面错误 (Handling Page Faults)

页面错误(Page Fault)发生在当程序试图访问的页面不在物理内存中时。这种情况需要操作系统采取特殊措施来处理。

  • 页面错误的回顾
    • 当程序访问的页面不在内存中时,页表中的相应条目有效位为0,这会导致页面错误。此时,操作系统需要从磁盘中加载所需的页面到内存中。
  • 页面错误的处理
    • 页面错误由陷阱处理程序来处理。页面错误处理程序(Page Fault Exception Handler)负责从磁盘加载页面,并更新页表。
    • 如果需要从磁盘中交换页面,操作系统可以在加载页面的过程中执行上下文切换,这样其他进程可以利用CPU时间,从而提高系统效率。
    • 一旦页面加载完成,操作系统会重新执行触发页面错误的指令。
  • 写保护违规
    • 另外,写保护违规也会触发类似的异常,要求操作系统进行处理。这是为了防止未经授权的写操作损坏系统数据。

这些机制使操作系统能够高效地管理内存和进程,确保即使在发生错误或中断时,系统仍然能够保持稳定和高效的运行。

OS: Boot and System Calls

操作系统:启动与系统调用

计算机开机时发生了什么? (What Happens at Boot?)

当计算机启动时,它会从一个预定义的启动地址开始执行,这一过程与模拟器(如Venus)启动时的行为相似。启动过程的核心是加载并启动操作系统,以使系统能够运行用户应用程序。

image-20240811122400679

CPU的启动地址

  • 预定义的启动地址
    • 计算机的CPU在启动时会从一个预定义的地址开始执行指令,这个地址通常存储在只读存储器(ROM)中,或者更现代的系统中会存储在闪存ROM中。例如,在一些系统中,这个地址可能是0x2000。
    • 这些启动指令通常用于初始化硬件系统并准备加载操作系统。它们的主要任务是将固件复制到RAM中,并跳转到该内存位置继续执行操作系统的加载。

启动过程的关键步骤

image-20240811122417619

  1. BIOS (Basic Input Output System) 初始化
    • BIOS是系统启动的第一步,它是固化在ROM中的一组固件程序。BIOS首先会进行基本的硬件自检(POST),然后寻找存储设备(如硬盘、SSD、USB设备)来加载引导加载程序(Bootloader)。
  2. 引导加载程序 (Bootloader)
    • BIOS找到存储设备后,会从该设备的第一个扇区加载引导加载程序。这通常是一个小型程序,负责加载操作系统内核到内存中,并将控制权转移给内核。常见的引导加载程序如GRUB允许选择不同的操作系统或内核版本进行启动。
  3. 操作系统内核启动
    • 引导加载程序将操作系统内核加载到内存后,系统开始执行内核代码。操作系统内核负责初始化系统的各个子系统和驱动程序,使得硬件设备(如键盘、显示器、网络接口等)能够正常工作。
  4. Init进程的启动
    • 在操作系统内核启动并完成基本初始化后,init进程是系统启动的第一个用户级进程。init进程负责启动系统中的关键服务和守护进程,如网络服务、日志服务、图形用户界面(GUI)等,最终准备好用户交互环境(如终端或桌面环境)。

系统调用与应用程序的启动 (System Calls and Launching Applications)

系统调用(syscall)是用户程序与操作系统内核进行交互的关键机制。它允许用户程序请求操作系统提供的各种服务,如文件操作、进程控制、设备访问等。

系统调用的功能

  • 用户程序与内核交互
    • 系统调用的作用类似于函数调用,但执行环境从用户模式切换到内核模式。例如,用户程序通过系统调用请求操作系统执行特定任务,如文件读写、内存分配(malloc)、进程管理等。
    • 在RISC-V架构中,系统调用通过特殊指令(如ecall)触发。这些指令使处理器从用户模式切换到内核模式,内核处理系统调用并将结果返回给用户程序。

应用程序的启动过程

  • Shell进程与fork系统调用
    • 当用户在Shell(命令行解释器)中输入命令来启动一个新应用时,Shell进程会通过fork系统调用创建一个新进程。这时,操作系统内核会创建该进程的一个副本。
    • 新进程会通过exec系统调用加载指定的程序文件,将其代码和数据加载到内存中,并将控制权转移到该程序的main函数的起始地址。
  • 进程的执行与等待
    • 新进程启动后,Shell进程通常会调用waitjoin系统调用来等待新进程的完成。当新进程执行完毕并返回后,Shell进程会继续执行用户的其他命令。
  • 系统调用与执行模式的切换
    • 在应用程序的整个生命周期中,系统调用是频繁发生的。例如,当应用程序需要访问文件系统或进行网络通信时,它会通过系统调用请求内核的服务。在这些操作中,CPU会在用户模式和内核模式之间进行频繁切换,确保操作系统能够安全、高效地管理系统资源。

通过理解启动过程和系统调用的工作原理,可以更好地理解操作系统如何管理硬件资源、执行用户程序以及保持系统的稳定性和安全性。


© 2024 LzzsSite
该笔记由 LzzsG 基于 CS 61C / Garcia, Yan 的作品创作,采用的是 CC BY-NC-SA 许可。