clib/mktemp.c & shell/If: Fix checking for existing file.
[AROS.git] / arch / i386-pc / kernel / startup.c
blob50d4c08e55bbaaf8e6fb59b3d47467c3c8f1447c
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: i386-pc kernel startup code
6 Lang: english
7 */
9 #include <aros/kernel.h>
10 #include <aros/multiboot.h>
11 #include <asm/cpu.h>
12 #include <exec/resident.h>
13 #include <proto/arossupport.h>
14 #include <proto/exec.h>
16 #include <bootconsole.h>
17 #include <string.h>
19 #include "boot_utils.h"
20 #include "kernel_base.h"
21 #include "kernel_bootmem.h"
22 #include "kernel_debug.h"
23 #include "kernel_intern.h"
24 #include "kernel_mmap.h"
25 #include "kernel_romtags.h"
27 #define D(x) x
29 static char boot_stack[];
31 static void kernel_boot(const struct TagItem *msg);
32 void core_Kick(struct TagItem *msg, void *target);
33 void kernel_cstart(const struct TagItem *msg);
36 * Here the history starts. We are already in flat, 32bit mode. All protections
37 * are off, CPU is working in Supervisor level (CPL0). Interrupts should
38 * be disabled.
40 * Here we run on a stack provided by the bootstrap. We can perform calls, but we
41 * don't know where it is placed, so we need to switch away from it ASAP.
43 IPTR __startup kernel_entry(struct TagItem *bootMsg, ULONG magic)
45 if (magic == AROS_BOOT_MAGIC)
46 core_Kick(bootMsg, kernel_boot);
48 return -1;
52 * The real entry point for initial boot.
53 * Here we initialize debug console and say "hello".
54 * Warm restart skips this since the screen was taken over by display driver.
56 static void kernel_boot(const struct TagItem *msg)
59 * Initial framebuffer mirror will be located by default at (1MB + 4KB).
60 * This is done because our bootstrap begins at 1MB, and its .tables
61 * sections are placed in the beginning. We must not ocassionally overwrite
62 * these sections for now because they contain boot-time data for us
63 * (taglist etc).
64 * A well-behaved bootstrap should give us ProtAreaEnd.
66 fb_Mirror = (void *)LibGetTagData(KRN_ProtAreaEnd, 0x101000, msg);
67 con_InitTagList(msg);
69 bug("AROS - The AROS Research OS. Compiled %s\n",__DATE__);
71 kernel_cstart(msg);
75 * This function actually runs the kickstart from the specified address.
76 * Before doing this it clears .bss sections of all modules.
78 void core_Kick(struct TagItem *msg, void *target)
80 const struct TagItem *bss = LibFindTagItem(KRN_KernelBss, msg);
82 /* First clear .bss */
83 if (bss)
84 __clear_bss((const struct KernelBSS *)bss->ti_Data);
87 * ... then switch to initial stack and jump to target address.
88 * We set ebp to 0 and use call here in order to get correct stack traces
89 * if the boot task crashes. Otherwise backtrace goes beyond this location
90 * into memory areas with undefined contents.
92 asm volatile("movl %1, %%esp \n\t"
93 "movl $0, %%ebp \n\t"
94 "pushl %0 \n\t"
95 "cld \n\t" /* At the startup it's very important */
96 "cli \n\t" /* to lock all interrupts. Both on the */
97 "movb $-1,%%al \n\t" /* CPU side and hardware side. We don't */
98 "outb %%al,$0x21 \n\t" /* have proper structures in RAM yet. */
99 "outb %%al,$0xa1 \n\t"
100 "call *%2\n"::"r"(msg), "r"(boot_stack + STACK_SIZE), "r"(target));
103 /* Common IBM PC memory layout */
104 static const struct MemRegion PC_Memory[] =
107 * Give low memory a bit lower priority. This will help us to locate its MemHeader (the last one in the list).
108 * We explicitly need low memory for SMP bootstrap.
110 {0x00000000, 0x000a0000, "Low memory" , -6, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT|MEMF_24BITDMA},
111 {0x00100000, 0x01000000, "ISA DMA memory", -5, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT|MEMF_24BITDMA},
113 * FIXME: The following should also be CHIP. trackdisk.device fix is needed
114 * (use MEMF_24BITDMA instead of MEMF_CHIP for 24-bit ISA DMA-capable area.
115 * EXPERIMENTAL: Some (or all?) 64-bit machines expose RAM at addresses up to
116 * 0xD0000000 (giving 3.5 GB total). All MMIO sits beyond this border. We
117 * intentionally specify 4GB as limit, just in case if some machine exhibits
118 * even more RAM in this space. We want all the RAM to be usable.
120 {0x01000000, 0xFFFFFFFF, "High memory" , 0, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_FAST|MEMF_31BIT },
121 {0 , 0 , NULL , 0, 0 }
125 * Our transient data.
126 * They must survive warm restart, so we put them into .data section.
127 * We also have SysBase here, this way we move it away from zero page,
128 * making it harder to trash it.
130 __attribute__((section(".data"))) IPTR kick_end = 0;
131 __attribute__((section(".data"))) struct segment_desc *GDT = NULL;
132 __attribute__((section(".data"))) struct ExecBase *SysBase = NULL;
135 * Static read-only copy of prebuilt GDT.
136 * We only need to patch a TSS segment, after TSS has been allocated.
138 static const struct {UWORD l1, l2, l3, l4;}
139 GDT_Table[] =
141 { 0x0000, 0x0000, 0x0000, 0x0000 },
142 { 0xffff, 0x0000, 0x9a00, 0x00cf },
143 { 0xffff, 0x0000, 0x9200, 0x00cf },
144 { 0xffff, 0x0000, 0xfa00, 0x00cf },
145 { 0xffff, 0x0000, 0xf200, 0x00cf },
146 { 0x0000, 0x0000, 0x0000, 0x0000 },
147 { 0x0067, 0x0000, 0x8900, 0x0000 },
148 { 0x0000, 0x0000, 0x0000, 0x0000 }
152 * This is the main entry point.
153 * We run from here both at first boot and upon reboot.
155 void kernel_cstart(const struct TagItem *msg)
157 struct TagItem *tag;
158 struct mb_mmap *mmap = NULL;
159 unsigned long mmap_len = 0;
160 IPTR kick_start = 0;
161 struct table_desc gdtr;
162 struct MinList memList;
163 struct MemHeader *mh, *mh2;
164 UWORD *ranges[3];
165 struct mb_mmap *region;
167 D(bug("[Kernel] Transient kickstart end 0x%p, BootMsg 0x%p\n", kick_end, BootMsg));
168 D(bug("[Kernel] Boot stack: 0x%p - 0x%p\n", boot_stack, boot_stack + STACK_SIZE));
170 if (!kick_end)
172 struct vbe_mode *vmode = NULL;
173 char *cmdline = NULL;
175 /* If kick_end is not set, this is our first start. */
176 tag = LibFindTagItem(KRN_KernelHighest, msg);
177 if (!tag)
178 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
179 "Highest kickstart address is not supplied\n");
181 /* Align kickstart top address (we are going to place a structure after it) */
182 BootMemPtr = (void *)AROS_ROUNDUP2(tag->ti_Data + 1, sizeof(APTR));
185 * Our boot taglist is placed by the bootstrap just somewhere in memory.
186 * The first thing is to move it into some safe place.
187 * This function also sets global BootMsg pointer.
189 RelocateBootMsg(msg);
191 /* Now relocate linked data */
192 mmap_len = LibGetTagData(KRN_MMAPLength, 0, BootMsg);
193 msg = BootMsg;
194 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
196 switch (tag->ti_Tag)
198 case KRN_KernelBss:
199 RelocateBSSData(tag);
200 break;
202 case KRN_MMAPAddress:
203 RelocateTagData(tag, mmap_len);
204 break;
206 case KRN_VBEModeInfo:
207 RelocateTagData(tag, sizeof(struct vbe_mode));
208 vmode = (struct vbe_mode *)tag->ti_Data;
209 break;
211 case KRN_VBEControllerInfo:
212 RelocateTagData(tag, sizeof(struct vbe_controller));
213 break;
215 case KRN_CmdLine:
216 RelocateStringData(tag);
217 cmdline = (char *)tag->ti_Data;
218 break;
220 case KRN_BootLoader:
221 RelocateStringData(tag);
222 break;
226 /* Allocate space for GDT */
227 GDT = krnAllocBootMemAligned(sizeof(GDT_Table), 128);
229 vesahack_Init(cmdline, vmode);
232 * Set new kickstart end address.
233 * Kickstart area now includes boot taglist with all its contents.
235 kick_end = (IPTR)BootMemPtr;
236 D(bug("[Kernel] Boot-time setup complete, end of kickstart area 0x%p\n", kick_end));
240 * Obtain the needed data from the boot taglist.
241 * We parse it from scratch here because we come here in both cases
242 * (first boot and reboot)
244 msg = BootMsg;
245 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
247 switch (tag->ti_Tag)
249 case KRN_KernelLowest:
250 kick_start = tag->ti_Data;
251 break;
253 case KRN_MMAPAddress:
254 mmap = (struct mb_mmap *)tag->ti_Data;
255 break;
257 case KRN_MMAPLength:
258 mmap_len = tag->ti_Data;
259 break;
263 /* Sanity check */
264 if ((!kick_start) || (!mmap) || (!mmap_len))
266 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
267 "Kickstart address : 0x%P\n"
268 "Memory map address: 0x%P, length %ld\n",
269 kick_start, mmap, mmap_len);
272 /* Create global descriptor table */
273 krnCopyMem(GDT_Table, GDT, sizeof(GDT_Table));
276 * Initial CPU setup. Load the GDT and segment registers.
277 * AROS uses only CS SS DS and ES. FS and GS are set to 0
278 * so we can generate GP if someone uses them.
280 gdtr.size = sizeof(GDT_Table) - 1;
281 gdtr.base = (unsigned long)GDT;
284 " lgdt %0\n"
285 " mov %1,%%ds\n"
286 " mov %1,%%es\n"
287 " mov %1,%%ss\n"
288 " mov %2,%%fs\n"
289 " mov %2,%%gs\n"
290 " ljmp %3,$1f\n"
291 "1:\n"
292 ::"m"(gdtr),"r"(KERNEL_DS),"r"(0),"i"(KERNEL_CS)
295 D(bug("[Kernel] GDT @ 0x%p reloaded\n", GDT));
298 * Explore memory map and create MemHeaders
299 * 4KB at address 0 are reserved for our needs.
301 NEWLIST(&memList);
302 mmap_InitMemory(mmap, mmap_len, &memList, kick_start, kick_end, 0x00001000, PC_Memory);
305 * mmap_InitMemory() adds MemHeaders to the list in the order they were created.
306 * I. e. highest addresses are added last.
307 * Take highest region in order to create SysBase in it.
309 mh = (struct MemHeader *)REMTAIL(&memList);
310 D(bug("[Kernel] Initial MemHeader: 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
312 if (SysBase)
315 * Validate SysBase.
316 * Criteria: The pointer should point to a valid memory region.
317 * This is only address validation.
318 * Checksum etc is processed in PrepareExecBase() in exec.library.
320 BOOL sysbase_bad = TRUE;
322 region = mmap_FindRegion((unsigned long)SysBase, mmap, mmap_len);
323 if (region && region->type == MMAP_TYPE_RAM)
325 IPTR end = region->addr + region->len;
327 if ((IPTR)SysBase + sizeof(struct ExecBase) < end)
328 sysbase_bad = FALSE;
331 if (sysbase_bad)
332 SysBase = NULL;
335 ranges[0] = (UWORD *)kick_start;
336 ranges[1] = (UWORD *)kick_end;
337 ranges[2] = (UWORD *)-1;
339 krnPrepareExecBase(ranges, mh, BootMsg);
342 * Now we have working exec.library memory allocator.
343 * Move console mirror buffer away from unused memory.
344 * WARNING!!! Do not report anything in the debug log before this is done. Remember that sequental
345 * AllocMem()s return sequental blocks! And right beyond our allocated area there will be MemChunk.
346 * Between krnPrepareExecBase() and this AllocMem() upon warm reboot console mirror buffer is set
347 * to an old value right above ExecBase. During krnPrepareExecBase() a MemChunk is built there,
348 * which can be overwritten by bootconsole, especially if the output scrolls.
350 if (scr_Type == SCR_GFX)
352 char *mirror = AllocMem(scr_Width * scr_Height, MEMF_PUBLIC);
354 fb_SetMirror(mirror);
357 D(bug("[Kernel] Created SysBase at 0x%p, MemHeader 0x%p\n", SysBase, mh));
359 /* Transfer the rest of memory list into SysBase */
360 D(bug("[Kernel] Transferring memory list into SysBase...\n"));
361 for (mh = (struct MemHeader *)memList.mlh_Head; mh->mh_Node.ln_Succ; mh = mh2)
363 mh2 = (struct MemHeader *)mh->mh_Node.ln_Succ;
365 D(bug("[Kernel] * 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
366 Enqueue(&SysBase->MemList, &mh->mh_Node);
370 * Now we can initialize SINGLETASK residents.
371 * This includes kernel.resource itself. Its platform-specific code
372 * will initialize the rest of hardware.
374 InitCode(RTF_SINGLETASK, 0);
377 * After RTF_SINGLETASK we can have various interesting things like ACPI.
378 * Secondary platform initialization code makes use of them.
380 PlatformPostInit();
382 # define _stringify(x) #x
383 # define stringify(x) _stringify(x)
385 asm("movl $" stringify(USER_DS) ",%%eax\n\t"
386 "mov %%eax,%%ds\n\t" /* User DS */
387 "mov %%eax,%%es\n\t" /* User ES */
388 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
389 "pushl %%eax\n\t" /* User SS */
390 "pushl %%ebx\n\t" /* Stack frame */
391 "pushl $0x3002\n\t" /* IOPL:3 */
392 "pushl $" stringify(USER_CS) "\n\t" /* User CS */
393 "pushl $1f\n\t" /* Entry address */
394 "iret\n" /* Go down to the user mode */
395 "1:":::"eax","ebx");
397 InitCode(RTF_COLDSTART, 0);
399 krnPanic(KernelBase, "Failed to start up the system");
402 /* Our boot-time stack. Safe to be in .bss. */
403 static char boot_stack[STACK_SIZE] __attribute__((aligned(16)));