Hello,
I have wanted a scheme to change switch settings at boot time so I
change the behavior of the Linux kernel and here is one solution I put
together.
This may be one way to simulate switch or jumper settings one may change
on a board before booting.
It uses a simple text file for input. The file name is pointed to by
-config <path to file> on the command line.
example:
config file:
[switches]
7:on
[jumpers]
Note: both [switches] and [jumpers] are required at the moment
to use:
qemu-system-arm -M mainstone -kernel /tftpboot/mainstone -pflash
~/mst_flashl1 -config ~/config.txt
this will enable the processor flash bank on the Mainstone and if I
change 7:on to 7:off , I get the main mother board flash.
feedback and comment are always welcome.
-Armin
Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c
+++ qemu/vl.c
@@ -232,6 +232,8 @@ const char *prom_envs[MAX_PROM_ENVS];
#endif
int nb_drives_opt;
char drives_opt[MAX_DRIVES][1024];
+int configed = 0;
+const char *qemu_config;
static CPUState *cur_cpu;
static CPUState *next_cpu;
@@ -1547,6 +1549,118 @@ static void quit_timers(void)
alarm_timer->stop(alarm_timer);
alarm_timer = NULL;
}
+/**********************************************************/
+/* config file */
+#define CONFIG_MAXLEN 256
+
+int switch_get_value(SwitchInterfaceType interface, int number)
+{
+ int index;
+
+ struct spdt_switch *sw = config_table[interface].sw;
+
+ for (index = 0; index < config_table[interface].nb_switches; index++){
+ if(sw[index].num == number)
+ return sw[index].value;
+ }
+ return -1;
+}
+
+static ssize_t config_rdline(FILE *fd, char *buf, size_t bufsz)
+{
+ int i, ch;
+ for(i = 0; i < bufsz && (ch=fgetc(fd)) != '\n' ; i++) {
+ if (ch == EOF) {
+ *buf = '\0';
+ return -1;
+ }
+ if(ch == '[') {
+ return -2;
+ }
+ *buf++ = ch;
+ }
+ *buf = '\0';
+ return i;
+}
+
+static int config_read_switches(FILE *fd, int index)
+{
+ int cnt = 0;
+ int size = 0;
+ char *tmp;
+ int sw_size = sizeof(struct spdt_switch);
+ struct spdt_switch *sw;
+
+ sw = (struct spdt_switch*) malloc(sw_size);
+ if(!sw) {
+ printf("config_read_switches - Malloc error!!");
+ return -ENOMEM;
+ }
+
+ config_table[index].sw = sw;
+ while(size != -1) {
+ char buf[CONFIG_MAXLEN];
+
+ size = config_rdline(fd, buf, CONFIG_MAXLEN);
+ if(size <= 0) {
+ break;
+ }
+
+ tmp = strchr(buf, ':');
+ sw[cnt].value = (strcmp(++tmp,"off")) ? 1 : 0 ;
+ sw[cnt].num = atoi(buf);
+ sw_size += sizeof(struct spdt_switch);
+ sw = (struct spdt_switch *) realloc(config_table[index].sw, sw_size );
+ if(!sw)
+ return -1;
+ cnt++;
+ };
+ return cnt;
+}
+
+static int config_file_read(char const *file)
+{
+ FILE *fd;
+ int index;
+
+ struct {
+ char *key;
+ SwitchInterfaceType interface;
+ } switch_keywords[]= {
+ {"switches", CFG_SPDT_SWITCH},
+ {"jumpers", CFG_JUMPERS_SWITCH}
+ };
+
+ fd = fopen(file,"r");
+ if(fd < 0) {
+ printf("Open error\n");
+ return -1;
+ }
+
+ for(index = 0; index < (sizeof(switch_keywords)/sizeof(switch_keywords[0]));
+ index++){
+
+ int ret;
+ char buf[CONFIG_MAXLEN];
+ ret = config_rdline(fd, buf, CONFIG_MAXLEN);
+ if(ret == -1) {
+ return -1;
+ }
+ if(ret == -2) {
+ ret = config_rdline(fd, buf, CONFIG_MAXLEN);
+ if(ret == -1) {
+ return -1;
+ }
+ }
+ if(strstr(buf, switch_keywords[index].key) != NULL) {
+ int cnt;
+ cnt = config_read_switches(fd,switch_keywords[index].interface);
+ config_table[index].nb_switches = cnt;
+ }
+ }
+ fclose(fd);
+ return 1;
+}
/***********************************************************/
/* character device */
@@ -7562,6 +7676,7 @@ static void help(int exitcode)
#endif
"-clock force the use of the given methods for timer alarm.\n"
" To see what timers are available use -clock help\n"
+ "-config file config file for kernel startup like switches and jumpers\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -7664,6 +7779,7 @@ enum {
QEMU_OPTION_old_param,
QEMU_OPTION_clock,
QEMU_OPTION_startdate,
+ QEMU_OPTION_config,
};
typedef struct QEMUOption {
@@ -7772,6 +7888,7 @@ const QEMUOption qemu_options[] = {
#endif
{ "clock", HAS_ARG, QEMU_OPTION_clock },
{ "startdate", HAS_ARG, QEMU_OPTION_startdate },
+ { "config", HAS_ARG, QEMU_OPTION_config },
{ NULL },
};
@@ -8603,6 +8720,15 @@ int main(int argc, char **argv)
}
}
break;
+
+ case QEMU_OPTION_config:
+ qemu_config = optarg;
+ configed = config_file_read(qemu_config);
+ if( configed == -1){
+ fprintf(stderr, "Invalid config file: %s\n",qemu_config);
+ exit(1);
+ }
+ break;
}
}
}
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h
+++ qemu/sysemu.h
@@ -180,7 +180,8 @@ void usb_info(void);
/* config */
typedef enum {
- CFG_SPDT_SWITCH, CFG_DIP_SWITCH
+ CFG_SPDT_SWITCH = 0,
+ CFG_JUMPERS_SWITCH
} SwitchInterfaceType;
struct spdt_switch{
@@ -191,11 +192,12 @@ struct spdt_switch{
typedef struct SwitchInfo {
SwitchInterfaceType interface;
struct spdt_switch *sw;
+ int nb_switches;
} SwitchInfo;
#define MAX_SWITCH_TYPES 2
SwitchInfo config_table[MAX_SWITCH_TYPES +1];
-extern int switch_get_index(SwitchInterfaceType interface, int number);
+extern int switch_get_value(SwitchInterfaceType interface, int number);
#endif