- - Rewritten startup code. GDT, IDT and TSS moved away from zero page.
[AROS.git] / arch / i386-pc / exec / exec_init.c
blobe9b34dab5d672eb235e525635dcaec3bfd30a76d
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Early bootup section
6 Lang: english
7 */
9 /*
10 i386-pc AROS MemoryMap:
12 First 4KB of RAM (page 0x0000-0x0FFF) are READ ONLY!
14 +------------+-----------+-------------------------------------------------+
15 | address | length | description |
16 +------------+-----------+-------------------------------------------------+
17 | System page. Read only! Addresses undefined here are not allowed!!!! |
18 +------------------------+-------------------------------------------------+
19 | 0x00000000 | 0x0000100 | Extended BIOS data area preserved |
20 | 0x00000004 | 0x0000004 | SysBase pointer |
21 | 0x00000100 | 0x0000800 | Not used |
22 | 0x00000900 | 0x0000004 | INT server! cached_irq_mask |
23 | 0x00000904 | 0x0000004 | INT server! io_apic_irqs |
24 | 0x00000940 | 0x0000001 | INT server! softblock |
25 | 0x00000a00 | 0x0000200 | INT server! irq_desc[] |
26 | 0x00000c00 | 0x0000300 | Temporary stack for warm reboot |
27 +------------+-----------+-------------------------------------------------+
28 | 0x00001000 | ......... | System RAM. Initially bootstrap resides here. |
29 | 0x000a0000 | 0x0060000 | Data reserved for BIOS, VGA and some MMIO cards |
30 1MB| 0x00100000 | ......... | System RAM divided into DMA and rest. |
31 +------------+-----------+-------------------------------------------------+
34 #include <exec/resident.h>
35 #include <exec/types.h>
36 #include <exec/nodes.h>
37 #include <exec/execbase.h>
38 #include <exec/memory.h>
39 #include <hardware/intbits.h>
40 #include <asm/segments.h>
41 #include <asm/linkage.h>
42 #include <asm/ptrace.h>
43 #include <dos/dosextens.h>
45 #include <aros/arossupportbase.h>
46 #include <aros/asmcall.h>
47 #include <aros/config.h>
49 #include <aros/kernel.h>
51 #define DEBUG 1
53 #include <aros/debug.h>
54 #include <aros/multiboot.h>
56 #include <utility/tagitem.h>
58 #include <hardware/custom.h>
59 #include <resources/acpi.h>
61 #include <proto/alib.h>
62 #include <proto/exec.h>
64 #include <stddef.h>
65 #include <stdio.h>
66 #include <string.h>
68 #include <inttypes.h>
70 #include LC_LIBDEFS_FILE
72 #include "etask.h"
73 #include "exec_intern.h"
74 #include "exec_debug.h"
75 #include "exec_util.h"
76 #include "intservers.h"
77 #include "memory.h"
78 #include "traps.h"
80 /* As long as we don't have CPU detection routine, assume FPU to be present */
82 #define ASSUME_FPU 1
85 * Some macro definitions. __text will place given structure in .text section.
86 * __no_ret will force function type to be no-return function. __packed will
87 * force any structure to be non-aligned (we don't need alignment in native
88 * AROS).
91 #define __text __attribute__((section(".text")))
92 #define __no_ret __attribute__((noreturn))
93 #define __packed __attribute__((packed))
95 #define rdcr(reg) \
96 ({ long val; asm volatile("mov %%" #reg ",%0":"=r"(val)); val; })
98 #define wrcr(reg, val) \
99 do { asm volatile("mov %0,%%" #reg::"r"(val)); } while(0)
101 #define cpuid(num, eax, ebx, ecx, edx) \
102 do { asm volatile("cpuid":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx):"a"(num)); } while(0)
105 * Some declarations
107 AROS_UFP3S(struct ExecBase *, exec_init,
108 AROS_UFPA(struct MemHeader *, mh, D0),
109 AROS_UFPA(struct TagItem *, tagList, A0),
110 AROS_UFPA(struct ExecBase *, sysBase, A6));
112 void irqSetup(void);
114 extern const UBYTE LIBEND __text; /* Somewhere in library */
116 extern void AROS_SLIB_ENTRY(SerialRawIOInit, Exec, 84)();
117 extern void AROS_SLIB_ENTRY(SerialRawPutChar, Exec, 86)(UBYTE chr);
118 extern void AROS_SLIB_ENTRY(MemoryRawIOInit, Exec, 84)();
119 extern void AROS_SLIB_ENTRY(MemoryRawPutChar, Exec, 86)(UBYTE chr);
121 extern void AROS_SLIB_ENTRY(Switch_FPU, Exec, 9)();
122 extern void AROS_SLIB_ENTRY(PrepareContext_FPU, Exec, 6)();
123 extern void AROS_SLIB_ENTRY(Dispatch_FPU, Exec, 10)();
125 extern void AROS_SLIB_ENTRY(Switch_SSE, Exec, 9)();
126 extern void AROS_SLIB_ENTRY(PrepareContext_SSE, Exec, 6)();
127 extern void AROS_SLIB_ENTRY(Dispatch_SSE, Exec, 10)();
128 extern void AROS_SLIB_ENTRY(CopyMem_SSE, Exec, 104)();
131 * First, we will define exec.library (global) to make it usable outside this
132 * file.
134 const char exec_name[] __text = "exec.library";
135 /* Now ID string as it will be used in a minute in resident structure. */
136 const char exec_idstring[] __text = VERSION_STRING;
139 * The RomTag structure. It has to be placed inside .text block as there will
140 * be no public RomTagList. In future we may change RTC_MATCHWORD to be machine
141 * specific.
143 const struct Resident Exec_resident __text=
145 RTC_MATCHWORD, /* Magic value used to find resident */
146 &Exec_resident, /* Points to Resident itself */
147 (APTR)&LIBEND, /* Where could we find next Resident? */
148 0, /* There are no flags!! */
149 VERSION_NUMBER, /* Version */
150 NT_LIBRARY, /* Type */
151 126, /* Very high startup priority. */
152 (char *)exec_name, /* Pointer to name string */
153 (char *)exec_idstring, /* Ditto */
154 exec_init /* Library initializer */
158 /* These defines used to keep control over interrupt server */
159 asm(".globl cached_irq_mask\n\t"
160 ".globl io_apic_irqs\n\t"
161 ".globl softblock\n\t"
162 ".globl irq_desc\n\t"
163 ".set cached_irq_mask, 0x00000900\n\t"
164 ".set io_apic_irqs, 0x00000904\n\t"
165 ".set softblock, 0x00000940\n\t"
166 ".set irq_desc, 0x00000a00");
168 AROS_UFH3S(struct ExecBase *, exec_init,
169 AROS_UFHA(struct MemHeader *, mh, D0),
170 AROS_UFHA(struct TagItem *, tagList, A0),
171 AROS_UFHA(struct ExecBase *, origSysBase, A6)
174 AROS_USERFUNC_INIT
176 if (!origSysBase)
177 return PrepareExecBase(mh, tagList);
179 return NULL;
181 AROS_USERFUNC_EXIT
184 void exec_boot(struct TagItem *msg)
186 char *cmdline = (char *)LibGetTagData(KRN_CmdLine, 0, msg);
187 int i;
189 bug("Initializing library...");
191 for (i=0; i<16; i++)
193 if( (1<<i) & (INTF_PORTS|INTF_COPER|INTF_VERTB|INTF_EXTER|INTF_SETCLR))
195 struct Interrupt *is;
196 struct SoftIntList *sil;
197 is = AllocMem
199 sizeof(struct Interrupt) + sizeof(struct SoftIntList),
200 MEMF_CLEAR | MEMF_PUBLIC
202 if( is == NULL )
204 bug("ERROR: Cannot install Interrupt Servers!\n");
206 sil = (struct SoftIntList *)((struct Interrupt *)is + 1);
208 is->is_Code = &IntServer;
209 is->is_Data = sil;
210 NEWLIST((struct List *)sil);
211 SetIntVector(i,is);
213 else
215 struct Interrupt *is;
216 switch (i)
218 case INTB_SOFTINT :
219 is = AllocMem
221 sizeof(struct Interrupt),
222 MEMF_CLEAR | MEMF_PUBLIC
224 if (is == NULL)
226 bug("Error: Cannot install Interrupt Servers!\n");
227 // Alert(AT_DeadEnd | AN_IntrMem);
229 is->is_Node.ln_Type = NT_SOFTINT; //INTERRUPT;
230 is->is_Node.ln_Pri = 0;
231 is->is_Node.ln_Name = "SW Interrupt Dispatcher";
232 is->is_Data = NULL;
233 is->is_Code = (void *)SoftIntDispatch;
234 SetIntVector(i,is);
235 break;
240 irqSetup();
241 bug("IRQ services initialized\n");
243 /* Enable interrupts and set int disable level to -1 */
244 asm("sti");
245 SysBase->TDNestCnt = -1;
246 SysBase->IDNestCnt = -1;
248 bug("Creating the very first task...");
250 /* Complete boot task. */
252 struct Task *t = SysBase->ThisTask;
253 struct MemList *ml;
255 ml = (struct MemList *)AllocMem(sizeof(struct MemList), MEMF_PUBLIC|MEMF_CLEAR);
257 if(!ml)
259 bug("ERROR: Cannot create Boot Task!\n");
260 for(;;);
262 ml->ml_NumEntries = 1;
263 ml->ml_ME[0].me_Addr = t;
264 ml->ml_ME[0].me_Length = sizeof(struct Process);
266 AddHead(&t->tc_MemEntry,&ml->ml_Node);
268 t->tc_Flags |= TF_ETASK;
269 t->tc_UnionETask.tc_ETask = AllocVec(sizeof(struct IntETask), MEMF_CLEAR);
271 if (!t->tc_UnionETask.tc_ETask)
273 bug("Not enough memory for first task\n");
274 for(;;);
277 /* Initialise the ETask data. */
278 InitETask(t, t->tc_UnionETask.tc_ETask);
280 GetIntETask(t)->iet_Context = AllocTaskMem(t, SIZEOF_ALL_REGISTERS, MEMF_PUBLIC|MEMF_CLEAR);
282 if (!GetIntETask(t)->iet_Context)
284 bug("Not enough memory for first task\n");
285 for(;;);
287 t->tc_UnionETask.tc_ETask->et_Parent = NULL;
290 bug("Done\n");
293 Check whether the CPU supports SSE and FXSAVE.
295 Dirty check, without use of any defines and human readable constants. The
296 cpuid instruction with %eax=1 will return some essential cpu informations in %edx back,
297 including:
298 - bit 24: CPU does support FXSAVE and FXRSTOR for MMX/FPU/SSE context saving and restoring
299 - bit 25: CPU supports SSE
300 - bit 26: CPU supports SSE2
303 ULONG v1,v2,v3,v4;
304 cpuid(1, v1,v2,v3,v4);
306 bug("cpuid 1 = %08x %08x %08x %08x\n", v1, v2, v3, v4);
308 if (v4 & (1 << 24))
310 bug("The CPU supports FXSAVE and FXRSTOR. Good.\n");
311 bug("CPU Supports ");
313 switch ((v4 >> 25) & 3)
315 case 3:
316 case 2:
317 bug("SSE2 ");
318 case 1:
319 bug("SSE\n");
320 /* Patch exec with some SSE-aware functions */
321 SetFunction(&SysBase->LibNode, -6*LIB_VECTSIZE, AROS_SLIB_ENTRY(PrepareContext_SSE, Exec, 6));
322 SetFunction(&SysBase->LibNode, -9*LIB_VECTSIZE, AROS_SLIB_ENTRY(Switch_SSE, Exec, 9));
323 SetFunction(&SysBase->LibNode, -10*LIB_VECTSIZE, AROS_SLIB_ENTRY(Dispatch_SSE, Exec, 10));
324 SetFunction(&SysBase->LibNode, -104*LIB_VECTSIZE, AROS_SLIB_ENTRY(CopyMem_SSE, Exec, 104));
325 SetFunction(&SysBase->LibNode, -105*LIB_VECTSIZE, AROS_SLIB_ENTRY(CopyMem_SSE, Exec, 104));
326 /* tell the CPU that we will support SSE */
327 wrcr(cr4, rdcr(cr4) | (3 << 9));
328 /* Clear the EM and MP flags of CR0 */
329 wrcr(cr0, rdcr(cr0) & ~6);
330 bug("SSE enabled.\n");
331 break;
333 default:
335 Ha! Bloody PentiumII does supports MMX/FPU/SSE saving instructions,
336 but it does not support SSE
338 bug("no SSE. Sorry :)\n");
339 break;
342 else
344 #if ASSUME_FPU
345 SetFunction(&SysBase->LibNode, -6*LIB_VECTSIZE, AROS_SLIB_ENTRY(PrepareContext_FPU, Exec, 6));
346 SetFunction(&SysBase->LibNode, -9*LIB_VECTSIZE, AROS_SLIB_ENTRY(Switch_FPU, Exec, 9));
347 SetFunction(&SysBase->LibNode, -10*LIB_VECTSIZE, AROS_SLIB_ENTRY(Dispatch_FPU, Exec, 10));
349 bug("FPU enabled.\n");
350 #endif
354 bug("Jumping out from Supervisor mode...");
356 #if 0
358 asm("mov %0,%%ds\n\t" /* User DS */
359 "mov %0,%%es\n\t" /* User ES */
360 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
361 "pushl %0\n\t" /* User SS */
362 "pushl %%ebx\n\t" /* Stack frame */
363 "pushl $0x3002\n\t" /* IOPL:3 */
364 "pushl %1\n\t" /* User CS */
365 "pushl $1f\n\t" /* Entry address */
366 "iret\n" /* Go down to the user mode */
367 "1:\tsti" /* Enable interrupts */
369 : "eax"(USER_DS),"ecx"(USER_CS));
370 #else
371 # define _stringify(x) #x
372 # define stringify(x) _stringify(x)
374 asm("movl $" stringify(USER_DS) ",%%eax\n\t"
375 "mov %%eax,%%ds\n\t" /* User DS */
376 "mov %%eax,%%es\n\t" /* User ES */
377 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
378 "pushl %%eax\n\t" /* User SS */
379 "pushl %%ebx\n\t" /* Stack frame */
380 "pushl $0x3002\n\t" /* IOPL:3 */
381 "pushl $" stringify(USER_CS) "\n\t" /* User CS */
382 "pushl $1f\n\t" /* Entry address */
383 "iret\n" /* Go down to the user mode */
384 "1:\tsti":::"eax","ebx"); /* Enable interrupts */
386 # undef stringify
387 # undef _stringify
388 #endif
390 bug("Done\n");
392 SysBase->TDNestCnt++;
393 Permit();
396 * Enable type of debug output chosen by user.
397 * 'serial' is not handled in libbootconsole.
399 if (strstr(cmdline, "debug=memory"))
401 SetFunction(&SysBase->LibNode, -84 * LIB_VECTSIZE,
402 AROS_SLIB_ENTRY(MemoryRawIOInit, Exec, 84));
403 SetFunction(&SysBase->LibNode, -86 * LIB_VECTSIZE,
404 AROS_SLIB_ENTRY(MemoryRawPutChar, Exec, 86));
406 RawIOInit();
408 if (SysBase->CoolCapture)
410 void (*p)() = SysBase->CoolCapture;
412 bug("Executing CoolCapture at 0x%p\n", p);
413 (*p)();
416 InitCode(RTF_COLDSTART, 0);
419 /* Small delay routine used by exec_cinit initializer */
420 asm("\ndelay:\t.short 0x00eb\n\tret");
422 AROS_LH1(struct ExecBase *, open,
423 AROS_LHA(ULONG, version, D0),
424 struct ExecBase *, SysBase, 1, Exec)
426 AROS_LIBFUNC_INIT
428 /* I have one more opener. */
429 SysBase->LibNode.lib_OpenCnt++;
430 return SysBase;
431 AROS_LIBFUNC_EXIT
434 AROS_LH0(BPTR, close,
435 struct ExecBase *, SysBase, 2, Exec)
437 AROS_LIBFUNC_INIT
439 /* I have one fewer opener. */
440 SysBase->LibNode.lib_OpenCnt--;
441 return 0;
442 AROS_LIBFUNC_EXIT
445 AROS_LH0I(int, null,
446 struct ExecBase *, SysBase, 3, Exec)
448 AROS_LIBFUNC_INIT
449 return 0;
450 AROS_LIBFUNC_EXIT
453 AROS_LH0I(int, null,
454 struct ExecBase *, SysBase, 4, Exec)
456 AROS_LIBFUNC_INIT
457 return 0;
458 AROS_LIBFUNC_EXIT