setpci.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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, &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, &ptr, 16) & 0xffff) << 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 (ctxt->state[1].set)
  169. {
  170. const char *optr;
  171. ptr = ctxt->state[1].arg;
  172. optr = ptr;
  173. bus = grub_strtoul (ptr, &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, N_("missing `%c' symbol"), ':');
  185. ptr++;
  186. optr = ptr;
  187. device = grub_strtoul (ptr, &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, &ptr, 16);
  199. if (grub_errno)
  200. return grub_errno;
  201. check_function = 1;
  202. }
  203. }
  204. if (ctxt->state[2].set)
  205. varname = ctxt->state[2].arg;
  206. else
  207. varname = NULL;
  208. write_mask = 0;
  209. if (argc != 1)
  210. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
  211. ptr = argv[0];
  212. for (i = 0; i < ARRAY_SIZE (pci_registers); i++)
  213. {
  214. if (grub_strncmp (ptr, pci_registers[i].name,
  215. grub_strlen (pci_registers[i].name)) == 0)
  216. break;
  217. }
  218. if (i == ARRAY_SIZE (pci_registers))
  219. {
  220. regsize = 0;
  221. regaddr = grub_strtoul (ptr, &ptr, 16);
  222. if (grub_errno)
  223. return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown register");
  224. }
  225. else
  226. {
  227. regaddr = pci_registers[i].addr;
  228. regsize = pci_registers[i].size;
  229. ptr += grub_strlen (pci_registers[i].name);
  230. }
  231. if (grub_errno)
  232. return grub_errno;
  233. if (*ptr == '+')
  234. {
  235. ptr++;
  236. regaddr += grub_strtoul (ptr, &ptr, 16);
  237. if (grub_errno)
  238. return grub_errno;
  239. }
  240. if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) == 0
  241. || grub_memcmp (ptr, ".l", sizeof (".l") - 1) == 0)
  242. {
  243. regsize = 4;
  244. ptr += sizeof (".l") - 1;
  245. }
  246. else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) == 0
  247. || grub_memcmp (ptr, ".w", sizeof (".w") - 1) == 0)
  248. {
  249. regsize = 2;
  250. ptr += sizeof (".w") - 1;
  251. }
  252. else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) == 0
  253. || grub_memcmp (ptr, ".b", sizeof (".b") - 1) == 0)
  254. {
  255. regsize = 1;
  256. ptr += sizeof (".b") - 1;
  257. }
  258. if (!regsize)
  259. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  260. "unknown register size");
  261. write_mask = 0;
  262. if (*ptr == '=')
  263. {
  264. ptr++;
  265. regwrite = grub_strtoul (ptr, &ptr, 16);
  266. if (grub_errno)
  267. return grub_errno;
  268. write_mask = 0xffffffff;
  269. if (*ptr == ':')
  270. {
  271. ptr++;
  272. write_mask = grub_strtoul (ptr, &ptr, 16);
  273. if (grub_errno)
  274. return grub_errno;
  275. }
  276. regwrite &= write_mask;
  277. }
  278. if (write_mask && varname)
  279. return grub_error (GRUB_ERR_BAD_ARGUMENT,
  280. "option -v isn't valid for writes");
  281. grub_pci_iterate (grub_setpci_iter, NULL);
  282. return GRUB_ERR_NONE;
  283. }
  284. static grub_extcmd_t cmd;
  285. GRUB_MOD_INIT(setpci)
  286. {
  287. cmd = grub_register_extcmd_lockdown ("setpci", grub_cmd_setpci, 0,
  288. N_("[-s POSITION] [-d DEVICE] [-v VAR] "
  289. "REGISTER[=VALUE[:MASK]]"),
  290. N_("Manipulate PCI devices."), options);
  291. }
  292. GRUB_MOD_FINI(setpci)
  293. {
  294. grub_unregister_extcmd (cmd);
  295. }