mirror of
https://review.coreboot.org/flashrom.git
synced 2025-04-27 23:22:37 +02:00
One of the problems is that --force had multiple meanings
- Force chip read by faking probe success. - Force chip access even if the chip is bigger than max decode size for the flash bus. - Force erase even if erase is known bad. - Force write even if write is known bad. - Force writing even if cbtable tells us that this is the wrong image for this board. This patch cleans up --force usage: - Remove any suggestions to use --force for probe/read from flashrom output. - Don't talk about "success" or "Found chip" if the chip is forced. - Add a new internal programmer parameter boardmismatch=force. This overrides any mismatch detection from cbtable/image comparisons. - Add a new internal programmer parameter laptop=force_I_want_a_brick. - Adjust the documentation for --force. - Clean up the man page a bit whereever it talks about --force or laptops. Additional changes in this patch: - Add warnings about laptops to the documentation. - Abort if a laptop is detected. Can be overridden with the programmer parameter mentioned above. - Add "Portable" to the list of DMI strings indicating laptops. - Check if a chip specified with -c is known to flashrom. - Programmer parameter reliability and consistency fixes. - More paranoid self-checks. - Improve documentation. Corresponding to flashrom svn r996. Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> Acked-by: Michael Karcher <flashrom@mkarcher.dialup.fu-berlin.de>
This commit is contained in:
parent
837d810796
commit
270237687a
6
README
6
README
@ -11,6 +11,12 @@ program flash chips.
|
|||||||
It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and TSOP40
|
It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and TSOP40
|
||||||
chips, which use various protocols such as LPC, FWH, parallel flash, or SPI.
|
chips, which use various protocols such as LPC, FWH, parallel flash, or SPI.
|
||||||
|
|
||||||
|
Do not use flashrom on laptops! The embedded controller (EC) present in many
|
||||||
|
laptops interacts badly with any flash attempts and can brick your laptop
|
||||||
|
permanently.
|
||||||
|
|
||||||
|
Please make a backup of your flash chip before writing to it.
|
||||||
|
|
||||||
Please see the flashrom(8) manpage.
|
Please see the flashrom(8) manpage.
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,6 +248,10 @@ int cli_classic(int argc, char *argv[])
|
|||||||
switch (optarg[namelen]) {
|
switch (optarg[namelen]) {
|
||||||
case ':':
|
case ':':
|
||||||
programmer_param = strdup(optarg + namelen + 1);
|
programmer_param = strdup(optarg + namelen + 1);
|
||||||
|
if (!strlen(programmer_param)) {
|
||||||
|
free(programmer_param);
|
||||||
|
programmer_param = NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
break;
|
break;
|
||||||
@ -303,6 +307,21 @@ int cli_classic(int argc, char *argv[])
|
|||||||
cli_classic_usage(argv[0]);
|
cli_classic_usage(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chip_to_probe) {
|
||||||
|
for (flash = flashchips; flash && flash->name; flash++)
|
||||||
|
if (!strcmp(flash->name, chip_to_probe))
|
||||||
|
break;
|
||||||
|
if (!flash || !flash->name) {
|
||||||
|
fprintf(stderr, "Error: Unknown chip '%s' specified.\n",
|
||||||
|
chip_to_probe);
|
||||||
|
printf("Run flashrom -L to view the hardware supported "
|
||||||
|
"in this flashrom version.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* Clean up after the check. */
|
||||||
|
flash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (programmer_init()) {
|
if (programmer_init()) {
|
||||||
fprintf(stderr, "Error: Programmer initialization failed.\n");
|
fprintf(stderr, "Error: Programmer initialization failed.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -329,18 +348,14 @@ int cli_classic(int argc, char *argv[])
|
|||||||
} else if (!flashes[0]) {
|
} else if (!flashes[0]) {
|
||||||
printf("No EEPROM/flash device found.\n");
|
printf("No EEPROM/flash device found.\n");
|
||||||
if (!force || !chip_to_probe) {
|
if (!force || !chip_to_probe) {
|
||||||
printf("If you know which flash chip you have, and if this version of flashrom\n");
|
printf("Note: flashrom can never write if the flash chip isn't found automatically.\n");
|
||||||
printf("supports a similar flash chip, you can try to force read your chip. Run:\n");
|
|
||||||
printf("flashrom -f -r -c similar_supported_flash_chip filename\n");
|
|
||||||
printf("\n");
|
|
||||||
printf("Note: flashrom can never write when the flash chip isn't found automatically.\n");
|
|
||||||
}
|
}
|
||||||
if (force && read_it && chip_to_probe) {
|
if (force && read_it && chip_to_probe) {
|
||||||
printf("Force read (-f -r -c) requested, forcing chip probe success:\n");
|
printf("Force read (-f -r -c) requested, pretending the chip is there:\n");
|
||||||
flashes[0] = probe_flash(flashchips, 1);
|
flashes[0] = probe_flash(flashchips, 1);
|
||||||
if (!flashes[0]) {
|
if (!flashes[0]) {
|
||||||
printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe);
|
printf("Probing for flash chip '%s' failed.\n", chip_to_probe);
|
||||||
printf("Run flashrom -L to view the hardware supported in this flashrom version.\n");
|
programmer_shutdown();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
printf("Please note that forced reads most likely contain garbage.\n");
|
printf("Please note that forced reads most likely contain garbage.\n");
|
||||||
|
3
dmi.c
3
dmi.c
@ -102,7 +102,8 @@ void dmi_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
chassis_type = get_dmi_string("chassis-type");
|
chassis_type = get_dmi_string("chassis-type");
|
||||||
if (chassis_type && !strcmp(chassis_type, "Notebook")) {
|
if (chassis_type && (!strcmp(chassis_type, "Notebook") ||
|
||||||
|
!strcmp(chassis_type, "Portable"))) {
|
||||||
printf_debug("Laptop detected via DMI\n");
|
printf_debug("Laptop detected via DMI\n");
|
||||||
is_laptop = 1;
|
is_laptop = 1;
|
||||||
}
|
}
|
||||||
|
1
flash.h
1
flash.h
@ -385,6 +385,7 @@ void release_io_perms(void);
|
|||||||
#if INTERNAL_SUPPORT == 1
|
#if INTERNAL_SUPPORT == 1
|
||||||
extern int is_laptop;
|
extern int is_laptop;
|
||||||
extern int force_boardenable;
|
extern int force_boardenable;
|
||||||
|
extern int force_boardmismatch;
|
||||||
void probe_superio(void);
|
void probe_superio(void);
|
||||||
int internal_init(void);
|
int internal_init(void);
|
||||||
int internal_shutdown(void);
|
int internal_shutdown(void);
|
||||||
|
55
flashrom.8
55
flashrom.8
@ -61,7 +61,10 @@ Erase the flash ROM chip.
|
|||||||
More verbose output.
|
More verbose output.
|
||||||
.TP
|
.TP
|
||||||
.B "\-c, \-\-chip" <chipname>
|
.B "\-c, \-\-chip" <chipname>
|
||||||
Probe only for specified flash ROM chip.
|
Probe only for specified flash ROM chip. This option takes the chip name as
|
||||||
|
printed by
|
||||||
|
.B "flashrom \-L"
|
||||||
|
without the vendor name. Please note that the chip name is case sensitive.
|
||||||
.TP
|
.TP
|
||||||
.B "\-m, \-\-mainboard" <[vendor:]part>
|
.B "\-m, \-\-mainboard" <[vendor:]part>
|
||||||
Override mainboard settings.
|
Override mainboard settings.
|
||||||
@ -77,11 +80,16 @@ a list of boards which require the specification of the board name, if no
|
|||||||
coreboot table is found.
|
coreboot table is found.
|
||||||
.TP
|
.TP
|
||||||
.B "\-f, \-\-force"
|
.B "\-f, \-\-force"
|
||||||
Force write without checking whether the ROM image file is really meant
|
Force one or more of the following actions:
|
||||||
to be used on this board.
|
|
||||||
.sp
|
.sp
|
||||||
Note: This check only works while coreboot is running, and only for those
|
* Force chip read and pretend the chip is there.
|
||||||
boards where the coreboot code supports it.
|
.sp
|
||||||
|
* Force chip access even if the chip is bigger than max decode size for\
|
||||||
|
the flash bus.
|
||||||
|
.sp
|
||||||
|
* Force erase even if erase is known bad.
|
||||||
|
.sp
|
||||||
|
* Force write even if write is known bad.
|
||||||
.TP
|
.TP
|
||||||
.B "\-l, \-\-layout <file>"
|
.B "\-l, \-\-layout <file>"
|
||||||
Read ROM layout from
|
Read ROM layout from
|
||||||
@ -135,7 +143,7 @@ Same as
|
|||||||
but outputs the supported hardware in MediaWiki syntax, so that it can be
|
but outputs the supported hardware in MediaWiki syntax, so that it can be
|
||||||
easily pasted into the wiki page at http://www.flashrom.org/.
|
easily pasted into the wiki page at http://www.flashrom.org/.
|
||||||
.TP
|
.TP
|
||||||
.B "\-p, \-\-programmer <name>[:parameters]"
|
.B "\-p, \-\-programmer <name>[:parameter[,parameter[,parameter]]]"
|
||||||
Specify the programmer device. Currently supported are:
|
Specify the programmer device. Currently supported are:
|
||||||
.sp
|
.sp
|
||||||
.BR "* internal" " (default, for in-system flashing in the mainboard)"
|
.BR "* internal" " (default, for in-system flashing in the mainboard)"
|
||||||
@ -220,6 +228,13 @@ has been written because it is known that writing/erasing without the board
|
|||||||
enable is going to fail. In any case (success or failure), please report to
|
enable is going to fail. In any case (success or failure), please report to
|
||||||
the flashrom mailing list, see below.
|
the flashrom mailing list, see below.
|
||||||
.sp
|
.sp
|
||||||
|
On systems running coreboot, flashrom checks whether the desired image matches
|
||||||
|
your mainboard. This needs some special board ID to be present in the image.
|
||||||
|
If flashrom detects that the image you want to write and the current board
|
||||||
|
do not match, it will refuse to write the image unless you specify
|
||||||
|
.sp
|
||||||
|
.B "flashrom -p internal:boardmismatch=force"
|
||||||
|
.sp
|
||||||
If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus
|
If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus
|
||||||
translation, flashrom should autodetect that configuration. You can use
|
translation, flashrom should autodetect that configuration. You can use
|
||||||
.B "flashrom -p internal:it87spiport=portnum"
|
.B "flashrom -p internal:it87spiport=portnum"
|
||||||
@ -228,6 +243,24 @@ syntax as explained in the
|
|||||||
programmer section to use a non-default port for controlling the IT87 series
|
programmer section to use a non-default port for controlling the IT87 series
|
||||||
Super I/O. In the unlikely case flashrom doesn't detect an active IT87 LPC<->SPI
|
Super I/O. In the unlikely case flashrom doesn't detect an active IT87 LPC<->SPI
|
||||||
bridge, you can try to force recognition by using the it87spi programmer.
|
bridge, you can try to force recognition by using the it87spi programmer.
|
||||||
|
.sp
|
||||||
|
Using flashrom on laptops is dangerous and may easily make your hardware
|
||||||
|
unusable (see also the BUGS section). The embedded controller (EC) in these
|
||||||
|
machines often interacts badly with flashing. http://www.flashrom.org/Laptops
|
||||||
|
has more information. If flash is shared with the EC, erase is guaranteed to
|
||||||
|
brick your laptop and write is very likely to brick your laptop.
|
||||||
|
Chip read and probe may irritate your EC and cause fan failure, backlight
|
||||||
|
failure, sudden poweroff, and other nasty effects.
|
||||||
|
flashrom will attempt to detect laptops and abort immediately for safety
|
||||||
|
reasons.
|
||||||
|
If you want to proceed anyway at your own risk, use
|
||||||
|
.sp
|
||||||
|
.B "flashrom -p internal:laptop=force_I_want_a_brick"
|
||||||
|
.sp
|
||||||
|
You have been warned.
|
||||||
|
.sp
|
||||||
|
We will not help you if you force flashing on a laptop because this is a really
|
||||||
|
dumb idea.
|
||||||
.TP
|
.TP
|
||||||
.BR "dummy " programmer
|
.BR "dummy " programmer
|
||||||
An optional parameter specifies the bus types it
|
An optional parameter specifies the bus types it
|
||||||
@ -315,8 +348,14 @@ flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem
|
|||||||
.SH BUGS
|
.SH BUGS
|
||||||
Please report any bugs at
|
Please report any bugs at
|
||||||
.BR http://www.flashrom.org/trac/flashrom/newticket ","
|
.BR http://www.flashrom.org/trac/flashrom/newticket ","
|
||||||
or on the flashrom mailing list
|
or on the flashrom mailing list at
|
||||||
.RB "(" http://www.flashrom.org/mailman/listinfo/flashrom ")."
|
.BR http://www.flashrom.org/mailman/listinfo/flashrom "."
|
||||||
|
.sp
|
||||||
|
Using flashrom on laptops is dangerous and may easily make your hardware
|
||||||
|
unusable unless you can desolder the flash chip and have a full flash chip
|
||||||
|
backup. This is caused by the embedded controller (EC) present in many laptops,
|
||||||
|
which interacts badly with any flash attempts. This is a hardware limitation
|
||||||
|
and flashrom will attempt to detect it and abort immediately for safety reasons.
|
||||||
.SH LICENCE
|
.SH LICENCE
|
||||||
.B flashrom
|
.B flashrom
|
||||||
is covered by the GNU General Public License (GPL), version 2. Some files are
|
is covered by the GNU General Public License (GPL), version 2. Some files are
|
||||||
|
13
flashrom.c
13
flashrom.c
@ -488,7 +488,17 @@ char *extract_param(char **haystack, char *needle, char *delim)
|
|||||||
char *param_pos, *rest, *tmp;
|
char *param_pos, *rest, *tmp;
|
||||||
char *dev = NULL;
|
char *dev = NULL;
|
||||||
int devlen;
|
int devlen;
|
||||||
|
int needlelen;
|
||||||
|
|
||||||
|
needlelen = strlen(needle);
|
||||||
|
if (!needlelen) {
|
||||||
|
msg_gerr("%s: empty needle! Please report a bug at "
|
||||||
|
"flashrom@flashrom.org\n", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* No programmer parameters given. */
|
||||||
|
if (*haystack == NULL)
|
||||||
|
return NULL;
|
||||||
param_pos = strstr(*haystack, needle);
|
param_pos = strstr(*haystack, needle);
|
||||||
do {
|
do {
|
||||||
if (!param_pos)
|
if (!param_pos)
|
||||||
@ -924,7 +934,8 @@ notfound:
|
|||||||
if (!flash || !flash->name)
|
if (!flash || !flash->name)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
|
printf("%s chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
|
||||||
|
force ? "Assuming" : "Found",
|
||||||
flash->vendor, flash->name, flash->total_size,
|
flash->vendor, flash->name, flash->total_size,
|
||||||
flashbuses_to_text(flash->bustype), base);
|
flashbuses_to_text(flash->bustype), base);
|
||||||
|
|
||||||
|
84
internal.c
84
internal.c
@ -101,6 +101,7 @@ struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
|
|||||||
#if INTERNAL_SUPPORT == 1
|
#if INTERNAL_SUPPORT == 1
|
||||||
struct superio superio = {};
|
struct superio superio = {};
|
||||||
int force_boardenable = 0;
|
int force_boardenable = 0;
|
||||||
|
int force_boardmismatch = 0;
|
||||||
|
|
||||||
void probe_superio(void)
|
void probe_superio(void)
|
||||||
{
|
{
|
||||||
@ -117,26 +118,42 @@ int is_laptop;
|
|||||||
int internal_init(void)
|
int internal_init(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int force_laptop = 0;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
if (programmer_param && !strlen(programmer_param)) {
|
arg = extract_param(&programmer_param, "boardenable=", ",:");
|
||||||
free(programmer_param);
|
if (arg && !strcmp(arg,"force")) {
|
||||||
programmer_param = NULL;
|
force_boardenable = 1;
|
||||||
|
} else if (arg && !strlen(arg)) {
|
||||||
|
msg_perr("Missing argument for boardenable.\n");
|
||||||
|
} else if (arg) {
|
||||||
|
msg_perr("Unknown argument for boardenable: %s\n", arg);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
if (programmer_param) {
|
free(arg);
|
||||||
char *arg;
|
|
||||||
arg = extract_param(&programmer_param, "boardenable=", ",:");
|
|
||||||
if (arg && !strcmp(arg,"force"))
|
|
||||||
force_boardenable = 1;
|
|
||||||
else if (arg)
|
|
||||||
msg_perr("Unknown argument for boardenable: %s\n", arg);
|
|
||||||
free(arg);
|
|
||||||
|
|
||||||
if (strlen(programmer_param))
|
arg = extract_param(&programmer_param, "boardmismatch=", ",:");
|
||||||
msg_perr("Unhandled programmer parameters: %s\n",
|
if (arg && !strcmp(arg,"force")) {
|
||||||
programmer_param);
|
force_boardmismatch = 1;
|
||||||
free(programmer_param);
|
} else if (arg && !strlen(arg)) {
|
||||||
programmer_param = NULL;
|
msg_perr("Missing argument for boardmismatch.\n");
|
||||||
|
} else if (arg) {
|
||||||
|
msg_perr("Unknown argument for boardmismatch: %s\n", arg);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
free(arg);
|
||||||
|
|
||||||
|
arg = extract_param(&programmer_param, "laptop=", ",:");
|
||||||
|
if (arg && !strcmp(arg,"force_I_want_a_brick")) {
|
||||||
|
force_laptop = 1;
|
||||||
|
} else if (arg && !strlen(arg)) {
|
||||||
|
msg_perr("Missing argument for laptop.\n");
|
||||||
|
} else if (arg) {
|
||||||
|
msg_perr("Unknown argument for laptop: %s\n", arg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
free(arg);
|
||||||
|
|
||||||
get_io_perms();
|
get_io_perms();
|
||||||
|
|
||||||
/* Initialize PCI access for flash enables */
|
/* Initialize PCI access for flash enables */
|
||||||
@ -155,22 +172,35 @@ int internal_init(void)
|
|||||||
probe_superio();
|
probe_superio();
|
||||||
|
|
||||||
/* Warn if a laptop is detected. */
|
/* Warn if a laptop is detected. */
|
||||||
if (is_laptop)
|
if (is_laptop) {
|
||||||
printf("========================================================================\n"
|
msg_perr("========================================================================\n"
|
||||||
"WARNING! You seem to be running flashrom on a laptop.\n"
|
"WARNING! You seem to be running flashrom on a laptop.\n"
|
||||||
"Laptops, notebooks and netbooks are difficult to support and we recommend\n"
|
"Laptops, notebooks and netbooks are difficult to support and we recommend\n"
|
||||||
"to use the vendor flashing utility. The embedded controller (EC) in these\n"
|
"to use the vendor flashing utility. The embedded controller (EC) in these\n"
|
||||||
"machines often interacts badly with flashing.\n"
|
"machines often interacts badly with flashing.\n"
|
||||||
"See http://www.flashrom.org/Laptops for details.\n"
|
"See http://www.flashrom.org/Laptops for details.\n\n"
|
||||||
"========================================================================\n");
|
"If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
|
||||||
|
"and write may brick your laptop.\n"
|
||||||
|
"Read and probe may irritate your EC and cause fan failure, backlight\n"
|
||||||
|
"failure and sudden poweroff.\n"
|
||||||
|
"You have been warned.\n"
|
||||||
|
"========================================================================\n");
|
||||||
|
if (force_laptop) {
|
||||||
|
msg_perr("Proceeding anyway because user specified "
|
||||||
|
"laptop=force_I_want_a_brick\n");
|
||||||
|
} else {
|
||||||
|
msg_perr("Aborting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* try to enable it. Failure IS an option, since not all motherboards
|
/* try to enable it. Failure IS an option, since not all motherboards
|
||||||
* really need this to be done, etc., etc.
|
* really need this to be done, etc., etc.
|
||||||
*/
|
*/
|
||||||
ret = chipset_flash_enable();
|
ret = chipset_flash_enable();
|
||||||
if (ret == -2) {
|
if (ret == -2) {
|
||||||
printf("WARNING: No chipset found. Flash detection "
|
msg_perr("WARNING: No chipset found. Flash detection "
|
||||||
"will most likely fail.\n");
|
"will most likely fail.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Probe for IT87* LPC->SPI translation unconditionally. */
|
/* Probe for IT87* LPC->SPI translation unconditionally. */
|
||||||
@ -182,7 +212,7 @@ int internal_init(void)
|
|||||||
* The error code might have been a warning only.
|
* The error code might have been a warning only.
|
||||||
* Besides that, we don't check the board enable return code either.
|
* Besides that, we don't check the board enable return code either.
|
||||||
*/
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int internal_shutdown(void)
|
int internal_shutdown(void)
|
||||||
|
7
layout.c
7
layout.c
@ -111,14 +111,15 @@ int show_id(uint8_t *bios, int size, int force)
|
|||||||
!strcasecmp(mainboard_part, lb_part)) {
|
!strcasecmp(mainboard_part, lb_part)) {
|
||||||
printf_debug("This firmware image matches this mainboard.\n");
|
printf_debug("This firmware image matches this mainboard.\n");
|
||||||
} else {
|
} else {
|
||||||
if (force) {
|
if (force_boardmismatch) {
|
||||||
printf("WARNING: This firmware image does not "
|
printf("WARNING: This firmware image does not "
|
||||||
"seem to fit to this machine - forcing it.\n");
|
"seem to fit to this machine - forcing it.\n");
|
||||||
} else {
|
} else {
|
||||||
printf("ERROR: Your firmware image (%s:%s) does not "
|
printf("ERROR: Your firmware image (%s:%s) does not "
|
||||||
"appear to\n be correct for the detected "
|
"appear to\n be correct for the detected "
|
||||||
"mainboard (%s:%s)\n\nOverride with --force if you "
|
"mainboard (%s:%s)\n\nOverride with -p internal:"
|
||||||
"are absolutely sure that you\nare using a correct "
|
"boardmismatch=force if you are absolutely sure "
|
||||||
|
"that\nyou are using a correct "
|
||||||
"image for this mainboard or override\nthe detected "
|
"image for this mainboard or override\nthe detected "
|
||||||
"values with --mainboard <vendor>:<mainboard>.\n\n",
|
"values with --mainboard <vendor>:<mainboard>.\n\n",
|
||||||
mainboard_vendor, mainboard_part, lb_vendor,
|
mainboard_vendor, mainboard_part, lb_vendor,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user