注明:这些实验在完成整体实验的过程中,会先放到csdn做暂时存储(因为这台破机子没法装md的笔记软件),偏向于讲解实验如何完成,以及对于代码的一些解释,相当与在这里做一些笔记和记录。
因为我之前在检索关于实验的教程的时候,会发现其实很多学长学姐留下的资料基本都是偏报告的,不过嘛熟悉我的兄弟们肯定都知道,我更习惯把自己的过程给手把手的教出来,当然这不是鼓励大家去照抄de。。。。能在某个特殊环节让大家找到方向,或许就是我写这些东西的意义。
总的来说,也是菜菜一个,课设也是靠着各位学长留下的”轮子“慢慢摸索拼凑的,但是我想整理一下或许能让同学和学弟学妹们少走一些弯路。如果有写的不对的地方,或者还有什么要了解的,欢迎直接私信我,我最迟会在半天内回复de。
1.关于nachos:
nachos是一个“模拟的”操作系统,换句话说这个东西并不是像linux,window等等可以直接安装在机器上,而是在模拟,就类似我们的模拟器,本质上是一个教学用的"操作系统"。在我们学校的这个版本中,nachos是使用一些cpp的类来模拟各个硬件,软件以及通信设施的,我们需要做的就是对于一些方法进行改写的和拓展。
关于文档的话,我还专门去stack overflow上问了一下,人家给我找来了百科。。。。。
如果懂得使用魔法,可以在google上搜索“南开大学 操作系统 Nachos”等等关键字,应该可以搜索到一个南开大学整理的nachos文档,他们使用的集成工具ide有点诡异,不过剩下的没啥区别,如果有需要可以看一下他们的文档,里面有对nachos的详细解释,还有一些可能用的上的操作的步骤。
这篇博客的话主要是整理一下如何使用nachos,以及如何进行一些初步的改写,顺带作为自己实验报告的一个准备材料,打算全写完就正式报告了。
2.如何安装nachos:
在安装nachos之前,我觉得你需要准备一下以下的工作:
1.保证自己电脑/虚拟机上有c/c++的编译器,也就是gcc/g++这样。
2.老师发过来的文件中有两个tar.gz文件,这个就是核心了。
另外要注意,这篇博客无法解决你对上述操作的特殊要求,比如虚拟机和主机如何传递文件,虚拟机连不上网络,虚拟机怎么崩了,虚拟机怎么下载之类的。。。。
我是实体机器上装的linux,无法解决大家的问题,见谅。。。。
2.0,关于64位机器需要注意的问题:
由于大多数机器都是64位的,所以可能会遇到32位gcc无法进行编译,所以在进行如下操作之前,请确保以下操作正常执行:
sudo apt install gcc-multilib g++-multilib
2.1,nachos的安装:
首先我们需要这两个文件
在老师给的文件里是可以找到这两个文件的。
nachos的安装其实很简单,其实就是把文件夹解压到一个自己比较熟悉的文件夹下面即可,对于大多数虚拟机来说,你可以直接使用图形化界面来进行直接解压。当然linux用户还是习惯直接用指令处理:
tar -xzvf nachos文件压缩包
解压以后是这些文件:
关于这些文件是什么,我们将在后面进行解释,这就是获取nachos成功了
2.2: 交叉编译器的安装
交叉编译器指的是MIPS工具, 由于nachos和linux的指令集不同,所以代码可能需要这个工具才能正常跑起来。这个工具的压缩包就是上图中所演示的第二个文件压缩包。
不过要注意一个问题,MIPS工具需要解压到特定的usr/local的文件夹下,而这个文件夹需要一点点root权限,比如我这种实体机器基本就完蛋了。
因此办法是,首先使用cd指令进入这个系统目录下,然后吧MIPS工具远程解压到这个文件夹下面
这里默认压缩包在~/下
cd /usr/local
sudo tar -xzvf ~/文件名称
这就基本结束了前期准备
2.3: 关于环境的验证
安装完这两个内容以后,需要进行验证,证明你的环境配置是有效果的。
进入项目目录下的code/threads文件夹,我们以线程部分单独运行的结果来判断是否安装完毕
注意先进入这个目录再说!
进入该目录以后执行如下操作,这几个操作的目的和结果是什么我们以后再说
make clean # 清除上一次makefile编译的结果
make # 根据makefile文件执行编译
# 执行该目录下生成的一个可执行文件,名为nachos
./nachos
输入输出结果是一些操作系统有关的信息,那么就代表你的nachos环境安装成功了,类似这样子
3.关于项目文件的解析
其实想写这个博客的目的就是这个,这个虽然是实验部分,但是看之前的学长学界们似乎很少有对这个进行直接解释的,在这里希望能整理一下自己的思路,也解答一下大家的疑惑。
3.1关于源文件的部分
源文件其实就这三个东西,c++example是一些样例,用来给一些没怎么写过cpp的c程序员来过渡的,我相信至少软院的大家是不需要这些东西的,因为大家要么是自幼学习c,要么是经过了各个课程毒打硬是学会了写cpp.
doc则是nachos的作者写的一些文档之类的东西,比如经典的readme,其实也没啥用,有兴趣的可以研读一下,我们重点需要关注的是code这个文件夹,在这个文件夹中是nachos的核心代码,以及一些需要我们改写的东西:
首先先解释一下上图中的所有文件夹:
1. bin: Nachos用户实现MIPS程序目标码变化的实用程序以及源码,
2. machine: MIPS虚拟机模拟系统代码
3. network: 网络管理部分,课设部分没有提及,不用管
4. filesys: 文件管理部分系统代码
5. threads: 线程管理部分系统代码
6. userprog: 用户程序部分系统代码
7. test: 一些测试用的程序
8. demo: demo0是演示Makefile的例子, demo1是使用信号两解决生产者消费者同步的例子,可以做个参考
9. lab2-lab7: 实验需要对应的代码部分,也是需要我们作出修改的地方,对应了后面的六个实验,我们需要作出改变的也只有这个文件夹里的内容,其他文件夹则是nachos的核心部分!
另外, bin,test,还有剩下的文件,因为其内部MakeFile的设置不同,调用的编译器也不一样,这里就不多解释了,估计到后面也用不上这一点
另外一个很重要的事情就是最下面的四个文件
两个文件Makefile.dep和Makefile.common,分别是要用到的两个编译用的配置文件,这个会在下面讲到。
但是另外两个后缀为orig的文件,老师给的手册里并没有说明这是什么文件,个人认为这是original,也就是用来对照最原始的版本,防止某个没备份的小朋友吧自己的配置文件全改错了(比如我/。。。。)
3.2关于makefile
makefile是一种cpp项目的启动文件,其作用类似我们平时写js的脚本程序
内部的文本语法,是这样子的,用来协助我们执行一些程序
在这个虚拟的操作系统项目中,makefile一共有四种类型,makefile(dep,common,local),以及最终的组件内总和Makefile,大致结构如下
common:这个是一些全局的配置,无需我们进行修改
dep:关于硬件的依赖,也算是一种无需修改的全局配置
上面的两个是直接在code目录下,不属于某个组建,属于通用配置,不能修改。
其中对于内部的解析如下,如果不想了解可以直接跳过这个代码段
dep中的内容
# This is part of a GNU-Makefile, to specify system-dependent
# parts of the Makefile enviroment.
# 系统相关的一部分
# This gets included as part of the GNU-Makefile used in each of
# the subdirectories.
# 这个的文件应该在每个子部分中都作为一个引入被包含进来
# Waterloo modifications should make picking up the right machine
# definition automatic. You should not have to edit this file for
# either MIPS machines (cantor.math), or SPARC (descartes, napier,
# cayley, ...).
# 建议不要编辑此文件,无论什么情况
ifndef MAKEFILE_DEP # 这段代码的目的是检查是否存在一个名为MAKEFILE_DEP的对象
define MAKEFILE_DEP # 如果不存在就定义一个,并且赋值为yes
yes # 这个变量在这里推测是控制整个条件进行执行的
endef # 别的哥们也不敢多说了,nachos真的是不懂啊
# These definitions may change as the software is updated.
# Some of them are also system dependent
# 以下这些定义会随着软件的变化而变化
# 这里主要是一些变量 和别名
CPP=/lib/cpp # c程序的与处理器
CC = g++ # c程序的编译程序
LD = g++ # 链接器的路径
AS = as # 汇编器的路径
uname = $(shell uname) # 获取当前操作系统的名称
mips_arch = dec-mips-ultrix # 存储MIPS架构,暂时不知道是干啥的
# DEC MIPS, Ultrix # 这一大段代码就是判断操作系统的。。。
ifeq ($(uname),ULTRIX) # 往下很多都是处理硬件的东西,先不用看了
HOST := -DHOST_MIPS
arch = $(mips_arch)
CPPFLAGS = -P $(INCDIR) $(HOST)
ifdef MAKEFILE_TEST
LDFLAGS = -T script -N
endif
endif
# SUN SPARC, Sun 4.xx
ifeq ($(uname),SunOS)
HOST := -DHOST_SPARC -DHOST_IS_BIG_ENDIAN
arch = sun-sparc-sunos
CPPFLAGS = $(INCDIR) $(HOST)
ifdef MAKEFILE_TEST
GCCDIR = /software/gcc_nachos/bin/decstation-ultrix-
LDFLAGS = -T script -N
ASFLAGS = -mips2
endif
endif
# HP PA-RISC, HP_UX
# NOTE: I don't have access to an HP so I don't know what
# uname really outputs here...
ifeq ($(uname),HpUX)
HOST = -DHOST_SNAKE -DHOST_IS_BIG_ENDIAN
arch = parisc-hpux
endif
# 386, 386BSD Unix, or NetBSD Unix (available via anon ftp
# from agate.berkeley.edu)
ifeq ($(uname),Linux)
HOST_LINUX=-linux
HOST = -DHOST_i386 -DHOST_LINUX
CPP=/lib/cpp
CPPFLAGS = $(INCDIR) -D HOST_i386 -D HOST_LINUX
arch = unknown-i386-linux
ifdef MAKEFILE_TEST
#GCCDIR = /usr/local/nachos/bin/decstation-ultrix-
GCCDIR = /usr/local/mips/bin/decstation-ultrix-
LDFLAGS = -T script -N
ASFLAGS = -mips2
endif
endif
# slight variant for 386 FreeBSD
ifeq ($(uname),386FreeBSD)
HOST = -DHOST_i386 -DFreeBSD
CPP=/usr/bin/cpp
arch = x86-freebsd
endif
# OSF on DEC Alpha by David Bowers
ifeq ($(uname),OSF1)
HOST = -DHOST_ALPHA
CPPFLAGS = $(INCDIR) -D HOST_ALPHA
CPP=/usr/local/lib/gcc-lib/alpha-dec-osf4.0/2.7.2/cpp
arch = dec-alpha-osf
ifdef MAKEFILE_TEST
GCCDIR = /home/unit/66204/gcc/bin/decstation-ultrix-
LDFLAGS = -T script -N
ASFLAGS = -mips2
endif
endif
arch_dir = arch/$(arch) # 一些系统架构的变量
obj_dir = $(arch_dir)/objects
bin_dir = $(arch_dir)/bin
depends_dir = $(arch_dir)/depends
# 32/64 bit compiler dependent options. Aug. 5, 2021
longbit = $(shell getconf LONG_BIT)
ifeq ($(longbit),64)
GCCOPT32 = -m32
ifndef MAKEFILE_TEST
ASOPT32 = --32
endif
endif
endif # MAKEFILE_DEP
# 其实整个dep就是一个系统硬件相关的。。。。。。
commun中因为篇幅有限,只展示一部分注释
# To build nachos, you should only have to type 'make' in the appropriate
# directory. You can type make in the toplevel nachos/code directory and
# build all versions of nachos, but this will probably blow your diskquota.
# 想要构建nachos,只需要在对应的目录下输入make指令即可,为什么说对应目录
# 因为在/code下面也不是不行,这样将构建所有版本的nachos, 可能会超出磁盘内存
# To build nachos user programs, you should just have to type 'make' in
# the nachos/code/test directory.
# 想要构建用户程序,可以在code/test下面输入“make”指令
# See the files */Makefile and */Makefile.local for how to re-order the
# assignments, and how to add new source files.
# 检查这两个文件并且重新排序如何赋值,以及怎么样添加源文件。
# You might want to play with the CFLAGS, but if you use -O it may
# break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger.
# (一些如果需要再进行尝试的选项)
# Copyright (c) 1992 The Regents of the University of California.
# All rights reserved. See copyright.h for copyright notice and limitation
# of liability and disclaimer of warranty provisions.
# (版权声明)
# 这里是定义MAKEFILE_COMMUN 和防止MAKEFILE_COMMON没能定义 的功能
ifndef MAKEFILE_COMMON
define MAKEFILE_COMMON
yes
endef
# 从MakeFile.dep 这个文件中获取硬件标准
# Makefile.dep is where most machine/architecture dependent stuff
# should go.
include ../Makefile.dep #引入硬件标准,也就是包含这个文件
# vpath tells gnu make where to look for certain files, as determined
# by the target pattern, if it cannot find them in the current directory.
# vpath的作用就是指明了哪些文件需要去什么地方寻找到。。。
# 比如下面就是列出了寻找cpp,寻找头文件,还有寻找s文件应该去什么目录下面
# 这应该是整个common中最重要的一部分了
vpath %.cc ../network:../filesys:../userprog:../threads:../machine
vpath %.h ../network:../filesys:../userprog:../threads:../machine
vpath %.s ../network:../filesys:../userprog:../threads:../machine
# CFLAGS 是一个变量,用于设置 C/C++ 编译器的参数和选项
# 这些参数兄弟我是真的不太会了。。。。我真不写cpp
#CFLAGS = -g -Wall -Wshadow -fwritable-strings $(INCPATH) $(DEFINES) $(HOST) -DCHANGED
# to comment -fwritable-strings out to make new compiler happy
# -ptang, 8/22/05
CFLAGS = $(GCCOPT32) -g -Wall -Wshadow $(INCPATH) $(DEFINES) $(HOST) -DCHANGED
# c,cpp,s(补充一下,s为汇编语言源文件) 这些文件变量需要在Makefile里面初始化
# ofiles 变量在构建 nachos 的不同版本时被使用。每个作业可能对应着不同的 nachos 版本,
# 因此 ofiles 变量用于指定构建过程中所使用的目标文件的列表。
# The variables {C,S,CC}FILES should be initialized by the Makefile
# that invokes this makefile. The ofiles variable is used in building
# the different versions of nachos corresponding to each assignment; it
# is not used by the Makefiles for the bin or test directories.
s_ofiles = $(SFILES:%.s=$(obj_dir)/%.o)
c_ofiles = $(CFILES:%.c=$(obj_dir)/%.o) # 这些变量带标量这些文件的可执行文件的位置
cc_ofiles = $(CCFILES:%.cc=$(obj_dir)/%.o)
ofiles = $(cc_ofiles) $(c_ofiles) $(s_ofiles) # 该变量包含了所有目标文件的路径
program = $(bin_dir)/nachos # 用于表示最终可执行文件的地点
# Unless the invoking Makefile defines a target before including
# Makefile.common (this file), then the following target will be the
# default.
# 除非负责唤醒/编译的Makefile文件在引入这个Makefile.common之前,就定义了一个目标
# 不然就将使用下面的默认配置
接下来来说说子文件夹里的内容:
子文件夹中的Makefile,是一个引入文件,作用是在模块中导入上述的几个文件,以及本地的local文件中的配置,这一点自己打开文件内部也可以看到,这个文件也就是我们上面使用make指令所参照的文件,类比一下,就是package.json,xml,或者tsconfig.json这类东西
至于makefile.local的部分,这个内容也是需要我们自己进行修改的,这里简单解释一下一个基础的makefile.local中有什么东西,具体的修改详见第四部分。
一个local中,有这些东西
# 这一整段代码是其中的条件编译部分,用于定义变量和文件列表
# 判断变量MAKEFILE_THREADS_LOCAL是否存在,如果不存在,则创建一个并且赋值为yes
ifndef MAKEFILE_THREADS_LOCAL
define MAKEFILE_THREADS_LOCAL
yes
endef
# 这个条目的作用是定义一个汇编文件列表,里面的变量是在别处定义的
SFILES = switch$(HOST_LINUX).s
# If you add new files, you need to add them to CCFILES,
# you can define CFILES if you choose to make .c files instead.
# CCFILES是cpp源文件列表,这里面包括了本文件夹中所有的cpp源文件
# 注意: 如果该目录下有了新的cpp文件,就要加入到这个目录下
# 总之大致意思就是,如果你有哪个文件是需要重写的,就扔进对应的文件夹进行重写
# 然后如果有新的文件不再这里面,就加进来
CCFILES = main.cc\ # 以及这个部分最好不要动。。。可以新增但是不能删除,删了会有问题
list.cc\ # 可能会碰上没有的,那种的新增进来就行了
scheduler.cc\ # 剩下的千万别碰55555
synch.cc\
synchlist.cc\
system.cc\
thread.cc\
utility.cc\
threadtest.cc\
synchtest.cc\
interrupt.cc\
sysdep.cc\
stats.cc\
timer.cc
# 因为哥们真的不写c++,因此真的不太理解下面这两个东西起到什么作用
# incpath:用于指定头文件的搜索路径
INCPATH += -I../threads -I../machine
# 用于定义宏变量
DEFINES += -DTHREADS
endif # MAKEFILE_THREADS_LOCAL # 结束语句而已
# 总之需要改的应该就是CCFILES这个变量下面的东西
其中需要我们动的有两个东西,首先是INCPATH,以及CCFILES .
嘛,不过这都是后话了
4.如何构建自己的nachos?
(也就是如何进行拓展实验?)
好了接下来终于到了关键部分了,我们该如何调整并且自行拓展出一个新的nachos呢?
换句话说,我们该如何操作这个项目里的代码呢?
别急,首先老师给的课件里应该反复说明了一点
nachos虽然是一个虚拟的操作系统,但是本质上是被linux理解为一个进程(虽然我知道来看我博客的人和我一样上课不喜欢听课)。因此最终,编译完成的形式是一个可执行文件。在文件中也可以看到每个项目下面都有一个nx的可执行文件,以及一些实例的文字。
上面我们已经阐述了一些关于makefile的东西,成功执行makefile以后,会在对应的模块下面生成一个名为nachos的可执行文件(文件拓展名字是什么哥们其实也不知道,我不写cpp的)
4.1:怎么修改代码
修改代码之前,我们要说明,除了两个demo文件夹,test文件夹,以及lab2-7文件夹,剩下的都是不可进行修改的内容,也就是源码文件。而每个lab和demo下面都有自己的Makefile和makefile.local, 能在我们的实验文件夹下中生成一个独立的nachos可执行文件,也就是我们的目标了。
(1)第一步,复制对应的文件
每个实验都有自己需要复制的文件,我们随便举个例子,比如我们想要修改一些调度相关的拓展,那么我们只需要把调度相关的cc文件和h文件从源码部分移动到这个文件夹中。
为什么只要移动这两个,不是需要生成一个新的nachos吗?其他的源码呢
别急,下面告诉你
(2)检查local中的配置
打开makefile.local可以看到如下配置
首先要做的就是看看你引入的cc文件,是否包括在CCFILES下面,如果在这里面没有你引入的cc文件,那么就请按照这个格式加上。另外注意一点,里面原本的东西不要动。
第二点,修改INCPATH,图中可以看到我在最开始追加了两项,这两项是在ppt中提到的”简单构建方法“ -I- 以及 -I../"文件夹名"
完成以上配置的效果就是”对于这些文件,会优先找本文件夹下的,如果没有才去找threads下面,然后是machine下面“,这一整个INCPATH就类似环境变量,以后有别的实验慢慢解释
(3)make执行,生成可执行文件
make clean指令:用来撤销上一次生成的可执行文件
make:根据makefile进行链接编译,生成可执行文件
./nachos:执行可执行文件
4.2:怎么跑起来
上面已经说了好像,根据生成的可执行文件,直接命令行执行即可
什么,不会命令行执行程序?
那就不是我的问题了,我一个学前端的都会。。。。
别总是依赖ide啦,兄弟
5.关于实验
这里是关于实验1的部分,实验1不需要写代码,因此只需要分析一下这些东西即可。
实验要求如下:
1. Nachos开发环境的安装测试
2. Nachos实验代码框架的基本分析
3. Makefile基本分析
4. 硬件机制模拟部分的原理分析(中断,时钟,CPU指令的执行)
实验内容:
注:每张图片均有csdn水印,因为在做实验的时候,linux不方便做笔记,因此将文档在csdn的个人博客中在线整理完成,再重新放在windows下的word中编辑。ViceMusic5就是学生本人的csdn的帐号昵称,如果老师需要验证真实性可以随时找我验证。
1.Nachos开发环境的安装测试
该实验使用非虚拟机安装,版本为ubuntu22.04版本操作系统。
gcc等环境工具已经在本机中适配,这里不再过多阐述。
安装过程:
1. 根据项目需求,首先将nachos的tar.gz压缩文件使用tar -xzvf指令进行解压缩,解压缩后的文件夹,在今后的实验中直接视为工作目录使用。
这里将文件文件夹名称直接修改为:nachos_modified
2.根据项目需求,将MIPS工具解压到本机根目录下的usr/local目录下方,使得交叉编译能正常运行
3.由于我是64位机器,所以需要单独安装gcc来编译32位程序和指令集
4.验证
我们选择在lab2中完成验证,首先使用make clean清除事前已有的可执行文件,然后重新使用make指令生成文件
如图所示,生成了一个可执行文件nachos,由此即可证明验证完成。
2.nachos文件目录的基本分析
(1)code/下的文件夹如图所示
1. bin: Nachos用户实现MIPS程序目标码变化的实用程序以及源码
2. machine: MIPS虚拟机模拟代码,一般不需要修改
3. network: 网络管理部分,课设部分没有提及
4. filesys: 文件管理部分源码
5. threads: 线程管理部分源码
6. userprog: 用户程序部分源码
7. test: 一些测试用的程序
8. demo: demo0是演示Makefile的例子, demo1是使用信号两解决生产者消费者同步的例子
9. lab2-lab7: 实验需要对应的代码部分,主要的修改和添加,以及编译生成新的nachos扩展,都在这系列目录下
(2)c++ example文件夹内容如图所示:该文件夹主要用于讲解cpp和c之间的过渡案例
(3)doc文件夹中内容如图所示,主要是一些文档内容,与实际操作关系不大
3.Makefile基本分析
makefile使用make指令,根据自动化编译来实现效果
其根本效果类似package.json,会在当前目录下自动寻找名为makefile的文件
(1)基本语法如图所示
(2)项目中的makefile分析如下图所示
dep为硬件的环境依赖
广义上的Makefile可以被分为local和common,前者在各个文件夹下面,后者在根目录下。
而每个子模块的内部都集成了这个东西,然后在各自的目录下创建了Makefile,作为真的引入模块和make命令执行文件
以下是删除英文注释以后,补上的汉语注解
commun:==================================================================
# 这里是定义MAKEFILE_COMMUN 和防止MAKEFILE_COMMON没能定义 的功能
ifndef MAKEFILE_COMMON
define MAKEFILE_COMMON
yes
endef
# 从MakeFile.dep 这个文件中获取硬件标准
include ../Makefile.dep #引入硬件标准,也就是包含这个文件
# vpath的作用就是指明了哪些文件需要去什么地方寻找到。。。
# 比如下面就是列出了寻找cpp,寻找头文件,还有寻找s文件应该去什么目录下面
# 这应该是整个common中最重要的一部分了
vpath %.cc ../network:../filesys:../userprog:../threads:../machine
vpath %.h ../network:../filesys:../userprog:../threads:../machine
vpath %.s ../network:../filesys:../userprog:../threads:../machine
# CFLAGS 是一个变量,用于设置 C/C++ 编译器的参数和选项
# 这些参数兄弟我是真的不太会了。。。。我真不写cpp
CFLAGS = $(GCCOPT32) -g -Wall -Wshadow $(INCPATH) $(DEFINES) $(HOST) -DCHANGED
# c,cpp,s(补充一下,s为汇编语言源文件) 这些文件变量需要在Makefile里面初始化
# ofiles 变量在构建 nachos 的不同版本时被使用。每个作业可能对应着不同的 nachos 版本,
# 因此 ofiles 变量用于指定构建过程中所使用的目标文件的列表。
s_ofiles = $(SFILES:%.s=$(obj_dir)/%.o)
c_ofiles = $(CFILES:%.c=$(obj_dir)/%.o) # 这些变量带标量这些文件的可执行文件的位置
cc_ofiles = $(CCFILES:%.cc=$(obj_dir)/%.o)
ofiles = $(cc_ofiles) $(c_ofiles) $(s_ofiles) # 该变量包含了所有目标文件的路径
program = $(bin_dir)/nachos # 用于表示最终可执行文件的地点
# 除非负责唤醒/编译的Makefile文件在引入这个Makefile.common之前,就定义了一个目标
# 不然就将使用下面的默认配置
$(program): $(ofiles)
# 上面这个其实就是关于可执行文件的生成 [target]:[dependency]这个语法
# 根据makefile的自动检查机制,保证每个都是最新的
# 构建各种文件的规则:
# 上面这段说的是:。。。。。真不懂是再说什么,不过不重要,总之是通过文件前缀来判断是否为可执行文件
$(bin_dir)/% :
@echo ">>> Linking" $@ "<<<"
$(LD) $(GCCOPT32) $^ $(LDFLAGS) -o $@
ln -sf $@ $(notdir $@)
(----------------省略一些二进制文件的处理指令--------------)
# 关系依赖的生成过程现在是自动的了,旧的已经被覆盖掉了
# (补充,后缀d则表明这是一个依赖关系文件)
s_dfiles = $(SFILES:%.s=$(depends_dir)/%.d)
c_dfiles = $(CFILES:%.c=$(depends_dir)/%.d)
cc_dfiles = $(CCFILES:%.cc=$(depends_dir)/%.d)
dfiles = $(cc_dfiles) $(c_dfiles) $(s_dfiles) # 依赖关系文件的列表存在这里
# 下面的规则是构建依赖文件需要的部分
$(depends_dir)/%.d: %.cc
@echo ">>> Building dependency file for " $< "<<<"
@$(SHELL) -ec '$(CC) -MM $(CFLAGS) $< \
| sed '\''s@$*.o[ ]*:@$(depends_dir)/$(notdir $@) $(obj_dir)/&@g'\'' > $@'
(---------------------省略-----------------------------------------)
# 在往下就是清理掉可执行文件的过程了。。。。
include $(dfiles)
clean:
rm -f `find $(arch_dir) -type f -print | egrep -v '(CVS|cvsignore)'`
rm -f nachos coff2noff coff2flat
rm -f *.noff *.flat
tmpclean:
rm -f tmp*
endif # MAKEFILE_COMMON
dep:===========================================================
ifndef MAKEFILE_DEP # 这段代码的目的是检查是否存在一个名为MAKEFILE_DEP的对象
define MAKEFILE_DEP # 如果不存在就定义一个,并且赋值为yes
yes # 这个变量在这里推测是控制整个条件进行执行的
endef # 别的哥们也不敢多说了,nachos真的是不懂啊
# 以下这些定义会随着软件的变化而变化
# 这里主要是一些变量 和别名
CPP=/lib/cpp # c程序的与处理器
CC = g++ # c程序的编译程序
LD = g++ # 链接器的路径
AS = as # 汇编器的路径
uname = $(shell uname) # 获取当前操作系统的名称
mips_arch = dec-mips-ultrix # 存储MIPS架构,暂时不知道是干啥的
# DEC MIPS, Ultrix # 这一大段代码就是判断操作系统的。。。
ifeq ($(uname),ULTRIX) # 往下很多都是处理硬件的东西,先不用看了
HOST := -DHOST_MIPS
arch = $(mips_arch)
CPPFLAGS = -P $(INCDIR) $(HOST)
ifdef MAKEFILE_TEST
LDFLAGS = -T script -N
endif
endif
(---------------------省略---------------------------)
arch_dir = arch/$(arch) # 一些系统架构的变量
obj_dir = $(arch_dir)/objects
bin_dir = $(arch_dir)/bin
depends_dir = $(arch_dir)/depends
longbit = $(shell getconf LONG_BIT)
ifeq ($(longbit),64)
GCCOPT32 = -m32
ifndef MAKEFILE_TEST
ASOPT32 = --32
endif
endif
endif
local:=======================以threads下的为例子=======================
# 这一整段代码是其中的条件编译部分,用于定义变量和文件列表
# 判断变量MAKEFILE_THREADS_LOCAL是否存在,如果不存在,则创建一个并且赋值为yes
ifndef MAKEFILE_THREADS_LOCAL
define MAKEFILE_THREADS_LOCAL
yes
endef
# 这个条目的作用是定义一个汇编文件列表,里面的变量是在别处定义的
SFILES = switch$(HOST_LINUX).s
# CCFILES是cpp源文件列表,这里面包括了本文件夹中所有的cpp源文件
# 注意: 如果该目录下有了新的cpp文件,就要加入到这个目录下
# 总之大致意思就是,如果你有哪个文件是需要重写的,就扔进对应的文件夹进行重写
# 然后如果有新的文件不再这里面,就加进来
CCFILES = main.cc\ # 以及这个部分最好不要动。。。可以新增但是不能删除,删了会有问题
list.cc\ # 可能会碰上没有的,那种的新增进来就行了
scheduler.cc\
synch.cc\
synchlist.cc\
system.cc\
thread.cc\
utility.cc\
threadtest.cc\
synchtest.cc\
interrupt.cc\
sysdep.cc\
stats.cc\
timer.cc
# incpath:用于指定头文件的搜索路径
INCPATH += -I../threads -I../machine
# 用于定义宏变量
DEFINES += -DTHREADS
endif # MAKEFILE_THREADS_LOCAL # 结束语句而已
# 总之需要改的应该就是CCFILES这个变量下面的东西
MakeFile:=============以threads中为例==========
ifndef MAKEFILE_THREADS
define MAKEFILE_THREADS
yes
endef
include Makefile.local
include ../Makefile.common
endif
(3)基础命令的执行:
make clean 用来清理之前生成的可执行文件
make 用来根据当前目录下的设置
4.硬件机制模拟部分的原理分析(中断,时钟,CPU指令的执行)
(1)中断
interrupt中定义了两个类,PendingInterrupt则保存了准备发生的中断的信息,包括中断处理程序入口、交给中断处理程序的参数、该中断应该被处理的时间。
Interrupt包含了PendingInterrupt类型元素的有序列表,以及其它一些中断系统变量,比如是否允许中断、当前是否在运行中断处理程序、从中断返回时是否要切换上下文、机器当前所处的模式(空闲/内核态/用户态)。Interrupt中定义了很多操作,其中,构造函数中初始化了上述系统变量值,析构函数释放待发生中断的列表占用的空间,转换、获取机器模态的操作,开闭中断,让系统空闲,停机,转换上下文,打印中断信息,产生一个终端。
(2)时钟
时钟由文件timer.cc和timer.h实现,该模块的作用是模拟时钟中断。Nachos虚拟机可以如同实际的硬件一样,每隔一定的时间会发生一次时钟中断。Timer类模拟定时器。定时器每隔X个时钟周期就向CPU发一个时钟中断。它是时间片管理必不可少的硬件基础。它的实现方法是将一个即将发生的时钟中断放入中断队列,到了时钟中断应发生的时候,中断系统将处理这个中断,在中断处理的过程中又将下一个即将发生的时钟中断放入中断队列,这样每隔X个时钟周期,就有一个时钟中断发生。Nachos利用其模拟的中断机制来模拟时钟中断。时钟中断间隔由TimerTicks宏决定(100倍Tick的时间)
(3)指令执行
CPU指令执行由文件machine.cc和machine.h实现,Machine类用来模拟计算机主机。它提供的功能有:读写寄存器。读写主存、运行一条用户程序的汇编指令、运行用户程序、单步调试用户程序、显示主存和寄存器状态、将虚拟内存地址转换为物理内存地址、陷入 Nachos 内核等等。
Machine类实现方法是在宿主机上分配两块内存分别作为虚拟机的寄存器和物理内存。运行用户程序时,先将用户程序从 Nachos 文件系统中读出,写入模拟的物理内存中,然后调用指令模拟模块对每一条用户指令解释执行。将用户程序的读写内存要求,转变为对物理内存地址的读写。Machine提供了单步调试用户程序的功能,执行一条指令后会自动停下,让用户查看系统状态。当用户程序想使用操作系统提供的功能或者发出异常信号时,Machine调用系统异常陷入功能,进入Nachos的核心部分。
(参考操作手册和其他学长学姐的分享后得出,后续将在代码中不断学习这个过程)