blob: 99813782870d07ef78f50b44b5b2fb277c03346b [file] [log] [blame]
Norman Jamesc0d94e02015-10-13 10:06:12 -05001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <fcntl.h>
5#include <sys/mman.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
9#include <byteswap.h>
10#include <stdint.h>
11#include <stdbool.h>
12#include <getopt.h>
13#include <limits.h>
14#include <arpa/inet.h>
15#include <assert.h>
16
17#include <libflash/libflash.h>
18#include <libflash/libffs.h>
19#include "progress.h"
20#include "io.h"
21#include "ast.h"
22#include "sfc-ctrl.h"
23#include "interfaces/openbmc_intf.h"
24#include "includes/openbmc.h"
25
26static const gchar* dbus_object_path = "/org/openbmc/control";
27static const gchar* dbus_object_name = "Flasher_0";
28static const gchar* dbus_name = "org.openbmc.control.Flasher";
29
30static GDBusObjectManagerServer *manager = NULL;
31
32#define __aligned(x) __attribute__((aligned(x)))
33
34#define PFLASH_VERSION "0.8.6"
35
36static bool must_confirm = false;
37static bool dummy_run;
38static bool need_relock;
39static bool bmc_flash;
40#ifdef __powerpc__
41static bool using_sfc;
42#endif
43
44#define FILE_BUF_SIZE 0x10000
45static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
46
47static struct spi_flash_ctrl *fl_ctrl;
48static struct flash_chip *fl_chip;
49static struct ffs_handle *ffsh;
50static uint32_t fl_total_size, fl_erase_granule;
51static const char *fl_name;
52static int32_t ffs_index = -1;
53
Norman James166acf42015-10-22 07:11:51 -050054static uint8_t FLASH_OK = 0;
55static uint8_t FLASH_ERROR = 1;
Norman Jamesc0d94e02015-10-13 10:06:12 -050056
57static int erase_chip(void)
58{
59 int rc = 0;
60
61 printf("Erasing... (may take a while !) ");
62 fflush(stdout);
63
64 rc = flash_erase_chip(fl_chip);
65 if (rc) {
66 fprintf(stderr, "Error %d erasing chip\n", rc);
67 return(rc);
68 }
69
70 printf("done !\n");
71 return (rc);
72}
73
Norman James166acf42015-10-22 07:11:51 -050074void flash_message(GDBusConnection* connection,char* obj_path,char* method, char* error_msg)
75{
76 GDBusProxy *proxy;
77 GError *error;
78 GVariant *parm = NULL;
79 GVariant *result;
80 error = NULL;
81 proxy = g_dbus_proxy_new_sync (connection,
82 G_DBUS_PROXY_FLAGS_NONE,
83 NULL, /* GDBusInterfaceInfo* */
84 "org.openbmc.control.Flash", /* name */
85 obj_path, /* object path */
86 "org.openbmc.Flash", /* interface name */
87 NULL, /* GCancellable */
88 &error);
89 g_assert_no_error (error);
90
91 error = NULL;
92 if (strcmp(method,"error")==0) {
93 parm = g_variant_new("(s)",error_msg);
94 }
95 result = g_dbus_proxy_call_sync (proxy,
96 method,
97 parm,
98 G_DBUS_CALL_FLAGS_NONE,
99 -1,
100 NULL,
101 &error);
102
103 g_assert_no_error (error);
104}
105
106
Norman Jamesc0d94e02015-10-13 10:06:12 -0500107static int program_file(FlashControl* flash_control, const char *file, uint32_t start, uint32_t size)
108{
109 int fd, rc;
110 ssize_t len;
111 uint32_t actual_size = 0;
112
113 fd = open(file, O_RDONLY);
114 if (fd == -1) {
115 perror("Failed to open file");
116 return(fd);
117 }
118 printf("About to program \"%s\" at 0x%08x..0x%08x !\n",
119 file, start, size);
120
121 printf("Programming & Verifying...\n");
122 //progress_init(size >> 8);
123 unsigned int save_size = size;
124 uint8_t last_progress = 0;
125 while(size) {
126 len = read(fd, file_buf, FILE_BUF_SIZE);
127 if (len < 0) {
128 perror("Error reading file");
129 return(1);
130 }
131 if (len == 0)
132 break;
133 if (len > size)
134 len = size;
135 size -= len;
136 actual_size += len;
137 rc = flash_write(fl_chip, start, file_buf, len, true);
138 if (rc) {
139 if (rc == FLASH_ERR_VERIFY_FAILURE)
140 fprintf(stderr, "Verification failed for"
141 " chunk at 0x%08x\n", start);
142 else
143 fprintf(stderr, "Flash write error %d for"
144 " chunk at 0x%08x\n", rc, start);
145 return(rc);
146 }
147 start += len;
148 unsigned int percent = (100*actual_size/save_size);
149 uint8_t progress = (uint8_t) (percent);
150 if (progress != last_progress) {
151 flash_control_emit_progress(flash_control,file,progress);
152 last_progress = progress;
153 }
154 }
155 close(fd);
156
157 /* If this is a flash partition, adjust its size */
158 if (ffsh && ffs_index >= 0) {
159 printf("Updating actual size in partition header...\n");
160 ffs_update_act_size(ffsh, ffs_index, actual_size);
161 }
162 return(0);
163}
164
165static void do_read_file(const char *file, uint32_t start, uint32_t size)
166{
167 int fd, rc;
168 ssize_t len;
169 uint32_t done = 0;
170
171 fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666);
172 if (fd == -1) {
173 perror("Failed to open file");
174 exit(1);
175 }
176 printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
177 file, start, size);
178
179 progress_init(size >> 8);
180 while(size) {
181 len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size;
182 rc = flash_read(fl_chip, start, file_buf, len);
183 if (rc) {
184 fprintf(stderr, "Flash read error %d for"
185 " chunk at 0x%08x\n", rc, start);
186 exit(1);
187 }
188 rc = write(fd, file_buf, len);
189 if (rc < 0) {
190 perror("Error writing file");
191 exit(1);
192 }
193 start += len;
194 size -= len;
195 done += len;
196 progress_tick(done >> 8);
197 }
198 progress_end();
199 close(fd);
200}
201static void flash_access_cleanup_bmc(void)
202{
203 if (ffsh)
204 ffs_close(ffsh);
205 flash_exit(fl_chip);
206 ast_sf_close(fl_ctrl);
207 close_devs();
208}
209
210static void flash_access_setup_bmc(bool use_lpc, bool need_write)
211{
212 int rc;
Norman James166acf42015-10-22 07:11:51 -0500213 printf("Setting up BMC flash\n");
Norman Jamesc0d94e02015-10-13 10:06:12 -0500214 /* Open and map devices */
215 open_devs(use_lpc, true);
216
217 /* Create the AST flash controller */
218 rc = ast_sf_open(AST_SF_TYPE_BMC, &fl_ctrl);
219 if (rc) {
220 fprintf(stderr, "Failed to open controller\n");
221 exit(1);
222 }
223
224 /* Open flash chip */
225 rc = flash_init(fl_ctrl, &fl_chip);
226 if (rc) {
227 fprintf(stderr, "Failed to open flash chip\n");
228 exit(1);
229 }
230
231 /* Setup cleanup function */
232 atexit(flash_access_cleanup_bmc);
233}
234
235static void flash_access_cleanup_pnor(void)
236{
237 /* Re-lock flash */
238 if (need_relock)
239 set_wrprotect(true);
240
241 if (ffsh)
242 ffs_close(ffsh);
243 flash_exit(fl_chip);
244#ifdef __powerpc__
245 if (using_sfc)
246 sfc_close(fl_ctrl);
247 else
248 ast_sf_close(fl_ctrl);
249#else
250 ast_sf_close(fl_ctrl);
251#endif
252 close_devs();
253}
254
255static void flash_access_setup_pnor(bool use_lpc, bool use_sfc, bool need_write)
256{
257 int rc;
Norman James166acf42015-10-22 07:11:51 -0500258 printf("Setting up BIOS flash\n");
Norman Jamesc0d94e02015-10-13 10:06:12 -0500259
260 /* Open and map devices */
261 open_devs(use_lpc, false);
262
263#ifdef __powerpc__
264 if (use_sfc) {
265 /* Create the SFC flash controller */
266 rc = sfc_open(&fl_ctrl);
267 if (rc) {
268 fprintf(stderr, "Failed to open controller\n");
269 exit(1);
270 }
271 using_sfc = true;
272 } else {
273#endif
274 /* Create the AST flash controller */
275 rc = ast_sf_open(AST_SF_TYPE_PNOR, &fl_ctrl);
276 if (rc) {
277 fprintf(stderr, "Failed to open controller\n");
278 exit(1);
279 }
280#ifdef __powerpc__
281 }
282#endif
283
284 /* Open flash chip */
285 rc = flash_init(fl_ctrl, &fl_chip);
286 if (rc) {
287 fprintf(stderr, "Failed to open flash chip\n");
288 exit(1);
289 }
290
291 /* Unlock flash (PNOR only) */
292 if (need_write)
293 need_relock = set_wrprotect(false);
294
295 /* Setup cleanup function */
296 atexit(flash_access_cleanup_pnor);
297}
298
Norman James15aaa802015-10-28 06:54:48 -0500299uint8_t flash(FlashControl* flash_control,bool bmc_flash, uint32_t address, char* write_file, char* obj_path)
Norman Jamesc0d94e02015-10-13 10:06:12 -0500300{
301 bool has_sfc = false, has_ast = false, use_lpc = true;
302 bool erase = true, program = true;
Norman James15aaa802015-10-28 06:54:48 -0500303
Norman Jamesc0d94e02015-10-13 10:06:12 -0500304 int rc;
Norman James15aaa802015-10-28 06:54:48 -0500305 printf("flasher: %s, BMC = %d, address = 0x%x\n",write_file,bmc_flash,address);
Norman Jamesc0d94e02015-10-13 10:06:12 -0500306#ifdef __arm__
307 /* Check platform */
308 check_platform(&has_sfc, &has_ast);
309
310 /* Prepare for access */
311 if (bmc_flash) {
312 if (!has_ast) {
313 fprintf(stderr, "No BMC on this platform\n");
Norman James166acf42015-10-22 07:11:51 -0500314 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500315 }
316 flash_access_setup_bmc(use_lpc, erase || program);
317 } else {
318 if (!has_ast && !has_sfc) {
319 fprintf(stderr, "No BMC nor SFC on this platform\n");
Norman James166acf42015-10-22 07:11:51 -0500320 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500321 }
322 flash_access_setup_pnor(use_lpc, has_sfc, erase || program);
323 }
324
325 rc = flash_get_info(fl_chip, &fl_name,
326 &fl_total_size, &fl_erase_granule);
327 if (rc) {
328 fprintf(stderr, "Error %d getting flash info\n", rc);
Norman James166acf42015-10-22 07:11:51 -0500329 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500330 }
331#endif
332 if (strcmp(write_file,"")!=0)
333 {
334 // If file specified but not size, get size from file
335 struct stat stbuf;
336 if (stat(write_file, &stbuf)) {
337 perror("Failed to get file size");
Norman James166acf42015-10-22 07:11:51 -0500338 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500339 }
340 uint32_t write_size = stbuf.st_size;
341#ifdef __arm__
342 rc = erase_chip();
343 if (rc) {
Norman James166acf42015-10-22 07:11:51 -0500344 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500345 }
346 rc = program_file(flash_control, write_file, address, write_size);
347 if (rc) {
Norman James166acf42015-10-22 07:11:51 -0500348 return FLASH_ERROR;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500349 }
350#endif
351
Norman Jamesc0d94e02015-10-13 10:06:12 -0500352 printf("Flash done\n");
353 }
354 else
355 {
Norman Jamesc0d94e02015-10-13 10:06:12 -0500356 printf("Flash tuned\n");
357 }
Norman James166acf42015-10-22 07:11:51 -0500358 return FLASH_OK;
Norman Jamesc0d94e02015-10-13 10:06:12 -0500359}
360
361static void
362on_bus_acquired (GDBusConnection *connection,
363 const gchar *name,
364 gpointer user_data)
365{
366
367 cmdline *cmd = user_data;
Norman James166acf42015-10-22 07:11:51 -0500368 if (cmd->argc < 4)
Norman Jamesc0d94e02015-10-13 10:06:12 -0500369 {
Norman James166acf42015-10-22 07:11:51 -0500370 g_print("flasher [flash name] [filename] [source object]\n");
Norman Jamesc0d94e02015-10-13 10:06:12 -0500371 return;
372 }
Norman James166acf42015-10-22 07:11:51 -0500373 printf("Starting flasher: %s,%s,%s,\n",cmd->argv[1],cmd->argv[2],cmd->argv[3]);
Norman Jamesc0d94e02015-10-13 10:06:12 -0500374 ObjectSkeleton *object;
375 manager = g_dbus_object_manager_server_new (dbus_object_path);
376 gchar *s;
377 s = g_strdup_printf ("%s/%s",dbus_object_path,cmd->argv[1]);
378
379 object = object_skeleton_new (s);
380 g_free (s);
381
382 FlashControl* flash_control = flash_control_skeleton_new ();
383 object_skeleton_set_flash_control (object, flash_control);
384 g_object_unref (flash_control);
385
386 /* Export the object (@manager takes its own reference to @object) */
387 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
388 g_object_unref (object);
389
390 /* Export all objects */
391 g_dbus_object_manager_server_set_connection (manager, connection);
Norman James166acf42015-10-22 07:11:51 -0500392 bool bmc_flash = false;
Norman James15aaa802015-10-28 06:54:48 -0500393 uint32_t address = 0;
Norman James166acf42015-10-22 07:11:51 -0500394 if (strcmp(cmd->argv[1],"bmc")==0) {
395 bmc_flash = true;
396 }
Norman James15aaa802015-10-28 06:54:48 -0500397 if (strcmp(cmd->argv[1],"bmc_ramdisk")==0) {
398 bmc_flash = true;
399 address = 0x20300000;
400 }
401 if (strcmp(cmd->argv[1],"bmc_kernel")==0) {
402 bmc_flash = true;
403 address = 0x20080000;
404 }
405
406 int rc = flash(flash_control,bmc_flash,address,cmd->argv[2],cmd->argv[3]);
Norman James166acf42015-10-22 07:11:51 -0500407 if (rc == FLASH_ERROR) {
408 flash_message(connection,cmd->argv[3],"error","Flash Error");
409 } else {
410 flash_message(connection,cmd->argv[3],"done","");
411 }
Norman Jamesc0d94e02015-10-13 10:06:12 -0500412
413 //Object exits when done flashing
414 g_main_loop_quit(cmd->loop);
415}
416
417int main(int argc, char *argv[])
418{
419
420 GMainLoop *loop;
421 cmdline cmd;
422 cmd.argc = argc;
423 cmd.argv = argv;
424
425 guint id;
426 loop = g_main_loop_new (NULL, FALSE);
427 cmd.loop = loop;
428
429 id = g_bus_own_name (DBUS_TYPE,
430 dbus_name,
431 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
432 G_BUS_NAME_OWNER_FLAGS_REPLACE,
433 on_bus_acquired,
434 NULL,
435 NULL,
436 &cmd,
437 NULL);
438
439 g_main_loop_run (loop);
440
441 g_bus_unown_name (id);
442 g_main_loop_unref (loop);
443
444 return 0;
445}