|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // LUNA NVRAM.DAT エディタ
9: //
10:
11: #include "header.h"
12: #include "mystring.h"
13: #include <cstdio>
14: #include <string>
15: #include <vector>
16: #include <err.h>
17: #include <fcntl.h>
18: #include <unistd.h>
19: #include <sys/mman.h>
20: #include <sys/stat.h>
21:
22: using updatefunc = bool (*)(const std::string&, const std::string&);
23:
24: [[noreturn]] static void usage();
25: static void show();
26: static void edit(int ac, char *av[]);
27: static bool update_luna1(const std::string&, const std::string&);
28: static bool update_luna88k(const std::string&, const std::string&);
29: static std::string read_string(uint32 addr);
30: static void write_string(uint32 addr, const std::string&);
31: static uint32 find_string(const std::string&);
32: static uint8 calc_checksum();
33: static bool verify_checksum();
34:
35: static int debug;
36: static bool opt_force;
37: static bool opt_showaddr;
38: static uint8 *nvram;
39:
40: #define DPRINTF(fmt...) do { \
41: if (debug) { \
42: printf("%s: ", __func__); \
43: printf(fmt); \
44: } \
45: } while (0)
46:
47: int
48: main(int ac, char *av[])
49: {
50: const char *filename;
51: struct stat st;
52: int c;
53: int fd;
54: int mode;
55: int prot;
56: size_t maplen;
57:
58: while ((c = getopt(ac, av, "dfnh")) != -1) {
59: switch (c) {
60: case 'd':
61: debug++;
62: break;
63: case 'f':
64: opt_force = true;
65: break;
66: case 'n':
67: opt_showaddr = true;
68: break;
69: case 'h':
70: default:
71: usage();
72: break;
73: }
74: }
75: ac -= optind;
76: av += optind;
77:
78: if (ac == 0) {
79: usage();
80: }
81:
82: filename = av[0];
83: ac--;
84: av++;
85:
86: if (ac == 0) {
87: // show
88: mode = O_RDONLY;
89: prot = PROT_READ;
90: } else {
91: // edit
92: mode = O_RDWR;
93: prot = PROT_READ | PROT_WRITE;
94: }
95:
96: fd = open(filename, mode);
97: if (fd < 0) {
98: err(1, "%s: open", filename);
99: }
100:
101: if (fstat(fd, &st) < 0) {
102: err(1, "%s: fstat", filename);
103: }
104:
1.1.1.3 ! root 105: maplen = 2048;
! 106: if (st.st_size == 2040) {
! 107: warnx("%s: Old filesize (2040 bytes). Current size is %zu bytes.\n",
! 108: filename, maplen);
! 109: } else if (st.st_size < maplen) {
1.1 root 110: errx(1, "%s: File too short. Correct size is %zu bytes.\n",
111: filename, maplen);
112: } else if (st.st_size > maplen) {
113: warnx("%s: File too large. Correct size is %zu bytes. "
114: "(Ignore the extra space)", filename, maplen);
115: }
116:
117: int flag = MAP_FILE | MAP_SHARED;
118: void *m = mmap(NULL, maplen, prot, flag, fd, 0);
119: if (m == MAP_FAILED) {
120: err(1, "%s: mmap", filename);
121: }
122: nvram = (uint8 *)m;
123:
124: if (ac == 0) {
125: show();
126: } else {
127: edit(ac, av);
128: }
129:
130: munmap(m, maplen);
131: close(fd);
132: return 0;
133: }
134:
135: static void
136: usage()
137: {
138: fprintf(stderr,
139: "usage: %s [<options>] <NVRAM.DAT> .. show all\n",
140: getprogname());
141: fprintf(stderr,
142: " %s [<options>] <NVRAM.DAT> <key=value> .. set\n",
143: getprogname());
144: fprintf(stderr,
145: " -d : debug\n"
146: " -f : force to show/set even if nvram is broken\n"
147: " -n : show address\n"
148: );
149: exit(1);
150: }
151:
152: // 表示する
153: static void
154: show()
155: {
156: if (verify_checksum() == false && opt_force == false) {
157: printf("Broken NVRAM. Specify -f to force\n");
158: return;
159: }
160:
161: // LUNA-I の 0x560 には ENADDR があるけど、
162: // チェックサムの範囲外だしどういう扱いなんだべ。
163: uint32 end = 0x560;
164: if (strcmp((const char *)&nvram[0x560], "ENADDR") == 0) {
165: end = 0x580;
166: }
167:
168: for (uint32 addr = 0x20; addr < end; addr += 0x20) {
169: if (nvram[addr] == '\0') {
170: continue;
171: }
172:
173: std::string key = read_string(addr);
174: std::string val = read_string(addr + 16);
175:
176: if (opt_showaddr) {
177: printf("0x%04x: ", addr);
178: }
179: printf("%-16s = %s\n", key.c_str(), val.c_str());
180: }
181: }
182:
183: static void
184: edit(int ac, char *av[])
185: {
186: if (verify_checksum() == false && opt_force == false) {
187: printf("Broken NVRAM. Specify -f to force\n");
188: return;
189: }
190:
191: // 機種によってたぶんフィールドの扱いが違う気がする。
1.1.1.2 root 192: // LUNA-I か LUNA-88K か厳密には区別できない気がするけど、とりあえず
1.1 root 193: // 自由フィールドっぽい 0x560 までより後ろに "ENADDR" があれば
194: // LUNA-I ということにしてみる。LUNA-II と LUNA-88K2 は未調査。
195: updatefunc updater;
196: if (strcmp((const char *)&nvram[0x560], "ENADDR") == 0) {
197: updater = update_luna1;
198: } else {
199: updater = update_luna88k;
200: }
201:
202: int updated = 0;
203: for (int i = 0; i < ac; i++) {
204: const char *s;
205: const char *e;
206:
207: s = av[i];
208: e = strchr(s, '=');
209: if (e == NULL) {
210: warnx("%s: syntax error", av[i]);
211: return;
212: }
213:
214: std::string key(s, (e - s));
215: std::string val(e + 1);
216:
217: if (key.empty()) {
218: warnx("%s: key must be specified", av[i]);
219: return;
220: }
221: if (val.empty()) {
222: warnx("%s: value must be specified", av[i]);
223: return;
224: }
225:
226: if (updater(key, val)) {
227: updated++;
228: }
229: }
230:
231: // 更新があればチェックサムを再計算
232: if (updated > 0) {
233: uint8 eor = calc_checksum();
234: for (int i = 0; i < 3; i++) {
235: nvram[0x1c + i] = eor;
236: }
237: }
238: }
239:
240: // LUNA-I のパラメータ表
241: struct luna1param {
242: uint32 addr;
243: const char *key;
244: };
245: static std::vector<luna1param> luna1params = {
246: { 0x0020, "BOOT" },
247: { 0x0040, "HOST" },
248: { 0x0060, "SERVER" },
249: { 0x0080, "DKUNIT" },
250: { 0x00a0, "DKPART" },
251: { 0x00c0, "DKFILE" },
252: { 0x00e0, "FLUNIT" },
253: { 0x0100, "FLFILE" },
254: { 0x0120, "STUNIT" },
255: { 0x0140, "STFLNO" },
256: { 0x0160, "STFILE" },
257: { 0x0180, "ETBOOT" },
258: { 0x01a0, "ETFILE" },
259: { 0x0560, "ENADDR" },
260: };
261:
262: // LUNA-I の場合、キーはたぶん固定じゃないかな。
263: // 更新したら true を返す。
264: static bool
265: update_luna1(const std::string& key, const std::string& val)
266: {
267: uint32 addr = 0;
268:
269: // 探す
270: for (const auto& p : luna1params) {
271: if (key == p.key) {
272: addr = p.addr;
273: break;
274: }
275: }
276: if (addr == 0) {
277: warnx("%s: Unknown key name", key.c_str());
278: return false;
279: }
280:
281: // 値だけ更新でいいはず
282: write_string(addr + 16, val);
283: return true;
284: }
285:
1.1.1.2 root 286: // LUNA-88K の場合、キーはフリーダムのように見える。
1.1 root 287: // 更新したら true を返す。
288: static bool
289: update_luna88k(const std::string& key, const std::string& val)
290: {
291: uint32 addr = 0;
292:
293: addr = find_string(key);
294: if (addr == 0) {
295: // 見付からなければ新規追加
296: addr = find_string("");
297: if (addr == 0) {
298: // 空きエントリがない
299: warnx("No spaces available");
300: return false;
301: }
302: }
303:
304: // 追加の場合もあるので常に更新してしまう。副作用はないはず。
305: write_string(addr, key);
306: write_string(addr + 16, val);
307: return true;
308: }
309:
310: // キーと値はいずれも 16文字未満なら '\0' 終端、
311: // 16文字の場合は '\0' で終端せず 16文字とするフォーマット。
312:
313: // 文字列を読み込む
314: static std::string
315: read_string(uint32 addr)
316: {
317: char buf[18];
318:
319: memset(buf, 0, sizeof(buf));
320: memcpy(buf, &nvram[addr], 16);
321:
322: return std::string(buf);
323: }
324:
325: // 文字列を書き込む
326: static void
327: write_string(uint32 addr, const std::string& str)
328: {
329: memset(&nvram[addr], 0, 16);
330: memcpy(&nvram[addr], str.data(), str.size());
331: }
332:
1.1.1.2 root 333: // キーの位置を探す。主に LUNA-88K 用。
1.1 root 334: // str が "" でも探せる (新規追加時の空きエントリ探索用)
335: // 見付かればアドレスを返す。
336: // 見付からなければ 0 を返す (0 は変数のアドレスとしては使えない)
337: static uint32
338: find_string(const std::string& str)
339: {
340: for (uint32 addr = 0x20; addr < 0x560; addr += 0x20) {
341: std::string key = read_string(addr);
342: if (str == key) {
343: return addr;
344: }
345: }
346:
347: return 0;
348: }
349:
350: // NVRAM のチェックサムを返す
351: static uint8
352: calc_checksum()
353: {
354: uint8 eor = 0;
355:
356: for (uint32 addr = 0x20; addr < 0x560; addr++) {
357: eor ^= nvram[addr];
358: }
359: DPRINTF("Calculated checksum is 0x%02x\n", eor);
360: return eor;
361: }
362:
363: // NVRAM のチェックサムを照合し、正しければ true を返す
364: static bool
365: verify_checksum()
366: {
367: if (memcmp(&nvram[4], "<nv>", 4) != 0) {
368: DPRINTF("Magic string mismatch\n");
369: return false;
370: }
371:
372: uint8 eor = calc_checksum();
373: for (uint32 i = 0; i < 3; i++) {
374: if (nvram[0x1c + i] != eor) {
375: DPRINTF("Checksum[%d] mismatch\n", i);
376: return false;
377: }
378: }
379: DPRINTF("Checksum ok\n");
380: return true;
381: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.