实验楼配套实验二
一、默认代码执行
接下来配合chatgpt学习并完成实验内容:
上述代码为构建和启动一个自定义的Linux内核。首先,它删除任何先前构建的内核相关文件,然后应用一个补丁文件来修改内核源代码。接下来,它配置内核选项,然后编译内核。最后,它使用QEMU虚拟机来启动新编译的内核。这个过程旨在允许用户自定义内核,以满足特定需求或测试新功能。
执行make后发现新的内核已经准备就绪。
但执行$ qemu -kernel arch/x86/boot/bzImage后发现进入死循环:
二、完成一个简单的时间片轮转多道程序内核代码
进入kernel目录:
cd mykernel
创建mypcb.h文件保存在mykernel:
/*
* linux/mykernel/mypcb.h
* Kernel internal PCB types
* Copyright (C) 2013 Mengning
*/
#define MAX_TASK_NUM 4 /* 定义最大任务数为4 */
#define KERNEL_STACK_SIZE 1024*2 /* 定义内核堆栈大小为1024*2字节 */
/* CPU-specific state of this task */
struct Thread { /* 定义Thread结构体,表示任务的CPU相关状态 */
unsigned long ip; /* 存储指令指针 */
unsigned long sp; /* 存储栈指针 */
};
typedef struct PCB { /* 定义进程控制块参数 */
int pid; /* 进程ID(Process ID)*/
volatile long state; /* 进程状态:-1 表示不可运行, 0 表示可运行, >0 表示停止 */
unsigned long stack[KERNEL_STACK_SIZE]; /* 存储内核堆栈 */
/* CPU-specific state of this task */
struct Thread thread; /* 存储任务的CPU相关状态 */
unsigned long task_entry; /* 存储任务的入口地址 */
struct PCB *next; /* 存储下一个进程控制块的指针,用于构建链表 */
} tPCB;
void my_schedule(void); /* 声明调度函数my_schedule() */
修改mymain.c:
/*
* linux/mykernel/mymain.c
*
* Kernel internal my_start_kernel
*
* Copyright (C) 2013 Mengning
*
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>
#include "mypcb.h"
tPCB task[MAX_TASK_NUM];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;
void my_process(void);
void __init my_start_kernel(void)
{
int pid = 0;
int i;
/* Initialize process 0*/
task[pid].pid = pid;
task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */
task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;
task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];
task[pid].next = &task[pid];
/*fork more process */
for(i=1;i<MAX_TASK_NUM;i++)
{
memcpy(&task[i],&task[0],sizeof(tPCB));
task[i].pid = i;
task[i].state = -1;
task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];
task[i].next = task[i-1].next;
task[i-1].next = &task[i];
}
/* start process 0 by task[0] */
pid = 0;
my_current_task = &task[pid];
asm volatile(
"movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */
"pushl %1\n\t" /* push ebp */
"pushl %0\n\t" /* push task[pid].thread.ip */
"ret\n\t" /* pop task[pid].thread.ip to eip */
"popl %%ebp\n\t"
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/
);
}
void my_process(void)
{
int i = 0;
while(1)
{
i++;
if(i%10000000 == 0)
{
printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
if(my_need_sched == 1)
{
my_need_sched = 0;
my_schedule();
}
printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
}
}
}
修改myinterrupt.c:
/*
* linux/mykernel/myinterrupt.c
*/
#include "mypcb.h" // 包含自定义的进程控制块头文件
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>
extern tPCB task[MAX_TASK_NUM]; // 外部声明,引用来自其他文件的全局变量
extern tPCB *my_current_task;
extern volatile int my_need_sched;
volatile int time_count = 0;
/*
* 当定时器中断被调用时执行的处理函数。
*/
void my_timer_handler(void)
{
if (time_count % 1000 == 0 && my_need_sched != 1)
{
printk(KERN_NOTICE ">>>my_timer_handler here<<<\n"); // 打印调试信息
my_need_sched = 1; // 设置需要进行进程调度的标志
}
time_count++;
return;
}
/*
* 进程调度函数
*/
void my_schedule(void)
{
tPCB *next;
tPCB *prev;
// 检查当前任务和下一个任务是否有效
if (my_current_task == NULL || my_current_task->next == NULL)
{
return;
}
printk(KERN_NOTICE ">>>my_schedule<<<\n"); // 打印调度信息
/* 进行任务切换 */
next = my_current_task->next; // 获取下一个任务
prev = my_current_task; // 获取当前任务
if (next->state == 0) /* -1 不可运行, 0 可运行, >0 停止 */
{
my_current_task = next; // 切换到下一个任务
printk(KERN_NOTICE ">>>switch %d to %d<<<\n", prev->pid, next->pid); // 打印任务切换信息
/* 执行任务切换 */
asm volatile(
"pushl %%ebp\n\t" /* 压栈当前任务的值 */
"movl %%esp,%0\n\t" /* 将当前栈指针保存到当前任务的tPCB结构中 */
"movl %2,%%esp\n\t" /* 切换到下一个任务的栈指针 */
"movl $1f,%1\n\t" /* 将标签1的地址保存到当前任务的thread.ip中 */
"pushl %3\n\t" /* 将下一个任务的thread.ip压栈 */
"ret\n\t" /* 返回,实现任务切换 */
"1:\t" /* 标签1,用于返回时跳转 */
"popl %%ebp\n\t"
: "=m"(prev->thread.sp), "=m"(prev->thread.ip)
: "m"(next->thread.sp), "m"(next->thread.ip)
);
}
else
{
next->state = 0; // 设置下一个任务的状态为可运行
my_current_task = next; // 切换到下一个任务
printk(KERN_NOTICE ">>>switch %d to %d<<<\n", prev->pid, next->pid); // 打印任务切换信息
/* 执行任务切换 */
asm volatile(
"pushl %%ebp\n\t" /* 压栈当前任务的值 */
"movl %%esp,%0\n\t" /* 将当前栈指针保存到当前任务的tPCB结构中 */
"movl %2,%%esp\n\t" /* 切换到下一个任务的栈指针 */
"movl %2,%%ebp\n\t" /* 切换到下一个任务的栈底指针 */
"movl $1f,%1\n\t" /* 将标签1的地址保存到当前任务的thread.ip中 */
"pushl %3\n\t" /* 将下一个任务的thread.ip压栈 */
"ret\n\t" /* 返回,实现任务切换 */
"1:\t" /* 标签1,用于返回时跳转 */
"popl %%ebp\n\t"
: "=m"(prev->thread.sp), "=m"(prev->thread.ip)
: "m"(next->thread.sp), "m"(next->thread.ip)
);
}
return;
}
结果
重新执行make后: