aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruce Allan <bruce.w.allan@intel.com>2008-10-01 20:18:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-01 20:31:25 -0400
commit4a7703582836f55a1cbad0e2c1c6ebbee3f9b3a7 (patch)
tree8ebe25b1ef16c8fd4ced6d356232ddca94ef97a2
parent20b918dc77b383e9779dafceee3f2198a6f7b0e5 (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.h2
-rw-r--r--drivers/net/e1000e/ethtool.c3
-rw-r--r--drivers/net/e1000e/ich8lan.c58
-rw-r--r--drivers/net/e1000e/netdev.c10
-rw-r--r--drivers/net/e1000e/param.c30
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);
385extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); 386extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
386extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); 387extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
387 388
389extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
388extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 390extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
389 bool state); 391 bool state);
390extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); 392extern 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 */
155union 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
153static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); 167static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
154static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 168static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
155static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 169static 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 **/
1401void 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"
51char e1000e_driver_name[] = "e1000e"; 51char e1000e_driver_name[] = "e1000e";
52const char e1000e_driver_version[] = DRV_VERSION; 52const 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 */
134E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround"); 134E1000_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 */
143E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
144
136struct e1000_option { 145struct 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}