1 /*
2 * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved.
3 *
4 * Base on code from
5 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistribution of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistribution in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name of Sun Microsystems, Inc. or the names of
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * This software is provided "AS IS," without a warranty of any kind.
23 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
24 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
25 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
26 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
27 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
28 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
29 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
30 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
31 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
32 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
33 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36 /****************************************************************************
37 *
38 * Copyright (c) 2009 Kontron Canada, Inc. All Rights Reserved.
39 *
40 * IME
41 * Intel Manageability Engine
42 * Firmware Update Agent
43 *
44 * The ME is an IPMI-enabled component included in Intel(R) Next Generation
45 * Server Chipset Nehalem-EP platforms.
46 *
47 * These are a few synonyms for the ME :
48 *
49 * - Dynamic Power Node Manager
50 * - Intelligent Power Node Manager
51 *
52 * Consult Intel litterature for more information on this technology.
53 *
54 * The ME firmware resides on the platform boot flash and contains read only
55 * boot code for the ME as well as boot image redundancy support.
56 *
57 * This module implements an Upgrade Agent for the ME firwmare. Because the ME
58 * implements IPMI command handling, the agent speaks directly to the ME. In other
59 * words, in order the reach the ME, the BMC must implement IPMB bridging.
60 *
61 * The update is done through IPMI (this is IPMITOOL right !), not HECI.
62 *
63 * Example: ME available at address 0x88 on IPMI channel 8:
64 * ipmitool -m 0x20 -t 0x88 -b 8 ime info
65 *
66 * !! WARNING - You MUST use an image provided by your board vendor. - WARNING !!
67 *
68 * author:
69 * Jean-Michel.Audet@ca.kontron.com
70 * Francois.Isabelle@ca.kontron.com
71 *
72 *****************************************************************************/
73 /*
74 * HISTORY
75 * ===========================================================================
76 * 2009-04-20
77 *
78 * First public release of Kontron
79 *
80 */
81 #include <ipmitool/ipmi_ime.h>
82 #include <ipmitool/log.h>
83 #include <ipmitool/ipmi_intf.h>
84 #include <ipmitool/ipmi_mc.h>
85 #include <ipmitool/helper.h>
86 #include <ipmitool/ipmi_strings.h>
87
88
89 #undef OUTPUT_DEBUG
90
91 #include <stdlib.h>
92 #include <string.h>
93 #include <errno.h>
94 #include <time.h>
95
96 static const int IME_SUCCESS = 0;
97 static const int IME_ERROR = -1;
98 static const int IME_RESTART = -2;
99
100 #define IME_UPGRADE_BUFFER_SIZE 22
101 #define IME_RETRY_COUNT 5
102
103 typedef struct ImeUpdateImageCtx
104 {
105 uint32_t size;
106 uint8_t * pData;
107 uint8_t crc8;
108 }tImeUpdateImageCtx;
109
110 typedef enum eImeState
111 {
112 IME_STATE_IDLE = 0,
113 IME_STATE_UPDATE_REQUESTED = 1,
114 IME_STATE_UPDATE_IN_PROGRESS = 2,
115 IME_STATE_SUCCESS = 3,
116 IME_STATE_FAILED = 4,
117 IME_STATE_ROLLED_BACK = 5,
118 IME_STATE_ABORTED = 6,
119 IME_STATE_INIT_FAILED = 7
120 } tImeStateEnum;
121
122
123 typedef enum tImeUpdateType
124 {
125 IME_UPDTYPE_NORMAL = 1,
126 IME_UPDTYPE_MANUAL_ROLLBACK = 3,
127 IME_UPDTYPE_ABORT = 4
128 } tImeUpdateType;
129
130
131 #ifdef HAVE_PRAGMA_PACK
132 #pragma pack(1)
133 #endif
134 typedef struct sImeStatus {
135 uint8_t image_status;
136 tImeStateEnum update_state;
137 uint8_t update_attempt_status;
138 uint8_t rollback_attempt_status;
139 uint8_t update_type;
140 uint8_t dependent_flag;
141 uint8_t free_area_size[4];
142 } ATTRIBUTE_PACKING tImeStatus ;
143 #ifdef HAVE_PRAGMA_PACK
144 #pragma pack(0)
145 #endif
146
147 #ifdef HAVE_PRAGMA_PACK
148 #pragma pack(1)
149 #endif
150 typedef struct sImeCaps {
151 uint8_t area_supported;
152 uint8_t special_caps;
153 } ATTRIBUTE_PACKING tImeCaps ;
154 #ifdef HAVE_PRAGMA_PACK
155 #pragma pack(0)
156 #endif
157
158
159 static void ImePrintUsage(void);
160 static int ImeGetInfo(struct ipmi_intf *intf);
161 static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename);
162 static int ImeManualRollback(struct ipmi_intf *intf);
163 static int ImeUpdatePrepare(struct ipmi_intf *intf);
164 static int ImeUpdateOpenArea(struct ipmi_intf *intf);
165 static int ImeUpdateWriteArea(
166 struct ipmi_intf *intf,
167 uint8_t sequence,
168 uint8_t length,
169 uint8_t * pBuf
170 );
171 static int ImeUpdateCloseArea(
172 struct ipmi_intf *intf,
173 uint32_t size,
174 uint16_t checksum
175 );
176
177 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus);
178 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps );
179 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type);
180
181 static int ImeImageCtxFromFile(
182 char * imageFilename,
183 tImeUpdateImageCtx * pImageCtx);
184 static int ImeUpdateShowStatus(struct ipmi_intf *intf);
185
186 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf );
187
188
ImeGetInfo(struct ipmi_intf * intf)189 static int ImeGetInfo(struct ipmi_intf *intf)
190 {
191 int rc = IME_ERROR;
192 struct ipmi_rs * rsp;
193 struct ipmi_rq req;
194 struct ipm_devid_rsp *devid;
195 const char *product=NULL;
196 tImeStatus status;
197 tImeCaps caps;
198
199 memset(&req, 0, sizeof(req));
200 req.msg.netfn = IPMI_NETFN_APP;
201 req.msg.cmd = BMC_GET_DEVICE_ID;
202 req.msg.data_len = 0;
203
204 rsp = intf->sendrecv(intf, &req);
205 if (rsp == NULL) {
206 lprintf(LOG_ERR, "Get Device ID command failed");
207 return IME_ERROR;
208 }
209 if (rsp->ccode > 0) {
210 lprintf(LOG_ERR, "Get Device ID command failed: %s",
211 val2str(rsp->ccode, completion_code_vals));
212 return IME_ERROR;
213 }
214
215 devid = (struct ipm_devid_rsp *) rsp->data;
216
217 lprintf(LOG_DEBUG,"Device ID : %i", devid->device_id);
218 lprintf(LOG_DEBUG,"Device Revision : %i",
219 devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK);
220
221 if(
222 (devid->device_id == 0)
223 &&
224 ((devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK) == 0)
225 &&
226 (
227 (devid->manufacturer_id[0] == 0x57) // Intel
228 &&
229 (devid->manufacturer_id[1] == 0x01) // Intel
230 &&
231 (devid->manufacturer_id[2] == 0x00) // Intel
232 )
233 &&
234 (
235 (devid->product_id[1] == 0x0b)
236 &&
237 (devid->product_id[0] == 0x00)
238 )
239 )
240 {
241 rc = IME_SUCCESS;
242 printf("Manufacturer Name : %s\n",
243 val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
244 ipmi_oem_info) );
245
246 printf("Product ID : %u (0x%02x%02x)\n",
247 buf2short((uint8_t *)(devid->product_id)),
248 devid->product_id[1], devid->product_id[0]);
249
250 product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
251 (devid->product_id[1]<<8)+devid->product_id[0],
252 ipmi_oem_product_info);
253
254 if (product!=NULL)
255 {
256 printf("Product Name : %s\n", product);
257 }
258
259 printf("Intel ME Firmware Revision : %x.%02x.%02x.%x%x%x.%x\n",
260 ((devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK ) ),
261 ((devid->fw_rev2 ) >> 4),
262 ((devid->fw_rev2 ) & 0x0f),
263 ((devid->aux_fw_rev[1] ) >> 4),
264 ((devid->aux_fw_rev[1] ) & 0x0f),
265 ((devid->aux_fw_rev[2] ) >> 4),
266 ((devid->aux_fw_rev[2] ) & 0x0f)
267 );
268
269 printf("SPS FW IPMI cmd version : %x.%x\n",
270 devid->aux_fw_rev[0] >> 4,
271 devid->aux_fw_rev[0] & 0x0f);
272
273 lprintf(LOG_DEBUG,"Flags: %xh", devid->aux_fw_rev[3]);
274
275 printf("Current Image Type : ");
276 switch( (devid->aux_fw_rev[3] & 0x03) )
277 {
278 case 0:
279 printf("Recovery\n");
280 break;
281
282 case 1:
283 printf("Operational Image 1\n");
284 break;
285
286 case 2:
287 printf("Operational Image 2\n");
288 break;
289
290 case 3:
291 default:
292 printf("Unknown\n");
293 break;
294 }
295 }
296 else
297 {
298 printf("Supported ME not found\n");
299 }
300
301 if(rc == IME_SUCCESS)
302 {
303 rc = ImeUpdateGetStatus(intf, &status);
304
305 if(rc == IME_SUCCESS)
306 {
307 rc = ImeUpdateGetCapabilities(intf, &caps);
308 }
309
310 }
311
312 if(rc == IME_SUCCESS)
313 {
314 uint8_t newImage = ((status.image_status >> 1) & 0x01);
315 uint8_t rollImage = ((status.image_status >> 2) & 0x01);
316 uint8_t runArea = ((status.image_status >> 3) & 0x03);
317 uint8_t rollSup = ((caps.special_caps >> 0) & 0x01);
318 uint8_t recovSup = ((caps.special_caps >> 1) & 0x01);
319
320 uint8_t operSup = ((caps.area_supported >> 1) & 0x01);
321 uint8_t piaSup = ((caps.area_supported >> 2) & 0x01);
322 uint8_t sdrSup = ((caps.area_supported >> 3) & 0x01);
323
324 printf("\nSupported Area\n");
325 printf(" Operation Code : %s\n", (operSup ? "Supported" : "Unsupported"));
326 printf(" PIA : %s\n", (piaSup ? "Supported" : "Unsupported"));
327 printf(" SDR : %s\n", (sdrSup ? "Supported" : "Unsupported"));
328
329 printf("\nSpecial Capabilities\n");
330 printf(" Rollback : %s\n", (rollSup ? "Supported" : "Unsupported"));
331 printf(" Recovery : %s\n", (recovSup ? "Supported" : "Unsupported"));
332
333 printf("\nImage Status\n");
334 printf(" Staging (new) : %s\n", (newImage ? "Valid" : "Invalid"));
335 printf(" Rollback : %s\n", (rollImage ? "Valid" : "Invalid"));
336 if(runArea == 0)
337 printf(" Running Image Area : CODE\n");
338 else
339 printf(" Running Image Area : CODE%d\n", runArea);
340
341 }
342
343 return rc;
344 }
345
346
ImeUpgrade(struct ipmi_intf * intf,char * imageFilename)347 static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename)
348 {
349 int rc = IME_SUCCESS;
350 tImeUpdateImageCtx imgCtx;
351 tImeStatus imeStatus;
352 time_t start,end,current;
353
354 time(&start);
355
356 memset(&imgCtx, 0, sizeof(tImeUpdateImageCtx));
357
358 rc = ImeImageCtxFromFile(imageFilename, &imgCtx);
359
360 if(
361 (rc == IME_ERROR) ||
362 (imgCtx.pData == NULL) ||
363 (imgCtx.size == 0)
364 )
365 {
366 return IME_ERROR;
367 }
368
369 ImeUpdateGetStatus(intf,&imeStatus);
370
371 if(rc == IME_SUCCESS)
372 {
373 rc = ImeUpdatePrepare(intf);
374 ImeUpdateGetStatus(intf,&imeStatus);
375 }
376
377 if(
378 (rc == IME_SUCCESS) &&
379 (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
380 )
381 {
382 rc = ImeUpdateOpenArea(intf);
383 ImeUpdateGetStatus(intf,&imeStatus);
384 }
385 else if(rc == IME_SUCCESS)
386 {
387 lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
388 rc = IME_ERROR;
389 }
390
391
392 if(
393 (rc == IME_SUCCESS) &&
394 (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
395 )
396 {
397 uint8_t sequence = 0;
398 uint32_t counter = 0;
399 uint8_t retry = 0;
400 uint8_t shownPercent = 0xff;
401
402 while(
403 (counter < imgCtx.size) &&
404 (rc == IME_SUCCESS) &&
405 (retry < IME_RETRY_COUNT)
406 )
407 {
408 uint8_t length = IME_UPGRADE_BUFFER_SIZE;
409 uint8_t currentPercent;
410
411 if( (imgCtx.size - counter) < IME_UPGRADE_BUFFER_SIZE )
412 {
413 length = (imgCtx.size - counter);
414 }
415
416 rc = ImeUpdateWriteArea(intf,sequence,length,&imgCtx.pData[counter]);
417
418 /*
419 As per the flowchart Intel Dynamic Power Node Manager 1.5 IPMI Iface
420 page 65
421 We shall send the GetStatus command each time following a write area
422 but this add too much time to the upgrade
423 */
424 /* ImeUpdateGetStatus(intf,&imeStatus); */
425 counter += length;
426 sequence ++;
427
428
429 currentPercent = ((float)counter/imgCtx.size)*100;
430
431 if(currentPercent != shownPercent)
432 {
433 uint16_t timeElapsedSecond;
434 shownPercent = currentPercent;
435 printf("Percent: %02i, ", shownPercent);
436 time(¤t);
437 timeElapsedSecond = (current-start) + ((current-start)%60);
438 printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60));
439 fflush(stdout);
440
441 }
442 }
443 ImeUpdateGetStatus(intf,&imeStatus);
444 printf("\n");
445 }
446 else if(rc == IME_SUCCESS)
447 {
448 lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
449 rc = IME_ERROR;
450 }
451
452 if(
453 (rc == IME_SUCCESS) &&
454 (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
455 )
456 {
457 rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8);
458 ImeUpdateGetStatus(intf,&imeStatus);
459 }
460 else if(rc == IME_SUCCESS)
461 {
462 lprintf(LOG_ERROR,"ME state error, aborting");
463 rc = IME_ERROR;
464 }
465
466 if(
467 (rc == IME_SUCCESS) &&
468 (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
469 )
470 {
471 printf("UpdateCompleted, Activate now\n");
472 rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL);
473 ImeUpdateGetStatus(intf,&imeStatus);
474 }
475 else if(rc == IME_SUCCESS)
476 {
477 lprintf(LOG_ERROR,"ME state error, aborting");
478 rc = IME_ERROR;
479 }
480
481 if(
482 (rc == IME_SUCCESS) &&
483 (imeStatus.update_state == IME_STATE_SUCCESS)
484 )
485 {
486 time(&end);
487 printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60);
488 }
489 else
490 {
491 time(&end);
492 printf("Update Error\n");
493 printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60);
494 }
495
496 return rc;
497 }
498
499
ImeUpdatePrepare(struct ipmi_intf * intf)500 static int ImeUpdatePrepare(struct ipmi_intf *intf)
501 {
502 struct ipmi_rs * rsp;
503 struct ipmi_rq req;
504
505 #ifdef OUTPUT_DEBUG
506 printf("ImeUpdatePrepare\n");
507 #endif
508
509 memset(&req, 0, sizeof(req));
510 req.msg.netfn = 0x30; // OEM NetFn
511 req.msg.cmd = 0xA0;
512 req.msg.data_len = 0;
513
514 rsp = intf->sendrecv(intf, &req);
515 if (rsp == NULL) {
516 lprintf(LOG_ERR, "UpdatePrepare command failed");
517 return IME_ERROR;
518 }
519 if (rsp->ccode > 0) {
520 lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
521 val2str(rsp->ccode, completion_code_vals));
522 return IME_ERROR;
523 }
524
525 lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
526 return IME_SUCCESS;
527 }
528
ImeUpdateOpenArea(struct ipmi_intf * intf)529 static int ImeUpdateOpenArea(struct ipmi_intf *intf)
530 {
531 struct ipmi_rs * rsp;
532 struct ipmi_rq req;
533 uint8_t buffer[ 2 ];
534
535 #ifdef OUTPUT_DEBUG
536 printf("ImeUpdateOpenArea\n");
537 #endif
538
539 memset(&req, 0, sizeof(req));
540 req.msg.netfn = 0x30; // OEM NetFn
541 req.msg.cmd = 0xA1;
542
543 buffer[0] = 0x01; // Area Type : Operational code
544 buffer[1] = 0x00; // Reserved : 0
545 req.msg.data = buffer;
546
547 req.msg.data_len = 2;
548
549 rsp = intf->sendrecv(intf, &req);
550 if (rsp == NULL) {
551 lprintf(LOG_ERR, "UpdateOpenArea command failed");
552 return IME_ERROR;
553 }
554 if (rsp->ccode > 0) {
555 lprintf(LOG_ERR, "UpdateOpenArea command failed: %s",
556 val2str(rsp->ccode, completion_code_vals));
557 return IME_ERROR;
558 }
559
560 lprintf(LOG_DEBUG, "UpdateOpenArea command succeed");
561 return IME_SUCCESS;
562 }
563
ImeUpdateWriteArea(struct ipmi_intf * intf,uint8_t sequence,uint8_t length,uint8_t * pBuf)564 static int ImeUpdateWriteArea(
565 struct ipmi_intf *intf,
566 uint8_t sequence,
567 uint8_t length,
568 uint8_t * pBuf
569 )
570 {
571 struct ipmi_rs * rsp;
572 struct ipmi_rq req;
573 uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ];
574
575 // printf("ImeUpdateWriteArea %i\n", sequence);
576
577 if(length > IME_UPGRADE_BUFFER_SIZE)
578 return IME_ERROR;
579
580 buffer[0] = sequence;
581 memcpy(&buffer[1], pBuf, length);
582
583 memset(&req, 0, sizeof(req));
584 req.msg.netfn = 0x30; // OEM NetFn
585 req.msg.cmd = 0xA2;
586 req.msg.data = buffer;
587 req.msg.data_len = length + 1;
588
589 rsp = intf->sendrecv(intf, &req);
590 if (rsp == NULL) {
591 lprintf(LOG_ERR, "UpdateWriteArea command failed");
592 return IME_ERROR;
593 }
594 if (rsp->ccode > 0) {
595 lprintf(LOG_ERR, "UpdateWriteArea command failed: %s",
596 val2str(rsp->ccode, completion_code_vals));
597 if( rsp->ccode == 0x80) // restart operation
598 return IME_RESTART;
599 else
600 return IME_ERROR;
601 }
602
603 lprintf(LOG_DEBUG, "UpdateWriteArea command succeed");
604 return IME_SUCCESS;
605 }
606
ImeUpdateCloseArea(struct ipmi_intf * intf,uint32_t size,uint16_t checksum)607 static int ImeUpdateCloseArea(
608 struct ipmi_intf *intf,
609 uint32_t size,
610 uint16_t checksum
611 )
612 {
613 struct ipmi_rs * rsp;
614 struct ipmi_rq req;
615 uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t );
616 uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ];
617
618 #ifdef OUTPUT_DEBUG
619 printf( "ImeUpdateCloseArea\n");
620 #endif
621
622 buffer[0] = (uint8_t)((size & 0x000000ff) >> 0);
623 buffer[1] = (uint8_t)((size & 0x0000ff00) >> 8);
624 buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16);
625 buffer[3] = (uint8_t)((size & 0xff000000) >> 24);
626
627 buffer[4] = (uint8_t)((checksum & 0x00ff) >> 0);
628 buffer[5] = (uint8_t)((checksum & 0xff00) >> 8);
629
630 memset(&req, 0, sizeof(req));
631 req.msg.netfn = 0x30; // OEM NetFn
632 req.msg.cmd = 0xA3;
633 req.msg.data = buffer;
634 req.msg.data_len = length;
635
636 rsp = intf->sendrecv(intf, &req);
637 if (rsp == NULL) {
638 lprintf(LOG_ERR, "UpdateCloseArea command failed");
639 return IME_ERROR;
640 }
641 if (rsp->ccode > 0) {
642 lprintf(LOG_ERR, "UpdateCloseArea command failed: %s",
643 val2str(rsp->ccode, completion_code_vals));
644 return IME_ERROR;
645 }
646
647 lprintf(LOG_DEBUG, "UpdateCloseArea command succeed");
648 return IME_SUCCESS;
649 }
650
ImeUpdateGetStatus(struct ipmi_intf * intf,tImeStatus * pStatus)651 static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus )
652 {
653 struct ipmi_rs * rsp;
654 struct ipmi_rq req;
655 tImeStatus *pGetStatus;
656
657 memset(pStatus, 0, sizeof(tImeStatus));
658 pStatus->update_state = IME_STATE_ABORTED;
659
660
661 #ifdef OUTPUT_DEBUG
662 printf("ImeUpdateGetStatus: ");
663 #endif
664
665 memset(&req, 0, sizeof(req));
666 req.msg.netfn = 0x30; // OEM NetFn
667 req.msg.cmd = 0xA6;
668 req.msg.data_len = 0;
669
670 rsp = intf->sendrecv(intf, &req);
671 if (rsp == NULL) {
672 lprintf(LOG_ERR, "UpdatePrepare command failed");
673 return IME_ERROR;
674 }
675 if (rsp->ccode > 0) {
676 lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
677 val2str(rsp->ccode, completion_code_vals));
678 return IME_ERROR;
679 }
680
681 lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
682
683 pGetStatus = (tImeStatus *) rsp->data;
684
685 memcpy( pStatus, pGetStatus, sizeof(tImeStatus));
686
687 #ifdef OUTPUT_DEBUG
688 printf("%x - ", pStatus->updateState);
689
690 switch( pStatus->update_state )
691 {
692 case IME_STATE_IDLE:
693 printf("IDLE\n");
694 break;
695 case IME_STATE_UPDATE_REQUESTED:
696 printf("Update Requested\n");
697 break;
698 case IME_STATE_UPDATE_IN_PROGRESS:
699 printf("Update in Progress\n");
700 break;
701 case IME_STATE_SUCCESS:
702 printf("Update Success\n");
703 break;
704 case IME_STATE_FAILED:
705 printf("Update Failed\n");
706 break;
707 case IME_STATE_ROLLED_BACK:
708 printf("Update Rolled Back\n");
709 break;
710 case IME_STATE_ABORTED:
711 printf("Update Aborted\n");
712 break;
713 case IME_STATE_INIT_FAILED:
714 printf("Update Init Failed\n");
715 break;
716 default:
717 printf("Unknown, reserved\n");
718 break;
719 }
720 #endif
721
722 return IME_SUCCESS;
723 }
724
ImeUpdateGetCapabilities(struct ipmi_intf * intf,tImeCaps * pCaps)725 static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps )
726 {
727 struct ipmi_rs * rsp;
728 struct ipmi_rq req;
729 tImeCaps * pGetCaps;
730
731 memset(pCaps, 0, sizeof(tImeCaps));
732
733
734 #ifdef OUTPUT_DEBUG
735 printf("ImeUpdateGetStatus: ");
736 #endif
737
738 memset(&req, 0, sizeof(req));
739 req.msg.netfn = 0x30; // OEM NetFn
740 req.msg.cmd = 0xA7;
741 req.msg.data_len = 0;
742
743 rsp = intf->sendrecv(intf, &req);
744 if (rsp == NULL) {
745 lprintf(LOG_ERR, "UpdatePrepare command failed");
746 return IME_ERROR;
747 }
748 if (rsp->ccode > 0) {
749 lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
750 val2str(rsp->ccode, completion_code_vals));
751 return IME_ERROR;
752 }
753
754 lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
755
756 pGetCaps = (tImeCaps *) rsp->data;
757
758 memcpy( pCaps, pGetCaps, sizeof(tImeCaps));
759
760 return IME_SUCCESS;
761 }
762
763
ImeUpdateRegisterUpdate(struct ipmi_intf * intf,tImeUpdateType type)764 static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type)
765 {
766 struct ipmi_rs * rsp;
767 struct ipmi_rq req;
768 uint8_t buffer[ 2 ];
769
770 #ifdef OUTPUT_DEBUG
771 printf( "ImeUpdateRegisterUpdate\n");
772 #endif
773
774 buffer[0] = type; // Normal Update
775 buffer[1] = 0; // Flags, reserved
776
777 memset(&req, 0, sizeof(req));
778 req.msg.netfn = 0x30; // OEM NetFn
779 req.msg.cmd = 0xA4;
780 req.msg.data = buffer;
781 req.msg.data_len = 2;
782
783 rsp = intf->sendrecv(intf, &req);
784 if (rsp == NULL) {
785 lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed");
786 return IME_ERROR;
787 }
788 if (rsp->ccode > 0) {
789 lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s",
790 val2str(rsp->ccode, completion_code_vals));
791 return IME_ERROR;
792 }
793
794 lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed");
795 return IME_SUCCESS;
796 }
797
798
799
800
ImeUpdateShowStatus(struct ipmi_intf * intf)801 static int ImeUpdateShowStatus(struct ipmi_intf *intf)
802 {
803 struct ipmi_rs * rsp;
804 struct ipmi_rq req;
805 tImeStatus *pStatus;
806
807 printf("ImeUpdateGetStatus: ");
808
809 memset(&req, 0, sizeof(req));
810 req.msg.netfn = 0x30; // OEM NetFn
811 req.msg.cmd = 0xA6;
812 req.msg.data_len = 0;
813
814 rsp = intf->sendrecv(intf, &req);
815 if (rsp == NULL) {
816 lprintf(LOG_ERR, "UpdatePrepare command failed");
817 return IME_ERROR;
818 }
819 if (rsp->ccode > 0) {
820 lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
821 val2str(rsp->ccode, completion_code_vals));
822 return IME_ERROR;
823 }
824
825 lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
826
827 pStatus = (tImeStatus *) rsp->data ;
828
829
830 printf("image_status: %x - ", pStatus->image_status);
831
832 printf("update_state: %x - ", pStatus->update_state);
833
834 switch( pStatus->update_state )
835 {
836 case IME_STATE_IDLE:
837 printf("IDLE\n");
838 break;
839 case IME_STATE_UPDATE_REQUESTED:
840 printf("Update Requested\n");
841 break;
842 case IME_STATE_UPDATE_IN_PROGRESS:
843 printf("Update in Progress\n");
844 break;
845 case IME_STATE_SUCCESS:
846 printf("Update Success\n");
847 break;
848 case IME_STATE_FAILED:
849 printf("Update Failed\n");
850 break;
851 case IME_STATE_ROLLED_BACK:
852 printf("Update Rolled Back\n");
853 break;
854 case IME_STATE_ABORTED:
855 printf("Update Aborted\n");
856 break;
857 case IME_STATE_INIT_FAILED:
858 printf("Update Init Failed\n");
859 break;
860 default:
861 printf("Unknown, reserved\n");
862 break;
863 }
864 printf("update_attempt_status : %x\n", pStatus->update_attempt_status);
865 printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status);
866 printf("update_type : %x\n", pStatus->update_type);
867 printf("dependent_flag : %x\n", pStatus->dependent_flag);
868 printf("free_area_size : %x\n", pStatus->free_area_size[0]);
869 printf(" : %x\n", pStatus->free_area_size[1]);
870 printf(" : %x\n", pStatus->free_area_size[2]);
871 printf(" : %x\n", pStatus->free_area_size[3]);
872
873 return IME_SUCCESS;
874 }
875
876
ImeImageCtxFromFile(char * imageFilename,tImeUpdateImageCtx * pImageCtx)877 static int ImeImageCtxFromFile(
878 char* imageFilename,
879 tImeUpdateImageCtx * pImageCtx
880 )
881 {
882 int rc = IME_SUCCESS;
883 FILE* pImageFile = fopen(imageFilename, "rb");
884
885 if ( pImageFile == NULL )
886 {
887 lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename);
888 rc = IME_ERROR;
889 }
890
891 if ( rc == IME_SUCCESS )
892 {
893 /* Get the raw data in file */
894 fseek(pImageFile, 0, SEEK_END);
895 pImageCtx->size = ftell(pImageFile);
896 if (pImageCtx->size <= 0) {
897 if (pImageCtx->size < 0)
898 lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno));
899 rc = IME_ERROR;
900 fclose(pImageFile);
901 return rc;
902 }
903 pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size);
904 rewind(pImageFile);
905
906 if ( pImageCtx->pData != NULL )
907 {
908 if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char),
909 pImageCtx->size, pImageFile))
910 rc = IME_ERROR;
911 }
912 else
913 {
914 rc = IME_ERROR;
915 }
916 }
917
918 // Calculate checksum CRC8
919 if ( rc == IME_SUCCESS )
920 {
921 pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData);
922 }
923
924
925 if( pImageFile != NULL)
926 {
927 fclose(pImageFile);
928 }
929
930 return rc;
931 }
932
ImeCrc8(uint32_t length,uint8_t * pBuf)933 static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf )
934 {
935 uint8_t crc = 0;
936 uint32_t bufCount;
937
938 for ( bufCount = 0; bufCount < length; bufCount++ )
939 {
940 uint8_t count;
941
942 crc = crc ^ pBuf[bufCount];
943
944 for ( count = 0; count < 8; count++ )
945 {
946 if (( crc & 0x80 ) != 0 )
947 {
948 crc <<= 1;
949 crc ^= 0x07;
950 }
951 else
952 {
953 crc <<= 1;
954 }
955 }
956 }
957
958 lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc);
959 return crc;
960 }
961
962
ImeManualRollback(struct ipmi_intf * intf)963 static int ImeManualRollback(struct ipmi_intf *intf)
964 {
965 int rc = IME_SUCCESS;
966 tImeStatus imeStatus;
967
968 rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK);
969 ImeUpdateGetStatus(intf,&imeStatus);
970
971
972 if(
973 (rc == IME_SUCCESS) &&
974 (imeStatus.update_state == IME_STATE_ROLLED_BACK)
975 )
976 {
977 printf("Manual Rollback Succeed\n");
978 return IME_SUCCESS;
979 }
980 else
981 {
982 printf("Manual Rollback Completed With Error\n");
983 return IME_ERROR;
984 }
985 }
986
987
988
ImePrintUsage(void)989 static void ImePrintUsage(void)
990 {
991 lprintf(LOG_NOTICE,"help - This help menu");
992 lprintf(LOG_NOTICE,"info - Information about the present Intel ME");
993 lprintf(LOG_NOTICE,"update <file> - Upgrade the ME firmware from received image <file>");
994 lprintf(LOG_NOTICE,"rollback - Manual Rollback ME");
995 // lprintf(LOG_NOTICE,"rollback - Rollback ME Firmware");
996 }
997
998
999
ipmi_ime_main(struct ipmi_intf * intf,int argc,char ** argv)1000 int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv)
1001 {
1002 int rc = IME_SUCCESS;
1003
1004 lprintf(LOG_DEBUG,"ipmi_ime_main()");
1005
1006
1007 if ( (argc == 0) || (strcmp(argv[0], "help") == 0) )
1008 {
1009 ImePrintUsage();
1010 }
1011 else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) )
1012 {
1013 rc = ImeGetInfo(intf);
1014 }
1015 else if ( strcmp(argv[0], "update") == 0)
1016 {
1017 if(argc == 2)
1018 {
1019 lprintf(LOG_NOTICE,"Update using file: %s", argv[1]);
1020 rc = ImeUpgrade(intf, argv[1]);
1021 }
1022 else
1023 {
1024 lprintf(LOG_ERROR,"File must be provided with this option, see help\n");
1025 rc = IME_ERROR;
1026 }
1027 }
1028 else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) )
1029 {
1030 rc = ImeManualRollback(intf);
1031 }
1032 else
1033 {
1034 ImePrintUsage();
1035 }
1036
1037 return rc;
1038 }
1039
1040
1041
1042