1 #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 #include <libflash/arch_flash.h> 17 #include <libflash/libffs.h> 18 #include <libflash/blocklevel.h> 19 #include <libflash/errors.h> 20 #include <openbmc_intf.h> 21 #include <openbmc.h> 22 23 static const gchar* dbus_object_path = "/org/openbmc/control"; 24 static const gchar* dbus_name = "org.openbmc.control.Flasher"; 25 26 static GDBusObjectManagerServer *manager = NULL; 27 28 #define __aligned(x) __attribute__((aligned(x))) 29 30 static bool need_relock; 31 32 #define FILE_BUF_SIZE 0x10000 33 static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000); 34 35 static struct blocklevel_device *bl; 36 static struct ffs_handle *ffsh; 37 static uint32_t fl_total_size, fl_erase_granule; 38 static const char *fl_name; 39 static int32_t ffs_index = -1; 40 41 static uint8_t FLASH_OK = 0; 42 static uint8_t FLASH_ERROR = 0x01; 43 static uint8_t FLASH_SETUP_ERROR = 0x02; 44 45 static int 46 erase_chip(void) 47 { 48 int rc = 0; 49 50 printf("Erasing... (may take a while !) "); 51 fflush(stdout); 52 53 rc = arch_flash_erase_chip(bl); 54 if(rc) { 55 fprintf(stderr, "Error %d erasing chip\n", rc); 56 return(rc); 57 } 58 59 printf("done !\n"); 60 return(rc); 61 } 62 63 void 64 flash_message(GDBusConnection* connection,char* obj_path,char* method, char* error_msg) 65 { 66 GDBusProxy *proxy; 67 GError *error; 68 GVariant *parm = NULL; 69 error = NULL; 70 proxy = g_dbus_proxy_new_sync(connection, 71 G_DBUS_PROXY_FLAGS_NONE, 72 NULL, /* GDBusInterfaceInfo* */ 73 "org.openbmc.control.Flash", /* name */ 74 obj_path, /* object path */ 75 "org.openbmc.Flash", /* interface name */ 76 NULL, /* GCancellable */ 77 &error); 78 g_assert_no_error(error); 79 80 error = NULL; 81 if(strcmp(method,"error")==0) { 82 parm = g_variant_new("(s)",error_msg); 83 } 84 g_dbus_proxy_call_sync(proxy, 85 method, 86 parm, 87 G_DBUS_CALL_FLAGS_NONE, 88 -1, 89 NULL, 90 &error); 91 92 g_assert_no_error(error); 93 } 94 95 static int 96 program_file(FlashControl* flash_control, const char *file, uint32_t start, uint32_t size) 97 { 98 int fd, rc; 99 ssize_t len; 100 uint32_t actual_size = 0; 101 102 fd = open(file, O_RDONLY); 103 if(fd == -1) { 104 perror("Failed to open file"); 105 return(fd); 106 } 107 printf("About to program \"%s\" at 0x%08x..0x%08x !\n", 108 file, start, size); 109 110 printf("Programming & Verifying...\n"); 111 //progress_init(size >> 8); 112 unsigned int save_size = size; 113 uint8_t last_progress = 0; 114 while(size) { 115 len = read(fd, file_buf, FILE_BUF_SIZE); 116 if(len < 0) { 117 perror("Error reading file"); 118 return(1); 119 } 120 if(len == 0) 121 break; 122 if(len > size) 123 len = size; 124 size -= len; 125 actual_size += len; 126 rc = blocklevel_write(bl, start, file_buf, len); 127 if(rc) { 128 if(rc == FLASH_ERR_VERIFY_FAILURE) 129 fprintf(stderr, "Verification failed for" 130 " chunk at 0x%08x\n", start); 131 else 132 fprintf(stderr, "Flash write error %d for" 133 " chunk at 0x%08x\n", rc, start); 134 return(rc); 135 } 136 start += len; 137 unsigned int percent = (100*actual_size/save_size); 138 uint8_t progress = (uint8_t)(percent); 139 if(progress != last_progress) { 140 flash_control_emit_progress(flash_control,file,progress); 141 last_progress = progress; 142 } 143 } 144 close(fd); 145 146 /* If this is a flash partition, adjust its size */ 147 if(ffsh && ffs_index >= 0) { 148 printf("Updating actual size in partition header...\n"); 149 ffs_update_act_size(ffsh, ffs_index, actual_size); 150 } 151 return(0); 152 } 153 154 static void 155 flash_access_cleanup_bmc(void) 156 { 157 if(ffsh) 158 ffs_close(ffsh); 159 arch_flash_close(bl, NULL); 160 } 161 162 static int 163 flash_access_setup_bmc(bool need_write) 164 { 165 int rc; 166 printf("Setting up BMC flash\n"); 167 168 if(arch_flash_bmc(bl, BMC_DIRECT) != BMC_DIRECT) { 169 fprintf(stderr, "Failed to init flash chip\n"); 170 return FLASH_SETUP_ERROR; 171 } 172 173 /* Setup cleanup function */ 174 atexit(flash_access_cleanup_bmc); 175 return FLASH_OK; 176 } 177 178 static void 179 flash_access_cleanup_pnor(void) 180 { 181 /* Re-lock flash */ 182 if(need_relock) 183 arch_flash_set_wrprotect(bl, 1); 184 185 flash_access_cleanup_bmc(); 186 } 187 188 static int 189 flash_access_setup_pnor(bool need_write) 190 { 191 int rc; 192 printf("Setting up BIOS flash\n"); 193 194 /* Create the AST flash controller */ 195 196 /* Open flash chip */ 197 rc = arch_flash_init(&bl, NULL, true); 198 if(rc) { 199 fprintf(stderr, "Failed to open flash chip\n"); 200 return FLASH_SETUP_ERROR; 201 } 202 203 /* Unlock flash (PNOR only) */ 204 if(need_write) 205 need_relock = arch_flash_set_wrprotect(bl, 0); 206 207 /* Setup cleanup function */ 208 atexit(flash_access_cleanup_pnor); 209 return FLASH_OK; 210 } 211 212 uint8_t 213 flash(FlashControl* flash_control,bool bmc_flash, uint32_t address, char* write_file, char* obj_path) 214 { 215 bool erase = true, program = true; 216 217 int rc; 218 printf("flasher: %s, BMC = %d, address = 0x%x\n",write_file,bmc_flash,address); 219 220 /* Prepare for access */ 221 if(bmc_flash) { 222 rc = flash_access_setup_bmc(erase || program); 223 if(rc) { 224 return FLASH_SETUP_ERROR; 225 } 226 } else { 227 rc = flash_access_setup_pnor(erase || program); 228 if(rc) { 229 return FLASH_SETUP_ERROR; 230 } 231 } 232 233 rc = blocklevel_get_info(bl, &fl_name, 234 &fl_total_size, &fl_erase_granule); 235 if(rc) { 236 fprintf(stderr, "Error %d getting flash info\n", rc); 237 return FLASH_SETUP_ERROR; 238 } 239 if(strcmp(write_file,"")!=0) 240 { 241 // If file specified but not size, get size from file 242 struct stat stbuf; 243 if(stat(write_file, &stbuf)) { 244 perror("Failed to get file size"); 245 return FLASH_ERROR; 246 } 247 uint32_t write_size = stbuf.st_size; 248 rc = erase_chip(); 249 if(rc) { 250 return FLASH_ERROR; 251 } 252 rc = program_file(flash_control, write_file, address, write_size); 253 if(rc) { 254 return FLASH_ERROR; 255 } 256 257 printf("Flash done\n"); 258 } 259 else 260 { 261 printf("Flash tuned\n"); 262 } 263 return FLASH_OK; 264 } 265 266 static void 267 on_bus_acquired(GDBusConnection *connection, 268 const gchar *name, 269 gpointer user_data) 270 { 271 cmdline *cmd = user_data; 272 if(cmd->argc < 4) 273 { 274 g_print("flasher [flash name] [filename] [source object]\n"); 275 g_main_loop_quit(cmd->loop); 276 return; 277 } 278 printf("Starting flasher: %s,%s,%s,\n",cmd->argv[1],cmd->argv[2],cmd->argv[3]); 279 ObjectSkeleton *object; 280 manager = g_dbus_object_manager_server_new(dbus_object_path); 281 gchar *s; 282 s = g_strdup_printf("%s/%s",dbus_object_path,cmd->argv[1]); 283 284 object = object_skeleton_new(s); 285 g_free(s); 286 287 FlashControl* flash_control = flash_control_skeleton_new(); 288 object_skeleton_set_flash_control(object, flash_control); 289 g_object_unref(flash_control); 290 291 /* Export the object (@manager takes its own reference to @object) */ 292 g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object)); 293 g_object_unref(object); 294 295 /* Export all objects */ 296 g_dbus_object_manager_server_set_connection(manager, connection); 297 bool bmc_flash = false; 298 uint32_t address = 0; 299 if(strcmp(cmd->argv[1],"bmc")==0) { 300 bmc_flash = true; 301 } 302 if(strcmp(cmd->argv[1],"bmc_ramdisk")==0) { 303 bmc_flash = true; 304 address = 0x20300000; 305 } 306 if(strcmp(cmd->argv[1],"bmc_kernel")==0) { 307 bmc_flash = true; 308 address = 0x20080000; 309 } 310 311 int rc = flash(flash_control,bmc_flash,address,cmd->argv[2],cmd->argv[3]); 312 if(rc) { 313 flash_message(connection,cmd->argv[3],"error","Flash Error"); 314 } else { 315 flash_message(connection,cmd->argv[3],"done",""); 316 } 317 318 //Object exits when done flashing 319 g_main_loop_quit(cmd->loop); 320 } 321 322 int 323 main(int argc, char *argv[]) 324 { 325 GMainLoop *loop; 326 cmdline cmd; 327 cmd.argc = argc; 328 cmd.argv = argv; 329 330 guint id; 331 loop = g_main_loop_new(NULL, FALSE); 332 cmd.loop = loop; 333 334 id = g_bus_own_name(DBUS_TYPE, 335 dbus_name, 336 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | 337 G_BUS_NAME_OWNER_FLAGS_REPLACE, 338 on_bus_acquired, 339 NULL, 340 NULL, 341 &cmd, 342 NULL); 343 344 g_main_loop_run(loop); 345 346 g_bus_unown_name(id); 347 g_main_loop_unref(loop); 348 349 return 0; 350 } 351