环境配置
对gdb配置有问题的可以参考MIT 6.S081 Lab 0: 实验配置, 调试及测试
列几个常用的指令:
//以gdb模式启动qemu
make CPUS=1 qemu-gdb
//在另一个窗口开启gdb
riscv64-unknown-elf-gdb
//不多说,神器
layout split
实验
System call tracing (moderate)
xv6用perl脚本做到内核代码函数和用户函数的自动对应,感觉挺有趣的,但感觉要看懂要很久。
//user/usys.pl
...
entry("sleep");
entry("uptime");
entry("trace");//新增
//kernel/syscall.h
#define SYS_close 21
#define SYS_trace 22//新增
//kernel/sysproc.c
uint64
sys_trace(void)
{
int mask;
if (argint(0, &mask) < 0)
return -1;
myproc()->mask = mask;
return 0;
}
//kernel/proc.h
struct proc {
struct spinlock lock;
// p->lock must be held when using these:
enum procstate state; // Process state
struct proc *parent; // Parent process
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
// these are private to the process, so p->lock need not be held.
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
uint64 mask; // trace mask
};
//kernel/proc.c
allocproc(void)
{
struct proc *p;
...
p->mask = 0;//新增
return p;
}
int
fork(void)
{
int i, pid;
struct proc *np;
struct proc *p = myproc();
// Allocate process.
if((np = allocproc()) == 0){
return -1;
}
// Copy user memory from parent to child.
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
freeproc(np);
release(&np->lock);
return -1;
}
np->sz = p->sz;
np->parent = p;
np->mask = p->mask;//新增
return pid;
}
//kernel/syscall.c
extern uint64 sys_trace(void); //新增
static char* sysnames[] = {"", "fork", "exit", "wait", "pipe", "read", "kill", "exec",
"fstat", "chdir", "dup", "getpid", "sbrk", "sleep", "uptime", "open", "write",
"mknod", "unlink", "link", "mkdir", "close", "trace"};
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();
if ((p->mask & (1 << num)) > 0) {
printf("%d: syscall %s -> %d\n", p->pid, sysnames[num], p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
疑问:之前总是出现如下问题(改了allocproc后还是这样),后面代码一行没改又好了,很奇怪
Sysinfo (moderate)
几乎流程与上个相同,就是需要注意一些细节,下面仅列出部分关键代码。
//kernel/kalloc.c
void
kinit()
{
struct sysinfo* info = mysysinfo();
info->freemem = 0;
initlock(&kmem.lock, "kmem");
freerange(end, (void*)PHYSTOP);
}
kfree(void *pa)
{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
struct sysinfo* info = mysysinfo();//新增
acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
info->freemem += PGSIZE;//新增
release(&kmem.lock);
}
kalloc(void)
{
struct run *r;
struct sysinfo* info = mysysinfo();
acquire(&kmem.lock);
r = kmem.freelist;
if(r)
if(r) {
kmem.freelist = r->next;
info->freemem -= PGSIZE;//新增
}
release(&kmem.lock);
//kernel/proc.c
struct sysinfo sysinfo;
struct sysinfo*
mysysinfo(void)
{
struct sysinfo* info = &sysinfo;
return info;
};
allocproc(void)
{
struct proc *p;
struct sysinfo* info;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == UNUSED) {
...
return 0;
}
info = mysysinfo();
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
p->mask = 0;
info->nproc++;
return p;
}
//kernel/sysproc.c
uint64
sys_sysinfo(void)
{
uint64 addr;
if(argaddr(0, &addr) < 0)
return -1;
struct proc *p = myproc();
struct sysinfo* info = mysysinfo();
if(copyout(p->pagetable, addr, (char *)info, sizeof(*info)) < 0)
return -1;
return 0;
}