CS450: 2023Spring
Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit
CS450: 2023Spring
1) (15 points) You will trace the read () system call. Assume that a user program executes the statement read (fd, *buf, count) but fd is undefined. | Therefore, the result of the execution will be an exception. You are asked to write down in a document which lines in which files of xv6 are executed. Organize the lines of code into blocks of code and explain the purpose of each of block. The result will be a story of what happened when a non-existing file descriptor is given to a read (). The story starts in the user space when the system call first gets executed and ends with feedback to the user that fd is bad. «
1. User mode, call read function
int main(int argc, char *argv[])
char buf[1024]={,,\0,};
// unvalid fd
int fd =・3; read(fd, buf, 10);
「 exit(0);
s
2. User mode, the syscall
ecall: from user mode switch to kernel mode
1. a7: store the syscall number
2. a0-a6 store arguments
3. syscall puts return value in aO when its done then we trace sys_write
Breakpoint 2, read () at user/usys.S:25
25 li a7, SYS_read
(gdb) 1
20 li a7, SYS_pipe
21 ecall
22 ret
23 .global read
24 read:
25 li a7, SYS_read
26 ecall
27 ret
28 .global write
29 write:
(gdb) backtrace
#0 read () at user/usys.S:25
#1 0x0000000000000036 in main (argc=
3. kernel mode Trampoline(kernel/trampoline.S)
For its cpu logic cmd, so we can not see it in GDB
Kernel will need a7 and ao-a6 to handle the syscall.(wrapped by TRAPFRAME) Saved registers will need to be restored when we finish.
sys_read () at kernel/sysfile.c:70
0X0000000080002576 in syscall () at kernel/syscall.c:141 0x000000008000286c in usertrap () at kernel/trap.c:67 0x0000000000000036 in ??()
4. usertrap()(kernel/trap.c)
Entry c code point: for systemcalls,exceptions,interrupts
5. syscall handler (kernel/syscall.c)
12 syscall(void)
3 {
14 int num;
15 struct proc *p = myproc();
16
16 num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
19 // Use num to lookup the system call function for num, call it,
I。 // and store its return value in p->trapframe->a0
1-1 p->trapframe->a0 = syscalls[num]();
12 } else &
printf("%d %s: unknown sys call %d\n",
冋 p->pid, p->name, num);
15 p->trapframe->a0 =・1;
6. sys_read (kernel/sysfile.c)
68 |
uint64 |
|
69 |
sys_read(void) |
|
70 |
I ' |
|
71 |
struct file *f; |
|
72 |
int n; |
|
73 |
uint64 p; |
|
74 |
|
|
75 |
argaddr(lJ &p); |
|
76 |
argint(2, &n); |
|
77 |
if(argfd(0, 0, &f) |
< 0) |
78 |
return -1; |
|
79 |
return fileread(f, |
P, n); |
80 |
I |
|
argaddr:
// Retrieve an argument as a pointer. // Doesn't check for legality, since // copyin/copyout will do that. void
argaddr(int n, uint64 *ip)
argint:
// Fetch the nth 32-bit system call argument, void
argint(int n, int *ip)
argfd:
// Fetch the nth word-sized system call argument as a file descriptor // and return both the descriptor and the corresponding struct file, static int
argfd(|int n, int *pfd, struct file **pf|)|
We can see they are both Function that can get the information of the n'th register and point to it with some type.
So when we input an unvalid fd,
77 if(argfd(0, 0, &f) < 6)
(gdb) step
argfd (n=n^entry=0, pfd=pfd@entry=0x0, pf=pf^entry=0x3fffff9fa8) at kernel/sysfile.c:27
27 argint(n, &fd);
(gdb) 1
22 argfd(int n, int *pfd, struct file **pf)
23 {
24 int fd;
25 struct file
26
26 _ argint(n^_&fd);
27 if(fd < 0 I I fd >= NOFILE 11 (f=myproc()->ofile[fd]) == 0)
28 return -1;
29 if(pfd)
30 *pfd - fd;
(gdb) print fd
$3 = 0
(gdb) n
28 if(fd < 0 I I fd >- NOFILE || (f»myproc()->ofile[fd]) “ 0)
(gdb) print fd
$4 =• -3
(gdb) ■
We can see that function return -1
7. return and switch back to user mode (kernel/trampoline.S)
# restore user a。~
Id a。, 112(a0)
# return to user mode and user pc.
# usertrapretf) set up sstatus and sepc. sret
ii. (20 points) The program that calls alsoNice() will have its time slice increased to n times "
Add time_slice
And time_slice_tick
Define T = 1
#define T 1
// Pep-ppoc6ss te
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 |
wa |
int pid; |
// Process ID |
|
|
// wait_lock must be held when using this: struct proc *parent; // Parent process
int time_slice; // jun int time_slice_tick;
Initialize time slice to Zero
// initialize the proc table.
\ftid procinit(void)
struct proc *p;
initlock(&pid_lockJ "nextpid"); initlock(&wait_lock, "wait_lock"); for(p = proc; p < &proc[NPROC]; p++) { initlock(&p->lock, "proc"); p->state = UNUSED;
p->kstack = KSTACK((int) (p - proc)); p->time_slice = 0;
p->time_slice_tick = p->time_slice; p->priority = 0;
}
}
When process ended, we reset the value.
346 |
// Exit the current process. Does not return. |
347 |
// An exited process remains in the zombie state |
348 |
// until its parent calls wait(). |
349 |
void |
350 |
exit(int status) |
351 |
{ |
352 |
struct proc *p = myproc(); |
353 |
|
354 |
if(p == initproc) |
355 |
panic("init exiting"); |
356 |
|
357 |
// Close all open files. |
358 |
for(int fd = 0; fd < NOFILE; fd++)( |
359 |
if(p->ofile[fd])( |
360 |
struct file *f = p->ofile[fd]; |
361 |
fileclose(f); |
362 |
p->ofile[fd] = 0; |
363 |
} |
364 |
} |
365 |
|
366 |
p->time_slice = 0; |
367 |
p->time_slice_tick = 0; |
368 |
|
369 |
begin_op(); |
alsoNice implement
When input n < 0 , its invalid, we return -1
3 5 6 |
// jun uint64 sys_alsoNice(void) fl . |
|
7 8 |
|
int times; |
9 |
|
argint(。, ×); |
2 |
|
if (times < 0) ( |
3 |
|
return -1; |
7 4 6 |
|
} struct proc *p = myproc(); acquire(&p->lock); p->time_slice += times * T; p->time_slice_tick += p->time_slice; printf("numll : %d ", p->time_slice_tick); release(&p->lock);| return 0; 3 |
And we need to handle time slice in scheduler before switch context.
acquire(&p_used->lock); p_used->state = RUNNING; c->proc = p_used;
p_used->time_slice_tick -= T; // jun if(p_used->time_slice_tick <= 0) {
p_used->time_slice = 0; p_used->time_slice_tick = 0;
swtch(&c->context, &p_used->context);
3) (15 points on 3.3, 3.4 and 3.7) A manual page for the system call alsoNice () including the exception handling interface. You also need to describe how to call it from user level. This document should not be longer than 1 page.,
And here we need to define some function and marco
To implement a new system call.
user call func alsoNice -> ecall -> trampoline ->usertrap -> systemcall -> sys_a Iso Nice ->return and switch back to user mode
22 #define SYS_close 21
23
> 24+ #define SYS_alsoNice 22 25+1
39 40+ entry("alsoNice"); # // jun 41+1
$U/_zombie\ $U/_test_read\ $U/_test_alsoNice\
extern uint64 sys_alsoNice(void);
int alsoNice(int); // jun
Here we use GDB to show:
user call func alsoNice -> ecall -> trampoline ->usertrap -> systemcall -> sys_a Iso Nice
->return and switch back to user mode
(gdb) b alsoNice
Breakpoint 1 at 0x4a4: file user/usys.S, line 110. (gdb) c
Continuing.
Breakpoint 1, alsoNice () at user/usys.S:110
110 |
li a7, SYS_alsoNice |
(gdb) |
1 |
105 |
li a7, SYS_uptime |
106 |
ecall |
107 |
ret |
108 |
.global alsoNice |
109 |
alsoNice: |
110 |
li a7, SYS_alsoNice |
111 |
ecall |
112 |
ret |
(gdb) |
backtrace |
2023-04-10