setpci.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. GRUB_MOD_LICENSE ("GPLv3+");
  27. struct pci_register
  28. {
  29. const char *name;
  30. grub_uint16_t addr;
  31. unsigned size;
  32. };
  33. static struct pci_register pci_registers[] =
  34. {
  35. {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2},
  36. {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2},
  37. {"COMMAND", GRUB_PCI_REG_COMMAND , 2},
  38. {"STATUS", GRUB_PCI_REG_STATUS , 2},
  39. {"REVISION", GRUB_PCI_REG_REVISION , 1},
  40. {"CLASS_PROG", GRUB_PCI_REG_CLASS + 1 , 1},
  41. {"CLASS_DEVICE", GRUB_PCI_REG_CLASS + 2 , 2},
  42. {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE , 1},
  43. {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER , 1},
  44. {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE , 1},
  45. {"BIST", GRUB_PCI_REG_BIST , 1},
  46. {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0, 4},
  47. {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1, 4},
  48. {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2, 4},
  49. {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3, 4},
  50. {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4, 4},
  51. {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5, 4},
  52. {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER , 4},
  53. {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR , 2},
  54. {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM , 2},
  55. {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS , 4},
  56. {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER , 1},
  57. {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE , 1},
  58. {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN , 1},
  59. {"MIN_GNT", GRUB_PCI_REG_MIN_GNT , 1},
  60. {"MAX_LAT", GRUB_PCI_REG_MIN_GNT , 1},
  61. };
  62. static const struct grub_arg_option options[] =
  63. {
  64. {0, 'd', 0, N_("Select device by vendor and device IDs."),
  65. N_("[vendor]:[device]"), ARG_TYPE_STRING},
  66. {0, 's', 0, N_("Select device by its position on the bus."),
  67. N_("[bus]:[slot][.func]"), ARG_TYPE_STRING},
  68. {0, 'v', 0, N_("Save read value into variable VARNAME."),
  69. N_("VARNAME"), ARG_TYPE_STRING},
  70. {0, 0, 0, 0, 0, 0}
  71. };
  72. static grub_uint32_t pciid_check_mask, pciid_check_value;
  73. static int bus, device, function;
  74. static int check_bus, check_device, check_function;
  75. static grub_uint32_t write_mask, regwrite;
  76. static int regsize;
  77. static grub_uint16_t regaddr;
  78. static const char *varname;
  79. static int
  80. grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
  81. void *data __attribute__ ((unused)))
  82. {
  83. grub_uint32_t regval = 0;
  84. grub_pci_address_t addr;
  85. if ((pciid & pciid_check_mask) != pciid_check_value)
  86. return 0;
  87. if (check_bus && grub_pci_get_bus (dev) != bus)
  88. return 0;
  89. if (check_device && grub_pci_get_device (dev) != device)
  90. return 0;
  91. if (check_function && grub_pci_get_function (dev) != function)
  92. return 0;
  93. addr = grub_pci_make_address (dev, regaddr);
  94. switch (regsize)
  95. {
  96. case 1:
  97. regval = grub_pci_read_byte (addr);
  98. break;
  99. case 2:
  100. regval = grub_pci_read_word (addr);
  101. break;
  102. case 4:
  103. regval = grub_pci_read (addr);
  104. break;
  105. }
  106. if (varname)
  107. {
  108. char buf[sizeof ("XXXXXXXX")];
  109. grub_snprintf (buf, sizeof (buf), "%x", regval);
  110. grub_env_set (varname, buf);
  111. return 1;
  112. }
  113. if (!write_mask)
  114. {
  115. grub_printf (_("Register %x of %x:%02x.%x is %x\n"), regaddr,
  116. grub_pci_get_bus (dev),
  117. grub_pci_get_device (dev),
  118. grub_pci_get_function (dev),
  119. regval);
  120. return 0;
  121. }
  122. regval = (regval & ~write_mask) | regwrite;
  123. switch (regsize)
  124. {
  125. case 1:
  126. grub_pci_write_byte (addr, regval);
  127. break;
  128. case 2:
  129. grub_pci_write_word (addr, regval);
  130. break;
  131. case 4:
  132. grub_pci_write (addr, regval);
  133. break;
  134. }
  135. return 0;
  136. }
  137. static grub_err_t
  138. grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv)
  139. {
  140. const char *ptr;
  141. unsigned i;
  142. pciid_check_value = 0;
  143. pciid_check_mask = 0;
  144. if (ctxt->state[0].set)
  145. {
  146. ptr = ctxt->state[0].arg;
  147. pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff);
  148. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  149. {
  150. grub_errno = GRUB_ERR_NONE;
  151. ptr = ctxt->state[0].arg;
  152. }
  153. else
  154. pciid_check_mask |= 0xffff;
  155. if (grub_errno)
  156. return grub_errno;
  157. if (*ptr != ':')
  158. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
  159. ptr++;
  160. pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff)
  161. << 16;
  162. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  163. grub_errno = GRUB_ERR_NONE;
  164. else
  165. pciid_check_mask |= 0xffff0000;
  166. }
  167. pciid_check_value &= pciid_check_mask;
  168. check_bus = check_device = check_function = 0;
  169. if (ctxt->state[1].set)
  170. {
  171. const char *optr;
  172. ptr = ctxt->state[1].arg;
  173. optr = ptr;
  174. bus = grub_strtoul (ptr, (char **) &ptr, 16);
  175. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  176. {
  177. grub_errno = GRUB_ERR_NONE;
  178. ptr = optr;
  179. }
  180. else
  181. check_bus = 1;
  182. if (grub_errno)
  183. return grub_errno;
  184. if (*ptr != ':')
  185. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing `%c' symbol"), ':');
  186. ptr++;
  187. optr = ptr;
  188. device = grub_strtoul (ptr, (char **) &ptr, 16);
  189. if (grub_errno == GRUB_ERR_BAD_NUMBER)
  190. {
  191. grub_errno = GRUB_ERR_NONE;
  192. ptr = optr;
  193. }
  194. else
  195. check_device = 1;
  196. if (*ptr == '.')
  197. {
  198. ptr++;
  199. function = grub_strtoul (ptr, (char **) &ptr, 16);
  200. if (grub_errno)
  201. return grub_errno;
  202. check_function = 1;
  203. }
  204. }
  205. if (ctxt->state[2].set)
  206. varname = ctxt->state[2].arg;
  207. else
  208. varname = NULL;
  209. write_mask = 0;
  210. if (argc != 1)
  211. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  212. ptr = argv[0];
  213. for (i = 0; i < ARRAY_SIZE (pci_registers); i++)
  214. {
  215. if (grub_strncmp (ptr, pci_registers[i].name,
  216. grub_strlen (pci_registers[i].name)) == 0)
  217. break;
  218. }
  219. if (i == ARRAY_SIZE (pci_registers))
  220. {
  221. regsize = 0;
  222. regaddr = grub_strtoul (ptr, (char **) &ptr, 16);
  223. if (grub_errno)
  224. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown register");
  225. }
  226. else
  227. {
  228. regaddr = pci_registers[i].addr;
  229. regsize = pci_registers[i].size;
  230. ptr += grub_strlen (pci_registers[i].name);
  231. }
  232. if (grub_errno)
  233. return grub_errno;
  234. if (*ptr == '+')
  235. {
  236. ptr++;
  237. regaddr += grub_strtoul (ptr, (char **) &ptr, 16);
  238. if (grub_errno)
  239. return grub_errno;
  240. }
  241. if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0
  242. || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0)
  243. {
  244. regsize = 4;
  245. ptr += sizeof (".l") - 1;
  246. }
  247. else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0
  248. || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0)
  249. {
  250. regsize = 2;
  251. ptr += sizeof (".w") - 1;
  252. }
  253. else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0
  254. || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0)
  255. {
  256. regsize = 1;
  257. ptr += sizeof (".b") - 1;
  258. }
  259. if (!regsize)
  260. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  261. "unknown register size");
  262. write_mask = 0;
  263. if (*ptr == '=')
  264. {
  265. ptr++;
  266. regwrite = grub_strtoul (ptr, (char **) &ptr, 16);
  267. if (grub_errno)
  268. return grub_errno;
  269. write_mask = 0xffffffff;
  270. if (*ptr == ':')
  271. {
  272. ptr++;
  273. write_mask = grub_strtoul (ptr, (char **) &ptr, 16);
  274. if (grub_errno)
  275. return grub_errno;
  276. write_mask = 0xffffffff;
  277. }
  278. regwrite &= write_mask;
  279. }
  280. if (write_mask && varname)
  281. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  282. "option -v isn't valid for writes");
  283. grub_pci_iterate (grub_setpci_iter, NULL);
  284. return GRUB_ERR_NONE;
  285. }
  286. static grub_extcmd_t cmd;
  287. GRUB_MOD_INIT(setpci)
  288. {
  289. cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, 0,
  290. N_("[-s POSITION] [-d DEVICE] [-v VAR] "
  291. "REGISTER[=VALUE[:MASK]]"),
  292. N_("Manipulate PCI devices."), options);
  293. }
  294. GRUB_MOD_FINI(setpci)
  295. {
  296. grub_unregister_extcmd (cmd);
  297. }