2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Desc: i386-pc kernel startup code
9 #include <aros/kernel.h>
10 #include <aros/multiboot.h>
12 #include <exec/resident.h>
13 #include <proto/arossupport.h>
14 #include <proto/exec.h>
16 #include <bootconsole.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"
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
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
);
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
64 * A well-behaved bootstrap should give us ProtAreaEnd.
66 fb_Mirror
= (void *)LibGetTagData(KRN_ProtAreaEnd
, 0x101000, msg
);
69 bug("AROS - The AROS Research OS. Compiled %s\n",__DATE__
);
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 */
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"
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
;}
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
)
156 struct mb_mmap
*mmap
= NULL
;
157 unsigned long mmap_len
= 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
));
172 struct vbe_mode
*vmode
= NULL
;
174 /* If kick_end is not set, this is our first start. */
175 tag
= LibFindTagItem(KRN_KernelHighest
, msg
);
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
);
193 while ((tag
= LibNextTagItem((struct TagItem
**)&msg
)))
198 RelocateBSSData(tag
);
201 case KRN_MMAPAddress
:
202 RelocateTagData(tag
, mmap_len
);
205 case KRN_VBEModeInfo
:
206 RelocateTagData(tag
, sizeof(struct vbe_mode
));
207 vmode
= (struct vbe_mode
*)tag
->ti_Data
;
210 case KRN_VBEControllerInfo
:
211 RelocateTagData(tag
, sizeof(struct vbe_controller
));
215 RelocateStringData(tag
);
216 cmdline
= (char *)tag
->ti_Data
;
220 RelocateStringData(tag
);
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)
244 while ((tag
= LibNextTagItem((struct TagItem
**)&msg
)))
248 case KRN_KernelLowest
:
249 kick_start
= tag
->ti_Data
;
252 case KRN_MMAPAddress
:
253 mmap
= (struct mb_mmap
*)tag
->ti_Data
;
257 mmap_len
= tag
->ti_Data
;
261 cmdline
= (char *)tag
->ti_Data
;
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
;
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.
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
));
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
)
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.
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 */
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)));