diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2008-10-01 20:18:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-01 20:31:25 -0400 |
commit | 4a7703582836f55a1cbad0e2c1c6ebbee3f9b3a7 (patch) | |
tree | 8ebe25b1ef16c8fd4ced6d356232ddca94ef97a2 | |
parent | 20b918dc77b383e9779dafceee3f2198a6f7b0e5 (diff) |
e1000e: write protect ICHx NVM to prevent malicious write/erase
Set the hardware to ignore all write/erase cycles to the GbE region in
the ICHx NVM. This feature can be disabled by the WriteProtectNVM module
parameter (enabled by default) only after a hardware reset, but
the machine must be power cycled before trying to enable writes.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
CC: arjan@linux.intel.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/net/e1000e/e1000.h | 2 | ||||
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 3 | ||||
-rw-r--r-- | drivers/net/e1000e/ich8lan.c | 58 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 10 | ||||
-rw-r--r-- | drivers/net/e1000e/param.c | 30 |
5 files changed, 100 insertions, 3 deletions
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index ac4e506b4f88..f0c48a2a6799 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -305,6 +305,7 @@ struct e1000_info { | |||
305 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) | 305 | #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) |
306 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) | 306 | #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) |
307 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) | 307 | #define FLAG_HAS_JUMBO_FRAMES (1 << 7) |
308 | #define FLAG_READ_ONLY_NVM (1 << 8) | ||
308 | #define FLAG_IS_ICH (1 << 9) | 309 | #define FLAG_IS_ICH (1 << 9) |
309 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) | 310 | #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) |
310 | #define FLAG_IS_QUAD_PORT_A (1 << 12) | 311 | #define FLAG_IS_QUAD_PORT_A (1 << 12) |
@@ -385,6 +386,7 @@ extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); | |||
385 | extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); | 386 | extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); |
386 | extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); | 387 | extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); |
387 | 388 | ||
389 | extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw); | ||
388 | extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, | 390 | extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, |
389 | bool state); | 391 | bool state); |
390 | extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); | 392 | extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); |
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index e21c9e0f3738..5ed8e13d5fed 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
@@ -529,6 +529,9 @@ static int e1000_set_eeprom(struct net_device *netdev, | |||
529 | if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) | 529 | if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16))) |
530 | return -EFAULT; | 530 | return -EFAULT; |
531 | 531 | ||
532 | if (adapter->flags & FLAG_READ_ONLY_NVM) | ||
533 | return -EINVAL; | ||
534 | |||
532 | max_len = hw->nvm.word_size * 2; | 535 | max_len = hw->nvm.word_size * 2; |
533 | 536 | ||
534 | first_word = eeprom->offset >> 1; | 537 | first_word = eeprom->offset >> 1; |
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 9e38452a738c..d8efba884134 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #define ICH_FLASH_HSFCTL 0x0006 | 58 | #define ICH_FLASH_HSFCTL 0x0006 |
59 | #define ICH_FLASH_FADDR 0x0008 | 59 | #define ICH_FLASH_FADDR 0x0008 |
60 | #define ICH_FLASH_FDATA0 0x0010 | 60 | #define ICH_FLASH_FDATA0 0x0010 |
61 | #define ICH_FLASH_PR0 0x0074 | ||
61 | 62 | ||
62 | #define ICH_FLASH_READ_COMMAND_TIMEOUT 500 | 63 | #define ICH_FLASH_READ_COMMAND_TIMEOUT 500 |
63 | #define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 | 64 | #define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500 |
@@ -150,6 +151,19 @@ union ich8_hws_flash_regacc { | |||
150 | u16 regval; | 151 | u16 regval; |
151 | }; | 152 | }; |
152 | 153 | ||
154 | /* ICH Flash Protected Region */ | ||
155 | union ich8_flash_protected_range { | ||
156 | struct ich8_pr { | ||
157 | u32 base:13; /* 0:12 Protected Range Base */ | ||
158 | u32 reserved1:2; /* 13:14 Reserved */ | ||
159 | u32 rpe:1; /* 15 Read Protection Enable */ | ||
160 | u32 limit:13; /* 16:28 Protected Range Limit */ | ||
161 | u32 reserved2:2; /* 29:30 Reserved */ | ||
162 | u32 wpe:1; /* 31 Write Protection Enable */ | ||
163 | } range; | ||
164 | u32 regval; | ||
165 | }; | ||
166 | |||
153 | static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); | 167 | static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); |
154 | static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); | 168 | static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); |
155 | static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); | 169 | static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); |
@@ -1284,6 +1298,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) | |||
1284 | * programming failed. | 1298 | * programming failed. |
1285 | */ | 1299 | */ |
1286 | if (ret_val) { | 1300 | if (ret_val) { |
1301 | /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ | ||
1287 | hw_dbg(hw, "Flash commit failed.\n"); | 1302 | hw_dbg(hw, "Flash commit failed.\n"); |
1288 | e1000_release_swflag_ich8lan(hw); | 1303 | e1000_release_swflag_ich8lan(hw); |
1289 | return ret_val; | 1304 | return ret_val; |
@@ -1374,6 +1389,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) | |||
1374 | } | 1389 | } |
1375 | 1390 | ||
1376 | /** | 1391 | /** |
1392 | * e1000e_write_protect_nvm_ich8lan - Make the NVM read-only | ||
1393 | * @hw: pointer to the HW structure | ||
1394 | * | ||
1395 | * To prevent malicious write/erase of the NVM, set it to be read-only | ||
1396 | * so that the hardware ignores all write/erase cycles of the NVM via | ||
1397 | * the flash control registers. The shadow-ram copy of the NVM will | ||
1398 | * still be updated, however any updates to this copy will not stick | ||
1399 | * across driver reloads. | ||
1400 | **/ | ||
1401 | void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw) | ||
1402 | { | ||
1403 | union ich8_flash_protected_range pr0; | ||
1404 | union ich8_hws_flash_status hsfsts; | ||
1405 | u32 gfpreg; | ||
1406 | s32 ret_val; | ||
1407 | |||
1408 | ret_val = e1000_acquire_swflag_ich8lan(hw); | ||
1409 | if (ret_val) | ||
1410 | return; | ||
1411 | |||
1412 | gfpreg = er32flash(ICH_FLASH_GFPREG); | ||
1413 | |||
1414 | /* Write-protect GbE Sector of NVM */ | ||
1415 | pr0.regval = er32flash(ICH_FLASH_PR0); | ||
1416 | pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK; | ||
1417 | pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK); | ||
1418 | pr0.range.wpe = true; | ||
1419 | ew32flash(ICH_FLASH_PR0, pr0.regval); | ||
1420 | |||
1421 | /* | ||
1422 | * Lock down a subset of GbE Flash Control Registers, e.g. | ||
1423 | * PR0 to prevent the write-protection from being lifted. | ||
1424 | * Once FLOCKDN is set, the registers protected by it cannot | ||
1425 | * be written until FLOCKDN is cleared by a hardware reset. | ||
1426 | */ | ||
1427 | hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); | ||
1428 | hsfsts.hsf_status.flockdn = true; | ||
1429 | ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval); | ||
1430 | |||
1431 | e1000_release_swflag_ich8lan(hw); | ||
1432 | } | ||
1433 | |||
1434 | /** | ||
1377 | * e1000_write_flash_data_ich8lan - Writes bytes to the NVM | 1435 | * e1000_write_flash_data_ich8lan - Writes bytes to the NVM |
1378 | * @hw: pointer to the HW structure | 1436 | * @hw: pointer to the HW structure |
1379 | * @offset: The offset (in bytes) of the byte/word to read. | 1437 | * @offset: The offset (in bytes) of the byte/word to read. |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index d266510c8a94..1f767feda9a7 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -47,7 +47,7 @@ | |||
47 | 47 | ||
48 | #include "e1000.h" | 48 | #include "e1000.h" |
49 | 49 | ||
50 | #define DRV_VERSION "0.3.3.3-k2" | 50 | #define DRV_VERSION "0.3.3.3-k4" |
51 | char e1000e_driver_name[] = "e1000e"; | 51 | char e1000e_driver_name[] = "e1000e"; |
52 | const char e1000e_driver_version[] = DRV_VERSION; | 52 | const char e1000e_driver_version[] = DRV_VERSION; |
53 | 53 | ||
@@ -4467,6 +4467,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
4467 | 4467 | ||
4468 | adapter->bd_number = cards_found++; | 4468 | adapter->bd_number = cards_found++; |
4469 | 4469 | ||
4470 | e1000e_check_options(adapter); | ||
4471 | |||
4470 | /* setup adapter struct */ | 4472 | /* setup adapter struct */ |
4471 | err = e1000_sw_init(adapter); | 4473 | err = e1000_sw_init(adapter); |
4472 | if (err) | 4474 | if (err) |
@@ -4482,6 +4484,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
4482 | if (err) | 4484 | if (err) |
4483 | goto err_hw_init; | 4485 | goto err_hw_init; |
4484 | 4486 | ||
4487 | if ((adapter->flags & FLAG_IS_ICH) && | ||
4488 | (adapter->flags & FLAG_READ_ONLY_NVM)) | ||
4489 | e1000e_write_protect_nvm_ich8lan(&adapter->hw); | ||
4490 | |||
4485 | hw->mac.ops.get_bus_info(&adapter->hw); | 4491 | hw->mac.ops.get_bus_info(&adapter->hw); |
4486 | 4492 | ||
4487 | adapter->hw.phy.autoneg_wait_to_complete = 0; | 4493 | adapter->hw.phy.autoneg_wait_to_complete = 0; |
@@ -4573,8 +4579,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, | |||
4573 | INIT_WORK(&adapter->reset_task, e1000_reset_task); | 4579 | INIT_WORK(&adapter->reset_task, e1000_reset_task); |
4574 | INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); | 4580 | INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task); |
4575 | 4581 | ||
4576 | e1000e_check_options(adapter); | ||
4577 | |||
4578 | /* Initialize link parameters. User can change them with ethtool */ | 4582 | /* Initialize link parameters. User can change them with ethtool */ |
4579 | adapter->hw.mac.autoneg = 1; | 4583 | adapter->hw.mac.autoneg = 1; |
4580 | adapter->fc_autoneg = 1; | 4584 | adapter->fc_autoneg = 1; |
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index ed912e023a72..d91dbf7ba434 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c | |||
@@ -133,6 +133,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down"); | |||
133 | */ | 133 | */ |
134 | E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); | 134 | E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); |
135 | 135 | ||
136 | /* | ||
137 | * Write Protect NVM | ||
138 | * | ||
139 | * Valid Range: 0, 1 | ||
140 | * | ||
141 | * Default Value: 1 (enabled) | ||
142 | */ | ||
143 | E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]"); | ||
144 | |||
136 | struct e1000_option { | 145 | struct e1000_option { |
137 | enum { enable_option, range_option, list_option } type; | 146 | enum { enable_option, range_option, list_option } type; |
138 | const char *name; | 147 | const char *name; |
@@ -388,4 +397,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) | |||
388 | opt.def); | 397 | opt.def); |
389 | } | 398 | } |
390 | } | 399 | } |
400 | { /* Write-protect NVM */ | ||
401 | const struct e1000_option opt = { | ||
402 | .type = enable_option, | ||
403 | .name = "Write-protect NVM", | ||
404 | .err = "defaulting to Enabled", | ||
405 | .def = OPTION_ENABLED | ||
406 | }; | ||
407 | |||
408 | if (adapter->flags & FLAG_IS_ICH) { | ||
409 | if (num_WriteProtectNVM > bd) { | ||
410 | unsigned int write_protect_nvm = WriteProtectNVM[bd]; | ||
411 | e1000_validate_option(&write_protect_nvm, &opt, | ||
412 | adapter); | ||
413 | if (write_protect_nvm) | ||
414 | adapter->flags |= FLAG_READ_ONLY_NVM; | ||
415 | } else { | ||
416 | if (opt.def) | ||
417 | adapter->flags |= FLAG_READ_ONLY_NVM; | ||
418 | } | ||
419 | } | ||
420 | } | ||
391 | } | 421 | } |