Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / hypervisor / src / greatlakes / common / src / vdev_console.s
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* Hypervisor Software File: vdev_console.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 "@(#)vdev_console.s 1.12 07/02/14 SMI"
50
51 .file "vdev_console.s"
52
53/*
54 * Virtual console device implementation
55 */
56
57#include <sys/asm_linkage.h>
58#include <sys/htypes.h>
59#include <hprivregs.h>
60#include <asi.h>
61#include <fpga.h>
62#include <sun4v/traps.h>
63#include <sun4v/mmu.h>
64#include <sun4v/asi.h>
65#include <sparcv9/asi.h>
66#include <sun4v/queue.h>
67#include <devices/pc16550.h>
68
69#include <guest.h>
70#include <offsets.h>
71#include <util.h>
72#include <svc.h>
73#include <vdev_intr.h>
74#include <abort.h>
75#include <vdev_console.h>
76#include <debug.h>
77#include <vcpu.h>
78#include <mmu.h>
79#include <ldc.h>
80
81/*
82 * Virtual console guest interfaces (hcalls)
83 */
84
85/*
86 * Service Channel implementation
87 */
88
89
90/*
91 * cons_putchar
92 *
93 * arg0 char (%o0)
94 * --
95 * ret0 status (%o0)
96 */
97 ENTRY_NP(hcall_cons_putchar)
98#if 0 /* XXX check for invalid char -or- magic values (BREAK) */
99 cmp %o0, MAX_CHAR
100 bgu,pn %xcc, herr_inval
101#endif
102
103 VCPU_GUEST_STRUCT(%g4, %g3)
104 ! %g3 = guestp
105 ! %g4 = cpup
106
107 ! if not initialized, then just swallow the characters.
108 ! OK What type of console do we have.
109 ldub [%g3 + GUEST_CONSOLE + CONS_TYPE], %g5
110 cmp %g5, CONS_TYPE_UNCONFIG
111 beq,pn %xcc, hret_ok
112 nop
113 cmp %g5, CONS_TYPE_LDC
114 beq,pt %xcc, .use_ldc_put
115 nop
116#ifdef CONFIG_CN_UART /* { */
117 cmp %g5, CONS_TYPE_UART
118 beq,pt %xcc, .use_uart_put
119 nop
120#endif /* } */
121 ba,pt %xcc, herr_inval ! Return inval if console not configd
122 nop
123
124 /*
125 * Console put char using a LDC channel as output
126 */
127.use_ldc_put:
128
129 setx GUEST_CONSOLE, %g2, %g6
130 add %g6, %g3, %g6
131
132 ldub [%g6 + CONS_STATUS], %g2 ! chk if ready
133 andcc %g2, LDC_CONS_READY, %g2
134 bz,pn %xcc, herr_wouldblock
135 nop
136
137 ldx [%g6 + CONS_ENDPT], %g1
138
139 ! %g1 = channel
140 ! %g3 = guest struct
141
142 mulx %g1, LDC_ENDPOINT_SIZE, %g1
143 set GUEST_LDC_ENDPOINT, %g2
144 add %g1, %g2, %g1
145 add %g1, %g3, %g2
146
147 ! %g2 = our endpoint
148 ! %g3 = guest struct
149
150 ! Since the SRAM LDC is a bottleneck (for performance)
151 ! we have to try and buffer up more than one char per LDC
152 ! packet.
153 ldub [ %g2 + LDC_TARGET_TYPE ], %g5
154 cmp %g5, LDC_SP_ENDPOINT
155 bne %xcc, 1f
156 nop
157
158 ! SRAM LDC
159 !
160 ! Since any code which pulls data out of our TX queue and into
161 ! the SRAM will have to obtain the SP_LDC_TX_LOCK, we can go
162 ! ahead and grab that lock now and try to "pack" the console
163 ! LDC packets a little better so that we are not simply sending
164 ! one character per packet in all cases.
165
166 ROOT_STRUCT(%g1)
167 ldx [%g1 + CONFIG_SP_LDCS], %g1
168 ldx [%g2 + LDC_TARGET_CHANNEL], %g4
169 mulx %g4, SP_LDC_ENDPOINT_SIZE, %g4
170 add %g1, %g4, %g1 ! target endpoint
171
172 add %g1, SP_LDC_TX_LOCK, %g4
173 SPINLOCK_ENTER(%g4, %g5, %g6)
174
175 lduw [ %g2 + LDC_TX_QHEAD ], %g6
176 lduw [ %g2 + LDC_TX_QTAIL ], %g4
177
178 cmp %g4, %g6 ! Is the TX queue empty?
179 be %xcc, .putchar_release_sp_lk ! If so, nothing to compact
180 nop ! so proceed as normal.
181
182 ldx [ %g2 + LDC_TX_QSIZE ], %g6 ! "tail" points to next
183 dec Q_EL_SIZE, %g6 ! available packet, so we
184 dec Q_EL_SIZE, %g4 ! actually want the previous
185 and %g4, %g6, %g4 ! packet.
186
187 ldx [ %g2 + LDC_TX_QBASE_PA ], %g6
188 add %g4, %g6, %g4 ! Find the last packet
189
190 ldub [%g4 + LDC_CONS_SIZE], %g5 ! read current size (#chars)
191
192 cmp %g5, LDC_CONS_PAYLOAD_SZ ! is packet already full?
193 bgeu,a %xcc, .putchar_release_sp_lk ! if so, just start the next
194 nop ! packet as usual (unpacked)
195
196 add %g4, %g5, %g6 ! offset of this char.
197 stb %o0, [%g6 + LDC_CONS_PAYLOAD] ! store char in payload.
198
199 inc %g5 ! # chars in payload now.
200 stb %g5, [%g4 + LDC_CONS_SIZE] ! store new payload size.
201
202 add %g1, SP_LDC_TX_LOCK, %g4
203 SPINLOCK_EXIT(%g4)
204
205 ! Queue was not empty, so no need to send notification.
206 HCALL_RET(EOK)
207
208.putchar_release_sp_lk:
209
210 add %g1, SP_LDC_TX_LOCK, %g4
211 SPINLOCK_EXIT(%g4)
212
213 ba,a .send_pkt
214
2151:
216 ! target is a guest endpoint
217 ! if it has no receive queue configured drop the
218 ! console char and return back
219 ldx [ %g2 + LDC_TARGET_GUEST ], %g6
220 ldx [ %g2 + LDC_TARGET_CHANNEL ], %g4
221 mulx %g4, LDC_ENDPOINT_SIZE, %g4
222 set GUEST_LDC_ENDPOINT, %g5
223 add %g6, %g5, %g6
224 add %g6, %g4, %g6 ! g6 is the target endpoint
225 ldx [ %g6 + LDC_RX_QSIZE ], %g4 ! check if queue is configured
226 brnz,a,pn %g4, .send_pkt
227 nop
228 HCALL_RET(EOK)
229
230.send_pkt:
231 ! %g2 = our endpoint
232 ! %g3 = guest struct
233
234 lduw [ %g2 + LDC_TX_QHEAD ], %g6
235 lduw [ %g2 + LDC_TX_QTAIL ], %g4
236
237 ldx [ %g2 + LDC_TX_QSIZE ], %g5
238 dec Q_EL_SIZE, %g5
239 add %g4, Q_EL_SIZE, %g1
240 and %g1, %g5, %g1
241
242 cmp %g1, %g6 ! Does TX queue have room?
243 bne,pt %xcc, 2f ! If so, continue.
244 nop
245
246 ! TX queue is full. Have we already marked it as such?
247 ldub [ %g2 + LDC_TXQ_FULL ], %g5
248 set 1, %g6
249 brz,a %g5, 1b ! If not, mark it and try one
250 stb %g6, [ %g2 + LDC_TXQ_FULL ] ! last time to avoid lost intr.
251
252 ba herr_wouldblock
253 nop
2542:
255 ! %g1 = new tail value
256 ! %g2 = our endpoint
257 ! %g3 = guest struct
258 ! %g4 = old tail
259
260 ldx [ %g2 + LDC_TX_QBASE_PA ], %g3
261 add %g4, %g3, %g4
262
263 ! %g1 = new tail value
264 ! %g2 = sender's endpoint
265 ! %g4 = pointer to outgoing queue entry
266
267 stx %g0, [%g4]
268 stx %g0, [%g4 + 0x08]
269 stx %g0, [%g4 + 0x10]
270 stx %g0, [%g4 + 0x18]
271 stx %g0, [%g4 + 0x20]
272 stx %g0, [%g4 + 0x28]
273 stx %g0, [%g4 + 0x30]
274 stx %g0, [%g4 + 0x38]
275
276 set LDC_CONSOLE_DATA, %g5
277 stb %g5, [%g4 + LDC_CONS_TYPE]
278 mov 1, %g5 ! size=1, one char is
279 stb %g5, [%g4 + LDC_CONS_SIZE] ! being sent
280 stb %o0, [%g4 + LDC_CONS_PAYLOAD]
281
282 ldub [ %g2 + LDC_TARGET_TYPE ], %g5
283 cmp %g5, LDC_GUEST_ENDPOINT
284 be %xcc, 3f
285 nop
286
287 ! %g1 = new tail value
288 ! %g2 = sender's endpoint
289
290 HVCALL(guest_to_sp_tx_set_tail) ! clobbers all %g1,%g3-%g7
291 ba 4f
292 nop
2933:
294
295 HVCALL(guest_to_guest_tx_set_tail) ! clobbers all %g1,%g3-%g7
2964:
297 ! %g2 = sender's endpoint
298
299 HCALL_RET(EOK)
300
301 /*
302 * Console put char using a service channel as output
303 */
304
305
306#ifdef CONFIG_CN_UART /* { */
307.use_uart_put:
308 ldx [%g3 + GUEST_CONSOLE + CONS_UARTBASE], %g1
309 ! %g1 = uartp
3100:
311 ldub [%g1 + LSR_ADDR], %g4
312 btst LSR_THRE, %g4
313 bz,pn %xcc, herr_wouldblock
314 nop
315 stb %o0, [%g1]
316 HCALL_RET(EOK)
317
318#endif /* } */
319
320 SET_SIZE(hcall_cons_putchar)
321
322
323/*
324 * cons_getchar
325 *
326 * no arguments
327 * --
328 * ret0 status (%o0)
329 * ret1 char (%o1)
330 */
331 ENTRY_NP(hcall_cons_getchar)
332
333 GUEST_STRUCT(%g1)
334 ! %g1 = guestp
335
336 ! if not initialized, then return EWOULDBLOCK.
337 ! OK What type of console do we have.
338 ldub [%g1 + GUEST_CONSOLE + CONS_TYPE], %g5
339 cmp %g5, CONS_TYPE_UNCONFIG
340 beq,pn %xcc, herr_wouldblock
341 nop
342 cmp %g5, CONS_TYPE_LDC
343 beq,pt %xcc, .use_ldc_get
344 nop
345#ifdef CONFIG_CN_UART /* { */
346 cmp %g5, CONS_TYPE_UART
347 beq,pt %xcc, .use_uart_get
348 nop
349#endif /* } */
350 ba,pt %xcc, herr_inval ! Return inval if console not configd
351 nop
352
353#ifdef CONFIG_CN_UART /* { */
354
355.use_uart_get:
356 ldx [%g1 + GUEST_CONSOLE + CONS_UARTBASE], %g2
357
358 ! %g2 = uartp
359 ldub [%g2 + LSR_ADDR], %g3 ! line status register
360 btst LSR_BINT, %g3 ! BREAK?
361 bz,pt %xcc, 1f
362 nop
363
364 ! BREAK
365 andn %g3, LSR_BINT, %g3
366 stb %g3, [%g2 + LSR_ADDR] ! XXX clear BREAK? need w1c
367 mov CONS_BREAK, %o1
368 HCALL_RET(EOK)
369
3701: btst LSR_DRDY, %g3 ! character ready?
371 bz,pt %xcc, herr_wouldblock
372 nop
373
374 ldub [%g2], %o1 ! input data register
375 HCALL_RET(EOK)
376
377#endif /* } CONFIG_CN_UART */
378
379 ! read character from LDC internal buffer
380 !
381.use_ldc_get:
382
383 ! %g1 = guestp
384
385 mov %g1, %g4
386
387 ! LDC based console processing
388 setx GUEST_CONSOLE, %g2, %g3
389 add %g1, %g3, %g1
390
391 ldx [%g1 + CONS_ENDPT], %g2
392
393 mulx %g2, LDC_ENDPOINT_SIZE, %g2
394 set GUEST_LDC_ENDPOINT, %g3
395 add %g2, %g3, %g2
396 add %g2, %g4, %g2
397
398 ! %g2 = our endpoint
399
400 ldub [ %g2 + LDC_TARGET_TYPE ], %g3
401 cmp %g3, LDC_SP_ENDPOINT
402 be %xcc, 1f
403 nop
404
405 HVCALL(guest_to_guest_pull_data) ! clobbers all %g1,%g3-%g7
406 ba 2f
407 nop
4081:
409 HVCALL(sp_to_guest_pull_data) ! clobbers all %g1,%g3-%g7
4102:
411 ! %g2 = our endpoint
412
413 lduw [%g2 + LDC_RX_QHEAD], %g3 ! check if there is any data
414 lduw [%g2 + LDC_RX_QTAIL], %g4 ! in our RX queue.
415 cmp %g3, %g4
416 be %xcc, 1f
417
418 CPU_PUSH(%g2, %g4, %g5, %g6) ! save off endpoint struct
419 CPU_PUSH(%g3, %g4, %g5, %g6) ! save off head pointer
420
421 ! There is data in the RX queue, so process the next console packet.
422 ldx [%g2 + LDC_RX_QBASE_PA], %g4
423 add %g3, %g4, %g2
424
425 GUEST_STRUCT(%g1)
426
427 HVCALL(cons_ldc_callback)
428
429 CPU_POP(%g3, %g4, %g5, %g6) ! restore head pointer
430 CPU_POP(%g2, %g4, %g5, %g6) ! restore endpoint struct
431
432 ! Now we have to incriment the head pointer
433 ldx [%g2 + LDC_RX_QSIZE], %g5
434 dec Q_EL_SIZE, %g5
435 add %g3, Q_EL_SIZE, %g3
436 and %g3, %g5, %g5
437 stw %g5, [%g2 + LDC_RX_QHEAD]
438
4391:
440 GUEST_STRUCT(%g1)
441
442 ! LDC based console processing
443 setx GUEST_CONSOLE, %g2, %g3
444 add %g1, %g3, %g1
445
446 ! %g1 = guest console
447
448 ldub [%g1 + CONS_STATUS], %g2 ! chk if ready
449 andcc %g2, LDC_CONS_READY, %g0
450 bz,pn %xcc, herr_wouldblock
451 nop
452
453 andcc %g2, LDC_CONS_BREAK, %g0
454 bz,pt %xcc, 2f
455 nop
456 mov LDC_CONS_READY, %g2
457 stb %g2, [%g1 + CONS_STATUS] ! clear break
458 mov CONS_BREAK, %o1
459 HCALL_RET(EOK)
4602:
461 andcc %g2, LDC_CONS_HUP, %g0
462 bz,pt %xcc, 3f
463 nop
464 mov LDC_CONS_READY, %g2
465 stb %g2, [%g1 + CONS_STATUS] ! clear break
466 mov CONS_HUP, %o1
467 HCALL_RET(EOK)
468
4693: ! LDC Console data
470 ldx [%g1 + CONS_INHEAD], %g2 ! chk if head=tail
471 ldx [%g1 + CONS_INTAIL], %g3
472 cmp %g2, %g3
473 beq,pt %xcc, herr_wouldblock
474 nop
475
476 add %g1, CONS_INBUF, %g3 ! get inbuf addr
477 add %g3, %g2, %g3
478
479 ldub [%g3], %o1 ! input data register
480
481 inc %g2 ! inc the head
482 and %g2, (CONS_INBUF_SIZE - 1), %g2
483 stx %g2, [%g1 + CONS_INHEAD]
484
485 HCALL_RET(EOK)
486 SET_SIZE(hcall_cons_getchar)
487
488
489/*
490 * cons_read - read characters from the console
491 *
492 * Read arg1 characters from the console and place into buffer at arg0.
493 * If arg1 is zero the call immediately returns success, no data
494 * is consumed.
495 * On success ret1 contains either a magic character (CONS_BREAK, CONS_HUP)
496 * or the number of characters placed into the buffer.
497 *
498 * arg0 buffer RA (%o0)
499 * arg1 length (%o1)
500 * --
501 * ret0 status (%o0)
502 * ret1 length completed (%o1)
503 */
504 ENTRY_NP(hcall_cons_read)
505 /*
506 * read buffer size is 0, return success
507 */
508 brz,pn %o1, hret_ok
509 nop
510
511 GUEST_STRUCT(%g1)
512
513 ldub [%g1 + GUEST_CONSOLE + CONS_TYPE], %g5
514 cmp %g5, CONS_TYPE_UNCONFIG
515 beq,pn %xcc, herr_wouldblock
516 nop
517 cmp %g5, CONS_TYPE_LDC
518 beq,pt %xcc, .use_ldc_read
519 nop
520#ifdef CONFIG_CN_UART /* { */
521 cmp %g5, CONS_TYPE_UART
522 beq,pt %xcc, .use_uart_read
523 nop
524#endif /* } */
525 ba,pt %xcc, herr_inval ! Return inval if console not configd
526 nop
527
528#ifdef CONFIG_CN_UART /* { */
529
530.use_uart_read:
531 ldx [%g1 + GUEST_CONSOLE + CONS_UARTBASE], %g2
532 ! %g2 = uartp
533
534 ldub [%g2 + LSR_ADDR], %g3 ! line status register
535 btst LSR_BINT, %g3 ! BREAK?
536 bz,pt %xcc, 1f
537 nop
538
539 ! BREAK
540 andn %g3, LSR_BINT, %g3
541 stb %g3, [%g2 + LSR_ADDR] ! XXX clear BREAK? need w1c
542 mov CONS_BREAK, %o1
543 HCALL_RET(EOK)
544
5451: btst LSR_DRDY, %g3 ! character ready?
546 bz,pt %xcc, herr_wouldblock
547 nop
548
549 RA2PA_RANGE_CONV_UNK_SIZE(%g1, %o0, %o1, herr_noraddr, %g5, %g6)
550 mov %g6, %o0
551 ! %o0 buf PA
552
553 ldub [%g2], %g3 ! input data register
554 stb %g3, [%o0]
555 mov 1, %o1 ! Always one character
556 HCALL_RET(EOK)
557
558#endif /* } CONFIG_CN_UART */
559
560.use_ldc_read:
561 ! LDC based console processing
562 setx GUEST_CONSOLE, %g2, %g3
563 add %g1, %g3, %g6
564
565 ldx [%g6 + CONS_ENDPT], %g2
566
567 mulx %g2, LDC_ENDPOINT_SIZE, %g2
568 set GUEST_LDC_ENDPOINT, %g3
569 add %g2, %g3, %g2
570 add %g2, %g1, %g2
571
572 ! %g2 = our endpoint
573
574 ldub [ %g2 + LDC_TARGET_TYPE ], %g3
575 cmp %g3, LDC_SP_ENDPOINT
576 be %xcc, 1f
577 nop
578
579 HVCALL(guest_to_guest_pull_data) ! clobbers all %g1,%g3-%g7
580 ba 2f
581 nop
5821:
583 HVCALL(sp_to_guest_pull_data) ! clobbers all %g1,%g3-%g7
5842:
585 ! %g2 = our endpoint
586
587 lduw [%g2 + LDC_RX_QHEAD], %g3 ! check if there is any data
588 lduw [%g2 + LDC_RX_QTAIL], %g4 ! in our RX queue.
589 cmp %g3, %g4
590 be %xcc, 1f
591
592 CPU_PUSH(%g2, %g4, %g5, %g6) ! save off endpoint struct
593 CPU_PUSH(%g3, %g4, %g5, %g6) ! save off head pointer
594
595 ! There is data in the RX queue, so process the next console packet.
596 ldx [%g2 + LDC_RX_QBASE_PA], %g4
597 add %g3, %g4, %g2
598
599 GUEST_STRUCT(%g1)
600
601 HVCALL(cons_ldc_callback)
602
603 CPU_POP(%g3, %g4, %g5, %g6) ! restore head pointer
604 CPU_POP(%g2, %g4, %g5, %g6) ! restore endpoint struct
605
606 ! Now we have to incriment the head pointer
607 ldx [%g2 + LDC_RX_QSIZE], %g5
608 dec Q_EL_SIZE, %g5
609 add %g3, Q_EL_SIZE, %g3
610 and %g3, %g5, %g5
611 stw %g5, [%g2 + LDC_RX_QHEAD]
612
6131:
614 GUEST_STRUCT(%g6)
615
616 ! LDC based console processing
617 setx GUEST_CONSOLE, %g2, %g3
618 add %g6, %g3, %g6
619
620 ! %g6 = guest console struct
621 ldub [%g6 + CONS_STATUS], %g2 ! chk if ready
622 andcc %g2, LDC_CONS_READY, %g0
623 bz,pn %xcc, herr_wouldblock
624 nop
625
626 andcc %g2, LDC_CONS_BREAK, %g0
627 bz,pt %xcc, 2f
628 nop
629 mov LDC_CONS_READY, %g2
630 stb %g2, [%g6 + CONS_STATUS] ! clear break
631 mov CONS_BREAK, %o1
632 HCALL_RET(EOK)
6332:
634 andcc %g2, LDC_CONS_HUP, %g0
635 bz,pt %xcc, 3f
636 nop
637 mov LDC_CONS_READY, %g2
638 stb %g2, [%g6 + CONS_STATUS] ! clear hup
639 mov CONS_HUP, %o1
640 HCALL_RET(EOK)
6413:
642 ! LDC Console data
643 ldx [%g6 + CONS_INHEAD], %g2 ! chk if head=tail
644 ldx [%g6 + CONS_INTAIL], %g3
645 cmp %g2, %g3
646 beq,pt %xcc, herr_wouldblock
647 nop
648
649 GUEST_STRUCT(%g1)
650
651 RA2PA_RANGE_CONV_UNK_SIZE(%g1, %o0, %o1, herr_noraddr, %g5, %g4)
652 mov %g4, %o0
653 ! %o0 buf PA
654
655
656 add %g6, CONS_INBUF, %g3 ! get inbuf addr
657 mov %g0, %g4
658
659 ! g2 = cons buf head idx
660 ! g3 = cons buf ptr
661 ! g4 = count of chars read
662 ! g5 = current buf tail idx
663
6644:
665 ldub [%g3 + %g2], %g5
666 stb %g5, [%o0 + %g4]
667 inc %g4 ! inc count
668 inc %g2 ! inc the head
669 and %g2, (CONS_INBUF_SIZE - 1), %g2
670 stx %g2, [%g6 + CONS_INHEAD]
671
672 cmp %g4, %o1
673 bgeu,pt %xcc, 5f
674 nop
675 ldx [%g6 + CONS_INTAIL], %g5
676 cmp %g2, %g5
677 beq,pt %xcc, 5f
678 nop
679 ba 4b ! next char
680 nop
6815:
682 mov %g4, %o1 ! characters read
683 HCALL_RET(EOK)
684
685 SET_SIZE(hcall_cons_read)
686
687
688/*
689 * cons_write - write characters to the console
690 *
691 * Writes arg1 characters from the buffer at arg0 to the console.
692 * If arg1 is zero the call immediately returns success, no data
693 * is consumed.
694 * On success ret1 contains the actual number of characters consumed
695 * from the buffer.
696 *
697 * arg0 buffer RA (%o0)
698 * arg1 length (%o1)
699 * --
700 * ret0 status (%o0)
701 * ret1 length completed (%o1)
702 */
703 ENTRY_NP(hcall_cons_write)
704 brz,pn %o1, hret_ok
705 nop
706 VCPU_GUEST_STRUCT(%g4, %g3)
707
708 ! %g3 = guestp
709 ! %g4 = cpup
710 RA2PA_RANGE_CONV_UNK_SIZE(%g3, %o0, %o1, herr_noraddr, %g5, %g2)
711 mov %g2, %o0
712 ! %o0 buf PA
713
714 ldub [%g3 + GUEST_CONSOLE + CONS_TYPE], %g5
715 cmp %g5, CONS_TYPE_UNCONFIG
716 beq,pn %xcc, hret_ok
717 nop
718 cmp %g5, CONS_TYPE_LDC
719 beq,pt %xcc, .use_ldc_write
720 nop
721#ifdef CONFIG_CN_UART /* { */
722 cmp %g5, CONS_TYPE_UART
723 beq,pt %xcc, .use_uart_write
724 nop
725#endif /* } */
726 ba,pt %xcc, herr_inval ! Return inval if console not configd
727 nop
728
729#ifdef CONFIG_CN_UART /* { */
730
731.use_uart_write:
732 ldx [%g3 + GUEST_CONSOLE + CONS_UARTBASE], %g1
733 ! %g1 = uartp
734
735 ldub [%g1 + LSR_ADDR], %g4
736 btst LSR_THRE, %g4
737 bz,pn %xcc, herr_wouldblock
738 nop
739
740 mov 0, %g2
741 ! %g2 count of characters written
7421:
743 ldub [%o0 + %g2], %g3
744 stb %g3, [%g1]
745 inc %g2
746 cmp %g2, %o1
747 bgeu,pn %xcc, 2f
748 nop
749 ldub [%g1 + LSR_ADDR], %g4
750 btst LSR_THRE, %g4
751 bnz,pt %xcc, 1b
752 nop
753
7542:
755 mov %g2, %o1
756 HCALL_RET(EOK)
757
758#endif /* } CONFIG_CN_UART */
759
760.use_ldc_write:
761 setx GUEST_CONSOLE, %g2, %g6
762 add %g6, %g3, %g6
763
764 ldub [%g6 + CONS_STATUS], %g2 ! chk if ready
765 andcc %g2, LDC_CONS_READY, %g2
766 bz,pn %xcc, herr_wouldblock
767 nop
768
769 ldx [%g6 + CONS_ENDPT], %g1
770
771 ! %g1 = channel
772 ! %g3 = guest struct
773
774 mulx %g1, LDC_ENDPOINT_SIZE, %g1
775 set GUEST_LDC_ENDPOINT, %g2
776 add %g1, %g2, %g1
777 add %g1, %g3, %g2
778
779 ! target is a guest endpoint
780 ! if it has no receive queue configured drop the
781 ! console char and return back
782 ldub [ %g2 + LDC_TARGET_TYPE ], %g5
783 cmp %g5, LDC_GUEST_ENDPOINT
784 bne %xcc, 1f
785 nop
786
787 ldx [ %g2 + LDC_TARGET_GUEST ], %g6
788 ldx [ %g2 + LDC_TARGET_CHANNEL ], %g4
789 mulx %g4, LDC_ENDPOINT_SIZE, %g4
790 set GUEST_LDC_ENDPOINT, %g5
791 add %g6, %g5, %g6
792 add %g6, %g4, %g6 ! g6 is the target endpoint
793 ldx [ %g6 + LDC_RX_QSIZE ], %g4 ! check if queue is configured
794 brnz,a,pn %g4, 1f
795 nop
796 HCALL_RET(EOK)
797
798 ! %g2 = our endpoint
799 ! %g3 = guest struct
8001:
801 lduw [ %g2 + LDC_TX_QHEAD ], %g6
802 lduw [ %g2 + LDC_TX_QTAIL ], %g4
803
804 ldx [ %g2 + LDC_TX_QSIZE ], %g5
805 dec Q_EL_SIZE, %g5
806 add %g4, Q_EL_SIZE, %g1
807 and %g1, %g5, %g1
808
809 cmp %g1, %g6 ! Does TX queue have room?
810 bne,pt %xcc, 2f ! If so, continue.
811 nop
812
813 ! TX queue is full. Have we already marked it as such?
814 ldub [ %g2 + LDC_TXQ_FULL ], %g5
815 set 1, %g6
816 brz,a %g5, 1b ! If not, mark it and try one
817 stb %g6, [ %g2 + LDC_TXQ_FULL ] ! last time to avoid lost intr.
818
819 ba herr_wouldblock
820 nop
8212:
822 ! %g2 = our endpoint
823 ! %g3 = guest struct
824
825 ldx [ %g2 + LDC_TX_QBASE_PA ], %g3
826 add %g4, %g3, %g4
827
828 ! %g1 = new tail value
829 ! %g2 = sender's endpoint
830 ! %g4 = pointer to outgoing queue entry
831
832 set LDC_CONSOLE_DATA, %g5
833 stb %g5, [%g4 + LDC_CONS_TYPE]
834 mov %g0, %g6
835 add %g4, LDC_CONS_PAYLOAD, %g3 ! payload buffer
8363:
837 ldub [%o0 + %g6], %g5
838 stb %g5, [%g3 + %g6]
839 inc %g6
840 cmp %g6, %o1 ! copied all chars ?
841 bgeu,pn %xcc, 4f
842 nop
843 cmp %g6, LDC_CONS_PAYLOAD_SZ ! payload buf full ?
844 bgeu,pn %xcc, 4f
845 nop
846 ba 3b ! store next char in pkt
847 nop
8484:
849 mov %g6, %o1 ! return / store chars copied
850 stb %g6, [%g4 + LDC_CONS_SIZE]
851
852 ldub [ %g2 + LDC_TARGET_TYPE ], %g5
853 cmp %g5, LDC_GUEST_ENDPOINT
854 be %xcc, 3f
855 nop
856
857 ! %g1 = new tail value
858 ! %g2 = sender's endpoint
859
860 HVCALL(guest_to_sp_tx_set_tail) ! clobbers all %g1,%g3-%g7
861 ba 4f
862 nop
8633:
864 HVCALL(guest_to_guest_tx_set_tail) ! clobbers all %g1,%g3-%g7
8654:
866 ! %g2 = sender's endpoint
867
868 HCALL_RET(EOK)
869
870 SET_SIZE(hcall_cons_write)
871
872