summaryrefslogtreecommitdiffstats
path: root/src/soc/amd/common/block/psp/psp_smm.c
blob: 7ffa6b61164c14a1ec43c212f45582980ce055ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/* SPDX-License-Identifier: GPL-2.0-only */
/* This file is part of the coreboot project. */

#include <device/mmio.h>
#include <cpu/x86/msr.h>
#include <cpu/amd/msr.h>
#include <cbfs.h>
#include <region_file.h>
#include <timer.h>
#include <bootstate.h>
#include <rules.h>
#include <console/console.h>
#include <amdblocks/psp.h>
#include <soc/iomap.h>
#include <soc/northbridge.h>
#include "psp_def.h"

#define C2P_BUFFER_MAXSIZE 0xc00 /* Core-to-PSP buffer */
#define P2C_BUFFER_MAXSIZE 0xc00 /* PSP-to-core buffer */

struct {
	u8 buffer[C2P_BUFFER_MAXSIZE];
} __attribute__((aligned(32))) c2p_buffer;

struct {
	u8 buffer[P2C_BUFFER_MAXSIZE];
} __attribute__((aligned(32))) p2c_buffer;

static uint32_t smm_flag; /* Non-zero for SMM, clear when not */

static void set_smm_flag(void)
{
	smm_flag = 1;
}

static void clear_smm_flag(void)
{
	smm_flag = 0;
}

int psp_notify_smm(void)
{
	msr_t msr;
	int cmd_status;
	struct mbox_cmd_smm_info_buffer buffer = {
		.header = {
			.size = sizeof(buffer)
		},
		.req = {
			.psp_smm_data_region = (uintptr_t)p2c_buffer.buffer,
			.psp_smm_data_length = sizeof(p2c_buffer),
			.psp_mbox_smm_buffer_address = (uintptr_t)c2p_buffer.buffer,
			.psp_mbox_smm_flag_address = (uintptr_t)&smm_flag,
		}
	};

	msr = rdmsr(SMM_ADDR_MSR);
	buffer.req.smm_base = ((uint64_t)msr.hi << 32) | msr.lo;
	msr = rdmsr(SMM_MASK_MSR);
	msr.lo &= 0xffff0000; /* mask SMM_LOCK and SMM_TSEG_VALID and reserved bits */
	buffer.req.smm_mask = ((uint64_t)msr.hi << 32) | msr.lo;

	soc_fill_smm_trig_info(&buffer.req.smm_trig_info);
#if (CONFIG(SOC_AMD_COMMON_BLOCK_PSP_GEN2))
	soc_fill_smm_reg_info(&buffer.req.smm_reg_info);
#endif

	printk(BIOS_DEBUG, "PSP: Notify SMM info... ");

	set_smm_flag();
	cmd_status = send_psp_command(MBOX_BIOS_CMD_SMM_INFO, &buffer);
	clear_smm_flag();

	/* buffer's status shouldn't change but report it if it does */
	psp_print_cmd_status(cmd_status, &buffer.header);

	return cmd_status;
}

/* Notify PSP the system is going to a sleep state. */
void psp_notify_sx_info(u8 sleep_type)
{
	int cmd_status;
	struct mbox_cmd_sx_info_buffer *buffer;

	/* PSP verifies that this buffer is at the address specified in psp_notify_smm() */
	buffer = (struct mbox_cmd_sx_info_buffer *)c2p_buffer.buffer;
	memset(buffer, 0, sizeof(*buffer));
	buffer->header.size = sizeof(*buffer);

	if (sleep_type > MBOX_BIOS_CMD_SX_INFO_SLEEP_TYPE_MAX) {
		printk(BIOS_ERR, "PSP: BUG: invalid sleep type 0x%x requested\n", sleep_type);
		return;
	}

	printk(BIOS_DEBUG, "PSP: Prepare to enter sleep state %d... ", sleep_type);

	buffer->sleep_type = sleep_type;

	set_smm_flag();
	cmd_status = send_psp_command(MBOX_BIOS_CMD_SX_INFO, buffer);
	clear_smm_flag();

	/* buffer's status shouldn't change but report it if it does */
	psp_print_cmd_status(cmd_status, &buffer->header);
}