bootctrl.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /* Copyright Statement:
  2. *
  3. * This software/firmware and related documentation ("MediaTek Software") are
  4. * protected under relevant copyright laws. The information contained herein is
  5. * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
  6. * the prior written permission of MediaTek inc. and/or its licensors, any
  7. * reproduction, modification, use or disclosure of MediaTek Software, and
  8. * information contained herein, in whole or in part, shall be strictly
  9. * prohibited.
  10. *
  11. * MediaTek Inc. (C) 2016. All rights reserved.
  12. *
  13. * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
  14. * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
  15. * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
  16. * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
  17. * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  19. * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
  20. * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
  21. * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
  22. * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
  23. * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
  24. * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
  25. * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
  26. * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
  27. * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
  28. * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
  29. * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
  30. * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
  31. * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
  32. *
  33. * The following software/firmware and/or related documentation ("MediaTek
  34. * Software") have been modified by MediaTek Inc. All revisions are subject to
  35. * any receiver's applicable license agreements with MediaTek Inc.
  36. */
  37. #include <errno.h>
  38. #include <fcntl.h>
  39. #include <unistd.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <hardware/hardware.h>
  44. #include <hardware/boot_control.h>
  45. #include <android-base/logging.h>
  46. #include <cutils/properties.h>
  47. #define LOG_TAG "bootctrlHAL"
  48. #include <log/log.h>
  49. #include "bootctrl.h"
  50. #if !defined(ARCH_X86)
  51. #include <linux/scsi/ufs/ufs-mtk-ioctl.h>
  52. #include <linux/mmc/mmc-mtk-ioctl.h>
  53. #include <sys/ioctl.h>
  54. #endif
  55. #include <fstab.h>
  56. #include <bootloader_message/bootloader_message.h>
  57. // Debug for update_engine_sideload
  58. //#define ALOGE printf
  59. //#define ALOGI printf
  60. using android::fs_mgr::Fstab;
  61. using android::fs_mgr::GetEntryForMountPoint;
  62. using android::fs_mgr::ReadDefaultFstab;
  63. static char *blk_dev_path = NULL;
  64. static int bootctrl_read_metadata(boot_ctrl_t *bctrl)
  65. {
  66. int fd, err;
  67. ssize_t sz, size;
  68. char *buf = (char *)bctrl;
  69. fd = open(blk_dev_path, O_RDONLY);
  70. if (fd < 0) {
  71. err = errno;
  72. ALOGE("%s Error opening metadata file: %s\n", __func__ ,strerror(errno));
  73. return -err;
  74. }
  75. if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
  76. err = errno;
  77. ALOGE("%s Error seeking to metadata offset: %s\n", __func__ ,strerror(errno));
  78. close(fd);
  79. return -err;
  80. }
  81. size = sizeof(boot_ctrl_t);
  82. do {
  83. sz = read(fd, buf, size);
  84. if (sz == 0) {
  85. break;
  86. } else if (sz < 0) {
  87. if (errno == EINTR) {
  88. continue;
  89. }
  90. err = -errno;
  91. ALOGE("%s Error reading metadata file\n", __func__);
  92. close(fd);
  93. return err;
  94. }
  95. size -= sz;
  96. buf += sz;
  97. } while(size > 0);
  98. close(fd);
  99. /* Check bootctrl magic number */
  100. if (bctrl->magic != BOOTCTRL_MAGIC) {
  101. ALOGE("metadata is not initialised or corrupted.\n");
  102. return -EIO;
  103. }
  104. return 0;
  105. }
  106. static int bootctrl_write_metadata(boot_ctrl_t *bctrl)
  107. {
  108. int fd, err;
  109. ssize_t sz, size;
  110. char *buf = (char *)bctrl;
  111. fd = open(blk_dev_path, O_RDWR);
  112. if (fd < 0) {
  113. err = errno;
  114. ALOGE("%s Error opening metadata file: %s\n", __func__,strerror(errno));
  115. return -err;
  116. }
  117. if (lseek(fd, OFFSETOF_SLOT_SUFFIX, SEEK_SET) < 0) {
  118. err = errno;
  119. ALOGE("%s Error seeking to metadata offset: %s\n", __func__ ,strerror(errno));
  120. close(fd);
  121. return -err;
  122. }
  123. size = sizeof(boot_ctrl_t);
  124. do {
  125. sz = write(fd, buf, size);
  126. if (sz == 0) {
  127. break;
  128. } else if (sz < 0) {
  129. if (errno == EINTR) {
  130. continue;
  131. }
  132. err = -errno;
  133. ALOGE("%s Error Writing metadata file\n",__func__);
  134. close(fd);
  135. return err;
  136. }
  137. size -= sz;
  138. buf += sz;
  139. } while(size > 0);
  140. close(fd);
  141. return 0;
  142. }
  143. void bootctrl_init(boot_control_module_t *module __unused)
  144. {
  145. static Fstab fstab;
  146. ALOGI("boot control HAL init");
  147. if(blk_dev_path == NULL) {
  148. /* Initial read fstab */
  149. if(!ReadDefaultFstab(&fstab)) {
  150. ALOGE("bootctrl read fstab fail\n");
  151. return;
  152. }
  153. auto v = GetEntryForMountPoint(&fstab, "/misc");
  154. if (v == nullptr) {
  155. LOG(ERROR)<<"failed to get block device path by mount point";
  156. return;
  157. }
  158. blk_dev_path = strdup(v->blk_device.c_str());
  159. }
  160. ALOGI("%s misc blk device path = %s\n", __func__ ,blk_dev_path);
  161. }
  162. unsigned bootctrl_get_number_slots(boot_control_module_t *module __unused)
  163. {
  164. return 2;
  165. }
  166. int bootctrl_get_active_slot()
  167. {
  168. int fd, err, slot;
  169. ssize_t size = COMMAND_LINE_SIZE, sz;
  170. char *buf, *ptr;
  171. char *str;
  172. fd = open(COMMAND_LINE_PATH, O_RDONLY);
  173. if (fd < 0) {
  174. err = -errno;
  175. ALOGE("%s error reading commandline\n", __func__);
  176. return err;
  177. }
  178. ptr = buf = (char *)malloc(size);
  179. if (!buf) {
  180. err = -errno;
  181. ALOGE("%s Error allocating memory\n", __func__);
  182. close(fd);
  183. return err;
  184. }
  185. do {
  186. sz = read(fd, buf, size);
  187. if (sz == 0) {
  188. break;
  189. } else if (sz < 0) {
  190. if (errno == EINTR) {
  191. continue;
  192. }
  193. err = -errno;
  194. ALOGE("%s Error reading file\n",__func__);
  195. free(ptr);
  196. close(fd);
  197. return err;
  198. }
  199. size -= sz;
  200. buf += sz;
  201. } while(size > 0);
  202. str = strstr((char *)ptr, SLOT_SUFFIX_STR);
  203. if (!str) {
  204. err = -EIO;
  205. ALOGE("%s cannot find %s in kernel commandline.\n", __func__ , SLOT_SUFFIX_STR);
  206. free(ptr);
  207. close(fd);
  208. return err;
  209. }
  210. str += sizeof(SLOT_SUFFIX_STR);
  211. slot = (*str == 'a') ? 0 : 1;
  212. free(ptr);
  213. close(fd);
  214. return slot;
  215. }
  216. static int mmc_read_extcsd(int fd, __u8 *ext_csd)
  217. {
  218. int ret = 0;
  219. struct mmc_ioc_cmd mmc_ioctl_cmd;
  220. memset(ext_csd, 0, sizeof(__u8) * 512);
  221. memset(&mmc_ioctl_cmd, 0, sizeof(mmc_ioctl_cmd));
  222. mmc_ioctl_cmd.blocks = 1;
  223. mmc_ioctl_cmd.blksz = 512;
  224. mmc_ioctl_cmd.opcode = MMC_SEND_EXT_CSD;
  225. mmc_ioctl_cmd.flags = MMC_CMD_ADTC | MMC_RSP_R1;
  226. mmc_ioc_cmd_set_data(mmc_ioctl_cmd, ext_csd);
  227. ret = ioctl(fd, MMC_IOC_CMD, &mmc_ioctl_cmd);
  228. if (ret)
  229. ALOGE("ioctl error, mmc_read_extcsd fail, ret = %d\n", ret);
  230. return ret;
  231. }
  232. static int mmc_switch_bootpart(int fd, __u8 *ext_csd, __u8 bootpart)
  233. {
  234. int ret = 0;
  235. struct mmc_ioc_cmd mmc_ioctl_cmd;
  236. __u8 val;
  237. val = (ext_csd[EXT_CSD_PART_CONFIG] & ~(0x38)) | (bootpart << 3);
  238. memset(&mmc_ioctl_cmd, 0, sizeof(mmc_ioctl_cmd));
  239. mmc_ioctl_cmd.opcode = MMC_SWITCH;
  240. mmc_ioctl_cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24)
  241. | (EXT_CSD_PART_CONFIG << 16)
  242. | val << 8
  243. | EXT_CSD_CMD_SET_NORMAL;
  244. mmc_ioctl_cmd.flags = MMC_CMD_AC | MMC_RSP_R1B;
  245. mmc_ioc_cmd_set_data(mmc_ioctl_cmd, ext_csd);
  246. ret = ioctl(fd, MMC_IOC_CMD, &mmc_ioctl_cmd);
  247. if (ret)
  248. ALOGE("ioctl error, mmc_switch_bootpart fail ret = %d\n", ret);
  249. return ret;
  250. }
  251. static int emmc_set_active_boot_part(int bootpart)
  252. {
  253. __u8 ext_csd[512];
  254. __u8 cur_bootpart;
  255. int ret;
  256. int fd= open("/dev/block/mmcblk0", O_RDWR);
  257. if (fd >= 0) {
  258. ret = mmc_read_extcsd(fd, ext_csd);
  259. if (ret) {
  260. ALOGE("Could not read EXT_CSD, error=%d\n", ret);
  261. close(fd);
  262. return 1;
  263. }
  264. /* check current boot part */
  265. cur_bootpart = (ext_csd[EXT_CSD_PART_CONFIG] >> 3) & 0x7;
  266. if (cur_bootpart == bootpart)
  267. {
  268. ALOGI("Current boot part is boot%d, no neeed switch\n", cur_bootpart);
  269. } else {
  270. ALOGI("Current boot part is boot%d, need switch to %d\n",cur_bootpart, bootpart);
  271. ret = mmc_switch_bootpart(fd, ext_csd, bootpart);
  272. if(ret) {
  273. ALOGE("Could not switch boot part, error=%d\n", ret);
  274. close(fd);
  275. return 1;
  276. }
  277. }
  278. close(fd);
  279. return 0;
  280. } else {
  281. ALOGE("open /dev/block/mmcblk0 fail\n");
  282. return 1;
  283. }
  284. }
  285. int ufs_set_active_boot_part(int boot)
  286. {
  287. struct ufs_ioctl_query_data idata;
  288. unsigned char buf[1];
  289. int fd, ret = 0;
  290. fd = open("/dev/block/sdc", O_RDWR);
  291. if (fd < 0) {
  292. printf("%s: open device failed, err: %d\n", __func__, fd);
  293. ret = -1;
  294. goto out;
  295. }
  296. buf[0] = boot; /* 1: BootLU A, 2: BootLU B */
  297. idata.opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
  298. idata.idn = QUERY_ATTR_IDN_BOOT_LUN_EN;
  299. idata.idx = 0;
  300. idata.buf_ptr = &buf[0];
  301. idata.buf_byte = 1;
  302. ret = ioctl(fd, UFS_IOCTL_QUERY, &idata);
  303. if(ret < 0)
  304. printf("ufs_set boot_part fail: %s\n", strerror(errno));
  305. out:
  306. if(fd >= 0)
  307. close(fd);
  308. return ret;
  309. }
  310. static int get_boot_type(void) {
  311. int fd;
  312. size_t s;
  313. char boot_type[4] = {'0'};
  314. fd = open("/sys/class/BOOT/BOOT/boot/boot_type", O_RDONLY);
  315. if (fd < 0) {
  316. ALOGE("fail to open: %s\n", "/sys/class/BOOT/BOOT/boot/boot_type");
  317. return -1;
  318. }
  319. s = read(fd, boot_type, sizeof(boot_type) - 1);
  320. close(fd);
  321. if (s <= 0) {
  322. ALOGE("could not read boot type sys file\n");
  323. return -1;
  324. }
  325. boot_type[s] = '\0';
  326. return atoi(boot_type);
  327. }
  328. static int set_ota_result(int result, int offset) {
  329. if (blk_dev_path == NULL) {
  330. printf("Error: blk_dev_path is NULL\n");
  331. return -1;
  332. }
  333. int dev = -1;
  334. int count;
  335. dev = open(blk_dev_path, O_WRONLY | O_SYNC);
  336. if (dev < 0) {
  337. printf("Can't open %s\n(%s)\n", blk_dev_path, strerror(errno));
  338. return -1;
  339. }
  340. if (lseek(dev, offset, SEEK_SET) == -1) {
  341. printf("Failed seeking %s\n(%s)\n", blk_dev_path, strerror(errno));
  342. close(dev);
  343. return -1;
  344. }
  345. count = write(dev, &result, sizeof(result));
  346. if (count != sizeof(result)) {
  347. printf("Failed writing %s\n(%s)\n", blk_dev_path, strerror(errno));
  348. close(dev);
  349. return -1;
  350. }
  351. if (close(dev) != 0) {
  352. printf("Failed closing %s\n(%s)\n", blk_dev_path, strerror(errno));
  353. return -1;
  354. }
  355. sync();
  356. return 1;
  357. }
  358. static int SetOTAResultForDMVerity(void) {
  359. int ota_result_offset, ret = -1;
  360. ota_result_offset = sizeof(bootloader_message_ab);
  361. ret = set_ota_result(1, ota_result_offset);
  362. return ret;
  363. }
  364. int switch_pl_boot_part(unsigned slot)
  365. {
  366. int ret = 0;
  367. int boot_part = 0;
  368. /* slot 0 is A , slot 1 is B */
  369. if (slot >= 2) {
  370. ALOGE("%s Wrong Slot value %u\n", __func__ , slot);
  371. return -1;
  372. }
  373. if(slot)
  374. boot_part = 2;
  375. else
  376. boot_part = 1;
  377. int mt_boot_type = get_boot_type();
  378. if(mt_boot_type == -1) {
  379. ALOGI("Get boot type failed then use default device type\n");
  380. mt_boot_type = FS_TYPE_EMMC;
  381. }
  382. /* EMMC */
  383. if(mt_boot_type == FS_TYPE_EMMC) {
  384. ALOGI("emmc_set_active_boot_part\n");
  385. ret = emmc_set_active_boot_part(boot_part);
  386. if(ret) {
  387. ALOGE("emmc set boot_part fail\n");
  388. return -1;
  389. }
  390. return 1;
  391. }
  392. /* UFS */
  393. if(mt_boot_type == FS_TYPE_UFS) {
  394. ALOGI ("boot_type is UFS\n");
  395. ret = ufs_set_active_boot_part(boot_part);
  396. if(ret) {
  397. ALOGE("ufs set boot_part fail\n");
  398. return -1;
  399. }
  400. return 1;
  401. }
  402. ALOGE("Un support phone type\n");
  403. return -1;
  404. }
  405. uint32_t bootctrl_get_current_slot(boot_control_module_t *module __unused)
  406. {
  407. ALOGI("boot control bootctrl_get_current_slot\n");
  408. uint32_t slot = 0;
  409. slot = bootctrl_get_active_slot();
  410. ALOGI("bootctrl_get_current_slot %d\n", slot);
  411. return slot;
  412. }
  413. int bootctrl_mark_boot_successful(boot_control_module_t *module __unused)
  414. {
  415. ALOGI("boot control bootctrl_mark_boot_successful\n");
  416. int ret;
  417. uint32_t slot = 0;
  418. boot_ctrl_t metadata;
  419. slot_metadata_t *slotp;
  420. ret = bootctrl_read_metadata(&metadata);
  421. if (ret < 0) {
  422. return ret;
  423. }
  424. slot = bootctrl_get_active_slot();
  425. if (slot < 0) {
  426. ALOGE("bootctrl_mark_boot_successful fail , slot = \n");
  427. return slot;
  428. }
  429. slotp = &metadata.slot_info[slot];
  430. slotp->successful_boot = 1;
  431. slotp->retry_count = 3;
  432. return bootctrl_write_metadata(&metadata);
  433. }
  434. int bootctrl_set_active_boot_slot(boot_control_module_t *module __unused,
  435. unsigned slot)
  436. {
  437. ALOGI("boot control bootctrl_set_active_boot_slot , slot is %d\n", slot);
  438. int ret, slot2;
  439. boot_ctrl_t metadata;
  440. slot_metadata_t *slotp;
  441. if (slot >= 2) {
  442. ALOGE("%s Wrong Slot value %u\n", __func__ , slot);
  443. return -EINVAL;
  444. }
  445. ret = bootctrl_read_metadata(&metadata);
  446. if (ret < 0) {
  447. return ret;
  448. }
  449. /* Set highest prioority and reset retry count */
  450. slotp = &metadata.slot_info[slot];
  451. slotp->successful_boot = 0;
  452. slotp->priority = 7;
  453. slotp->retry_count = 3;
  454. slotp->normal_boot = 1;
  455. /* Set lower priority to another slot */
  456. slot2 = (slot == 0) ? 1 : 0;
  457. slotp = &metadata.slot_info[slot2];
  458. if (slotp->priority >= 7) {
  459. slotp->priority = 6;
  460. }
  461. slotp->retry_count = 3;
  462. ret = bootctrl_write_metadata(&metadata);
  463. if (ret < 0) {
  464. return ret;
  465. }
  466. ret = switch_pl_boot_part(slot);
  467. if (ret < 0) {
  468. ALOGE("bootctrl_set_active_boot_slot switch boot part fail\n");
  469. return ret;
  470. }
  471. ret = SetOTAResultForDMVerity();
  472. if (ret < 0) {
  473. ALOGE("bootctrl_set_active_boot_slot SetOTAResultForDMVerity fail\n");
  474. return ret;
  475. }
  476. return 0;
  477. }
  478. int bootctrl_set_slot_as_unbootable(boot_control_module_t *module __unused,
  479. unsigned slot)
  480. {
  481. ALOGI("boot control bootctrl_set_slot_as_unbootable\n");
  482. int ret;
  483. boot_ctrl_t metadata;
  484. slot_metadata_t *slotp;
  485. if (slot >= 2) {
  486. ALOGE("%s Wrong Slot value %u\n", __func__ , slot);
  487. return -EINVAL;
  488. }
  489. ret = bootctrl_read_metadata(&metadata);
  490. if (ret < 0) {
  491. return ret;
  492. }
  493. /* Set zero to priority ,successful_boot and retry_count */
  494. slotp = &metadata.slot_info[slot];
  495. slotp->successful_boot = 0;
  496. slotp->priority = 0;
  497. slotp->retry_count = 0;
  498. ret = bootctrl_write_metadata(&metadata);
  499. if (ret < 0) {
  500. return ret;
  501. }
  502. return 0;
  503. }
  504. int bootctrl_is_slot_bootable(boot_control_module_t *module __unused,
  505. unsigned slot)
  506. {
  507. ALOGI("boot control bootctrl_is_slot_bootable\n");
  508. int ret;
  509. boot_ctrl_t metadata;
  510. /* slot 0 is A , slot 1 is B */
  511. if (slot >= 2) {
  512. ALOGE("%s Wrong slot value %u\n", __func__,slot);
  513. return -EINVAL;
  514. }
  515. ret = bootctrl_read_metadata(&metadata);
  516. if (ret < 0) {
  517. return ret;
  518. }
  519. return (metadata.slot_info[slot].priority != 0);
  520. }
  521. int bootctrl_get_bootup_status(boot_control_module_t *module __unused,
  522. unsigned slot)
  523. {
  524. ALOGI("bootctrl bootctrl_get_bootup_status\n");
  525. int ret = -1;
  526. slot_metadata_t *slotp;
  527. boot_ctrl_t metadata;
  528. if(slot >= 2) {
  529. ALOGE("%s Wrong slot value %u\n", __func__,slot);
  530. return -1;
  531. }
  532. ret = bootctrl_read_metadata(&metadata);
  533. if (ret < 0) {
  534. return ret;
  535. }
  536. slotp = &metadata.slot_info[slot];
  537. ALOGI("bootctrl bootctrl_get_bootup_status = %d\n", slotp->successful_boot);
  538. return slotp->successful_boot;
  539. }
  540. const char *bootctrl_get_suffix(boot_control_module_t *module __unused,
  541. unsigned slot)
  542. {
  543. ALOGI("boot control bootctrl_get_suffix\n");
  544. static const char* suffix[2] = {BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B};
  545. if (slot >= 2)
  546. return NULL;
  547. return suffix[slot];
  548. }
  549. static struct hw_module_methods_t bootctrl_methods = {
  550. .open = NULL,
  551. };
  552. /* Boot Control Module implementation */
  553. boot_control_module_t HAL_MODULE_INFO_SYM = {
  554. .common = {
  555. .tag = HARDWARE_MODULE_TAG,
  556. .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
  557. .hal_api_version = HARDWARE_HAL_API_VERSION,
  558. .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
  559. .name = "boot_control HAL",
  560. .author = "Mediatek Corporation",
  561. .methods = &bootctrl_methods,
  562. },
  563. .init = bootctrl_init,
  564. .getNumberSlots = bootctrl_get_number_slots,
  565. .getCurrentSlot = bootctrl_get_current_slot,
  566. .markBootSuccessful = bootctrl_mark_boot_successful,
  567. .setActiveBootSlot = bootctrl_set_active_boot_slot,
  568. .setSlotAsUnbootable = bootctrl_set_slot_as_unbootable,
  569. .isSlotBootable = bootctrl_is_slot_bootable,
  570. .isSlotMarkedSuccessful = bootctrl_get_bootup_status,
  571. .getSuffix = bootctrl_get_suffix,
  572. };