setpci.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /* lspci.c - List PCI devices. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/pci.h>
  20. #include <grub/dl.h>
  21. #include <grub/misc.h>
  22. #include <grub/extcmd.h>
  23. #include <grub/env.h>
  24. #include <grub/mm.h>
  25. #include <grub/i18n.h>
  26. struct pci_register
  27. {
  28. const char *name;
  29. grub_uint16_t addr;
  30. unsigned size;
  31. };
  32. struct pci_register pci_registers[] =
  33. {
  34. {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2},
  35. {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2},
  36. {"COMMAND", GRUB_PCI_REG_COMMAND , 2},
  37. {"STATUS", GRUB_PCI_REG_STATUS , 2},
  38. {"REVISION", GRUB_PCI_REG_REVISION , 1},
  39. {"CLASS_PROG", GRUB_PCI_REG_CLASS + 1 , 1},
  40. {"CLASS_DEVICE", GRUB_PCI_REG_CLASS + 2 , 2},
  41. {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE , 1},
  42. {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER , 1},
  43. {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE , 1},
  44. {"BIST", GRUB_PCI_REG_BIST , 1},
  45. {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0, 4},
  46. {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1, 4},
  47. {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2, 4},
  48. {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3, 4},
  49. {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4, 4},
  50. {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5, 4},
  51. {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER , 4},
  52. {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR , 2},
  53. {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM , 2},
  54. {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS , 4},
  55. {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER , 1},
  56. {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE , 1},
  57. {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN , 1},
  58. {"MIN_GNT", GRUB_PCI_REG_MIN_GNT , 1},
  59. {"MAX_LAT", GRUB_PCI_REG_MIN_GNT , 1},
  60. };
  61. static const struct grub_arg_option options[] =
  62. {
  63. {0, 'd', 0, "Select device by vendor and device IDs.",
  64. "[vendor]:[device]", ARG_TYPE_STRING},
  65. {0, 's', 0, "Select device by its position on the bus.",
  66. "[bus]:[slot][.func]", ARG_TYPE_STRING},
  67. {0, 'v', 0, "Save read value into variable VARNAME.",
  68. "VARNAME", ARG_TYPE_STRING},
  69. {0, 0, 0, 0, 0, 0}
  70. };
  71. static grub_uint32_t pciid_check_mask, pciid_check_value;
  72. static int bus, device, function;
  73. static int check_bus, check_device, check_function;
  74. static grub_uint32_t write_mask, regwrite;
  75. static int regsize;
  76. static grub_uint16_t regaddr;
  77. static const char *varname;
  78. static int
  79. grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
  80. void *closure __attribute__ ((unused)))
  81. {
  82. grub_uint32_t regval = 0;
  83. grub_pci_address_t addr;
  84. if ((pciid & pciid_check_mask) != pciid_check_value)
  85. return 0;
  86. if (check_bus && grub_pci_get_bus (dev) != bus)
  87. return 0;
  88. if (check_device && grub_pci_get_device (dev) != device)
  89. return 0;
  90. if (check_function && grub_pci_get_function (dev) != device)
  91. return 0;
  92. addr = grub_pci_make_address (dev, regaddr);
  93. switch (regsize)
  94. {
  95. case 1:
  96. regval = grub_pci_read_byte (addr);
  97. break;
  98. case 2:
  99. regval = grub_pci_read_word (addr);
  100. break;
  101. case 4:
  102. regval = grub_pci_read (addr);
  103. break;
  104. }
  105. if (varname)
  106. {
  107. char buf[sizeof ("XXXXXXXX")];
  108. grub_snprintf (buf, sizeof (buf), "%x", regval);
  109. grub_env_set (varname, buf);
  110. return 1;
  111. }
  112. if (!write_mask)
  113. {
  114. grub_printf ("Register %x of %d:%d.%d is %x\n", regaddr,
  115. grub_pci_get_bus (dev),
  116. grub_pci_get_device (dev),
  117. grub_pci_get_function (dev),
  118. regval);
  119. return 0;
  120. }
  121. regval = (regval & ~write_mask) | regwrite;
  122. switch (regsize)
  123. {
  124. case 1:
  125. grub_pci_write_byte (addr, regval);
  126. break;
  127. case 2:
  128. grub_pci_write_word (addr, regval);
  129. break;
  130. case 4:
  131. grub_pci_write (addr, regval);
  132. break;
  133. }
  134. return 0;
  135. }
  136. static grub_err_t
  137. grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
  138. {
  139. const char *ptr;
  140. unsigned i;
  141. pciid_check_value = 0;
  142. pciid_check_mask = 0;
  143. if (cmd->state[0].set)
  144. {
  145. ptr = cmd->state[0].arg;
  146. pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff);
  147. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  148. {
  149. grub_errno = GRUB_ERR_NONE;
  150. ptr = cmd->state[0].arg;
  151. }
  152. else
  153. pciid_check_mask |= 0xffff;
  154. if (grub_errno)
  155. return grub_errno;
  156. if (*ptr != ':')
  157. return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected.");
  158. ptr++;
  159. pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff)
  160. << 16;
  161. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  162. grub_errno = GRUB_ERR_NONE;
  163. else
  164. pciid_check_mask |= 0xffff0000;
  165. }
  166. pciid_check_value &= pciid_check_mask;
  167. check_bus = check_device = check_function = 0;
  168. if (cmd->state[1].set)
  169. {
  170. const char *optr;
  171. ptr = cmd->state[1].arg;
  172. optr = ptr;
  173. bus = grub_strtoul (ptr, (char **) &ptr, 16);
  174. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  175. {
  176. grub_errno = GRUB_ERR_NONE;
  177. ptr = optr;
  178. }
  179. else
  180. check_bus = 1;
  181. if (grub_errno)
  182. return grub_errno;
  183. if (*ptr != ':')
  184. return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected.");
  185. ptr++;
  186. optr = ptr;
  187. device = grub_strtoul (ptr, (char **) &ptr, 16);
  188. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  189. {
  190. grub_errno = GRUB_ERR_NONE;
  191. ptr = optr;
  192. }
  193. else
  194. check_device = 1;
  195. if (*ptr == '.')
  196. {
  197. ptr++;
  198. function = grub_strtoul (ptr, (char **) &ptr, 16);
  199. if (grub_errno)
  200. return grub_errno;
  201. check_function = 1;
  202. }
  203. }
  204. if (cmd->state[2].set)
  205. varname = cmd->state[2].arg;
  206. else
  207. varname = NULL;
  208. write_mask = 0;
  209. if (argc == 0)
  210. return grub_error (GRUB_ERR_BAD_ARGUMENT, "Command expected.");
  211. if (argc > 1)
  212. return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one command is supported.");
  213. ptr = argv[0];
  214. for (i = 0; i < ARRAY_SIZE (pci_registers); i++)
  215. {
  216. if (grub_strncmp (ptr, pci_registers[i].name,
  217. grub_strlen (pci_registers[i].name)) == 0)
  218. break;
  219. }
  220. if (i == ARRAY_SIZE (pci_registers))
  221. {
  222. regsize = 0;
  223. regaddr = grub_strtoul (ptr, (char **) &ptr, 16);
  224. if (grub_errno)
  225. return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown register");
  226. }
  227. else
  228. {
  229. regaddr = pci_registers[i].addr;
  230. regsize = pci_registers[i].size;
  231. ptr += grub_strlen (pci_registers[i].name);
  232. }
  233. if (grub_errno)
  234. return grub_errno;
  235. if (*ptr == '+')
  236. {
  237. ptr++;
  238. regaddr += grub_strtoul (ptr, (char **) &ptr, 16);
  239. if (grub_errno)
  240. return grub_errno;
  241. }
  242. if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0
  243. || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0)
  244. {
  245. regsize = 4;
  246. ptr += sizeof (".l") - 1;
  247. }
  248. else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0
  249. || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0)
  250. {
  251. regsize = 2;
  252. ptr += sizeof (".w") - 1;
  253. }
  254. else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0
  255. || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0)
  256. {
  257. regsize = 1;
  258. ptr += sizeof (".b") - 1;
  259. }
  260. if (!regsize)
  261. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  262. "Unknown register size.");
  263. write_mask = 0;
  264. if (*ptr == '=')
  265. {
  266. ptr++;
  267. regwrite = grub_strtoul (ptr, (char **) &ptr, 16);
  268. if (grub_errno)
  269. return grub_errno;
  270. write_mask = 0xffffffff;
  271. if (*ptr == ':')
  272. {
  273. ptr++;
  274. write_mask = grub_strtoul (ptr, (char **) &ptr, 16);
  275. if (grub_errno)
  276. return grub_errno;
  277. write_mask = 0xffffffff;
  278. }
  279. regwrite &= write_mask;
  280. }
  281. if (write_mask && varname)
  282. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  283. "Option -v isn't valid for writes.");
  284. grub_pci_iterate (grub_setpci_iter, 0);
  285. return GRUB_ERR_NONE;
  286. }
  287. static grub_extcmd_t cmd;
  288. GRUB_MOD_INIT(setpci)
  289. {
  290. cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, GRUB_COMMAND_FLAG_BOTH,
  291. N_("[-s POSITION] [-d DEVICE] [-v VAR] "
  292. "[REGISTER][=VALUE[:MASK]]"),
  293. N_("Manipulate PCI devices."), options);
  294. }
  295. GRUB_MOD_FINI(setpci)
  296. {
  297. grub_unregister_extcmd (cmd);
  298. }