7fa33fc0c20598e2b800153a9a3a2d582a194b2a
[coreboot.git] / src / cpu / amd / model_gx2 / vsmsetup.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2000 Erik Arjan Hendriks
5  * Copyright (C) 2000 Scyld Computing Corporation
6  * Copyright (C) 2001 University of California.  LA-CC Number 01-67.
7  * Copyright (C) 2005 Nick.Barker9@btinternet.com
8  * Copyright (C) 2007 coresystems GmbH
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  * LA-CC is the Los Alamos Control and Compliance Number, see also:
25  * http://supply.lanl.gov/property/customs/eximguide/default.shtml
26  */
27
28 #include <console/console.h>
29 #include <device/device.h>
30 #include <device/pci.h>
31 #include <string.h>
32 #include <cpu/cpu.h>
33 #include <cpu/x86/lapic.h>
34 #include <cpu/x86/cache.h>
35 #include <arch/io.h>
36 #include <cbfs.h>
37
38 u32 VSA_vrRead(u16 classIndex);
39 void do_vsmbios(void);
40
41 #define VSA2_BUFFER             0x60000
42 #define VSA2_ENTRY_POINT        0x60020
43 #define VSA2_SIGNATURE  0x56534132      // 'VSA2' returned in EAX 
44 #define SIGNATURE                       0x03
45 /**
46  * TODO.
47  *
48  * The address arguments to this function are PHYSICAL ADDRESSES!
49  *
50  * @param smm TODO.
51  * @param sysm TODO.
52  */
53 static void real_mode_switch_call_vsm(unsigned long smm, unsigned long sysm)
54 {
55         u16 entryHi = (VSA2_ENTRY_POINT & 0xffff0000) >> 4;
56         u16 entryLo = (VSA2_ENTRY_POINT & 0xffff);
57
58         __asm__ __volatile__(
59                 /* Paranoia -- does ecx get saved? not sure. This is
60                  * the easiest safe thing to do.
61                  */
62                 "       pushal                  \n"
63                 /* Save the stack. */
64                 "       mov     %%esp, __stack  \n"
65                 "       jmp     1f              \n"
66                 "__stack: .long 0               \n" 
67                 "1:\n"
68                 /* Get devfn into %%ecx. */
69                 "       movl    %%esp, %%ebp    \n"
70                 /* Get the smm and sysm args into ecx and edx. */
71                 "       movl    %0, %%ecx       \n"
72                 "       movl    %1, %%edx       \n"
73                 /* Load 'our' gdt. */
74                 "       lgdt    %%cs:__mygdtaddr        \n"
75                 /* This configures CS properly for real mode. */
76                 "       ljmp    $0x28, $__rms_16bit\n"
77                 "__rms_16bit:                   \n"
78                 "       .code16                 \n"
79                 /* 16 bit code from here on... */
80                 /* Load the segment registers with properly configured segment
81                  * descriptors. They will retain these configurations (limits,
82                  * writability, etc.) once protected mode is turned off.
83                  */
84                 "       mov     $0x30, %%ax     \n"
85                 "       mov     %%ax, %%ds              \n"
86                 "       mov     %%ax, %%es              \n"
87                 "       mov     %%ax, %%fs              \n"
88                 "       mov     %%ax, %%gs              \n"
89                 "       mov     %%ax, %%ss              \n"
90                 /* Turn off protection (bit 0 in CR0). */
91                 "       movl    %%cr0, %%eax    \n"
92                 "       andl    $0xFFFFFFFE, %%eax \n"
93                 "       movl    %%eax, %%cr0    \n"
94                 /* Now really going into real mode. */
95                 "       ljmp    $0,  $__rms_real\n"
96                 "__rms_real:                    \n"
97
98                 /* Put the stack at the end of page zero.
99                  * That way we can easily share it between real and protected,
100                  * since the 16-bit ESP at segment 0 will work for any case.
101                  */
102
103                 /* Setup a stack. */
104                 "       mov     $0x0, %%ax      \n"
105                 "       mov     %%ax, %%ss      \n"
106                 "       movl    $0x1000, %%eax  \n"
107                 "       movl    %%eax, %%esp    \n"
108                 /* Dump zeros in the other segregs. */
109                 "       mov     %%ax, %%es      \n"
110                 /* FIXME: Big real mode for gs, fs? */
111                 "       mov     %%ax, %%fs      \n"
112                 "       mov     %%ax, %%gs      \n"
113                 "       mov     $0x40, %%ax     \n"
114                 "       mov     %%ax, %%ds      \n"
115                 /* "     mov     %%cx, %%ax      \n" */
116                 "       movl    %0, %%ecx       \n"
117                 "       movl    %1, %%edx       \n"
118                 /* Call the VSA2 entry point address. */
119                 "       lcall   %2, %3\n"
120                 /* If we got here, just about done.
121                  * Need to get back to protected mode.
122                  */
123                 "       movl    %%cr0, %%eax    \n" 
124                 "       orl     $0x0000001, %%eax\n"    /* PE = 1 */
125                 "       movl    %%eax, %%cr0    \n"
126                 /* Now that we are in protected mode,
127                  * jump to a 32 bit code segment.
128                  */
129                 "       data32  ljmp    $0x10, $vsmrestart\n"
130                 "vsmrestart:\n"
131                 "       .code32\n"
132                 "       movw    $0x18, %%ax     \n"
133                 "       mov     %%ax, %%ds      \n"
134                 "       mov     %%ax, %%es      \n"
135                 "       mov     %%ax, %%fs      \n"
136                 "       mov     %%ax, %%gs      \n"
137                 "       mov     %%ax, %%ss      \n"
138                 /* Restore proper gdt. */
139                 "       lgdt    %%cs:gdtarg     \n"
140                 ".globl vsm_exit                \n"
141                 "vsm_exit:                      \n"
142                 "       mov     __stack, %%esp  \n"
143                 "       popal                   \n"::
144                 "g" (smm), "g"(sysm), "g"(entryHi), "g"(entryLo)
145         );
146 }
147
148 __asm__(".text\n" "real_mode_switch_end:\n");
149 extern char real_mode_switch_end[];
150
151 /* andrei: Some VSA virtual register helpers: raw read and MSR read. */
152
153 u32 VSA_vrRead(u16 classIndex)
154 {
155         unsigned eax, ebx, ecx, edx;
156         asm volatile (
157                 "movw   $0x0AC1C, %%dx          \n"
158                 "orl    $0x0FC530000, %%eax     \n"
159                 "outl   %%eax, %%dx             \n"
160                 "addb   $2, %%dl                \n"
161                 "inw    %%dx, %%ax              \n"
162                 : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx) 
163                 : "a"(classIndex)
164         );
165
166         return eax;
167 }
168
169 u32 VSA_msrRead(u32 msrAddr)
170 {
171         unsigned eax, ebx, ecx, edx;
172         asm volatile (
173                 "movw   $0x0AC1C, %%dx                  \n"
174                 "movl   $0x0FC530007, %%eax             \n"
175                 "outl   %%eax, %%dx                             \n"
176                 "addb   $2, %%dl                                \n"
177                 "inw    %%dx, %%ax                              \n"
178                 : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
179                 : "c"(msrAddr)
180         );
181
182         return eax;
183 }
184
185 void do_vsmbios(void)
186 {
187         unsigned char *buf;
188         int i;
189
190         printk_err( "do_vsmbios\n");
191         /* Clear VSM BIOS data area. */
192         for (i = 0x400; i < 0x500; i++)
193                 *(volatile unsigned char *)i = 0;
194         if ((unsigned int)cbfs_load_stage("vsa") != VSA2_ENTRY_POINT) {
195                 printk_err("do_vsmbios: Failed to load VSA.\n");
196         }
197         buf = VSA2_BUFFER;
198
199         printk_debug("buf[0x20] signature is %x:%x:%x:%x\n",
200                buf[0x20], buf[0x21], buf[0x22], buf[0x23]);
201         /* Check for POST code at start of vsainit.bin. If you don't see it,
202          * don't bother.
203          */
204         if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) ||
205             (buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) {
206                 die("FATAL: no vsainit.bin signature, skipping!\n");
207         }
208
209         /* ecx gets smm, edx gets sysm. */
210         printk_err("Call real_mode_switch_call_vsm\n");
211 //      real_mode_switch_call_vsm(MSR_GLIU0_SMM, MSR_GLIU0_SYSMEM);
212
213         /* Restart Timer 1. */
214         outb(0x56, 0x43);
215         outb(0x12, 0x41);
216
217         /* Check that VSA is running OK. */
218         if (VSA_vrRead(SIGNATURE) == VSA2_SIGNATURE)
219                 printk_debug("do_vsmbios: VSA2 VR signature verified\n");
220         else
221                 die("FATAL: VSA2 VR signature not valid, install failed!\n");
222 }
223