/* SPDX-License-Identifier: GPL-2.0 */1/*2*3* Copyright (C) 1991, 1992 Linus Torvalds4*5* Enhanced CPU detection and feature setting code by Mike Jagdis6* and Martin Mares, November 1997.7*/89.text10#include <linux/export.h>11#include <linux/threads.h>12#include <linux/init.h>13#include <linux/linkage.h>14#include <asm/segment.h>15#include <asm/page_types.h>16#include <asm/pgtable_types.h>17#include <asm/cache.h>18#include <asm/thread_info.h>19#include <asm/asm-offsets.h>20#include <asm/setup.h>21#include <asm/processor-flags.h>22#include <asm/msr-index.h>23#include <asm/cpufeatures.h>24#include <asm/percpu.h>25#include <asm/nops.h>26#include <asm/nospec-branch.h>27#include <asm/bootparam.h>28#include <asm/pgtable_32.h>2930/* Physical address */31#define pa(X) ((X) - __PAGE_OFFSET)3233/*34* References to members of the new_cpu_data structure.35*/3637#define X86 new_cpu_data+CPUINFO_x8638#define X86_VENDOR new_cpu_data+CPUINFO_x86_vendor39#define X86_MODEL new_cpu_data+CPUINFO_x86_model40#define X86_STEPPING new_cpu_data+CPUINFO_x86_stepping41#define X86_HARD_MATH new_cpu_data+CPUINFO_hard_math42#define X86_CPUID new_cpu_data+CPUINFO_cpuid_level43#define X86_CAPABILITY new_cpu_data+CPUINFO_x86_capability44#define X86_VENDOR_ID new_cpu_data+CPUINFO_x86_vendor_id4546/*47* Worst-case size of the kernel mapping we need to make:48* a relocatable kernel can live anywhere in lowmem, so we need to be able49* to map all of lowmem.50*/51KERNEL_PAGES = LOWMEM_PAGES5253INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE54RESERVE_BRK(pagetables, INIT_MAP_SIZE)5556/*57* 32-bit kernel entrypoint; only used by the boot CPU. On entry,58* %esi points to the real-mode code as a 32-bit pointer.59* CS and DS must be 4 GB flat segments, but we don't depend on60* any particular GDT layout, because we load our own as soon as we61* can.62*/63__HEAD64SYM_CODE_START(startup_32)65movl pa(initial_stack),%ecx6667/*68* Set segments to known values.69*/70lgdt pa(boot_gdt_descr)71movl $(__BOOT_DS),%eax72movl %eax,%ds73movl %eax,%es74movl %eax,%fs75movl %eax,%gs76movl %eax,%ss77leal -__PAGE_OFFSET(%ecx),%esp7879/*80* Clear BSS first so that there are no surprises...81*/82cld83xorl %eax,%eax84movl $pa(__bss_start),%edi85movl $pa(__bss_stop),%ecx86subl %edi,%ecx87shrl $2,%ecx88rep stosl89/*90* Copy bootup parameters out of the way.91* Note: %esi still has the pointer to the real-mode data.92* With the kexec as boot loader, parameter segment might be loaded beyond93* kernel image and might not even be addressable by early boot page tables.94* (kexec on panic case). Hence copy out the parameters before initializing95* page tables.96*/97movl $pa(boot_params),%edi98movl $(PARAM_SIZE/4),%ecx99cld100rep movsl101movl pa(boot_params) + NEW_CL_POINTER,%esi102andl %esi,%esi103jz 1f # No command line104movl $pa(boot_command_line),%edi105movl $(COMMAND_LINE_SIZE/4),%ecx106rep movsl1071:108109#ifdef CONFIG_OLPC110/* save OFW's pgdir table for later use when calling into OFW */111movl %cr3, %eax112movl %eax, pa(olpc_ofw_pgd)113#endif114115/* Create early pagetables. */116call mk_early_pgtbl_32117118/* Do early initialization of the fixmap area */119movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax120#ifdef CONFIG_X86_PAE121#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */122movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)123#else124movl %eax,pa(initial_page_table+0xffc)125#endif126127jmp .Ldefault_entry128SYM_CODE_END(startup_32)129130/*131* Non-boot CPU entry point; entered from trampoline.S132* We can't lgdt here, because lgdt itself uses a data segment, but133* we know the trampoline has already loaded the boot_gdt for us.134*135* If cpu hotplug is not supported then this code can go in init section136* which will be freed later137*/138SYM_FUNC_START(startup_32_smp)139cld140movl $(__BOOT_DS),%eax141movl %eax,%ds142movl %eax,%es143movl %eax,%fs144movl %eax,%gs145movl pa(initial_stack),%ecx146movl %eax,%ss147leal -__PAGE_OFFSET(%ecx),%esp148149.Ldefault_entry:150movl $(CR0_STATE & ~X86_CR0_PG),%eax151movl %eax,%cr0152153/*154* We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave155* bits like NT set. This would confuse the debugger if this code is traced. So156* initialize them properly now before switching to protected mode. That means157* DF in particular (even though we have cleared it earlier after copying the158* command line) because GCC expects it.159*/160pushl $0161popfl162163/*164* New page tables may be in 4Mbyte page mode and may be using the global pages.165*166* NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists167* if and only if CPUID exists and has flags other than the FPU flag set.168*/169movl $-1,pa(X86_CPUID) # preset CPUID level170movl $X86_EFLAGS_ID,%ecx171pushl %ecx172popfl # set EFLAGS=ID173pushfl174popl %eax # get EFLAGS175testl $X86_EFLAGS_ID,%eax # did EFLAGS.ID remained set?176jz .Lenable_paging # hw disallowed setting of ID bit177# which means no CPUID and no CR4178179xorl %eax,%eax180cpuid181movl %eax,pa(X86_CPUID) # save largest std CPUID function182183movl $1,%eax184cpuid185andl $~1,%edx # Ignore CPUID.FPU186jz .Lenable_paging # No flags or only CPUID.FPU = no CR4187188movl pa(mmu_cr4_features),%eax189movl %eax,%cr4190191testb $X86_CR4_PAE, %al # check if PAE is enabled192jz .Lenable_paging193194/* Check if extended functions are implemented */195movl $0x80000000, %eax196cpuid197/* Value must be in the range 0x80000001 to 0x8000ffff */198subl $0x80000001, %eax199cmpl $(0x8000ffff-0x80000001), %eax200ja .Lenable_paging201202/* Clear bogus XD_DISABLE bits */203call verify_cpu204205mov $0x80000001, %eax206cpuid207/* Execute Disable bit supported? */208btl $(X86_FEATURE_NX & 31), %edx209jnc .Lenable_paging210211/* Setup EFER (Extended Feature Enable Register) */212movl $MSR_EFER, %ecx213rdmsr214215btsl $_EFER_NX, %eax216/* Make changes effective */217wrmsr218219.Lenable_paging:220221/*222* Enable paging223*/224movl $pa(initial_page_table), %eax225movl %eax,%cr3 /* set the page table pointer.. */226movl $CR0_STATE,%eax227movl %eax,%cr0 /* ..and set paging (PG) bit */228ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */2291:230/* Shift the stack pointer to a virtual address */231addl $__PAGE_OFFSET, %esp232233/*234* Check if it is 486235*/236movb $4,X86 # at least 486237cmpl $-1,X86_CPUID238je .Lis486239240/* get vendor info */241xorl %eax,%eax # call CPUID with 0 -> return vendor ID242cpuid243movl %eax,X86_CPUID # save CPUID level244movl %ebx,X86_VENDOR_ID # lo 4 chars245movl %edx,X86_VENDOR_ID+4 # next 4 chars246movl %ecx,X86_VENDOR_ID+8 # last 4 chars247248orl %eax,%eax # do we have processor info as well?249je .Lis486250251movl $1,%eax # Use the CPUID instruction to get CPU type252cpuid253movb %al,%cl # save reg for future use254andb $0x0f,%ah # mask processor family255movb %ah,X86256andb $0xf0,%al # mask model257shrb $4,%al258movb %al,X86_MODEL259andb $0x0f,%cl # mask mask revision260movb %cl,X86_STEPPING261movl %edx,X86_CAPABILITY262263.Lis486:264movl $0x50022,%ecx # set AM, WP, NE and MP265movl %cr0,%eax266andl $0x80000011,%eax # Save PG,PE,ET267orl %ecx,%eax268movl %eax,%cr0269270lgdt early_gdt_descr271ljmp $(__KERNEL_CS),$1f2721: movl $(__KERNEL_DS),%eax # reload all the segment registers273movl %eax,%ss # after changing gdt.274275movl $(__USER_DS),%eax # DS/ES contains default USER segment276movl %eax,%ds277movl %eax,%es278279movl $(__KERNEL_PERCPU), %eax280movl %eax,%fs # set this cpu's percpu281282xorl %eax,%eax283movl %eax,%gs # clear possible garbage in %gs284285xorl %eax,%eax # Clear LDT286lldt %ax287288call *(initial_code)2891: jmp 1b290SYM_FUNC_END(startup_32_smp)291292#include "verify_cpu.S"293294__INIT295SYM_FUNC_START(early_idt_handler_array)296# 36(%esp) %eflags297# 32(%esp) %cs298# 28(%esp) %eip299# 24(%rsp) error code300i = 0301.rept NUM_EXCEPTION_VECTORS302.if ((EXCEPTION_ERRCODE_MASK >> i) & 1) == 0303pushl $0 # Dummy error code, to make stack frame uniform304.endif305pushl $i # 20(%esp) Vector number306jmp early_idt_handler_common307i = i + 1308.fill early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc309.endr310SYM_FUNC_END(early_idt_handler_array)311312SYM_CODE_START_LOCAL(early_idt_handler_common)313/*314* The stack is the hardware frame, an error code or zero, and the315* vector number.316*/317cld318319incl %ss:early_recursion_flag320321/* The vector number is in pt_regs->gs */322323cld324pushl %fs /* pt_regs->fs (__fsh varies by model) */325pushl %es /* pt_regs->es (__esh varies by model) */326pushl %ds /* pt_regs->ds (__dsh varies by model) */327pushl %eax /* pt_regs->ax */328pushl %ebp /* pt_regs->bp */329pushl %edi /* pt_regs->di */330pushl %esi /* pt_regs->si */331pushl %edx /* pt_regs->dx */332pushl %ecx /* pt_regs->cx */333pushl %ebx /* pt_regs->bx */334335/* Fix up DS and ES */336movl $(__KERNEL_DS), %ecx337movl %ecx, %ds338movl %ecx, %es339340/* Load the vector number into EDX */341movl PT_GS(%esp), %edx342343/* Load GS into pt_regs->gs (and maybe clobber __gsh) */344movw %gs, PT_GS(%esp)345346movl %esp, %eax /* args are pt_regs (EAX), trapnr (EDX) */347call early_fixup_exception348349popl %ebx /* pt_regs->bx */350popl %ecx /* pt_regs->cx */351popl %edx /* pt_regs->dx */352popl %esi /* pt_regs->si */353popl %edi /* pt_regs->di */354popl %ebp /* pt_regs->bp */355popl %eax /* pt_regs->ax */356popl %ds /* pt_regs->ds (always ignores __dsh) */357popl %es /* pt_regs->es (always ignores __esh) */358popl %fs /* pt_regs->fs (always ignores __fsh) */359popl %gs /* pt_regs->gs (always ignores __gsh) */360decl %ss:early_recursion_flag361addl $4, %esp /* pop pt_regs->orig_ax */362iret363SYM_CODE_END(early_idt_handler_common)364365/* This is the default interrupt "handler" :-) */366SYM_FUNC_START(early_ignore_irq)367cld368#ifdef CONFIG_PRINTK369pushl %eax370pushl %ecx371pushl %edx372pushl %es373pushl %ds374movl $(__KERNEL_DS),%eax375movl %eax,%ds376movl %eax,%es377cmpl $2,early_recursion_flag378je hlt_loop379incl early_recursion_flag380pushl 16(%esp)381pushl 24(%esp)382pushl 32(%esp)383pushl 40(%esp)384pushl $int_msg385call _printk386387call dump_stack388389addl $(5*4),%esp390popl %ds391popl %es392popl %edx393popl %ecx394popl %eax395#endif396iret397398hlt_loop:399hlt400jmp hlt_loop401SYM_FUNC_END(early_ignore_irq)402403__INITDATA404.align 4405SYM_DATA(early_recursion_flag, .long 0)406407__REFDATA408.align 4409SYM_DATA(initial_code, .long i386_start_kernel)410411#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION412#define PGD_ALIGN (2 * PAGE_SIZE)413#define PTI_USER_PGD_FILL 1024414#else415#define PGD_ALIGN (PAGE_SIZE)416#define PTI_USER_PGD_FILL 0417#endif418/*419* BSS section420*/421__PAGE_ALIGNED_BSS422.align PGD_ALIGN423#ifdef CONFIG_X86_PAE424.globl initial_pg_pmd425initial_pg_pmd:426.fill 1024*KPMDS,4,0427#else428.globl initial_page_table429initial_page_table:430.fill 1024,4,0431#endif432.align PGD_ALIGN433initial_pg_fixmap:434.fill 1024,4,0435.globl swapper_pg_dir436.align PGD_ALIGN437swapper_pg_dir:438.fill 1024,4,0439.fill PTI_USER_PGD_FILL,4,0440.globl empty_zero_page441empty_zero_page:442.fill 4096,1,0443EXPORT_SYMBOL(empty_zero_page)444445/*446* This starts the data section.447*/448#ifdef CONFIG_X86_PAE449__PAGE_ALIGNED_DATA450/* Page-aligned for the benefit of paravirt? */451.align PGD_ALIGN452SYM_DATA_START(initial_page_table)453.long pa(initial_pg_pmd+PGD_IDENT_ATTR),0 /* low identity map */454# if KPMDS == 3455.long pa(initial_pg_pmd+PGD_IDENT_ATTR),0456.long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0457.long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0458# elif KPMDS == 2459.long 0,0460.long pa(initial_pg_pmd+PGD_IDENT_ATTR),0461.long pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0462# elif KPMDS == 1463.long 0,0464.long 0,0465.long pa(initial_pg_pmd+PGD_IDENT_ATTR),0466# else467# error "Kernel PMDs should be 1, 2 or 3"468# endif469.align PAGE_SIZE /* needs to be page-sized too */470471#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION472/*473* PTI needs another page so sync_initial_pagetable() works correctly474* and does not scribble over the data which is placed behind the475* actual initial_page_table. See clone_pgd_range().476*/477.fill 1024, 4, 0478#endif479480SYM_DATA_END(initial_page_table)481#endif482483.data484.balign 4485SYM_DATA(initial_stack, .long __top_init_kernel_stack)486487__INITRODATA488int_msg:489.asciz "Unknown interrupt or fault at: %p %p %p\n"490491#include "../xen/xen-head.S"492493/*494* The IDT and GDT 'descriptors' are a strange 48-bit object495* only used by the lidt and lgdt instructions. They are not496* like usual segment descriptors - they consist of a 16-bit497* segment size, and 32-bit linear address value:498*/499500.data501ALIGN502# early boot GDT descriptor (must use 1:1 address mapping)503.word 0 # 32 bit align gdt_desc.address504SYM_DATA_START_LOCAL(boot_gdt_descr)505.word __BOOT_DS+7506.long boot_gdt - __PAGE_OFFSET507SYM_DATA_END(boot_gdt_descr)508509# boot GDT descriptor (later on used by CPU#0):510.word 0 # 32 bit align gdt_desc.address511SYM_DATA_START(early_gdt_descr)512.word GDT_ENTRIES*8-1513.long gdt_page /* Overwritten for secondary CPUs */514SYM_DATA_END(early_gdt_descr)515516/*517* The boot_gdt must mirror the equivalent in setup.S and is518* used only for booting.519*/520.align L1_CACHE_BYTES521SYM_DATA_START(boot_gdt)522.fill GDT_ENTRY_BOOT_CS,8,0523.quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */524.quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */525SYM_DATA_END(boot_gdt)526527528