diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c | 345 |
1 files changed, 209 insertions, 136 deletions
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c index 154785ee0b..10a58ace38 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/installer-fiiom3k.c | |||
@@ -19,192 +19,265 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "installer.h" | 22 | #include "installer-fiiom3k.h" |
23 | #include "nand-x1000.h" | 23 | #include "nand-x1000.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "core_alloc.h" | 25 | #include "core_alloc.h" |
26 | #include "file.h" | 26 | #include "file.h" |
27 | #include "microtar.h" | ||
28 | #include <stdint.h> | ||
29 | #include <string.h> | ||
30 | #include <stdio.h> | ||
27 | 31 | ||
28 | #define INSTALL_SUCCESS 0 | 32 | #define IMAGE_SIZE (128 * 1024) |
29 | #define ERR_FLASH_OPEN_FAILED (-1) | 33 | #define TAR_SIZE (256 * 1024) |
30 | #define ERR_FLASH_ENABLE_WP_FAILED (-2) | 34 | |
31 | #define ERR_FLASH_DISABLE_WP_FAILED (-3) | 35 | static int flash_prepare(void) |
32 | #define ERR_FLASH_ERASE_FAILED (-4) | ||
33 | #define ERR_FLASH_WRITE_FAILED (-5) | ||
34 | #define ERR_FLASH_READ_FAILED (-6) | ||
35 | #define ERR_OUT_OF_MEMORY (-7) | ||
36 | #define ERR_CANNOT_READ_FILE (-8) | ||
37 | #define ERR_CANNOT_WRITE_FILE (-9) | ||
38 | #define ERR_WRONG_SIZE (-10) | ||
39 | |||
40 | #define BOOT_IMAGE_SIZE (128 * 1024) | ||
41 | |||
42 | static int install_from_buffer(const void* buf) | ||
43 | { | 36 | { |
44 | int status = INSTALL_SUCCESS; | ||
45 | int mf_id, dev_id; | 37 | int mf_id, dev_id; |
38 | int rc; | ||
39 | |||
40 | rc = nand_open(); | ||
41 | if(rc < 0) | ||
42 | return INSTALL_ERR_FLASH(NAND_OPEN, rc); | ||
46 | 43 | ||
47 | if(nand_open()) | 44 | rc = nand_identify(&mf_id, &dev_id); |
48 | return ERR_FLASH_OPEN_FAILED; | 45 | if(rc < 0) { |
49 | if(nand_identify(&mf_id, &dev_id)) { | 46 | nand_close(); |
50 | status = ERR_FLASH_OPEN_FAILED; | 47 | return INSTALL_ERR_FLASH(NAND_IDENTIFY, rc); |
51 | goto _exit; | ||
52 | } | 48 | } |
53 | 49 | ||
54 | if(nand_enable_writes(true)) { | 50 | return INSTALL_SUCCESS; |
55 | status = ERR_FLASH_DISABLE_WP_FAILED; | 51 | } |
56 | goto _exit; | 52 | |
53 | static void flash_finish(void) | ||
54 | { | ||
55 | /* Ensure writes are always disabled when we finish. | ||
56 | * Errors are safe to ignore here, there's nothing we could do anyway. */ | ||
57 | nand_enable_writes(false); | ||
58 | nand_close(); | ||
59 | } | ||
60 | |||
61 | static int flash_img_read(uint8_t* buffer) | ||
62 | { | ||
63 | int rc = flash_prepare(); | ||
64 | if(rc < 0) | ||
65 | goto error; | ||
66 | |||
67 | rc = nand_read(0, IMAGE_SIZE, buffer); | ||
68 | if(rc < 0) { | ||
69 | rc = INSTALL_ERR_FLASH(NAND_READ, rc); | ||
70 | goto error; | ||
57 | } | 71 | } |
58 | 72 | ||
59 | if(nand_erase(0, BOOT_IMAGE_SIZE)) { | 73 | error: |
60 | status = ERR_FLASH_ERASE_FAILED; | 74 | flash_finish(); |
61 | goto _exit; | 75 | return rc; |
76 | } | ||
77 | |||
78 | static int flash_img_write(const uint8_t* buffer) | ||
79 | { | ||
80 | int rc = flash_prepare(); | ||
81 | if(rc < 0) | ||
82 | goto error; | ||
83 | |||
84 | rc = nand_enable_writes(true); | ||
85 | if(rc < 0) { | ||
86 | rc = INSTALL_ERR_FLASH(NAND_ENABLE_WRITES, rc); | ||
87 | goto error; | ||
62 | } | 88 | } |
63 | 89 | ||
64 | if(nand_write(0, BOOT_IMAGE_SIZE, (const uint8_t*)buf)) { | 90 | rc = nand_erase(0, IMAGE_SIZE); |
65 | status = ERR_FLASH_WRITE_FAILED; | 91 | if(rc < 0) { |
66 | goto _exit; | 92 | rc = INSTALL_ERR_FLASH(NAND_ERASE, rc); |
93 | goto error; | ||
67 | } | 94 | } |
68 | 95 | ||
69 | if(nand_enable_writes(false)) { | 96 | rc = nand_write(0, IMAGE_SIZE, buffer); |
70 | status = ERR_FLASH_ENABLE_WP_FAILED; | 97 | if(rc < 0) { |
71 | goto _exit; | 98 | rc = INSTALL_ERR_FLASH(NAND_WRITE, rc); |
99 | goto error; | ||
72 | } | 100 | } |
73 | 101 | ||
74 | _exit: | 102 | error: |
75 | nand_close(); | 103 | flash_finish(); |
76 | return status; | 104 | return rc; |
77 | } | 105 | } |
78 | 106 | ||
79 | static int dump_to_buffer(void* buf) | 107 | static int patch_img(mtar_t* tar, uint8_t* buffer, const char* filename, |
108 | size_t patch_offset, size_t patch_size) | ||
80 | { | 109 | { |
81 | int status = INSTALL_SUCCESS; | 110 | /* Seek to file */ |
82 | int mf_id, dev_id; | 111 | mtar_header_t h; |
83 | 112 | int rc = mtar_find(tar, filename, &h); | |
84 | if(nand_open()) | 113 | if(rc != MTAR_ESUCCESS) { |
85 | return ERR_FLASH_OPEN_FAILED; | 114 | rc = INSTALL_ERR_MTAR(TAR_FIND, rc); |
86 | if(nand_identify(&mf_id, &dev_id)) { | 115 | return rc; |
87 | status = ERR_FLASH_OPEN_FAILED; | ||
88 | goto _exit; | ||
89 | } | 116 | } |
90 | 117 | ||
91 | if(nand_read(0, BOOT_IMAGE_SIZE, (uint8_t*)buf)) { | 118 | /* We need a normal file */ |
92 | status = ERR_FLASH_READ_FAILED; | 119 | if(h.type != 0 && h.type != MTAR_TREG) |
93 | goto _exit; | 120 | return INSTALL_ERR_BAD_FORMAT; |
121 | |||
122 | /* Check size does not exceed patch area */ | ||
123 | if(h.size > patch_size) | ||
124 | return INSTALL_ERR_BAD_FORMAT; | ||
125 | |||
126 | /* Read data directly into patch area, fill unused bytes with 0xff */ | ||
127 | memset(&buffer[patch_offset], 0xff, patch_size); | ||
128 | rc = mtar_read_data(tar, &buffer[patch_offset], h.size); | ||
129 | if(rc != MTAR_ESUCCESS) { | ||
130 | rc = INSTALL_ERR_MTAR(TAR_READ, rc); | ||
131 | return rc; | ||
94 | } | 132 | } |
95 | 133 | ||
96 | _exit: | 134 | return INSTALL_SUCCESS; |
97 | nand_close(); | ||
98 | return status; | ||
99 | } | 135 | } |
100 | 136 | ||
101 | int install_bootloader(const char* path) | 137 | int install_boot(const char* srcfile) |
102 | { | 138 | { |
103 | /* Allocate memory to hold image */ | 139 | int rc; |
104 | size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; | 140 | mtar_t* tar = NULL; |
105 | int handle = core_alloc("boot_image", bufsize); | 141 | int handle = -1; |
106 | if(handle < 0) | ||
107 | return ERR_OUT_OF_MEMORY; | ||
108 | |||
109 | int status = INSTALL_SUCCESS; | ||
110 | void* buffer = core_get_data(handle); | ||
111 | CACHEALIGN_BUFFER(buffer, bufsize); | ||
112 | 142 | ||
113 | /* Open the boot image */ | 143 | /* Allocate enough memory for image and tar state */ |
114 | int fd = open(path, O_RDONLY); | 144 | size_t bufsize = IMAGE_SIZE + sizeof(mtar_t) + 2*CACHEALIGN_SIZE; |
115 | if(fd < 0) { | 145 | handle = core_alloc("boot_image", bufsize); |
116 | status = ERR_CANNOT_READ_FILE; | 146 | if(handle < 0) { |
117 | goto _exit; | 147 | rc = INSTALL_ERR_OUT_OF_MEMORY; |
148 | goto error; | ||
118 | } | 149 | } |
119 | 150 | ||
120 | /* Check file size */ | 151 | uint8_t* buffer = core_get_data(handle); |
121 | off_t fsize = filesize(fd); | 152 | |
122 | if(fsize != BOOT_IMAGE_SIZE) { | 153 | /* Tar state alloc */ |
123 | status = ERR_WRONG_SIZE; | 154 | CACHEALIGN_BUFFER(buffer, bufsize); |
124 | goto _exit; | 155 | tar = (mtar_t*)buffer; |
125 | } | 156 | memset(tar, 0, sizeof(tar)); |
157 | |||
158 | /* Image buffer alloc */ | ||
159 | buffer += sizeof(mtar_t); | ||
160 | CACHEALIGN_BUFFER(buffer, bufsize); | ||
161 | |||
162 | /* Read the flash -- we need an existing image to patch */ | ||
163 | rc = flash_img_read(buffer); | ||
164 | if(rc < 0) | ||
165 | goto error; | ||
126 | 166 | ||
127 | /* Read the file into the buffer */ | 167 | /* Open the tarball */ |
128 | ssize_t cnt = read(fd, buffer, BOOT_IMAGE_SIZE); | 168 | rc = mtar_open(tar, srcfile, "r"); |
129 | if(cnt != BOOT_IMAGE_SIZE) { | 169 | if(rc != MTAR_ESUCCESS) { |
130 | status = ERR_CANNOT_READ_FILE; | 170 | rc = INSTALL_ERR_MTAR(TAR_OPEN, rc); |
131 | goto _exit; | 171 | goto error; |
132 | } | 172 | } |
133 | 173 | ||
134 | /* Perform the installation */ | 174 | /* Extract the needed files & patch 'em in */ |
135 | status = install_from_buffer(buffer); | 175 | rc = patch_img(tar, buffer, "spl.m3k", 0, 12 * 1024); |
176 | if(rc < 0) | ||
177 | goto error; | ||
136 | 178 | ||
137 | _exit: | 179 | rc = patch_img(tar, buffer, "bootloader.ucl", 0x6800, 102 * 1024); |
138 | if(fd >= 0) | 180 | if(rc < 0) |
139 | close(fd); | 181 | goto error; |
140 | core_free(handle); | 182 | |
141 | return status; | 183 | /* Flash the new image */ |
184 | rc = flash_img_write(buffer); | ||
185 | if(rc < 0) | ||
186 | goto error; | ||
187 | |||
188 | rc = INSTALL_SUCCESS; | ||
189 | |||
190 | error: | ||
191 | if(tar && tar->close) | ||
192 | mtar_close(tar); | ||
193 | if(handle >= 0) | ||
194 | core_free(handle); | ||
195 | return rc; | ||
142 | } | 196 | } |
143 | 197 | ||
144 | /* Dump the current bootloader to a file */ | 198 | int backup_boot(const char* destfile) |
145 | int dump_bootloader(const char* path) | ||
146 | { | 199 | { |
147 | /* Allocate memory to hold image */ | 200 | int rc; |
148 | size_t bufsize = BOOT_IMAGE_SIZE + CACHEALIGN_SIZE - 1; | 201 | int handle = -1; |
149 | int handle = core_alloc("boot_image", bufsize); | ||
150 | if(handle < 0) | ||
151 | return -1; | ||
152 | |||
153 | /* Read data from flash */ | ||
154 | int fd = -1; | 202 | int fd = -1; |
155 | void* buffer = core_get_data(handle); | 203 | size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1; |
204 | handle = core_alloc("boot_image", bufsize); | ||
205 | if(handle < 0) { | ||
206 | rc = INSTALL_ERR_OUT_OF_MEMORY; | ||
207 | goto error; | ||
208 | } | ||
209 | |||
210 | uint8_t* buffer = core_get_data(handle); | ||
156 | CACHEALIGN_BUFFER(buffer, bufsize); | 211 | CACHEALIGN_BUFFER(buffer, bufsize); |
157 | int status = dump_to_buffer(buffer); | ||
158 | if(status) | ||
159 | goto _exit; | ||
160 | 212 | ||
161 | /* Open file */ | 213 | rc = flash_img_read(buffer); |
162 | fd = open(path, O_CREAT|O_TRUNC|O_WRONLY); | 214 | if(rc < 0) |
215 | goto error; | ||
216 | |||
217 | fd = open(destfile, O_CREAT|O_TRUNC|O_WRONLY); | ||
163 | if(fd < 0) { | 218 | if(fd < 0) { |
164 | status = ERR_CANNOT_WRITE_FILE; | 219 | rc = INSTALL_ERR_FILE_IO; |
165 | goto _exit; | 220 | goto error; |
166 | } | 221 | } |
167 | 222 | ||
168 | /* Write data to file */ | 223 | ssize_t cnt = write(fd, buffer, IMAGE_SIZE); |
169 | ssize_t cnt = write(fd, buffer, BOOT_IMAGE_SIZE); | 224 | if(cnt != IMAGE_SIZE) { |
170 | if(cnt != BOOT_IMAGE_SIZE) { | 225 | rc = INSTALL_ERR_FILE_IO; |
171 | status = ERR_CANNOT_WRITE_FILE; | 226 | goto error; |
172 | goto _exit; | ||
173 | } | 227 | } |
174 | 228 | ||
175 | _exit: | 229 | error: |
176 | if(fd >= 0) | 230 | if(fd >= 0) |
177 | close(fd); | 231 | close(fd); |
178 | core_free(handle); | 232 | if(handle >= 0) |
179 | return status; | 233 | core_free(handle); |
234 | return rc; | ||
180 | } | 235 | } |
181 | 236 | ||
182 | const char* installer_strerror(int rc) | 237 | int restore_boot(const char* srcfile) |
183 | { | 238 | { |
184 | switch(rc) { | 239 | int rc; |
185 | case INSTALL_SUCCESS: | 240 | int handle = -1; |
186 | return "Success"; | 241 | int fd = -1; |
187 | case ERR_FLASH_OPEN_FAILED: | 242 | size_t bufsize = IMAGE_SIZE + CACHEALIGN_SIZE - 1; |
188 | return "Can't open flash device"; | 243 | handle = core_alloc("boot_image", bufsize); |
189 | case ERR_FLASH_ENABLE_WP_FAILED: | 244 | if(handle < 0) { |
190 | return "Couldn't re-enable write protect"; | 245 | rc = INSTALL_ERR_OUT_OF_MEMORY; |
191 | case ERR_FLASH_DISABLE_WP_FAILED: | 246 | goto error; |
192 | return "Can't disable write protect"; | ||
193 | case ERR_FLASH_ERASE_FAILED: | ||
194 | return "Flash erase failed"; | ||
195 | case ERR_FLASH_WRITE_FAILED: | ||
196 | return "Flash write error"; | ||
197 | case ERR_FLASH_READ_FAILED: | ||
198 | return "Flash read error"; | ||
199 | case ERR_OUT_OF_MEMORY: | ||
200 | return "Out of memory"; | ||
201 | case ERR_CANNOT_READ_FILE: | ||
202 | return "Error reading file"; | ||
203 | case ERR_CANNOT_WRITE_FILE: | ||
204 | return "Error writing file"; | ||
205 | case ERR_WRONG_SIZE: | ||
206 | return "Wrong file size"; | ||
207 | default: | ||
208 | return "Unknown error"; | ||
209 | } | 247 | } |
248 | |||
249 | uint8_t* buffer = core_get_data(handle); | ||
250 | CACHEALIGN_BUFFER(buffer, bufsize); | ||
251 | |||
252 | fd = open(srcfile, O_RDONLY); | ||
253 | if(fd < 0) { | ||
254 | rc = INSTALL_ERR_FILE_NOT_FOUND; | ||
255 | goto error; | ||
256 | } | ||
257 | |||
258 | off_t fsize = filesize(fd); | ||
259 | if(fsize != IMAGE_SIZE) { | ||
260 | rc = INSTALL_ERR_BAD_FORMAT; | ||
261 | goto error; | ||
262 | } | ||
263 | |||
264 | ssize_t cnt = read(fd, buffer, IMAGE_SIZE); | ||
265 | if(cnt != IMAGE_SIZE) { | ||
266 | rc = INSTALL_ERR_FILE_IO; | ||
267 | goto error; | ||
268 | } | ||
269 | |||
270 | close(fd); | ||
271 | fd = -1; | ||
272 | |||
273 | rc = flash_img_write(buffer); | ||
274 | if(rc < 0) | ||
275 | goto error; | ||
276 | |||
277 | error: | ||
278 | if(fd >= 0) | ||
279 | close(fd); | ||
280 | if(handle >= 0) | ||
281 | core_free(handle); | ||
282 | return rc; | ||
210 | } | 283 | } |