Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / common / src / hcall.s
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: hcall.s
5*
6* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
7*
8* - Do no alter or remove copyright notices
9*
10* - Redistribution and use of this software in source and binary forms, with
11* or without modification, are permitted provided that the following
12* conditions are met:
13*
14* - Redistribution of source code must retain the above copyright notice,
15* this list of conditions and the following disclaimer.
16*
17* - Redistribution in binary form must reproduce the above copyright notice,
18* this list of conditions and the following disclaimer in the
19* documentation and/or other materials provided with the distribution.
20*
21* Neither the name of Sun Microsystems, Inc. or the names of contributors
22* may be used to endorse or promote products derived from this software
23* without specific prior written permission.
24*
25* This software is provided "AS IS," without a warranty of any kind.
26* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
27* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
28* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
29* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
30* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
31* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
32* OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
33* FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
34* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
35* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
36* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*
38* You acknowledge that this software is not designed, licensed or
39* intended for use in the design, construction, operation or maintenance of
40* any nuclear facility.
41*
42* ========== Copyright Header End ============================================
43*/
44/*
45 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
46 * Use is subject to license terms.
47 */
48
49 .ident "@(#)hcall.s 1.99 07/05/03 SMI"
50
51#include <sys/asm_linkage.h>
52#include <sys/htypes.h>
53#include <asi.h>
54#include <guest.h>
55#include <offsets.h>
56#include <util.h>
57#include <debug.h>
58#include <hcall.h>
59
60/*
61 * hcall_core - Entry point for CORE_TRAP hcalls
62 *
63 * These calls are unversioned, and universal to all guests. They
64 * represent key functionality that a guest must have available
65 * even if API versions have not been negotiated.
66 *
67 * Calling conventions are identical to the FAST_TRAP conventions
68 * described for hcall, below.
69 */
70 ENTRY_NP(hcall_core)
71 cmp %o5, (.core_end - .core_table) / 4 ! in table?
72 bgeu,pn %xcc, herr_badtrap ! no, error
73 sllx %o5, 2, %g2 ! scaled index
74 LABEL_ADDRESS(.core_table, %g1) ! &core_table
75 jmp %g1 + %g2 ! ... and go!
76 nop
77
78.core_table:
79 ba,a,pt %xcc, hcall_api_set_version ! 0x00
80 ba,a,pt %xcc, hcall_cons_putchar ! 0x01
81 ba,a,pt %xcc, hcall_mach_exit ! 0x02
82 ba,a,pt %xcc, hcall_api_get_version ! 0x03
83.core_end:
84 SET_SIZE(hcall_core)
85
86
87/*
88 * hcall - Entry point for FAST_TRAP hcalls
89 *
90 * function# (%o5) - number of the specific API function to be invoked
91 * arg0-arg4 (%o0-%o4) arguments to the function
92 * --
93 * ret0 (%o0) status (EOK, or an error code)
94 * ret1-ret5 (%o1-%o5) return values
95 *
96 * This code has access to fresh g-registers for scratch. %o5 is
97 * also legal for scratch, but the calling conventions require all
98 * other o-registers to be preserved unless the specific call uses
99 * the register either as an input or output argument.
100 */
101 ENTRY_NP(hcall)
102 GUEST_STRUCT(%g2)
103 ldx [%g2 + GUEST_HCALL_TABLE], %g2
104
105 cmp %o5, MAX_FAST_TRAP_VALUE
106 bleu,pt %xcc, 0f
107 sllx %o5, API_ENTRY_SIZE_SHIFT, %g1
108
109 sub %o5, MAX_FAST_TRAP_VALUE, %g1
110 sllx %g1, API_ENTRY_SIZE_SHIFT, %g1
1110:
112 ldx [%g2 + %g1], %g2
113 jmp %g2
114 nop
115 SET_SIZE(hcall)
116
117/*
118 * api_set_version - select API version
119 *
120 * arg0 (%o0) api_group
121 * arg1 (%o1) major_version
122 * arg2 (%o2) minor_version
123 * --
124 * ret0 (%o0) status
125 * ret1 (%o1) actual_minor
126 */
127 ENTRY_NP(hcall_api_set_version)
128 GUEST_STRUCT(%g2)
129 add %g2, GUEST_API_GROUPS, %g2 ! %g2 = &guest->api_groups
130
131 /*
132 * API_GROUP_SUN4V is special. There are no API calls
133 * associated with this group. Instead, each major version
134 * in the api_group corresponds to a set of known CPU errata
135 * that the guest must work around. The meaning of minor
136 * numbers other than zero isn't defined; we're explicitly
137 * ignoring the passed in minor version.
138 *
139 * Note we store the major and minor numbers for
140 * API_GROUP_SUN4V for the api_get_version call, same as for
141 * any other API group. The index is the first entry in the
142 * guest's local info table.
143 */
144 cmp %o0, API_GROUP_SUN4V ! check for the special group
145 bne,pt %xcc, 0f ! not special, skip it
146 cmp %o1, SUN4V_VERSION_INITIAL ! check if supported
147 bne,pt %xcc, herr_notsupported ! unknown major
148 nop
149
150 ba,pt %xcc, .storeversion ! return success
151 mov 0, %o2 ! ... with minor number 0
152
1530:
154
155 /*
156 * Look up the table entry for the guest's requested
157 * api_group.
158 *
159 * We're calculating addresses in two tables:
160 * hcall_api_group_map (store in %g1), and the api_groups
161 * table in the guest structure (store in %g2).
162 */
163 setx hcall_api_group_map, %g3, %g1 ! %g1 = api mapping table
164 ROOT_STRUCT(%g3) ! address of config struct
165 ldx [%g3 + CONFIG_RELOC], %g3 ! ... for relocation offset
166 sub %g1, %g3, %g1 ! relocated table address
167
1680:
169 lduw [%g1+4], %g4 ! offset to next group entry
170 lduw [%g1], %g3 ! api group number
171 inc VERSION_SIZE, %g2 ! next api_groups entry
172 brz %g4, herr_inval ! EINVAL if end of table
173 cmp %g3, %o0 ! is this the one?
174 bne,a,pt %xcc, 0b ! ... no, keep looking
175 add %g1, %g4, %g1 ! next API group entry
176
177
178 /*
179 * Register usage at this point:
180 * %o0-%o2 - HCALL arguments
181 * %g1 - pointer to the api_group entry in the mapping
182 * table
183 * %g2 - pointer to the entry in guest->api_groups
184 *
185 * We have the information for the requested api_group. Our
186 * next step is to scan this api_group's entry to see if the
187 * requested major version is supported. If it is, check
188 * the maximum minor version we can handle, and if necessary
189 * adjust the guest's request.
190 *
191 * As a special case, if the requested major_version is 0,
192 * we disable the entire API group. There are checks here
193 * and in other places below. The checks aren't optional,
194 * because the VERSION_PTR for the API group isn't valid in
195 * this case. It's a bit hairy, so stay sharp out there.
196 */
197 brnz,pt %o1, .findmajor ! must search if major_version != 0
198 inc 8, %g1 ! advance to version info
199
200 ! major_version == 0 means disable the api_group
201 mov 0, %g1 ! ... to be stored in guest struct
202 ba,pt %xcc, .check_disable
203 mov 0, %o2 ! ... to be stored in guest struct
204 ! (and returned to guest)
205
206
2070:
208 brz,pn %g3, herr_notsupported ! not found, ENOTSUPPORTED
209 inc 3, %g4 ! version plus first two xwords
210 sllx %g4, 3, %g4 ! scale index
211 add %g1, %g4, %g1 ! skip over minor version data
212.findmajor:
213 lduw [%g1 + MAJOR_OFF], %g3 ! get major number from table
214 cmp %g3, %o1 ! is it a match?
215 bne,pt %xcc, 0b ! no, keep looking
216 lduw [%g1 + MINOR_OFF], %g4 ! get minor number from table
217
218
219 ! Found the requested major number; check the requested
220 ! minor number
221 cmp %g4, %o2 ! minor number supported?
222 movlu %xcc, %g4, %o2 ! no, downgrade the request
223 inc 8, %g1 ! advance to minor version list
224
225
226 /*
227 * Register usage at this point:
228 * %o0-%o2 - HCALL arguments
229 * %g1 - pointer to the list of minor version table
230 * addresses
231 * %g2 - pointer to the entry in guest->api_groups
232 *
233 * We've found the info for the major number being requested
234 * by the guest.
235 *
236 * Next big step, figure out if the guest's request is going
237 * to disable or enable any API functions.
238 *
239 * A picture to help explain the ubiquitous +1 found in all
240 * the index calculations below:
241 * +--------------------------------------------+
242 * 1.0 -> | ... 1.0 entries here ... |
243 * +--------------------------------------------+
244 * | ... post 1.0 entries here ... |
245 * +--------------------------------------------+
246 * 1.old-> | ... 1.old entries here are in use ... |
247 * +--------------------------------------------+
248 * 1.old+1-> | ... from here on must be enabled ... |
249 * +--------------------------------------------+
250 * | ... after 1.old, before 1.new ... |
251 * +--------------------------------------------+
252 * 1.new-> | ... 1.new entries here must be enabled ... |
253 * +--------------------------------------------+
254 * 1.new+1-> | ... stop enabling from here on ... |
255 * +--------------------------------------------+
256 *
257 * This picture applies to the case where the major number
258 * isn't changing, and the minor number is increasing.
259 *
260 * Similar pictures apply to the other cases; drawing them
261 * is left as an exercise for the reader.
262 */
263.check_disable:
264 lduw [%g2 + VERSION_MAJOR], %g3 ! old major number
265 cmp %g3, %o1 ! changing major numbers?
266 be,pt %xcc, .check_minor ! no, next check
267 lduw [%g2 + VERSION_MINOR], %g5 ! guest's old minor number
268
269 ! We're changing major numbers, disable everything in the
270 ! old group
271 brz,pt %g3, .check_enable ! nothing to disable if was 0.0
272 ldx [%g2 + VERSION_PTR], %g4 ! guest's old table entry
273 ldx [%g4], %g3 ! disable start addr
274 inc %g5 ! old_minor+1
275 sllx %g5, 3, %g5 ! ... scaled
276 ba,pt %xcc, .do_disable
277 ldx [%g4 + %g5], %g4 ! disable end addr
278
279.check_minor:
280 ! We're not changing the major number; if the major
281 ! number was zero, we're done.
282 brz %g3, .storeversion
283 ! Otherwise, check whether the guest is changing its minor
284 ! number (delay slot)
285 cmp %g5, %o2 ! changing?
286
287 be,pn %xcc, .storeversion ! no, we're done
288 inc %g5 ! old_minor+1
289 add %o2, 1, %g6 ! new_minor+1
290 sllx %g5, 3, %g5
291 bgu,pn %xcc, 0f ! old > new, downgrading
292 sllx %g6, 3, %g6
293
294 ! We're upgrading from a lower minor number to a higher one.
295 ldx [%g1 + %g5], %g3 ! enable from old_minor+1
296 ba,pt %xcc, .do_enable
297 ldx [%g1 + %g6], %g4 ! ... to new_minor+1
298
2990:
300 ! We're downgrading from a higher minor number to a lower
301 ldx [%g1 + %g6], %g3 ! disable from new_minor+1
302 ldx [%g1 + %g5], %g4 ! ... to old_minor+1
303
304
305 /*
306 * Register usage at this point:
307 * %o0-%o2 - HCALL arguments
308 * %g1 - pointer to the list of minor version table
309 * addresses
310 * %g2 - pointer to the entry in guest->api_groups
311 * %g3 - starting address of list of hcall functions to be
312 * disabled (unrelocated)
313 * %g4 - ending address of list of hcall functions to be
314 * disabled (unrelocated)
315 *
316 * Disable the entries indicated by the starting and ending
317 * addresses in %g3 and %g4.
318 */
319.do_disable:
320 dec HCALL_ENTRY_SIZE - HCALL_ENTRY_INDEX, %g4
321 sub %g3, %g4, %g3 ! adjust for loop check
322 LABEL_ADDRESS(herr_badtrap, %g5)
323 GUEST_STRUCT(%g7)
324 ldx [%g7 + GUEST_HCALL_TABLE], %g7 ! hcall table address
325 ROOT_STRUCT(%g6)
326 ldx [%g6 + CONFIG_RELOC], %g6
327 sub %g4, %g6, %g4 ! relocate end address
328
3290:
330 ldx [%g3 + %g4], %g6 ! function index
331 ! tbl, fn, tgt
332 UPDATE_HCALL_TARGET(%g7, %g6, %g5)
333 brlz,pt %g3, 0b
334 inc HCALL_ENTRY_SIZE, %g3
335
336
337 /*
338 * Register usage at this point:
339 * %o0-%o2 - HCALL arguments
340 * %g1 - pointer to the list of minor version table
341 * addresses
342 * %g2 - pointer to the entry in guest->api_groups
343 *
344 * We've finished disabling any calls that won't be
345 * available. If the new major version is 0, then we're done.
346 */
347 brz,pn %o1, .storeversion ! done if major_version==0
348 .empty
349.check_enable:
350 add %o2, 1, %g5
351 sllx %g5, 3, %g5 ! (minor_version+1)*8
352 ldx [%g1], %g3 ! enable start addr
353 ldx [%g1 + %g5], %g4 ! enable end addr
354
355
356 /*
357 * Register usage at this point:
358 * %o0-%o2 - HCALL arguments
359 * %g1 - pointer to the list of minor version table
360 * addresses
361 * %g2 - pointer to the entry in guest->api_groups
362 * %g3 - starting address of list of hcall functions to be
363 * enabled (unrelocated)
364 * %g4 - ending address of list of hcall functions to be
365 * enabled (unrelocated)
366 *
367 * Enable the entries indicated by the starting and ending
368 * addresses in %g3 and %g4.
369 */
370.do_enable:
371 dec HCALL_ENTRY_SIZE - HCALL_ENTRY_INDEX, %g4
372 GUEST_STRUCT(%g7)
373 ldx [%g7 + GUEST_HCALL_TABLE], %g7 ! hcall table address
374 ROOT_STRUCT(%g6)
375 ldx [%g6 + CONFIG_RELOC], %g6
376 sub %g3, %g6, %g3 ! relocate start address
377 sub %g4, %g6, %g4 ! relocate end address
378
3790:
380 ldx [%g3 + HCALL_ENTRY_INDEX], %g6 ! function index
381 ldx [%g3 + HCALL_ENTRY_LABEL], %g5 ! target address
382 ROOT_STRUCT(%o0)
383 ldx [%o0 + CONFIG_RELOC], %o0
384 sub %g5, %o0, %g5 ! relocated target
385 UPDATE_HCALL_TARGET(%g7, %g6, %g5)
386 cmp %g3, %g4
387 bne,pt %xcc, 0b
388 inc HCALL_ENTRY_SIZE, %g3
389
390.storeversion:
391 sllx %o1, MAJOR_SHIFT, %g3
392 or %o2, %g3, %g3
393 stx %g3, [%g2 + VERSION_NUM]
394 stx %g1, [%g2 + VERSION_PTR]
395 mov %o2, %o1
396 HCALL_RET(EOK)
397
398 SET_SIZE(hcall_api_set_version)
399
400
401/*
402 * api_get_version - select API version
403 *
404 * arg0 (%o0) api_group
405 * --
406 * ret0 (%o0) status
407 * reg1 (%o1) major_version
408 * reg2 (%o2) minor_version
409 */
410 ENTRY_NP(hcall_api_get_version)
411 GUEST_STRUCT(%g2)
412 add %g2, GUEST_API_GROUPS, %g2 ! %g2 = guest's local table
413
414 /*
415 * Check for API_GROUP_SUN4V. This API group number isn't
416 * in the mapping table; the version info for this API group
417 * is the first entry in the guest's local info table.
418 */
419 cmp %o0, API_GROUP_SUN4V ! check for the special group
420 be,pn %xcc, .getversion ! special, we have the address
421 nop
422
423 /*
424 * Look up the table entry for the guest's requested
425 * api_group.
426 *
427 * There are two tables: the global table that maps API
428 * groups onto available API functions, and the guest's
429 * local table that indicates what version the guest has
430 * selected for each API group.
431 */
432 setx hcall_api_group_map, %g3, %g1 ! %g1 = api mapping table
433 ROOT_STRUCT(%g3) ! address of config struct
434 ldx [%g3 + CONFIG_RELOC], %g3 ! ... for relocation offset
435 sub %g1, %g3, %g1 ! relocated table address
436
4370:
438 lduw [%g1+4], %g4 ! offset to next group entry
439 lduw [%g1], %g3 ! api group number
440 inc VERSION_SIZE, %g2 ! next api_groups entry
441 brz %g4, herr_inval ! EINVAL if end of table
442 cmp %g3, %o0 ! is this the one?
443 bne,a,pt %xcc, 0b ! ... no, keep looking
444 add %g1, %g4, %g1 ! next API group entry
445
446
447.getversion:
448 ldx [%g2 + VERSION_NUM], %g3
449 srlx %g3, MAJOR_SHIFT, %o1
450 sllx %g3, 64-MAJOR_SHIFT, %g3
451 srlx %g3, 64-MAJOR_SHIFT, %o2
452 HCALL_RET(EOK)
453
454 SET_SIZE(hcall_api_get_version)
455
456
457/*
458 * Common error escapes so errors can be implemented by
459 * cmp, branch.
460 */
461 ENTRY(hret_ok)
462 HCALL_RET(EOK)
463 SET_SIZE(hret_ok)
464
465 ENTRY(herr_nocpu)
466 HCALL_RET(ENOCPU)
467 SET_SIZE(herr_nocpu)
468
469 ENTRY(herr_noraddr)
470 HCALL_RET(ENORADDR)
471 SET_SIZE(herr_noraddr)
472
473 ENTRY(herr_nointr)
474 HCALL_RET(ENOINTR)
475 SET_SIZE(herr_nointr)
476
477 ENTRY(herr_badpgsz)
478 HCALL_RET(EBADPGSZ)
479 SET_SIZE(herr_badpgsz)
480
481 ENTRY(herr_badtsb)
482 HCALL_RET(EBADTSB)
483 SET_SIZE(herr_badtsb)
484
485 ENTRY(herr_inval)
486 HCALL_RET(EINVAL)
487 SET_SIZE(herr_inval)
488
489 ENTRY(herr_badtrap)
490 HCALL_RET(EBADTRAP)
491 SET_SIZE(herr_badtrap)
492
493 ENTRY(herr_badalign)
494 HCALL_RET(EBADALIGN)
495 SET_SIZE(herr_badalign)
496
497 ENTRY(herr_wouldblock)
498 HCALL_RET(EWOULDBLOCK)
499 SET_SIZE(herr_wouldblock)
500
501 ENTRY(herr_noaccess)
502 HCALL_RET(ENOACCESS)
503 SET_SIZE(herr_noaccess)
504
505 ENTRY(herr_ioerror)
506 HCALL_RET(EIO)
507 SET_SIZE(herr_ioerror)
508
509 ENTRY(herr_cpuerror)
510 HCALL_RET(ECPUERROR)
511 SET_SIZE(herr_cpuerror)
512
513 ENTRY(herr_toomany)
514 HCALL_RET(ETOOMANY)
515 SET_SIZE(herr_toomany)
516
517 ENTRY(herr_nomap)
518 HCALL_RET(ENOMAP)
519 SET_SIZE(herr_nomap)
520
521 ENTRY(herr_notsupported)
522 HCALL_RET(ENOTSUPPORTED)
523 SET_SIZE(herr_notsupported)
524
525 ENTRY(herr_invalchan)
526 HCALL_RET(ECHANNEL)
527 SET_SIZE(herr_invalchan)
528
529#ifdef CONFIG_VERSION_TEST
530 /*
531 * Test API calls to go with test API group 0x400 above.
532 */
533
534/****
535 \ Cut and paste this at ok prompt if you want to test
536
537 hex
538 2 3 0 7f hypercall: api-set-version
539 3 1 3 7f hypercall: api-get-version
540 1 0 4 7f hypercall: bad-core4
541 1 0 -1 7f hypercall: bad-core-1
542 2 0 e0 0 hypercall: version-e0
543 2 0 e1 0 hypercall: version-e1
544 2 0 e2 0 hypercall: version-e2
545 2 0 e3 0 hypercall: version-e3
546
547 : test-api ( mjr mnr -- )
548 swap 400 api-set-version ." set-version: " . . cr
549 400 api-get-version ." get-version: " . . . cr
550 version-e0 ." e0: " . . cr
551 version-e1 ." e1: " . . cr
552 version-e2 ." e2: " . . cr
553 version-e3 ." e3: " . . cr
554 ;
555****/
556
557 ENTRY(hcall_version_test_1_0)
558 mov 0x10, %o1
559 HCALL_RET(EOK)
560 SET_SIZE(hcall_version_test_1_0)
561
562 ENTRY(hcall_version_test_1_1)
563 mov 0x11, %o1
564 HCALL_RET(EOK)
565 SET_SIZE(hcall_version_test_1_1)
566
567 ENTRY(hcall_version_test_1_2)
568 mov 0x12, %o1
569 HCALL_RET(EOK)
570 SET_SIZE(hcall_version_test_1_2)
571
572 ENTRY(hcall_version_test_2_0)
573 mov 0x20, %o1
574 HCALL_RET(EOK)
575 SET_SIZE(hcall_version_test_2_0)
576
577 ENTRY(hcall_version_test_2_1)
578 mov 0x21, %o1
579 HCALL_RET(EOK)
580 SET_SIZE(hcall_version_test_2_1)
581
582 ENTRY(hcall_version_test_2_2)
583 mov 0x22, %o1
584 HCALL_RET(EOK)
585 SET_SIZE(hcall_version_test_2_2)
586
587 ENTRY(hcall_version_test_3_0)
588 mov 0x30, %o1
589 HCALL_RET(EOK)
590 SET_SIZE(hcall_version_test_3_0)
591#endif