Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Modified boot and vmxassist to handle real/protected transition.
[palacios.git] / bios / vmxassist / setup.c
1 /*
2  * setup.c: Setup the world for vmxassist.
3  *
4  * Leendert van Doorn, leendert@watson.ibm.com
5  * Copyright (c) 2005, International Business Machines Corporation.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18  * Place - Suite 330, Boston, MA 02111-1307 USA.
19  */
20 #include "vm86.h"
21 #include "util.h"
22 #include "machine.h"
23
24 #if (VMXASSIST_BASE != TEXTADDR)
25 #error VMXAssist base mismatch
26 #endif
27
28 #define NR_PGD          (PGSIZE / sizeof(unsigned))
29
30 #define min(a, b)       ((a) > (b) ? (b) : (a))
31
32 /* Which CPU are we booting, and what is the initial CS segment? */
33 int booting_cpu, booting_vector;
34
35 unsigned long long gdt[] __attribute__ ((aligned(32))) = {
36         0x0000000000000000ULL,          /* 0x00: reserved */
37         0x0000890000000000ULL,          /* 0x08: 32-bit TSS */
38         0x00CF9A000000FFFFULL,          /* 0x10: CS 32-bit */
39         0x00CF92000000FFFFULL,          /* 0x18: DS 32-bit */
40 };
41
42 struct dtr gdtr = { sizeof(gdt)-1, (unsigned long) &gdt };
43
44 struct tss tss __attribute__ ((aligned(4)));
45
46 unsigned long long idt[NR_TRAPS] __attribute__ ((aligned(32)));
47
48 struct dtr idtr = { sizeof(idt)-1, (unsigned long) &idt };
49
50 struct vmx_assist_context oldctx;
51 struct vmx_assist_context newctx;
52
53 unsigned long memory_size;
54 int initialize_real_mode;
55
56 extern char stack_top[];
57 extern unsigned trap_handlers[];
58
59 void
60 banner(void)
61 {
62         printf("VMXAssist (%s)\n", __DATE__);
63
64         /* Bochs its way to convey memory size */
65         memory_size = ((get_cmos(0x35) << 8) | get_cmos(0x34)) << 6;
66         if (memory_size > 0x3bc000)
67                 memory_size = 0x3bc000;
68         memory_size = (memory_size << 10) + 0xF00000;
69         if (memory_size <= 0xF00000)
70                 memory_size =
71                     (((get_cmos(0x31) << 8) | get_cmos(0x30)) + 0x400) << 10;
72         memory_size += 0x400 << 10; /* + 1MB */
73
74         printf("Memory size %ld MB\n", memory_size >> 20);
75         printf("E820 map:\n");
76         print_e820_map(HVM_E820, *HVM_E820_NR);
77         printf("\n");
78 }
79
80 void
81 setup_gdt(void)
82 {
83         unsigned long long addr = (unsigned long long) &tss;
84
85         /* setup task state segment */
86         memset(&tss, 0, sizeof(tss));
87         tss.ss0 = DATA_SELECTOR;
88         tss.esp0 = (unsigned) stack_top;
89         tss.iomap_base = offsetof(struct tss, iomap);
90         tss.iomap[sizeof(tss.iomap)-1] = 0xff;
91
92         /* initialize gdt's tss selector */
93         gdt[TSS_SELECTOR / sizeof(gdt[0])] |=
94                 ((addr & 0xFF000000) << (56-24)) |
95                 ((addr & 0x00FF0000) << (32-16)) |
96                 ((addr & 0x0000FFFF) << (16)) |
97                 (sizeof(tss) - 1);
98
99         /* switch to our own gdt and set current tss */
100         __asm__ __volatile__ ("lgdt %0" : : "m" (gdtr));
101         __asm__ __volatile__ ("movl %%eax,%%ds;"
102                               "movl %%eax,%%es;"
103                               "movl %%eax,%%fs;"
104                               "movl %%eax,%%gs;"
105                               "movl %%eax,%%ss" : : "a" (DATA_SELECTOR));
106
107         __asm__ __volatile__ ("ljmp %0,$1f; 1:" : : "i" (CODE_SELECTOR));
108
109         __asm__ __volatile__ ("ltr %%ax" : : "a" (TSS_SELECTOR));
110 }
111
112 void
113 set_intr_gate(int i, unsigned handler)
114 {
115         unsigned long long addr = handler;
116
117         idt[i] = ((addr & 0xFFFF0000ULL) << 32) | (0x8E00ULL << 32) |
118                 (addr & 0xFFFFULL) | (CODE_SELECTOR << 16);
119 }
120
121 void
122 setup_idt(void)
123 {
124         int i;
125
126         for (i = 0; i < NR_TRAPS; i++)
127                 set_intr_gate(i, trap_handlers[i]);
128         __asm__ __volatile__ ("lidt %0" : : "m" (idtr));
129 }
130
131 void
132 setup_pic(void)
133 {
134         /* mask all interrupts */
135         outb(PIC_MASTER + PIC_IMR, 0xFF);
136         outb(PIC_SLAVE + PIC_IMR, 0xFF);
137
138         /* setup master PIC */
139         outb(PIC_MASTER + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
140         outb(PIC_MASTER + PIC_IMR, NR_EXCEPTION_HANDLER);
141         outb(PIC_MASTER + PIC_IMR, 1 << 2); /* slave on channel 2 */
142         outb(PIC_MASTER + PIC_IMR, 0x01);
143
144         /* setup slave PIC */
145         outb(PIC_SLAVE + PIC_CMD, 0x11); /* edge triggered, cascade, ICW4 */
146         outb(PIC_SLAVE + PIC_IMR, NR_EXCEPTION_HANDLER + 8);
147         outb(PIC_SLAVE + PIC_IMR, 0x02); /* slave identity is 2 */
148         outb(PIC_SLAVE + PIC_IMR, 0x01);
149
150         /* enable all interrupts */
151         outb(PIC_MASTER + PIC_IMR, 0);
152         outb(PIC_SLAVE + PIC_IMR, 0);
153 }
154
155 void
156 setiomap(int port)
157 {
158         tss.iomap[port >> 3] |= 1 << (port & 7);
159 }
160
161 void
162 enter_real_mode(struct regs *regs)
163 {
164         /* mask off TSS busy bit */
165         gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL;
166
167         /* start 8086 emulation of BIOS */
168         if (initialize_real_mode) {
169                 initialize_real_mode = 0;
170                 regs->eflags |= EFLAGS_VM | 0x02;
171                 regs->ves = regs->vds = regs->vfs = regs->vgs = 0xF000;
172                 if (booting_cpu == 0) {
173                         regs->cs = 0xF000; /* ROM BIOS POST entry point */
174                         regs->eip = 0xFFF0;
175                 } else {
176                         regs->cs = booting_vector << 8; /* AP entry point */
177                         regs->eip = 0;
178                 }
179
180                 regs->uesp = regs->uss = 0;
181                 regs->eax = regs->ecx = regs->edx = regs->ebx = 0;
182                 regs->esp = regs->ebp = regs->esi = regs->edi = 0;
183
184                 /* intercept accesses to the PIC */
185                 setiomap(PIC_MASTER+PIC_CMD);
186                 setiomap(PIC_MASTER+PIC_IMR);
187                 setiomap(PIC_SLAVE+PIC_CMD);
188                 setiomap(PIC_SLAVE+PIC_IMR);
189
190                 printf("Starting emulated 16-bit real-mode: ip=%04x:%04x\n",
191                         regs->cs, regs->eip);
192
193                 mode = VM86_REAL; /* becomes previous mode */
194                 set_mode(regs, VM86_REAL);
195
196                 /* this should get us into 16-bit mode */
197                 return;
198         }
199
200         /* go from protected to real mode */
201         set_mode(regs, VM86_PROTECTED_TO_REAL);
202         emulate(regs);
203         if (mode != VM86_REAL)
204                 panic("failed to emulate between clear PE and long jump.\n");
205 }
206
207 /*
208  * Setup the environment for VMX assist.
209  * This environment consists of flat segments (code and data),
210  * its own gdt, idt, and tr.
211  */
212 void
213 setup_ctx(void)
214 {
215         struct vmx_assist_context *c = &newctx;
216
217         memset(c, 0, sizeof(*c));
218         c->eip = (unsigned long) switch_to_real_mode;
219         c->esp = (unsigned) stack_top;
220         c->eflags = 0x2; /* no interrupts, please */
221
222         /*
223          * Obviously, vmx assist is not running with CR0_PE disabled.
224          * The reason why the vmx assist cr0 has CR0.PE disabled is
225          * that a transtion to CR0.PE causes a world switch. It seems
226          * more natural to enable CR0.PE to cause a world switch to
227          * protected mode rather than disabling it.
228          */
229         c->cr0 = (get_cr0() | CR0_NE) & ~CR0_PE;
230         c->cr3 = 0;
231         c->cr4 = get_cr4();
232
233         c->idtr_limit = sizeof(idt)-1;
234         c->idtr_base = (unsigned long) &idt;
235
236         c->gdtr_limit = sizeof(gdt)-1;
237         c->gdtr_base = (unsigned long) &gdt;
238
239         c->cs_sel = CODE_SELECTOR;
240         c->cs_limit = 0xFFFFFFFF;
241         c->cs_base = 0;
242         c->cs_arbytes.fields.seg_type = 0xb;
243         c->cs_arbytes.fields.s = 1;
244         c->cs_arbytes.fields.dpl = 0;
245         c->cs_arbytes.fields.p = 1;
246         c->cs_arbytes.fields.avl = 0;
247         c->cs_arbytes.fields.default_ops_size = 1;
248         c->cs_arbytes.fields.g = 1;
249
250         c->ds_sel = DATA_SELECTOR;
251         c->ds_limit = 0xFFFFFFFF;
252         c->ds_base = 0;
253         c->ds_arbytes = c->cs_arbytes;
254         c->ds_arbytes.fields.seg_type = 0x3;
255
256         c->es_sel = DATA_SELECTOR;
257         c->es_limit = 0xFFFFFFFF;
258         c->es_base = 0;
259         c->es_arbytes = c->ds_arbytes;
260
261         c->ss_sel = DATA_SELECTOR;
262         c->ss_limit = 0xFFFFFFFF;
263         c->ss_base = 0;
264         c->ss_arbytes = c->ds_arbytes;
265
266         c->fs_sel = DATA_SELECTOR;
267         c->fs_limit = 0xFFFFFFFF;
268         c->fs_base = 0;
269         c->fs_arbytes = c->ds_arbytes;
270
271         c->gs_sel = DATA_SELECTOR;
272         c->gs_limit = 0xFFFFFFFF;
273         c->gs_base = 0;
274         c->gs_arbytes = c->ds_arbytes;
275
276         c->tr_sel = TSS_SELECTOR;
277         c->tr_limit = sizeof(tss) - 1;
278         c->tr_base = (unsigned long) &tss;
279         c->tr_arbytes.fields.seg_type = 0xb; /* 0x9 | 0x2 (busy) */
280         c->tr_arbytes.fields.s = 0;
281         c->tr_arbytes.fields.dpl = 0;
282         c->tr_arbytes.fields.p = 1;
283         c->tr_arbytes.fields.avl = 0;
284         c->tr_arbytes.fields.default_ops_size = 0;
285         c->tr_arbytes.fields.g = 0;
286
287         c->ldtr_sel = 0;
288         c->ldtr_limit = 0;
289         c->ldtr_base = 0;
290         c->ldtr_arbytes = c->ds_arbytes;
291         c->ldtr_arbytes.fields.seg_type = 0x2;
292         c->ldtr_arbytes.fields.s = 0;
293         c->ldtr_arbytes.fields.dpl = 0;
294         c->ldtr_arbytes.fields.p = 1;
295         c->ldtr_arbytes.fields.avl = 0;
296         c->ldtr_arbytes.fields.default_ops_size = 0;
297         c->ldtr_arbytes.fields.g = 0;
298 }
299
300 /*
301  * Start BIOS by causing a world switch to vmxassist, which causes
302  * VM8086 to be enabled and control is transfered to F000:FFF0.
303  */
304 void
305 start_bios(void)
306 {
307         if (booting_cpu == 0)
308                 printf("Start BIOS ...\n");
309         else
310                 printf("Start AP %d from %08x ...\n",
311                        booting_cpu, booting_vector << 12);
312
313         initialize_real_mode = 1;
314         set_cr0(get_cr0() & ~CR0_PE);
315         panic("vmxassist returned"); /* "cannot happen" */
316 }
317
318 int
319 main(void)
320 {
321         if (booting_cpu == 0)
322                 banner();
323
324         setup_gdt();
325         setup_idt();
326
327         set_cr4(get_cr4() | CR4_VME);
328
329         setup_ctx();
330
331         if (booting_cpu == 0)
332                 setup_pic();
333
334         start_bios();
335
336         return 0;
337 }