Statistics
| Branch: | Revision:

root / pc-bios / optionrom / kvmvapic.S @ 2a2af967

History | View | Annotate | Download (5.2 kB)

1
#
2
# Local APIC acceleration for Windows XP and related guests
3
#
4
# Copyright 2011 Red Hat, Inc. and/or its affiliates
5
#
6
# Author: Avi Kivity <avi@redhat.com>
7
#
8
# This work is licensed under the terms of the GNU GPL, version 2, or (at your
9
# option) any later version.  See the COPYING file in the top-level directory.
10
#
11

    
12
	.text 0
13
	.code16
14
.global _start
15
_start:
16
	.short 0xaa55
17
	.byte (_end - _start) / 512
18
	# clear vapic area: firmware load using rep insb may cause
19
	# stale tpr/isr/irr data to corrupt the vapic area.
20
	push %es
21
	push %cs
22
	pop %es
23
	xor %ax, %ax
24
	mov $vapic_size/2, %cx
25
	lea vapic, %di
26
	cld
27
	rep stosw
28
	pop %es
29
	mov $vapic_base, %ax
30
	out %ax, $0x7e
31
	lret
32

    
33
	.code32
34
vapic_size = 2*4096
35

    
36
.macro fixup delta=-4
37
777:
38
	.text 1
39
	.long 777b + \delta  - vapic_base
40
	.text 0
41
.endm
42

    
43
.macro reenable_vtpr
44
	out %al, $0x7e
45
.endm
46

    
47
.text 1
48
	fixup_start = .
49
.text 0
50

    
51
.align 16
52

    
53
vapic_base:
54
	.ascii "kvm aPiC"
55

    
56
	/* relocation data */
57
	.long vapic_base	; fixup
58
	.long fixup_start	; fixup
59
	.long fixup_end		; fixup
60

    
61
	.long vapic		; fixup
62
	.long vapic_size
63
vcpu_shift:
64
	.long 0
65
real_tpr:
66
	.long 0
67
	.long up_set_tpr	; fixup
68
	.long up_set_tpr_eax	; fixup
69
	.long up_get_tpr_eax	; fixup
70
	.long up_get_tpr_ecx	; fixup
71
	.long up_get_tpr_edx	; fixup
72
	.long up_get_tpr_ebx	; fixup
73
	.long 0 /* esp. won't work. */
74
	.long up_get_tpr_ebp	; fixup
75
	.long up_get_tpr_esi	; fixup
76
	.long up_get_tpr_edi	; fixup
77
	.long up_get_tpr_stack  ; fixup
78
	.long mp_set_tpr	; fixup
79
	.long mp_set_tpr_eax	; fixup
80
	.long mp_get_tpr_eax	; fixup
81
	.long mp_get_tpr_ecx	; fixup
82
	.long mp_get_tpr_edx	; fixup
83
	.long mp_get_tpr_ebx	; fixup
84
	.long 0 /* esp. won't work. */
85
	.long mp_get_tpr_ebp	; fixup
86
	.long mp_get_tpr_esi	; fixup
87
	.long mp_get_tpr_edi	; fixup
88
	.long mp_get_tpr_stack  ; fixup
89

    
90
.macro kvm_hypercall
91
	.byte 0x0f, 0x01, 0xc1
92
.endm
93

    
94
kvm_hypercall_vapic_poll_irq = 1
95

    
96
pcr_cpu = 0x51
97

    
98
.align 64
99

    
100
mp_get_tpr_eax:
101
	pushf
102
	cli
103
	reenable_vtpr
104
	push %ecx
105

    
106
	fs/movzbl pcr_cpu, %eax
107

    
108
	mov vcpu_shift, %ecx	; fixup
109
	shl %cl, %eax
110
	testb $1, vapic+4(%eax)	; fixup delta=-5
111
	jz mp_get_tpr_bad
112
	movzbl vapic(%eax), %eax ; fixup
113

    
114
mp_get_tpr_out:
115
	pop %ecx
116
	popf
117
	ret
118

    
119
mp_get_tpr_bad:
120
	mov real_tpr, %eax	; fixup
121
	mov (%eax), %eax
122
	jmp mp_get_tpr_out
123

    
124
mp_get_tpr_ebx:
125
	mov %eax, %ebx
126
	call mp_get_tpr_eax
127
	xchg %eax, %ebx
128
	ret
129

    
130
mp_get_tpr_ecx:
131
	mov %eax, %ecx
132
	call mp_get_tpr_eax
133
	xchg %eax, %ecx
134
	ret
135

    
136
mp_get_tpr_edx:
137
	mov %eax, %edx
138
	call mp_get_tpr_eax
139
	xchg %eax, %edx
140
	ret
141

    
142
mp_get_tpr_esi:
143
	mov %eax, %esi
144
	call mp_get_tpr_eax
145
	xchg %eax, %esi
146
	ret
147

    
148
mp_get_tpr_edi:
149
	mov %eax, %edi
150
	call mp_get_tpr_edi
151
	xchg %eax, %edi
152
	ret
153

    
154
mp_get_tpr_ebp:
155
	mov %eax, %ebp
156
	call mp_get_tpr_eax
157
	xchg %eax, %ebp
158
	ret
159

    
160
mp_get_tpr_stack:
161
	call mp_get_tpr_eax
162
	xchg %eax, 4(%esp)
163
	ret
164

    
165
mp_set_tpr_eax:
166
	push %eax
167
	call mp_set_tpr
168
	ret
169

    
170
mp_set_tpr:
171
	pushf
172
	push %eax
173
	push %ecx
174
	push %edx
175
	push %ebx
176
	cli
177
	reenable_vtpr
178

    
179
mp_set_tpr_failed:
180
	fs/movzbl pcr_cpu, %edx
181

    
182
	mov vcpu_shift, %ecx	; fixup
183
	shl %cl, %edx
184

    
185
	testb $1, vapic+4(%edx)	; fixup delta=-5
186
	jz mp_set_tpr_bad
187

    
188
	mov vapic(%edx), %eax	; fixup
189

    
190
	mov %eax, %ebx
191
	mov 24(%esp), %bl
192

    
193
	/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
194

    
195
	lock cmpxchg %ebx, vapic(%edx) ; fixup
196
	jnz mp_set_tpr_failed
197

    
198
	/* compute ppr */
199
	cmp %bh, %bl
200
	jae mp_tpr_is_bigger
201
mp_isr_is_bigger:
202
	mov %bh, %bl
203
mp_tpr_is_bigger:
204
	/* %bl = ppr */
205
	mov %bl, %ch   /* ch = ppr */
206
	rol $8, %ebx
207
	/* now: %bl = irr, %bh = ppr */
208
	cmp %bh, %bl
209
	ja mp_set_tpr_poll_irq
210

    
211
mp_set_tpr_out:
212
	pop %ebx
213
	pop %edx
214
	pop %ecx
215
	pop %eax
216
	popf
217
	ret $4
218

    
219
mp_set_tpr_poll_irq:
220
	mov $kvm_hypercall_vapic_poll_irq, %eax
221
	kvm_hypercall
222
	jmp mp_set_tpr_out
223

    
224
mp_set_tpr_bad:
225
	mov 24(%esp), %ecx
226
	mov real_tpr, %eax	; fixup
227
	mov %ecx, (%eax)
228
	jmp mp_set_tpr_out
229

    
230
up_get_tpr_eax:
231
	reenable_vtpr
232
	movzbl vapic, %eax ; fixup
233
	ret
234

    
235
up_get_tpr_ebx:
236
	reenable_vtpr
237
	movzbl vapic, %ebx ; fixup
238
	ret
239

    
240
up_get_tpr_ecx:
241
	reenable_vtpr
242
	movzbl vapic, %ecx ; fixup
243
	ret
244

    
245
up_get_tpr_edx:
246
	reenable_vtpr
247
	movzbl vapic, %edx ; fixup
248
	ret
249

    
250
up_get_tpr_esi:
251
	reenable_vtpr
252
	movzbl vapic, %esi ; fixup
253
	ret
254

    
255
up_get_tpr_edi:
256
	reenable_vtpr
257
	movzbl vapic, %edi ; fixup
258
	ret
259

    
260
up_get_tpr_ebp:
261
	reenable_vtpr
262
	movzbl vapic, %ebp ; fixup
263
	ret
264

    
265
up_get_tpr_stack:
266
	reenable_vtpr
267
	movzbl vapic, %eax ; fixup
268
	xchg %eax, 4(%esp)
269
	ret
270

    
271
up_set_tpr_eax:
272
	push %eax
273
	call up_set_tpr
274
	ret
275

    
276
up_set_tpr:
277
	pushf
278
	push %eax
279
	push %ecx
280
	push %ebx
281
	reenable_vtpr
282

    
283
up_set_tpr_failed:
284
	mov vapic, %eax	; fixup
285

    
286
	mov %eax, %ebx
287
	mov 20(%esp), %bl
288

    
289
	/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
290

    
291
	lock cmpxchg %ebx, vapic ; fixup
292
	jnz up_set_tpr_failed
293

    
294
	/* compute ppr */
295
	cmp %bh, %bl
296
	jae up_tpr_is_bigger
297
up_isr_is_bigger:
298
	mov %bh, %bl
299
up_tpr_is_bigger:
300
	/* %bl = ppr */
301
	mov %bl, %ch   /* ch = ppr */
302
	rol $8, %ebx
303
	/* now: %bl = irr, %bh = ppr */
304
	cmp %bh, %bl
305
	ja up_set_tpr_poll_irq
306

    
307
up_set_tpr_out:
308
	pop %ebx
309
	pop %ecx
310
	pop %eax
311
	popf
312
	ret $4
313

    
314
up_set_tpr_poll_irq:
315
	mov $kvm_hypercall_vapic_poll_irq, %eax
316
	kvm_hypercall
317
	jmp up_set_tpr_out
318

    
319
.text 1
320
	fixup_end = .
321
.text 0
322

    
323
/*
324
 * vapic format:
325
 *  per-vcpu records of size 2^vcpu shift.
326
 *     byte 0: tpr (r/w)
327
 *     byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
328
 *     byte 2: zero (r/o)
329
 *     byte 3: highest pending interrupt (irr) (r/o)
330
 */
331
.text 2
332

    
333
.align 128
334

    
335
vapic:
336
. = . + vapic_size
337

    
338
.byte 0  # reserve space for signature
339
.align 512, 0
340

    
341
_end: