summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/core/gdbidt.S
blob: 78945c62cf4059b9c3b178fa52d46579174a2609 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Interrupt handlers for GDB stub
 */

#define SIZEOF_I386_REGS	32
#define SIZEOF_I386_FLAGS	4

/****************************************************************************
 * Interrupt handlers
 ****************************************************************************
 */
	.section ".note.GNU-stack", "", @progbits
	.section ".text", "ax", @progbits
	.code32

/* POSIX signal numbers for reporting traps to GDB */
#define SIGILL 4
#define SIGTRAP 5
#define SIGFPE 8
#define SIGSTKFLT 16

	.globl	gdbmach_sigfpe
gdbmach_sigfpe:
	pushl	$SIGFPE
	jmp	gdbmach_interrupt

	.globl	gdbmach_sigtrap
gdbmach_sigtrap:
	pushl	$SIGTRAP
	jmp	gdbmach_interrupt

	.globl	gdbmach_sigstkflt
gdbmach_sigstkflt:
	pushl	$SIGSTKFLT
	jmp	gdbmach_interrupt

	.globl	gdbmach_sigill
gdbmach_sigill:
	pushl	$SIGILL
	jmp	gdbmach_interrupt

/* When invoked, the stack contains: eflags, cs, eip, signo. */
#define IH_OFFSET_GDB_REGS ( 0 )
#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )

/* We also access the stack whilst still storing or restoring
 * the register snapshot.  Since ESP is in flux, we need
 * special offsets.
 */
#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
gdbmach_interrupt:
	/* Store CPU state in GDB register snapshot */
	pushw	$0
	pushw	%gs
	pushw	$0
	pushw	%fs
	pushw	$0
	pushw	%es
	pushw	$0
	pushw	%ds
	pushw	$0
	pushw	%ss
	pushw	$0
	pushw	IH_OFFSET_FLUX_OLD_CS + 2(%esp)
	pushl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
	pushl	IH_OFFSET_FLUX_OLD_EIP(%esp)
	pushl	%edi
	pushl	%esi
	pushl	%ebp
	leal	IH_OFFSET_FLUX_END(%esp), %edi
	pushl	%edi /* old ESP */
	pushl	%ebx
	pushl	%edx
	pushl	%ecx
	pushl	%eax

	/* Switch to virtual addressing */
	call	_intr_to_virt

	/* Call GDB stub exception handler */
	pushl	%esp
	pushl	(IH_OFFSET_SIGNO + 4)(%esp)
	call	gdbmach_handler
	addl	$8, %esp

	/* Copy register snapshot to new stack and switch to new stack */
	movl	%esp, %esi
	movl	(IH_OFFSET_GDB_SEG_REGS + 4)(%esp), %eax
	movl	%eax, %es
	movl	(IH_OFFSET_GDB_REGS + 16)(%esp), %edi
	subl	$IH_OFFSET_END, %edi
	movl	$(IH_OFFSET_END / 4), %ecx
	pushl	%edi
	ss rep movsl
	popl	%edi
	movl	%eax, %ss
	movl	%edi, %esp

	/* Restore CPU state from GDB register snapshot */
	popl	%eax
	popl	%ecx
	popl	%edx
	popl	%ebx
	popl	%ebp /* Skip %esp: already loaded */
	popl	%ebp
	popl	%esi
	popl	%edi
	popl	IH_OFFSET_FLUX_OLD_EIP(%esp)
	popl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
	popl	IH_OFFSET_FLUX_OLD_CS(%esp)
	popl	%ds /* Skip %ss: already loaded */
	popl	%ds
	popl	%es
	popl	%fs
	popl	%gs

	addl	$4, %esp /* drop signo */
	iret