浏览代码

[librm] Allow interrupts in protected mode

When running in a virtual machine, switching to real mode may be
expensive.  Allow interrupts to be enabled while in protected mode and
reflected down to the real-mode interrupt handlers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 年前
父节点
当前提交
23b671daf4

+ 38
- 113
src/arch/i386/core/gdbidt.S 查看文件

@@ -1,101 +1,10 @@
1 1
 /*
2
- * Interrupt Descriptor Table (IDT) setup and interrupt handlers for GDB stub.
2
+ * Interrupt handlers for GDB stub
3 3
  */
4 4
 
5
-#include <librm.h>
6
-
7 5
 #define SIZEOF_I386_REGS	32
8 6
 #define SIZEOF_I386_FLAGS	4
9 7
 
10
-/****************************************************************************
11
- * Interrupt Descriptor Table
12
- ****************************************************************************
13
- */
14
-	.section ".data16", "aw", @progbits
15
-	.globl idtr
16
-idtr:
17
-idt_limit:
18
-	.word	idt_length - 1
19
-idt_base:
20
-	.long	0
21
-
22
-/* IDT entries have the following format:
23
- * offset_lo, segment selector, flags, offset_hi
24
- *
25
- * Since it is not possible to specify relocations in arbitrary
26
- * expressions like (int_overflow & 0xffff), we initialise the
27
- * IDT with entries in an incorrect format.
28
- *
29
- * The entries are shuffled into the correct format in init_librm().
30
- */
31
-#define IDT_ENTRY_EMPTY(name) .word 0, 0, 0, 0
32
-#define IDT_ENTRY_PRESENT(name) \
33
-	.long	int_##name; \
34
-	.word	0x8e00, VIRTUAL_CS
35
-
36
-.align 16
37
-idt:
38
-	IDT_ENTRY_PRESENT(divide_error)
39
-	IDT_ENTRY_PRESENT(debug_trap)
40
-	IDT_ENTRY_EMPTY(non_maskable_interrupt)
41
-	IDT_ENTRY_PRESENT(breakpoint)
42
-	IDT_ENTRY_PRESENT(overflow)
43
-	IDT_ENTRY_PRESENT(bound_range_exceeded)
44
-	IDT_ENTRY_PRESENT(invalid_opcode)
45
-	IDT_ENTRY_EMPTY(device_not_available)
46
-	IDT_ENTRY_PRESENT(double_fault)
47
-	IDT_ENTRY_EMPTY(coprocessor_segment_overrun)
48
-	IDT_ENTRY_PRESENT(invalid_tss)
49
-	IDT_ENTRY_PRESENT(segment_not_present)
50
-	IDT_ENTRY_PRESENT(stack_segment_fault)
51
-	IDT_ENTRY_PRESENT(general_protection)
52
-	IDT_ENTRY_PRESENT(page_fault)
53
-idt_end:
54
-	.equ	idt_length, idt_end - idt
55
-
56
-/* The IDT entries are fixed up (once) in init_librm() */
57
-idt_fixed:
58
-	.byte	0
59
-
60
-/****************************************************************************
61
- * idt_init (real-mode near call, 16-bit real-mode near return address)
62
- *
63
- * Initialise the IDT, called from init_librm.
64
- *
65
- * Parameters:
66
- *   %eax : IDT base address
67
- *
68
- * Destroys %ax, %bx, and %di.
69
- ****************************************************************************
70
- */
71
-	.section ".text16", "ax", @progbits
72
-	.code16
73
-	.globl idt_init
74
-idt_init:
75
-	movl	%eax, idt_base
76
-	addl	$idt, idt_base
77
-
78
-	/* IDT entries are only fixed up once */
79
-	movb	idt_fixed, %al
80
-	orb	%al, %al
81
-	jnz	2f
82
-	movb	$1, idt_fixed
83
-
84
-	/* Shuffle IDT entries into the correct format */
85
-	movb	$(idt_length / 8), %al
86
-	movw	$idt, %bx
87
-	or	%al, %al
88
-	jz	2f
89
-1:
90
-	movw	2(%bx), %di
91
-	xchg	%di, 6(%bx)
92
-	movw	%di, 2(%bx)
93
-	addw	$8, %bx
94
-	dec	%al
95
-	jnz	1b
96
-2:
97
-	ret
98
-
99 8
 /****************************************************************************
100 9
  * Interrupt handlers
101 10
  ****************************************************************************
@@ -111,35 +20,35 @@ idt_init:
111 20
 #define SIGSEGV 11
112 21
 #define SIGSTKFLT 16
113 22
 
114
-int_divide_error:
23
+	.globl	gdbmach_nocode_sigfpe
24
+gdbmach_nocode_sigfpe:
115 25
 	pushl	$SIGFPE
116
-	jmp	do_interrupt
26
+	jmp	gdbmach_interrupt
117 27
 
118
-int_debug_trap:
119
-int_breakpoint:
28
+	.globl	gdbmach_nocode_sigtrap
29
+gdbmach_nocode_sigtrap:
120 30
 	pushl	$SIGTRAP
121
-	jmp	do_interrupt
31
+	jmp	gdbmach_interrupt
122 32
 
123
-int_overflow:
124
-int_bound_range_exceeded:
33
+	.globl	gdbmach_nocode_sigstkflt
34
+gdbmach_nocode_sigstkflt:
125 35
 	pushl	$SIGSTKFLT
126
-	jmp	do_interrupt
36
+	jmp	gdbmach_interrupt
127 37
 
128
-int_invalid_opcode:
38
+	.globl	gdbmach_nocode_sigill
39
+gdbmach_nocode_sigill:
129 40
 	pushl	$SIGILL
130
-	jmp	do_interrupt
41
+	jmp	gdbmach_interrupt
131 42
 
132
-int_double_fault:
43
+	.globl	gdbmach_withcode_sigbus
44
+gdbmach_withcode_sigbus:
133 45
 	movl	$SIGBUS, (%esp)
134
-	jmp	do_interrupt
46
+	jmp	gdbmach_interrupt
135 47
 
136
-int_invalid_tss:
137
-int_segment_not_present:
138
-int_stack_segment_fault:
139
-int_general_protection:
140
-int_page_fault:
48
+	.globl	gdbmach_withcode_sigsegv
49
+gdbmach_withcode_sigsegv:
141 50
 	movl	$SIGSEGV, (%esp)
142
-	jmp	do_interrupt
51
+	jmp	gdbmach_interrupt
143 52
 
144 53
 /* When invoked, the stack contains: eflags, cs, eip, signo. */
145 54
 #define IH_OFFSET_GDB_REGS ( 0 )
@@ -161,7 +70,7 @@ int_page_fault:
161 70
 #define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
162 71
 #define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
163 72
 #define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
164
-do_interrupt:
73
+gdbmach_interrupt:
165 74
 	/* Store CPU state in GDB register snapshot */
166 75
 	pushw	$0
167 76
 	pushw	%gs
@@ -187,25 +96,41 @@ do_interrupt:
187 96
 	pushl	%ecx
188 97
 	pushl	%eax
189 98
 
99
+	/* Switch to virtual addressing */
100
+	call	_intr_to_virt
101
+
190 102
 	/* Call GDB stub exception handler */
191 103
 	pushl	%esp
192 104
 	pushl	(IH_OFFSET_SIGNO + 4)(%esp)
193 105
 	call	gdbmach_handler
194 106
 	addl	$8, %esp
195 107
 
108
+	/* Copy register snapshot to new stack and switch to new stack */
109
+	movl	%esp, %esi
110
+	movl	(IH_OFFSET_GDB_SEG_REGS + 4)(%esp), %eax
111
+	movl	%eax, %es
112
+	movl	(IH_OFFSET_GDB_REGS + 16)(%esp), %edi
113
+	subl	$IH_OFFSET_END, %edi
114
+	movl	$(IH_OFFSET_END / 4), %ecx
115
+	pushl	%edi
116
+	ss rep movsl
117
+	popl	%edi
118
+	movl	%eax, %ss
119
+	movl	%edi, %esp
120
+
196 121
 	/* Restore CPU state from GDB register snapshot */
197 122
 	popl	%eax
198 123
 	popl	%ecx
199 124
 	popl	%edx
200 125
 	popl	%ebx
201
-	addl	$4, %esp /* Changing ESP currently not supported */
126
+	popl	%ebp /* Skip %esp: already loaded */
202 127
 	popl	%ebp
203 128
 	popl	%esi
204 129
 	popl	%edi
205 130
 	popl	IH_OFFSET_FLUX_OLD_EIP(%esp)
206 131
 	popl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
207 132
 	popl	IH_OFFSET_FLUX_OLD_CS(%esp)
208
-	popl	%ss
133
+	popl	%ds /* Skip %ss: already loaded */
209 134
 	popl	%ds
210 135
 	popl	%es
211 136
 	popl	%fs

+ 28
- 0
src/arch/i386/core/gdbmach.c 查看文件

@@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
24 24
 #include <assert.h>
25 25
 #include <ipxe/uaccess.h>
26 26
 #include <ipxe/gdbstub.h>
27
+#include <librm.h>
27 28
 #include <gdbmach.h>
28 29
 
29 30
 /** @file
@@ -150,3 +151,30 @@ __asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
150 151
 	gdbstub_handler ( signo, regs );
151 152
 	gdbmach_enable_hwbps();
152 153
 }
154
+
155
+static void * gdbmach_interrupt_vectors[] = {
156
+	gdbmach_nocode_sigfpe,		/* Divide by zero */
157
+	gdbmach_nocode_sigtrap,		/* Debug trap */
158
+	NULL,				/* Non-maskable interrupt */
159
+	gdbmach_nocode_sigtrap,		/* Breakpoint */
160
+	gdbmach_nocode_sigstkflt,	/* Overflow */
161
+	gdbmach_nocode_sigstkflt,	/* Bound range exceeded */
162
+	gdbmach_nocode_sigill,		/* Invalid opcode */
163
+	NULL,				/* Device not available */
164
+	gdbmach_withcode_sigbus,	/* Double fault */
165
+	NULL,				/* Coprocessor segment overrun */
166
+	gdbmach_withcode_sigsegv,	/* Invalid TSS */
167
+	gdbmach_withcode_sigsegv,	/* Segment not present */
168
+	gdbmach_withcode_sigsegv,	/* Stack segment fault */
169
+	gdbmach_withcode_sigsegv,	/* General protection fault */
170
+	gdbmach_withcode_sigsegv,	/* Page fault */
171
+};
172
+
173
+void gdbmach_init ( void ) {
174
+	unsigned int i;
175
+
176
+	for ( i = 0 ; i < ( sizeof ( gdbmach_interrupt_vectors ) /
177
+			    sizeof ( gdbmach_interrupt_vectors[0] ) ) ; i++ ) {
178
+		set_interrupt_vector ( i, gdbmach_interrupt_vectors[i] );
179
+	}
180
+}

+ 52
- 10
src/arch/i386/core/virtaddr.S 查看文件

@@ -36,6 +36,7 @@ _virt_to_phys:
36 36
 	addl	%ebp, 12(%esp)
37 37
 
38 38
 	/* Switch to physical code segment */
39
+	cli
39 40
 	pushl	$PHYSICAL_CS
40 41
 	leal	1f(%ebp), %eax
41 42
 	pushl	%eax
@@ -44,10 +45,10 @@ _virt_to_phys:
44 45
 	/* Reload other segment registers and adjust %esp */
45 46
 	movl	$PHYSICAL_DS, %eax
46 47
 	movl	%eax, %ds
47
-	movl	%eax, %es	
48
-	movl	%eax, %fs	
48
+	movl	%eax, %es
49
+	movl	%eax, %fs
49 50
 	movl	%eax, %gs
50
-	movl	%eax, %ss	
51
+	movl	%eax, %ss
51 52
 	addl	%ebp, %esp
52 53
 
53 54
 	/* Restore registers and flags, and return */
@@ -64,9 +65,6 @@ _virt_to_phys:
64 65
  * selectors.  All other registers are preserved.  Flags are
65 66
  * preserved.
66 67
  *
67
- * Note that this depends on the GDT already being correctly set up
68
- * (e.g. by a call to run_here()).
69
- *
70 68
  * Parameters: none
71 69
  * Returns: none
72 70
  ****************************************************************************
@@ -79,18 +77,19 @@ _phys_to_virt:
79 77
 	pushl	%ebp
80 78
 
81 79
 	/* Switch to virtual code segment */
80
+	cli
82 81
 	ljmp	$VIRTUAL_CS, $1f
83
-1:	
82
+1:
84 83
 	/* Reload data segment registers */
85 84
 	movl	$VIRTUAL_DS, %eax
86 85
 	movl	%eax, %ds
87
-	movl	%eax, %es	
88
-	movl	%eax, %fs	
86
+	movl	%eax, %es
87
+	movl	%eax, %fs
89 88
 	movl	%eax, %gs
90 89
 
91 90
 	/* Reload stack segment and adjust %esp */
92 91
 	movl	virt_offset, %ebp
93
-	movl	%eax, %ss	
92
+	movl	%eax, %ss
94 93
 	subl	%ebp, %esp
95 94
 
96 95
 	/* Change the return address to a virtual address */
@@ -101,3 +100,46 @@ _phys_to_virt:
101 100
 	popl	%eax
102 101
 	popfl
103 102
 	ret
103
+
104
+/****************************************************************************
105
+ * _intr_to_virt (virtual code segment, virtual or physical stack segment)
106
+ *
107
+ * Switch from virtual code segment with either a virtual or physical
108
+ * stack segment to using virtual addressing.  %esp is adjusted if
109
+ * necessary to a virtual value.  Segment registers are set to virtual
110
+ * selectors.  All other registers are preserved.  Flags are
111
+ * preserved.
112
+ *
113
+ * Parameters: none
114
+ * Returns: none
115
+ ****************************************************************************
116
+ */
117
+	.globl _intr_to_virt
118
+_intr_to_virt:
119
+	/* Preserve registers and flags */
120
+	pushfl
121
+	pushl	%eax
122
+	pushl	%ebp
123
+
124
+	/* Check whether stack segment is physical or virtual */
125
+	movl	%ss, %eax
126
+	cmpw	$VIRTUAL_DS, %ax
127
+	movl	$VIRTUAL_DS, %eax
128
+
129
+	/* Reload data segment registers */
130
+	movl	%eax, %ds
131
+	movl	%eax, %es
132
+	movl	%eax, %fs
133
+	movl	%eax, %gs
134
+
135
+	/* Reload stack segment and adjust %esp if necessary */
136
+	je	1f
137
+	movl	virt_offset, %ebp
138
+	movl	%eax, %ss
139
+	subl	%ebp, %esp
140
+1:
141
+	/* Restore registers and flags, and return */
142
+	popl	%ebp
143
+	popl	%eax
144
+	popfl
145
+	ret

+ 10
- 0
src/arch/i386/include/gdbmach.h 查看文件

@@ -46,6 +46,14 @@ enum {
46 46
 	GDBMACH_AWATCH,
47 47
 };
48 48
 
49
+/* Interrupt vectors */
50
+extern void gdbmach_nocode_sigfpe ( void );
51
+extern void gdbmach_nocode_sigtrap ( void );
52
+extern void gdbmach_nocode_sigstkflt ( void );
53
+extern void gdbmach_nocode_sigill ( void );
54
+extern void gdbmach_withcode_sigbus ( void );
55
+extern void gdbmach_withcode_sigsegv ( void );
56
+
49 57
 static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
50 58
 	regs [ GDBMACH_EIP ] = pc;
51 59
 }
@@ -61,4 +69,6 @@ static inline void gdbmach_breakpoint ( void ) {
61 69
 
62 70
 extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
63 71
 
72
+extern void gdbmach_init ( void );
73
+
64 74
 #endif /* GDBMACH_H */

+ 65
- 0
src/arch/i386/include/librm.h 查看文件

@@ -209,6 +209,71 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size );
209 209
 	asm_code_str					\
210 210
 	"call _phys_to_virt\n\t"
211 211
 
212
+/** Number of interrupts */
213
+#define NUM_INT 256
214
+
215
+/** An interrupt descriptor table register */
216
+struct idtr {
217
+	/** Limit */
218
+	uint16_t limit;
219
+	/** Base */
220
+	uint32_t base;
221
+} __attribute__ (( packed ));
222
+
223
+/** An interrupt descriptor table entry */
224
+struct interrupt_descriptor {
225
+	/** Low 16 bits of address */
226
+	uint16_t low;
227
+	/** Code segment */
228
+	uint16_t segment;
229
+	/** Unused */
230
+	uint8_t unused;
231
+	/** Type and attributes */
232
+	uint8_t attr;
233
+	/** High 16 bits of address */
234
+	uint16_t high;
235
+} __attribute__ (( packed ));
236
+
237
+/** Interrupt descriptor is present */
238
+#define IDTE_PRESENT 0x80
239
+
240
+/** Interrupt descriptor 32-bit interrupt gate type */
241
+#define IDTE_TYPE_IRQ32 0x0e
242
+
243
+/** An interrupt vector
244
+ *
245
+ * Each interrupt vector comprises an eight-byte fragment of code:
246
+ *
247
+ *   60			pushal
248
+ *   b0 xx		movb $INT, %al
249
+ *   e9 xx xx xx xx	jmp interrupt_wrapper
250
+ */
251
+struct interrupt_vector {
252
+	/** "pushal" instruction */
253
+	uint8_t pushal;
254
+	/** "movb" instruction */
255
+	uint8_t movb;
256
+	/** Interrupt number */
257
+	uint8_t intr;
258
+	/** "jmp" instruction */
259
+	uint8_t jmp;
260
+	/** Interrupt wrapper address offset */
261
+	uint32_t offset;
262
+	/** Next instruction after jump */
263
+	uint8_t next[0];
264
+} __attribute__ (( packed ));
265
+
266
+/** "pushal" instruction */
267
+#define PUSHAL_INSN 0x60
268
+
269
+/** "movb" instruction */
270
+#define MOVB_INSN 0xb0
271
+
272
+/** "jmp" instruction */
273
+#define JMP_INSN 0xe9
274
+
275
+extern void set_interrupt_vector ( unsigned int intr, void *vector );
276
+
212 277
 #endif /* ASSEMBLY */
213 278
 
214 279
 #endif /* LIBRM_H */

+ 48
- 7
src/arch/i386/transitions/librm.S 查看文件

@@ -128,10 +128,15 @@ init_librm:
128 128
 	addr32 leal	(%eax, %edi), %ebx
129 129
 	movl	%ebx, rm_data16
130 130
 
131
-	/* Set GDT and IDT base */
131
+	/* Set GDT base */
132 132
 	movl	%eax, gdt_base
133 133
 	addl	$gdt, gdt_base
134
-	call	idt_init
134
+
135
+	/* Initialise IDT */
136
+	pushl	$init_idt
137
+	pushw	%cs
138
+	call	prot_call
139
+	popl	%eax /* discard */
135 140
 
136 141
 	/* Restore registers */
137 142
 	negl	%edi
@@ -141,14 +146,12 @@ init_librm:
141 146
 
142 147
 	.section ".text16", "ax", @progbits
143 148
 	.code16
144
-	.weak idt_init
145 149
 set_seg_base:
146 150
 1:	movw	%ax, 2(%bx)
147 151
 	rorl	$16, %eax
148 152
 	movb	%al, 4(%bx)
149 153
 	movb	%ah, 7(%bx)
150 154
 	roll	$16, %eax
151
-idt_init: /* Reuse the return opcode here */
152 155
 	ret
153 156
 
154 157
 /****************************************************************************
@@ -237,10 +240,8 @@ real_to_prot:
237 240
 	/* Return to virtual address */
238 241
 	ret
239 242
 
240
-	/* Default IDTR with no interrupts */
243
+	/* Default real-mode interrupt descriptor table */
241 244
 	.section ".data16", "aw", @progbits
242
-	.weak idtr
243
-idtr:
244 245
 rm_idtr:
245 246
 	.word 0xffff /* limit */
246 247
 	.long 0 /* base */
@@ -536,6 +537,46 @@ flatten_real_mode:
536 537
 flatten_dummy:
537 538
 	ret
538 539
 
540
+/****************************************************************************
541
+ * Interrupt wrapper
542
+ *
543
+ * Used by the protected-mode interrupt vectors to call the
544
+ * interrupt() function.
545
+ *
546
+ * May be entered with either physical or virtual stack segment.
547
+ ****************************************************************************
548
+ */
549
+	.globl interrupt_wrapper
550
+interrupt_wrapper:
551
+	/* Preserve segment registers and original %esp */
552
+	pushl	%ds
553
+	pushl	%es
554
+	pushl	%fs
555
+	pushl	%gs
556
+	pushl	%ss
557
+	pushl	%esp
558
+
559
+	/* Switch to virtual addressing */
560
+	call	_intr_to_virt
561
+
562
+	/* Expand IRQ number to whole %eax register */
563
+	movzbl	%al, %eax
564
+
565
+	/* Call interrupt handler */
566
+	call	interrupt
567
+
568
+	/* Restore original stack and segment registers */
569
+	lss	(%esp), %esp
570
+	popl	%ss
571
+	popl	%gs
572
+	popl	%fs
573
+	popl	%es
574
+	popl	%ds
575
+
576
+	/* Restore registers and return */
577
+	popal
578
+	iret
579
+
539 580
 /****************************************************************************
540 581
  * Stored real-mode and protected-mode stack pointers
541 582
  *

+ 78
- 5
src/arch/i386/transitions/librm_mgmt.c 查看文件

@@ -9,19 +9,35 @@ FILE_LICENCE ( GPL2_OR_LATER );
9 9
 
10 10
 #include <stdint.h>
11 11
 #include <realmode.h>
12
+#include <pic8259.h>
12 13
 
13 14
 /*
14 15
  * This file provides functions for managing librm.
15 16
  *
16 17
  */
17 18
 
19
+/** The interrupt wrapper */
20
+extern char interrupt_wrapper[];
21
+
22
+/** The interrupt vectors */
23
+static struct interrupt_vector intr_vec[ IRQ_MAX + 1 ];
24
+
25
+/** The interrupt descriptor table */
26
+struct interrupt_descriptor idt[NUM_INT] __attribute__ (( aligned ( 16 ) ));
27
+
28
+/** The interrupt descriptor table register */
29
+struct idtr __data16 ( idtr ) = {
30
+	.limit = ( sizeof ( idt ) - 1 ),
31
+};
32
+#define idtr __use_data16 ( idtr )
33
+
18 34
 /**
19 35
  * Allocate space on the real-mode stack and copy data there from a
20 36
  * user buffer
21 37
  *
22
- * @v data			User buffer
23
- * @v size			Size of stack data
24
- * @ret sp			New value of real-mode stack pointer
38
+ * @v data		User buffer
39
+ * @v size		Size of stack data
40
+ * @ret sp		New value of real-mode stack pointer
25 41
  */
26 42
 uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
27 43
 	userptr_t rm_stack;
@@ -35,8 +51,8 @@ uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
35 51
  * Deallocate space on the real-mode stack, optionally copying back
36 52
  * data to a user buffer.
37 53
  *
38
- * @v data			User buffer
39
- * @v size			Size of stack data
54
+ * @v data		User buffer
55
+ * @v size		Size of stack data
40 56
  */
41 57
 void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
42 58
 	if ( data ) {
@@ -46,6 +62,63 @@ void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
46 62
 	rm_sp += size;
47 63
 };
48 64
 
65
+/**
66
+ * Set interrupt vector
67
+ *
68
+ * @v intr		Interrupt number
69
+ * @v vector		Interrupt vector, or NULL to disable
70
+ */
71
+void set_interrupt_vector ( unsigned int intr, void *vector ) {
72
+	struct interrupt_descriptor *idte;
73
+
74
+	idte = &idt[intr];
75
+	idte->segment = VIRTUAL_CS;
76
+	idte->attr = ( vector ? ( IDTE_PRESENT | IDTE_TYPE_IRQ32 ) : 0 );
77
+	idte->low = ( ( ( uint32_t ) vector ) & 0xffff );
78
+	idte->high = ( ( ( uint32_t ) vector ) >> 16 );
79
+}
80
+
81
+/**
82
+ * Initialise interrupt descriptor table
83
+ *
84
+ */
85
+void init_idt ( void ) {
86
+	struct interrupt_vector *vec;
87
+	unsigned int irq;
88
+	unsigned int intr;
89
+
90
+	/* Initialise the interrupt descriptor table and interrupt vectors */
91
+	for ( irq = 0 ; irq <= IRQ_MAX ; irq++ ) {
92
+		intr = IRQ_INT ( irq );
93
+		vec = &intr_vec[irq];
94
+		vec->pushal = PUSHAL_INSN;
95
+		vec->movb = MOVB_INSN;
96
+		vec->intr = intr;
97
+		vec->jmp = JMP_INSN;
98
+		vec->offset = ( ( uint32_t ) interrupt_wrapper -
99
+				( uint32_t ) vec->next );
100
+		set_interrupt_vector ( intr, vec );
101
+	}
102
+
103
+	/* Initialise the interrupt descriptor table register */
104
+	idtr.base = virt_to_phys ( idt );
105
+}
106
+
107
+/**
108
+ * Interrupt handler
109
+ *
110
+ * @v irq		Interrupt number
111
+ */
112
+void __attribute__ (( cdecl, regparm ( 1 ) )) interrupt ( int irq ) {
113
+	uint32_t discard_eax;
114
+
115
+	/* Reissue interrupt in real mode */
116
+	__asm__ __volatile__ ( REAL_CODE ( "movb %%al, %%cs:(1f + 1)\n\t"
117
+					   "\n1:\n\t"
118
+					   "int $0x00\n\t" )
119
+			       : "=a" ( discard_eax ) : "0" ( irq ) );
120
+}
121
+
49 122
 PROVIDE_UACCESS_INLINE ( librm, phys_to_user );
50 123
 PROVIDE_UACCESS_INLINE ( librm, user_to_phys );
51 124
 PROVIDE_UACCESS_INLINE ( librm, virt_to_user );

+ 2
- 0
src/arch/x86_64/include/gdbmach.h 查看文件

@@ -48,4 +48,6 @@ static inline void gdbmach_breakpoint ( void ) {
48 48
 
49 49
 extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
50 50
 
51
+extern void gdbmach_init ( void );
52
+
51 53
 #endif /* GDBMACH_H */

+ 1
- 0
src/core/gdbstub.c 查看文件

@@ -396,5 +396,6 @@ struct gdb_transport *find_gdb_transport ( const char *name ) {
396 396
 void gdbstub_start ( struct gdb_transport *trans ) {
397 397
 	stub.trans = trans;
398 398
 	stub.payload = &stub.buf [ 1 ];
399
+	gdbmach_init();
399 400
 	gdbmach_breakpoint();
400 401
 }

正在加载...
取消
保存