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
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
25 #include <arch/romcc_io.h>
26 #include <console/console.h>
27 #include <cpu/x86/cache.h>
28 #include <cpu/x86/smm.h>
29 #include <device/pci_def.h>
32 extern unsigned char *mbi;
35 // #define DEBUG_SMI_I82830
37 /* If YABEL is enabled and it's not running at 0x00000000, we have to add some
38 * offset to all our mbi object memory accesses
40 #if defined(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && CONFIG_PCI_OPTION_ROM_RUN_YABEL && !CONFIG_YABEL_DIRECTHW
41 #define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION
43 #define OBJ_OFFSET 0x00000
48 #define D_OPEN (1 << 6)
49 #define D_CLS (1 << 5)
50 #define D_LCK (1 << 4)
51 #define G_SMRANE (1 << 3)
52 #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
60 } __attribute__((packed)) banner_id_t;
63 #define MSH_OK_RESTART 0x0001
64 #define MSH_FWH_ERR 0x00ff
65 #define MSH_IF_BAD_ID 0x0100
66 #define MSH_IF_BAD_FUNC 0x0101
67 #define MSH_IF_MBI_CORRUPT 0x0102
68 #define MSH_IF_BAD_HANDLE 0x0103
69 #define MSH_ALRDY_ATCHED 0x0104
70 #define MSH_NOT_ATCHED 0x0105
72 #define MSH_IF_INVADDR 0x0107
73 #define MSH_IF_UKN_TYPE 0x0108
74 #define MSH_IF_NOT_FOUND 0x0109
75 #define MSH_IF_NO_KEY 0x010a
76 #define MSH_IF_BUF_SIZE 0x010b
77 #define MSH_IF_NOT_PENDING 0x010c
79 #ifdef DEBUG_SMI_I82830
81 dump(u8 * addr, u32 len)
83 printk(BIOS_DEBUG, "\n%s(%p, %x):\n", __func__, addr, len);
85 unsigned int tmpCnt = len;
89 printk(BIOS_DEBUG, "\n%p: ", addr);
93 printk(BIOS_DEBUG, "%02x ", x);
99 //reset addr ptr to print ascii
100 addr = addr - tmpCnt;
104 if ((x < 32) || (x >= 127)) {
108 printk(BIOS_DEBUG, "%c", x);
111 printk(BIOS_DEBUG, "\n");
119 u32 smicombuffersize;
120 } __attribute__((packed)) version_t;
131 } __attribute__((packed)) mbi_header_t;
138 } __attribute__((packed)) obj_header_t;
148 } __attribute__((packed)) get_object_t;
150 static void mbi_call(u8 subf, banner_id_t *banner_id)
152 #ifdef DEBUG_SMI_I82830
153 printk(BIOS_DEBUG, "MBI\n");
154 printk(BIOS_DEBUG, "|- sub function %x\n", subf);
155 printk(BIOS_DEBUG, "|- banner id @ %x\n", (u32)banner_id);
156 printk(BIOS_DEBUG, "| |- mhid %x\n", banner_id->mhid);
157 printk(BIOS_DEBUG, "| |- function %x\n", banner_id->function);
158 printk(BIOS_DEBUG, "| |- return status %x\n", banner_id->retsts);
159 printk(BIOS_DEBUG, "| |- rfu %x\n", banner_id->rfu);
162 switch(banner_id->function) {
165 printk(BIOS_DEBUG, "|- MBI_QueryInterface\n");
166 version = (version_t *)banner_id;
167 version->banner.retsts = MSH_OK;
168 version->versionmajor=1;
169 version->versionminor=3;
170 version->smicombuffersize=0x1000;
174 printk(BIOS_DEBUG, "|- MBI_Attach\n");
175 printk(BIOS_DEBUG, "| |- Not Implemented!\n");
178 printk(BIOS_DEBUG, "|- MBI_Detach\n");
179 printk(BIOS_DEBUG, "| |- Not Implemented!\n");
182 obj_header_t *obj_header = (obj_header_t *)banner_id;
183 mbi_header_t *mbi_header = NULL;
184 printk(BIOS_DEBUG, "|- MBI_GetObjectHeader\n");
185 printk(BIOS_DEBUG, "| |- objnum = %d\n", obj_header->objnum);
188 obj_header->banner.retsts = MSH_IF_NOT_FOUND;
190 for (i=0; i<mbi_len;) {
193 if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
198 mbi_header = (mbi_header_t *)&mbi[i];
199 len = ALIGN((mbi_header->size * 16) + sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
201 if (obj_header->objnum == count) {
202 #ifdef DEBUG_SMI_I82830
203 if (mbi_header->name_len == 0xff) {
204 printk(BIOS_DEBUG, "| |- corrupt.\n");
208 int headerlen = ALIGN(sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
209 #ifdef DEBUG_SMI_I82830
210 printk(BIOS_DEBUG, "| |- headerlen = %d\n", headerlen);
212 memcpy(&obj_header->header, mbi_header, headerlen);
213 obj_header->banner.retsts = MSH_OK;
214 printk(BIOS_DEBUG, "| |- MBI module '");
216 for (j=0; j < mbi_header->name_len && mbi_header->name[j]; j++)
217 printk(BIOS_DEBUG, "%c", mbi_header->name[j]);
218 printk(BIOS_DEBUG, "' found.\n");
219 #ifdef DEBUG_SMI_I82830
220 dump((u8 *)banner_id, sizeof(obj_header_t) + ALIGN(mbi_header->name_len, 16));
227 if (obj_header->banner.retsts == MSH_IF_NOT_FOUND)
228 printk(BIOS_DEBUG, "| |- MBI object #%d not found.\n", obj_header->objnum);
232 get_object_t *getobj = (get_object_t *)banner_id;
233 mbi_header_t *mbi_header = NULL;
234 printk(BIOS_DEBUG, "|- MBI_GetObject\n");
235 #ifdef DEBUG_SMI_I82830
236 printk(BIOS_DEBUG, "| |- handle = %016Lx\n", getobj->handle);
238 printk(BIOS_DEBUG, "| |- objnum = %d\n", getobj->objnum);
239 printk(BIOS_DEBUG, "| |- start = %x\n", getobj->start);
240 printk(BIOS_DEBUG, "| |- numbytes = %x\n", getobj->numbytes);
241 printk(BIOS_DEBUG, "| |- buflen = %x\n", getobj->buflen);
242 printk(BIOS_DEBUG, "| |- buffer = %x\n", getobj->buffer);
245 getobj->banner.retsts = MSH_IF_NOT_FOUND;
247 for (i=0; i< mbi_len;) {
248 int headerlen, objectlen;
250 if (!(mbi[i] == 0xf0 && mbi [i+1] == 0xf6)) {
255 mbi_header = (mbi_header_t *)&mbi[i];
256 headerlen = ALIGN(sizeof(mbi_header) + ALIGN(mbi_header->name_len, 16), 16);
257 objectlen = ALIGN((mbi_header->size * 16), 16);
259 if (getobj->objnum == count) {
260 printk(BIOS_DEBUG, "| |- len = %x\n", headerlen + objectlen);
262 memcpy((void *)(getobj->buffer + OBJ_OFFSET),
263 ((char *)mbi_header) + headerlen, (objectlen > getobj->buflen) ? getobj->buflen : objectlen);
265 getobj->banner.retsts = MSH_OK;
266 #ifdef DEBUG_SMI_I82830
267 dump((u8 *)banner_id, sizeof(*getobj));
268 dump((u8 *)getobj->buffer + OBJ_OFFSET, objectlen);
272 i += (headerlen + objectlen);
275 if (getobj->banner.retsts == MSH_IF_NOT_FOUND)
276 printk(BIOS_DEBUG, "MBI module %d not found.\n", getobj->objnum);
280 printk(BIOS_DEBUG, "|- function %x\n", banner_id->function);
281 printk(BIOS_DEBUG, "| |- Unknown Function!\n");
284 printk(BIOS_DEBUG, "\n");
285 //dump(banner_id, 0x20);
288 #define SMI_IFC_SUCCESS 1
289 #define SMI_IFC_FAILURE_GENERIC 0
290 #define SMI_IFC_FAILURE_INVALID 2
291 #define SMI_IFC_FAILURE_CRITICAL 4
292 #define SMI_IFC_FAILURE_NONCRITICAL 6
299 static void smi_interface_call(void)
301 u32 mmio = pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14);
302 // mmio &= 0xfff80000;
303 // printk(BIOS_DEBUG, "mmio=%x\n", mmio);
304 u16 swsmi = pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0);
309 swsmi &= ~(1 << 0); // clear SMI toggle
311 switch ((swsmi>>1) & 0xf) {
313 printk(BIOS_DEBUG, "Interface Function Presence Test.\n");
315 swsmi &= ~(7 << 5); // Exit: Result
316 swsmi |= (SMI_IFC_SUCCESS << 5);
318 swsmi |= (PC13 << 8);
319 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
321 write32(mmio + 0x71428, 0x494e5443);
324 printk(BIOS_DEBUG, "Get BIOS Data.\n");
325 printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi);
328 printk(BIOS_DEBUG, "Call MBI Functions.\n");
329 mbi_call(swsmi >> 8, (banner_id_t *)((read32(mmio + 0x71428) & 0x000fffff) + OBJ_OFFSET) );
331 swsmi &= ~(7 << 5); // Exit: Result
332 swsmi |= (SMI_IFC_SUCCESS << 5);
333 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
336 printk(BIOS_DEBUG, "System BIOS Callbacks.\n");
337 printk(BIOS_DEBUG, "swsmi=%04x\n", swsmi);
340 printk(BIOS_DEBUG, "Unknown SMI interface call %04x\n", swsmi);
344 swsmi &= ~(7 << 5); // Exit: Result
345 swsmi |= (SMI_IFC_FAILURE_CRITICAL << 7);
346 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi);
350 * @brief read and clear ERRSTS
351 * @return ERRSTS register
353 static u16 reset_err_status(void)
357 reg16 = pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS);
358 /* set status bits are cleared by writing 1 to them */
359 pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS, reg16);
364 static void dump_err_status(u32 errsts)
366 printk(BIOS_DEBUG, "ERRSTS: ");
367 if (errsts & (1 << 12)) printk(BIOS_DEBUG, "MBI ");
368 if (errsts & (1 << 9)) printk(BIOS_DEBUG, "LCKF ");
369 if (errsts & (1 << 8)) printk(BIOS_DEBUG, "DTF ");
370 if (errsts & (1 << 5)) printk(BIOS_DEBUG, "UNSC ");
371 if (errsts & (1 << 4)) printk(BIOS_DEBUG, "OOGF ");
372 if (errsts & (1 << 3)) printk(BIOS_DEBUG, "IAAF ");
373 if (errsts & (1 << 2)) printk(BIOS_DEBUG, "ITTEF ");
374 printk(BIOS_DEBUG, "\n");
377 void northbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
381 /* We need to clear the SMI status registers, or we won't see what's
382 * happening in the following calls.
384 errsts = reset_err_status();
385 if (errsts & (1 << 12)) {
386 smi_interface_call();
389 dump_err_status(errsts);