CS318 - Pintos
Pintos source browser for JHU CS318 course
interrupt.c
Go to the documentation of this file.
1 #include "threads/interrupt.h"
2 #include <debug.h>
3 #include <inttypes.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include "threads/flags.h"
7 #include "threads/intr-stubs.h"
8 #include "threads/io.h"
9 #include "threads/thread.h"
10 #include "threads/vaddr.h"
11 #include "devices/timer.h"
12 
13 /** Programmable Interrupt Controller (PIC) registers.
14  A PC has two PICs, called the master and slave PICs, with the
15  slave attached ("cascaded") to the master IRQ line 2. */
16 #define PIC0_CTRL 0x20 /**< Master PIC control register address. */
17 #define PIC0_DATA 0x21 /**< Master PIC data register address. */
18 #define PIC1_CTRL 0xa0 /**< Slave PIC control register address. */
19 #define PIC1_DATA 0xa1 /**< Slave PIC data register address. */
20 
21 /** Number of x86 interrupts. */
22 #define INTR_CNT 256
23 
24 /** The Interrupt Descriptor Table (IDT). The format is fixed by
25  the CPU. See [IA32-v3a] sections 5.10 "Interrupt Descriptor
26  Table (IDT)", 5.11 "IDT Descriptors", 5.12.1.2 "Flag Usage By
27  Exception- or Interrupt-Handler Procedure". */
29 
30 /** Interrupt handler functions for each interrupt. */
32 
33 /** Names for each interrupt, for debugging purposes. */
34 static const char *intr_names[INTR_CNT];
35 
36 /** Number of unexpected interrupts for each vector. An
37  unexpected interrupt is one that has no registered handler. */
38 static unsigned int unexpected_cnt[INTR_CNT];
39 
40 /** External interrupts are those generated by devices outside the
41  CPU, such as the timer. External interrupts run with
42  interrupts turned off, so they never nest, nor are they ever
43  pre-empted. Handlers for external interrupts also may not
44  sleep, although they may invoke intr_yield_on_return() to
45  request that a new process be scheduled just before the
46  interrupt returns. */
47 static bool in_external_intr; /**< Are we processing an external interrupt? */
48 static bool yield_on_return; /**< Should we yield on interrupt return? */
49 
50 /** Programmable Interrupt Controller helpers. */
51 static void pic_init (void);
52 static void pic_end_of_interrupt (int irq);
53 
54 /** Interrupt Descriptor Table helpers. */
55 static uint64_t make_intr_gate (void (*) (void), int dpl);
56 static uint64_t make_trap_gate (void (*) (void), int dpl);
57 static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
58 
59 /** Interrupt handlers. */
60 void intr_handler (struct intr_frame *args);
61 static void unexpected_interrupt (const struct intr_frame *);
62 
63 /** Returns the current interrupt status. */
64 enum intr_level
66 {
67  uint32_t flags;
68 
69  /* Push the flags register on the processor stack, then pop the
70  value off the stack into `flags'. See [IA32-v2b] "PUSHF"
71  and "POP" and [IA32-v3a] 5.8.1 "Masking Maskable Hardware
72  Interrupts". */
73  asm volatile ("pushfl; popl %0" : "=g" (flags));
74 
75  return flags & FLAG_IF ? INTR_ON : INTR_OFF;
76 }
77 
78 /** Enables or disables interrupts as specified by LEVEL and
79  returns the previous interrupt status. */
80 enum intr_level
82 {
83  return level == INTR_ON ? intr_enable () : intr_disable ();
84 }
85 
86 /** Enables interrupts and returns the previous interrupt status. */
87 enum intr_level
88 intr_enable (void)
89 {
90  enum intr_level old_level = intr_get_level ();
91  ASSERT (!intr_context ());
92 
93  /* Enable interrupts by setting the interrupt flag.
94 
95  See [IA32-v2b] "STI" and [IA32-v3a] 5.8.1 "Masking Maskable
96  Hardware Interrupts". */
97  asm volatile ("sti");
98 
99  return old_level;
100 }
101 
102 /** Disables interrupts and returns the previous interrupt status. */
103 enum intr_level
105 {
106  enum intr_level old_level = intr_get_level ();
107 
108  /* Disable interrupts by clearing the interrupt flag.
109  See [IA32-v2b] "CLI" and [IA32-v3a] 5.8.1 "Masking Maskable
110  Hardware Interrupts". */
111  asm volatile ("cli" : : : "memory");
112 
113  return old_level;
114 }
115 
116 /** Initializes the interrupt system. */
117 void
118 intr_init (void)
119 {
120  uint64_t idtr_operand;
121  int i;
122 
123  /* Initialize interrupt controller. */
124  pic_init ();
125 
126  /* Initialize IDT. */
127  for (i = 0; i < INTR_CNT; i++)
128  idt[i] = make_intr_gate (intr_stubs[i], 0);
129 
130  /* Load IDT register.
131  See [IA32-v2a] "LIDT" and [IA32-v3a] 5.10 "Interrupt
132  Descriptor Table (IDT)". */
133  idtr_operand = make_idtr_operand (sizeof idt - 1, idt);
134  asm volatile ("lidt %0" : : "m" (idtr_operand));
135 
136  /* Initialize intr_names. */
137  for (i = 0; i < INTR_CNT; i++)
138  intr_names[i] = "unknown";
139  intr_names[0] = "#DE Divide Error";
140  intr_names[1] = "#DB Debug Exception";
141  intr_names[2] = "NMI Interrupt";
142  intr_names[3] = "#BP Breakpoint Exception";
143  intr_names[4] = "#OF Overflow Exception";
144  intr_names[5] = "#BR BOUND Range Exceeded Exception";
145  intr_names[6] = "#UD Invalid Opcode Exception";
146  intr_names[7] = "#NM Device Not Available Exception";
147  intr_names[8] = "#DF Double Fault Exception";
148  intr_names[9] = "Coprocessor Segment Overrun";
149  intr_names[10] = "#TS Invalid TSS Exception";
150  intr_names[11] = "#NP Segment Not Present";
151  intr_names[12] = "#SS Stack Fault Exception";
152  intr_names[13] = "#GP General Protection Exception";
153  intr_names[14] = "#PF Page-Fault Exception";
154  intr_names[16] = "#MF x87 FPU Floating-Point Error";
155  intr_names[17] = "#AC Alignment Check Exception";
156  intr_names[18] = "#MC Machine-Check Exception";
157  intr_names[19] = "#XF SIMD Floating-Point Exception";
158 }
159 
160 /** Registers interrupt VEC_NO to invoke HANDLER with descriptor
161  privilege level DPL. Names the interrupt NAME for debugging
162  purposes. The interrupt handler will be invoked with
163  interrupt status set to LEVEL. */
164 static void
165 register_handler (uint8_t vec_no, int dpl, enum intr_level level,
166  intr_handler_func *handler, const char *name)
167 {
168  ASSERT (intr_handlers[vec_no] == NULL);
169  if (level == INTR_ON)
170  idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
171  else
172  idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
173  intr_handlers[vec_no] = handler;
174  intr_names[vec_no] = name;
175 }
176 
177 /** Registers external interrupt VEC_NO to invoke HANDLER, which
178  is named NAME for debugging purposes. The handler will
179  execute with interrupts disabled. */
180 void
182  const char *name)
183 {
184  ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
185  register_handler (vec_no, 0, INTR_OFF, handler, name);
186 }
187 
188 /** Registers internal interrupt VEC_NO to invoke HANDLER, which
189  is named NAME for debugging purposes. The interrupt handler
190  will be invoked with interrupt status LEVEL.
191 
192  The handler will have descriptor privilege level DPL, meaning
193  that it can be invoked intentionally when the processor is in
194  the DPL or lower-numbered ring. In practice, DPL==3 allows
195  user mode to invoke the interrupts and DPL==0 prevents such
196  invocation. Faults and exceptions that occur in user mode
197  still cause interrupts with DPL==0 to be invoked. See
198  [IA32-v3a] sections 4.5 "Privilege Levels" and 4.8.1.1
199  "Accessing Nonconforming Code Segments" for further
200  discussion. */
201 void
202 intr_register_int (uint8_t vec_no, int dpl, enum intr_level level,
203  intr_handler_func *handler, const char *name)
204 {
205  ASSERT (vec_no < 0x20 || vec_no > 0x2f);
206  register_handler (vec_no, dpl, level, handler, name);
207 }
208 
209 /** Returns true during processing of an external interrupt
210  and false at all other times. */
211 bool
213 {
214  return in_external_intr;
215 }
216 
217 /** During processing of an external interrupt, directs the
218  interrupt handler to yield to a new process just before
219  returning from the interrupt. May not be called at any other
220  time. */
221 void
223 {
224  ASSERT (intr_context ());
225  yield_on_return = true;
226 }
227 
228 /** 8259A Programmable Interrupt Controller. */
229 
230 /** Initializes the PICs. Refer to [8259A] for details.
231 
232  By default, interrupts 0...15 delivered by the PICs will go to
233  interrupt vectors 0...15. Those vectors are also used for CPU
234  traps and exceptions, so we reprogram the PICs so that
235  interrupts 0...15 are delivered to interrupt vectors 32...47
236  (0x20...0x2f) instead. */
237 static void
238 pic_init (void)
239 {
240  /* Mask all interrupts on both PICs. */
241  outb (PIC0_DATA, 0xff);
242  outb (PIC1_DATA, 0xff);
243 
244  /* Initialize master. */
245  outb (PIC0_CTRL, 0x11); /**< ICW1: single mode, edge triggered, expect ICW4. */
246  outb (PIC0_DATA, 0x20); /**< ICW2: line IR0...7 -> irq 0x20...0x27. */
247  outb (PIC0_DATA, 0x04); /**< ICW3: slave PIC on line IR2. */
248  outb (PIC0_DATA, 0x01); /**< ICW4: 8086 mode, normal EOI, non-buffered. */
249 
250  /* Initialize slave. */
251  outb (PIC1_CTRL, 0x11); /**< ICW1: single mode, edge triggered, expect ICW4. */
252  outb (PIC1_DATA, 0x28); /**< ICW2: line IR0...7 -> irq 0x28...0x2f. */
253  outb (PIC1_DATA, 0x02); /**< ICW3: slave ID is 2. */
254  outb (PIC1_DATA, 0x01); /**< ICW4: 8086 mode, normal EOI, non-buffered. */
255 
256  /* Unmask all interrupts. */
257  outb (PIC0_DATA, 0x00);
258  outb (PIC1_DATA, 0x00);
259 }
260 
261 /** Sends an end-of-interrupt signal to the PIC for the given IRQ.
262  If we don't acknowledge the IRQ, it will never be delivered to
263  us again, so this is important. */
264 static void
266 {
267  ASSERT (irq >= 0x20 && irq < 0x30);
268 
269  /* Acknowledge master PIC. */
270  outb (0x20, 0x20);
271 
272  /* Acknowledge slave PIC if this is a slave interrupt. */
273  if (irq >= 0x28)
274  outb (0xa0, 0x20);
275 }
276 
277 /** Creates an gate that invokes FUNCTION.
278 
279  The gate has descriptor privilege level DPL, meaning that it
280  can be invoked intentionally when the processor is in the DPL
281  or lower-numbered ring. In practice, DPL==3 allows user mode
282  to call into the gate and DPL==0 prevents such calls. Faults
283  and exceptions that occur in user mode still cause gates with
284  DPL==0 to be invoked. See [IA32-v3a] sections 4.5 "Privilege
285  Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments"
286  for further discussion.
287 
288  TYPE must be either 14 (for an interrupt gate) or 15 (for a
289  trap gate). The difference is that entering an interrupt gate
290  disables interrupts, but entering a trap gate does not. See
291  [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
292  Interrupt-Handler Procedure" for discussion. */
293 static uint64_t
294 make_gate (void (*function) (void), int dpl, int type)
295 {
296  uint32_t e0, e1;
297 
298  ASSERT (function != NULL);
299  ASSERT (dpl >= 0 && dpl <= 3);
300  ASSERT (type >= 0 && type <= 15);
301 
302  e0 = (((uint32_t) function & 0xffff) /**< Offset 15:0. */
303  | (SEL_KCSEG << 16)); /**< Target code segment. */
304 
305  e1 = (((uint32_t) function & 0xffff0000) /**< Offset 31:16. */
306  | (1 << 15) /**< Present. */
307  | ((uint32_t) dpl << 13) /**< Descriptor privilege level. */
308  | (0 << 12) /**< System. */
309  | ((uint32_t) type << 8)); /**< Gate type. */
310 
311  return e0 | ((uint64_t) e1 << 32);
312 }
313 
314 /** Creates an interrupt gate that invokes FUNCTION with the given
315  DPL. */
316 static uint64_t
317 make_intr_gate (void (*function) (void), int dpl)
318 {
319  return make_gate (function, dpl, 14);
320 }
321 
322 /** Creates a trap gate that invokes FUNCTION with the given
323  DPL. */
324 static uint64_t
325 make_trap_gate (void (*function) (void), int dpl)
326 {
327  return make_gate (function, dpl, 15);
328 }
329 
330 /** Returns a descriptor that yields the given LIMIT and BASE when
331  used as an operand for the LIDT instruction. */
332 static inline uint64_t
333 make_idtr_operand (uint16_t limit, void *base)
334 {
335  return limit | ((uint64_t) (uint32_t) base << 16);
336 }
337 
338 /** Interrupt handlers. */
339 
340 /** Handler for all interrupts, faults, and exceptions. This
341  function is called by the assembly language interrupt stubs in
342  intr-stubs.S. FRAME describes the interrupt and the
343  interrupted thread's registers. */
344 void
345 intr_handler (struct intr_frame *frame)
346 {
347  bool external;
348  intr_handler_func *handler;
349 
350  /* External interrupts are special.
351  We only handle one at a time (so interrupts must be off)
352  and they need to be acknowledged on the PIC (see below).
353  An external interrupt handler cannot sleep. */
354  external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
355  if (external)
356  {
358  ASSERT (!intr_context ());
359 
360  in_external_intr = true;
361  yield_on_return = false;
362  }
363 
364  /* Invoke the interrupt's handler. */
365  handler = intr_handlers[frame->vec_no];
366  if (handler != NULL)
367  handler (frame);
368  else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
369  {
370  /* There is no handler, but this interrupt can trigger
371  spuriously due to a hardware fault or hardware race
372  condition. Ignore it. */
373  }
374  else
375  unexpected_interrupt (frame);
376 
377  /* Complete the processing of an external interrupt. */
378  if (external)
379  {
381  ASSERT (intr_context ());
382 
383  in_external_intr = false;
384  pic_end_of_interrupt (frame->vec_no);
385 
386  if (yield_on_return)
387  thread_yield ();
388  }
389 }
390 
391 /** Handles an unexpected interrupt with interrupt frame F. An
392  unexpected interrupt is one that has no registered handler. */
393 static void
395 {
396  /* Count the number so far. */
397  unsigned int n = ++unexpected_cnt[f->vec_no];
398 
399  /* If the number is a power of 2, print a message. This rate
400  limiting means that we get information about an uncommon
401  unexpected interrupt the first time and fairly often after
402  that, but one that occurs many times will not overwhelm the
403  console. */
404  if ((n & (n - 1)) == 0)
405  printf ("Unexpected interrupt %#04x (%s)\n",
406  f->vec_no, intr_names[f->vec_no]);
407 }
408 
409 /** Dumps interrupt frame F to the console, for debugging. */
410 void
411 intr_dump_frame (const struct intr_frame *f)
412 {
413  uint32_t cr2;
414 
415  /* Store current value of CR2 into `cr2'.
416  CR2 is the linear address of the last page fault.
417  See [IA32-v2a] "MOV--Move to/from Control Registers" and
418  [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
419  (#PF)". */
420  asm ("movl %%cr2, %0" : "=r" (cr2));
421 
422  printf ("Interrupt %#04x (%s) at eip=%p\n",
423  f->vec_no, intr_names[f->vec_no], f->eip);
424  printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
425  printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
426  f->eax, f->ebx, f->ecx, f->edx);
427  printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
428  f->esi, f->edi, (uint32_t) f->esp, f->ebp);
429  printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
430  f->cs, f->ds, f->es, f->ss);
431 }
432 
433 /** Returns the name of interrupt VEC. */
434 const char *
436 {
437  return intr_names[vec];
438 }
uint64_t
unsigned long long int uint64_t
Definition: stdint.h:29
name
char * name[]
Definition: insult.c:47
uint8_t
unsigned char uint8_t
Definition: stdint.h:20
pic_end_of_interrupt
static void pic_end_of_interrupt(int irq)
Sends an end-of-interrupt signal to the PIC for the given IRQ.
Definition: interrupt.c:265
INTR_CNT
#define INTR_CNT
Number of x86 interrupts.
Definition: interrupt.c:22
intr_context
bool intr_context(void)
Returns true during processing of an external interrupt and false at all other times.
Definition: interrupt.c:212
NULL
#define NULL
Definition: stddef.h:4
intr_level
intr_level
Interrupts on or off?
Definition: interrupt.h:8
intr_handler
void intr_handler(struct intr_frame *args)
Interrupt handlers.
Definition: interrupt.c:345
in_external_intr
static bool in_external_intr
External interrupts are those generated by devices outside the CPU, such as the timer.
Definition: interrupt.c:47
intr_frame::ss
uint16_t ss
Definition: interrupt.h:55
idt
static uint64_t idt[INTR_CNT]
The Interrupt Descriptor Table (IDT).
Definition: interrupt.c:28
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: interrupt.c:81
unexpected_cnt
static unsigned int unexpected_cnt[INTR_CNT]
Number of unexpected interrupts for each vector.
Definition: interrupt.c:38
intr_frame::eip
void(* eip)(void)
Next instruction to execute.
Definition: interrupt.h:51
SEL_KCSEG
#define SEL_KCSEG
Kernel code selector.
Definition: loader.h:30
yield_on_return
static bool yield_on_return
Should we yield on interrupt return?
Definition: interrupt.c:48
uint16_t
unsigned short int uint16_t
Definition: stdint.h:23
intr_frame::cs
uint16_t cs
Definition: interrupt.h:52
intr_frame::es
uint16_t uint16_t uint16_t es
Saved FS segment register.
Definition: interrupt.h:32
intr_frame::esp
void * esp
Saved stack pointer.
Definition: interrupt.h:54
PIC1_DATA
#define PIC1_DATA
Slave PIC data register address.
Definition: interrupt.c:19
block::type
enum block_type type
Type of block device.
Definition: block.c:14
PIC1_CTRL
#define PIC1_CTRL
Slave PIC control register address.
Definition: interrupt.c:18
pic_init
static void pic_init(void)
Programmable Interrupt Controller helpers.
Definition: interrupt.c:238
interrupt.h
uint32_t
unsigned int uint32_t
Definition: stdint.h:26
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
intr_get_level
enum intr_level intr_get_level(void)
Returns the current interrupt status.
Definition: interrupt.c:65
PIC0_CTRL
#define PIC0_CTRL
Programmable Interrupt Controller (PIC) registers.
Definition: interrupt.c:16
timer.h
intr_frame::ecx
uint32_t ecx
Saved ECX.
Definition: interrupt.h:30
intr_enable
enum intr_level intr_enable(void)
Enables interrupts and returns the previous interrupt status.
Definition: interrupt.c:88
intr_name
const char * intr_name(uint8_t vec)
Returns the name of interrupt VEC.
Definition: interrupt.c:435
intr-stubs.h
intr_frame::esi
uint32_t esi
Saved ESI.
Definition: interrupt.h:25
intr_handler_func
void intr_handler_func(struct intr_frame *)
Definition: interrupt.h:58
stdint.h
intr_disable
enum intr_level intr_disable(void)
Disables interrupts and returns the previous interrupt status.
Definition: interrupt.c:104
make_intr_gate
static uint64_t make_intr_gate(void(*)(void), int dpl)
Interrupt Descriptor Table helpers.
Definition: interrupt.c:317
ASSERT
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
outb
static void outb(uint16_t port, uint8_t data)
Writes byte DATA to PORT.
Definition: io.h:66
intr_handlers
static intr_handler_func * intr_handlers[INTR_CNT]
Interrupt handler functions for each interrupt.
Definition: interrupt.c:31
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 j...
Definition: interrupt.c:222
unexpected_interrupt
static void unexpected_interrupt(const struct intr_frame *)
Handles an unexpected interrupt with interrupt frame F.
Definition: interrupt.c:394
PRIx16
#define PRIx16
Definition: inttypes.h:17
intr_frame::eax
uint32_t eax
Saved EAX.
Definition: interrupt.h:31
intr_frame::edi
uint32_t edi
Saved EDI.
Definition: interrupt.h:24
intr_names
static const char * intr_names[INTR_CNT]
Names for each interrupt, for debugging purposes.
Definition: interrupt.c:34
intr_frame::ds
uint16_t uint16_t uint16_t uint16_t ds
Saved ES segment register.
Definition: interrupt.h:32
intr_stubs
intr_stub_func * intr_stubs[256]
io.h
register_handler
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.
Definition: interrupt.c:165
INTR_OFF
Interrupts disabled.
Definition: interrupt.h:10
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.
Definition: interrupt.c:202
intr_dump_frame
void intr_dump_frame(const struct intr_frame *f)
Dumps interrupt frame F to the console, for debugging.
Definition: interrupt.c:411
vaddr.h
make_gate
static uint64_t make_gate(void(*function)(void), int dpl, int type)
Creates an gate that invokes FUNCTION.
Definition: interrupt.c:294
intr_frame::vec_no
uint16_t uint16_t uint16_t uint16_t uint32_t vec_no
Saved DS segment register.
Definition: interrupt.h:32
flags.h
intr_init
void intr_init(void)
Initializes the interrupt system.
Definition: interrupt.c:118
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.
Definition: interrupt.c:181
intr_frame
Interrupt stack frame.
Definition: interrupt.h:20
FLAG_IF
#define FLAG_IF
Interrupt Flag.
Definition: flags.h:6
thread.h
inttypes.h
thread_yield
void thread_yield(void)
Yields the CPU.
Definition: thread.c:302
intr_frame::error_code
uint32_t error_code
Error code.
Definition: interrupt.h:43
PIC0_DATA
#define PIC0_DATA
Master PIC data register address.
Definition: interrupt.c:17
intr_frame::edx
uint32_t edx
Saved EDX.
Definition: interrupt.h:29
intr_frame::ebp
uint32_t ebp
Saved EBP.
Definition: interrupt.h:26
debug.h
make_trap_gate
static uint64_t make_trap_gate(void(*)(void), int dpl)
Creates a trap gate that invokes FUNCTION with the given DPL.
Definition: interrupt.c:325
PRIx32
#define PRIx32
Definition: inttypes.h:24
INTR_ON
Interrupts enabled.
Definition: interrupt.h:11
intr_frame::ebx
uint32_t ebx
Saved EBX.
Definition: interrupt.h:28
make_idtr_operand
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 instru...
Definition: interrupt.c:333