bcmblob: new tool for reading Broadcom's BLOBs
[project/firmware-utils.git] / src / iptime-crc32.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2021 Sungbo Eo <mans0n@gorani.run>
4 *
5 * This code is based on mkdhpimg.c and mkzcfw.c
6 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
7 * Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.com>
8 *
9 * Checksum algorithm is derived from add_iptime_fw_header.c
10 * Copyright (C) 2020 Jaehoon You <teslamint@gmail.com>
11 */
12
13 #include <byteswap.h>
14 #include <endian.h>
15 #include <err.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "cyg_crc.h"
26
27 #if !defined(__BYTE_ORDER)
28 #error "Unknown byte order"
29 #endif
30
31 #if (__BYTE_ORDER == __BIG_ENDIAN)
32 #define HOST_TO_LE32(x) bswap_32(x)
33 #elif (__BYTE_ORDER == __LITTLE_ENDIAN)
34 #define HOST_TO_LE32(x) (x)
35 #else
36 #error "Unsupported endianness"
37 #endif
38
39 #define FW_VERSION "00_000"
40
41 struct fw_header {
42 uint8_t model[8];
43 uint8_t version[8];
44 uint8_t reserved[32];
45 uint32_t size;
46 uint32_t checksum;
47 } __attribute__ ((packed));
48
49 struct board_info {
50 const char *model;
51 size_t payload_offset;
52 };
53
54 struct board_info boards[] = {
55 { .model = "a6004mx", .payload_offset = 0x800 },
56 { .model = "ax2004m", .payload_offset = 0x38 },
57 { .model = "ax8004m", .payload_offset = 0x38 },
58 { /* sentinel */ }
59 };
60
61 struct board_info *find_board(const char *model)
62 {
63 struct board_info *ret = NULL;
64 struct board_info *board;
65
66 for (board = boards; board->model != NULL; board++) {
67 if (strcmp(model, board->model) == 0) {
68 ret = board;
69 break;
70 }
71 }
72
73 return ret;
74 }
75
76 uint32_t make_checksum(struct fw_header *header, uint8_t *payload, int size)
77 {
78 cyg_uint32 checksum;
79
80 /* get CRC of header */
81 checksum = cyg_crc32_accumulate(~0L, header, sizeof(*header));
82
83 /* get CRC of payload buffer with header CRC as initial value */
84 return (uint32_t)cyg_crc32_accumulate(checksum, payload, size);
85 }
86
87 void make_header(struct board_info *board, uint8_t *buffer, size_t img_size)
88 {
89 struct fw_header *header = (struct fw_header *)buffer;
90 uint32_t checksum;
91
92 strncpy((char *)header->model, board->model, sizeof(header->model)-1);
93 strncpy((char *)header->version, FW_VERSION, sizeof(header->version)-1);
94 header->size = HOST_TO_LE32(img_size);
95 checksum = make_checksum(header, buffer + board->payload_offset, img_size);
96 header->checksum = HOST_TO_LE32(checksum);
97 }
98
99 int main(int argc, const char *argv[])
100 {
101 const char *model_name, *img_in, *img_out;
102 struct board_info *board;
103 int file_in, file_out;
104 struct stat stat_in;
105 size_t size_in, size_out;
106 uint8_t *buffer;
107
108 if (argc != 4) {
109 fprintf(stderr, "Usage: %s <model> <input> <output>\n", argv[0]);
110 return EXIT_FAILURE;
111 }
112 model_name = argv[1];
113 img_in = argv[2];
114 img_out = argv[3];
115
116 board = find_board(model_name);
117 if (board == NULL) {
118 fprintf(stderr, "%s: Not supported model\n", model_name);
119 return EXIT_FAILURE;
120 }
121
122 if ((file_in = open(img_in, O_RDONLY)) == -1)
123 err(EXIT_FAILURE, "%s", img_in);
124
125 if (fstat(file_in, &stat_in) == -1)
126 err(EXIT_FAILURE, "%s", img_in);
127
128 size_in = stat_in.st_size;
129 size_out = board->payload_offset + size_in;
130
131 if ((buffer = malloc(size_out)) == NULL)
132 err(EXIT_FAILURE, "malloc");
133
134 read(file_in, buffer + board->payload_offset, size_in);
135 close(file_in);
136
137 memset(buffer, 0, board->payload_offset);
138
139 make_header(board, buffer, size_in);
140
141 if ((file_out = creat(img_out, 0644)) == -1)
142 err(EXIT_FAILURE, "%s", img_out);
143 write(file_out, buffer, size_out);
144 close(file_out);
145
146 free(buffer);
147
148 return EXIT_SUCCESS;
149 }