2023-2024-1 20232824《Linux内核原理与分析》第三周作业

实验楼配套实验二

一、默认代码执行

接下来配合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后:
在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值