首页 > 系统相关 >操作系统实践之路——五、初始化(2.Linux初始化)

操作系统实践之路——五、初始化(2.Linux初始化)

时间:2024-03-19 19:30:27浏览次数:30  
标签:bin 初始化 操作系统 img 文件 vmlinux BIOS 内核 Linux

文章目录

前言

​ 本章节将讨论一下Linux如何去做初始化。

一、全局流程

​ 在机器加电后,BIOS 会进行自检,然后由 BIOS 加载引导设备中引导扇区。在安装有 Linux 操作系统的情况下,在引导扇区里,通常是安装的 GRUB 的一小段程序(安装 windows 的情况则不同)。最后,GRUB 会加载 Linux 的内核映像 vmlinuz,如下图所示:

在这里插入图片描述

二、从BIOS到GRUB

​ 内存在断电后就没法保存数据了,那 BIOS 又是如何启动的呢?硬件工程师设计 CPU 时,硬性地规定在加电的瞬间,强制将 CS 寄存器的值设置为 0XF000,IP 寄存器的值设置为 0XFFF0。

​ 这样一来,CS:IP 就指向了 0XFFFF0 这个物理地址。在这个物理地址上连接了主板上的一块小的 ROM 芯片。这种芯片的访问机制和寻址方式和内存一样,只是它在断电时不会丢失数据,在常规下也不能往这里写入数据,它是一种只读内存BIOS 程序就被固化在该 ROM 芯片里。

​ 现在,CS:IP 指向了 0XFFFF0 这个位置,正是 BIOS 程序的入口地址。这意味着 BIOS 正式开始启动。

​ BIOS 一开始会初始化 CPU,接着检查并初始化内存,然后将自己的一部分复制到内存,最后跳转到内存中运行。BIOS 的下一步就是枚举本地设备进行初始化,并进行相关的检查,检查硬件是否损坏,这期间 BIOS 会调用其它设备上的固件程序,如显卡、网卡等设备上的固件程序。当设备初始化和检查步骤完成之后,BIOS 会在内存中建立中断表和中断服务程序,这是启动 Linux 至关重要的工作,因为 Linux 会用到它们。

​ 具体是怎么操作的呢?BIOS 会从内存地址(0x00000)开始用 1KB 的内存空间(0x00000~0x003FF)构建中断表,在紧接着中断表的位置,用 256KB 的内存空间构建 BIOS 数据区(0x00400~0x004FF),并在 0x0e05b 的地址加载了 8KB 大小的与中断表对应的中断服务程序。中断表中有 256 个条目,每个条目占用 4 个字节,其中两个字节是 CS 寄存器的值,两个字节是 IP 寄存器的值。每个条目都指向一个具体的中断服务程序。

​ Linux 通常是从硬盘中启动的。硬盘上的第 1 个扇区(每个扇区 512 字节空间),被称为 MBR(主启动记录),其中包含有基本的 GRUB 启动程序和分区表,安装 GRUB 时会自动写入到这个扇区,当 MBR 被 BIOS 装载到 0x7c00 地址开始的内存空间中后,BIOS 就会将控制权转交给了 MBR。在当前的情况下,其实是交给了 GRUB。

​ 到这里,BIOS 到 GRUB 的过程结束。

三、GRUB是如何启动的

​ GRUB 的加载分成了多个步骤,同时 GRUB 也分成了多个文件,其中有两个重要的文件 boot.img 和 core.img

​ 其中,boot.img 被 GRUB 的安装程序写入到硬盘的 MBR 中,同时在 boot.img 文件中的一个位置写入 core.img 文件占用的第一个扇区的扇区号。而 core.img 文件是由 GRUB 安装程序根据安装时环境信息,用其它 GRUB 的模块文件动态生成。如下图所示:

在这里插入图片描述

​ 如果是从硬盘启动的话,core.img 中的第一个扇区的内容就是 diskboot.img 文件。diskboot.img 文件的作用是,读取 core.img 中剩余的部分到内存中。

​ 由于这时 diskboot.img 文件还不识别文件系统,所以我们将 core.img 文件的全部位置,都用文件块列表的方式保存到 diskboot.img 文件中。这样就能确保 diskboot.img 文件找到 core.img 文件的剩余内容,最后将控制权交给 kernel.img 文件。

​ 因为这时 core.img 文件中嵌入了足够多的功能模块,所以可以保证 GRUB 识别出硬盘分区上文件系统,能够访问 /boot/grub 目录,并且可以加载相关的配置文件和功能模块,来实现相关的功能,例如加载启动菜单、加载目标操作系统等。

​ 正因为 GRUB2 大量使用了动态加载功能模块,这使得 core.img 文件的体积变得足够小。而 GRUB 的 core.img 文件一旦开始工作,就可以加载 Linux 系统的 vmlinuz 内核文件了。

四、详解vmlinuz文件结构

​ 我们在 /boot 目录下会发现 vmlinuz 文件,其实它是由 Linux 编译生成的 bzImage 文件复制而来的。

​ 生成 bzImage 文件需要三个依赖文件:setup.bin、vmlinux.bin,linux/arch/x86/boot/tools 目录下的 build。让我们挨个来分析一下。

​ 其实,build 只是一个 HOSTOS(正在使用的 Linux)下的应用程序,它的作用就是将 setup.bin、vmlinux.bin 两个文件拼接成一个 bzImage 文件,如下图所示:

在这里插入图片描述

​ 剩下的就是搞清楚 setup.bin、vmlinux.bin 这两个文件的的结构,先来看看 setup.bin 文件,setup.bin 文件是由 objcopy 命令根据 setup.elf 生成的。

​ setup.bin 文件正是由 /arch/x86/boot/ 目录下一系列对应的程序源代码文件编译链接产生,其中的 head.S 文件和 main.c 文件格外重要。

​ vmlinux.bin 文件依赖于 linux/arch/x86/boot/compressed/ 目录下的 vmlinux 目标

​ vmlinux 文件就是编译整个 Linux 内核源代码文件生成的,Linux 的代码分布在各个代码目录下,这些目录之下又存在目录,Linux 的 kbuild(内核编译)系统,会递归进入到每个目录,由该目录下的 Makefile 决定要编译哪些文件。

​ 在编译完具体文件之后,就会在该目录下,把已经编译了的文件链接成一个该目录下的 built-in.o 文件,这个 built-in.o 文件也会与上层目录的 built-in.o 文件链接在一起。

​ 再然后,层层目录返回到顶层目录,所有的 built-in.o 文件会链接生成一个 vmlinux 文件,这个 vmlinux 文件会通过前面的方法转换成 vmlinux.bin 文件。但是请注意,vmlinux.bin 文件它依然是 ELF 格式的文件。

​ 最后,工具软件会压缩成 vmlinux.bin.gz 文件,这里我们以 gzip 方式压缩。

​ piggy.S 非常简单,使用汇编指令 incbin 将压缩的 vmlinux.bin.gz 毫无修改地包含进来。

​ 除了包含了压缩的 vmlinux.bin.gz 内核映像文件外,piggy.S 中还定义了解压 vmlinux.bin.gz 时需要的各种信息,包括压缩内核映像的长度、解压后的长度等信息。

这些信息和 vmlinux.bin.gz 文件,它们一起生成了 piggy.o 文件,然后 piggy.o 文件和 ( v m l i n u x − o b j s − y ) (vmlinux-objs-y) (vmlinux−objs−y)(efi-obj-y) 中的目标文件一起链接生成,最终生成了 linux/arch/x86/boot/compressed 目录下的 vmlinux。

五、流程梳理-1

操作系统的启动分为两个阶段:引导boot和启动startup,本节主要还是boot过程:
BIOS->GRUG1->GRUB1.5->GRUB2->Linux内核【环境硬盘引导、MBR分区】

1、按电源键,系统加电

2、主板通电
CPU加电时,会默认设置[CS:IP]为[0XF000:0XFFF0],根据实模式下寻址规则,CPU指向0XFFFF0
这个地址正是BIOS启动程序位置,而BIOS访问方式与内存一致,所以CPU可以直接读取命令并执行

3、BIOS执行
3.1、BIOS首先执行POST自检,包括主板、内存、外设等,遇到问题则报警并停止引导

3.2、BIOS对设备执行简单的初始化工作

3.3、BIOS 会在内存中:
建立中断表(0x00000~0x003FF)
构建 BIOS 数据区(0x00400~0x004FF)
加载了中断服务程序(0x0e05b~0x1005A)

3.4、BIOS根据设备启动顺序,依次判断是否可以启动
比如先检查光驱能否启动
然后依次检查硬盘是否可以启动【硬盘分区的时候,设置为活动分区】

4、硬盘引导
4.1、先说下寻址方式,与扇区编号的事情
最传统的磁盘寻址方式为CHS,由三个参数决定读取哪个扇区:磁头(Heads)、柱面(Cylinder)、扇区(Sector)
磁头数【8位】,从0开始,最大255【微软DOS系统,只能用255个】,决定了读取哪个盘片的哪个面【一盘两面】
柱面数【10位】,从0开始,最大1023【决定了读取哪个磁道,磁道无论长短都会划分为相同扇区数】
扇区数【6位】,从1开始,最大数 63【CHS中扇区从1开始,而逻辑划分中扇区从0开始,经常会造成很多误解】
每个扇区为512字节

4.2、然后说下引导方式
BIOS在发现硬盘启动标志后,BIOS会引发INT 19H中断
这个操作,会将MBR【逻辑0扇区】,也就是磁盘CHS【磁头0,柱面0,扇区1】,读取到内存[0:7C00h],然后执行其代码【GRUB1阶段】,至此BIOS把主动权交给了GRUB1阶段代码
MBR扇区为512字节,扇区最后分区表至少需要66字节【64字节DPT+2字节引导标志】,所以这段代码最多只能有446字节,grub中对应的就是引导镜像boot.img
boot.img的任务就是,定位,并通过BIOS INT13中断读取1.5阶段代码,并运行

5、Grub1.5阶段
5.1、先说一下MBR GAP
据说微软DOS系统原因,第一个分区的起始逻辑扇区是63扇区,在MBR【0扇区】和分布表之间【63扇区】,存在62个空白扇区,共 31KB。
Grub1.5阶段代码就安装在这里。

5.2、上面提到,boot.img主要功能就是找到并加载Grub1.5阶段代码,并切换执行。
Grub1.5阶段代码是core.img,其主要功能就是加载文件系统驱动,挂载文件系统, 位加载并运行GRUB2阶段代码。
core.img包括多个映像和模块:
diskboot.img【1.5阶段引导程序】,存在于MBR GAP第一个扇区;【这里是硬盘启动的情况,如果是cd启动就会是cdboot.img】
lzma_decompress.img【解压程序】
kernel.img【grub核心代码】,会【压缩存放】
biosdisk.mod【磁盘驱动】、Part_msdos.mod【MBR分区支持】、Ext2.mod【EXT文件系统】等,会【压缩存放】

其实boot.img只加载了core.img的第一个扇区【存放diskboot.img】,然后控制权就交出去了,grub阶段1代码使命结束。
diskboot.img知道后续每个文件的位置,会继续通过BIOS中断读取扇区,加载余下的部分并转交控制权,包括:
加载lzma_decompress.img,从而可以解压被压缩的模块
加载kernel.img,并转交控制权给kernel.img
kernel.img的grub_main函数会调用grub_load_modules函数加载各个mod模块
加载各个mod后,grub就支持文件系统了,访问磁盘不需要再依靠BIOS的中断以扇区为单位读取了,终于可以使用文件系统了

6、GRUB2阶段
现在grub就能访问boot/grub及其子目录了
kernel.img接着调用grub_load_normal_mode加载normal模块
normal模块读取解析文件grub.cfg,查看有哪些命令,比如发现了linux、initrd这几个命令,需要linux模块
normal模块会根据command.lst,定位并加载用到的linux模块【一般在/boot/grub2/i386-pc目录】
当然,同时需要完成初始化显示、载入字体等工作
接下来Grub就会给咱们展示启动菜单了

7、选择启动菜单
7.1、引导协议
引导程序加载内核,前提是确定好数据交换方式,叫做引导协议,内核中引导协议相关部分的代码在arch/x86/boot/header.S中,内核会在这个文件中标明自己的对齐要求、是否可以重定位以及希望的加载地址等信息。同时也会预留空位,由引导加载程序在加载内核时填充,比如initramfs的加载位置和大小等信息。
引导加载程序和内核均为此定义了一个结构体linux_kernel_params,称为引导参数,用于参数设定。Grub会在把控制权移交给内核之前,填充好linux_kernel_params结构体。如果用户要通过grub向内核传递启动参数,即grub.cfg中linux后面的命令行参数。Grub也会把这部分信息关联到引导参数结构体中。

7.2、开始引导
Linux内核的相关文件位于/boot 目录下,文件名均带有前缀 vmlinuz。
咱们选择对应的菜单后,Grub会开始执行对应命令,定位、加载、初始化内核,并移交到内核继续执行。
调用linux模块中的linux命令,加载linux内核
调用linux模块中的initrd命令,填充initramfs信息,然后Grub会把控制权移交给内核。
内核此时开始执行,同时也就可以读取linux_kernel_params结构体的数据了
boot阶段结束,开始进入startup阶段。

六、内核初始化从_start开始

​ 下面,我们先从 setup.bin 文件的入口 _start 开始,了解启动信息结构,接着由 16 位 main 函数切换 CPU 到保护模式,然后跳入 vmlinux.bin 文件中的 startup_32 函数重新加载段描述符。如果是 64 位的系统,就要进入 startup_64 函数,切换到 CPU 到长模式,最后调用 extract_kernel 函数解压 Linux 内核,并进入内核的 startup_64 函数,由此 Linux 内核开始运行。

​ vmlinux.bin.gz 文件则是由编译的 Linux 内核所生成的 elf 格式的 vmlinux 文件,去掉了文件的符号信息和重定位信息后,压缩得到的。

​ CPU 是无法识别压缩文件中的指令直接运行的,必须先进行解压后,然后解析 elf 格式的文件,把其中的指令段和数据段加载到指定的内存空间中,才能由 CPU 执行。

​ 这就需要用到前面的 setup.bin 文件了,_start 正是 setup.bin 文件的入口。

​ GRUB 将 vmlinuz 的 setup.bin 部分读到内存地址 0x90000 处,然后跳转到 0x90200 开始执行,恰好跳过了前面 512 字节的 bootsector,从 _start 开始。

16 位的 main 函数,各种初始化后,会跳到0x100000,GRUB 会把 vmlinuz 中的 vmlinux.bin 部分,放在 1MB 开始的内存空间中。通过这一跳转,正式进入 vmlinux.bin 中。

startup_32 函数,重新加载段描述符,之后计算 vmlinux.bin 文件的编译生成的地址和实际加载地址的偏移,然后重新设置内核栈,检测 CPU 是否支持长模式,接着再次计算 vmlinux.bin 加载地址的偏移,来确定对其中 vmlinux.bin.gz 解压缩的地址。

​ 如果 CPU 支持长模式的话,就要设置 64 位的全局描述表,开启 CPU 的 PAE 物理地址扩展特性。再设置最初的 MMU 页表,最后开启分页并进入长模式,跳转到 startup_64

startup_64 函数,初始化长模式下数据段寄存器,确定最终解压缩地址,然后拷贝压缩 vmlinux.bin 到该地址,跳转到 decompress_kernel 地址处,开始解压 vmlinux.bin.gz

kernel startup_64,这是内核中开始函数,最后就是调用x86_64_start_kernel 函数,然后就是start_kernel函数了

start_kernel 函数

各种初始化,start_kernel 函数执行完成,Linux 内核就具备了向应用程序提供一系列功能服务的能力。

​ 最后执行了arch_call_rest_init函数,第一个进程

七、流程梳理-2

Grub在/boot目录下找到的linux内核,是bzImage格式
1、bzImage格式生成:
1.1、head_64.S+其他源文件->编译-> vmlinux【A】
1.2、objcopy工具拷贝【 拷贝时,删除了文件中“.comment”段,符号表和重定位表】->vmlinux.bin【A】
1.3、gzib压缩->vmlinux.bin.gz
1.4、piggy打包,附加解压信息->piggy.o->其他.o文件一起链接->vmlinux【B】
1.5、objcopy工具拷贝【 拷贝时,删除了文件中“.comment”段,符号表和重定位表】->vmlinux【B】
1.6、head.S +main.c+其他->setup.bin
1.7、setup.bin+vmlinux.bin【B】->bzImage合并->bzImage

2、GRUB加载bzImage文件
2.1、会将bzImage的setup.bin加载到内存地址0x90000 处
2.2、把vmlinuz中的vmlinux.bin部分,加载到1MB 开始的内存地址

3、GRUB会继续执行setup.bin代码,入口在header.S【arch/x86/boot/header.S】
GRUB会填充linux内核的一个setup_header结构,将内核启动需要的信息,写入到内核中对应位置,而且GRUB自身也维护了一个相似的结构。
Header.S文件中从start_of_setup开始,其实就是这个setup_header的结构。
此外, bootparam.h有这个结构的C语言定义,会从Header.S中把数据拷贝到结构体中,方便后续使用。

4、GRUB然后会跳转到 0x90200开始执行【恰好跳过了最开始512 字节的 bootsector】,正好是head.S的_start这个位置;

5、在head.S最后,调用main函数继续执行

6、main函数【 arch/x86/boot/main.c】【16 位实模式】
6.1、拷贝header.S中setup_header结构,到boot_params【arch\x86\include\uapi\asm\bootparam.h】
6.2、调用BIOS中断,进行初始化设置,包括console、堆、CPU模式、内存、键盘、APM、显卡模式等
6.3、调用go_to_protected_mode进入保护模式

7、 go_to_protected_mode函数【 arch/x86/boot/pm.c】
7.1、安装实模式切换钩子
7.2、启用1M以上内存
7.3、设置中断描述符表IDT
7.4、设置全局描述符表GDT
7.4、protected_mode_jump,跳转到boot_params.hdr.code32_start【保护模式下,长跳转,地址为 0x100000】

8、恰好是vmlinux.bin在内存中的位置,通过这一跳转,正式进入vmlinux.bin

9、startup_32【 arch/x86/boot/compressed/head64.S】
全局描述符GDT
加载段描述符
设置栈
检查CPU是否支持长模式
开启PAE
建立MMU【4级,4G】
开启长模式
段描述符和startup_64地址入栈
开启分页和保护模式
弹出段描述符和startup_64地址到CS:RIP中,进入长模式

10、 startup_64【 arch/x86/boot/compressed/head64.S】
初始化寄存器
初始化栈
调准给MMU级别
压缩内核移动到Buffer最后
调用.Lrelocated

11、.Lrelocated
申请内存
被解压数据开始地址
被解压数据长度
解压数据开始地址
解压后数据长度
调用 extract_kernel解压内核

12、extract_kernel解压内核【 arch/x86/boot/compressed/misc.c】
保存boot_params
解压内核
解析ELF,处理重定向, 把 vmlinux 中的指令段、数据段、BSS 段,根据 elf 中信息和要求放入特定的内存空间
返回了解压后内核地址,保存到%rax

13、返回到.Lrelocated继续执行
跳转到%rax【解压后内核地址】,继续执行
解压后的内核文件,入口函数为【arch/x86/kernel/head_64.S】

14、SYM_CODE_START_NOALIGN(startup_64)【arch/x86/kernel/head_64.S】
SMP 系统加电之后,总线仲裁机制会选出多个 CPU 中的一个 CPU,称为 BSP,也叫第一个 CPU。它负责让 BSP CPU 先启动,其它 CPU 则等待 BSP CPU 的唤醒。
第一个启动的 CPU,会跳转 secondary_startup_64 函数中 1 标号处,对于其它被唤醒的 CPU 则会直接执行 secondary_startup_64 函数。

15、secondary_startup_64 函数【arch/x86/kernel/head_64.S】
各类初始化工作,gdt、描述符等
跳转到initial_code,也就是x86_64_start_kernel

16、 x86_64_start_kernel【 arch/x86/kernel/head64.c】
各类初始化工作,清理bss段,清理页目录,复制引导信息等
调用x86_64_start_reservations

17、x86_64_start_reservations【 arch/x86/kernel/head64.c】
调用start_kernel();

18、start_kernel【 init/main.c】
各类初始化:ARCH、日志、陷阱门、内存、调度器、工作队列、RCU锁、Trace事件、IRQ中断、定时器、软中断、ACPI、fork、缓存、安全、pagecache、信号量、cpuset、cgroup等等
调用 arch_call_rest_init,调用到rest_init

19、rest_init【 init/main.c】
kernel_thread,调用_do_fork,创建了kernel_init进程,pid=1 . 是系统中所有其它用户进程的祖先
kernel_thread,调用_do_fork,创建了 kernel_thread进程,pid=2, 负责所有内核线程的调度和管理
【最后当前的进程, 会变成idle进程,pid=0】

20、kernel_init
根据内核启动参数,调用run_init_process,创建对应进程
调用try_to_run_init_process函数,尝试以 /sbin/init、/etc/init、/bin/init、/bin/sh 这些文件为可执行文件建立init进程,只要其中之一成功就可以

调用链如下:
try_to_run_init_process
run_init_process
kernel_execve
bprm_execve
exec_binprm
search_binary_handler-》依次尝试按各种可执行文件格式进行加载,而ELF的处理函数为 load_elf_binary
load_elf_binary
start_thread
start_thread_common,会将寄存器地址,设置为ELF启动地址
当从系统调用返回用户态时,init进程【1号进程】,就从ELF执行了

到此为止,系统的启动过程结束。

Linux启动流程:

在这里插入图片描述

思维导图:

在这里插入图片描述

参考资料

以上内容是我学习彭东老师的《操作系统实战45讲》后所进行的一个笔记记录,如有错误,还请各位大佬多多指教。

我主要参考了以下资料,十分感谢:

操作系统实战45讲——彭东老师

评论区大佬——neohope、艾恩凝等

标签:bin,初始化,操作系统,img,文件,vmlinux,BIOS,内核,Linux
From: https://blog.csdn.net/XieHYBlog/article/details/136846661

相关文章

  • 从 Linux 内核角度探秘 JDK MappedByteBuffer
    本文涉及到的内核源码版本为:5.4,JVM源码为:OpenJDK17,RocketMQ源码版本为:5.1.1在之前的文章《一步一图带你深入剖析JDKNIOByteBuffer在不同字节序下的设计与实现》中,笔者为大家详细剖析了JDKBuffer的整个设计体系,从总体上来讲,JDKNIO为每一种Java基本类型定义了对......
  • Linux TCP/UDP CS模型
    LinuxTCP/UDPCS模型目录LinuxTCP/UDPCS模型TCPServer/TCPClientUDPServer/UDPClientTCPServer/TCPClient在C语言中实现一个TCP服务器时,使用select函数可以帮助我们同时监控多个文件描述符(包括socket)的状态,从而实现非阻塞的I/O操作。以下是一个简单的TCP服务器示例,它......
  • linux命令 --简化版--快速上手
    linux命令--简化版--快速上手系统信息arch显示机器的处理器架构(1)uname-m显示机器的处理器架构(2)uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMB[IOS](https://www.2cto.com/kf/yidong/iphone/)/DMI)hdparm-i/dev/hda罗列一个磁盘的......
  • linux--shell 一般把脚本文件放到哪里
    linux--shell一般把脚本文件放到哪里shell在Linux系统中,脚本文件的存放位置取决于其用途和类型。以下是几个常见的脚本存放位置:系统级脚本:这些脚本通常与系统管理、初始化、配置或权限认证相关。/usr/bin:主要存放所有用户都可用的系统程序,即普通的基本命令。/etc:存放系统......
  • linux下永久添加静态路由-不同
    linux下永久添加静态路由-不同添加路由的命令:1,routeaddrouteadd-net192.56.76.0netmask255.255.255.0deveth0#添加一条静态路由routeadddefaultgw192.168.0.1#添加默认路由routedel-net192.168.1.0/24gw192.168.0.1#删除一条路由route-n#查看路由表2,ipr......
  • linux-实现日志分析--python
    linux-实现日志分析--python涉及到的主要python包和系统命令:1.datetime#用于处理时间2.subprocess#用于调用命令行工具3.tail-flogFile#获取logFile新增内容废话不多说,下面说一下场景需求和具体解决方案。1.[场景需求]一个区块链项目,在项目测试过程中,通过日志发......
  • 操作系统
    进程管理-进程状态三态与五态 进程管理-前趋图进程的同步与互斥互斥:同类资源竞争关系同步:进程间的协作关系进程管理-pv操作进程管理-死锁问题216+1026*5131页面置换算法:最优算法(理想型,不现实)随机算法先进先出(FIFO)算法:有可能产生抖动......
  • Linux系统编程
    文章目录1.文件里面存放了5行数据,使用追加模式打开文件,打印前3行,并写入一行,期间使用ftell打印当前位置。2.修改文件的权限,注意必须使用命令行参数。3.使用两种方法打印当前目录。4.传递一个路径名,还有一个文件名,搜索对应路径下是否有该文件,有就打印显示该文件的绝对......
  • 操作系统内存管理笔记
    单级页表分页储存页表页表中的页表项是连续存放的,因此页号可以是隐含的,不需要占用空间页表中的块号所记录的只是内存块号,而非内存块的起始地址案例一假设某系统物理内存大小为4GB,页面大小为4KB,则每个页表项至少应该为多少字节解答:由题目可知,内存块大小=页......
  • 小白如何在服务器上配置环境(连接Linux服务器和anaconda3安装)
    由于服务器账号原因,悲惨的博主只能从头开始配置环境,但是博主脑子的缓存比较小,一周前配好的现在就忘掉了,为了防止再发生这种问题,博主从头开始记录一下。(连接Linux服务器和anaconda3安装)第一步连接到服务器1.安装插件(ReomoteSSH),安装好了之后点击左下角的><,点击“连接到主机.........