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=, argv«) at user/test_read.c:11

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