该仓库为哈尔滨工程大学计算机科学与技术学院2024~2025学年秋季课程——操作系统配套实验代码,配套平台为北京杰创永恒科技有限公司旗下的云端课程体系建设平台。该项目作者only9464精力和能力都有限,只整理对应的任务所要修改的文件及其对应的行数的代码,同时上传了实验教程、实验报告模板以及各个实验的要求,各位同志可以作为参考来完成自己的实验操作。若有谬误,请多多指教,欢迎提交issue或者发送邮件至sky9464@qq.com以联系作者。仅供参考,请勿抄袭()。
注意:README.md中修改或者添加的代码均为最后提交的版本,中间版本暂时不予提供
问题反馈:README.md中的代码总结可能不完善或者存在谬误,若你在参考的过程中坐牢了,可以看一下仓库中对应的文件的源代码,欢迎纠错与补充!
- 感谢 @MadLongTom 对 实验8地址映射和内存共享-任务1 --> kernel/system_call.s 的纠错(#1)
- 感谢 @Erwwyh 对 实验8地址映射和内存共享-任务1 --> include/linux/sys.h 的补充(#2)
- 感谢 @penguinway、@Erwwyh 对 实验8地址映射和内存共享-任务2 --> newapp/loop.c 的提醒(#4、#3)
- 感谢 @WaterWhisperer 对 实验1实验环境的使用-任务2 --> newapp/makefile 的纠错(#5、#6)
- README.md: 包含本仓库说明、最终修改的文件代码位置等
- Linux内核实验教程_4.10.pdf: 实验教程
- 学生包.zip: 部分实验所需要的写好的库文件 ps:点击下载
实验软件安装包: 点击下载实验文档: 点击下载Linux操作系统实验介绍.mp4: 点击下载
- 1. 实验1实验环境的使用-任务1
- 2. 实验1实验环境的使用-任务2
- 3. 实验2操作系统的启动
- 4. 实验5进程的创建-任务1
- 5. 实验5进程的创建-任务2
- 6. 实验8地址映射和内存共享-任务1
- 7. 实验8地址映射和内存共享-任务2
- 8. 实验11proc文件系统的实现
第234行添加:
printf("Hello Linux!\n\r");第10行添加:
/* 新增代码,输出内容任意即可 */printf("Github: https://github.com/only9464\n");intadd(intx,inty){
returnx+y;
}#include<stdio.h>intadd(intx,inty);
intmain(){
inta;
intb;
intsum;
printf("Please input two number:\n");
scanf("%d %d",&a,&b);
sum=add(a,b);
printf("The result is:%d\n",sum);
return0;
}CC = gcc
CFLAGS = -Wall -g
SRC = add.c main.c
OBJ = $(SRC:.c=.o)TARGET = app
all: $(TARGET)$(TARGET): $(OBJ)$(CC)$(CFLAGS) -o $@$^%.o: %.c
$(CC)$(CFLAGS) -c $< -o $@clean:
rm -f $(OBJ)$(TARGET).PHONY: all clean第116行之前添加:
movax,cs ; 将当前代码段加载到AXmovds,ax ; 设置DS为AX值,以确保数据段正确movsi, message ; SI指向字符串开始位置movah,0x0e ; 设置BIOS teletype功能print_message:lodsb ; 将[SI]中的字符加载到AL,并自动递增SIcmpal,0 ; 检查AL是否为0(字符串结束符)je done_message ; 如果为0,跳转到done_messageint0x10 ; 显示字符jmp print_message ; 循环回去显示下一个字符done_message: ; 恢复寄存器和控制流 ; mov ds, INITSEG ; 如果需要,恢复ds等寄存器jmp next_step ; 显式跳转到下一步(例如进入保护模式的代码)message db 'Enter protected mode ...',0 ; 以0结束的字符串next_step:第203行改为:
printk("\n\n\nPartition table%s ok.\n\r",(NR_HD>1)?"s":"");#define_LIBRARY_#include<stdio.h>#include<unistd.h>intmain(){
intpid;
printf("PID:%D parent process start.\n",getpid());
pid=fork();
if(pid!=0 )
{
wait(NULL);
printf("PID:%d parent process continue.\n",getpid());
}
else
{
printf("PID:%d child process start.\n",getpid());
printf("PID:%d child process exit.\n",getpid());
return0;
}
printf("PID:%d parent process exit.\n",getpid());
return0;
}#define__LIBRARY__ #include <stdio.h> #include<unistd.h>intmain( intargc, char*argv[] ) { printf("PID:%d new process.\n", getpid()); return0; } #define__LIBRARY__ #include <stdio.h> #include<unistd.h>intmain( intargc, char*argv[] ) { printf("PID:%d old process start.\n", getpid()); execve("new", NULL, NULL ); printf("PID:%d old process exit.\n", getpid()); return0; } 第22行添加:
intphysical_mem();第87行后添加:
externintdump_physical_mem();第177行(sys_uselib所在行)改为:
sys_uselib, //86 dump_physical_mem//87第162行添加:
#define__NR_dump_physical_mem 87第353行添加:
intdump_physical_mem(){
physical_mem();
return0;
}第73行改为:
nr_system_calls = 88 # Linux 0.11 版内核中的系统调用总数。第817行添加:
intphysical_mem()
{
inti, free=0; /* free表示空闲页的总数 */
__asm("cli");
/* PAGING_PAGES 是在本文件第 137 行处定义,表示分页后的物理内存页数。*//* mem_map[] 是在第 152 行定义的内存映射字节图(1 字节代表 1 页内存), 每个页面对应的字节用于标志页面当前被引用(占用)次数。*/for(i=0 ; i<PAGING_PAGES ; i++)
{
if (0==mem_map[i])
{
free++;
}
}
printk("Page Count : %d\n", PAGING_PAGES);
printk("Memory Count : %d * 4096 = %d Byte\n\n", PAGING_PAGES, PAGING_PAGES*4096);
printk("Free Page Count : %d\n", free);
printk("Used Page Count : %d\n", PAGING_PAGES-free);
// 分配一个空闲物理页intallocated_page=get_free_page();
if (allocated_page!=-1) {
// 计算分配的物理页地址void*allocated_address= (void*)(allocated_page*4096);
printk("**********After Allocated One Page**********\n");
printk("Allocated One Page : %p\n", allocated_address);
// 更新空闲页的数量free--; // 分配后空闲页数减少printk("Free Page Count : %d\n", free);
printk("Used Page Count : %d\n", PAGING_PAGES-free);
} else {
printk("Failed to allocate a page\n");
}
// 回收刚刚分配的物理页if (allocated_page!=-1) {
free_page(allocated_page);
printk("**********After Freed One Page**********\n");
// 计算释放的物理页地址void*freed_address= (void*)(allocated_page*4096);
free++; // 回收后空闲页数增加printk("Freed One Page : %p\n", freed_address);
printk("Free Page Count : %d\n", free);
printk("Used Page Count : %d\n", PAGING_PAGES-free);
}
__asm("sti");
return0;
}#define__LIBRARY__ #include <unistd.h> #define__NR_dump_physical_mem 87 _syscall0(int, dump_physical_mem) intmain() { dump_physical_mem(); return0; } #include<stdio.h>intmain(void)
{
inti=0x12345678;
printf("The logical/virtual address of i is 0x%08x\n", &i);
fflush(stdout);
while(i)
;
return0;
}第647行改为:
if (S_ISBLK(mode) ||S_ISCHR(mode) ||S_ISPROC(mode))#include<asm/segment.h>#include<linux/sched.h>#include<string.h>#include<stdarg.h>#include<stddef.h>#defineSIZE 1024 // 缓冲区大小
#defineBUFFER_SIZE 1024
charpsbuffer[SIZE]; // 定义缓冲区来存放结点信息// sprintf 和 vsprintf 的实现staticintvsprintf(char*buf, constchar*fmt, va_listargs) {
char*p;
intlen=0;
for (p= (char*)fmt; *p!='\0'; p++) {
if (*p!='%') {
if (len<BUFFER_SIZE-1) {
buf[len++] =*p;
}
continue;
}
p++; // Skip '%'switch (*p) {
case'd': { // Integerintnum=va_arg(args, int);
chartmp[12]; // Sufficient for 32-bit intinti=0;
if (num<0) {
buf[len++] ='-';
num=-num;
}
do {
tmp[i++] = (num % 10) +'0';
num /= 10;
} while (num&&i<sizeof(tmp));
while (i>0) {
buf[len++] =tmp[--i];
}
break;
}
case's': { // Stringchar*str=va_arg(args, char*);
while (*str&&len<BUFFER_SIZE-1) {
buf[len++] =*str++;
}
break;
}
default:
buf[len++] =*p;
break;
}
}
buf[len] ='\0'; // Null-terminate the bufferreturnlen;
}
intsprintf(char*buf, constchar*fmt, ...) {
va_listargs;
va_start(args, fmt);
intlen=vsprintf(buf, fmt, args);
va_end(args);
returnlen;
}
/* 读取系统中的信息放到 psbuffer 数组中, 并再读取 psbuffer 中的数据写入到用户空间的 buf 中 */intpsread(intdev, char*buf, intcount, off_t*f_pos) {
structtask_struct*p;
inti, j=0; // 变量 j 为在 psbuffer 中写数据的位置偏移量// 如果是第一次读取,将 psbuffer 进行初始化和赋值if (!(*f_pos)) {
memset(psbuffer, 0, SIZE); // 将 psbuffer 数组初始化为 0// 使用 sprintf 添加标题sprintf(psbuffer, "pid\tstate\tfather\tcounter\tstart_time\n");
j=strlen(psbuffer); // 更新偏移量// 遍历当前的进程,为 psinfo 节点赋值for (i=0; i<NR_TASKS; i++) {
p=task[i];
if (p==NULL) continue;
// 使用 sprintf 进行数据拼接j+=sprintf(psbuffer+j, "%d\t%d\t%d\t%d\t%d\n",
p->pid, p->state, p->father, p->counter, p->start_time);
}
}
// 将数组 psbuffer 中的信息读取到用户空间的 buf 位置处for (i=0; i<count; i++, (*f_pos)++) {
if (psbuffer[*f_pos] =='\0')
break;
// put_fs_byte 函数是将一字节存放在 fs 段中指定内存地址处put_fs_byte(psbuffer[*f_pos], &buf[i]);
}
returni;
}第32行添加:
// psread函数. fs/proc.cexternintpsread (intdev, char*buf, intcount, off_t*f_pos); 第113行(printk调用)前添加:
if(S_ISPROC(inode->i_mode)) returnpsread(inode->i_zone[0], buf, count, &file->f_pos); 第26行添加:
#defineS_IFPROC 0050000 // 新文件类型宏定义第38行添加:
#defineS_ISPROC(m) (((m)& S_IFMT) == S_IFPROC) // 为新文件类型添加相应的测试宏第13行添加:
#include<sys/stat.h>第43行添加:
_syscall2(int,mkdir,constchar*,name,mode_t,mode) _syscall3(int,mknod,constchar*,filename,mode_t,mode,dev_t,dev) 第235行添加:
mkdir("/proc",0755); mknod("/proc/psinfo",S_IFPROC|0444,0);