Indentation fix, cleanup.
[AROS.git] / arch / i386-pc / kernel / kernel_startup.c
blobc0055a00a5d9aabe5d3f03a81829326e31eab574
1 /*
2 Copyright © 1995-2014, 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 * EXPERIMENTAL: Some (or all?) 64-bit machines expose RAM at addresses up to
114 * 0xD0000000 (giving 3.5 GB total). All MMIO sits beyond this border. We
115 * intentionally specify 4GB as limit, just in case if some machine exhibits
116 * even more RAM in this space. We want all the RAM to be usable.
118 {0x01000000, 0xFFFFFFFF, "High memory" , 0, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT },
119 {0 , 0 , NULL , 0, 0 }
123 * Our transient data.
124 * They must survive warm restart, so we put them into .data section.
125 * We also have SysBase here, this way we move it away from zero page,
126 * making it harder to trash it.
128 __attribute__((section(".data"))) IPTR kick_end = 0;
129 __attribute__((section(".data"))) struct segment_desc *GDT = NULL;
130 __attribute__((section(".data"))) struct ExecBase *SysBase = NULL;
133 * Static read-only copy of prebuilt GDT.
134 * We only need to patch a TSS segment, after TSS has been allocated.
136 static const struct {UWORD l1, l2, l3, l4;}
137 GDT_Table[] =
139 { 0x0000, 0x0000, 0x0000, 0x0000 },
140 { 0xffff, 0x0000, 0x9a00, 0x00cf },
141 { 0xffff, 0x0000, 0x9200, 0x00cf },
142 { 0xffff, 0x0000, 0xfa00, 0x00cf },
143 { 0xffff, 0x0000, 0xf200, 0x00cf },
144 { 0x0000, 0x0000, 0x0000, 0x0000 },
145 { 0x0067, 0x0000, 0x8900, 0x0000 },
146 { 0x0000, 0x0000, 0x0000, 0x0000 }
150 * This is the main entry point.
151 * We run from here both at first boot and upon reboot.
153 void kernel_cstart(const struct TagItem *msg)
155 struct TagItem *tag;
156 struct mb_mmap *mmap = NULL;
157 unsigned long mmap_len = 0;
158 IPTR kick_start = 0;
159 struct table_desc gdtr;
160 struct MinList memList;
161 struct MemHeader *mh, *mh2;
162 UWORD *ranges[] = {NULL, NULL, (UWORD *)-1};
163 struct mb_mmap *region;
164 char *cmdline = NULL;
165 ULONG allocator = ALLOCATOR_TLSF;
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;
174 /* If kick_end is not set, this is our first start. */
175 tag = LibFindTagItem(KRN_KernelHighest, msg);
176 if (!tag)
177 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
178 "Highest kickstart address is not supplied\n");
180 /* Align kickstart top address (we are going to place a structure after it) */
181 BootMemPtr = (void *)AROS_ROUNDUP2(tag->ti_Data + 1, sizeof(APTR));
184 * Our boot taglist is placed by the bootstrap just somewhere in memory.
185 * The first thing is to move it into some safe place.
186 * This function also sets global BootMsg pointer.
188 RelocateBootMsg(msg);
190 /* Now relocate linked data */
191 mmap_len = LibGetTagData(KRN_MMAPLength, 0, BootMsg);
192 msg = BootMsg;
193 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
195 switch (tag->ti_Tag)
197 case KRN_KernelBss:
198 RelocateBSSData(tag);
199 break;
201 case KRN_MMAPAddress:
202 RelocateTagData(tag, mmap_len);
203 break;
205 case KRN_VBEModeInfo:
206 RelocateTagData(tag, sizeof(struct vbe_mode));
207 vmode = (struct vbe_mode *)tag->ti_Data;
208 break;
210 case KRN_VBEControllerInfo:
211 RelocateTagData(tag, sizeof(struct vbe_controller));
212 break;
214 case KRN_CmdLine:
215 RelocateStringData(tag);
216 cmdline = (char *)tag->ti_Data;
217 break;
219 case KRN_BootLoader:
220 RelocateStringData(tag);
221 break;
225 /* Allocate space for GDT */
226 GDT = krnAllocBootMemAligned(sizeof(GDT_Table), 128);
228 vesahack_Init(cmdline, vmode);
231 * Set new kickstart end address.
232 * Kickstart area now includes boot taglist with all its contents.
234 kick_end = (IPTR)BootMemPtr;
235 D(bug("[Kernel] Boot-time setup complete, end of kickstart area 0x%p\n", kick_end));
239 * Obtain the needed data from the boot taglist.
240 * We parse it from scratch here because we come here in both cases
241 * (first boot and reboot)
243 msg = BootMsg;
244 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
246 switch (tag->ti_Tag)
248 case KRN_KernelLowest:
249 kick_start = tag->ti_Data;
250 break;
252 case KRN_MMAPAddress:
253 mmap = (struct mb_mmap *)tag->ti_Data;
254 break;
256 case KRN_MMAPLength:
257 mmap_len = tag->ti_Data;
258 break;
260 case KRN_CmdLine:
261 cmdline = (char *)tag->ti_Data;
262 break;
266 /* Sanity check */
267 if ((!kick_start) || (!mmap) || (!mmap_len))
269 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
270 "Kickstart address : 0x%P\n"
271 "Memory map address: 0x%P, length %ld\n",
272 kick_start, mmap, mmap_len);
275 if (cmdline && strstr(cmdline, "notlsf"))
276 allocator = ALLOCATOR_STD;
279 /* Create global descriptor table */
280 krnCopyMem(GDT_Table, GDT, sizeof(GDT_Table));
283 * Initial CPU setup. Load the GDT and segment registers.
284 * AROS uses only CS SS DS and ES. FS and GS are set to 0
285 * so we can generate GP if someone uses them.
287 gdtr.size = sizeof(GDT_Table) - 1;
288 gdtr.base = (unsigned long)GDT;
291 " lgdt %0\n"
292 " mov %1,%%ds\n"
293 " mov %1,%%es\n"
294 " mov %1,%%ss\n"
295 " mov %2,%%fs\n"
296 " mov %2,%%gs\n"
297 " ljmp %3,$1f\n"
298 "1:\n"
299 ::"m"(gdtr),"r"(KERNEL_DS),"r"(0),"i"(KERNEL_CS)
302 D(bug("[Kernel] GDT @ 0x%p reloaded\n", GDT));
305 * Explore memory map and create MemHeaders
306 * 4KB at address 0 are reserved for our needs.
308 NEWLIST(&memList);
309 mmap_InitMemory(mmap, mmap_len, &memList, kick_start, kick_end, 0x00001000, PC_Memory, allocator);
312 * mmap_InitMemory() adds MemHeaders to the list in the order they were created.
313 * I. e. highest addresses are added last.
314 * Take highest region in order to create SysBase in it.
316 mh = (struct MemHeader *)REMTAIL(&memList);
318 D(bug("[Kernel] Initial MemHeader: 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
320 if (SysBase)
323 * Validate SysBase.
324 * Criteria: The pointer should point to a valid memory region.
325 * This is only address validation.
326 * Checksum etc is processed in PrepareExecBase() in exec.library.
328 BOOL sysbase_bad = TRUE;
330 region = mmap_FindRegion((unsigned long)SysBase, mmap, mmap_len);
331 if (region && region->type == MMAP_TYPE_RAM)
333 IPTR end = region->addr + region->len;
335 if ((IPTR)SysBase + sizeof(struct ExecBase) < end)
336 sysbase_bad = FALSE;
339 if (sysbase_bad)
340 SysBase = NULL;
343 ranges[0] = (UWORD *)kick_start;
344 ranges[1] = (UWORD *)kick_end;
345 krnPrepareExecBase(ranges, mh, BootMsg);
347 krnCreateROMHeader("Kickstart ROM", (APTR)kick_start, (APTR)kick_end);
350 * Now we have working exec.library memory allocator.
351 * Move console mirror buffer away from unused memory.
352 * WARNING!!! Do not report anything in the debug log before this is done. Remember that sequental
353 * AllocMem()s return sequental blocks! And right beyond our allocated area there will be MemChunk.
354 * Between krnPrepareExecBase() and this AllocMem() upon warm reboot console mirror buffer is set
355 * to an old value right above ExecBase. During krnPrepareExecBase() a MemChunk is built there,
356 * which can be overwritten by bootconsole, especially if the output scrolls.
358 if (scr_Type == SCR_GFX)
360 char *mirror = AllocMem(scr_Width * scr_Height, MEMF_PUBLIC);
362 fb_SetMirror(mirror);
365 D(bug("[Kernel] Created SysBase at 0x%p, MemHeader 0x%p\n", SysBase, mh));
367 /* Transfer the rest of memory list into SysBase */
368 D(bug("[Kernel] Transferring memory list into SysBase...\n"));
369 for (mh = (struct MemHeader *)memList.mlh_Head; mh->mh_Node.ln_Succ; mh = mh2)
371 mh2 = (struct MemHeader *)mh->mh_Node.ln_Succ;
373 D(bug("[Kernel] * 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
374 Enqueue(&SysBase->MemList, &mh->mh_Node);
378 * Now we can initialize SINGLETASK residents.
379 * This includes kernel.resource itself. Its platform-specific code
380 * will initialize the rest of hardware.
382 InitCode(RTF_SINGLETASK, 0);
385 * After RTF_SINGLETASK we can have various interesting things like ACPI.
386 * Secondary platform initialization code makes use of them.
388 PlatformPostInit();
390 # define _stringify(x) #x
391 # define stringify(x) _stringify(x)
393 asm("movl $" stringify(USER_DS) ",%%eax\n\t"
394 "mov %%eax,%%ds\n\t" /* User DS */
395 "mov %%eax,%%es\n\t" /* User ES */
396 "movl %%esp,%%ebx\n\t" /* Hold the esp value before pushing! */
397 "pushl %%eax\n\t" /* User SS */
398 "pushl %%ebx\n\t" /* Stack frame */
399 "pushl $0x3002\n\t" /* IOPL:3 */
400 "pushl $" stringify(USER_CS) "\n\t" /* User CS */
401 "pushl $1f\n\t" /* Entry address */
402 "iret\n" /* Go down to the user mode */
403 "1:":::"eax","ebx");
405 InitCode(RTF_COLDSTART, 0);
407 krnPanic(KernelBase, "Failed to start up the system");
410 /* Our boot-time stack. Safe to be in .bss. */
411 static char boot_stack[STACK_SIZE] __attribute__((aligned(16)));