coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
setup_heci_uma.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <device/mmio.h>
5 #include <device/pci_def.h>
6 #include <device/pci_ops.h>
10 #include <types.h>
11 
12 #define HECIDEV PCI_DEV(0, 0x16, 0)
13 
14 /* FIXME: add timeout. */
15 static void wait_heci_ready(void)
16 {
17  while (!(read32(DEFAULT_HECIBAR + 0xc) & 8)) // = 0x8000000c
18  ;
19 
20  write32((DEFAULT_HECIBAR + 0x4), (read32(DEFAULT_HECIBAR + 0x4) & ~0x10) | 0xc);
21 }
22 
23 /* FIXME: add timeout. */
24 static void wait_heci_cb_avail(int len)
25 {
26  union {
27  struct mei_csr csr;
28  u32 raw;
29  } csr;
30 
31  while (!(read32(DEFAULT_HECIBAR + 0xc) & 8))
32  ;
33 
34  do {
35  csr.raw = read32(DEFAULT_HECIBAR + 0x4);
36  } while (len > csr.csr.buffer_depth - (csr.csr.buffer_write_ptr -
37  csr.csr.buffer_read_ptr));
38 }
39 
40 static void send_heci_packet_dword(u8 *payload, size_t length)
41 {
42  int i;
43  for (i = 0; i < length; i += sizeof(uint32_t)) {
44  uint32_t dword = 0;
45  size_t bytes = MIN(length - i, sizeof(dword));
46  memcpy(&dword, payload + i, bytes);
47  write32(DEFAULT_HECIBAR + 0, dword);
48  }
49 }
50 
51 static void send_heci_packet(struct mei_header *head, u8 *payload)
52 {
53  wait_heci_cb_avail(DIV_ROUND_UP(sizeof(*head) + head->length, sizeof(u32)));
54 
55  send_heci_packet_dword((u8 *)head, sizeof(*head));
56  send_heci_packet_dword(payload, head->length);
57 
58  write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 0x4);
59 }
60 
61 static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
62 {
63  struct mei_header head;
64  int maxlen;
65 
67  maxlen = (read32(DEFAULT_HECIBAR + 0x4) >> 24) * 4 - 4;
68 
69  while (len) {
70  int cur = len;
71  if (cur > maxlen) {
72  cur = maxlen;
73  head.is_complete = 0;
74  } else
75  head.is_complete = 1;
76  head.length = cur;
77  head.reserved = 0;
78  head.client_address = clientaddress;
79  head.host_address = hostaddress;
80  send_heci_packet(&head, msg);
81  len -= cur;
82  msg += cur;
83  }
84 }
85 
86 /* FIXME: Add timeout. */
87 static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
88 {
89  union {
90  struct mei_csr csr;
91  u32 raw;
92  } csr;
93  int i = 0;
94 
95  write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
96  do {
97  csr.raw = read32(DEFAULT_HECIBAR + 0xc);
98  } while (csr.csr.buffer_write_ptr == csr.csr.buffer_read_ptr);
99 
100  *(u32 *) head = read32(DEFAULT_HECIBAR + 0x8);
101  if (!head->length) {
102  write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 2);
103  *packet_size = 0;
104  return 0;
105  }
106  if (head->length + 4 > 4 * csr.csr.buffer_depth || head->length > *packet_size) {
107  *packet_size = 0;
108  return -1;
109  }
110 
111  do {
112  csr.raw = read32(DEFAULT_HECIBAR + 0xc);
113  } while (((head->length + 3) >> 2) >
114  (csr.csr.buffer_write_ptr - csr.csr.buffer_read_ptr));
115 
116  for (i = 0; i < (head->length + 3) >> 2; i++)
117  packet[i++] = read32(DEFAULT_HECIBAR + 0x8);
118  *packet_size = head->length;
119  if (!csr.csr.ready)
120  *packet_size = 0;
121  write32(DEFAULT_HECIBAR + 0x4, read32(DEFAULT_HECIBAR + 0x4) | 4);
122  return 0;
123 }
124 
125 union uma_reply {
126  struct {
132  u8 unk3[0x48 - 4 - 1];
133  };
134  u32 dwords[0x48 / sizeof(u32)];
136 
137 /* FIXME: Add timeout. */
138 static int recv_heci_message(union uma_reply *message, u32 *message_size)
139 {
140  struct mei_header head;
141  int current_position;
142 
143  current_position = 0;
144  while (1) {
145  u32 current_size;
146  current_size = *message_size - current_position;
147  if (recv_heci_packet
148  (&head, &message->dwords[current_position / sizeof(u32)],
149  &current_size) == -1)
150  break;
151  if (!current_size)
152  break;
153  current_position += current_size;
154  if (head.is_complete) {
155  *message_size = current_position;
156  return 0;
157  }
158 
159  if (current_position >= *message_size)
160  break;
161  }
162  *message_size = 0;
163  return -1;
164 }
165 
166 static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
167 {
168  union uma_reply reply;
169 
170  struct uma_message {
171  u8 group_id;
172  u8 cmd;
173  u8 reserved;
174  u8 result;
175  u32 c2;
176  u64 heci_uma_addr;
177  u32 heci_uma_size;
178  u16 c3;
179  } __packed msg = {
180  .group_id = 0,
181  .cmd = MKHI_SET_UMA,
182  .reserved = 0,
183  .result = 0,
184  .c2 = 0x82,
185  .heci_uma_addr = heci_uma_addr,
186  .heci_uma_size = heci_uma_size,
187  .c3 = 0,
188  };
189  u32 reply_size;
190 
191  send_heci_message((u8 *) &msg, sizeof(msg), 0, 7);
192 
193  reply_size = sizeof(reply);
194  if (recv_heci_message(&reply, &reply_size) == -1)
195  return;
196 
197  if (reply.command != (MKHI_SET_UMA | (1 << 7)))
198  die("HECI init failed\n");
199 }
200 
201 void setup_heci_uma(u64 heci_uma_addr, unsigned int heci_uma_size)
202 {
203  if (!heci_uma_size && !(pci_read_config32(HECIDEV, 0x40) & 0x20))
204  return;
205 
206  if (heci_uma_size) {
207  dmibar_clrbits32(DMIVC0RCTL, 1 << 7);
208  RCBA32(0x14) &= ~0x80;
209  dmibar_clrbits32(DMIVC1RCTL, 1 << 7);
210  RCBA32(0x20) &= ~0x80;
211  dmibar_clrbits32(DMIVCPRCTL, 1 << 7);
212  RCBA32(0x30) &= ~0x80;
213  dmibar_clrbits32(DMIVCMRCTL, 1 << 7);
214  RCBA32(0x40) &= ~0x80;
215 
216  RCBA32(0x40) = 0x87000080; // OK
217  dmibar_write32(DMIVCMRCTL, 0x87000080); // OK
218 
219  while ((RCBA16(0x46) & 2) && dmibar_read16(DMIVCMRSTS) & VCMNP)
220  ;
221  }
222 
223  mchbar_write32(0x24, 0x10000 + heci_uma_size);
224 
225  send_heci_uma_message(heci_uma_addr, heci_uma_size);
226 
227  pci_write_config32(HECIDEV, 0x10, 0x0);
228  pci_write_config8(HECIDEV, 0x4, 0x0);
229 }
u8 raw[sizeof(struct arm64_kernel_header)+0x100]
Definition: fit_payload.c:31
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define MIN(a, b)
Definition: helpers.h:37
#define DIV_ROUND_UP(x, y)
Definition: helpers.h:60
void __noreturn die(const char *fmt,...)
Definition: die.c:17
#define dmibar_clrbits32(addr, clear)
Definition: fixed_bars.h:117
static __always_inline void mchbar_write32(const uintptr_t offset, const uint32_t value)
Definition: fixed_bars.h:36
static __always_inline void dmibar_write32(const uintptr_t offset, const uint32_t value)
Definition: fixed_bars.h:91
static __always_inline uint16_t dmibar_read16(const uintptr_t offset)
Definition: fixed_bars.h:71
uint64_t length
Definition: fw_cfg_if.h:1
#define DMIVC0RCTL
Definition: gm45.h:347
#define DMIVC1RCTL
Definition: gm45.h:352
#define DMIVCPRCTL
Definition: dmibar.h:22
#define DMIVCMRSTS
Definition: dmibar.h:28
#define VCMNP
Definition: dmibar.h:29
#define DMIVCMRCTL
Definition: dmibar.h:27
static __always_inline void pci_write_config32(const struct device *dev, u16 reg, u32 val)
Definition: pci_ops.h:76
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
static __always_inline void pci_write_config8(const struct device *dev, u16 reg, u8 val)
Definition: pci_ops.h:64
result
Definition: mrc_cache.c:35
#define DEFAULT_HECIBAR
Definition: memmap.h:6
static void wait_heci_cb_avail(int len)
static int recv_heci_packet(struct mei_header *head, u32 *packet, u32 *packet_size)
static void send_heci_packet(struct mei_header *head, u8 *payload)
static int recv_heci_message(union uma_reply *message, u32 *message_size)
void setup_heci_uma(u64 heci_uma_addr, unsigned int heci_uma_size)
union uma_reply __packed
static void send_heci_uma_message(const u64 heci_uma_addr, const unsigned int heci_uma_size)
static void wait_heci_ready(void)
static void send_heci_message(u8 *msg, int len, u8 hostaddress, u8 clientaddress)
static void send_heci_packet_dword(u8 *payload, size_t length)
#define HECIDEV
#define RCBA16(x)
Definition: rcba.h:13
#define RCBA32(x)
Definition: rcba.h:14
#define MKHI_SET_UMA
Definition: me.h:180
uint64_t u64
Definition: stdint.h:54
unsigned int uint32_t
Definition: stdint.h:14
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
Definition: x86.c:23
Definition: me.h:213
Definition: me.h:235
u32 reserved
Definition: me.h:239
u32 is_complete
Definition: me.h:240
u32 raw
Definition: me.h:257
u32 length
Definition: me.h:238
u32 host_address
Definition: me.h:237
u32 client_address
Definition: me.h:236
u8 unk3[0x48 - 4 - 1]
u32 dwords[0x48/sizeof(u32)]