[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [CONFIGURATION METHOD] A proposal
From: |
Salvatore Lionetti |
Subject: |
[Qemu-devel] [CONFIGURATION METHOD] A proposal |
Date: |
Fri, 28 Nov 2008 00:55:22 +0000 (GMT) |
Hi,
i'm working a little on ppc405 emulation and.
Instead of
- overload method with many parameter,
- putting interface definition in the same implementation module,
- duplicate lot of code between similar board,
i've elaborated a first draft, compiled and working, of configuration
component: see the comment on the head of file.
Thanks for eventually feedback (information, comment, proposal)
1,528d0
< /* Configuration object
< * ====================
< *
< * Every object:
< * - is identified by a string (es '/walnut/cpu/mal/txeobisr')
< * - is tagged with a type (es 'INT' 'STRING' 'PTR' 'FILE' 'CALLBACK')
< * - have a value, which can be {set,get}ted.
< * Es "/walnut/cpu/mal/txeobisr INT 0"
< *
< * Collection of objects is readed from a char* variable,
< * so can be acquired both from configuration file and code.
< *
< * Every sw entity can intercept a value set over an object.
< * Co-relation take place in the context of set operation.
< *
< * As special case, sharing a pointer ex toward a variable,
< * no code change is required after registering it.
< *
< * Ascii representation has some constrain:
< * - start a line with a number of space equal to level number,
< * - every object name have to start with '/'.
< * - multivalue have to follow strictly this format: last/{a INT 0, b INT 1,
...}
< *
< * Some example:
< # Some comment
< /cpu
< # That can be inserted
< /emac
< # At any level
< /txeobisr INT 0
< /iic/eeprom/{address INT 0x56, image FILE pid.bin}
< /serial
< /serial0/{base PTR 0x300, intr INT 0}
< /serial1/{base PTR 0x400, intr INT 1, filename STRING "tcp:..."}
< *
< * Common interface or inheritance relation should be supported
< * Not in this release
< * Some example:
< *
< eeprom{address INT, image FILE}
<
< /cpu_meta
< /emac
< /txeobisr INT 0
< /iic/eeprom
<
< /cpu0(cpu_meta)
< /cpu1(cpu_meta)
< *
< * Configuration is totally dinamic so assertion about missing definition of
an object (es no value during get())
< * take place only when needed, like pure virtual function call in C++.
< */
<
< #include <assert.h>
< #define TEST
< #ifndef TEST
< #include "qemu-common.h"
< #include "hw.h"
< #else
< #define qemu_malloc malloc
< #include <string.h>
< #include <stdio.h>
< #include <fcntl.h>
< #include <malloc.h>
< #include <sys/mman.h>
< /* Configuration object is a 3-ple:
< * "/name/of/object", type, value
< * Every function return <0 on error.
< */
< enum hw_conf_basicT {
< HW_CONF_NOTYPE,
< HW_CONF_INT,
< HW_CONF_STRING,
< HW_CONF_PTR,
< HW_CONF_FUNC,
< };
< #define HW_CONF_GET(name, val) hw_conf_get(name, (void**)&val)
< #define HW_CONF_SET(name, val) hw_conf_set(name, (void*)val)
< /* 0 let change happen, 1 deny current change (a voting alg) */
< typedef int (HWConf_corelateFunc)(void *opaque, const char* name, void* newv);
<
< /* Return number of object successfully parsed. Value is only an opaque of
type void* */
< int hw_conf_parsefrom(const char* str, int sz);
< int hw_conf_get(const char* name, void** val);
< int hw_conf_set(const char* name, void* val);
< void hw_conf_corelatewith(const char* str, HWConf_corelateFunc f, void*
opaque);
< #endif
< struct hw_conf_corelateT {
< HWConf_corelateFunc* f;
< void* opaque;
< };
< struct hw_conf_nodeT {
< /* Three related */
< struct hw_conf_nodeT* nextH;
< struct hw_conf_nodeT* nextV;
< struct hw_conf_nodeT* prevV;
<
< char* id;
< /* Data contents */
< enum hw_conf_basicT type;
< void* opaque;
<
< /* Communique with the world */
< struct hw_conf_corelateT core[10];
< };
<
< static struct hw_conf_nodeT hw_conf_root;
< static int hw_conf_haveroot = 0;
<
< static void hw_conf_nodeinit(struct hw_conf_nodeT* n) {
< int l;
<
< assert(n);
< n->nextH = n->nextV = n->prevV = NULL;
< n->id = NULL;
< for (l=0; l<sizeof(n->core)/sizeof(n->core[0]); l++) {
< n->core[l].f = NULL;
< n->core[l].opaque = NULL;
< }
< }
<
< static void hw_conf_skipword(const char** s0, int n) {
< const char* s = *s0;
< while (*s && (s-*s0)<n) {
< /* Until a char [^0-9xa-zA-Z_'"'"] */
< if (!((*s>='0' && *s<='9') || (*s>='a' && *s<='z') || (*s>='A'
&& *s<='Z')/*|| *s=='\'' || *s=='\"'*/)) {
< break;
< }
< s++;
< }
< *s0 = s;
< }
<
< /* Return 0 => root */
< static int hw_conf_getLevel(struct hw_conf_nodeT* n) {
< int ret = 0;
< while (n->prevV != &hw_conf_root) {
< n = n->prevV;
< ret++;
< }
< return ret;
< }
< static struct hw_conf_nodeT* hw_conf_find(struct hw_conf_nodeT* n0, const
char** id, int create) {
< char haveMultiValue;
< struct hw_conf_nodeT* n, *nKm1;
< struct hw_conf_nodeT* ret = NULL;
< if (n0 == NULL || id == NULL || *id==NULL)
< return ret;
<
< (*id)++;
< if ((*id)[0]=='{')
< (*id)++;
< /* Root initialize */
< if (hw_conf_haveroot == 0) {
< hw_conf_nodeinit(&hw_conf_root);
< hw_conf_haveroot = 1;
< }
<
< haveMultiValue = 0;
< /* Down one level, then loop trow node */
< nKm1 = n = n0->nextV;
< while (n && !ret) {
< if (strstr(*id, n->id)) {
< *id+=strlen(n->id);
< switch (*id[0]) {
< case '/':
< ret = hw_conf_find(n, id, create);
< break;
< case '\x0':
< ret = n;
< break;
< default:
< break;
< }
< }
< nKm1 = n;
< n = n->nextH;
< }
< if (!ret && create) {
< struct hw_conf_nodeT* newn = (struct hw_conf_nodeT*)
qemu_malloc(sizeof(struct hw_conf_nodeT));
< const char* eon;
< int len;
<
< eon = *id;
< hw_conf_skipword(&eon, 255);
<
< len = eon-*id;
< hw_conf_nodeinit(newn);
< newn->id = qemu_malloc(len+1);
< memcpy(newn->id, *id, len);
< newn->id[len] = '\x0';
<
< /*
< * on new node:
< * nextH: NULL (we add to the tail)
< * nextV: NULL (no child when create)
< * prevV: n0 (always have a node of level-1)
< */
< newn->prevV = n0;
< if (n0->nextV) {
< /* Link to last in this level */
< assert(nKm1->nextH==NULL);
< nKm1->nextH = newn;
< } else {
< /* First item on this level */
< n0->nextV = newn;
< }
<
< *id=eon;
< ret = *eon!='/' ? newn : hw_conf_find(newn, id, create);
< }
< if (ret) {
< switch (ret->type) {
< case HW_CONF_INT:
< case HW_CONF_STRING:
< case HW_CONF_PTR:
< case HW_CONF_FUNC:
< case HW_CONF_NOTYPE:
< break;
< default:
< assert("Find a node with unmanaged type!");
< break;
< }
< }
< return ret;
< }
<
< char* hw_conf_getTypeDes(enum hw_conf_basicT t) {
< char* ret = NULL;
< switch (t) {
< case HW_CONF_INT: ret = "INT"; break;
< case HW_CONF_STRING: ret = "STRING"; break;
< case HW_CONF_PTR: ret = "PTR"; break;
< case HW_CONF_FUNC: ret = "FUNC"; break;
< case HW_CONF_NOTYPE: ret = "NOTYPE"; break;
< default: ret = "UNKTYPE"; break;
< }
< return ret;
< }
<
< enum hw_conf_basicT hw_conf_parseType(const char** s, int n) {
< enum hw_conf_basicT ret = HW_CONF_NOTYPE;
< if (s==NULL || *s==NULL || n==0)
< return ret;
<
< if (strncmp(*s, "INT ", n>4?4:n)==0) {
< (*s)+=4;
< ret = HW_CONF_INT;
< } else if (strncmp(*s, "STRING ", n>7?7:n)==0) {
< (*s)+=7;
< ret = HW_CONF_STRING;
< } else if (strncmp(*s, "PTR ", n>4?4:n)==0) {
< (*s)+=4;
< ret = HW_CONF_PTR;
< } else if (strncmp(*s, "FUNC ", n>5?5:n)==0) {
< (*s)+=5;
< ret = HW_CONF_FUNC;
< }
< return ret;
< }
< int hw_conf_parseValue(const char** s0, int n, enum hw_conf_basicT t, void**
o) {
< int ret=0;
< if (s0 && *s0 && n) {
< const char* s = *s0;
< switch (t) {
< case HW_CONF_INT:
< case HW_CONF_PTR:
< hw_conf_skipword(&s, n);
< if (sscanf(*s0, "0x%x", (int*)o)==1 ||
sscanf(*s0, "%d", (int*)o)==1)
< ret = 1;
< break;
< case HW_CONF_STRING:
< case HW_CONF_FUNC:
< {
< if (**s0=='\'' || **s0=='\"') {
< char* tmp;
< s++;
< while (n-(*s0-s)>0 && (*s!='\'' &&
*s!='\"')) {
< s++;
< }
< tmp = qemu_malloc(s-*s0);
< memcpy(tmp, *s0+1, s-*s0-1);
< tmp[s-*s0-1] = '\x0';
< *o = (void*) tmp;
<
< ret = 1;
< }
< break;
< }
< }
< if (ret==1) {
< *s0 = s;
< }
< }
< return ret;
< }
<
< /* Elaborate until eof | eos */
< int hw_conf_parsefrom(const char* name, int sz) {
< enum {HW_CONF_READING_LEVEL, HW_CONF_READING_NAME, HW_CONF_READED_NAME,
HW_CONF_READING_TYPE, HW_CONF_READING_VALUE, HW_CONF_READING_DONE} state;
< enum hw_conf_basicT t;
< void *o;
< char nlev, nlevKm1, comment;
< int nobj;
< const char* n = name;
< struct hw_conf_nodeT* node;
<
< printf("len %d\n", sz);
< state = HW_CONF_READING_LEVEL;
< t = HW_CONF_NOTYPE;
< nlev = nlevKm1 = comment = 0;
< nobj = 0;
< if (name==NULL)
< return nobj;
< if (sz == 0)
< sz = strlen(name);
< while ((n-name)<sz && *n) {
< if (comment==0 || *n==0xa) {
< switch (*n) {
< case ' ':
< if (state == HW_CONF_READED_NAME) {
< state = HW_CONF_READING_TYPE;
< }
< if (state == HW_CONF_READING_LEVEL) {
< nlev++;
< }
< break;
< case ',':
< /* Multi value line */
< if (state == HW_CONF_READING_DONE) {
< state = HW_CONF_READING_NAME;
< nlev--;
< node = node->prevV;
< n++; /* Skip ',' */
< } else {
< break;
< }
< case '/':
< if (state <= HW_CONF_READING_NAME) {
< if (nlev>nlevKm1) {
< assert((nlev - nlevKm1) == 1);
< }
< while (nlev && nlev<=nlevKm1) {
< node = node->prevV;
< nlevKm1--;
< }
< if (nlev == 0) {
< node = &hw_conf_root;
< }
< node = hw_conf_find(node, &n, 1);
< nlev = hw_conf_getLevel(node);
< state=HW_CONF_READED_NAME;
< n--;
< }
< break;
< case '}':
< nlev--;
< node = node->prevV;
< break;
< case 0xa:
< if (comment) {
< nlev = 0;
< }
< comment = 0;
< if (state != HW_CONF_READING_LEVEL) {
< state = HW_CONF_READING_LEVEL;
< nlevKm1 = nlev;
< nlev = 0;
< }
< break;
< case '#':
< comment = 1;
< break;
< default:
< switch (state) {
< case HW_CONF_READING_TYPE:
< if ((t = hw_conf_parseType(&n,
sz-(n-name)))!=HW_CONF_NOTYPE) {
< state =
HW_CONF_READING_VALUE;
< n--;
< }
< break;
< case HW_CONF_READING_VALUE:
< if (hw_conf_parseValue(&n,
sz-(n-name), t, &o)) {
< node->type = t;
< node->opaque = o;
< state =
HW_CONF_READING_DONE;
< nobj++;
< n--;
< }
< default:
< break;
< }
< break;
< } /* switch */
< } /* if */
< n++;
<
< }
< return nobj;
< }
< int hw_conf_get(const char* name, void** val) {
< struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< if (ret)
< *val = ret->opaque;
< return ret!=NULL;
< }
< int hw_conf_set(const char* name, void* val) {
< const char* orign = name;
< struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< if (ret) {
< /* Inform the world */
< int i, l;
< l = 0;
< for (i=0; i<sizeof(ret->core)/sizeof(ret->core[0]); i++)
< if (ret->core[i].f)
< l += ret->core[i].f(ret->core[i].opaque, orign,
val);
<
< if (l==0)
< ret->opaque = val;
< }
< return ret!=NULL;
< }
< void hw_conf_corelatewith(const char* name, HWConf_corelateFunc f, void*
opaque) {
< struct hw_conf_nodeT *ret = hw_conf_find(&hw_conf_root, &name, 0);
< if (ret) {
< int i;
< for (i=0; i<sizeof(ret->core)/sizeof(ret->core[0]); i++)
< if (ret->core[i].f==NULL && ret->core[i].opaque==NULL) {
< ret->core[i].f = f;
< ret->core[i].opaque = opaque;
< break;
< }
< if (i == sizeof(ret->core)/sizeof(ret->core[0])) {
< assert("Not enough space for store corelation
information!");
< }
< } else {
< assert("Corelation with non existent object");
< }
< }
< /* scende & stampa con nextV
< * sale con prevV e segue nextH
< * sale con prevV
< * fino ad n0
< */
< int hw_conf_printfrom(struct hw_conf_nodeT* n0) {
< struct hw_conf_nodeT *n;
< int nlev, nlevKm1, lastWasUp;
< int nobj = 0;
< if (n0==NULL || n0->nextV==NULL)
< return nobj;
< n = n0->nextV;
< nlev = lastWasUp = 0;
< while (n != n0) {
< if (!lastWasUp) {
< int i;
< for (i=0; i<nlev; i++)
< printf(" ");
< printf("/%s", n->id);
< if (n->type!=HW_CONF_NOTYPE) {
< printf(" %s ", hw_conf_getTypeDes(n->type));
< if (n->type == HW_CONF_STRING) {
< printf("'%s'", (char*) n->opaque);
< } else {
< printf("0x%x", n->opaque);
< }
< }
< printf("\n");
< }
< if (n->nextV && !lastWasUp) {
< nlev++;
< n = n->nextV;
< /* Are on leaf: 1) Try same level, then go up */
< } else {
< if (n->nextH) {
< n = n->nextH;
< lastWasUp = 0;
< } else {
< nlev--;
< n = n->prevV;
< lastWasUp = 1;
< }
< }
< }
< return nobj;
< }
<
< char* open_mmap(char* fn, int* len) {
< int fd;
< char* ret = NULL;
< fd = open(fn, O_RDONLY);
< if (fd>0) {
< *len = lseek(fd, 0, SEEK_END);
< printf("File lungo %d bytes\n", *len);
< ret=mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0);
< if (ret==MAP_FAILED)
< ret = NULL;
< }
< return ret;
< }
< #ifdef TEST
< int core(void *opaque, const char* name, void* newv) {
< printf("Co-relation(this=0x%x) %s now %x\n", opaque, name, newv);
< return 0;
< }
< int main(int argc, char* argv[]) {
< char tmp[256];
< char* tmp1=NULL;
< int len;
< void* serial_base;
< char* info = "\
< /cpu\n\
< /serial\n\
< /base PTR 0x500\n\
< /intr STRING '0'\n\
< /emac/txeobisr INT 0\n\
< /iic/eeprom\n\
< /address INT 0x56\n\
< /image STRING 'pid.bin'";
< len = 0;
< tmp1 = open_mmap("hw_conf.txt", &len);
< printf("parse = %d\n", hw_conf_parsefrom(tmp1, len));
< hw_conf_printfrom(&hw_conf_root);
< hw_conf_get("/cpu/serial/base", &serial_base);
< printf("get serial_base 0x%x\n", serial_base);
< hw_conf_corelatewith("/cpu/serial/base", core, (void*)4);
< serial_base++;
< hw_conf_set("/cpu/serial/base", serial_base);
< serial_base=0;
< hw_conf_get("/cpu/serial/base", &serial_base);
< printf("get serial_base 0x%x\n", serial_base);
< }
< #endif
- [Qemu-devel] [CONFIGURATION METHOD] A proposal,
Salvatore Lionetti <=