PKUOS - Pintos
Pintos source browser for PKU Operating System course
Macros | Functions | Variables
interrupt.c File Reference
#include "threads/interrupt.h"
#include <debug.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include "threads/flags.h"
#include "threads/intr-stubs.h"
#include "threads/io.h"
#include "threads/thread.h"
#include "threads/vaddr.h"
#include "devices/timer.h"
Include dependency graph for interrupt.c:

Go to the source code of this file.

Macros

#define PIC0_CTRL   0x20
 Programmable Interrupt Controller (PIC) registers. More...
 
#define PIC0_DATA   0x21
 Master PIC data register address. More...
 
#define PIC1_CTRL   0xa0
 Slave PIC control register address. More...
 
#define PIC1_DATA   0xa1
 Slave PIC data register address. More...
 
#define INTR_CNT   256
 Number of x86 interrupts. More...
 

Functions

static void pic_init (void)
 Programmable Interrupt Controller helpers. More...
 
static void pic_end_of_interrupt (int irq)
 Sends an end-of-interrupt signal to the PIC for the given IRQ. More...
 
static uint64_t make_intr_gate (void(*)(void), int dpl)
 Interrupt Descriptor Table helpers. More...
 
static uint64_t make_trap_gate (void(*function)(void), int dpl)
 Creates a trap gate that invokes FUNCTION with the given DPL. More...
 
static uint64_t make_idtr_operand (uint16_t limit, void *base)
 Returns a descriptor that yields the given LIMIT and BASE when used as an operand for the LIDT instruction. More...
 
void intr_handler (struct intr_frame *args)
 Interrupt handlers. More...
 
static void unexpected_interrupt (const struct intr_frame *f)
 Handles an unexpected interrupt with interrupt frame F. More...
 
enum intr_level intr_get_level (void)
 Returns the current interrupt status. More...
 
enum intr_level intr_set_level (enum intr_level level)
 Enables or disables interrupts as specified by LEVEL and returns the previous interrupt status. More...
 
enum intr_level intr_enable (void)
 Enables interrupts and returns the previous interrupt status. More...
 
enum intr_level intr_disable (void)
 Disables interrupts and returns the previous interrupt status. More...
 
void intr_init (void)
 Initializes the interrupt system. More...
 
static void register_handler (uint8_t vec_no, int dpl, enum intr_level level, intr_handler_func *handler, const char *name)
 Registers interrupt VEC_NO to invoke HANDLER with descriptor privilege level DPL. More...
 
void intr_register_ext (uint8_t vec_no, intr_handler_func *handler, const char *name)
 Registers external interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes. More...
 
void intr_register_int (uint8_t vec_no, int dpl, enum intr_level level, intr_handler_func *handler, const char *name)
 Registers internal interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes. More...
 
bool intr_context (void)
 Returns true during processing of an external interrupt and false at all other times. More...
 
void intr_yield_on_return (void)
 During processing of an external interrupt, directs the interrupt handler to yield to a new process just before returning from the interrupt. More...
 
static uint64_t make_gate (void(*function)(void), int dpl, int type)
 Creates an gate that invokes FUNCTION. More...
 
void intr_dump_frame (const struct intr_frame *f)
 Dumps interrupt frame F to the console, for debugging. More...
 
const char * intr_name (uint8_t vec)
 Returns the name of interrupt VEC. More...
 

Variables

static uint64_t idt [INTR_CNT]
 The Interrupt Descriptor Table (IDT). More...
 
static intr_handler_funcintr_handlers [INTR_CNT]
 Interrupt handler functions for each interrupt. More...
 
static const char * intr_names [INTR_CNT]
 Names for each interrupt, for debugging purposes. More...
 
static unsigned int unexpected_cnt [INTR_CNT]
 Number of unexpected interrupts for each vector. More...
 
static bool in_external_intr
 External interrupts are those generated by devices outside the CPU, such as the timer. More...
 
static bool yield_on_return
 Should we yield on interrupt return? More...
 

Macro Definition Documentation

◆ INTR_CNT

#define INTR_CNT   256

Number of x86 interrupts.

Definition at line 22 of file interrupt.c.

◆ PIC0_CTRL

#define PIC0_CTRL   0x20

Programmable Interrupt Controller (PIC) registers.

A PC has two PICs, called the master and slave PICs, with the slave attached ("cascaded") to the master IRQ line 2. Master PIC control register address.

Definition at line 16 of file interrupt.c.

◆ PIC0_DATA

#define PIC0_DATA   0x21

Master PIC data register address.

Definition at line 17 of file interrupt.c.

◆ PIC1_CTRL

#define PIC1_CTRL   0xa0

Slave PIC control register address.

Definition at line 18 of file interrupt.c.

◆ PIC1_DATA

#define PIC1_DATA   0xa1

Slave PIC data register address.

Definition at line 19 of file interrupt.c.

Function Documentation

◆ intr_context()

bool intr_context ( void  )

Returns true during processing of an external interrupt and false at all other times.

Definition at line 212 of file interrupt.c.

References in_external_intr.

Referenced by acquire_console(), cond_signal(), cond_wait(), console_locked_by_current_thread(), intq_getc(), intq_putc(), intr_enable(), intr_handler(), intr_yield_on_return(), lock_acquire(), release_console(), sema_down(), thread_block(), thread_exit(), thread_yield(), and wait().

Here is the caller graph for this function:

◆ intr_disable()

enum intr_level intr_disable ( void  )

Disables interrupts and returns the previous interrupt status.

Definition at line 104 of file interrupt.c.

References intr_get_level().

Referenced by debug_backtrace_all(), debug_panic(), idle(), init_thread(), input_getc(), intr_set_level(), pit_configure_channel(), sema_down(), sema_try_down(), sema_up(), serial_flush(), serial_init_queue(), serial_putc(), speaker_off(), speaker_on(), thread_exit(), thread_unblock(), thread_yield(), timer_ticks(), and vga_putc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_dump_frame()

void intr_dump_frame ( const struct intr_frame f)

Dumps interrupt frame F to the console, for debugging.

Definition at line 411 of file interrupt.c.

References intr_frame::cs, intr_frame::ds, intr_frame::eax, intr_frame::ebp, intr_frame::ebx, intr_frame::ecx, intr_frame::edi, intr_frame::edx, intr_frame::eip, intr_frame::error_code, intr_frame::es, intr_frame::esi, intr_frame::esp, intr_names, printf(), PRIx16, PRIx32, intr_frame::ss, and intr_frame::vec_no.

Referenced by kill().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_enable()

enum intr_level intr_enable ( void  )

Enables interrupts and returns the previous interrupt status.

Definition at line 88 of file interrupt.c.

References ASSERT, intr_context(), and intr_get_level().

Referenced by intr_set_level(), kernel_thread(), page_fault(), and thread_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_get_level()

enum intr_level intr_get_level ( void  )

◆ intr_handler()

void intr_handler ( struct intr_frame frame)

Interrupt handlers.

Handler for all interrupts, faults, and exceptions. This function is called by the assembly language interrupt stubs in intr-stubs.S. FRAME describes the interrupt and the interrupted thread's registers.

Definition at line 345 of file interrupt.c.

References ASSERT, in_external_intr, intr_context(), intr_get_level(), intr_handlers, INTR_OFF, NULL, pic_end_of_interrupt(), thread_yield(), unexpected_interrupt(), intr_frame::vec_no, and yield_on_return.

Here is the call graph for this function:

◆ intr_init()

void intr_init ( void  )

Initializes the interrupt system.

Definition at line 118 of file interrupt.c.

References idt, INTR_CNT, intr_names, intr_stubs, make_idtr_operand(), make_intr_gate(), and pic_init().

Referenced by pintos_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_name()

const char * intr_name ( uint8_t  vec)

Returns the name of interrupt VEC.

threads/interrupt.h

Definition at line 435 of file interrupt.c.

References intr_names.

Referenced by kill().

Here is the caller graph for this function:

◆ intr_register_ext()

void intr_register_ext ( uint8_t  vec_no,
intr_handler_func handler,
const char *  name 
)

Registers external interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes.

The handler will execute with interrupts disabled.

Definition at line 181 of file interrupt.c.

References ASSERT, INTR_OFF, name, and register_handler().

Referenced by ide_init(), kbd_init(), serial_init_queue(), and timer_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_register_int()

void intr_register_int ( uint8_t  vec_no,
int  dpl,
enum intr_level  level,
intr_handler_func handler,
const char *  name 
)

Registers internal interrupt VEC_NO to invoke HANDLER, which is named NAME for debugging purposes.

The interrupt handler will be invoked with interrupt status LEVEL.

The handler will have descriptor privilege level DPL, meaning that it can be invoked intentionally when the processor is in the DPL or lower-numbered ring. In practice, DPL==3 allows user mode to invoke the interrupts and DPL==0 prevents such invocation. Faults and exceptions that occur in user mode still cause interrupts with DPL==0 to be invoked. See [IA32-v3a] sections 4.5 "Privilege Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments" for further discussion.

Definition at line 202 of file interrupt.c.

References ASSERT, name, and register_handler().

Referenced by exception_init(), and syscall_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_set_level()

enum intr_level intr_set_level ( enum intr_level  level)

Enables or disables interrupts as specified by LEVEL and returns the previous interrupt status.

Definition at line 81 of file interrupt.c.

References intr_disable(), intr_enable(), and INTR_ON.

Referenced by debug_backtrace_all(), init_thread(), input_getc(), pit_configure_channel(), sema_down(), sema_try_down(), sema_up(), serial_flush(), serial_init_queue(), serial_putc(), speaker_off(), speaker_on(), thread_unblock(), thread_yield(), timer_ticks(), and vga_putc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ intr_yield_on_return()

void intr_yield_on_return ( void  )

During processing of an external interrupt, directs the interrupt handler to yield to a new process just before returning from the interrupt.

May not be called at any other time.

Definition at line 222 of file interrupt.c.

References ASSERT, intr_context(), and yield_on_return.

Referenced by thread_tick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_gate()

static uint64_t make_gate ( void(*)(void)  function,
int  dpl,
int  type 
)
static

Creates an gate that invokes FUNCTION.

The gate has descriptor privilege level DPL, meaning that it can be invoked intentionally when the processor is in the DPL or lower-numbered ring. In practice, DPL==3 allows user mode to call into the gate and DPL==0 prevents such calls. Faults and exceptions that occur in user mode still cause gates with DPL==0 to be invoked. See [IA32-v3a] sections 4.5 "Privilege Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments" for further discussion.

TYPE must be either 14 (for an interrupt gate) or 15 (for a trap gate). The difference is that entering an interrupt gate disables interrupts, but entering a trap gate does not. See [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or Interrupt-Handler Procedure" for discussion.

< Offset 15:0.

< Target code segment.

< Offset 31:16.

< Present.

< Descriptor privilege level.

< System.

< Gate type.

Definition at line 294 of file interrupt.c.

References ASSERT, NULL, and SEL_KCSEG.

Referenced by make_intr_gate(), and make_trap_gate().

Here is the caller graph for this function:

◆ make_idtr_operand()

static uint64_t make_idtr_operand ( uint16_t  limit,
void *  base 
)
inlinestatic

Returns a descriptor that yields the given LIMIT and BASE when used as an operand for the LIDT instruction.

Definition at line 333 of file interrupt.c.

Referenced by intr_init().

Here is the caller graph for this function:

◆ make_intr_gate()

static uint64_t make_intr_gate ( void(*)(void)  function,
int  dpl 
)
static

Interrupt Descriptor Table helpers.

Creates an interrupt gate that invokes FUNCTION with the given DPL.

Definition at line 317 of file interrupt.c.

References make_gate().

Referenced by intr_init(), and register_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_trap_gate()

static uint64_t make_trap_gate ( void(*)(void)  function,
int  dpl 
)
static

Creates a trap gate that invokes FUNCTION with the given DPL.

Definition at line 325 of file interrupt.c.

References make_gate().

Referenced by register_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pic_end_of_interrupt()

static void pic_end_of_interrupt ( int  irq)
static

Sends an end-of-interrupt signal to the PIC for the given IRQ.

If we don't acknowledge the IRQ, it will never be delivered to us again, so this is important.

Definition at line 265 of file interrupt.c.

References ASSERT, and outb().

Referenced by intr_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pic_init()

static void pic_init ( void  )
static

Programmable Interrupt Controller helpers.

8259A Programmable Interrupt Controller.

Initializes the PICs. Refer to [8259A] for details.

By default, interrupts 0...15 delivered by the PICs will go to interrupt vectors 0...15. Those vectors are also used for CPU traps and exceptions, so we reprogram the PICs so that interrupts 0...15 are delivered to interrupt vectors 32...47 (0x20...0x2f) instead.

< ICW1: single mode, edge triggered, expect ICW4.

< ICW2: line IR0...7 -> irq 0x20...0x27.

< ICW3: slave PIC on line IR2.

< ICW4: 8086 mode, normal EOI, non-buffered.

< ICW1: single mode, edge triggered, expect ICW4.

< ICW2: line IR0...7 -> irq 0x28...0x2f.

< ICW3: slave ID is 2.

< ICW4: 8086 mode, normal EOI, non-buffered.

Definition at line 238 of file interrupt.c.

References outb(), PIC0_CTRL, PIC0_DATA, PIC1_CTRL, and PIC1_DATA.

Referenced by intr_init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ register_handler()

static void register_handler ( uint8_t  vec_no,
int  dpl,
enum intr_level  level,
intr_handler_func handler,
const char *  name 
)
static

Registers interrupt VEC_NO to invoke HANDLER with descriptor privilege level DPL.

Names the interrupt NAME for debugging purposes. The interrupt handler will be invoked with interrupt status set to LEVEL.

Definition at line 165 of file interrupt.c.

References ASSERT, idt, intr_handlers, intr_names, INTR_ON, intr_stubs, make_intr_gate(), make_trap_gate(), name, and NULL.

Referenced by intr_register_ext(), and intr_register_int().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ unexpected_interrupt()

static void unexpected_interrupt ( const struct intr_frame f)
static

Handles an unexpected interrupt with interrupt frame F.

An unexpected interrupt is one that has no registered handler.

Definition at line 394 of file interrupt.c.

References intr_names, printf(), unexpected_cnt, and intr_frame::vec_no.

Referenced by intr_handler().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ idt

uint64_t idt[INTR_CNT]
static

The Interrupt Descriptor Table (IDT).

The format is fixed by the CPU. See [IA32-v3a] sections 5.10 "Interrupt Descriptor Table (IDT)", 5.11 "IDT Descriptors", 5.12.1.2 "Flag Usage By Exception- or Interrupt-Handler Procedure".

Definition at line 28 of file interrupt.c.

Referenced by intr_init(), and register_handler().

◆ in_external_intr

bool in_external_intr
static

External interrupts are those generated by devices outside the CPU, such as the timer.

External interrupts run with interrupts turned off, so they never nest, nor are they ever pre-empted. Handlers for external interrupts also may not sleep, although they may invoke intr_yield_on_return() to request that a new process be scheduled just before the interrupt returns. Are we processing an external interrupt?

Definition at line 47 of file interrupt.c.

Referenced by intr_context(), and intr_handler().

◆ intr_handlers

intr_handler_func* intr_handlers[INTR_CNT]
static

Interrupt handler functions for each interrupt.

Definition at line 31 of file interrupt.c.

Referenced by intr_handler(), and register_handler().

◆ intr_names

const char* intr_names[INTR_CNT]
static

Names for each interrupt, for debugging purposes.

Definition at line 34 of file interrupt.c.

Referenced by intr_dump_frame(), intr_init(), intr_name(), register_handler(), and unexpected_interrupt().

◆ unexpected_cnt

unsigned int unexpected_cnt[INTR_CNT]
static

Number of unexpected interrupts for each vector.

An unexpected interrupt is one that has no registered handler.

Definition at line 38 of file interrupt.c.

Referenced by unexpected_interrupt().

◆ yield_on_return

bool yield_on_return
static

Should we yield on interrupt return?

Definition at line 48 of file interrupt.c.

Referenced by intr_handler(), and intr_yield_on_return().