Lab4: traps

RISC-V assembly

Which registers contain arguments to functions? For example, which register holds 13 in main's call to printf?

根据RISC-V函数调用规范,函数的前8个参数使用a0-a7寄存器传递。

当main函数调用printf函数时,a2寄存器保存13

Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.)

通过 li a1,12 可知,当main函数调用函数 f 时,已经内联了函数 f ,所以可以看到编译器直接将12保存到寄存器a1中

而在函数 f 中,编译器也内联了函数 g 的调用,直接向a0 寄存器加3

At what address is the function printf located?

0x0000000000000642

What value is in the register ra just after the jalr to printf in main?

0x38

Run the following code. What is the output? The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?

unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);

输出: He110 World 

如果是大端机器,57616 不用变,i 变为 0x726c6400

In the following code, what is going to be printed after 'y='? (note: the answer is not a specific value.) Why does this happen?

printf("x=%d y=%d", 3);

a2寄存器中的值

Backtrace

void backtrace(void)
{
	uint64 ra;
	uint64 fp = r_fp();
	uint64 up = PGROUNDUP(fp);

	printf("backtrace:\n");
	while (fp < up)
	{
		ra = fp - 8;
		printf("%p\n",*(uint64*)ra);
		fp = *(uint64*)(fp - 16);
	}
}

Alarm 

struct proc
{
	struct spinlock lock;

	// p->lock must be held when using these:
	enum procstate state; // Process state
	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

	// wait_lock must be held when using this:
	struct proc *parent; // Parent process

	// 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)
	int alarm_interval;	
	void (*alarm_handler)();
	int alarm_ticks;
	struct trapframe * alarm_frame;
	int alarm_is_returned;
};
void usertrap(void)
{
	int which_dev = 0;

	if ((r_sstatus() & SSTATUS_SPP) != 0)
		panic("usertrap: not from user mode");

	// send interrupts and exceptions to kerneltrap(),
	// since we're now in the kernel.
	w_stvec((uint64)kernelvec);

	struct proc *p = myproc();

	// save user program counter.
	p->trapframe->epc = r_sepc();

	if (r_scause() == 8)
	{
		// system call

		if (killed(p))
			exit(-1);

		// sepc points to the ecall instruction,
		// but we want to return to the next instruction.
		p->trapframe->epc += 4;

		// an interrupt will change sepc, scause, and sstatus,
		// so enable only now that we're done with those registers.
		intr_on();

		syscall();
	}
	else if ((which_dev = devintr()) != 0)
	{
		// ok
	}
	else
	{
		printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
		printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());
		setkilled(p);
	}

	if (killed(p))
		exit(-1);

	// give up the CPU if this is a timer interrupt.
	if (which_dev == 2)
	{
		p->alarm_ticks++;
		if (p->alarm_interval != 0 && p->alarm_ticks == p->alarm_interval && p->alarm_is_returned == 1)
		{
			memmove((void*)p->alarm_frame,(const void*)p->trapframe, sizeof(struct trapframe));
			p->trapframe->epc = (uint64)p->alarm_handler;
			p->alarm_ticks = 0;
			p->alarm_is_returned = 0;
		}
		
		yield();
	}

	usertrapret();
}
static struct proc *
allocproc(void)
{
	struct proc *p;

	for (p = proc; p < &proc[NPROC]; p++)
	{
		acquire(&p->lock);
		if (p->state == UNUSED)
		{
			goto found;
		}
		else
		{
			release(&p->lock);
		}
	}
	return 0;

found:
	p->pid = allocpid();
	p->state = USED;

	p->alarm_interval = 0;
	p->alarm_handler = 0;
	p->alarm_ticks = 0;
	p->alarm_is_returned = 1;

	// Allocate a trapframe page.
	if ((p->trapframe = (struct trapframe *)kalloc()) == 0)
	{
		freeproc(p);
		release(&p->lock);
		return 0;
	}

	if ((p->alarm_frame = (struct trapframe *)kalloc()) == 0)
	{
		freeproc(p);
		release(&p->lock);
		return 0;
	}
	
	// An empty user page table.
	p->pagetable = proc_pagetable(p);
	if (p->pagetable == 0)
	{
		freeproc(p);
		release(&p->lock);
		return 0;
	}

	// 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;

	return p;
}

// free a proc structure and the data hanging from it,
// including user pages.
// p->lock must be held.
static void
freeproc(struct proc *p)
{
	if (p->trapframe)
		kfree((void *)p->trapframe);
	p->trapframe = 0;
	if (p->alarm_frame)
	{
		kfree((void *)p->alarm_frame);
	}
	p->alarm_frame = 0;
	if (p->pagetable)
		proc_freepagetable(p->pagetable, p->sz);
	p->pagetable = 0;
	p->sz = 0;
	p->pid = 0;
	p->parent = 0;
	p->name[0] = 0;
	p->chan = 0;
	p->killed = 0;
	p->xstate = 0;
	p->state = UNUSED;
}

uint64
sys_sigalarm(void)
{
	int ticks;
	uint64 handler;
	struct proc *p = myproc();

	argint(0, &ticks);
	argaddr(1, &handler);

	p->alarm_interval = ticks;
	p->alarm_handler = (void*)handler;
	p->alarm_ticks = 0;
	p->alarm_is_returned = 1;

	return 0;
}

uint64
sys_sigreturn(void)
{
	struct proc *p = myproc();

	p->alarm_ticks = 0;
	p->alarm_is_returned = 1;

	memmove((void*)p->trapframe,(const void*)p->alarm_frame,sizeof(struct trapframe));

	return p->trapframe->a0;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值