xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/smm/smihandler.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/hlt.h>
4 #include <arch/io.h>
5 #include <console/console.h>
6 #include <cpu/x86/cache.h>
7 #include <cpu/x86/msr.h>
8 #include <cpu/x86/smm.h>
9 #include <cpu/intel/em64t100_save_state.h>
10 #include <cpu/intel/em64t101_save_state.h>
11 #include <cpu/intel/msr.h>
12 #include <delay.h>
13 #include <device/mmio.h>
14 #include <device/pci_def.h>
15 #include <device/pci_ops.h>
16 #include <elog.h>
17 #include <intelblocks/fast_spi.h>
18 #include <intelblocks/oc_wdt.h>
19 #include <intelblocks/pmclib.h>
20 #include <intelblocks/smihandler.h>
21 #include <intelblocks/tco.h>
22 #include <intelblocks/uart.h>
23 #include <smmstore.h>
24 #include <soc/nvs.h>
25 #include <soc/pci_devs.h>
26 #include <soc/pm.h>
27 #include <soc/gpio.h>
28 #include <soc/iomap.h>
29 #include <soc/smbus.h>
30 #include <spi-generic.h>
31 #include <stdint.h>
32 
33 /* SoC overrides. */
34 
get_smm_save_state_ops(void)35 __weak const struct smm_save_state_ops *get_smm_save_state_ops(void)
36 {
37 	return &em64t101_smm_ops;
38 }
39 
40 /* Specific SOC SMI handler during ramstage finalize phase */
smihandler_soc_at_finalize(void)41 __weak void smihandler_soc_at_finalize(void)
42 {
43 	/* no-op */
44 }
45 
smihandler_soc_disable_busmaster(pci_devfn_t dev)46 __weak int smihandler_soc_disable_busmaster(pci_devfn_t dev)
47 {
48 	return 1;
49 }
50 
51 /* Mainboard overrides. */
52 
mainboard_smi_gpi_handler(const struct gpi_status * sts)53 __weak void mainboard_smi_gpi_handler(
54 	const struct gpi_status *sts)
55 {
56 	/* no-op */
57 }
58 
mainboard_smi_espi_handler(void)59 __weak void mainboard_smi_espi_handler(void)
60 {
61 	/* no-op */
62 }
63 
64 /* Common Functions */
65 
find_save_state(const struct smm_save_state_ops * save_state_ops,int cmd)66 static void *find_save_state(const struct smm_save_state_ops *save_state_ops,
67 	int cmd)
68 {
69 	int node;
70 	void *state = NULL;
71 	uint32_t io_misc_info;
72 	uint8_t reg_al;
73 
74 	/* Check all nodes looking for the one that issued the IO */
75 	for (node = 0; node < CONFIG_MAX_CPUS; node++) {
76 		state = smm_get_save_state(node);
77 
78 		io_misc_info = save_state_ops->get_io_misc_info(state);
79 
80 		/* Check for Synchronous IO (bit0==1) */
81 		if (!(io_misc_info & (1 << 0)))
82 			continue;
83 		/* Make sure it was a write (bit4==0) */
84 		if (io_misc_info & (1 << 4))
85 			continue;
86 		/* Check for APMC IO port */
87 		if (((io_misc_info >> 16) & 0xff) != APM_CNT)
88 			continue;
89 		/* Check AL against the requested command */
90 		reg_al = save_state_ops->get_reg(state, RAX);
91 		if (reg_al != cmd)
92 			continue;
93 		break;
94 	}
95 	return state;
96 }
97 
98 /* Inherited from cpu/x86/smm.h resulting in a different signature */
southbridge_smi_set_eos(void)99 void southbridge_smi_set_eos(void)
100 {
101 	pmc_enable_smi(EOS);
102 }
103 
busmaster_disable_on_bus(int bus)104 static void busmaster_disable_on_bus(int bus)
105 {
106 	int slot, func;
107 	unsigned int val;
108 	unsigned char hdr;
109 
110 	for (slot = 0; slot < 0x20; slot++) {
111 		for (func = 0; func < 8; func++) {
112 			u16 reg16;
113 
114 			pci_devfn_t dev = PCI_DEV(bus, slot, func);
115 
116 			if (!smihandler_soc_disable_busmaster(dev))
117 				continue;
118 			val = pci_read_config32(dev, PCI_VENDOR_ID);
119 
120 			if (val == 0xffffffff || val == 0x00000000 ||
121 			    val == 0x0000ffff || val == 0xffff0000)
122 				continue;
123 
124 			/* Disable Bus Mastering for this one device */
125 			reg16 = pci_read_config16(dev, PCI_COMMAND);
126 			reg16 &= ~PCI_COMMAND_MASTER;
127 			pci_write_config16(dev, PCI_COMMAND, reg16);
128 
129 			/* If it's not a bridge, move on. */
130 			hdr = pci_read_config8(dev, PCI_HEADER_TYPE);
131 			hdr &= 0x7f;
132 			if (hdr != PCI_HEADER_TYPE_BRIDGE &&
133 			    hdr != PCI_HEADER_TYPE_CARDBUS)
134 				continue;
135 
136 			/*
137 			 * If secondary bus is equal to current bus bypass
138 			 * the bridge because it's likely unconfigured and
139 			 * would cause infinite recursion.
140 			 */
141 			int secbus = pci_read_config8(dev, PCI_SECONDARY_BUS);
142 
143 			if (secbus == bus)
144 				continue;
145 
146 			busmaster_disable_on_bus(secbus);
147 		}
148 	}
149 }
150 
smihandler_southbridge_sleep(const struct smm_save_state_ops * save_state_ops)151 void smihandler_southbridge_sleep(
152 	const struct smm_save_state_ops *save_state_ops)
153 {
154 	uint32_t reg32;
155 	uint8_t slp_typ;
156 
157 	/* First, disable further SMIs */
158 	pmc_disable_smi(SLP_SMI_EN);
159 	/* Figure out SLP_TYP */
160 	reg32 = inl(ACPI_BASE_ADDRESS + PM1_CNT);
161 	printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32);
162 	slp_typ = acpi_sleep_from_pm1(reg32);
163 
164 	/* Do any mainboard sleep handling */
165 	mainboard_smi_sleep(slp_typ);
166 
167 	/* Log S3, S4, and S5 entry */
168 	if (slp_typ >= ACPI_S3)
169 		elog_gsmi_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ);
170 
171 	/* Clear pending GPE events */
172 	pmc_clear_all_gpe_status();
173 
174 	/* Next, do the deed. */
175 
176 	switch (slp_typ) {
177 	case ACPI_S0:
178 		printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
179 		break;
180 	case ACPI_S3:
181 		printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
182 		if (CONFIG(SOC_INTEL_COMMON_BLOCK_UART))
183 			gnvs->uior = uart_is_controller_initialized();
184 
185 		/* Invalidate the cache before going to S3 */
186 		wbinvd();
187 		break;
188 	case ACPI_S4:
189 		printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
190 		break;
191 	case ACPI_S5:
192 		printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
193 
194 		/* Disable all GPE */
195 		pmc_disable_all_gpe();
196 		/* Set which state system will be after power reapplied */
197 		pmc_set_power_failure_state(false);
198 		/* also iterates over all bridges on bus 0 */
199 		busmaster_disable_on_bus(0);
200 
201 		/*
202 		 * Some platforms (e.g. Chromebooks) have observed race between
203 		 * SLP SMI and PWRBTN SMI because of the way these SMIs are
204 		 * triggered on power button press. Allow adding a delay before
205 		 * triggering sleep enable for S5, so that power button
206 		 * interrupt does not result into immediate wake.
207 		 */
208 		mdelay(CONFIG_SOC_INTEL_COMMON_BLOCK_SMM_S5_DELAY_MS);
209 
210 		/*
211 		 * Ensure any pending power button status bits are cleared as
212 		 * the system is entering S5 and doesn't want to be woken up
213 		 * right away from older power button events.
214 		 */
215 		pmc_clear_pm1_status();
216 
217 		break;
218 	default:
219 		printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
220 		break;
221 	}
222 
223 	/*
224 	 * Write back to the SLP register to cause the originally intended
225 	 * event again. We need to set BIT13 (SLP_EN) though to make the
226 	 * sleep happen.
227 	 */
228 	pmc_enable_pm1_control(SLP_EN);
229 
230 	/* Make sure to stop executing code here for S3/S4/S5 */
231 	if (slp_typ >= ACPI_S3)
232 		hlt();
233 
234 	/*
235 	 * In most sleep states, the code flow of this function ends at
236 	 * the line above. However, if we entered sleep state S1 and wake
237 	 * up again, we will continue to execute code in this function.
238 	 */
239 	if (pmc_read_pm1_control() & SCI_EN) {
240 		/* The OS is not an ACPI OS, so we set the state to S0 */
241 		pmc_disable_pm1_control(SLP_EN | SLP_TYP);
242 	}
243 }
244 
southbridge_smi_gsmi(const struct smm_save_state_ops * save_state_ops)245 static void southbridge_smi_gsmi(
246 	const struct smm_save_state_ops *save_state_ops)
247 {
248 	u8 sub_command, ret;
249 	void *io_smi = NULL;
250 	uint32_t reg_ebx;
251 
252 	io_smi = find_save_state(save_state_ops, APM_CNT_ELOG_GSMI);
253 	if (!io_smi)
254 		return;
255 	/* Command and return value in EAX */
256 	sub_command = (save_state_ops->get_reg(io_smi, RAX) >> 8)
257 		& 0xff;
258 
259 	/* Parameter buffer in EBX */
260 	reg_ebx = save_state_ops->get_reg(io_smi, RBX);
261 
262 	/* drivers/elog/gsmi.c */
263 	ret = gsmi_exec(sub_command, &reg_ebx);
264 	save_state_ops->set_reg(io_smi, RAX, ret);
265 }
266 
set_insmm_sts(const bool enable_writes)267 static void set_insmm_sts(const bool enable_writes)
268 {
269 	msr_t msr = {
270 		.lo = read32p(0xfed30880),
271 		.hi = 0,
272 	};
273 	if (enable_writes)
274 		msr.lo |= 1;
275 	else
276 		msr.lo &= ~1;
277 
278 	wrmsr(MSR_SPCL_CHIPSET_USAGE, msr);
279 }
280 
southbridge_smi_store(const struct smm_save_state_ops * save_state_ops)281 static void southbridge_smi_store(
282 	const struct smm_save_state_ops *save_state_ops)
283 {
284 	u8 sub_command, ret;
285 	void *io_smi;
286 	uint32_t reg_ebx;
287 
288 	io_smi = find_save_state(save_state_ops, APM_CNT_SMMSTORE);
289 	if (!io_smi)
290 		return;
291 	/* Command and return value in EAX */
292 	sub_command = (save_state_ops->get_reg(io_smi, RAX) >> 8) & 0xff;
293 
294 	/* Parameter buffer in EBX */
295 	reg_ebx = save_state_ops->get_reg(io_smi, RBX);
296 
297 	const bool wp_enabled = !fast_spi_wpd_status();
298 	if (wp_enabled) {
299 		set_insmm_sts(true);
300 		/*
301 		 * As per BWG, clearing "SPI_BIOS_CONTROL_SYNC_SS"
302 		 * bit is a must prior setting SPI_BIOS_CONTROL_WPD" bit
303 		 * to avoid 3-strike error.
304 		 */
305 		fast_spi_clear_sync_smi_status();
306 		fast_spi_disable_wp();
307 	}
308 
309 	/* drivers/smmstore/smi.c */
310 	ret = smmstore_exec(sub_command, (void *)(uintptr_t)reg_ebx);
311 	save_state_ops->set_reg(io_smi, RAX, ret);
312 
313 	if (wp_enabled) {
314 		fast_spi_enable_wp();
315 		set_insmm_sts(false);
316 	}
317 }
318 
soc_gpio_lock_config(size_t * num)319 __weak const struct gpio_lock_config *soc_gpio_lock_config(size_t *num)
320 {
321 	*num = 0;
322 	return NULL;
323 }
324 
soc_lock_gpios(void)325 static void soc_lock_gpios(void)
326 {
327 	const struct gpio_lock_config *soc_gpios;
328 	size_t soc_gpio_num;
329 
330 	/* get list of gpios from SoC */
331 	soc_gpios = soc_gpio_lock_config(&soc_gpio_num);
332 
333 	/* Lock any soc requested gpios */
334 	if (soc_gpio_num)
335 		gpio_lock_pads(soc_gpios, soc_gpio_num);
336 }
337 
finalize(void)338 static void finalize(void)
339 {
340 	static int finalize_done;
341 
342 	if (finalize_done) {
343 		printk(BIOS_DEBUG, "SMM already finalized.\n");
344 		return;
345 	}
346 	finalize_done = 1;
347 
348 	if (CONFIG(SPI_FLASH_SMM))
349 		/* Re-init SPI driver to handle locked BAR */
350 		fast_spi_init();
351 
352 	if (CONFIG(BOOTMEDIA_SMM_BWP)) {
353 		fast_spi_enable_wp();
354 		set_insmm_sts(false);
355 	}
356 
357 	/*
358 	 * HECI is disabled in smihandler_soc_at_finalize() which also locks down the side band
359 	 * interface.  Some boards may require this interface in mainboard_smi_finalize(),
360 	 * therefore, this call must precede smihandler_soc_at_finalize().
361 	 */
362 	mainboard_smi_finalize();
363 
364 	/* Lock down all GPIOs that may have been requested by the SoC and/or the mainboard. */
365 	if (CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_LOCK_GPIO_PADS))
366 		soc_lock_gpios();
367 
368 	/* Specific SOC SMI handler during ramstage finalize phase */
369 	smihandler_soc_at_finalize();
370 }
371 
smihandler_southbridge_apmc(const struct smm_save_state_ops * save_state_ops)372 void smihandler_southbridge_apmc(
373 	const struct smm_save_state_ops *save_state_ops)
374 {
375 	uint8_t reg8;
376 
377 	reg8 = apm_get_apmc();
378 	switch (reg8) {
379 	case APM_CNT_ACPI_DISABLE:
380 		pmc_disable_pm1_control(SCI_EN);
381 		break;
382 	case APM_CNT_ACPI_ENABLE:
383 		pmc_enable_pm1_control(SCI_EN);
384 		break;
385 	case APM_CNT_ELOG_GSMI:
386 		if (CONFIG(ELOG_GSMI))
387 			southbridge_smi_gsmi(save_state_ops);
388 		break;
389 	case APM_CNT_SMMSTORE:
390 		if (CONFIG(SMMSTORE))
391 			southbridge_smi_store(save_state_ops);
392 		break;
393 	case APM_CNT_FINALIZE:
394 		finalize();
395 		break;
396 	}
397 
398 	mainboard_smi_apmc(reg8);
399 }
400 
smihandler_southbridge_pm1(const struct smm_save_state_ops * save_state_ops)401 void smihandler_southbridge_pm1(
402 	const struct smm_save_state_ops *save_state_ops)
403 {
404 	uint16_t pm1_sts = pmc_clear_pm1_status();
405 	u16 pm1_en = pmc_read_pm1_enable();
406 
407 	/*
408 	 * While OSPM is not active, poweroff immediately
409 	 * on a power button event.
410 	 */
411 	if ((pm1_sts & PWRBTN_STS) && (pm1_en & PWRBTN_EN)) {
412 		/* power button pressed */
413 		elog_gsmi_add_event(ELOG_TYPE_POWER_BUTTON);
414 		pmc_disable_pm1_control(~0);
415 		pmc_enable_pm1_control(SLP_EN | (SLP_TYP_S5 << SLP_TYP_SHIFT));
416 	}
417 }
418 
smihandler_southbridge_gpe0(const struct smm_save_state_ops * save_state_ops)419 void smihandler_southbridge_gpe0(
420 	const struct smm_save_state_ops *save_state_ops)
421 {
422 	pmc_clear_all_gpe_status();
423 }
424 
smihandler_southbridge_tco(const struct smm_save_state_ops * save_state_ops)425 void smihandler_southbridge_tco(
426 	const struct smm_save_state_ops *save_state_ops)
427 {
428 	uint32_t tco_sts = pmc_clear_tco_status();
429 
430 	/*
431 	 * SPI synchronous SMIs are TCO SMIs, but they do not have a status
432 	 * bit in the TCO_STS register. Furthermore, the TCO_STS bit in the
433 	 * SMI_STS register is continually set until the SMI handler clears
434 	 * the SPI synchronous SMI status bit in the SPI controller. To not
435 	 * risk missing any other TCO SMIs, do not clear the TCO_STS bit in
436 	 * this SMI handler invocation. If the TCO_STS bit remains set when
437 	 * returning from SMM, another SMI immediately happens which clears
438 	 * the TCO_STS bit and handles any pending events.
439 	 */
440 	fast_spi_clear_sync_smi_status();
441 
442 	/* If enabled, enforce SMM BIOS write protection */
443 	if (CONFIG(BOOTMEDIA_SMM_BWP) && fast_spi_wpd_status()) {
444 		/*
445 		 * BWE is RW, so the SMI was caused by a
446 		 * write to BWE, not by a write to the BIOS
447 		 *
448 		 * This is the place where we notice someone
449 		 * is trying to tinker with the BIOS. We are
450 		 * trying to be nice and just ignore it. A more
451 		 * resolute answer would be to power down the
452 		 * box.
453 		 */
454 		printk(BIOS_DEBUG, "Switching SPI back to RO\n");
455 		fast_spi_enable_wp();
456 		set_insmm_sts(false);
457 	}
458 
459 	/* Any TCO event? */
460 	if (!tco_sts)
461 		return;
462 
463 	if (tco_sts & TCO1_STS_TIMEOUT) { /* TIMEOUT */
464 		/* Handle TCO timeout */
465 		printk(BIOS_DEBUG, "TCO Timeout.\n");
466 	}
467 
468 	if (tco_sts & (TCO2_INTRD_DET << 16)) { /* INTRUDER# assertion */
469 		/*
470 		 * Handle intrusion event
471 		 * If we ever get here, probably the case has been opened.
472 		 */
473 		printk(BIOS_CRIT, "Case intrusion detected.\n");
474 	}
475 }
476 
smihandler_southbridge_periodic(const struct smm_save_state_ops * save_state_ops)477 void smihandler_southbridge_periodic(
478 	const struct smm_save_state_ops *save_state_ops)
479 {
480 	uint32_t reg32;
481 
482 	reg32 = pmc_get_smi_en();
483 
484 	/* Are periodic SMIs enabled? */
485 	if ((reg32 & PERIODIC_EN) == 0)
486 		return;
487 	printk(BIOS_DEBUG, "Periodic SMI.\n");
488 
489 	if (CONFIG(SOC_INTEL_COMMON_OC_WDT_RELOAD_IN_PERIODIC_SMI))
490 		oc_wdt_reload();
491 }
492 
smihandler_southbridge_gpi(const struct smm_save_state_ops * save_state_ops)493 void smihandler_southbridge_gpi(
494 	const struct smm_save_state_ops *save_state_ops)
495 {
496 	struct gpi_status smi_sts;
497 
498 	gpi_clear_get_smi_status(&smi_sts);
499 	mainboard_smi_gpi_handler(&smi_sts);
500 
501 	/* Clear again after mainboard handler */
502 	gpi_clear_get_smi_status(&smi_sts);
503 }
504 
smihandler_southbridge_espi(const struct smm_save_state_ops * save_state_ops)505 void smihandler_southbridge_espi(
506 	const struct smm_save_state_ops *save_state_ops)
507 {
508 	mainboard_smi_espi_handler();
509 }
510 
southbridge_smi_handler(void)511 void southbridge_smi_handler(void)
512 {
513 	int i;
514 	uint32_t smi_sts;
515 	const struct smm_save_state_ops *save_state_ops;
516 
517 	/*
518 	 * We need to clear the SMI status registers, or we won't see what's
519 	 * happening in the following calls.
520 	 */
521 	smi_sts = pmc_clear_smi_status();
522 
523 	/*
524 	 * When the SCI_EN bit is set, PM1 and GPE0 events will trigger a SCI
525 	 * instead of a SMI#. However, SMI_STS bits PM1_STS and GPE0_STS can
526 	 * still be set. Therefore, when SCI_EN is set, ignore PM1 and GPE0
527 	 * events in the SMI# handler, as these events have triggered a SCI.
528 	 * Do not ignore any other SMI# types, since they cannot cause a SCI.
529 	 */
530 	if (pmc_read_pm1_control() & SCI_EN)
531 		smi_sts &= ~(1 << PM1_STS_BIT | 1 << GPE0_STS_BIT);
532 
533 	if (!smi_sts)
534 		return;
535 
536 	save_state_ops = get_smm_save_state_ops();
537 
538 	/* Call SMI sub handler for each of the status bits */
539 	for (i = 0; i < ARRAY_SIZE(southbridge_smi); i++) {
540 		if (!(smi_sts & (1 << i)))
541 			continue;
542 
543 		if (southbridge_smi[i] != NULL) {
544 			southbridge_smi[i](save_state_ops);
545 		} else {
546 			printk(BIOS_DEBUG,
547 			       "SMI_STS[%d] occurred, but no "
548 			       "handler available.\n", i);
549 		}
550 	}
551 }
552 
em64t100_smm_save_state_get_io_misc_info(void * state)553 static uint32_t em64t100_smm_save_state_get_io_misc_info(void *state)
554 {
555 	em64t100_smm_state_save_area_t *smm_state = state;
556 	return smm_state->io_misc_info;
557 }
558 
em64t100_smm_save_state_get_reg(void * state,enum smm_reg reg)559 static uint64_t em64t100_smm_save_state_get_reg(void *state, enum smm_reg reg)
560 {
561 	uintptr_t value = 0;
562 	em64t100_smm_state_save_area_t *smm_state = state;
563 
564 	switch (reg) {
565 	case RAX:
566 		value = smm_state->rax;
567 		break;
568 	case RBX:
569 		value = smm_state->rbx;
570 		break;
571 	case RCX:
572 		value = smm_state->rcx;
573 		break;
574 	case RDX:
575 		value = smm_state->rdx;
576 		break;
577 	default:
578 		break;
579 	}
580 	return value;
581 }
582 
em64t100_smm_save_state_set_reg(void * state,enum smm_reg reg,uint64_t val)583 static void em64t100_smm_save_state_set_reg(void *state, enum smm_reg reg,
584 	uint64_t val)
585 {
586 	em64t100_smm_state_save_area_t *smm_state = state;
587 	switch (reg) {
588 	case RAX:
589 		smm_state->rax = val;
590 		break;
591 	case RBX:
592 		smm_state->rbx = val;
593 		break;
594 	case RCX:
595 		smm_state->rcx = val;
596 		break;
597 	case RDX:
598 		smm_state->rdx = val;
599 		break;
600 	default:
601 		break;
602 	}
603 }
604 
em64t101_smm_save_state_get_io_misc_info(void * state)605 static uint32_t em64t101_smm_save_state_get_io_misc_info(void *state)
606 {
607 	em64t101_smm_state_save_area_t *smm_state = state;
608 	return smm_state->io_misc_info;
609 }
610 
em64t101_smm_save_state_get_reg(void * state,enum smm_reg reg)611 static uint64_t em64t101_smm_save_state_get_reg(void *state, enum smm_reg reg)
612 {
613 	uintptr_t value = 0;
614 	em64t101_smm_state_save_area_t *smm_state = state;
615 
616 	switch (reg) {
617 	case RAX:
618 		value = smm_state->rax;
619 		break;
620 	case RBX:
621 		value = smm_state->rbx;
622 		break;
623 	case RCX:
624 		value = smm_state->rcx;
625 		break;
626 	case RDX:
627 		value = smm_state->rdx;
628 		break;
629 	default:
630 		break;
631 	}
632 	return value;
633 }
634 
em64t101_smm_save_state_set_reg(void * state,enum smm_reg reg,uint64_t val)635 static void em64t101_smm_save_state_set_reg(void *state, enum smm_reg reg,
636 	uint64_t val)
637 {
638 	em64t101_smm_state_save_area_t *smm_state = state;
639 	switch (reg) {
640 	case RAX:
641 		smm_state->rax = val;
642 		break;
643 	case RBX:
644 		smm_state->rbx = val;
645 		break;
646 	case RCX:
647 		smm_state->rcx = val;
648 		break;
649 	case RDX:
650 		smm_state->rdx = val;
651 		break;
652 	default:
653 		break;
654 	}
655 }
656 
657 const struct smm_save_state_ops em64t100_smm_ops = {
658 	.get_io_misc_info = em64t100_smm_save_state_get_io_misc_info,
659 	.get_reg = em64t100_smm_save_state_get_reg,
660 	.set_reg = em64t100_smm_save_state_set_reg,
661 };
662 
663 const struct smm_save_state_ops em64t101_smm_ops = {
664 	.get_io_misc_info = em64t101_smm_save_state_get_io_misc_info,
665 	.get_reg = em64t101_smm_save_state_get_reg,
666 	.set_reg = em64t101_smm_save_state_set_reg,
667 };
668