Presentation is loading. Please wait.

Presentation is loading. Please wait.

Discussions on HW2 Objectives

Similar presentations


Presentation on theme: "Discussions on HW2 Objectives"— Presentation transcript:

1 Discussions on HW2 Objectives
Implement tiny-UNIX on SAPC with 3 syscalls: read(dev, buf, nchar) write(dev, buf, nchar) exit(exitcode)

2 Steps in Making a System Call
count = read (fd, buffer, nbytes); _read read(…) syscall syscallc ttyread Table of Pointers

3 System Call Instruction
Instruction to cause execution to jump out of user execution into the kernel in a safe way For SUN SPARC processors, use ta (trap always) For Intel x86 processors, use int movl arg1, %ebx #move 1st argument in ebx movl arg2, %ecx #move 2nd argument in ecx movl arg3, %edx #move 3rd argument in edx movl $callno, %eax #move syscall # in eax int $0x80 #trap to kernel

4 Comparison Between Interrupts and Traps
CPU Interrupt Cycle saves CPU state (EIP and EFLAGS) gets interrupt vector number(nn) from PIC look up the ISR address in IDT[nn] and set EIP CPU enters kernel mode with IF=0 ISR services the interrupt and ends with “iret” to restore previously saved state and resume from point of interrupt CPU Trap Cycle saves CPU state(EIP and EFLAGS) gets ID(nn) from instruction operand looks up the trap handler address in IDT[nn] and set EIP Use number stored in %eax to determine the corresponding system call to service CPU enters kernel mode with IF=1 Trap handler services the system call and ends with “iret” to restore previously saved state and continues execution just after the int $nn

5 System Call Steps in hw2 1. User code in C does a read(dev, buf,nbytes) uprog.c 2. Calls in user library ulib.s 3.ulib copies dev, buf,nbytes off the stack into registers, put 3 in eax as syscall number. Trap to kernel by executing int $0x80 4. CPU trap cycle handler: save CPU stack on stack, get new EIP=(address of _syscall) from trap vector IDT[0x80] 5. _syscall executes, saves registers on the stack and call C syscall handler (_syscallc) sysentry.s 6. It accesses the saved registers via its args, determines from the syscall number that it should call sysread tunix.c 7. sysread executes, does the input and return to _syscallc io.c,tunix.c 8. Return to _syscall, restore registers and do final iret sysentry.s 9. Finish lib which ends with “ret” which restores saved ulib.s EIP and the “ret” causes function return 10.return to user C code after the call to read uprog.c

6 lib calls to do write, read, exit
User Program Flow startup0.s: Same as $pclibsrc/startup0.s - init kernel stack Start from Tutor Init memory Init kernel Start-up User program lib calls to do write, read, exit startup1.c: Modify from $pclibsrc/startup.c to call init kernel instead of main Part of tunix.c: new module -call ioinit -call set_trap_gate(0x80, &syscall) modified from set_intr_gate in $pclibsrc/cpu.c -call _ustart() crt0.s: Modify from $pclibsrc/startup0.s -init user stack -call _main -call _exit uprog.c: Modify from testio.c: -have a main -remove ioinit -call write -call read ulib.s: syscall lib setups; call trap handler;_write provided -add _read -add _exit

7 Kernel Program Flows sysentry.s: Modify from $pclibsrc/irq4.s
-push eax,ebx,ecd,edx on stack -call system call dispatcher: _syscallc -pop stack and iret Trap handler wrapper System call dispatcher Part of tunix.c: -depend on syscall #, call the handler routine System call trap handler routine io.c: same as hw1 -need to modify read to sysread -need to modify write to syswrite

8 Assembler/C Argument Passing
The C line is compiled into assembler code: write(dev,buf,nbytes) > pushl nbytes pushl buf pushl dev call _write On x86, stack grows from high address to low address At _write, the stack looks like: For GNU C, eax contains the return variable arg1 arg2 arg3 #%esp=%esp-4; (%esp) <- nbytes #%esp=%esp-4; (%esp) <- buf #%esp=%esp-4; (%esp) <- dev %esp before calling write High address nbytes buf dev Return address %esp at _write Low address

9 Assembler/C Function Calling
Assembler program calling a C function functc globl _functc, _funct _funct: pushl %edx #push reg to stack call _functc # call c function popl %edx # pop stack to reg ret C program calling an assembler function ustart extern void ustart(void) globl _ustart void init () _ustart: ….. { … …. ustart(); ret }

10 The write assembler code
_write: pushl %ebx # save the value of ebx movl 8(%esp),%ebx # arg1 in ebx movl 12(%esp),%ecx # arg2 in ecx movl 16(%esp),%edx # arg3in edx movl $4,%eax # syscall number in eax int $0x # trap to kernel popl %ebx # restore the value of ebx ret Register storage dev --> ebx nbytes--> edx buf --> ecx syscall#-->eax Need to preserve ebx (not a C scratch register) because ebx is used in the routine

11 syscall in sysentry.s _syscall: pushl %edx # push the values of eax to edx to stack pushl %ecx pushl %ebx pushl %eax call _syscallc # call c trap routine in tunix.c popl %eax # or replace it with add $4, %esp to # skip over the eax from the stack popl %ebx # pop the values of ebx to edx from stack popl %ecx popl %edx iret

12 The syscallc C program Using the stack-register-stack method, we can call a C function using an assembler routine void syscallc(int user_eax, int arg1, char * arg2, int arg3) {… user_eax = syswrite(…); }

13 exit code Look at startup0.s # asm startup file
# very first module in load movl $0x3ffff0, %esp # set user program stack movl $0, %ebp # make debugger backtrace terminate here call _startupc # call C startup, which calls user main int $ # return to Tutor Add a label to int $3 to make it callable For suggested step 3: pass a bogus exit code For suggested step 4: pass the exit code from main

14 debug_log function New capability for debugging
sprintf(buf, “^%c”, ch); debug_log(buf); New capability for debugging stores the report in memory starting at 0x and then outputs them If the program crashes, you can still use Tutor to see the log Tutor> md use debug_log(“~”) to mark each interrupt debug_log(“e”) for an echo debug_log(“s”) for shutdown Tx interrupts

15 Suggested Steps 1. Get a system built. Change io.c's write to syswrite, read to sysread, fill out startup0 and startup1, write a tiny tunix.c init fn that calls ioinit, then calls main (cheating for now--later it should call ustart), and then returns to startup, shutting down. At this point, test1.c just has a main that kprintf's a message. Now it should build and run, but does no syscalls. 2. ulib.s is set up for write already, so do the write syscall first. Set the trap vector up in kernel init in tunix.c, and write sysentry.s—have it push registers on the stack and then call into tunix.c. In tunix.c, access the pushed registers (themselves syscall arguments from the user) via args to the C function, and call syswrite. Make test1.c do a simple write. We'll go over the trick about the syscall args in class. 3. Next implement syscall exit and add an exit to test1.c. 4. Write the proper user startup module crt0.s to reinitialize the stack and call into main, then when that returns, it does an exit syscall. It has entry point _ustart. Change the call to main in kernel initialization to call ustart now. Try a user program without its own exit syscall.


Download ppt "Discussions on HW2 Objectives"

Similar presentations


Ads by Google