1/* 2 * Copyright (c) 2010-2015 Wind River Systems, Inc. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6/** 7 * @file 8 * @brief Crt0 module for the IA-32 boards 9 * 10 * This module contains the initial code executed by the Zephyr Kernel ELF image 11 * after having been loaded into RAM. 12 * 13 * Note that most addresses (functions and variables) must be in physical 14 * address space. Depending on page table setup, they may or may not be 15 * available in virtual address space after loading of page table. 16 */ 17 18#include <zephyr/arch/x86/ia32/asm.h> 19#include <zephyr/arch/x86/msr.h> 20#include <kernel_arch_data.h> 21#include <zephyr/arch/cpu.h> 22#include <zephyr/arch/x86/multiboot.h> 23#include <x86_mmu.h> 24#include <zephyr/kernel/mm.h> 25 26 /* exports (private APIs) */ 27 28 GTEXT(__start) 29 30 /* externs */ 31 GTEXT(z_prep_c) 32 GTEXT(z_bss_zero) 33 GTEXT(z_data_copy) 34 35 GDATA(_idt_base_address) 36 GDATA(z_interrupt_stacks) 37 GDATA(z_x86_idt) 38#ifndef CONFIG_GDT_DYNAMIC 39 GDATA(_gdt) 40#endif 41 42 43#if defined(CONFIG_X86_SSE) 44 GDATA(_sse_mxcsr_default_value) 45#endif 46 47#if defined(CONFIG_THREAD_LOCAL_STORAGE) 48 GTEXT(z_x86_early_tls_update_gdt) 49#endif 50 51 GDATA(x86_cpu_boot_arg) 52 53.macro install_page_tables 54#ifdef CONFIG_X86_MMU 55 /* Enable paging. If virtual memory is enabled, the instruction pointer 56 * is currently at a physical address. There is an identity mapping 57 * for all RAM, plus a virtual mapping of RAM starting at 58 * CONFIG_KERNEL_VM_BASE using the same paging structures. 59 * 60 * Until we enable these page tables, only physical memory addresses 61 * work. 62 */ 63 movl $Z_MEM_PHYS_ADDR(z_x86_kernel_ptables), %eax 64 movl %eax, %cr3 65 66#ifdef CONFIG_X86_PAE 67 /* Enable PAE */ 68 movl %cr4, %eax 69 orl $CR4_PAE, %eax 70 movl %eax, %cr4 71 72 /* IA32_EFER NXE bit set */ 73 movl $0xC0000080, %ecx 74 rdmsr 75 orl $0x800, %eax 76 wrmsr 77#else 78 /* Enable Page Size Extensions (allowing 4MB pages). 79 * This is ignored if PAE is enabled so no need to do 80 * this above in PAE code. 81 */ 82 movl %cr4, %eax 83 orl $CR4_PSE, %eax 84 movl %eax, %cr4 85#endif /* CONFIG_X86_PAE */ 86 87 /* Enable paging (CR0.PG, bit 31) / write protect (CR0.WP, bit 16) */ 88 movl %cr0, %eax 89 orl $(CR0_PG | CR0_WP), %eax 90 movl %eax, %cr0 91 92#ifdef Z_VM_KERNEL 93 /* Jump to a virtual address, which works because the identity and 94 * virtual mappings both are to the same physical address. 95 */ 96 ljmp $CODE_SEG, $vm_enter 97vm_enter: 98 /* We are now executing in virtual memory. We'll un-map the identity 99 * mappings later once we are in the C domain 100 */ 101#endif /* Z_VM_KERNEL */ 102 103#endif /* CONFIG_X86_MMU */ 104.endm 105 106SECTION_FUNC(BOOT_TEXT, __start) 107 108#include "../common.S" 109 110 /* Enable write-back caching by clearing the NW and CD bits */ 111 movl %cr0, %eax 112 andl $0x9fffffff, %eax 113 movl %eax, %cr0 114 115 /* 116 * Ensure interrupts are disabled. Interrupts are enabled when 117 * the first context switch occurs. 118 */ 119 120 cli 121 122 /* 123 * Although the bootloader sets up an Interrupt Descriptor Table (IDT) 124 * and a Global Descriptor Table (GDT), the specification encourages 125 * booted operating systems to setup their own IDT and GDT. 126 */ 127#if CONFIG_SET_GDT 128 /* load 32-bit operand size GDT */ 129 lgdt Z_MEM_PHYS_ADDR(_gdt_rom) 130 131 /* If we set our own GDT, update the segment registers as well. 132 */ 133 movw $DATA_SEG, %ax /* data segment selector (entry = 3) */ 134 movw %ax, %ds /* set DS */ 135 movw %ax, %es /* set ES */ 136 movw %ax, %ss /* set SS */ 137 xorw %ax, %ax /* AX = 0 */ 138 movw %ax, %fs /* Zero FS */ 139 movw %ax, %gs /* Zero GS */ 140 141 ljmp $CODE_SEG, $Z_MEM_PHYS_ADDR(__csSet) /* set CS = 0x08 */ 142 143__csSet: 144#endif /* CONFIG_SET_GDT */ 145 146#if !defined(CONFIG_FPU) 147 /* 148 * Force an #NM exception for floating point instructions 149 * since FP support hasn't been configured 150 */ 151 152 movl %cr0, %eax /* move CR0 to EAX */ 153 orl $0x2e, %eax /* CR0[NE+TS+EM+MP]=1 */ 154 movl %eax, %cr0 /* move EAX to CR0 */ 155#else 156 /* 157 * Permit use of x87 FPU instructions 158 * 159 * Note that all floating point exceptions are masked by default, 160 * and that _no_ handler for x87 FPU exceptions (#MF) is provided. 161 */ 162 163 movl %cr0, %eax /* move CR0 to EAX */ 164 orl $0x22, %eax /* CR0[NE+MP]=1 */ 165 andl $~0xc, %eax /* CR0[TS+EM]=0 */ 166 movl %eax, %cr0 /* move EAX to CR0 */ 167 168 fninit /* set x87 FPU to its default state */ 169 170 #if defined(CONFIG_X86_SSE) 171 /* 172 * Permit use of SSE instructions 173 * 174 * Note that all SSE exceptions are masked by default, 175 * and that _no_ handler for SSE exceptions (#XM) is provided. 176 */ 177 178 movl %cr4, %eax /* move CR4 to EAX */ 179 orl $0x200, %eax /* CR4[OSFXSR] = 1 */ 180 andl $~0x400, %eax /* CR4[OSXMMEXCPT] = 0 */ 181 movl %eax, %cr4 /* move EAX to CR4 */ 182 183 ldmxcsr Z_MEM_PHYS_ADDR(_sse_mxcsr_default_value) /* initialize SSE control/status reg */ 184 185 #endif /* CONFIG_X86_SSE */ 186 187#endif /* !CONFIG_FPU */ 188 189 /* 190 * Set the stack pointer to the area used for the interrupt stack. 191 * Note this stack is used during the execution of __start() and 192 * z_cstart() until the multi-tasking kernel is initialized. The 193 * dual-purposing of this area of memory is safe since 194 * interrupts are disabled until the first context switch. 195 * 196 * kernel/init.c enforces that the z_interrupt_stacks pointer and 197 * the ISR stack size are some multiple of ARCH_STACK_PTR_ALIGN, which 198 * is at least 4. 199 */ 200#ifdef CONFIG_INIT_STACKS 201 movl $0xAAAAAAAA, %eax 202 leal Z_MEM_PHYS_ADDR(z_interrupt_stacks), %edi 203#ifdef CONFIG_X86_STACK_PROTECTION 204 addl $4096, %edi 205#endif 206 stack_size_dwords = (CONFIG_ISR_STACK_SIZE / 4) 207 movl $stack_size_dwords, %ecx 208 rep stosl 209#endif 210 211 movl $Z_MEM_PHYS_ADDR(z_interrupt_stacks), %esp 212#ifdef CONFIG_X86_STACK_PROTECTION 213 /* In this configuration, all stacks, including IRQ stack, are declared 214 * with a 4K non-present guard page preceding the stack buffer 215 */ 216 addl $(CONFIG_ISR_STACK_SIZE + 4096), %esp 217#else 218 addl $CONFIG_ISR_STACK_SIZE, %esp 219#endif 220 221#ifdef CONFIG_XIP 222 /* Copy data from flash to RAM. 223 * 224 * This is a must is CONFIG_GDT_DYNAMIC is enabled, 225 * as _gdt needs to be in RAM. 226 */ 227 call z_data_copy 228#endif 229 230 /* Note that installing page tables must be done after 231 * z_data_copy() as the page tables are being copied into 232 * RAM there. 233 */ 234 install_page_tables 235 236#ifdef CONFIG_GDT_DYNAMIC 237 /* activate RAM-based Global Descriptor Table (GDT) */ 238 lgdt %ds:_gdt 239#endif 240 241#if defined(CONFIG_X86_ENABLE_TSS) 242 mov $MAIN_TSS, %ax 243 ltr %ax 244#endif 245 246#ifdef Z_VM_KERNEL 247 /* Need to reset the stack to virtual address after 248 * page table is loaded. 249 */ 250 251 movl $z_interrupt_stacks, %esp 252#ifdef CONFIG_X86_STACK_PROTECTION 253 addl $(CONFIG_ISR_STACK_SIZE + 4096), %esp 254#else 255 addl $CONFIG_ISR_STACK_SIZE, %esp 256#endif 257#endif /* Z_VM_KERNEL */ 258 259#ifdef CONFIG_THREAD_LOCAL_STORAGE 260 pushl %esp 261 call z_x86_early_tls_update_gdt 262 popl %esp 263#endif 264 /* Clear BSS */ 265#ifdef CONFIG_LINKER_USE_BOOT_SECTION 266 call z_bss_zero_boot 267#endif 268#ifdef CONFIG_LINKER_USE_PINNED_SECTION 269 call z_bss_zero_pinned 270#endif 271#ifdef CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT 272 /* Don't clear BSS if the section is not present 273 * in memory at boot. Or else it would cause page 274 * faults. Zeroing BSS will be done later once the 275 * the paging mechanism has been initialized. 276 */ 277 call z_bss_zero 278#endif 279 280 /* load 32-bit operand size IDT */ 281 lidt z_x86_idt 282 283 movl $x86_cpu_boot_arg, %ebp 284 /* Boot type to multiboot, ebx content will help to mitigate */ 285 movl $MULTIBOOT_BOOT_TYPE, \ 286 __x86_boot_arg_t_boot_type_OFFSET(%ebp) 287 /* pointer to multiboot info, or NULL */ 288 movl %ebx, __x86_boot_arg_t_arg_OFFSET(%ebp) 289 pushl $x86_cpu_boot_arg 290 call z_prep_c /* enter kernel; never returns */ 291 292#if defined(CONFIG_X86_SSE) 293 294 /* SSE control & status register initial value */ 295 296_sse_mxcsr_default_value: 297 .long 0x1f80 /* all SSE exceptions clear & masked */ 298 299#endif /* CONFIG_X86_SSE */ 300 301 /* Interrupt Descriptor Table (IDT) definition */ 302 303z_x86_idt: 304 .word (CONFIG_IDT_NUM_VECTORS * 8) - 1 /* limit: size of IDT-1 */ 305 306 /* 307 * Physical start address = 0. When executing natively, this 308 * will be placed at the same location as the interrupt vector table 309 * setup by the BIOS (or GRUB?). 310 */ 311 312 /* IDT table start address */ 313 .long _idt_base_address 314 315 316#ifdef CONFIG_SET_GDT 317 /* 318 * The following 3 GDT entries implement the so-called "basic 319 * flat model", i.e. a single code segment descriptor and a single 320 * data segment descriptor, giving the kernel access to a continuous, 321 * unsegmented address space. Both segment descriptors map the entire 322 * linear address space (i.e. 0 to 4 GB-1), thus the segmentation 323 * mechanism will never generate "out of limit memory reference" 324 * exceptions even if physical memory does not reside at the referenced 325 * address. 326 * 327 * The 'A' (accessed) bit in the type field is set for all the 328 * data/code segment descriptors to accommodate placing these entries 329 * in ROM, to prevent the processor from freaking out when it tries 330 * and fails to set it. 331 */ 332 333SECTION_VAR(PINNED_RODATA, _gdt_rom) 334#ifndef CONFIG_GDT_DYNAMIC 335_gdt: 336#endif 337 338 /* GDT should be aligned on 8-byte boundary for best processor 339 * performance, see Section 3.5.1 of IA architecture SW developer 340 * manual, Vol 3. 341 */ 342 343 .balign 8 344 345 /* Entry 0 (selector=0x0000): The "NULL descriptor". The CPU never 346 * actually looks at this entry, so we stuff 6-byte the pseudo 347 * descriptor here */ 348 349 /* Limit on GDT */ 350 .word Z_MEM_PHYS_ADDR(_gdt_rom_end) - Z_MEM_PHYS_ADDR(_gdt_rom) - 1 351 /* table address: _gdt_rom */ 352 .long Z_MEM_PHYS_ADDR(_gdt_rom) 353 .word 0x0000 354 355 /* Entry 1 (selector=0x0008): Code descriptor: DPL0 */ 356 357 .word 0xffff /* limit: xffff */ 358 .word 0x0000 /* base : xxxx0000 */ 359 .byte 0x00 /* base : xx00xxxx */ 360 .byte 0x9b /* Accessed, Code e/r, Present, DPL0 */ 361 .byte 0xcf /* limit: fxxxx, Page Gra, 32bit */ 362 .byte 0x00 /* base : 00xxxxxx */ 363 364 /* Entry 2 (selector=0x0010): Data descriptor: DPL0 */ 365 366 .word 0xffff /* limit: xffff */ 367 .word 0x0000 /* base : xxxx0000 */ 368 .byte 0x00 /* base : xx00xxxx */ 369 .byte 0x93 /* Accessed, Data r/w, Present, DPL0 */ 370 .byte 0xcf /* limit: fxxxx, Page Gra, 32bit */ 371 .byte 0x00 /* base : 00xxxxxx */ 372 373_gdt_rom_end: 374#endif 375