revert between 56095 -> 55830 in arch
[AROS.git] / arch / i386-pc / kernel / kernel_startup.c
blob38ab32770342fa955cfc5bcb46489f3827a1e0e2
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: i386-pc kernel startup code
6 Lang: english
7 */
9 #include <aros/multiboot.h>
10 #include <asm/cpu.h>
11 #include <asm/io.h>
12 #include <aros/symbolsets.h>
13 #include <exec/lists.h>
14 #include <exec/memory.h>
15 #include <exec/resident.h>
16 #include <utility/tagitem.h>
17 #include <proto/arossupport.h>
18 #include <proto/exec.h>
20 #include <bootconsole.h>
21 #include <inttypes.h>
22 #include <string.h>
24 #include "boot_utils.h"
25 #include "kernel_base.h"
26 #include "kernel_intern.h"
27 #include "kernel_bootmem.h"
28 #include "kernel_debug.h"
29 #include "kernel_mmap.h"
30 #include "kernel_romtags.h"
32 #define D(x)
34 static char boot_stack[];
36 static void kernel_boot(const struct TagItem *msg);
37 void core_Kick(struct TagItem *msg, void *target);
38 void kernel_cstart(const struct TagItem *msg);
40 /* Common IBM PC memory layout (32bit version) */
41 static const struct MemRegion PC_Memory[] =
44 * Low memory has a bit lower priority -:
45 * - This helps the kernel/exec locate its MemHeader.
46 * - We explicitly need low memory for SMP bootstrap.
48 {0x00000000, 0x000a0000, "Low memory" , -6, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT|MEMF_24BITDMA},
49 {0x00100000, 0x01000000, "ISA DMA memory", -5, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT|MEMF_24BITDMA},
51 * 64-bit machines can expose RAM at addresses up to 0xD0000000 (giving 3.5 GB total).
52 * All MMIO sits beyond this border. AROS intentionally specifies a 4GB limit, in case some
53 * devices expose even more RAM in this space. This allows all the RAM to be usable.
55 {0x01000000, 0xFFFFFFFF, "High memory" , 0, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_CHIP|MEMF_31BIT },
56 {0 , 0 , NULL , 0, 0 }
60 * Here the history starts. We are already in flat, 32bit mode. All protections
61 * are off, CPU is working in Supervisor level (CPL0). Interrupts should
62 * be disabled.
64 * Here we run on a stack provided by the bootstrap. We can perform calls, but we
65 * don't know where it is placed, so we need to switch away from it ASAP.
67 IPTR __startup kernel_entry(struct TagItem *bootMsg, ULONG magic)
69 if (magic == AROS_BOOT_MAGIC)
70 core_Kick(bootMsg, kernel_boot);
72 return -1;
76 * The real entry point for initial boot.
77 * Here we initialize debug console and say "hello".
78 * Warm restart skips this since the screen was taken over by display driver.
80 static void kernel_boot(const struct TagItem *msg)
83 * Initial framebuffer mirror will be located by default at (1MB + 4KB).
84 * This is done because our bootstrap begins at 1MB, and its .tables
85 * sections are placed in the beginning. We must not ocassionally overwrite
86 * these sections for now because they contain boot-time data for us
87 * (taglist etc).
88 * A well-behaved bootstrap should give us ProtAreaEnd.
90 fb_Mirror = (void *)LibGetTagData(KRN_ProtAreaEnd, 0x101000, msg);
91 con_InitTagList(msg);
93 bug("AROS - The AROS Research OS. Compiled %s\n",__DATE__);
95 kernel_cstart(msg);
99 * This function actually runs the kickstart from the specified address.
100 * Before doing this it clears .bss sections of all modules.
102 void core_Kick(struct TagItem *msg, void *target)
104 const struct TagItem *bss = LibFindTagItem(KRN_KernelBss, msg);
106 /* First clear .bss */
107 if (bss)
108 __clear_bss((const struct KernelBSS *)bss->ti_Data);
111 * ... then switch to initial stack and jump to target address.
112 * We set ebp to 0 and use call here in order to get correct stack traces
113 * if the boot task crashes. Otherwise backtrace goes beyond this location
114 * into memory areas with undefined contents.
116 asm volatile("movl %1, %%esp \n\t"
117 "movl $0, %%ebp \n\t"
118 "pushl %0 \n\t"
119 "cld \n\t" /* At the startup it's very important */
120 "cli \n\t" /* to lock all interrupts. Both on the */
121 "movb $-1,%%al \n\t" /* CPU side and hardware side. We don't */
122 "outb %%al,$0x21 \n\t" /* have proper structures in RAM yet. */
123 "outb %%al,$0xa1 \n\t"
124 "call *%2\n"
125 ::"r"(msg), "r"(boot_stack + STACK_SIZE), "r"(target));
129 * Our transient data.
130 * They must survive warm restart, so we put them into .data section.
131 * We also have SysBase here, this way we move it away from zero page,
132 * making it harder to trash it.
134 __attribute__((section(".data"))) struct KernBootPrivate *__KernBootPrivate = NULL;
135 __attribute__((section(".data"))) IPTR kick_end = 0;
136 __attribute__((section(".data"))) struct ExecBase *SysBase = NULL;
139 * Static read-only copy of prebuilt GDT.
140 * We only need to patch a TSS segment, after TSS has been allocated.
142 static const struct {UWORD l1, l2, l3, l4;}
143 GDT_Table[] =
145 { 0x0000, 0x0000, 0x0000, 0x0000 },
146 { 0xffff, 0x0000, 0x9a00, 0x00cf },
147 { 0xffff, 0x0000, 0x9200, 0x00cf },
148 { 0xffff, 0x0000, 0xfa00, 0x00cf },
149 { 0xffff, 0x0000, 0xf200, 0x00cf },
150 { 0x0000, 0x0000, 0x0000, 0x0000 },
151 { 0x0067, 0x0000, 0x8900, 0x0000 },
152 { 0x0000, 0x0000, 0x0000, 0x0000 }
156 * This is the main entry point.
157 * We run from here both at first boot and upon reboot.
159 void kernel_cstart(const struct TagItem *msg)
161 struct TagItem *tag;
162 struct mb_mmap *mmap = NULL;
163 unsigned long mmap_len = 0;
164 IPTR kick_start = 0;
165 struct segment_selector gdtr;
166 struct MinList memList;
167 struct MemHeader *mh, *mh2;
168 UWORD *ranges[] = {NULL, NULL, (UWORD *)-1};
169 struct mb_mmap *region;
170 char *cmdline = NULL;
171 ULONG allocator = ALLOCATOR_TLSF;
173 D(bug("[Kernel] Transient kickstart end 0x%p, BootMsg 0x%p\n", kick_end, BootMsg));
174 D(bug("[Kernel] Boot stack: 0x%p - 0x%p\n", boot_stack, boot_stack + STACK_SIZE));
176 /* If __KernBootPrivate is not set, this is our first start. */
177 if (__KernBootPrivate == NULL)
179 struct vbe_mode *vmode = NULL;
181 tag = LibFindTagItem(KRN_KernelHighest, msg);
182 if (!tag)
183 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
184 "Highest kickstart address is not supplied\n");
186 /* Align kickstart top address (we are going to place a structure after it) */
187 BootMemPtr = (void *)AROS_ROUNDUP2(tag->ti_Data + 1, sizeof(APTR));
190 * Our boot taglist is placed by the bootstrap just somewhere in memory.
191 * The first thing is to move it into some safe place.
192 * This function also sets global BootMsg pointer.
194 RelocateBootMsg(msg);
196 /* Now relocate linked data */
197 mmap_len = LibGetTagData(KRN_MMAPLength, 0, BootMsg);
198 msg = BootMsg;
199 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
201 switch (tag->ti_Tag)
203 case KRN_KernelBss:
204 RelocateBSSData(tag);
205 break;
207 case KRN_MMAPAddress:
208 RelocateTagData(tag, mmap_len);
209 break;
211 case KRN_VBEModeInfo:
212 RelocateTagData(tag, sizeof(struct vbe_mode));
213 vmode = (struct vbe_mode *)tag->ti_Data;
214 break;
216 case KRN_VBEControllerInfo:
217 RelocateTagData(tag, sizeof(struct vbe_controller));
218 break;
220 case KRN_CmdLine:
221 RelocateStringData(tag);
222 cmdline = (char *)tag->ti_Data;
223 break;
225 case KRN_BootLoader:
226 RelocateStringData(tag);
227 break;
231 /* Now allocate KernBootPrivate */
232 __KernBootPrivate = krnAllocBootMem(sizeof(struct KernBootPrivate));
234 vesahack_Init(cmdline, vmode);
237 if (!__KernBootPrivate->BOOTGDT)
239 /* Allocate space for GDT */
240 __KernBootPrivate->BOOTGDT = krnAllocBootMemAligned(sizeof(GDT_Table), 128);
243 /* Create global descriptor table */
244 krnCopyMem(GDT_Table, __KernBootPrivate->BOOTGDT, sizeof(GDT_Table));
246 if (!__KernBootPrivate->TSS)
247 __KernBootPrivate->TSS = krnAllocBootMemAligned(sizeof(struct tss), 64);
249 if (!__KernBootPrivate->BOOTIDT)
250 __KernBootPrivate->BOOTIDT = krnAllocBootMemAligned(sizeof(apicidt_t) * 256, 256);
251 else memset(__KernBootPrivate->BOOTIDT, 0, sizeof(apicidt_t) * 256);
253 D(bug("[Kernel] BOOT GDT @ 0x%p, IDT @ 0x%p, TSS @ 0x%p\n", __KernBootPrivate->BOOTGDT, __KernBootPrivate->BOOTIDT, __KernBootPrivate->TSS));
255 if (!kick_end)
258 * Set new kickstart end address.
259 * Kickstart area now includes boot taglist with all its contents.
261 D(bug("[Kernel] Boot-time setup complete\n"));
262 kick_end = AROS_ROUNDUP2((IPTR)BootMemPtr, PAGE_SIZE);
265 D(bug("[Kernel] End of kickstart area 0x%p\n", kick_end));
268 * Obtain the needed data from the boot taglist.
269 * We parse it from scratch here because we come here in both cases
270 * (first boot and reboot)
272 msg = BootMsg;
273 while ((tag = LibNextTagItem((struct TagItem **)&msg)))
275 switch (tag->ti_Tag)
277 case KRN_KernelLowest:
278 kick_start = tag->ti_Data;
279 break;
281 case KRN_MMAPAddress:
282 mmap = (struct mb_mmap *)tag->ti_Data;
283 break;
285 case KRN_MMAPLength:
286 mmap_len = tag->ti_Data;
287 break;
289 case KRN_CmdLine:
290 cmdline = (char *)tag->ti_Data;
291 break;
295 /* Sanity check */
296 if ((!kick_start) || (!mmap) || (!mmap_len))
298 krnPanic(KernelBase, "Incomplete information from the bootstrap\n"
299 "Kickstart address : 0x%P\n"
300 "Memory map address: 0x%P, length %ld\n",
301 kick_start, mmap, mmap_len);
304 if (cmdline && strstr(cmdline, "notlsf"))
305 allocator = ALLOCATOR_STD;
308 * Initial CPU setup. Load the GDT and segment registers.
309 * AROS uses only CS SS DS and ES. FS and GS are set to 0
310 * so we can generate GP if someone uses them.
312 gdtr.size = sizeof(GDT_Table) - 1;
313 gdtr.base = (unsigned long)__KernBootPrivate->BOOTGDT;
316 " lgdt %0\n"
317 " mov %1,%%ds\n"
318 " mov %1,%%es\n"
319 " mov %1,%%ss\n"
320 " mov %2,%%fs\n"
321 " mov %2,%%gs\n"
322 " ljmp %3,$1f\n"
323 "1:\n"
324 ::"m"(gdtr),"r"(KERNEL_DS),"r"(0),"i"(KERNEL_CS)
327 D(bug("[Kernel] GDT reloaded\n"));
330 * Explore memory map and create MemHeaders
331 * 4KB at address 0 are reserved for our needs.
333 NEWLIST(&memList);
334 mmap_InitMemory(mmap, mmap_len, &memList, kick_start, kick_end, 0x00001000, PC_Memory, allocator);
337 * mmap_InitMemory() adds MemHeaders to the list in the order they were created.
338 * I. e. highest addresses are added last.
339 * Take highest region in order to create SysBase in it.
341 mh = (struct MemHeader *)REMTAIL(&memList);
343 D(bug("[Kernel] Initial MemHeader: 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
345 if (SysBase)
348 * Validate SysBase.
349 * Criteria: The pointer should point to a valid memory region.
350 * This is only address validation.
351 * Checksum etc is processed in PrepareExecBase() in exec.library.
353 BOOL sysbase_bad = TRUE;
355 region = mmap_FindRegion((unsigned long)SysBase, mmap, mmap_len);
356 if (region && region->type == MMAP_TYPE_RAM)
358 IPTR end = region->addr + region->len;
360 if ((IPTR)SysBase + sizeof(struct ExecBase) < end)
361 sysbase_bad = FALSE;
364 if (sysbase_bad)
365 SysBase = NULL;
368 ranges[0] = (UWORD *)kick_start;
369 ranges[1] = (UWORD *)kick_end;
370 krnPrepareExecBase(ranges, mh, BootMsg);
372 krnCreateROMHeader("Kickstart ROM", (APTR)kick_start, (APTR)kick_end);
375 * Now we have working exec.library memory allocator.
376 * Move console mirror buffer away from unused memory.
377 * WARNING!!! Do not report anything in the debug log before this is done. Remember that sequential
378 * AllocMem()s return sequential blocks! And right beyond our allocated area there will be MemChunk.
379 * Between krnPrepareExecBase() and this AllocMem() upon warm reboot console mirror buffer is set
380 * to an old value right above ExecBase. During krnPrepareExecBase() a MemChunk is built there,
381 * which can be overwritten by bootconsole, especially if the output scrolls.
383 if (scr_Type == SCR_GFX)
385 char *mirror = AllocMem(scr_Width * scr_Height, MEMF_PUBLIC);
387 fb_SetMirror(mirror);
390 D(bug("[Kernel] Created SysBase at 0x%p, MemHeader 0x%p\n", SysBase, mh));
392 /* Transfer the rest of memory list into SysBase */
393 D(bug("[Kernel] Transferring memory list into SysBase...\n"));
394 for (mh = (struct MemHeader *)memList.mlh_Head; mh->mh_Node.ln_Succ; mh = mh2)
396 mh2 = (struct MemHeader *)mh->mh_Node.ln_Succ;
398 D(bug("[Kernel] * 0x%p - 0x%p (%s)\n", mh->mh_Lower, mh->mh_Upper, mh->mh_Node.ln_Name));
399 Enqueue(&SysBase->MemList, &mh->mh_Node);
403 * Now we can initialize SINGLETASK residents.
404 * This includes kernel.resource itself. Its platform-specific code
405 * will initialize the rest of hardware.
407 InitCode(RTF_SINGLETASK, 0);
410 * After RTF_SINGLETASK we can have various interesting things like ACPI.
411 * Secondary platform initialization code makes use of them.
413 PlatformPostInit();
415 krnLeaveSupervisorRing(FLAGS_INTENABLED);
417 InitCode(RTF_COLDSTART, 0);
419 krnPanic(KernelBase, "Failed to start up the system");
422 /* Our boot-time stack. Safe to be in .bss. */
423 static char boot_stack[STACK_SIZE] __attribute__((aligned(16)));