Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * OpenSPARC T2 Processor File: parser.c | |
5 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
7 | * | |
8 | * The above named program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public | |
10 | * License version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * The above named program is distributed in the hope that it will be | |
13 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public | |
18 | * License along with this work; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
20 | * | |
21 | * ========== Copyright Header End ============================================ | |
22 | */ | |
23 | /* | |
24 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
25 | * Use is subject to license terms. | |
26 | */ | |
27 | ||
28 | #pragma ident "@(#)parser.c 1.35 07/04/02 SMI" | |
29 | ||
30 | #include <sys/types.h> | |
31 | #include <errno.h> | |
32 | #include <stdlib.h> | |
33 | #include <unistd.h> | |
34 | #include <stdio.h> | |
35 | #include <dlfcn.h> | |
36 | #include <link.h> | |
37 | #include <string.h> | |
38 | #include <search.h> | |
39 | ||
40 | #include "basics.h" | |
41 | #include "fatal.h" | |
42 | #include "strutil.h" | |
43 | #include "allocate.h" | |
44 | #include "simcore.h" | |
45 | #include "config.h" | |
46 | #include "options.h" | |
47 | #include "fileutil.h" | |
48 | #include "lexer.h" | |
49 | #include "sam_dev.h" | |
50 | ||
51 | #if ERROR_INJECTION | |
52 | #define CPP_OPTIONS " -DERROR_INJECTION" | |
53 | #else | |
54 | #define CPP_OPTIONS "" | |
55 | #endif | |
56 | ||
57 | #define MAX_TRIES 4 | |
58 | ||
59 | extern void lex_fatal(char * str, ...); | |
60 | ||
61 | /* | |
62 | * Parse the top-level config file. | |
63 | * Essentially this is restricted to the systems | |
64 | * directive in the config file | |
65 | */ | |
66 | ||
67 | ||
68 | ||
69 | static void parse_proc(domain_t *domainp); | |
70 | static void parse_device(domain_t *domainp); | |
71 | static void parse_mmi_device(domain_t *domainp); | |
72 | static void parse_addressmap(domain_t *domainp); | |
73 | static void parse_domain(domain_t *domainp); | |
74 | static void parse_domains(system_t *systemp); | |
75 | static void parse_systems(); | |
76 | static void parse_service_processor(system_t *systemp); | |
77 | static void parse_debug(); | |
78 | static void parse_save_state(); | |
79 | void *dlopen_lib(char *mdlnamep, char *symname, char *libname); | |
80 | ||
81 | proc_type_t * find_proc_type(char * procname); | |
82 | dev_type_t * find_dev_type(char * devname); | |
83 | extern void sam_init_device(char *dev_namep, config_dev_t *config_devp); | |
84 | extern void sam_parse_dev(domain_t *domainp, config_dev_t *config_devp); | |
85 | extern dev_type_t *sam_load_device(config_dev_t *config_devp); | |
86 | ||
87 | target_config_t target_config; /* define here ? */ | |
88 | ||
89 | /* list of dev_type_t pointers to dl'd devices */ | |
90 | LIST_DEF(dev_cache, dev_type_t); | |
91 | ||
92 | /* list of proc_type_t pointers to dl'd processors */ | |
93 | LIST_DEF(proc_cache, proc_type_t); | |
94 | ||
95 | ||
96 | /* | |
97 | * Setup empty configuration prior to config parsing | |
98 | */ | |
99 | ||
100 | void init_target_config() | |
101 | { | |
102 | LIST_INIT(target_config.systems, system_t); | |
103 | ||
104 | /* Init list of loaded device libraries */ | |
105 | ||
106 | LIST_INIT(dev_cache, dev_type_t); | |
107 | ||
108 | /* Init list of loaded processor libraries */ | |
109 | ||
110 | LIST_INIT(proc_cache, proc_type_t); | |
111 | } | |
112 | ||
113 | ||
114 | ||
115 | ||
116 | ||
117 | /* | |
118 | * This function calls into the lexer to | |
119 | * parse the config and state files. | |
120 | */ | |
121 | ||
122 | void parse_config_file() | |
123 | { | |
124 | char tempfilep[64]; | |
125 | char buffer[8192]; /* big space */ | |
126 | int count; | |
127 | int res; | |
128 | FILE * fp; | |
129 | ||
130 | /* | |
131 | * First step is to run the C pre-processor | |
132 | * over the config file. | |
133 | * Output from the pre-processor, is piped | |
134 | * directly into the lexer. | |
135 | * This is complicated because the pre-processor also | |
136 | * outputs errors, and may fail. | |
137 | */ | |
138 | ||
139 | /* FIXME: | |
140 | * Should probably do this properly with pipes etc. | |
141 | * but for now, just use a temp file in /tmp | |
142 | * for the sake of convenience. | |
143 | */ | |
144 | ||
145 | for (count = 0; count < MAX_TRIES; count++) { | |
146 | sprintf(tempfilep, "/tmp/sim.cfg.%d.%02d", (int)getpid(), count); | |
147 | if (!file_exists(tempfilep)) break; | |
148 | } | |
149 | if (count == 5) fatal("Unable to create a temporary file for config pre-processing"); | |
150 | errno = 0; | |
151 | sprintf(buffer, "%s" CPP_OPTIONS " %s %s > %s", | |
152 | options.cpp_cmd, options.cpp_optionsp, | |
153 | options.config_filep, tempfilep); | |
154 | ||
155 | do { | |
156 | DBG( printf("system(%s)\n", buffer); ); | |
157 | res = system(buffer); | |
158 | } while (res == -1 && (errno == EAGAIN || errno == EINTR)); | |
159 | if (res == -1) fatal("Failed trying to pre-process config file %s\n", options.config_filep); | |
160 | ||
161 | DBG( printf("Exit status %d\n", res); ); | |
162 | ||
163 | fp = fopen_check(tempfilep, "r"); | |
164 | init_lexer(options.config_filep, fp, tempfilep); | |
165 | ||
166 | parse_debug(); /* process any debug directives */ | |
167 | ||
168 | parse_systems(); | |
169 | ||
170 | fclose(fp); | |
171 | ||
172 | unlink(tempfilep); /* clean up - remove temp file */ | |
173 | ||
174 | ||
175 | ||
176 | if (options.dumpconfig) | |
177 | dump_config(stdout); | |
178 | } | |
179 | ||
180 | ||
181 | ||
182 | /* | |
183 | * Parse optional debug directive | |
184 | */ | |
185 | ||
186 | void parse_debug() | |
187 | { | |
188 | lexer_tok_t tok; | |
189 | ||
190 | tok = lex_get_token(); | |
191 | if (tok != T_Token || !streq(lex.strp, "debug")) { | |
192 | lex_unget(); | |
193 | return; | |
194 | } | |
195 | lex_get(T_L_Brace); | |
196 | ||
197 | do { | |
198 | tok = lex_get_token(); | |
199 | switch (tok) { | |
200 | case T_Token: | |
201 | if (streq(lex.strp, "save_state")) | |
202 | parse_save_state(); | |
203 | else | |
204 | lex_fatal("Unexpected string in debug directive\n"); | |
205 | break; | |
206 | case T_R_Brace: | |
207 | return; | |
208 | default: | |
209 | lex_fatal("Unexpected token in debug directive.\n"); | |
210 | } | |
211 | } while (1); | |
212 | ||
213 | } | |
214 | ||
215 | void | |
216 | parse_save_state() | |
217 | { | |
218 | lexer_tok_t tok; | |
219 | ||
220 | lex_get(T_L_Brace); | |
221 | ||
222 | do { | |
223 | tok = lex_get_token(); | |
224 | switch (tok) { | |
225 | case T_Token: | |
226 | if (streq(lex.strp, "filename")) { | |
227 | lex_get(T_String); | |
228 | options.save_restore.filenamep = Xstrdup(lex.strp); | |
229 | printf("debug:save_state:filename = %s\n", | |
230 | options.save_restore.filenamep); | |
231 | } else | |
232 | if (streq(lex.strp, "format")) { | |
233 | lex_get(T_String); | |
234 | if (streq(lex.strp, "legion")) | |
235 | options.save_restore.legion_format = true; | |
236 | else if (streq(lex.strp, "axis")) | |
237 | options.save_restore.legion_format = false; | |
238 | else | |
239 | lex_fatal("expected either legion or axis"); | |
240 | ||
241 | printf("debug:save_state:format = %s\n", | |
242 | options.save_restore.legion_format ? "legion" : "axis"); | |
243 | } else | |
244 | if (streq(lex.strp, "icount")) { | |
245 | lex_get(T_Number); | |
246 | options.save_restore.trigger_icount = lex.val; | |
247 | printf("debug:save_state:icount = 0x%llx\n", | |
248 | options.save_restore.trigger_icount); | |
249 | } else | |
250 | if (streq(lex.strp, "trap_pc")) { | |
251 | lex_get(T_Number); | |
252 | options.save_restore.trap_pc = lex.val; | |
253 | printf("debug:save_state:trap_pc = 0x%llx\n", | |
254 | options.save_restore.trap_pc); | |
255 | } else | |
256 | if (streq(lex.strp, "patch")) { | |
257 | lex_get(T_Number); /* addr */ | |
258 | options.save_restore.mem_patch.addr = lex.val; | |
259 | lex_get(T_Number); /* val */ | |
260 | options.save_restore.mem_patch.val = lex.val; | |
261 | printf("debug:save_state:patch addr=0x%llx with val=0x%llx\n", | |
262 | options.save_restore.mem_patch.addr, | |
263 | options.save_restore.mem_patch.val); | |
264 | } | |
265 | lex_get(T_S_Colon); | |
266 | break; | |
267 | case T_R_Brace: | |
268 | return; | |
269 | default: | |
270 | lex_fatal("Unexpected token in save_state directive.\n"); | |
271 | } | |
272 | } while (1); | |
273 | ||
274 | } | |
275 | ||
276 | /* | |
277 | * Top level of parser ... look for one or more | |
278 | * system directives. | |
279 | */ | |
280 | ||
281 | ||
282 | void parse_systems() | |
283 | { | |
284 | LIST_INIT( target_config.systems, system_t ); | |
285 | ||
286 | do { | |
287 | system_t * systemp; | |
288 | lexer_tok_t tok; | |
289 | int idx; | |
290 | ||
291 | tok = lex_get_token(); | |
292 | if (tok == T_EOF) break; | |
293 | if (tok != T_Token || !streq(lex.strp, "system")) | |
294 | lex_fatal("system definition expected"); | |
295 | ||
296 | lex_get(T_String); | |
297 | ||
298 | idx = target_config.systems.count; | |
299 | systemp = LIST_ADD( target_config.systems, system_t ); | |
300 | systemp->namep = Xstrdup(lex.strp); | |
301 | systemp->idx = idx; | |
302 | systemp->fake_sp = true; | |
303 | ||
304 | lex_get(T_L_Brace); | |
305 | ||
306 | parse_service_processor(systemp); /* if any */ | |
307 | ||
308 | parse_domains(systemp); | |
309 | ||
310 | lex_get(T_R_Brace); | |
311 | ||
312 | } while (1); | |
313 | ||
314 | if (target_config.systems.count == 0) lex_fatal("at least one system expected"); | |
315 | } | |
316 | ||
317 | ||
318 | /* | |
319 | * Read one service_processor into the specified system, if it exists | |
320 | */ | |
321 | ||
322 | void parse_service_processor(system_t *systemp) | |
323 | { | |
324 | domain_t *domainp; | |
325 | config_dev_t *config_devp; | |
326 | lexer_tok_t tok; | |
327 | char symname[BUFSIZ], libname[BUFSIZ], mdlname[BUFSIZ]; | |
328 | dev_type_t *dev_typep = NULL; | |
329 | ||
330 | tok = lex_get_token(); | |
331 | if (tok == T_EOF) | |
332 | lex_fatal("unexpected EOF"); | |
333 | if (tok == T_R_Brace) | |
334 | lex_fatal("service_processor specific token expected"); | |
335 | ||
336 | if (tok != T_Token || !streq(lex.strp, "service_processor")) { | |
337 | /* No Service processor - we're done */ | |
338 | lex_unget(); | |
339 | return; | |
340 | } | |
341 | ||
342 | lex_get(T_String); /* get the name of the service_proc */ | |
343 | ||
344 | sprintf(mdlname, "%s", lex.strp); | |
345 | sprintf(symname, "dev_type_%s", mdlname); | |
346 | DBG( printf("parse_service_processor - parsed %s - looking for %s\n", | |
347 | mdlname, symname); ); | |
348 | ||
349 | dev_typep = (dev_type_t *)dlopen_lib(mdlname, symname, libname); | |
350 | ||
351 | if (dev_typep == (dev_type_t *)0) | |
352 | lex_fatal("unknown dev type \"%s\"", mdlname); | |
353 | ||
354 | systemp->service_procp = Xmalloc(sizeof (service_proc_t)); | |
355 | ||
356 | /* parse service_processor */ | |
357 | dev_typep->parse_dev(NULL); | |
358 | ||
359 | /* save pointer to the service_processor handle */ | |
360 | systemp->service_procp->dev_typep = dev_typep; | |
361 | systemp->service_procp->namep = Xstrdup(mdlname); | |
362 | ||
363 | #ifdef NOT_NOW | |
364 | /* Turn off fake SP flag */ | |
365 | systemp->fake_sp = false; | |
366 | #endif | |
367 | ||
368 | return; | |
369 | } | |
370 | ||
371 | ||
372 | /* | |
373 | * Read one or more domains into the specified system | |
374 | */ | |
375 | ||
376 | void parse_domains(system_t *systemp) | |
377 | { | |
378 | LIST_INIT(systemp->domains, domain_t); | |
379 | ||
380 | do { | |
381 | domain_t * domainp; | |
382 | lexer_tok_t tok; | |
383 | int idx; | |
384 | ||
385 | tok = lex_get_token(); | |
386 | if (tok == T_EOF) lex_fatal("unexpected EOF"); | |
387 | if (tok == T_R_Brace) break; | |
388 | if (tok != T_Token || !streq(lex.strp, "domain")) | |
389 | lex_fatal("domain definition expected"); | |
390 | ||
391 | idx = systemp->domains.count; | |
392 | domainp = LIST_ADD( systemp->domains, domain_t ); | |
393 | domainp->idx = idx; | |
394 | domainp->systemp = systemp; | |
395 | ||
396 | lex_get(T_L_Brace); | |
397 | ||
398 | parse_domain(domainp); | |
399 | ||
400 | lex_get(T_R_Brace); | |
401 | } while (1); | |
402 | ||
403 | if (systemp->domains.count == 0) lex_fatal("At least one domain expected for system \"%s\"", systemp->namep); | |
404 | ||
405 | lex_unget(); | |
406 | } | |
407 | ||
408 | ||
409 | ||
410 | /* | |
411 | * OK, the more complicated function | |
412 | * to determine and connect the different | |
413 | * components of a domain. | |
414 | */ | |
415 | ||
416 | void parse_domain(domain_t *domainp) | |
417 | { | |
418 | LIST_INIT( domainp->procs, config_proc_t ); | |
419 | domainp->device.count = 0; | |
420 | domainp->device.listp = (config_dev_t *)0; | |
421 | ||
422 | do { | |
423 | lexer_tok_t tok; | |
424 | ||
425 | tok = lex_get_token(); | |
426 | if (tok == T_EOF) lex_fatal("unexpected EOF within domain defn"); | |
427 | if (tok == T_R_Brace) break; | |
428 | if (tok != T_Token) goto fail; | |
429 | ||
430 | if (streq(lex.strp, "sysclkfreq")) { | |
431 | domainp->sysclkfreq = parse_number_assign(); | |
432 | } else | |
433 | if (streq(lex.strp, "processor")) { | |
434 | parse_proc(domainp); | |
435 | } else | |
436 | if (streq(lex.strp, "addressmap")) { | |
437 | parse_addressmap(domainp); | |
438 | } else { | |
439 | fail: | |
440 | lex_fatal("domain specific token expected"); | |
441 | } | |
442 | ||
443 | } while (1); | |
444 | ||
445 | lex_unget(); | |
446 | ||
447 | if (domainp->sysclkfreq == 0) lex_fatal("sysclkfreq not specified in domain definition"); | |
448 | ||
449 | /* processor specific domain check of stuff parsed from conf file */ | |
450 | LIST_ENTRY(domainp->procs, 0)->proc_typep->domain_check(domainp); | |
451 | ||
452 | } | |
453 | ||
454 | ||
455 | ||
456 | ||
457 | ||
458 | ||
459 | /* | |
460 | * Handle the proc "name" wrapper around a processor definition. | |
461 | * This enables us to select the correct processor handler | |
462 | * then call into that handler to complete the parsing | |
463 | * of this specific processor. | |
464 | */ | |
465 | ||
466 | void parse_proc(domain_t *domainp) | |
467 | { | |
468 | proc_type_t * proc_typep; | |
469 | config_proc_t * config_procp; | |
470 | ||
471 | lex_get(T_String); /* get the name of the proc type */ | |
472 | ||
473 | proc_typep = find_proc_type(lex.strp); | |
474 | if (proc_typep == (proc_type_t *)0) lex_fatal("unknown processor type \"%s\"", lex.strp); | |
475 | ||
476 | /* | |
477 | * If the processor type module has not been loaded and | |
478 | * initialised .. do so now | |
479 | */ | |
480 | if (!proc_typep->flag_initialised) { | |
481 | if (!proc_typep->init_module(proc_typep)) fatal("Failed initialising processor module %s", proc_typep->proc_type_namep); | |
482 | } | |
483 | ||
484 | lex_get(T_L_Brace); | |
485 | ||
486 | /* OK, allocate the proc entry */ | |
487 | config_procp = LIST_ADD( domainp->procs, config_proc_t ); | |
488 | ||
489 | config_procp->proc_id = domainp->procs.count -1; | |
490 | config_procp->proc_typep = proc_typep; | |
491 | config_procp->domainp = domainp; | |
492 | ||
493 | /* based on the proc type we call the proc-dependent parser */ | |
494 | proc_typep->parse_proc(domainp, config_procp); | |
495 | ||
496 | /* finish up cleanly */ | |
497 | ||
498 | lex_get(T_R_Brace); | |
499 | } | |
500 | ||
501 | ||
502 | ||
503 | ||
504 | ||
505 | ||
506 | ||
507 | /* | |
508 | * This function (eventually) parses the address map | |
509 | * for each domain. Basically, this creates the devices | |
510 | * that are attached directly to the domain memory bus. | |
511 | * | |
512 | * Unnecessary ? FIXME | |
513 | */ | |
514 | ||
515 | void parse_addressmap(domain_t *domainp) | |
516 | { | |
517 | lexer_tok_t tok; | |
518 | ||
519 | lex_get(T_L_Brace); | |
520 | ||
521 | /* for now - just swallow until the } */ | |
522 | while (1) { | |
523 | tok = lex_get_token(); | |
524 | if (tok == T_EOF) lex_fatal("unexpected end of file"); | |
525 | if (tok == T_R_Brace) break; | |
526 | ||
527 | if (tok != T_Token) lex_fatal("addressmap element expected"); | |
528 | ||
529 | if (streq(lex.strp, "device")) { | |
530 | parse_device(domainp); | |
531 | } else if (streq(lex.strp, "mmi_device")) { | |
532 | parse_mmi_device(domainp); | |
533 | } else { | |
534 | lex_fatal("unknown/unexpected token %s in addressmap", lex.strp); | |
535 | } | |
536 | ||
537 | } while (tok != T_EOF && tok != T_R_Brace); | |
538 | lex_unget(); | |
539 | ||
540 | /* finish up cleanly */ | |
541 | lex_get(T_R_Brace); | |
542 | } | |
543 | ||
544 | ||
545 | ||
546 | ||
547 | ||
548 | ||
549 | /* | |
550 | * having decided the address map entry is a device, | |
551 | * parse its name, base, and extent, then drop into the | |
552 | * device's own parsing routine. | |
553 | */ | |
554 | ||
555 | void parse_device(domain_t *domainp) | |
556 | { | |
557 | config_dev_t * config_devp, *overlapp; | |
558 | config_addr_t *config_addrp; | |
559 | dev_type_t * dev_typep; | |
560 | bool_t is_size; | |
561 | lexer_tok_t tok; | |
562 | ||
563 | /* | |
564 | * We've found a device name so check whether we have a library | |
565 | * for this dev_type. | |
566 | */ | |
567 | lex_get(T_String); | |
568 | dev_typep = find_dev_type(lex.strp); | |
569 | if (dev_typep == (dev_type_t *)0) lex_fatal("unknown dev type \"%s\"",lex.strp); | |
570 | /* OK, allocate the proc entry */ | |
571 | config_devp = Xmalloc(sizeof (config_dev_t)); | |
572 | ||
573 | config_devp->is_implied = false; /* this is a real device */ | |
574 | config_devp->dev_typep = dev_typep; | |
575 | config_devp->devp = (void*)0; /* gets allocated in the dev parser */ | |
576 | config_devp->addrp = NULL; /* see insert_domain_address() */ | |
577 | ||
578 | do { | |
579 | tpaddr_t baseaddr, topaddr; | |
580 | ||
581 | lex_get(T_Number); | |
582 | baseaddr = lex.val; | |
583 | ||
584 | is_size = false; | |
585 | tok = lex_get_token(); | |
586 | if (tok == T_Plus) is_size = true; else lex_unget(); | |
587 | ||
588 | lex_get(T_Number); | |
589 | topaddr = lex.val; | |
590 | if (is_size) | |
591 | topaddr += baseaddr; | |
592 | ||
593 | if (topaddr <= baseaddr) | |
594 | lex_fatal("top address <= base address with device %s", | |
595 | config_devp->dev_typep->dev_type_namep); | |
596 | ||
597 | insert_domain_address(domainp, config_devp, baseaddr, topaddr); | |
598 | ||
599 | } while (lex_get_token() == T_Comma); | |
600 | ||
601 | lex_unget(); | |
602 | ||
603 | /* Insert device into the domain */ | |
604 | overlapp = insert_domain_device(domainp, config_devp); | |
605 | ||
606 | if (overlapp != NULL) { | |
607 | lex_fatal("device \"%s\" @ 0x%llx overlaps with device \"%s\" @ 0x%llx", | |
608 | overlapp->dev_typep->dev_type_namep, | |
609 | overlapp->addrp->baseaddr, | |
610 | config_devp->dev_typep->dev_type_namep, | |
611 | config_devp->addrp->baseaddr); | |
612 | } | |
613 | ||
614 | /* based on the dev type we call the dev-dependent parser */ | |
615 | dev_typep->parse_dev(config_devp); | |
616 | } | |
617 | ||
618 | ||
619 | ||
620 | /* | |
621 | * Parse MMI device | |
622 | */ | |
623 | void parse_mmi_device(domain_t *domainp) | |
624 | { | |
625 | config_dev_t * config_devp, *overlapp; | |
626 | config_addr_t *config_addrp; | |
627 | dev_type_t * dev_typep; | |
628 | lexer_tok_t tok; | |
629 | ||
630 | config_devp = Xmalloc(sizeof (config_dev_t)); | |
631 | ||
632 | /* | |
633 | * parse to get the MMI device name | |
634 | */ | |
635 | lex_get(T_String); | |
636 | if (lex.strp == NULL) | |
637 | lex_fatal("missing MMI device name in parse_mmi_device"); | |
638 | ||
639 | sam_init_device(lex.strp, config_devp); | |
640 | ||
641 | /* | |
642 | * finish the parsing | |
643 | */ | |
644 | sam_parse_dev(domainp, config_devp); | |
645 | ||
646 | /* | |
647 | * load MMI SAM device module | |
648 | */ | |
649 | dev_typep = sam_load_device(config_devp); | |
650 | if (dev_typep == (dev_type_t *)0) lex_fatal("unknown dev type \"%s\"",lex.strp); | |
651 | ||
652 | /* | |
653 | * Found a matching library, add it to the loaded list. | |
654 | * | |
655 | * NOTE: We do not dlclose() the libarary here as we know it will be | |
656 | * needed later on when the functions in the dev_typep are accessed. | |
657 | */ | |
658 | LIST_ADD_PTR(dev_cache, dev_type_t, dev_typep); | |
659 | } | |
660 | ||
661 | /* | |
662 | * Support functions for other parser codes | |
663 | */ | |
664 | ||
665 | /* | |
666 | * Parse a number assignment: | |
667 | * e.g. 0x40000 ; | |
668 | */ | |
669 | ||
670 | uint64_t parse_number_assign() | |
671 | { | |
672 | uint64_t val; | |
673 | ||
674 | lex_get(T_Number); | |
675 | val = lex.val; | |
676 | lex_get(T_S_Colon); | |
677 | ||
678 | return (val); | |
679 | } | |
680 | ||
681 | /* | |
682 | * dlopen a lib["mdlnamep"].so in the plugins/ dir or in the | |
683 | * options.libpath search path and locate the symbol "symname". | |
684 | * If there is a pre-existing handle - use it. | |
685 | * If the library was successfully opened, save the handle. | |
686 | * Once a valid handle is avail, get the address of symname and return. | |
687 | * Don't log error on failure to add to htable; non-fatal, only affects | |
688 | * performance. | |
689 | */ | |
690 | #define MAX_DLENT 128 /* max dlentries cacheable */ | |
691 | typedef struct { | |
692 | char *so_path; /* fq path to lib where symbol found */ | |
693 | void *so_addr; /* shared object symbol address */ | |
694 | } dlitem_t; | |
695 | ||
696 | void * | |
697 | dlopen_lib(char *mdlnamep, char *symname, char *libname) | |
698 | { | |
699 | static int first_pass = 0; | |
700 | void *dlh = NULL, *fptr = NULL; | |
701 | int idx; | |
702 | char *pathp; | |
703 | ENTRY item, *f_item; | |
704 | char hkey[128]; | |
705 | dlitem_t *dip; | |
706 | ||
707 | if (first_pass == 0) { | |
708 | (void) hcreate(MAX_DLENT); | |
709 | first_pass = 1; | |
710 | } | |
711 | ||
712 | sprintf(hkey, "%s%s", mdlnamep, symname); | |
713 | item.key = hkey; | |
714 | DBG( printf("Looking for module [%s][%s]\n", mdlnamep, symname); ); | |
715 | ||
716 | if ((f_item = hsearch(item, FIND)) != NULL) { | |
717 | /* found it, return info */ | |
718 | dip = (dlitem_t *)f_item->data; | |
719 | strcpy(libname, dip->so_path); | |
720 | DBG( printf("Found [%s][%s] %p\n", | |
721 | mdlnamep, symname, dip->so_addr); ); | |
722 | return (dip->so_addr); | |
723 | } | |
724 | ||
725 | /* not found, try to open and add it on libpath */ | |
726 | for (idx = 0; idx < options.libpath.count; idx++) { | |
727 | pathp = LIST_ENTRY(options.libpath, idx); | |
728 | sprintf(libname, "%s/lib%s.so", pathp, mdlnamep); | |
729 | ||
730 | DBG( printf("Loading the [%s] module - %s\n", mdlnamep, libname); ); | |
731 | ||
732 | if (NULL != (dlh = dlopen(libname, RTLD_NOW))) { | |
733 | goto dlopen_success; | |
734 | } | |
735 | } | |
736 | ||
737 | /* not found, try to open and add it on compiled in default paths */ | |
738 | sprintf(libname, "lib%s.so", mdlnamep); | |
739 | DBG( printf("Loading the [%s] module - %s\n", mdlnamep, libname); ); | |
740 | ||
741 | if (NULL == (dlh = dlopen(libname, RTLD_NOW))) { | |
742 | printf("\tdlopen_lib error opening [%s]\t%s\n", | |
743 | mdlnamep, dlerror()); | |
744 | return (NULL); | |
745 | } | |
746 | ||
747 | dlopen_success: | |
748 | /* Found a library in libpath that we can open */ | |
749 | DBG( printf("\tFound and opened [%s]\n", libname); ); | |
750 | ||
751 | /* Extract and return the symbol address from the shared object */ | |
752 | if (NULL == (fptr = dlsym(dlh, symname))) { | |
753 | printf("\tdlopen_lib: [%s]\n", dlerror()); | |
754 | /* do not add entry if no symbol found */ | |
755 | return (NULL); | |
756 | } | |
757 | ||
758 | /* Have a valid lib,symbol - add to lookup table */ | |
759 | dip = Xmalloc(sizeof (*dip)); | |
760 | dip->so_path = Xstrdup(libname); | |
761 | dip->so_addr = (void *)fptr; | |
762 | item.data = (void *)dip; | |
763 | item.key = Xstrdup(hkey); | |
764 | ||
765 | /* add item to lookup table */ | |
766 | if (NULL == hsearch(item, ENTER)) { | |
767 | free((void *)dip->so_path); | |
768 | free(item.data); | |
769 | free((void *)item.key); | |
770 | } | |
771 | ||
772 | return (fptr); | |
773 | } | |
774 | ||
775 | ||
776 | /* | |
777 | * Call dlopen_lib() to load the device module lib["devnamep"].so in | |
778 | * the plugins/ dir. If a matching library is found: | |
779 | * | |
780 | * - use dlsym() to look for it's dev_type_t structure | |
781 | * - check the dev_type_t name value matches the "devnamep" | |
782 | * - add the matching library to the loaded list | |
783 | * - return a pointer to the dev_type_t for this device | |
784 | */ | |
785 | dev_type_t * find_dev_type(char *devnamep) | |
786 | { | |
787 | char symname[BUFSIZ], libname[BUFSIZ]; | |
788 | dev_type_t *dev_typep = NULL; | |
789 | int idx; | |
790 | ||
791 | if (devnamep == NULL) | |
792 | return ((dev_type_t *)0); | |
793 | ||
794 | /* | |
795 | * First look through the cached list of device | |
796 | * modules we've already opened. | |
797 | */ | |
798 | for (idx = 0; idx < dev_cache.count; idx++) { | |
799 | dev_typep = LIST_ENTRY(dev_cache, idx); | |
800 | ||
801 | if (streq(dev_typep->dev_type_namep, devnamep)) | |
802 | return (dev_typep); | |
803 | } | |
804 | ||
805 | /* | |
806 | * Dlopen the device module library | |
807 | */ | |
808 | sprintf(symname, "dev_type_%s", devnamep); | |
809 | ||
810 | dev_typep = (dev_type_t *)dlopen_lib(devnamep, symname, libname); | |
811 | if (dev_typep == NULL) | |
812 | return ((dev_type_t *)0); | |
813 | ||
814 | /* | |
815 | * Make sure the name in the dev_type_name matches the device | |
816 | */ | |
817 | if (!streq(dev_typep->dev_type_namep, devnamep)) { | |
818 | printf("\nERROR: name does not match. %s != %s in %s:%s\n", | |
819 | dev_typep->dev_type_namep, devnamep, libname, symname); | |
820 | return ((dev_type_t *)0); | |
821 | } | |
822 | ||
823 | /* | |
824 | * Found a matching library, add it to the loaded list. | |
825 | * | |
826 | * NOTE: We do not dlclose() the libarary here as we know it will be | |
827 | * needed later on when the functions in the dev_typep are accessed. | |
828 | */ | |
829 | LIST_ADD_PTR(dev_cache, dev_type_t, dev_typep); | |
830 | ||
831 | return (dev_typep); | |
832 | } | |
833 | ||
834 | ||
835 | /* | |
836 | * Call dlopen_lib() to load the proc module lib["procnamep"].so in | |
837 | * the plugins/ dir. If a matching library is found: | |
838 | * | |
839 | * - use dlsym() to look for it's proc_type_t structure | |
840 | * - check the proc_type_t name value matches the "procnamep" | |
841 | * - add the matching library to the loaded list | |
842 | * - return a pointer to the proc_type_t for this proc | |
843 | */ | |
844 | proc_type_t * find_proc_type(char *procnamep) | |
845 | { | |
846 | char symname[BUFSIZ], libname[BUFSIZ]; | |
847 | proc_type_t *proc_typep = NULL; | |
848 | int idx; | |
849 | ||
850 | ||
851 | if (procnamep == NULL) | |
852 | return ((proc_type_t *)0); | |
853 | ||
854 | /* First look through the cached list of processor | |
855 | * modules we've already opened. | |
856 | */ | |
857 | ||
858 | for (idx = 0; idx < proc_cache.count; idx++) { | |
859 | proc_typep = LIST_ENTRY(proc_cache, idx); | |
860 | ||
861 | if (streq(proc_typep->proc_type_namep, procnamep)) | |
862 | return (proc_typep); | |
863 | } | |
864 | ||
865 | /* | |
866 | * Dlopen the proc module library | |
867 | */ | |
868 | sprintf(symname, "proc_type_%s", procnamep); | |
869 | ||
870 | proc_typep = (proc_type_t *)dlopen_lib(procnamep, symname, libname); | |
871 | if (proc_typep == NULL) | |
872 | return ((proc_type_t *)0); | |
873 | ||
874 | /* | |
875 | * Make sure the name in the proc_type_name matches the device | |
876 | */ | |
877 | if (!streq(proc_typep->proc_type_namep, procnamep)) { | |
878 | printf("\nERROR: name does not match. %s != %s in %s:%s\n", | |
879 | proc_typep->proc_type_namep, procnamep, libname, symname); | |
880 | return ((proc_type_t *)0); | |
881 | } | |
882 | ||
883 | /* | |
884 | * Found a matching library, add it to the loaded list. | |
885 | * | |
886 | * NOTE: We do not dlclose() the libarary here as we know it will be | |
887 | * needed later on when the functions in the proc_typep are accessed. | |
888 | */ | |
889 | LIST_ADD_PTR(proc_cache, proc_type_t, proc_typep); | |
890 | ||
891 | return (proc_typep); | |
892 | } | |
893 | ||
894 | /* | |
895 | * Insert a config device into the address map of a certain domain | |
896 | * Returns NULL on success, the overlapping device node on failure. | |
897 | */ | |
898 | ||
899 | config_dev_t * | |
900 | insert_domain_device(domain_t *domainp, config_dev_t *config_devp) | |
901 | { | |
902 | config_dev_t **pdp, *dp; | |
903 | ||
904 | config_devp->domainp = domainp; | |
905 | config_devp->device_id = domainp->device.count; | |
906 | ||
907 | ASSERT(config_devp->addrp->topaddr > config_devp->addrp->baseaddr); | |
908 | ASSERT(config_devp->addrp->range != (tvaddr_t)0); | |
909 | ||
910 | /* insert into sorted list of devices ... */ | |
911 | for (pdp = &(domainp->device.listp); (dp = *pdp) != (config_dev_t *)0; pdp = &(dp->nextp)) { | |
912 | if (dp->addrp->topaddr <= config_devp->addrp->baseaddr) continue; | |
913 | if (dp->addrp->baseaddr >= config_devp->addrp->topaddr) break; | |
914 | ||
915 | return (dp); | |
916 | } | |
917 | ||
918 | /* link device into list in order */ | |
919 | config_devp->nextp = *pdp; | |
920 | *pdp = config_devp; | |
921 | domainp->device.count ++; | |
922 | DBG( printf("insert_domain_device %p name=<%s> base=%p, top=%p\n", | |
923 | config_devp, config_devp->dev_typep->dev_type_namep, | |
924 | config_devp->addrp->baseaddr, | |
925 | config_devp->addrp->topaddr); ); | |
926 | return (NULL); | |
927 | } | |
928 | ||
929 | /* | |
930 | * Insert a config address into the address map of a certain domain | |
931 | * Returns NULL on success, the overlapping device node on failure. | |
932 | */ | |
933 | ||
934 | config_addr_t * | |
935 | insert_domain_address(domain_t *domainp, config_dev_t *devp, tpaddr_t baseaddr, tpaddr_t topaddr) | |
936 | { | |
937 | config_addr_t **pap, *ap, *addrp; | |
938 | ||
939 | addrp = Xmalloc(sizeof (config_addr_t)); | |
940 | ||
941 | addrp->config_devp = devp; | |
942 | addrp->baseaddr = baseaddr; | |
943 | addrp->topaddr = topaddr; | |
944 | /* save us annoying adds and subs all the time */ | |
945 | addrp->range = topaddr - baseaddr; | |
946 | ||
947 | if (devp->addrp == NULL) | |
948 | devp->addrp = addrp; | |
949 | ||
950 | /* insert into sorted list of addresses ... */ | |
951 | for (pap = &(domainp->address.listp); (ap = *pap) != NULL; | |
952 | pap = &(ap->nextp)) { | |
953 | if (ap->topaddr <= addrp->baseaddr) continue; | |
954 | if (ap->baseaddr >= addrp->topaddr) break; | |
955 | return (ap); | |
956 | } | |
957 | ||
958 | /* link device into list in order */ | |
959 | addrp->nextp = *pap; | |
960 | *pap = addrp; | |
961 | domainp->address.count++; | |
962 | DBG( printf("insert_domain_address devp=%p addrp=%p base=%llx, " | |
963 | "top=%llx\n", | |
964 | addrp->config_devp, addrp, addrp->baseaddr, | |
965 | addrp->topaddr); ); | |
966 | return (NULL); | |
967 | } |