Rename __attribute__((packed)) --> __packed
[coreboot.git] / src / northbridge / intel / i82830 / smihandler.c
blob569e62ec7b6c07b06e4827ea6326594c2aa4912a
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2010 coresystems GmbH
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <types.h>
18 #include <compiler.h>
19 #include <string.h>
20 #include <arch/io.h>
21 #include <console/console.h>
22 #include <cpu/x86/cache.h>
23 #include <cpu/x86/smm.h>
24 #include <device/pci_def.h>
25 #include "i82830.h"
27 extern unsigned char *mbi;
28 extern u32 mbi_len;
30 // #define DEBUG_SMI_I82830
32 /* If YABEL is enabled and it's not running at 0x00000000, we have to add some
33 * offset to all our mbi object memory accesses
35 #if IS_ENABLED(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && !CONFIG_YABEL_DIRECTHW
36 #define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION
37 #else
38 #define OBJ_OFFSET 0x00000
39 #endif
41 /* I830M */
42 #define SMRAM 0x90
43 #define D_OPEN (1 << 6)
44 #define D_CLS (1 << 5)
45 #define D_LCK (1 << 4)
46 #define G_SMRANE (1 << 3)
47 #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
50 typedef struct {
51 u32 mhid;
52 u32 function;
53 u32 retsts;
54 u32 rfu;
55 } __packed banner_id_t;
57 #define MSH_OK 0x0000
58 #define MSH_OK_RESTART 0x0001
59 #define MSH_FWH_ERR 0x00ff
60 #define MSH_IF_BAD_ID 0x0100
61 #define MSH_IF_BAD_FUNC 0x0101
62 #define MSH_IF_MBI_CORRUPT 0x0102
63 #define MSH_IF_BAD_HANDLE 0x0103
64 #define MSH_ALRDY_ATCHED 0x0104
65 #define MSH_NOT_ATCHED 0x0105
66 #define MSH_IF 0x0106
67 #define MSH_IF_INVADDR 0x0107
68 #define MSH_IF_UKN_TYPE 0x0108
69 #define MSH_IF_NOT_FOUND 0x0109
70 #define MSH_IF_NO_KEY 0x010a
71 #define MSH_IF_BUF_SIZE 0x010b
72 #define MSH_IF_NOT_PENDING 0x010c
74 #ifdef DEBUG_SMI_I82830
75 static void
76 dump(u8 * addr, u32 len)
78 printk(BIOS_DEBUG, "\n%s(%p, %x):\n", __func__, addr, len);
79 while (len) {
80 unsigned int tmpCnt = len;
81 unsigned char x;
82 if (tmpCnt > 8)
83 tmpCnt = 8;
84 printk(BIOS_DEBUG, "\n%p: ", addr);
85 // print hex
86 while (tmpCnt--) {
87 x = *addr++;
88 printk(BIOS_DEBUG, "%02x ", x);
90 tmpCnt = len;
91 if (tmpCnt > 8)
92 tmpCnt = 8;
93 len -= tmpCnt;
94 //reset addr ptr to print ascii
95 addr = addr - tmpCnt;
96 // print ascii
97 while (tmpCnt--) {
98 x = *addr++;
99 if ((x < 32) || (x >= 127)) {
100 //non-printable char
101 x = '.';
103 printk(BIOS_DEBUG, "%c", x);
106 printk(BIOS_DEBUG, "\n");
108 #endif
110 typedef struct {
111 banner_id_t banner;
112 u16 versionmajor;
113 u16 versionminor;
114 u32 smicombuffersize;
115 } __packed version_t;
117 typedef struct {
118 u16 header_id;
119 u16 attributes;
120 u16 size;
121 u8 name_len;
122 u8 reserved;
123 u32 type;
124 u32 header_ext;
125 u8 name[0];
126 } __packed mbi_header_t;
128 typedef struct {
129 banner_id_t banner;
130 u64 handle;
131 u32 objnum;
132 mbi_header_t header;
133 } __packed obj_header_t;
135 typedef struct {
136 banner_id_t banner;
137 u64 handle;
138 u32 objnum;
139 u32 start;
140 u32 numbytes;
141 u32 buflen;
142 u32 buffer;
143 } __packed get_object_t;
145 static void mbi_call(u8 subf, banner_id_t *banner_id)
147 #ifdef DEBUG_SMI_I82830
148 printk(BIOS_DEBUG, "MBI\n");
149 printk(BIOS_DEBUG, "|- sub function %x\n", subf);
150 printk(BIOS_DEBUG, "|- banner id @ %x\n", (u32)banner_id);
151 printk(BIOS_DEBUG, "| |- mhid %x\n", banner_id->mhid);
152 printk(BIOS_DEBUG, "| |- function %x\n", banner_id->function);
153 printk(BIOS_DEBUG, "| |- return status %x\n", banner_id->retsts);
154 printk(BIOS_DEBUG, "| |- rfu %x\n", banner_id->rfu);
155 #endif
157 switch(banner_id->function) {
158 case 0x0001: {
159 version_t *version;
160 printk(BIOS_DEBUG, "|- MBI_QueryInterface\n");
161 version = (version_t *)banner_id;
162 version->banner.retsts = MSH_OK;
163 version->versionmajor = 1;
164 version->versionminor = 3;
165 version->smicombuffersize = 0x1000;
166 break;
168 case 0x0002:
169 printk(BIOS_DEBUG, "|- MBI_Attach\n");
170 printk(BIOS_DEBUG, "| |- Not Implemented!\n");
171 break;
172 case 0x0003:
173 printk(BIOS_DEBUG, "|- MBI_Detach\n");
174 printk(BIOS_DEBUG, "| |- Not Implemented!\n");
175 break;
176 case 0x0201: {
177 obj_header_t *obj_header = (obj_header_t *)banner_id;
178 mbi_header_t *mbi_header = NULL;
179 printk(BIOS_DEBUG, "|- MBI_GetObjectHeader\n");
180 printk(BIOS_DEBUG, "| |- objnum = %d\n", obj_header->objnum);
182 int i, count = 0;
183 obj_header->banner.retsts = MSH_IF_NOT_FOUND;
185 for (i = 0; i < mbi_len;) {
186 int len;
188 if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
189 i+=16;
190 continue;
193 mbi_header = (mbi_header_t *)&mbi[i];
194 len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
196 if (obj_header->objnum == count) {
197 #ifdef DEBUG_SMI_I82830
198 if (mbi_header->name_len == 0xff) {
199 printk(BIOS_DEBUG, "| |- corrupt.\n");
200 break;
202 #endif
203 int headerlen = ALIGN(sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
204 #ifdef DEBUG_SMI_I82830
205 printk(BIOS_DEBUG, "| |- headerlen = %d\n", headerlen);
206 #endif
207 memcpy(&obj_header->header, mbi_header, headerlen);
208 obj_header->banner.retsts = MSH_OK;
209 printk(BIOS_DEBUG, "| |- MBI module '");
210 int j;
211 for (j = 0; j < mbi_header->name_len && mbi_header->name[j]; j++)
212 printk(BIOS_DEBUG, "%c", mbi_header->name[j]);
213 printk(BIOS_DEBUG, "' found.\n");
214 #ifdef DEBUG_SMI_I82830
215 dump((u8 *)banner_id, sizeof(obj_header_t) + ALIGN(mbi_header->name_len, 16));
216 #endif
217 break;
219 i += len;
220 count++;
222 if (obj_header->banner.retsts == MSH_IF_NOT_FOUND)
223 printk(BIOS_DEBUG, "| |- MBI object #%d not found.\n", obj_header->objnum);
224 break;
226 case 0x0203: {
227 get_object_t *getobj = (get_object_t *)banner_id;
228 mbi_header_t *mbi_header = NULL;
229 printk(BIOS_DEBUG, "|- MBI_GetObject\n");
230 #ifdef DEBUG_SMI_I82830
231 printk(BIOS_DEBUG, "| |- handle = %016Lx\n", getobj->handle);
232 #endif
233 printk(BIOS_DEBUG, "| |- objnum = %d\n", getobj->objnum);
234 printk(BIOS_DEBUG, "| |- start = %x\n", getobj->start);
235 printk(BIOS_DEBUG, "| |- numbytes = %x\n", getobj->numbytes);
236 printk(BIOS_DEBUG, "| |- buflen = %x\n", getobj->buflen);
237 printk(BIOS_DEBUG, "| |- buffer = %x\n", getobj->buffer);
239 int i, count = 0;
240 getobj->banner.retsts = MSH_IF_NOT_FOUND;
242 for (i = 0; i< mbi_len;) {
243 int headerlen, objectlen;
245 if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
246 i+=16;
247 continue;
250 mbi_header = (mbi_header_t *)&mbi[i];
251 headerlen = ALIGN(sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
252 objectlen = ALIGN((mbi_header->size * 16), 16);
254 if (getobj->objnum == count) {
255 printk(BIOS_DEBUG, "| |- len = %x\n", headerlen + objectlen);
257 memcpy((void *)(getobj->buffer + OBJ_OFFSET),
258 ((char *)mbi_header) + headerlen, (objectlen > getobj->buflen) ? getobj->buflen : objectlen);
260 getobj->banner.retsts = MSH_OK;
261 #ifdef DEBUG_SMI_I82830
262 dump((u8 *)banner_id, sizeof(*getobj));
263 dump((u8 *)getobj->buffer + OBJ_OFFSET, objectlen);
264 #endif
265 break;
267 i += (headerlen + objectlen);
268 count++;
270 if (getobj->banner.retsts == MSH_IF_NOT_FOUND)
271 printk(BIOS_DEBUG, "MBI module %d not found.\n", getobj->objnum);
272 break;
274 default:
275 printk(BIOS_DEBUG, "|- function %x\n", banner_id->function);
276 printk(BIOS_DEBUG, "| |- Unknown Function!\n");
277 break;
279 printk(BIOS_DEBUG, "\n");
280 //dump(banner_id, 0x20);
283 #define SMI_IFC_SUCCESS 1
284 #define SMI_IFC_FAILURE_GENERIC 0
285 #define SMI_IFC_FAILURE_INVALID 2
286 #define SMI_IFC_FAILURE_CRITICAL 4
287 #define SMI_IFC_FAILURE_NONCRITICAL 6
289 #define PC10 0x10
290 #define PC11 0x11
291 #define PC12 0x12
292 #define PC13 0x13
294 static void smi_interface_call(void)
296 u8 *mmio = (u8 *)pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14);
297 // mmio &= 0xfff80000;
298 // printk(BIOS_DEBUG, "mmio=%x\n", mmio);
299 u16 swsmi = pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0);
301 if (!(swsmi & 1))
302 return;
304 swsmi &= ~(1 << 0); // clear SMI toggle
306 switch ((swsmi>>1) & 0xf) {
307 case 0:
308 printk(BIOS_DEBUG, "Interface Function Presence Test.\n");
309 swsmi = 0;
310 swsmi &= ~(7 << 5); // Exit: Result
311 swsmi |= (SMI_IFC_SUCCESS << 5);
312 swsmi &= 0xff;
313 swsmi |= (PC13 << 8);
314 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
315 // write magic
316 write32(mmio + 0x71428, 0x494e5443);
317 return;
318 case 4:
319 printk(BIOS_DEBUG, "Get BIOS Data.\n");
320 printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi);
321 break;
322 case 5:
323 printk(BIOS_DEBUG, "Call MBI Functions.\n");
324 mbi_call(swsmi >> 8, (banner_id_t *)((read32(mmio + 0x71428) & 0x000fffff) + OBJ_OFFSET) );
325 // swsmi = 0x0000;
326 swsmi &= ~(7 << 5); // Exit: Result
327 swsmi |= (SMI_IFC_SUCCESS << 5);
328 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
329 return;
330 case 6:
331 printk(BIOS_DEBUG, "System BIOS Callbacks.\n");
332 printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi);
333 break;
334 default:
335 printk(BIOS_DEBUG, "Unknown SMI interface call %04x\n", swsmi);
336 break;
339 swsmi &= ~(7 << 5); // Exit: Result
340 swsmi |= (SMI_IFC_FAILURE_CRITICAL << 7);
341 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
345 * @brief read and clear ERRSTS
346 * @return ERRSTS register
348 static u16 reset_err_status(void)
350 u16 reg16;
352 reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS);
353 /* set status bits are cleared by writing 1 to them */
354 pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS, reg16);
356 return reg16;
359 static void dump_err_status(u32 errsts)
361 printk(BIOS_DEBUG, "ERRSTS: ");
362 if (errsts & (1 << 12)) printk(BIOS_DEBUG, "MBI ");
363 if (errsts & (1 << 9)) printk(BIOS_DEBUG, "LCKF ");
364 if (errsts & (1 << 8)) printk(BIOS_DEBUG, "DTF ");
365 if (errsts & (1 << 5)) printk(BIOS_DEBUG, "UNSC ");
366 if (errsts & (1 << 4)) printk(BIOS_DEBUG, "OOGF ");
367 if (errsts & (1 << 3)) printk(BIOS_DEBUG, "IAAF ");
368 if (errsts & (1 << 2)) printk(BIOS_DEBUG, "ITTEF ");
369 printk(BIOS_DEBUG, "\n");
372 void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
374 u16 errsts;
376 /* We need to clear the SMI status registers, or we won't see what's
377 * happening in the following calls.
379 errsts = reset_err_status();
380 if (errsts & (1 << 12)) {
381 smi_interface_call();
382 } else {
383 if (errsts)
384 dump_err_status(errsts);