Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / dummy_mods / dumbserial / dumbserial.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: dumbserial.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/* dumb serial device for NIOBP */
22
23/* "Leveraged" from Legion dumbserial devices :) */
24
25/*
26 * A dumb serial device - briefly modeled on the NS 16550 device
27 * ... i.e. register bit fields are similar, but that's about it.
28 *
29 * We support input and output character buffering.
30 * Eventually these sizes will be settable from the configfile
31 * Also eventually we will understand baud rates etc. and fake
32 * these appropriately.
33 * For the moment, we support only a simple status poll, byte
34 * get and byte put.
35 * Status simply returns, byte-available, underrun, and overrun
36 * for input info. Nothing for output (yet).
37 */
38
39
40 /*
41 * Registers (8-bits only - 8byte addressing, upper bits read 0 write ignored)
42 * num RW Function:
43 * 0 R Input data register
44 * 0 W Output data register
45 * 1 RW Interrupt enable register
46 * 2 R Interrupt indentification register
47 * 2 W FIFO control register
48 * 3 RW Line control register
49 * 4 RW Modem control register
50 * 5 RW Line status register
51 * 6 RW Modem status register
52 * 7 RW Scratch register
53 * 8 RW Divisor lo
54 * 9 RW Divisor hi
55 *
56 * See 16550 data sheet p 14 - table M
57 */
58
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <errno.h>
63#include <unistd.h>
64#include <assert.h>
65#include <fcntl.h>
66#include <sys/types.h>
67#include <sys/stat.h>
68#include <sys/mman.h>
69#include <sys/dkio.h>
70#include <sys/dklabel.h>
71#include <sys/vtoc.h>
72#include <strings.h>
73
74#include <pthread.h>
75#include <errno.h>
76#include <signal.h>
77#include <sys/socket.h>
78#include <netinet/in.h>
79#include <sys/un.h>
80#include <arpa/inet.h>
81#include <netdb.h>
82#include <pthread.h>
83
84#include "mmi.h"
85#include "ui.h"
86
87// #include "createthr.h"
88
89static int dumbserial_ld_operation (void *cd, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid);
90static int dumbserial_st_operation (void *cd, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid);
91
92#define MAXCPU 32
93
94#define DBGX(s) do {} while (0)
95
96#define MAXNAMELEN 256
97
98typedef enum {
99 DS_Input = 0x0, /* RO */
100 DS_Output = 0x0, /* WO */
101 DS_IntEnable = 0x1,
102 DS_IntIdent = 0x2, /* RO */
103 DS_FIFOCtrl = 0x2, /* WO */
104 DS_LineCtrl = 0x3,
105 DS_ModemCtrl = 0x4,
106 DS_LineStatus = 0x5,
107 DS_ModemStatus = 0x6,
108 DS_Scratch = 0x7,
109 DS_DivLo = 0x8,
110 DS_DivHi = 0x9
111} ds_reg_t;
112
113typedef enum {
114 TE_Normal,
115 TE_SawCR,
116 TE_SawTilde
117} ds_tildestate_t;
118
119#define ptest(_s) if (fds.revents & _s) printf(","#_s)
120
121typedef struct {
122
123 bool uses_term;
124
125 /* device registers .. */
126 uint8_t scratch; /* ! */
127 uint8_t line_status;
128#define DS_LSTAT_DATA_READY 0x1
129#define DS_LSTAT_OVERRUN 0x2
130#define DS_LSTAT_PARTIY_ERR 0x4
131#define DS_LSTAT_FRAMING_ERR 0x8
132#define DS_LSTAT_BREAK 0x10
133#define DS_LSTAT_TX_HOLD 0x20
134#define DS_LSTAT_TX_EMPTY 0x40
135#define DS_LSTAT_RCV_ERR 0x80
136
137#define DEFAULT_RXFIFOSZ 1024
138
139 struct {
140 uint8_t *bufp;
141 int head;
142 int tail;
143 int count;
144 int size;
145 } in;
146
147 int reg_shift; /* register alignment 0 .. 3 (default = 0 = byte align) */
148#define DS_REG_SHIFT_DEF 0
149
150 /* the following if uses_term is set */
151#define DEFAULT_XTERM_STR "/usr/openwin/bin/xterm -T TTY -e /bin/telnet %s %d &"
152 char * term_strp;
153 int tty_skt; /* socket to send / receive to client on */
154 bool tty_attached;
155 pthread_t pthread_id;
156 pthread_mutex_t tty_lock;
157 pthread_cond_t tty_cv;
158 ds_tildestate_t tilde_state;
159
160 uint64_t startpa;
161 uint64_t endpa;
162 const char * type; // GUEST or HYPERVISOR
163} ds_state_t;
164
165 /*
166 * Internal functions
167 */
168
169#define NUM_DEVICES 2 // hypervisor and guest consoles
170#define HV_DEVICE 0
171#define G_DEVICE 1
172static ds_state_t *dumbserials[NUM_DEVICES];
173
174int temp_ds_counter = 0;
175#define HV_SERIAL 0 // calls xterm
176#define G_SERIAL 1 // nothing
177
178/*
179#define HV_START 0x9f00000000
180#define HV_END 0x9f0000004f
181*/
182#define HV_START 0xfff0c2c000
183#define HV_END 0xfff0c2c04f
184#define G_START 0x9f10002000
185#define G_END 0x9f1000204f
186
187static void create_term(ds_state_t * dsp);
188extern "C" static void * ds_input_thr(void * ptr);
189static void ds_insert_bytes(ds_state_t * dsp, uint8_t * bufp, int len);
190static void dump_buf(char * strp, uint8_t * bufp, int len);
191
192#if NDEBUG /* { */
193 /* hack for TLB debugging - to go away FIXME */
194static void ds_dump_tlb(ds_state_t * dsp, bool is_itlb);
195#endif /* } */
196
197ds_state_t *get_ds_instance(uint64_t addr) {
198
199 assert(0); // should not be called
200#if 0
201 if ( addr >= HV_START && addr < HV_END ) {
202 return dumbserials[HV_DEVICE];
203 } else if ( addr >= G_START && addr < G_END ) {
204 return dumbserials[G_DEVICE];
205 } else {
206 fprintf(stderr, "Unknown dumbconsole address range!\n");
207 exit(1);
208 }
209#endif
210 return NULL;
211}
212
213extern "C" static int dumbserial_physio_access(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask)
214{
215 if (wr) {
216 return dumbserial_st_operation(obj, paddr, buf, size, cpuid);
217 } else {
218 return dumbserial_ld_operation(obj, paddr, buf, size, cpuid);
219 }
220}
221
222int dumbserial_ld_operation (void *obj, uint64_t paddr, uint64_t *buf, int size, uint32_t v9cpuid)
223{
224 // Load accessor ...
225 ds_reg_t reg;
226 uint64_t val;
227 ds_state_t *dsp = (ds_state_t *) obj;
228 DBGX (printf("CAUGHT LD to %016llx with size %d\n", paddr, size); );
229 if ((paddr & (((uint64_t)1<<dsp->reg_shift)-1))!=0) {
230 *buf = 0;
231 return false;
232 }
233 // use the offset of the address, not the entire address
234 reg = (ds_reg_t) ((paddr & 0xfff) >> dsp->reg_shift);
235 val = 0;
236 DBGX(printf("\treg: %d\n", reg); );
237 switch (reg) {
238 case DS_Input:
239 pthread_mutex_lock(&dsp->tty_lock);
240 if (dsp->in.count == 0) {
241 val = 0;
242 dsp->line_status &= ~DS_LSTAT_DATA_READY;
243 } else {
244 val = dsp->in.bufp[dsp->in.head];
245 dsp->in.head ++;
246 if (dsp->in.head >= dsp->in.size) dsp->in.head = 0;
247 dsp->in.count --;
248 if (dsp->in.count == 0) {
249 dsp->line_status &= ~DS_LSTAT_DATA_READY;
250 }
251 }
252 pthread_mutex_unlock(&dsp->tty_lock);
253 break;
254
255 case DS_IntEnable:
256 break;
257
258 case DS_IntIdent:
259 break;
260
261 case DS_LineCtrl:
262 break;
263
264 case DS_ModemCtrl:
265 break;
266
267 case DS_LineStatus:
268 /* FIXME - more to do here */
269 /* TX always empty for the moment */
270 pthread_mutex_lock(&dsp->tty_lock);
271 val = dsp->line_status;
272 pthread_mutex_unlock(&dsp->tty_lock);
273 break;
274
275 case DS_ModemStatus:
276 break;
277
278 case DS_Scratch:
279 dsp->scratch = val & 0xff;
280 break;
281
282 case DS_DivLo:
283 break;
284
285 case DS_DivHi:
286 break;
287
288 default:
289 return true;
290 }
291
292 if (1 == size)
293 val = (uint64_t)(int64_t)(int8_t)val;
294 DBGX(printf("\tLD from %016llx returning %016llx\n", paddr, val););
295 *buf = val;
296 return 0;
297}
298
299int dumbserial_st_operation (void *obj, uint64_t pa, uint64_t *buf, int size, uint32_t v9cpuid)
300{
301 // Store accessor ...
302 ds_reg_t reg;
303 uint64_t val;
304 ds_state_t *dsp = (ds_state_t *) obj;
305 DBGX(printf("caught st to %016llx with data %c, size %d\n", pa, (char)*buf, size););
306 if ((pa & (((uint64_t)1<<dsp->reg_shift)-1))!=0) {
307 return false;
308 }
309 // use the offset of the address, not the entire address
310 reg = (ds_reg_t) ((pa & 0xfff) >> dsp->reg_shift);
311 val = *buf;
312
313 if (val>0xff) {
314 return false;
315 }
316
317 val &= 0xff;
318
319 switch (reg) {
320 case DS_Output:
321 if (dsp->uses_term) {
322 if (dsp->tty_attached) {
323 uint8_t buf[1];
324 buf[0] = val;
325 write(dsp->tty_skt, buf, 1);
326 }
327 } else {
328 putchar(val);
329 fflush(stdout);
330 }
331 break;
332
333 case DS_IntEnable:
334 break;
335
336 case DS_FIFOCtrl:
337 break;
338
339 case DS_LineCtrl:
340 break;
341
342 case DS_ModemCtrl:
343 break;
344
345 case DS_LineStatus:
346 /* FIXME - more to do here */
347 /* TX always empty for the moment */
348 pthread_mutex_lock(&dsp->tty_lock);
349 dsp->line_status = (val & 0xff) | DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
350 pthread_mutex_unlock(&dsp->tty_lock);
351 break;
352
353 case DS_ModemStatus:
354 break;
355
356 case DS_Scratch:
357 dsp->scratch = val & 0xff;
358 break;
359
360 case DS_DivLo:
361 break;
362
363 case DS_DivHi:
364 break;
365
366 default:
367 return false;
368 }
369 return 0;
370}
371
372void ds_parse(void) {
373
374 ds_state_t *dsp = (ds_state_t *)calloc(1, sizeof(ds_state_t));
375
376 dsp->uses_term = false; /* default: output but no input */
377 dsp->in.size = DEFAULT_RXFIFOSZ;
378 dsp->reg_shift = DS_REG_SHIFT_DEF;
379
380 dsp->term_strp = (char *)malloc(256);
381 dsp->uses_term = true;
382
383 switch(temp_ds_counter) {
384 case HV_SERIAL:
385 strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x20+170+300 -T 'Hypervisor Console' -e ./netcons %s %d &");
386 dumbserials[HV_DEVICE] = dsp;
387 break;
388 case G_SERIAL:
389 strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x35+200+30 -T 'Guest Console' -e ./netcons %s %d &");
390 dumbserials[G_DEVICE] = dsp;
391 break;
392 default:
393 break;
394 }
395
396}
397
398void ds_init(ds_state_t * dsp) {
399#if 1
400 dsp->line_status = DS_LSTAT_TX_EMPTY | DS_LSTAT_TX_HOLD;
401#else
402 dsp->line_status = 0;
403#endif
404 dsp->scratch = 0;
405 dsp->in.count = 0;
406 dsp->in.head = 0;
407 dsp->in.tail = 0;
408 dsp->in.bufp = (uint8_t *)calloc(1, dsp->in.size);
409
410 /* if TTY to be created then do so ... */
411 if (dsp->uses_term) create_term(dsp);
412}
413
414 /*
415 * Create term ... during initialisation, create the thread to run the
416 * terminal.
417 */
418
419void create_term(ds_state_t * dsp)
420{
421 dsp->tty_skt = -1;
422 dsp->tty_attached = false;
423 /* dsp->tilde_state = TE_Normal; */
424 dsp->tilde_state = TE_SawCR; /* shouldn't have to CR to use ~ as first input char */
425 pthread_mutex_init(&dsp->tty_lock, NULL);
426 pthread_cond_init(&dsp->tty_cv, NULL);
427
428 /*
429 * OK first we create the management thread for this console's input
430 * - then wait for it to tell us that it is happily up and running
431 * before we return to the simulator to continue initialisation.
432 */
433
434 pthread_mutex_lock(&dsp->tty_lock);
435
436 pthread_create(&(dsp->pthread_id), NULL, ds_input_thr, (void *) dsp);
437
438 /* should probably timeout here incase child doesn't start */
439 while (!dsp->tty_attached) pthread_cond_wait(&dsp->tty_cv, &dsp->tty_lock);
440 pthread_mutex_unlock(&dsp->tty_lock);
441
442}
443
444
445
446
447
448 /*
449 * Thread to manage external connections to this serial port.
450 *
451 * By default it creates an xterm with a telnet connection to
452 * the appropriate i/o port.
453 */
454
455void * ds_input_thr(void * ptr)
456{
457 ds_state_t * dsp;
458 uint8_t buf[1024];
459#define MAXHOSTNAME 256
460 char myhostname[MAXHOSTNAME];
461 int ds_sv_skt;
462 struct hostent * hp;
463 int on, length;
464 struct sockaddr_in ds_server, from;
465 char * froms;
466
467 dsp = (ds_state_t*)ptr;
468
469 /*
470 * Create our socket to listen to
471 */
472
473 ds_sv_skt = socket(AF_INET, SOCK_STREAM, 0);
474 if (ds_sv_skt < 0) {
475 fprintf(stderr, "opening stream socket");
476 exit(1);
477 }
478
479 /* enable the reuse of this socket if this process dies */
480 if (setsockopt(ds_sv_skt, SOL_SOCKET, SO_REUSEADDR, (uint8_t*)&on, sizeof(on))<0) {
481 fprintf(stderr,"turning on REUSEADDR");
482 exit(1);
483 }
484
485 /* bind it */
486retry:;
487 ds_server.sin_family = AF_INET;
488 ds_server.sin_addr.s_addr = INADDR_ANY;
489 ds_server.sin_port = htons(0); /* bind to an OS selected local port */
490
491 if (bind(ds_sv_skt, (struct sockaddr *)&ds_server, sizeof(ds_server)) < 0) {
492 switch (errno) {
493 case EAGAIN:
494 goto retry;
495
496 case EADDRINUSE:
497 fprintf(stderr, "Port is already in use\n");
498 exit(1);
499 default:
500 fprintf(stderr, "binding tcp stream socket");
501 exit(1);
502 }
503 }
504
505 length = sizeof(ds_server);
506 if (getsockname(ds_sv_skt, (struct sockaddr *) &ds_server, &length)==-1) {
507 fprintf(stderr, "getting socket name");
508 exit(1);
509 }
510
511 listen(ds_sv_skt, 1);
512
513
514 /*
515 * Create the client xterm etc
516 */
517
518 gethostname(myhostname, MAXHOSTNAME);
519 sprintf((char*)buf, dsp->term_strp, myhostname, ntohs(ds_server.sin_port));
520
521 system((char*)buf);
522
523 /*
524 * OK main loop for processing connections and data traffic
525 */
526
527
528 do {
529 if (!dsp->tty_attached) {
530 ui->output("\nWaiting for connection to : %s:%d\n", myhostname, ntohs(ds_server.sin_port));
531
532 length = sizeof(from);
533 dsp->tty_skt = accept(ds_sv_skt, (struct sockaddr *)&from, (int*)&length);
534
535 hp = gethostbyaddr((char *)&from.sin_addr, 4, AF_INET);
536 if (hp == (struct hostent *)0) {
537 froms = inet_ntoa(from.sin_addr);
538 fprintf(stderr,"cant resolve hostname for %s\n", froms);;
539 } else {
540 froms = hp->h_name;
541 }
542 ui->output("connection from %s:%d\n", froms, ntohs(from.sin_port));
543
544 pthread_mutex_lock(&dsp->tty_lock);
545 dsp->tty_attached = true;
546 pthread_mutex_unlock(&dsp->tty_lock);
547 pthread_cond_signal(&dsp->tty_cv);
548 } else {
549 int res;
550 struct pollfd fds;
551
552#define POLL_TIMEOUT -1 /* wait forever ? FIXME ? */
553 fds.fd = dsp->tty_skt;
554 fds.events = POLLIN|POLLPRI;
555#if HOST_OS_SOLARIS9 /* { */
556 fds.events |= POLLRDNORM|POLLRDBAND;
557#endif /* } */
558 fds.revents = 0;
559
560 res = poll(&fds, 1, POLL_TIMEOUT);
561
562DBGX( printf("tty: ");
563 ptest(POLLIN);
564 ptest(POLLOUT);
565 ptest(POLLERR);
566 ptest(POLLHUP);
567 ptest(POLLNVAL);
568 printf("\n");
569 fflush(stdout); );
570
571#if HOST_OS_SOLARIS9 /* { */
572DBGX( printf("\t");
573 ptest(POLLRDNORM);
574 ptest(POLLRDBAND);
575 ptest(POLLWRNORM);
576 ptest(POLLWRBAND);
577 printf("\n");
578 fflush(stdout); );
579#endif /* } */
580
581 if (fds.revents & POLLIN) {
582 res = read(dsp->tty_skt, buf, sizeof (buf));
583 if (res == 0) {
584 /* a read of 0 bytes is an EOF */
585 pthread_mutex_lock(&dsp->tty_lock);
586 dsp->tty_attached = false;
587 pthread_mutex_unlock(&dsp->tty_lock);
588 pthread_cond_signal(&dsp->tty_cv);
589 close(dsp->tty_skt);
590 // assert(dsp->tty_skt = -1);
591 } else if (res<0) {
592 perror("read");
593 } else {
594DBGX( dump_buf("input bytes:", buf, res); );
595
596 ds_insert_bytes(dsp, buf, res);
597 }
598 }
599 }
600 } while (1);
601
602 return (void*)0; /* compiler joy */
603}
604
605
606void dump_buf(char * strp, uint8_t * bufp, int len)
607{
608 int i;
609
610 printf("%s read %d bytes: ", strp, len);
611 for(i=0; i<len; i++) printf("0x%02x [%c]",bufp[i],bufp[i]>=32 && bufp[i]<127 ? bufp[i] : '.');
612 printf("\n");
613}
614
615
616/* emits string and newline */
617void
618ds_output(ds_state_t *dsp, const char *str)
619{
620 if (dsp->uses_term && dsp->tty_attached) {
621 (void) write(dsp->tty_skt, str, strlen(str));
622 (void) write(dsp->tty_skt, "\n", 1);
623 } else {
624 puts(str);
625 fflush(stdout);
626 }
627}
628
629
630
631
632
633
634
635 /* FIXME: This compile option
636 * enables the console to force an external chip reset of any procs
637 * attached to the same domain.
638 * This is somewhat of a hack, and should be handled else where ...
639 * ... which is why it is not a device option in the config file
640 */
641
642#if CONSOLE_RESET /* { */
643void
644ds_domain_reset(ds_state_t * dsp)
645{
646 // domain_t * dp;
647 int i;
648
649 /*
650 * FIXME: this is a hack ...
651 * walk the procs in my domain, and reset them all
652 */
653
654 // dp = dsp->config_devp->domainp;
655
656 for (i=0; i<dp->procs.count; i++) {
657 config_proc_t * cp;
658
659 cp = LIST_ENTRY(dp->procs, i);
660
661 cp->proc_typep->ext_signal(cp, ES_Reset);
662 }
663}
664#endif /* } */
665
666void
667ds_insert_bytes(ds_state_t *dsp, uint8_t *bufp, int len)
668{
669 int i;
670
671 pthread_mutex_lock(&dsp->tty_lock);
672
673 /*
674 * process all characters in buffer, don't check for overrun
675 * right away
676 */
677 for (i = 0; i < len; i++) {
678 int c = bufp[i];
679
680DBGX( printf("State %d : Char typed 0x%x [%c]\n", (int)dsp->tilde_state, c, c>=' ' && c<127 ? c : '.'); fflush(stdout); );
681
682 switch (dsp->tilde_state) {
683 case TE_Normal: /* waiting for CR */
684 if (c == '\n') {
685 dsp->tilde_state = TE_SawCR;
686 break;
687 }
688 case TE_SawCR: /* waiting for tilde */
689 if (c == '~') {
690 dsp->tilde_state = TE_SawTilde;
691 goto skip;
692 }
693 if (c != '\n') dsp->tilde_state = TE_Normal;
694 break;
695
696 case TE_SawTilde: /* tilde command */
697 dsp->tilde_state = TE_SawCR;
698 switch (c) {
699 case '~': /* emit single tilde */
700 dsp->tilde_state = TE_Normal;
701 break;
702
703 case '#': /* BREAK */
704 dsp->line_status |= DS_LSTAT_BREAK;
705 ds_output(dsp, "BREAK");
706 /* allow another ~ cmd without CR */
707 goto skip;
708
709 case '?': /* help */
710 ds_output(dsp, "dumb_serial tilde escapes:");
711 ds_output(dsp, "\t# BREAK");
712 ds_output(dsp, "\t~ generate tilde");
713#if CONSOLE_RESET /* { */
714 ds_output(dsp, "\tx external reset for CPUs in same domain");
715#endif /* } */
716#if !NDEBUG /* { */
717 ds_output(dsp, "\ti dump I-TLB contents for CPUs in same domain");
718 ds_output(dsp, "\td dump D-TLB contents for CPUs in same domain");
719 ds_output(dsp, "\tb toggle the debug output enable bits");
720#endif /* } */
721 ds_output(dsp, "\t? this message");
722 /* allow another ~ cmd without CR */
723 goto skip;
724
725#if CONSOLE_RESET /* { */
726 case 'x': /* Hack to enable extern chip reset easily */
727 ds_output(dsp, "Resetting cpu(s) in domain");
728 ds_domain_reset(dsp);
729 goto skip; /* swallow 'x' character after sending reset */
730#endif /* } */
731
732#if !NDEBUG /* { */
733 case 'i':
734 // ds_dump_tlb(dsp, false);
735 goto skip;
736 case 'd':
737 // ds_dump_tlb(dsp, true);
738 goto skip;
739 case 'b':
740 // debug_bits ^= -1;
741 goto skip;
742#endif /* } */
743
744 default: /* eat current char */
745 /*
746 * FIXME could emit ~ and current char
747 * but it's harder
748 */
749 ds_output(dsp, "~? for tilde help");
750 goto skip;
751 }
752 break;
753 }
754 if (dsp->in.count < dsp->in.size) {
755 dsp->in.bufp[dsp->in.tail] = bufp[i];
756 dsp->in.tail++;
757 if (dsp->in.tail >= dsp->in.size)
758 dsp->in.tail = 0;
759 dsp->in.count++;
760 dsp->line_status |= DS_LSTAT_DATA_READY;
761 } else {
762 if (!(dsp->line_status & DS_LSTAT_OVERRUN))
763 fprintf(stderr, "dumbserial: buffer overrun");
764 dsp->line_status |= DS_LSTAT_OVERRUN;
765 }
766 skip:;
767 }
768 pthread_mutex_unlock(&dsp->tty_lock);
769}
770
771#if NDEBUG /* { */
772 /* hack for TLB debugging - to go away FIXME */
773
774 /* First find all the cpus, then dump their TLBs ... */
775static void ds_dump_tlb(ds_state_t * dsp, bool is_dtlb)
776{
777 extern void niagara_dump_tlbs(config_proc_t * cp, bool is_dtlb);
778 domain_t * dp;
779 int i;
780
781 /*
782 * FIXME: this is a hack ...
783 * walk the procs in my domain, and dump the tlb contents
784 */
785
786 dp = dsp->config_devp->domainp;
787
788 for (i=0; i<dp->procs.count; i++) {
789 config_proc_t * cp;
790
791 cp = LIST_ENTRY(dp->procs, i);
792
793 niagara_dump_tlbs(cp, is_dtlb); /* FIXME */
794 }
795}
796#endif /* } */
797
798extern "C" void dumbserial_create_instance (const char *modname, const char *instance_name)
799{
800 ds_state_t * dsp = new ds_state_t;
801
802 dsp->uses_term = true;
803 dsp->in.size = DEFAULT_RXFIFOSZ;
804 dsp->reg_shift = DS_REG_SHIFT_DEF;
805
806 dsp->term_strp = (char *)malloc(256);
807
808 mmi_instance_t instance = mmi_register_instance(modname, instance_name, (void *) dsp, "dumbserial model");
809
810 // parse startpa, endpa, type values for this instance
811 // syntax: sysconf dumbserial <name> type=<type> startpa=<pa> endpa=<pa>
812 // where <type> is either HYPERVISOR or GUEST
813 // syntax example: sysconf dumbserial ds0 type=HYPERVISOR startpa=0xfff0c2c000 endpa=0xfff0c2cfff
814
815 int argc = mmi_argc(instance);
816 int i;
817 for (i=0; i<argc; i++) {
818 char * arg = strdup(mmi_argv(instance, i));
819 char * marker;
820 char * lv = strtok_r(arg, "=", &marker);
821 if (strcmp(lv, "startpa") == 0) {
822 errno = 0;
823 char * rv = strtok_r(NULL, "=", &marker);
824 dsp->startpa = strtoull(rv, NULL, 0);
825 if (errno) {
826 perror("dumbserial: error parsing startpa");
827 exit(1);
828 }
829 } else if (strcmp(lv, "endpa") == 0) {
830 errno = 0;
831 char * rv = strtok_r(NULL, "=", &marker);
832 dsp->endpa = strtoull(rv, NULL, 0);
833 if (errno) {
834 perror("dumbserial: error parsing startpa");
835 exit(1);
836 }
837 } else if (strcmp(lv, "type") == 0) {
838 char * rv = strtok_r(NULL, "=", &marker);
839 dsp->type = strdup(rv);
840 } // else - do nothing
841
842 free(arg);
843 }
844
845 if (strcmp(dsp->type, "HYPERVISOR") == 0) {
846 strcpy(dsp->term_strp, "xterm -l -lf hypervisor1.log -bg black -fg green -geometry 80x20+170+300 -T 'Hypervisor Console' -e ./netcons %s %d &");
847 // dumbserials[HV_DEVICE] = dsp;
848 } else if (strcmp(dsp->type, "GUEST") == 0) {
849 strcpy(dsp->term_strp, "xterm -l -lf guest1.log -bg black -fg green -geometry 80x35+200+30 -T 'Guest Console' -e ./netcons %s %d &");
850 } else {
851 fprintf(stderr, "DUMBSERIAL: invalid type in sysconf directive (%s) - must be HYPERVISOR or GUEST\n", dsp->type);
852 }
853
854 // Parses memory information
855 // ds_parse();
856 // loads file
857 ds_init(dsp);
858
859 // register IO operations
860 uint64_t sz = dsp->endpa - dsp->startpa + 1;
861 ui->output ("dumbserial (%s): register LD/ST access @PA=0x%llx size=0x%llx\n", instance_name, dsp->startpa, sz);
862 if (mmi_map_physio(dsp->startpa, sz, (void *) dsp, dumbserial_physio_access)) {
863 fprintf (stderr, "dumbserial (%s): unable to register IO interceptor @0x%llx size 0x%llx\n", instance_name, dsp->startpa, sz);
864 return;
865 }
866}
867
868extern "C" void _init () {
869
870 char buff[128];
871 int ncpu;
872 int argc;
873 char *blaze_ver_s;
874 float blaze_ver;
875
876 if (! mmi_register_instance_creator ("dumbserial", dumbserial_create_instance )) {
877 fprintf (stderr, "Cannot register instance creator for <%s> \n", "dumbserial");
878 return;
879 }
880
881 /* Assign interface */
882
883}
884
885/////////////////////////////////////////////////
886
887extern "C" void _fini ()
888{
889}