* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: parser.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)parser.c 1.35 07/04/02 SMI"
#define CPP_OPTIONS " -DERROR_INJECTION"
extern void lex_fatal(char * str
, ...);
* Parse the top-level config file.
* Essentially this is restricted to the systems
* directive in the config file
static void parse_proc(domain_t
*domainp
);
static void parse_device(domain_t
*domainp
);
static void parse_mmi_device(domain_t
*domainp
);
static void parse_addressmap(domain_t
*domainp
);
static void parse_domain(domain_t
*domainp
);
static void parse_domains(system_t
*systemp
);
static void parse_systems();
static void parse_service_processor(system_t
*systemp
);
static void parse_debug();
static void parse_save_state();
void *dlopen_lib(char *mdlnamep
, char *symname
, char *libname
);
proc_type_t
* find_proc_type(char * procname
);
dev_type_t
* find_dev_type(char * devname
);
extern void sam_init_device(char *dev_namep
, config_dev_t
*config_devp
);
extern void sam_parse_dev(domain_t
*domainp
, config_dev_t
*config_devp
);
extern dev_type_t
*sam_load_device(config_dev_t
*config_devp
);
target_config_t target_config
; /* define here ? */
/* list of dev_type_t pointers to dl'd devices */
LIST_DEF(dev_cache
, dev_type_t
);
/* list of proc_type_t pointers to dl'd processors */
LIST_DEF(proc_cache
, proc_type_t
);
* Setup empty configuration prior to config parsing
void init_target_config()
LIST_INIT(target_config
.systems
, system_t
);
/* Init list of loaded device libraries */
LIST_INIT(dev_cache
, dev_type_t
);
/* Init list of loaded processor libraries */
LIST_INIT(proc_cache
, proc_type_t
);
* This function calls into the lexer to
* parse the config and state files.
char buffer
[8192]; /* big space */
* First step is to run the C pre-processor
* Output from the pre-processor, is piped
* directly into the lexer.
* This is complicated because the pre-processor also
* outputs errors, and may fail.
* Should probably do this properly with pipes etc.
* but for now, just use a temp file in /tmp
* for the sake of convenience.
for (count
= 0; count
< MAX_TRIES
; count
++) {
sprintf(tempfilep
, "/tmp/sim.cfg.%d.%02d", (int)getpid(), count
);
if (!file_exists(tempfilep
)) break;
if (count
== 5) fatal("Unable to create a temporary file for config pre-processing");
sprintf(buffer
, "%s" CPP_OPTIONS
" %s %s > %s",
options
.cpp_cmd
, options
.cpp_optionsp
,
options
.config_filep
, tempfilep
);
DBG( printf("system(%s)\n", buffer
); );
} while (res
== -1 && (errno
== EAGAIN
|| errno
== EINTR
));
if (res
== -1) fatal("Failed trying to pre-process config file %s\n", options
.config_filep
);
DBG( printf("Exit status %d\n", res
); );
fp
= fopen_check(tempfilep
, "r");
init_lexer(options
.config_filep
, fp
, tempfilep
);
parse_debug(); /* process any debug directives */
unlink(tempfilep
); /* clean up - remove temp file */
* Parse optional debug directive
if (tok
!= T_Token
|| !streq(lex
.strp
, "debug")) {
if (streq(lex
.strp
, "save_state"))
lex_fatal("Unexpected string in debug directive\n");
lex_fatal("Unexpected token in debug directive.\n");
if (streq(lex
.strp
, "filename")) {
options
.save_restore
.filenamep
= Xstrdup(lex
.strp
);
printf("debug:save_state:filename = %s\n",
options
.save_restore
.filenamep
);
if (streq(lex
.strp
, "format")) {
if (streq(lex
.strp
, "legion"))
options
.save_restore
.legion_format
= true;
else if (streq(lex
.strp
, "axis"))
options
.save_restore
.legion_format
= false;
lex_fatal("expected either legion or axis");
printf("debug:save_state:format = %s\n",
options
.save_restore
.legion_format
? "legion" : "axis");
if (streq(lex
.strp
, "icount")) {
options
.save_restore
.trigger_icount
= lex
.val
;
printf("debug:save_state:icount = 0x%llx\n",
options
.save_restore
.trigger_icount
);
if (streq(lex
.strp
, "trap_pc")) {
options
.save_restore
.trap_pc
= lex
.val
;
printf("debug:save_state:trap_pc = 0x%llx\n",
options
.save_restore
.trap_pc
);
if (streq(lex
.strp
, "patch")) {
lex_get(T_Number
); /* addr */
options
.save_restore
.mem_patch
.addr
= lex
.val
;
lex_get(T_Number
); /* val */
options
.save_restore
.mem_patch
.val
= lex
.val
;
printf("debug:save_state:patch addr=0x%llx with val=0x%llx\n",
options
.save_restore
.mem_patch
.addr
,
options
.save_restore
.mem_patch
.val
);
lex_fatal("Unexpected token in save_state directive.\n");
* Top level of parser ... look for one or more
LIST_INIT( target_config
.systems
, system_t
);
if (tok
!= T_Token
|| !streq(lex
.strp
, "system"))
lex_fatal("system definition expected");
idx
= target_config
.systems
.count
;
systemp
= LIST_ADD( target_config
.systems
, system_t
);
systemp
->namep
= Xstrdup(lex
.strp
);
parse_service_processor(systemp
); /* if any */
if (target_config
.systems
.count
== 0) lex_fatal("at least one system expected");
* Read one service_processor into the specified system, if it exists
void parse_service_processor(system_t
*systemp
)
config_dev_t
*config_devp
;
char symname
[BUFSIZ
], libname
[BUFSIZ
], mdlname
[BUFSIZ
];
dev_type_t
*dev_typep
= NULL
;
lex_fatal("unexpected EOF");
lex_fatal("service_processor specific token expected");
if (tok
!= T_Token
|| !streq(lex
.strp
, "service_processor")) {
/* No Service processor - we're done */
lex_get(T_String
); /* get the name of the service_proc */
sprintf(mdlname
, "%s", lex
.strp
);
sprintf(symname
, "dev_type_%s", mdlname
);
DBG( printf("parse_service_processor - parsed %s - looking for %s\n",
dev_typep
= (dev_type_t
*)dlopen_lib(mdlname
, symname
, libname
);
if (dev_typep
== (dev_type_t
*)0)
lex_fatal("unknown dev type \"%s\"", mdlname
);
systemp
->service_procp
= Xmalloc(sizeof (service_proc_t
));
/* parse service_processor */
dev_typep
->parse_dev(NULL
);
/* save pointer to the service_processor handle */
systemp
->service_procp
->dev_typep
= dev_typep
;
systemp
->service_procp
->namep
= Xstrdup(mdlname
);
/* Turn off fake SP flag */
systemp
->fake_sp
= false;
* Read one or more domains into the specified system
void parse_domains(system_t
*systemp
)
LIST_INIT(systemp
->domains
, domain_t
);
if (tok
== T_EOF
) lex_fatal("unexpected EOF");
if (tok
== T_R_Brace
) break;
if (tok
!= T_Token
|| !streq(lex
.strp
, "domain"))
lex_fatal("domain definition expected");
idx
= systemp
->domains
.count
;
domainp
= LIST_ADD( systemp
->domains
, domain_t
);
domainp
->systemp
= systemp
;
if (systemp
->domains
.count
== 0) lex_fatal("At least one domain expected for system \"%s\"", systemp
->namep
);
* OK, the more complicated function
* to determine and connect the different
* components of a domain.
void parse_domain(domain_t
*domainp
)
LIST_INIT( domainp
->procs
, config_proc_t
);
domainp
->device
.count
= 0;
domainp
->device
.listp
= (config_dev_t
*)0;
if (tok
== T_EOF
) lex_fatal("unexpected EOF within domain defn");
if (tok
== T_R_Brace
) break;
if (tok
!= T_Token
) goto fail
;
if (streq(lex
.strp
, "sysclkfreq")) {
domainp
->sysclkfreq
= parse_number_assign();
if (streq(lex
.strp
, "processor")) {
if (streq(lex
.strp
, "addressmap")) {
parse_addressmap(domainp
);
lex_fatal("domain specific token expected");
if (domainp
->sysclkfreq
== 0) lex_fatal("sysclkfreq not specified in domain definition");
/* processor specific domain check of stuff parsed from conf file */
LIST_ENTRY(domainp
->procs
, 0)->proc_typep
->domain_check(domainp
);
* Handle the proc "name" wrapper around a processor definition.
* This enables us to select the correct processor handler
* then call into that handler to complete the parsing
* of this specific processor.
void parse_proc(domain_t
*domainp
)
proc_type_t
* proc_typep
;
config_proc_t
* config_procp
;
lex_get(T_String
); /* get the name of the proc type */
proc_typep
= find_proc_type(lex
.strp
);
if (proc_typep
== (proc_type_t
*)0) lex_fatal("unknown processor type \"%s\"", lex
.strp
);
* If the processor type module has not been loaded and
* initialised .. do so now
if (!proc_typep
->flag_initialised
) {
if (!proc_typep
->init_module(proc_typep
)) fatal("Failed initialising processor module %s", proc_typep
->proc_type_namep
);
/* OK, allocate the proc entry */
config_procp
= LIST_ADD( domainp
->procs
, config_proc_t
);
config_procp
->proc_id
= domainp
->procs
.count
-1;
config_procp
->proc_typep
= proc_typep
;
config_procp
->domainp
= domainp
;
/* based on the proc type we call the proc-dependent parser */
proc_typep
->parse_proc(domainp
, config_procp
);
* This function (eventually) parses the address map
* for each domain. Basically, this creates the devices
* that are attached directly to the domain memory bus.
void parse_addressmap(domain_t
*domainp
)
/* for now - just swallow until the } */
if (tok
== T_EOF
) lex_fatal("unexpected end of file");
if (tok
== T_R_Brace
) break;
if (tok
!= T_Token
) lex_fatal("addressmap element expected");
if (streq(lex
.strp
, "device")) {
} else if (streq(lex
.strp
, "mmi_device")) {
parse_mmi_device(domainp
);
lex_fatal("unknown/unexpected token %s in addressmap", lex
.strp
);
} while (tok
!= T_EOF
&& tok
!= T_R_Brace
);
* having decided the address map entry is a device,
* parse its name, base, and extent, then drop into the
* device's own parsing routine.
void parse_device(domain_t
*domainp
)
config_dev_t
* config_devp
, *overlapp
;
config_addr_t
*config_addrp
;
* We've found a device name so check whether we have a library
dev_typep
= find_dev_type(lex
.strp
);
if (dev_typep
== (dev_type_t
*)0) lex_fatal("unknown dev type \"%s\"",lex
.strp
);
/* OK, allocate the proc entry */
config_devp
= Xmalloc(sizeof (config_dev_t
));
config_devp
->is_implied
= false; /* this is a real device */
config_devp
->dev_typep
= dev_typep
;
config_devp
->devp
= (void*)0; /* gets allocated in the dev parser */
config_devp
->addrp
= NULL
; /* see insert_domain_address() */
tpaddr_t baseaddr
, topaddr
;
if (tok
== T_Plus
) is_size
= true; else lex_unget();
lex_fatal("top address <= base address with device %s",
config_devp
->dev_typep
->dev_type_namep
);
insert_domain_address(domainp
, config_devp
, baseaddr
, topaddr
);
} while (lex_get_token() == T_Comma
);
/* Insert device into the domain */
overlapp
= insert_domain_device(domainp
, config_devp
);
lex_fatal("device \"%s\" @ 0x%llx overlaps with device \"%s\" @ 0x%llx",
overlapp
->dev_typep
->dev_type_namep
,
overlapp
->addrp
->baseaddr
,
config_devp
->dev_typep
->dev_type_namep
,
config_devp
->addrp
->baseaddr
);
/* based on the dev type we call the dev-dependent parser */
dev_typep
->parse_dev(config_devp
);
void parse_mmi_device(domain_t
*domainp
)
config_dev_t
* config_devp
, *overlapp
;
config_addr_t
*config_addrp
;
config_devp
= Xmalloc(sizeof (config_dev_t
));
* parse to get the MMI device name
lex_fatal("missing MMI device name in parse_mmi_device");
sam_init_device(lex
.strp
, config_devp
);
sam_parse_dev(domainp
, config_devp
);
* load MMI SAM device module
dev_typep
= sam_load_device(config_devp
);
if (dev_typep
== (dev_type_t
*)0) lex_fatal("unknown dev type \"%s\"",lex
.strp
);
* Found a matching library, add it to the loaded list.
* NOTE: We do not dlclose() the libarary here as we know it will be
* needed later on when the functions in the dev_typep are accessed.
LIST_ADD_PTR(dev_cache
, dev_type_t
, dev_typep
);
* Support functions for other parser codes
* Parse a number assignment:
uint64_t parse_number_assign()
* dlopen a lib["mdlnamep"].so in the plugins/ dir or in the
* options.libpath search path and locate the symbol "symname".
* If there is a pre-existing handle - use it.
* If the library was successfully opened, save the handle.
* Once a valid handle is avail, get the address of symname and return.
* Don't log error on failure to add to htable; non-fatal, only affects
#define MAX_DLENT 128 /* max dlentries cacheable */
char *so_path
; /* fq path to lib where symbol found */
void *so_addr
; /* shared object symbol address */
dlopen_lib(char *mdlnamep
, char *symname
, char *libname
)
static int first_pass
= 0;
void *dlh
= NULL
, *fptr
= NULL
;
(void) hcreate(MAX_DLENT
);
sprintf(hkey
, "%s%s", mdlnamep
, symname
);
DBG( printf("Looking for module [%s][%s]\n", mdlnamep
, symname
); );
if ((f_item
= hsearch(item
, FIND
)) != NULL
) {
/* found it, return info */
dip
= (dlitem_t
*)f_item
->data
;
strcpy(libname
, dip
->so_path
);
DBG( printf("Found [%s][%s] %p\n",
mdlnamep
, symname
, dip
->so_addr
); );
/* not found, try to open and add it on libpath */
for (idx
= 0; idx
< options
.libpath
.count
; idx
++) {
pathp
= LIST_ENTRY(options
.libpath
, idx
);
sprintf(libname
, "%s/lib%s.so", pathp
, mdlnamep
);
DBG( printf("Loading the [%s] module - %s\n", mdlnamep
, libname
); );
if (NULL
!= (dlh
= dlopen(libname
, RTLD_NOW
))) {
/* not found, try to open and add it on compiled in default paths */
sprintf(libname
, "lib%s.so", mdlnamep
);
DBG( printf("Loading the [%s] module - %s\n", mdlnamep
, libname
); );
if (NULL
== (dlh
= dlopen(libname
, RTLD_NOW
))) {
printf("\tdlopen_lib error opening [%s]\t%s\n",
/* Found a library in libpath that we can open */
DBG( printf("\tFound and opened [%s]\n", libname
); );
/* Extract and return the symbol address from the shared object */
if (NULL
== (fptr
= dlsym(dlh
, symname
))) {
printf("\tdlopen_lib: [%s]\n", dlerror());
/* do not add entry if no symbol found */
/* Have a valid lib,symbol - add to lookup table */
dip
= Xmalloc(sizeof (*dip
));
dip
->so_path
= Xstrdup(libname
);
dip
->so_addr
= (void *)fptr
;
item
.key
= Xstrdup(hkey
);
/* add item to lookup table */
if (NULL
== hsearch(item
, ENTER
)) {
free((void *)dip
->so_path
);
* Call dlopen_lib() to load the device module lib["devnamep"].so in
* the plugins/ dir. If a matching library is found:
* - use dlsym() to look for it's dev_type_t structure
* - check the dev_type_t name value matches the "devnamep"
* - add the matching library to the loaded list
* - return a pointer to the dev_type_t for this device
dev_type_t
* find_dev_type(char *devnamep
)
char symname
[BUFSIZ
], libname
[BUFSIZ
];
dev_type_t
*dev_typep
= NULL
;
return ((dev_type_t
*)0);
* First look through the cached list of device
* modules we've already opened.
for (idx
= 0; idx
< dev_cache
.count
; idx
++) {
dev_typep
= LIST_ENTRY(dev_cache
, idx
);
if (streq(dev_typep
->dev_type_namep
, devnamep
))
* Dlopen the device module library
sprintf(symname
, "dev_type_%s", devnamep
);
dev_typep
= (dev_type_t
*)dlopen_lib(devnamep
, symname
, libname
);
return ((dev_type_t
*)0);
* Make sure the name in the dev_type_name matches the device
if (!streq(dev_typep
->dev_type_namep
, devnamep
)) {
printf("\nERROR: name does not match. %s != %s in %s:%s\n",
dev_typep
->dev_type_namep
, devnamep
, libname
, symname
);
return ((dev_type_t
*)0);
* Found a matching library, add it to the loaded list.
* NOTE: We do not dlclose() the libarary here as we know it will be
* needed later on when the functions in the dev_typep are accessed.
LIST_ADD_PTR(dev_cache
, dev_type_t
, dev_typep
);
* Call dlopen_lib() to load the proc module lib["procnamep"].so in
* the plugins/ dir. If a matching library is found:
* - use dlsym() to look for it's proc_type_t structure
* - check the proc_type_t name value matches the "procnamep"
* - add the matching library to the loaded list
* - return a pointer to the proc_type_t for this proc
proc_type_t
* find_proc_type(char *procnamep
)
char symname
[BUFSIZ
], libname
[BUFSIZ
];
proc_type_t
*proc_typep
= NULL
;
return ((proc_type_t
*)0);
/* First look through the cached list of processor
* modules we've already opened.
for (idx
= 0; idx
< proc_cache
.count
; idx
++) {
proc_typep
= LIST_ENTRY(proc_cache
, idx
);
if (streq(proc_typep
->proc_type_namep
, procnamep
))
* Dlopen the proc module library
sprintf(symname
, "proc_type_%s", procnamep
);
proc_typep
= (proc_type_t
*)dlopen_lib(procnamep
, symname
, libname
);
return ((proc_type_t
*)0);
* Make sure the name in the proc_type_name matches the device
if (!streq(proc_typep
->proc_type_namep
, procnamep
)) {
printf("\nERROR: name does not match. %s != %s in %s:%s\n",
proc_typep
->proc_type_namep
, procnamep
, libname
, symname
);
return ((proc_type_t
*)0);
* Found a matching library, add it to the loaded list.
* NOTE: We do not dlclose() the libarary here as we know it will be
* needed later on when the functions in the proc_typep are accessed.
LIST_ADD_PTR(proc_cache
, proc_type_t
, proc_typep
);
* Insert a config device into the address map of a certain domain
* Returns NULL on success, the overlapping device node on failure.
insert_domain_device(domain_t
*domainp
, config_dev_t
*config_devp
)
config_devp
->domainp
= domainp
;
config_devp
->device_id
= domainp
->device
.count
;
ASSERT(config_devp
->addrp
->topaddr
> config_devp
->addrp
->baseaddr
);
ASSERT(config_devp
->addrp
->range
!= (tvaddr_t
)0);
/* insert into sorted list of devices ... */
for (pdp
= &(domainp
->device
.listp
); (dp
= *pdp
) != (config_dev_t
*)0; pdp
= &(dp
->nextp
)) {
if (dp
->addrp
->topaddr
<= config_devp
->addrp
->baseaddr
) continue;
if (dp
->addrp
->baseaddr
>= config_devp
->addrp
->topaddr
) break;
/* link device into list in order */
config_devp
->nextp
= *pdp
;
domainp
->device
.count
++;
DBG( printf("insert_domain_device %p name=<%s> base=%p, top=%p\n",
config_devp
, config_devp
->dev_typep
->dev_type_namep
,
config_devp
->addrp
->baseaddr
,
config_devp
->addrp
->topaddr
); );
* Insert a config address into the address map of a certain domain
* Returns NULL on success, the overlapping device node on failure.
insert_domain_address(domain_t
*domainp
, config_dev_t
*devp
, tpaddr_t baseaddr
, tpaddr_t topaddr
)
config_addr_t
**pap
, *ap
, *addrp
;
addrp
= Xmalloc(sizeof (config_addr_t
));
addrp
->config_devp
= devp
;
addrp
->baseaddr
= baseaddr
;
addrp
->topaddr
= topaddr
;
/* save us annoying adds and subs all the time */
addrp
->range
= topaddr
- baseaddr
;
/* insert into sorted list of addresses ... */
for (pap
= &(domainp
->address
.listp
); (ap
= *pap
) != NULL
;
if (ap
->topaddr
<= addrp
->baseaddr
) continue;
if (ap
->baseaddr
>= addrp
->topaddr
) break;
/* link device into list in order */
domainp
->address
.count
++;
DBG( printf("insert_domain_address devp=%p addrp=%p base=%llx, "
addrp
->config_devp
, addrp
, addrp
->baseaddr
,