dell_flash_unlock.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* SPDX-License-Identifier: MIT */
  2. /* SPDX-FileCopyrightText: 2023 Nicholas Chin */
  3. #include <sys/mman.h>
  4. #include <err.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <stdint.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include "accessors.h"
  12. int get_fdo_status(void);
  13. int check_lpc_decode(void);
  14. void ec_set_fdo();
  15. void write_ec_reg(uint8_t index, uint8_t data);
  16. void send_ec_cmd(uint8_t cmd);
  17. int wait_ec(void);
  18. int check_bios_write_en(void);
  19. int set_gbl_smi_en(int enable);
  20. int get_gbl_smi_en(void);
  21. #define EC_INDEX 0x910
  22. #define EC_DATA 0x911
  23. #define EC_ENABLE_FDO 2
  24. #define LPC_DEV PCI_DEV(0, 0x1f, 0)
  25. #define RCBA_MMIO_LEN 0x4000
  26. /* Register offsets */
  27. #define SPIBAR 0x3800
  28. #define HSFS_REG 0x04
  29. #define SMI_EN_REG 0x30
  30. volatile uint8_t *rcba_mmio;
  31. uint16_t pmbase;
  32. int
  33. main(int argc, char *argv[])
  34. {
  35. int devmemfd;
  36. (void)argc;
  37. (void)argv;
  38. if (sys_iopl(3) == -1)
  39. err(errno, "Could not access IO ports");
  40. if ((devmemfd = open("/dev/mem", O_RDONLY)) == -1)
  41. err(errno, "/dev/mem");
  42. /* Read RCBA and PMBASE from the LPC config registers */
  43. long int rcba = pci_read_32(LPC_DEV, 0xf0) & 0xffffc000;
  44. pmbase = pci_read_32(LPC_DEV, 0x40) & 0xff80;
  45. /* FDO pin-strap status bit is in RCBA mmio space */
  46. rcba_mmio = mmap(0, RCBA_MMIO_LEN, PROT_READ, MAP_SHARED, devmemfd,
  47. rcba);
  48. if (rcba_mmio == MAP_FAILED)
  49. err(errno, "Could not map RCBA");
  50. if (get_fdo_status() == 1) { /* Descriptor not overridden */
  51. if (check_lpc_decode() == -1)
  52. err(errno = ECANCELED, "Can't forward I/O to LPC");
  53. printf("Sending FDO override command to EC:\n");
  54. ec_set_fdo();
  55. printf("Flash Descriptor Override enabled.\n"
  56. "Shut down (don't reboot) now.\n\n"
  57. "The EC may auto-boot on some systems; if not then "
  58. "manually power on.\n When the system boots rerun "
  59. "this utility to finish unlocking.\n");
  60. } else if (check_bios_write_en() == 0) {
  61. /* SMI locks in place, try disabling SMIs to bypass them */
  62. if (set_gbl_smi_en(0)) {
  63. printf("SMIs disabled. Internal flashing should work "
  64. "now.\n After flashing, re-run this utility "
  65. "to enable SMIs.\n (shutdown is buggy when "
  66. "SMIs are disabled)\n");
  67. } else {
  68. err(errno = ECANCELED, "Could not disable SMIs!");
  69. }
  70. } else { /* SMI locks not in place or bypassed */
  71. if (get_gbl_smi_en()) {
  72. /* SMIs are still enabled, assume this is an Exx10
  73. * or newer which don't need the SMM bypass */
  74. printf("Flash is unlocked.\n"
  75. "Internal flashing should work.\n");
  76. } else {
  77. /* SMIs disabled, assume this is an Exx00 after
  78. * unlocking and flashing */
  79. set_gbl_smi_en(1);
  80. printf("SMIs enabled.\n"
  81. "You can now shutdown the system.\n");
  82. }
  83. }
  84. return errno;
  85. }
  86. int
  87. get_fdo_status(void)
  88. {
  89. return (*(uint16_t*)(rcba_mmio + SPIBAR + HSFS_REG) >> 13) & 1;
  90. }
  91. int
  92. check_lpc_decode(void)
  93. {
  94. /* Check that at a Generic Decode Range Register is set up to
  95. * forward I/O ports 0x910 and 0x911 over LPC for the EC */
  96. int i = 0;
  97. int gen_dec_free = -1;
  98. for (; i < 4; i++) {
  99. uint32_t reg_val = pci_read_32(LPC_DEV, 0x84 + 4*i);
  100. uint16_t base_addr = reg_val & 0xfffc;
  101. uint16_t mask = ((reg_val >> 16) & 0xfffc) | 0x3;
  102. /* Bit 0 is the enable for each decode range. If disabled, note
  103. * this register as available to add our own range decode */
  104. if ((reg_val & 1) == 0)
  105. gen_dec_free = i;
  106. /* Check if the current range register matches port 0x910.
  107. * 0x911 doesn't need to be checked as the LPC bridge only
  108. * decodes at the dword level, and thus a check is redundant */
  109. if ((0x910 & ~mask) == base_addr) {
  110. return 0;
  111. }
  112. }
  113. /* No matching range found, try setting a range in a free register */
  114. if (gen_dec_free != -1) {
  115. /* Set up an I/O decode range from 0x910-0x913 */
  116. pci_write_32(LPC_DEV, 0x84 + 4 * gen_dec_free, 0x911);
  117. return 0;
  118. } else {
  119. return -1;
  120. }
  121. }
  122. void
  123. ec_set_fdo()
  124. {
  125. /* EC FDO command arguments for reference:
  126. * 0 = Query EC FDO status
  127. * 2 = Enable FDO for next boot
  128. * 3 = Disable FDO for next boot */
  129. write_ec_reg(0x12, EC_ENABLE_FDO);
  130. send_ec_cmd(0xb8);
  131. }
  132. void
  133. write_ec_reg(uint8_t index, uint8_t data)
  134. {
  135. sys_outb(EC_INDEX, index);
  136. sys_outb(EC_DATA, data);
  137. }
  138. void
  139. send_ec_cmd(uint8_t cmd)
  140. {
  141. sys_outb(EC_INDEX, 0);
  142. sys_outb(EC_DATA, cmd);
  143. if (wait_ec() == -1)
  144. err(errno = ECANCELED, "Timeout while waiting for EC!");
  145. }
  146. int
  147. wait_ec(void)
  148. {
  149. uint8_t busy;
  150. int timeout = 1000;
  151. do {
  152. sys_outb(EC_INDEX, 0);
  153. busy = sys_inb(EC_DATA);
  154. timeout--;
  155. usleep(1000);
  156. } while (busy && timeout > 0);
  157. return timeout > 0 ? 0 : -1;
  158. }
  159. int
  160. check_bios_write_en(void)
  161. {
  162. uint8_t bios_cntl = pci_read_32(LPC_DEV, 0xdc) & 0xff;
  163. /* Bit 5 = SMM BIOS Write Protect Disable (SMM_BWP)
  164. * Bit 1 = BIOS Lock Enable (BLE)
  165. * If both are 0, then there's no write protection */
  166. if ((bios_cntl & 0x22) == 0)
  167. return 1;
  168. /* SMM protection is enabled, but try enabling writes
  169. * anyway in case the vendor SMM code doesn't reset it */
  170. pci_write_32(LPC_DEV, 0xdc, bios_cntl | 0x1);
  171. return pci_read_32(LPC_DEV, 0xdc) & 0x1;
  172. }
  173. int
  174. set_gbl_smi_en(int enable)
  175. {
  176. uint32_t smi_en = sys_inl(pmbase + SMI_EN_REG);
  177. if (enable) {
  178. smi_en |= 1;
  179. } else {
  180. smi_en &= ~1;
  181. }
  182. sys_outl(pmbase + SMI_EN_REG, smi_en);
  183. return (get_gbl_smi_en() == enable);
  184. }
  185. int
  186. get_gbl_smi_en(void)
  187. {
  188. return sys_inl(pmbase + SMI_EN_REG) & 1;
  189. }