1 #include <aros/multiboot.h>
4 #include <aros/symbolsets.h>
5 #include <exec/lists.h>
6 #include <exec/memory.h>
7 #include <exec/resident.h>
8 #include <utility/tagitem.h>
9 #include <proto/arossupport.h>
10 #include <proto/exec.h>
12 #include <bootconsole.h>
16 #include "boot_utils.h"
17 #include "kernel_base.h"
18 #include "kernel_bootmem.h"
19 #include "kernel_debug.h"
20 #include "kernel_intern.h"
21 #include "kernel_mmap.h"
22 #include "kernel_romtags.h"
30 /* Common IBM PC memory layout */
31 static const struct MemRegion PC_Memory
[] =
34 * Give low memory a bit lower priority. This will help us to locate its MemHeader (the last one in the list).
35 * We explicitly need low memory for SMP bootstrap.
37 {0x000000000, 0x000100000, "Low memory" , -6, MEMF_PUBLIC
|MEMF_LOCAL
|MEMF_KICK
|MEMF_CHIP
|MEMF_31BIT
|MEMF_24BITDMA
},
38 {0x000100000, 0x001000000, "ISA DMA memory", -5, MEMF_PUBLIC
|MEMF_LOCAL
|MEMF_KICK
|MEMF_CHIP
|MEMF_31BIT
|MEMF_24BITDMA
},
40 * FIXME: The following two entries should also be CHIP. trackdisk.device and i386 port
41 * fix is needed (use MEMF_24BITDMA instead of MEMF_CHIP for 24-bit ISA DMA-capable area.
43 * 1. Some (or all?) 64-bit machines expose RAM at addresses up to 0xD0000000 (giving 3.5 GB total). All MMIO
44 * sits beyond this border. We intentionally specify 4GB as limit, just in case if some machine exhibits
45 * even more RAM in this space. We want all the RAM to be usable.
46 * 2. We have MEMF_31BIT originating from MorphOS. But here we interpret it as "32-bit memory". I guess
47 * it originated from the assumption that MMIO starts at 0x80000000 (which is true at least for PegasosPPC).
48 * So, is it okay to assume actually 32-bit memory for MEMF_31BIT? Are there anything which really imposes
49 * 31-bit limit? AllocEntry() issue doesn't count...
51 {0x001000000, 0x0FFFFFFFF, "32-bit memory" , 0, MEMF_PUBLIC
|MEMF_LOCAL
|MEMF_KICK
|MEMF_FAST
|MEMF_31BIT
},
53 * FIXME: Our MMU mapping supports only 4GB address space.
54 * We can't enable more right now because lots of RAM would be required for MMU tables,
55 * and it will be irrational to reserve so large boot-time region (AROS will fail to boot
56 * up on systems with relatively small amount of RAM).
57 * MMU structures need to be allocated dynamically from a working memory. Waiting for Michal's
58 * page allocator to implement this...
59 {0x080000000, -1 , "Upper memory" , 10, MEMF_PUBLIC|MEMF_LOCAL|MEMF_KICK|MEMF_FAST }, */
60 {0 , 0 , NULL
, 0, 0 }
64 * Boot-time global variables.
65 * __KernBootPrivate needs to survive accross warm reboots, so it's put into .data.
66 * SysBase is intentionally put into .rodata. This way we prevent it from being modified.
68 __attribute__((section(".data"))) struct KernBootPrivate
*__KernBootPrivate
= NULL
;
69 __attribute__((section(".data"))) IPTR kick_highest
= 0;
70 __attribute__((section(".rodata"))) struct ExecBase
*SysBase
= NULL
;
72 static void boot_start(struct TagItem
*msg
);
73 static char boot_stack
[];
76 * This is where our kernel started.
77 * First we clear BSS section, then switch stack pointer to our temporary stack
78 * (which is itself located in BSS). While we are here, the stack is actually
79 * located inside our bootstrap, and it's safe to use it a little bit.
81 IPTR __startup
start64(struct TagItem
*msg
, ULONG magic
)
83 /* Anti-command-line-run protector */
84 if (magic
== AROS_BOOT_MAGIC
)
86 /* Run the kickstart from boot_start() routine. */
87 core_Kick(msg
, boot_start
);
94 * This code is executed only once, after the kickstart is loaded by bootstrap.
95 * Its main job is to initialize early debugging console ASAP in order to be able
96 * to see what happens. This will deal with both serial and on-screen console.
98 * Console mirror is placed at the end of bootstrap's protected area. We must not
99 * overwrite it because it contains boot-time GDT, taglist, and some other structures.
101 * Default address is bootstrap start + 4KB, just in case.
103 static void boot_start(struct TagItem
*msg
)
105 fb_Mirror
= (void *)LibGetTagData(KRN_ProtAreaEnd
, 0x101000, msg
);
106 con_InitTagList(msg
);
108 bug("AROS64 - The AROS Research OS, 64-bit version. Compiled %s\n", __DATE__
);
109 D(bug("[Kernel] boot_start: Jumped into kernel.resource @ %p [stub @ %p].\n", boot_start
, start64
));
115 * This routine actually launches the kickstart. It's called either upon first start or upon warm reboot.
116 * The only assumption is that stack is outside .bss . For both cases this is true:
117 * 1. First boot - the stack is located inside the bootstrap.
118 * 2. Warm reboot - the stack is located in supervisor area (__KernBootPrivate->SystemStack).
120 void core_Kick(struct TagItem
*msg
, void *target
)
122 const struct TagItem
*bss
= LibFindTagItem(KRN_KernelBss
, msg
);
124 /* First clear .bss */
126 __clear_bss((const struct KernelBSS
*)bss
->ti_Data
);
129 * ... then switch to initial stack and jump to target address.
130 * We set rbp to 0 and use call here in order to get correct stack traces
131 * if the boot task crashes. Otherwise backtrace goes beyond this location
132 * into memory areas with undefined contents.
134 asm volatile("movq %1, %%rsp\n\t"
136 "call *%2\n"::"D"(msg
), "r"(boot_stack
+ STACK_SIZE
), "r"(target
));
140 * This is the main entry point.
141 * We run from here both at first boot and upon reboot.
143 void kernel_cstart(const struct TagItem
*start_msg
)
145 struct MinList memList
;
146 struct TagItem
*msg
= (struct TagItem
*)start_msg
;
147 struct MemHeader
*mh
, *mh2
;
148 struct mb_mmap
*mmap
= NULL
;
154 UWORD
*ranges
[] = {NULL
, NULL
, (UWORD
*)-1};
156 /* Enable fxsave/fxrstor */
157 wrcr(cr4
, rdcr(cr4
) | _CR4_OSFXSR
| _CR4_OSXMMEXCPT
);
159 D(bug("[Kernel] Boot data: 0x%p\n", __KernBootPrivate
));
160 DSTACK(bug("[Kernel] Boot stack: 0x%p - 0x%p\n", boot_stack
, boot_stack
+ STACK_SIZE
));
162 if (__KernBootPrivate
== NULL
)
164 /* This is our first start. */
165 struct vbe_mode
*vmode
= NULL
;
166 char *cmdline
= NULL
;
169 /* We need highest KS address and memory map to begin the work */
170 khi
= LibGetTagData(KRN_KernelHighest
, 0, msg
);
171 mmap
= (struct mb_mmap
*)LibGetTagData(KRN_MMAPAddress
, 0, msg
);
172 mmap_len
= LibGetTagData(KRN_MMAPLength
, 0, msg
);
174 if ((!khi
) || (!mmap
) || (!mmap_len
))
176 krnPanic(NULL
, "Incomplete information from the bootstrap\n"
178 "Kickstart top: 0x%p\n"
179 "Memory map: address 0x%p, length %lu\n", khi
, mmap
, mmap
, mmap_len
);
183 * Our boot taglist is located just somewhere in memory. Additionally, it's very fragmented
184 * (its linked data, like VBE information, were also placed just somewhere, by GRUB.
185 * Now we need some memory to gather these things together. This memory will be preserved
186 * accross warm restarts.
187 * We know the bootstrap has reserved some space right beyond the kickstart. We get our highest
188 * address, and use memory map to locate topmost address of this area.
190 khi
= AROS_ROUNDUP2(khi
+ 1, sizeof(APTR
));
191 mmap
= mmap_FindRegion(khi
, mmap
, mmap_len
);
195 krnPanic(NULL
, "Inconsistent memory map or kickstart placement\n"
196 "Kickstart region not found");
199 if (mmap
->type
!= MMAP_TYPE_RAM
)
201 krnPanic(NULL
, "Inconsistent memory map or kickstart placement\n"
202 "Reserved memory overwritten\n"
203 "Region 0x%p - 0x%p type %d\n"
204 "Kickstart top 0x%p", mmap
->addr
, mmap
->addr
+ mmap
->len
- 1, mmap
->type
, khi
);
207 /* Initialize boot-time memory allocator */
208 BootMemPtr
= (void *)khi
;
209 BootMemLimit
= (void *)mmap
->addr
+ mmap
->len
;
211 D(bug("[Kernel] Bootinfo storage 0x%p - 0x%p\n", BootMemPtr
, BootMemLimit
));
214 * Our boot taglist is placed by the bootstrap just somewhere in memory.
215 * The first thing is to move it into some safe place.
218 /* This will relocate the taglist itself */
219 RelocateBootMsg(msg
);
222 * Now relocate linked data.
223 * Here we actually process only tags we know about and expect to get.
224 * For example, we are not going to receive KRN_HostInterface or KRN_OpenfirmwareTree.
227 while ((tag
= LibNextTagItem(&msg
)))
232 RelocateBSSData(tag
);
235 case KRN_MMAPAddress
:
236 RelocateTagData(tag
, mmap_len
);
239 case KRN_VBEModeInfo
:
240 RelocateTagData(tag
, sizeof(struct vbe_mode
));
241 vmode
= (struct vbe_mode
*)tag
->ti_Data
;
244 case KRN_VBEControllerInfo
:
245 RelocateTagData(tag
, sizeof(struct vbe_controller
));
249 RelocateStringData(tag
);
250 cmdline
= (char *)tag
->ti_Data
;
254 RelocateStringData(tag
);
259 /* Now allocate KernBootPrivate */
260 __KernBootPrivate
= krnAllocBootMem(sizeof(struct KernBootPrivate
));
262 if (cmdline
&& vmode
&& vmode
->phys_base
&& strstr(cmdline
, "vesahack"))
264 bug("[Kernel] VESA debugging hack activated\n");
268 * It divides screen height by 2 and increments framebuffer pointer.
269 * This allows VESA driver to use only upper half of the screen, while
270 * lower half will still be used for debug output.
272 vmode
->y_resolution
>>= 1;
274 __KernBootPrivate
->debug_y_resolution
= vmode
->y_resolution
;
275 __KernBootPrivate
->debug_framebuffer
= (void *)(unsigned long)vmode
->phys_base
+ vmode
->y_resolution
* vmode
->bytes_per_scanline
;
280 core_SetupGDT(__KernBootPrivate
);
282 if (!__KernBootPrivate
->SystemStack
)
285 * Allocate our supervisor stack from boot-time memory.
286 * It will be protected from user's intervention.
287 * Allocate actually three stacks: panic, supervisor, ring1.
288 * Note that we do the actual allocation only once. The region is kept
289 * in __KernBootPrivate which survives warm reboots.
291 __KernBootPrivate
->SystemStack
= (IPTR
)krnAllocBootMem(STACK_SIZE
* 3);
293 DSTACK(bug("[Kernel] Allocated supervisor stack 0x%p - 0x%p\n",
294 __KernBootPrivate
->SystemStack
, __KernBootPrivate
->SystemStack
+ STACK_SIZE
* 3));
297 /* We are x86-64, and we know we always have APIC. */
298 __KernBootPrivate
->_APICBase
= core_APIC_GetBase();
299 _APICID
= core_APIC_GetID(__KernBootPrivate
->_APICBase
);
300 D(bug("[Kernel] kernel_cstart: launching on BSP APIC ID %d, base @ %p\n", _APICID
, __KernBootPrivate
->_APICBase
));
302 /* Set TSS, GDT, LDT and MMU up */
303 core_CPUSetup(_APICID
, __KernBootPrivate
->SystemStack
);
304 core_SetupIDT(__KernBootPrivate
);
305 core_SetupMMU(__KernBootPrivate
);
308 * Here we ended all boot-time allocations.
309 * We won't do them again, for example on warm reboot. All our areas are stored in struct KernBootPrivate.
310 * We are going to make this area read-only and reset-proof.
314 D(bug("[Kernel] Boot-time setup complete\n"));
315 kick_highest
= AROS_ROUNDUP2((IPTR
)BootMemPtr
, PAGE_SIZE
);
318 D(bug("[Kernel] End of kickstart area 0x%p\n", kick_highest
));
321 * Obtain the needed data from the boot taglist.
322 * We need to do this even on first boot, because the taglist and its data
323 * have been moved to the permanent storage.
326 while ((tag
= LibNextTagItem(&msg
)))
332 * KRN_KernelBase is actually a border between read-only
333 * (code) and read-write (data) sections of the kickstart.
334 * read-write section goes to lower addresses from this one,
335 * so we align it upwards in order not to make part of RW data
338 addr
= AROS_ROUNDUP2(tag
->ti_Data
, PAGE_SIZE
);
341 case KRN_KernelLowest
:
342 klo
= AROS_ROUNDDOWN2(tag
->ti_Data
, PAGE_SIZE
);
345 case KRN_MMAPAddress
:
346 mmap
= (struct mb_mmap
*)tag
->ti_Data
;
350 mmap_len
= tag
->ti_Data
;
356 if ((!klo
) || (!addr
))
358 krnPanic(NULL
, "Incomplete information from the bootstrap\n"
360 "Kickstart lowest 0x%p, base 0x%p\n", klo
, addr
);
364 * Explore memory map and create MemHeaders.
365 * We reserve one page (PAGE_SIZE) at zero address. We will protect it.
368 mmap_InitMemory(mmap
, mmap_len
, &memList
, klo
, kick_highest
, PAGE_SIZE
, PC_Memory
);
370 D(bug("[Kernel] kernel_cstart: Booting exec.library...\n"));
373 * mmap_InitMemory() adds MemHeaders to the list in the order they were created.
374 * I. e. highest addresses are added last.
375 * Take highest region in order to create SysBase in it.
377 mh
= (struct MemHeader
*)REMTAIL(&memList
);
378 D(bug("[Kernel] Initial MemHeader: 0x%p - 0x%p (%s)\n", mh
->mh_Lower
, mh
->mh_Upper
, mh
->mh_Node
.ln_Name
));
382 D(bug("[Kernel] Got old SysBase 0x%p...\n", SysBase
));
384 * Validate existing SysBase pointer.
385 * Here we check that if refers to a valid existing memory region.
386 * Checksums etc are checked in arch-independent code in exec.library.
387 * It's enough to use only size of public part. Anyway, SysBase will be
388 * reallocated by PrepareExecBase(), it will just keep over some data from
389 * public part (KickMemPtr, KickTagPtr and capture vectors).
391 if (!mmap_ValidateRegion((unsigned long)SysBase
, sizeof(struct ExecBase
), mmap
, mmap_len
))
393 D(bug("[Kernel] ... invalidated\n"));
398 /* This handles failures itself */
399 ranges
[0] = (UWORD
*)klo
;
400 ranges
[1] = (UWORD
*)kick_highest
;
401 krnPrepareExecBase(ranges
, mh
, BootMsg
);
404 * Now we have working exec.library memory allocator.
405 * Move console mirror buffer away from unused memory.
406 * WARNING!!! Do not report anything in the debug log before this is done. Remember that sequental
407 * AllocMem()s return sequental blocks! And right beyond our allocated area there will be MemChunk.
408 * Between krnPrepareExecBase() and this AllocMem() upon warm reboot console mirror buffer is set
409 * to an old value right above ExecBase. During krnPrepareExecBase() a MemChunk is built there,
410 * which can be overwritten by bootconsole, especially if the output scrolls.
412 if (scr_Type
== SCR_GFX
)
414 char *mirror
= AllocMem(scr_Width
* scr_Height
, MEMF_PUBLIC
);
416 fb_SetMirror(mirror
);
419 D(bug("[Kernel] Created SysBase at 0x%p (pointer at 0x%p), MemHeader 0x%p\n", SysBase
, &SysBase
, mh
));
421 /* Block all user's access to zero page */
422 core_ProtKernelArea(0, PAGE_SIZE
, 1, 0, 0);
424 /* Store important private data */
425 TLS_SET(SysBase
, SysBase
);
427 /* Provide information about our supevisor stack. Useful at least for diagnostics. */
428 SysBase
->SysStkLower
= (APTR
)__KernBootPrivate
->SystemStack
;
429 SysBase
->SysStkUpper
= (APTR
)__KernBootPrivate
->SystemStack
+ STACK_SIZE
* 3;
432 * Make kickstart code area read-only.
433 * We do it only after ExecBase creation because SysBase pointer is put
434 * into .rodata. This way we prevent it from ocassional modification by buggy software.
436 core_ProtKernelArea(addr
, kick_highest
- addr
, 1, 0, 1);
438 /* Transfer the rest of memory list into SysBase */
439 D(bug("[Kernel] Transferring memory list into SysBase...\n"));
440 for (mh
= (struct MemHeader
*)memList
.mlh_Head
; mh
->mh_Node
.ln_Succ
; mh
= mh2
)
442 mh2
= (struct MemHeader
*)mh
->mh_Node
.ln_Succ
;
444 D(bug("[Kernel] * 0x%p - 0x%p (%s)\n", mh
->mh_Lower
, mh
->mh_Upper
, mh
->mh_Node
.ln_Name
));
445 Enqueue(&SysBase
->MemList
, &mh
->mh_Node
);
449 * RTF_SINGLETASK residents are called with supervisor privilege level.
450 * Original AmigaOS(tm) does the same, some Amiga hardware expansion ROM
451 * rely on it. Here we continue the tradition, because it's useful for
452 * acpi.resource (which needs to look for RSDP in zero page).
454 InitCode(RTF_SINGLETASK
, 0);
457 * After InitCode(RTF_SINGLETASK) we may have acpi.resource.
458 * Now we can use ACPI information in order to set up advanced things (SMP, APIC, etc).
459 * Interrupts are still disabled and we are still supervisor.
463 /* Now initialize our interrupt controller (XT-PIC or APIC) */
466 /* The last thing to do is to start up secondary CPU cores (if any) */
469 /* Drop privileges down to user mode before calling RTF_COLDSTART */
470 D(bug("[Kernel] Leaving supervisor mode\n"));
472 "mov %[user_ds],%%ds\n\t" // Load DS and ES
473 "mov %[user_ds],%%es\n\t"
474 "mov %%rsp,%%r12\n\t"
475 "pushq %[ds]\n\t" // SS
476 "pushq %%r12\n\t" // rSP
477 "pushq $0x3002\n\t" // rFLAGS
478 "pushq %[cs]\n\t" // CS
481 ::[user_ds
]"r"(USER_DS
),[ds
]"i"(USER_DS
),[cs
]"i"(USER_CS
):"r12");
483 D(bug("[Kernel] Done?! Still here?\n"));
486 * We are fully done. Run exec.library and the rest.
487 * exec.library will be the first resident to run. It will enable interrupts and multitasking for us.
489 InitCode(RTF_COLDSTART
, 0);
491 /* The above must not return */
492 krnPanic(KernelBase
, "System Boot Failed!");
495 /* Small delay routine used by exec_cinit initializer */
496 asm("\ndelay:\t.short 0x00eb\n\tretq");
498 /* Our boot-time stack */
499 static char boot_stack
[STACK_SIZE
] __attribute__((aligned(16)));
503 struct segment_desc seg0
; /* seg 0x00 */
504 struct segment_desc super_cs
; /* seg 0x08 */
505 struct segment_desc super_ds
; /* seg 0x10 */
506 struct segment_desc user_cs32
; /* seg 0x18 */
507 struct segment_desc user_ds
; /* seg 0x20 */
508 struct segment_desc user_cs
; /* seg 0x28 */
509 struct segment_desc gs
; /* seg 0x30 */
510 struct segment_desc ldt
; /* seg 0x38 */
513 struct segment_desc tss_low
; /* seg 0x40... */
514 struct segment_ext tss_high
;
518 void core_SetupGDT(struct KernBootPrivate
*__KernBootPrivate
)
520 struct gdt_64bit
*GDT
;
521 struct tss_64bit
*TSS
;
525 D(bug("[Kernel] core_SetupGDT(0x%p)\n", __KernBootPrivate
));
527 if (!__KernBootPrivate
->GDT
)
529 __KernBootPrivate
->system_tls
= krnAllocBootMem(sizeof(tls_t
));
530 __KernBootPrivate
->GDT
= krnAllocBootMemAligned(sizeof(struct gdt_64bit
), 128);
531 __KernBootPrivate
->TSS
= krnAllocBootMemAligned(sizeof(struct tss_64bit
) * 16, 128);
533 D(bug("[Kernel] Allocated GDT 0x%p, TLS 0x%p\n", __KernBootPrivate
->GDT
, __KernBootPrivate
->system_tls
));
536 GDT
= __KernBootPrivate
->GDT
;
537 TSS
= __KernBootPrivate
->TSS
;
539 /* Supervisor segments */
540 GDT
->super_cs
.type
=0x1a; /* code segment */
541 GDT
->super_cs
.dpl
=0; /* supervisor level */
542 GDT
->super_cs
.p
=1; /* present */
543 GDT
->super_cs
.l
=1; /* long (64-bit) one */
544 GDT
->super_cs
.d
=0; /* must be zero */
545 GDT
->super_cs
.limit_low
=0xffff;
546 GDT
->super_cs
.limit_high
=0xf;
549 GDT
->super_ds
.type
=0x12; /* data segment */
550 GDT
->super_ds
.dpl
=0; /* supervisor level */
551 GDT
->super_ds
.p
=1; /* present */
552 GDT
->super_ds
.limit_low
=0xffff;
553 GDT
->super_ds
.limit_high
=0xf;
557 /* User mode segments */
558 GDT
->user_cs
.type
=0x1a; /* code segment */
559 GDT
->user_cs
.dpl
=3; /* User level */
560 GDT
->user_cs
.p
=1; /* present */
561 GDT
->user_cs
.l
=1; /* long mode */
562 GDT
->user_cs
.d
=0; /* must be zero */
563 GDT
->user_cs
.limit_low
=0xffff;
564 GDT
->user_cs
.limit_high
=0xf;
567 GDT
->user_cs32
.type
=0x1a; /* code segment for legacy 32-bit code. NOT USED YET! */
568 GDT
->user_cs32
.dpl
=3; /* user level */
569 GDT
->user_cs32
.p
=1; /* present */
570 GDT
->user_cs32
.l
=0; /* 32-bit mode */
571 GDT
->user_cs32
.d
=1; /* 32-bit code */
572 GDT
->user_cs32
.limit_low
=0xffff;
573 GDT
->user_cs32
.limit_high
=0xf;
576 GDT
->user_ds
.type
=0x12; /* data segment */
577 GDT
->user_ds
.dpl
=3; /* user level */
578 GDT
->user_ds
.p
=1; /* present */
579 GDT
->user_ds
.limit_low
=0xffff;
580 GDT
->user_ds
.limit_high
=0xf;
584 for (i
=0; i
< 16; i
++)
586 const unsigned long tss_limit
= sizeof(struct tss_64bit
) * 16 - 1;
588 /* Task State Segment */
589 GDT
->tss
[i
].tss_low
.type
= 0x09; /* 64-bit TSS */
590 GDT
->tss
[i
].tss_low
.limit_low
= tss_limit
;
591 GDT
->tss
[i
].tss_low
.base_low
= ((unsigned long)&TSS
[i
]) & 0xffff;
592 GDT
->tss
[i
].tss_low
.base_mid
= (((unsigned long)&TSS
[i
]) >> 16) & 0xff;
593 GDT
->tss
[i
].tss_low
.dpl
= 3; /* User mode task */
594 GDT
->tss
[i
].tss_low
.p
= 1; /* present */
595 GDT
->tss
[i
].tss_low
.limit_high
= (tss_limit
>> 16) & 0x0f;
596 GDT
->tss
[i
].tss_low
.base_high
= (((unsigned long)&TSS
[i
]) >> 24) & 0xff;
597 GDT
->tss
[i
].tss_high
.base_ext
= 0; /* is within 4GB :-D */
600 tls_ptr
= (intptr_t)__KernBootPrivate
->system_tls
;
602 GDT
->gs
.type
=0x12; /* data segment */
603 GDT
->gs
.dpl
=3; /* user level */
604 GDT
->gs
.p
=1; /* present */
605 GDT
->gs
.base_low
= tls_ptr
& 0xffff;
606 GDT
->gs
.base_mid
= (tls_ptr
>> 16) & 0xff;
607 GDT
->gs
.base_high
= (tls_ptr
>> 24) & 0xff;
612 void core_CPUSetup(UBYTE _APICID
, IPTR SystemStack
)
614 struct segment_selector GDT_sel
;
615 struct tss_64bit
*TSS
= __KernBootPrivate
->TSS
;
617 D(bug("[Kernel] core_CPUSetup(%d, 0x%p)\n", _APICID
, SystemStack
));
620 * At the moment two of three stacks are reserved. IST is not used (indexes == 0 in interrupt gates)
621 * and ring 1 is not used either. However, the space pointed to by IST is used as a temporary stack
622 * for warm restart routine.
625 TSS
[_APICID
].ist1
= SystemStack
+ STACK_SIZE
- 16; /* Interrupt stack entry 1 (failsafe) */
626 TSS
[_APICID
].rsp0
= SystemStack
+ STACK_SIZE
* 2 - 16; /* Ring 0 (Supervisor) */
627 TSS
[_APICID
].rsp1
= SystemStack
+ STACK_SIZE
* 3 - 16; /* Ring 1 (reserved) */
629 D(bug("[Kernel] core_CPUSetup[%d]: Reloading the GDT and Task Register\n", _APICID
));
631 GDT_sel
.size
= sizeof(struct gdt_64bit
) - 1;
632 GDT_sel
.base
= (uint64_t)__KernBootPrivate
->GDT
;
633 asm volatile ("lgdt %0"::"m"(GDT_sel
));
634 asm volatile ("ltr %w0"::"r"(TASK_SEG
+ (_APICID
<< 4)));
635 asm volatile ("mov %0,%%gs"::"a"(USER_GS
));