coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
me.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /*
4  * This is a ramstage driver for the Intel Management Engine found in the
5  * 6-series chipset. It handles the required boot-time messages over the
6  * MMIO-based Management Engine Interface to tell the ME that the BIOS is
7  * finished with POST. Additional messages are defined for debug but are
8  * not used unless the console loglevel is high enough.
9  */
10 
11 #include <acpi/acpi.h>
12 #include <cf9_reset.h>
13 #include <device/mmio.h>
14 #include <device/device.h>
15 #include <device/pci.h>
16 #include <device/pci_ops.h>
17 #include <console/console.h>
18 #include <device/pci_ids.h>
19 #include <device/pci_def.h>
20 #include <elog.h>
21 #include <halt.h>
22 #include <option.h>
24 
25 #include "me.h"
26 #include "pch.h"
27 
28 /* Determine the path that we should take based on ME status */
29 static me_bios_path intel_me_path(struct device *dev)
30 {
32  union me_hfs hfs;
33  union me_gmes gmes;
34 
35  /* S3 wake skips all MKHI messages */
36  if (acpi_is_wakeup_s3())
37  return ME_S3WAKE_BIOS_PATH;
38 
39  hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
40  gmes.raw = pci_read_config32(dev, PCI_ME_GMES);
41 
42  /* Check and dump status */
43  intel_me_status(&hfs, &gmes);
44 
45  /* Check Current Working State */
46  switch (hfs.working_state) {
47  case ME_HFS_CWS_NORMAL:
48  path = ME_NORMAL_BIOS_PATH;
49  break;
50  case ME_HFS_CWS_REC:
51  path = ME_RECOVERY_BIOS_PATH;
52  break;
53  default:
54  path = ME_DISABLE_BIOS_PATH;
55  break;
56  }
57 
58  /* Check Current Operation Mode */
59  switch (hfs.operation_mode) {
60  case ME_HFS_MODE_NORMAL:
61  break;
62  case ME_HFS_MODE_DEBUG:
63  case ME_HFS_MODE_DIS:
66  default:
67  path = ME_DISABLE_BIOS_PATH;
68  break;
69  }
70 
71  /* Check for any error code and valid firmware */
72  if (hfs.error_code || hfs.fpt_bad)
73  path = ME_ERROR_BIOS_PATH;
74 
75  if (CONFIG(ELOG) && path != ME_NORMAL_BIOS_PATH) {
76  struct elog_event_data_me_extended data = {
78  .operation_state = hfs.operation_state,
79  .operation_mode = hfs.operation_mode,
80  .error_code = hfs.error_code,
81  .progress_code = gmes.progress_code,
82  .current_pmevent = gmes.current_pmevent,
83  .current_state = gmes.current_state,
84  };
87  &data, sizeof(data));
88  }
89 
90  return path;
91 }
92 
93 /* Get ME firmware version */
94 static int mkhi_get_fw_version(void)
95 {
96  struct me_fw_version version;
97  struct mkhi_header mkhi = {
99  .command = MKHI_GET_FW_VERSION,
100  };
101  struct mei_header mei = {
102  .is_complete = 1,
103  .host_address = MEI_HOST_ADDRESS,
104  .client_address = MEI_ADDRESS_MKHI,
105  .length = sizeof(mkhi),
106  };
107 
108  /* Send request and wait for response */
109  if (mei_sendrecv(&mei, &mkhi, NULL, &version, sizeof(version)) < 0) {
110  printk(BIOS_ERR, "ME: GET FW VERSION message failed\n");
111  return -1;
112  }
113 
114  printk(BIOS_INFO, "ME: Firmware Version %u.%u.%u.%u (code) "
115  "%u.%u.%u.%u (recovery)\n",
116  version.code_major, version.code_minor,
117  version.code_build_number, version.code_hot_fix,
118  version.recovery_major, version.recovery_minor,
119  version.recovery_build_number, version.recovery_hot_fix);
120 
121  return 0;
122 }
123 
124 static inline void print_cap(const char *name, int state)
125 {
126  printk(BIOS_DEBUG, "ME Capability: %-30s : %sabled\n",
127  name, state ? "en" : "dis");
128 }
129 
130 /* Get ME Firmware Capabilities */
131 static int mkhi_get_fwcaps(void)
132 {
133  u32 rule_id = 0;
134  struct me_fwcaps cap;
135  struct mkhi_header mkhi = {
137  .command = MKHI_FWCAPS_GET_RULE,
138  };
139  struct mei_header mei = {
140  .is_complete = 1,
141  .host_address = MEI_HOST_ADDRESS,
142  .client_address = MEI_ADDRESS_MKHI,
143  .length = sizeof(mkhi) + sizeof(rule_id),
144  };
145 
146  /* Send request and wait for response */
147  if (mei_sendrecv(&mei, &mkhi, &rule_id, &cap, sizeof(cap)) < 0) {
148  printk(BIOS_ERR, "ME: GET FWCAPS message failed\n");
149  return -1;
150  }
151 
152  print_cap("Full Network manageability", cap.caps_sku.full_net);
153  print_cap("Regular Network manageability", cap.caps_sku.std_net);
154  print_cap("Manageability", cap.caps_sku.manageability);
155  print_cap("Small business technology", cap.caps_sku.small_business);
156  print_cap("Level III manageability", cap.caps_sku.l3manageability);
157  print_cap("IntelR Anti-Theft (AT)", cap.caps_sku.intel_at);
158  print_cap("IntelR Capability Licensing Service (CLS)",
159  cap.caps_sku.intel_cls);
160  print_cap("IntelR Power Sharing Technology (MPC)",
161  cap.caps_sku.intel_mpc);
162  print_cap("ICC Over Clocking", cap.caps_sku.icc_over_clocking);
163  print_cap("Protected Audio Video Path (PAVP)", cap.caps_sku.pavp);
164  print_cap("IPV6", cap.caps_sku.ipv6);
165  print_cap("KVM Remote Control (KVM)", cap.caps_sku.kvm);
166  print_cap("Outbreak Containment Heuristic (OCH)", cap.caps_sku.och);
167  print_cap("Virtual LAN (VLAN)", cap.caps_sku.vlan);
168  print_cap("TLS", cap.caps_sku.tls);
169  print_cap("Wireless LAN (WLAN)", cap.caps_sku.wlan);
170 
171  return 0;
172 }
173 
174 
175 /* Check whether ME is present and do basic init */
176 static void intel_me_init(struct device *dev)
177 {
178  me_bios_path path = intel_me_path(dev);
179  bool need_reset = false;
180  union me_hfs hfs;
181 
182  /* Do initial setup and determine the BIOS path */
183  printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path));
184 
185  u8 me_state = get_uint_option("me_state", 0);
186  u8 me_state_prev = get_uint_option("me_state_prev", 0);
187 
188  printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev);
189 
190  switch (path) {
191  case ME_S3WAKE_BIOS_PATH:
192 #if CONFIG(HIDE_MEI_ON_ERROR)
193  case ME_ERROR_BIOS_PATH:
194 #endif
195  intel_me_hide(dev);
196  break;
197 
198  case ME_NORMAL_BIOS_PATH:
199  /* Validate the extend register */
200  if (intel_me_extend_valid(dev) < 0)
201  break; /* TODO: force recovery mode */
202 
203  /* Prepare MEI MMIO interface */
204  if (intel_mei_setup(dev) < 0)
205  break;
206 
207  if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) {
208  /* Print ME firmware version */
210  /* Print ME firmware capabilities */
211  mkhi_get_fwcaps();
212  }
213 
214  /* Put ME in Software Temporary Disable Mode, if needed */
215  if (me_state == CMOS_ME_STATE_DISABLED
216  && CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_NORMAL) {
217  printk(BIOS_INFO, "ME: disabling ME\n");
218  if (enter_soft_temp_disable()) {
220  need_reset = true;
221  } else {
222  printk(BIOS_ERR, "ME: failed to enter Soft Temporary Disable mode\n");
223  }
224 
225  break;
226  }
227 
228  /*
229  * Leave the ME unlocked in this path.
230  * It will be locked via SMI command later.
231  */
232  break;
233 
235  /* Bring ME out of Soft Temporary Disable mode, if needed */
236  hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
238  && me_state == CMOS_ME_STATE_NORMAL
239  && (CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_DISABLED
240  || !CMOS_ME_CHANGED(me_state_prev))) {
241  printk(BIOS_INFO, "ME: re-enabling ME\n");
242 
245 
246  /*
247  * ME starts loading firmware immediately after writing to H_GS,
248  * but Lenovo BIOS performs a reboot after bringing ME back to
249  * Normal mode. Assume that global reset is needed.
250  */
251  need_reset = true;
252  } else {
253  intel_me_hide(dev);
254  }
255  break;
256 
257 #if !CONFIG(HIDE_MEI_ON_ERROR)
258  case ME_ERROR_BIOS_PATH:
259 #endif
262  break;
263  }
264 
265  /* To avoid boot loops if ME fails to get back from disabled mode,
266  set the 'changed' bit here. */
267  if (me_state != CMOS_ME_STATE(me_state_prev) || need_reset) {
268  u8 new_state = me_state | CMOS_ME_STATE_CHANGED;
269  set_uint_option("me_state_prev", new_state);
270  }
271 
272  if (need_reset) {
273  set_global_reset(true);
274  full_reset();
275  }
276 }
277 
278 static struct device_operations device_ops = {
280  .set_resources = pci_dev_set_resources,
281  .enable_resources = pci_dev_enable_resources,
282  .init = intel_me_init,
283  .ops_pci = &pci_dev_ops_pci,
284 };
285 
286 static const struct pci_driver intel_me __pci_driver = {
287  .ops = &device_ops,
288  .vendor = PCI_VID_INTEL,
289  .device = 0x1c3a,
290 };
static int acpi_is_wakeup_s3(void)
Definition: acpi.h:9
const char * name
Definition: mmu.c:92
void full_reset(void)
Definition: cf9_reset.c:45
#define ELOG_TYPE_MANAGEMENT_ENGINE
Definition: elog.h:212
#define ELOG_TYPE_MANAGEMENT_ENGINE_EXT
Definition: elog.h:220
#define printk(level,...)
Definition: stdlib.h:16
int elog_add_event_raw(u8 event_type, void *data, u8 data_size)
Definition: elog.c:798
int elog_add_event_byte(u8 event_type, u8 data)
Definition: elog.c:868
@ CONFIG
Definition: dsi_common.h:201
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
unsigned int version[2]
Definition: edid.c:55
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_NOTICE
BIOS_NOTICE - Unexpected but relatively insignificant.
Definition: loglevel.h:100
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
state
Definition: raminit.c:1787
enum cb_err set_uint_option(const char *name, unsigned int value)
Definition: option.c:189
unsigned int get_uint_option(const char *name, const unsigned int fallback)
Definition: option.c:116
void pci_dev_enable_resources(struct device *dev)
Definition: pci_device.c:721
void pci_dev_read_resources(struct device *dev)
Definition: pci_device.c:534
struct pci_operations pci_dev_ops_pci
Default device operation for PCI devices.
Definition: pci_device.c:911
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
#define MKHI_GET_FW_VERSION
Definition: me.h:253
#define ME_HFS_CWS_REC
Definition: me.h:21
#define ME_HFS_MODE_NORMAL
Definition: me.h:36
#define ME_HFS_MODE_DIS
Definition: me.h:38
#define MKHI_GROUP_ID_FWCAPS
Definition: me.h:245
#define ME_HFS_MODE_OVER_MEI
Definition: me.h:40
#define MEI_ADDRESS_MKHI
Definition: me.h:229
#define PCI_ME_HFS
Definition: me.h:18
#define ME_HFS_CWS_NORMAL
Definition: me.h:22
#define ME_HFS_MODE_OVER_JMPR
Definition: me.h:39
#define MEI_HOST_ADDRESS
Definition: me.h:233
#define MKHI_GROUP_ID_GEN
Definition: me.h:252
me_bios_path
Definition: me.h:310
@ ME_ERROR_BIOS_PATH
Definition: me.h:313
@ ME_RECOVERY_BIOS_PATH
Definition: me.h:314
@ ME_DISABLE_BIOS_PATH
Definition: me.h:315
@ ME_FIRMWARE_UPDATE_BIOS_PATH
Definition: me.h:316
@ ME_S3WAKE_BIOS_PATH
Definition: me.h:312
@ ME_NORMAL_BIOS_PATH
Definition: me.h:311
#define MKHI_FWCAPS_GET_RULE
Definition: me.h:246
#define ME_HFS_MODE_DEBUG
Definition: me.h:37
void intel_me_status(void)
Definition: me.c:184
static struct device_operations device_ops
Definition: me.c:278
static const struct pci_driver intel_me __pci_driver
Definition: me.c:286
static void print_cap(const char *name, int state)
Definition: me.c:124
static int mkhi_get_fwcaps(void)
Definition: me.c:131
static int mkhi_get_fw_version(void)
Definition: me.c:94
static void intel_me_init(struct device *dev)
Definition: me.c:176
static me_bios_path intel_me_path(struct device *dev)
Definition: me.c:29
#define CMOS_ME_STATE_CHANGED
Definition: me.h:200
void exit_soft_temp_disable(struct device *dev)
Definition: me_common.c:454
#define CMOS_ME_STATE_NORMAL
Definition: me.h:198
#define CMOS_ME_STATE_DISABLED
Definition: me.h:199
const char *const me_get_bios_path_string(int path)
Definition: me_common.c:30
bool enter_soft_temp_disable(void)
Definition: me_common.c:411
#define PCI_ME_GMES
Definition: me.h:101
#define CMOS_ME_CHANGED(state)
Definition: me.h:197
void exit_soft_temp_disable_wait(struct device *dev)
Definition: me_common.c:460
void enter_soft_temp_disable_wait(void)
Definition: me_common.c:439
#define CMOS_ME_STATE(state)
Definition: me.h:196
void set_global_reset(const bool enable)
Definition: me.c:17
static void intel_me_hide(struct device *dev)
Definition: me.c:463
static int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi, void *req_data, void *rsp_data, int rsp_bytes)
Definition: me.c:315
static int intel_mei_setup(struct device *dev)
Definition: me.c:642
static int intel_me_extend_valid(struct device *dev)
Definition: me.c:669
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
uint8_t u8
Definition: stdint.h:45
void(* read_resources)(struct device *dev)
Definition: device.h:39
Definition: device.h:107
uint8_t current_working_state
Definition: elog.h:229
u32 wlan
Definition: me.h:418
u32 full_net
Definition: me.h:401
u32 icc_over_clocking
Definition: me.h:409
u32 och
Definition: me.h:414
u32 intel_cls
Definition: me.h:406
u32 intel_mpc
Definition: me.h:408
u32 pavp
Definition: me.h:410
u32 tls
Definition: me.h:416
u32 kvm
Definition: me.h:413
u32 manageability
Definition: me.h:403
u32 ipv6
Definition: me.h:412
u32 vlan
Definition: me.h:415
u32 std_net
Definition: me.h:402
u32 intel_at
Definition: me.h:405
Definition: me.h:474
mbp_mefwcaps caps_sku
Definition: me.h:477
Definition: me.h:51
u32 raw
Definition: me.h:69
u32 fpt_bad
Definition: me.h:54
u32 operation_state
Definition: me.h:55
u32 working_state
Definition: me.h:52
u32 operation_mode
Definition: me.h:60
u32 error_code
Definition: me.h:59
Definition: me.h:235
u32 is_complete
Definition: me.h:240
u32 group_id
Definition: me.h:259
Definition: me.h:110
u32 current_pmevent
Definition: me.h:124
u32 progress_code
Definition: me.h:125
u32 raw
Definition: me.h:127
u32 current_state
Definition: me.h:123