Required reading: xv6 trapasm.S
, trap.c
, syscall.c
, usys.S
.
You will need to consult
IA32 System
Programming Guide chapter 5 (skip 5.7.1, 5.8.2, 5.12.2).
Big picture: kernel is trusted third-party that runs the machine. Only the kernel can execute privileged instructions (e.g., changing MMU state). The processor enforces this protection through the ring bits in the code segment. If a user application needs to carry out a privileged operation or other kernel-only service, it must ask the kernel nicely. How can a user program change to the kernel address space? How can the kernel transfer to a user address space? What happens when a device attached to the computer needs attention? These are the topics for today's lecture.
There are three kinds of events that must be handled by the kernel, not user programs: (1) a system call invoked by a user program, (2) an illegal instruction or other kind of bad processor state (memory fault, etc.). and (3) an interrupt from a hardware device.
Although these three events are different, they all use the same mechanism to transfer control to the kernel. This mechanism consists of three steps that execute as one atomic unit. (a) change the processor to kernel mode; (b) save the old processor somewhere (usually the kernel stack); and (c) change the processor state to the values set up as the “official kernel entry values.” The exact implementation of this mechanism differs from processor to processor, but the idea is the same.
We'll work through examples of these today in lecture. You'll see all three in great detail in the labs as well.
A note on terminology: sometimes we'll use interrupt (or trap) to mean both interrupts and exceptions.
See handout Table 5-1, Figure 5-1, Figure 5-2.
xv6 Sheet 07: struct gatedesc
and SETGATE
.
xv6 Sheet 28: tvinit
and idtinit
.
Note setting of gate for T_SYSCALL
xv6 Sheet 29: vectors.pl
(also see generated vectors.S
).
xv6 Sheet 16: init.c
calls open("console")
.
How is that implemented?
xv6 usys.S
(not in book).
(No saving of registers. Why?)
Breakpoint 0x1b:"open"
,
step past int
instruction into kernel.
See handout Figure 9-4 [sic].
xv6 Sheet 28: in vectors.S
briefly, then in alltraps
.
Step through to call trap
, examine registers and stack.
How will the kernel find the argument to open
?
xv6 Sheet 29: trap
, on to syscall
.
xv6 Sheet 31: syscall
looks at eax
,
calls sys_open
.
(Briefly)
xv6 Sheet 52: sys_open
uses argstr
and argint
to get its arguments. How do they work?
xv6 Sheet 30: fetchint
, fetcharg
, argint
,
argptr
, argstr
.
What happens if a user program divides by zero
or accesses unmapped memory?
Exception. Same path as system call until trap
.
What happens if kernel divides by zero or accesses unmapped memory?
Like system calls, except: devices generate them at any time, there are no arguments in CPU registers, nothing to return to, usually can't ignore them.
How do they get generated?
Device essentially phones up the
interrupt controller and asks to talk to the CPU.
Interrupt controller then buzzes the CPU and
tells it, “keyboard on line 1.”
Interrupt controller is essentially the CPU's
secretary administrative assistant,
managing the phone lines on the CPU's behalf.
Have to set up interrupt controller.
(Briefly) xv6 Sheet 63: pic_init
sets up the interrupt controller,
irq_enable
tells the interrupt controller to let the given
interrupt through.
(Briefly) xv6 Sheet 68: pit8253_init
sets up the clock chip,
telling it to interrupt on IRQ_TIMER
100 times/second.
console_init
sets up the keyboard, enabling IRQ_KBD
.
In Bochs, set breakpoint at 0x8:"vector0" and continue, loading kernel. Step through clock interrupt, look at stack, registers.
Was the processor executing in kernel or user mode at the time of the clock interrupt? Why? (Have any user-space instructions executed at all?)
Can the kernel get an interrupt at any time?
Why or why not? cli
and sti
,
irq_enable
.