2 * RouterBOOT configuration utility
4 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
5 * Copyright (C) 2017 Thibaut VARENE <varenet@parisc-linux.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
21 #include <linux/limits.h>
26 #define RBCFG_TMP_FILE "/tmp/.rbcfg"
27 #define RBCFG_MTD_NAME "soft_config"
29 #define RB_ERR_NOTFOUND 1
30 #define RB_ERR_INVALID 2
31 #define RB_ERR_NOMEM 3
33 #define RB_ERR_NOTWANTED 5
35 #define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
53 #define RBCFG_ENV_TYPE_U32 0
59 const struct rbcfg_value
*values
;
63 #define CMD_FLAG_USES_CFG 0x01
65 struct rbcfg_command
{
69 int (*exec
)(int argc
, const char *argv
[]);
77 static void usage(void);
81 static struct rbcfg_ctx
*rbcfg_ctx
;
82 static char *rbcfg_name
;
84 #define CFG_U32(_name, _desc, _val) { \
90 static const struct rbcfg_value rbcfg_boot_delay
[] = {
91 CFG_U32("1", "1 second", RB_BOOT_DELAY_1SEC
),
92 CFG_U32("2", "2 seconds", RB_BOOT_DELAY_2SEC
),
93 CFG_U32("3", "3 seconds", RB_BOOT_DELAY_3SEC
),
94 CFG_U32("4", "4 seconds", RB_BOOT_DELAY_4SEC
),
95 CFG_U32("5", "5 seconds", RB_BOOT_DELAY_5SEC
),
96 CFG_U32("6", "6 seconds", RB_BOOT_DELAY_6SEC
),
97 CFG_U32("7", "7 seconds", RB_BOOT_DELAY_7SEC
),
98 CFG_U32("8", "8 seconds", RB_BOOT_DELAY_8SEC
),
99 CFG_U32("9", "9 seconds", RB_BOOT_DELAY_9SEC
),
102 static const struct rbcfg_value rbcfg_boot_device
[] = {
103 CFG_U32("eth", "boot over Ethernet",
104 RB_BOOT_DEVICE_ETHER
),
105 CFG_U32("nandeth", "boot from NAND, if fail then Ethernet",
106 RB_BOOT_DEVICE_NANDETH
),
107 CFG_U32("ethnand", "boot Ethernet once, then NAND",
108 RB_BOOT_DEVICE_ETHONCE
),
109 CFG_U32("nand", "boot from NAND only",
110 RB_BOOT_DEVICE_NANDONLY
),
111 CFG_U32("flash", "boot in flash configuration mode",
112 RB_BOOT_DEVICE_FLASHCFG
),
113 CFG_U32("flashnand", "boot in flash configuration mode once, then NAND",
114 RB_BOOT_DEVICE_FLSHONCE
),
117 static const struct rbcfg_value rbcfg_boot_key
[] = {
118 CFG_U32("any", "any key", RB_BOOT_KEY_ANY
),
119 CFG_U32("del", "<Delete> key only", RB_BOOT_KEY_DEL
),
122 static const struct rbcfg_value rbcfg_boot_protocol
[] = {
123 CFG_U32("bootp", "BOOTP protocol", RB_BOOT_PROTOCOL_BOOTP
),
124 CFG_U32("dhcp", "DHCP protocol", RB_BOOT_PROTOCOL_DHCP
),
127 static const struct rbcfg_value rbcfg_uart_speed
[] = {
128 CFG_U32("115200", "", RB_UART_SPEED_115200
),
129 CFG_U32("57600", "", RB_UART_SPEED_57600
),
130 CFG_U32("38400", "", RB_UART_SPEED_38400
),
131 CFG_U32("19200", "", RB_UART_SPEED_19200
),
132 CFG_U32("9600", "", RB_UART_SPEED_9600
),
133 CFG_U32("4800", "", RB_UART_SPEED_4800
),
134 CFG_U32("2400", "", RB_UART_SPEED_2400
),
135 CFG_U32("1200", "", RB_UART_SPEED_1200
),
136 CFG_U32("off", "disable console output", RB_UART_SPEED_OFF
),
139 static const struct rbcfg_value rbcfg_cpu_mode
[] = {
140 CFG_U32("powersave", "power save", RB_CPU_MODE_POWERSAVE
),
141 CFG_U32("regular", "regular (better for -0c environment)",
142 RB_CPU_MODE_REGULAR
),
145 static const struct rbcfg_value rbcfg_cpu_freq_dummy
[] = {
148 static const struct rbcfg_value rbcfg_cpu_freq_qca953x
[] = {
149 CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2
),
150 CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1
),
151 CFG_U32("0", "Factory", RB_CPU_FREQ_N0
),
152 CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1
),
153 CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2
),
156 static const struct rbcfg_value rbcfg_cpu_freq_ar9344
[] = {
157 CFG_U32("-2", "-100MHz", RB_CPU_FREQ_L2
),
158 CFG_U32("-1", "- 50MHz", RB_CPU_FREQ_L1
),
159 CFG_U32("0", "Factory", RB_CPU_FREQ_N0
),
160 CFG_U32("+1", "+ 50MHz", RB_CPU_FREQ_H1
),
161 CFG_U32("+2", "+100MHz", RB_CPU_FREQ_H2
),
162 CFG_U32("+3", "+150MHz", RB_CPU_FREQ_H3
),
165 static const struct rbcfg_value rbcfg_booter
[] = {
166 CFG_U32("regular", "load regular booter", RB_BOOTER_REGULAR
),
167 CFG_U32("backup", "force backup-booter loading", RB_BOOTER_BACKUP
),
170 static struct rbcfg_env rbcfg_envs
[] = {
172 .name
= "boot_delay",
173 .id
= RB_ID_BOOT_DELAY
,
174 .type
= RBCFG_ENV_TYPE_U32
,
175 .values
= rbcfg_boot_delay
,
176 .num_values
= ARRAY_SIZE(rbcfg_boot_delay
),
178 .name
= "boot_device",
179 .id
= RB_ID_BOOT_DEVICE
,
180 .type
= RBCFG_ENV_TYPE_U32
,
181 .values
= rbcfg_boot_device
,
182 .num_values
= ARRAY_SIZE(rbcfg_boot_device
),
185 .id
= RB_ID_BOOT_KEY
,
186 .type
= RBCFG_ENV_TYPE_U32
,
187 .values
= rbcfg_boot_key
,
188 .num_values
= ARRAY_SIZE(rbcfg_boot_key
),
190 .name
= "boot_protocol",
191 .id
= RB_ID_BOOT_PROTOCOL
,
192 .type
= RBCFG_ENV_TYPE_U32
,
193 .values
= rbcfg_boot_protocol
,
194 .num_values
= ARRAY_SIZE(rbcfg_boot_protocol
),
198 .type
= RBCFG_ENV_TYPE_U32
,
199 .values
= rbcfg_booter
,
200 .num_values
= ARRAY_SIZE(rbcfg_booter
),
203 .id
= RB_ID_CPU_MODE
,
204 .type
= RBCFG_ENV_TYPE_U32
,
205 .values
= rbcfg_cpu_mode
,
206 .num_values
= ARRAY_SIZE(rbcfg_cpu_mode
),
209 .id
= RB_ID_CPU_FREQ
,
210 .type
= RBCFG_ENV_TYPE_U32
,
211 .values
= rbcfg_cpu_freq_dummy
,
212 .num_values
= ARRAY_SIZE(rbcfg_cpu_freq_dummy
),
214 .name
= "uart_speed",
215 .id
= RB_ID_UART_SPEED
,
216 .type
= RBCFG_ENV_TYPE_U32
,
217 .values
= rbcfg_uart_speed
,
218 .num_values
= ARRAY_SIZE(rbcfg_uart_speed
),
222 static inline uint16_t
223 get_u16(const void *buf
)
225 const uint8_t *p
= buf
;
227 return ((uint16_t) p
[1] + ((uint16_t) p
[0] << 8));
230 static inline uint32_t
231 get_u32(const void *buf
)
233 const uint8_t *p
= buf
;
235 return ((uint32_t) p
[3] + ((uint32_t) p
[2] << 8) +
236 ((uint32_t) p
[1] << 16) + ((uint32_t) p
[0] << 24));
240 put_u32(void *buf
, uint32_t val
)
245 p
[2] = (val
>> 8) & 0xff;
246 p
[1] = (val
>> 16) & 0xff;
247 p
[0] = (val
>> 24) & 0xff;
251 rbcfg_find_tag(struct rbcfg_ctx
*ctx
, uint16_t tag_id
, uint16_t *tag_len
,
256 char *buf
= ctx
->buf
;
257 unsigned int buflen
= ctx
->buflen
;
258 int ret
= RB_ERR_NOTFOUND
;
260 /* skip magic and CRC value */
276 if (id
== RB_ID_TERMINATOR
) {
277 ret
= RB_ERR_NOTWANTED
;
295 if (RB_ERR_NOTFOUND
== ret
)
296 fprintf(stderr
, "no tag found with id=%u\n", tag_id
);
302 rbcfg_get_u32(struct rbcfg_ctx
*ctx
, uint16_t id
, uint32_t *val
)
308 err
= rbcfg_find_tag(ctx
, id
, &tag_len
, &tag_data
);
312 *val
= get_u32(tag_data
);
317 rbcfg_set_u32(struct rbcfg_ctx
*ctx
, uint16_t id
, uint32_t val
)
323 err
= rbcfg_find_tag(ctx
, id
, &tag_len
, &tag_data
);
327 put_u32(tag_data
, val
);
331 char *rbcfg_find_mtd(const char *name
, int *erase_size
)
340 f
= fopen("/proc/mtd", "r");
346 p
= fgets(dev
, sizeof(dev
), f
);
350 if (!strstr(dev
, name
))
353 err
= sscanf(dev
, "mtd%d: %08x", &mtd_num
, erase_size
);
357 sprintf(dev
, "/dev/mtdblock%d", mtd_num
);
362 if ((s
.st_mode
& S_IFBLK
) == 0)
365 ret
= malloc(strlen(dev
) + 1);
369 strncpy(ret
, dev
, strlen(dev
) + 1);
378 rbcfg_check_tmp(struct rbcfg_ctx
*ctx
)
383 err
= stat(ctx
->tmp_file
, &s
);
387 if ((s
.st_mode
& S_IFREG
) == 0)
390 if (s
.st_size
!= ctx
->buflen
)
397 rbcfg_load(struct rbcfg_ctx
*ctx
)
400 uint32_t crc_orig
, crc
;
406 tmp
= rbcfg_check_tmp(ctx
);
407 name
= (tmp
) ? ctx
->tmp_file
: ctx
->mtd_device
;
409 fd
= open(name
, O_RDONLY
);
411 fprintf(stderr
, "unable to open %s\n", name
);
416 err
= read(fd
, ctx
->buf
, ctx
->buflen
);
417 if (err
!= ctx
->buflen
) {
418 fprintf(stderr
, "unable to read from %s\n", name
);
423 magic
= get_u32(ctx
->buf
);
424 if (magic
!= RB_MAGIC_SOFT
) {
425 fprintf(stderr
, "invalid configuration\n");
426 err
= RB_ERR_INVALID
;
430 crc_orig
= get_u32(ctx
->buf
+ 4);
431 put_u32(ctx
->buf
+ 4, 0);
432 crc
= cyg_ether_crc32((unsigned char *) ctx
->buf
, ctx
->buflen
);
433 if (crc
!= crc_orig
) {
434 fprintf(stderr
, "configuration has CRC error\n");
435 err
= RB_ERR_INVALID
;
451 struct rbcfg_ctx
*ctx
;
455 mtd_device
= rbcfg_find_mtd(RBCFG_MTD_NAME
, &buflen
);
457 fprintf(stderr
, "unable to find configuration\n");
458 return RB_ERR_NOTFOUND
;
461 ctx
= malloc(sizeof(struct rbcfg_ctx
) + buflen
);
467 ctx
->mtd_device
= mtd_device
;
468 ctx
->tmp_file
= RBCFG_TMP_FILE
;
469 ctx
->buflen
= buflen
;
470 ctx
->buf
= (char *) &ctx
[1];
472 err
= rbcfg_load(ctx
);
487 rbcfg_update(int tmp
)
489 struct rbcfg_ctx
*ctx
= rbcfg_ctx
;
495 put_u32(ctx
->buf
, RB_MAGIC_SOFT
);
496 put_u32(ctx
->buf
+ 4, 0);
497 crc
= cyg_ether_crc32((unsigned char *) ctx
->buf
, ctx
->buflen
);
498 put_u32(ctx
->buf
+ 4, crc
);
500 name
= (tmp
) ? ctx
->tmp_file
: ctx
->mtd_device
;
501 fd
= open(name
, O_WRONLY
| O_CREAT
);
503 fprintf(stderr
, "unable to open %s for writing\n", name
);
508 err
= write(fd
, ctx
->buf
, ctx
->buflen
);
509 if (err
!= ctx
->buflen
) {
526 struct rbcfg_ctx
*ctx
;
529 free(ctx
->mtd_device
);
533 static const struct rbcfg_value
*
534 rbcfg_env_find(const struct rbcfg_env
*env
, const char *name
)
538 for (i
= 0; i
< env
->num_values
; i
++) {
539 const struct rbcfg_value
*v
= &env
->values
[i
];
541 if (strcmp(v
->name
, name
) == 0)
548 static const struct rbcfg_value
*
549 rbcfg_env_find_u32(const struct rbcfg_env
*env
, uint32_t val
)
553 for (i
= 0; i
< env
->num_values
; i
++) {
554 const struct rbcfg_value
*v
= &env
->values
[i
];
556 if (v
->val
.u32
== val
)
564 rbcfg_env_get_u32(const struct rbcfg_env
*env
)
566 const struct rbcfg_value
*v
;
570 err
= rbcfg_get_u32(rbcfg_ctx
, env
->id
, &val
);
574 v
= rbcfg_env_find_u32(env
, val
);
576 fprintf(stderr
, "unknown value %08x found for %s\n",
585 rbcfg_env_set_u32(const struct rbcfg_env
*env
, const char *data
)
587 const struct rbcfg_value
*v
;
590 v
= rbcfg_env_find(env
, data
);
592 fprintf(stderr
, "invalid value '%s'\n", data
);
593 return RB_ERR_INVALID
;
596 err
= rbcfg_set_u32(rbcfg_ctx
, env
->id
, v
->val
.u32
);
601 rbcfg_env_get(const struct rbcfg_env
*env
)
603 const char *ret
= NULL
;
606 case RBCFG_ENV_TYPE_U32
:
607 ret
= rbcfg_env_get_u32(env
);
615 rbcfg_env_set(const struct rbcfg_env
*env
, const char *data
)
620 case RBCFG_ENV_TYPE_U32
:
621 ret
= rbcfg_env_set_u32(env
, data
);
629 rbcfg_cmd_apply(int argc
, const char *argv
[])
631 return rbcfg_update(0);
635 rbcfg_cmd_help(int argc
, const char *argv
[])
642 rbcfg_cmd_get(int argc
, const char *argv
[])
644 int err
= RB_ERR_NOTFOUND
;
649 return RB_ERR_INVALID
;
652 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
653 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
656 if (strcmp(env
->name
, argv
[0]))
659 value
= rbcfg_env_get(env
);
661 fprintf(stdout
, "%s\n", value
);
671 rbcfg_cmd_set(int argc
, const char *argv
[])
673 int err
= RB_ERR_INVALID
;
677 /* not enough parameters */
679 return RB_ERR_INVALID
;
682 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
683 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
685 if (strcmp(env
->name
, argv
[0]))
688 err
= rbcfg_env_set(env
, argv
[1]);
690 err
= rbcfg_update(1);
698 rbcfg_cmd_show(int argc
, const char *argv
[])
704 return RB_ERR_INVALID
;
707 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
708 const struct rbcfg_env
*env
= &rbcfg_envs
[i
];
711 value
= rbcfg_env_get(env
);
713 fprintf(stdout
, "%s=%s\n", env
->name
, value
);
719 static const struct rbcfg_command rbcfg_commands
[] = {
723 "\t- write configuration to the mtd device",
724 .flags
= CMD_FLAG_USES_CFG
,
725 .exec
= rbcfg_cmd_apply
,
729 "\t- show this screen",
730 .exec
= rbcfg_cmd_help
,
733 .usage
= "get <name>\n"
734 "\t- get value of the configuration option <name>",
735 .flags
= CMD_FLAG_USES_CFG
,
736 .exec
= rbcfg_cmd_get
,
739 .usage
= "set <name> <value>\n"
740 "\t- set value of the configuration option <name> to <value>",
741 .flags
= CMD_FLAG_USES_CFG
,
742 .exec
= rbcfg_cmd_set
,
746 "\t- show value of all configuration options",
747 .flags
= CMD_FLAG_USES_CFG
,
748 .exec
= rbcfg_cmd_show
,
759 fprintf(stderr
, "Usage: %s <command>\n", rbcfg_name
);
761 fprintf(stderr
, "\nCommands:\n");
762 for (i
= 0; i
< ARRAY_SIZE(rbcfg_commands
); i
++) {
763 const struct rbcfg_command
*cmd
;
764 cmd
= &rbcfg_commands
[i
];
766 len
= snprintf(buf
, sizeof(buf
), "%s", cmd
->usage
);
768 fprintf(stderr
, "%s\n", buf
);
771 fprintf(stderr
, "\nConfiguration options:\n");
772 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
773 const struct rbcfg_env
*env
;
776 env
= &rbcfg_envs
[i
];
777 fprintf(stderr
, "\n%s:\n", env
->name
);
778 for (j
= 0; j
< env
->num_values
; j
++) {
779 const struct rbcfg_value
*v
= &env
->values
[j
];
780 fprintf(stderr
, "\t%-12s %s\n", v
->name
, v
->desc
);
783 fprintf(stderr
, "\n");
786 #define RBCFG_SOC_UNKNOWN 0
787 #define RBCFG_SOC_QCA953X 1
788 #define RBCFG_SOC_AR9344 2
790 static const struct rbcfg_soc rbcfg_socs
[] = {
793 .type
= RBCFG_SOC_QCA953X
,
796 .type
= RBCFG_SOC_AR9344
,
800 #define CPUINFO_BUFSIZE 128 /* lines of interest are < 80 chars */
802 static int cpuinfo_find_soc(void)
805 char temp
[CPUINFO_BUFSIZE
];
806 char *haystack
, *needle
;
807 int i
, found
= 0, soc_type
= RBCFG_SOC_UNKNOWN
;
809 fp
= fopen("/proc/cpuinfo", "r");
813 /* first, extract the system type line */
814 needle
= "system type";
815 while(fgets(temp
, CPUINFO_BUFSIZE
, fp
)) {
816 if (!strncmp(temp
, needle
, strlen(needle
))) {
824 /* failsafe in case cpuinfo format changes */
828 /* skip the field header */
829 haystack
= strchr(temp
, ':');
831 /* then, try to identify known SoC, stop at first match */
832 for (i
= 0; i
< ARRAY_SIZE(rbcfg_socs
); i
++) {
833 if ((strstr(haystack
, rbcfg_socs
[i
].needle
))) {
834 soc_type
= rbcfg_socs
[i
].type
;
843 static void fixup_rbcfg_envs(void)
845 int i
, num_val
, soc_type
;
846 const struct rbcfg_value
* env_value
;
849 soc_type
= cpuinfo_find_soc();
851 /* update rbcfg_envs */
853 case RBCFG_SOC_QCA953X
:
854 env_value
= rbcfg_cpu_freq_qca953x
;
855 num_val
= ARRAY_SIZE(rbcfg_cpu_freq_qca953x
);
857 case RBCFG_SOC_AR9344
:
858 env_value
= rbcfg_cpu_freq_ar9344
;
859 num_val
= ARRAY_SIZE(rbcfg_cpu_freq_ar9344
);
863 for (i
= 0; i
< ARRAY_SIZE(rbcfg_envs
); i
++) {
864 if (RB_ID_CPU_FREQ
== rbcfg_envs
[i
].id
) {
865 if (RBCFG_SOC_UNKNOWN
== soc_type
)
866 rbcfg_envs
[i
].id
= RB_ID_TERMINATOR
;
868 rbcfg_envs
[i
].values
= env_value
;
869 rbcfg_envs
[i
].num_values
= num_val
;
876 int main(int argc
, const char *argv
[])
878 const struct rbcfg_command
*cmd
= NULL
;
882 rbcfg_name
= (char *) argv
[0];
891 for (i
= 0; i
< ARRAY_SIZE(rbcfg_commands
); i
++) {
892 if (strcmp(rbcfg_commands
[i
].command
, argv
[1]) == 0) {
893 cmd
= &rbcfg_commands
[i
];
899 fprintf(stderr
, "unknown command '%s'\n", argv
[1]);
907 if (cmd
->flags
& CMD_FLAG_USES_CFG
) {
913 ret
= cmd
->exec(argc
, argv
);
915 if (cmd
->flags
& CMD_FLAG_USES_CFG
)