1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2700efc1bSEric W. Biederman /* 3700efc1bSEric W. Biederman * linux/arch/i386/kernel/head32.c -- prepare to run common code 4700efc1bSEric W. Biederman * 5700efc1bSEric W. Biederman * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 6700efc1bSEric W. Biederman * Copyright (C) 2007 Eric Biederman <ebiederm@xmission.com> 7700efc1bSEric W. Biederman */ 8700efc1bSEric W. Biederman 9700efc1bSEric W. Biederman #include <linux/init.h> 10700efc1bSEric W. Biederman #include <linux/start_kernel.h> 11c967da6aSYinghai Lu #include <linux/mm.h> 1272d7c3b3SYinghai Lu #include <linux/memblock.h> 13700efc1bSEric W. Biederman 1487e81786SThomas Gleixner #include <asm/desc.h> 15a4c81cf6SYinghai Lu #include <asm/setup.h> 16a4c81cf6SYinghai Lu #include <asm/sections.h> 1766441bd3SIngo Molnar #include <asm/e820/api.h> 18816c25e7SThomas Gleixner #include <asm/page.h> 19de934103SThomas Gleixner #include <asm/apic.h> 20de934103SThomas Gleixner #include <asm/io_apic.h> 2147a3d5daSThomas Gleixner #include <asm/bios_ebda.h> 22b40827faSBorislav Petkov #include <asm/tlbflush.h> 235dcd14ecSH. Peter Anvin #include <asm/bootparam_utils.h> 2447a3d5daSThomas Gleixner 2547a3d5daSThomas Gleixner static void __init i386_default_early_setup(void) 2647a3d5daSThomas Gleixner { 27421f91d2SUwe Kleine-König /* Initialize 32bit specific setup functions */ 2847a3d5daSThomas Gleixner x86_init.resources.reserve_resources = i386_reserve_resources; 2947a3d5daSThomas Gleixner x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; 3047a3d5daSThomas Gleixner } 31a4c81cf6SYinghai Lu 324208d2d7SJosh Poimboeuf asmlinkage __visible void __init __noreturn i386_start_kernel(void) 33700efc1bSEric W. Biederman { 349c48c096SThomas Gleixner /* Make sure IDT is set up before any exception happens */ 3587e81786SThomas Gleixner idt_setup_early_handler(); 3687e81786SThomas Gleixner 379c48c096SThomas Gleixner cr4_init_shadow(); 389c48c096SThomas Gleixner 395dcd14ecSH. Peter Anvin sanitize_boot_params(&boot_params); 405dcd14ecSH. Peter Anvin 418d152e7aSLuis R. Rodriguez x86_early_init_platform_quirks(); 428d152e7aSLuis R. Rodriguez 4347a3d5daSThomas Gleixner /* Call the subarch specific early setup function */ 4447a3d5daSThomas Gleixner switch (boot_params.hdr.hardware_subarch) { 45712b6aa8SKuppuswamy Sathyanarayanan case X86_SUBARCH_INTEL_MID: 46712b6aa8SKuppuswamy Sathyanarayanan x86_intel_mid_early_setup(); 473f4110a4SThomas Gleixner break; 48c751e17bSThomas Gleixner case X86_SUBARCH_CE4100: 49c751e17bSThomas Gleixner x86_ce4100_early_setup(); 50c751e17bSThomas Gleixner break; 5147a3d5daSThomas Gleixner default: 5247a3d5daSThomas Gleixner i386_default_early_setup(); 5347a3d5daSThomas Gleixner break; 5447a3d5daSThomas Gleixner } 55a4c81cf6SYinghai Lu 56700efc1bSEric W. Biederman start_kernel(); 57700efc1bSEric W. Biederman } 581e620f9bSBoris Ostrovsky 591e620f9bSBoris Ostrovsky /* 601e620f9bSBoris Ostrovsky * Initialize page tables. This creates a PDE and a set of page 611e620f9bSBoris Ostrovsky * tables, which are located immediately beyond __brk_base. The variable 621e620f9bSBoris Ostrovsky * _brk_end is set up to point to the first "safe" location. 631e620f9bSBoris Ostrovsky * Mappings are created both at virtual address 0 (identity mapping) 641e620f9bSBoris Ostrovsky * and PAGE_OFFSET for up to _end. 651e620f9bSBoris Ostrovsky * 661e620f9bSBoris Ostrovsky * In PAE mode initial_page_table is statically defined to contain 671e620f9bSBoris Ostrovsky * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 681e620f9bSBoris Ostrovsky * entries). The identity mapping is handled by pointing two PGD entries 691e620f9bSBoris Ostrovsky * to the first kernel PMD. Note the upper half of each PMD or PTE are 701e620f9bSBoris Ostrovsky * always zero at this stage. 711e620f9bSBoris Ostrovsky */ 722eb5d1dfSArnd Bergmann void __init mk_early_pgtbl_32(void); 73242db758SThomas Gleixner 74242db758SThomas Gleixner void __init __no_stack_protector mk_early_pgtbl_32(void) 751e620f9bSBoris Ostrovsky { 761e620f9bSBoris Ostrovsky pte_t pte, *ptep; 771e620f9bSBoris Ostrovsky int i; 781e620f9bSBoris Ostrovsky unsigned long *ptr; 791e620f9bSBoris Ostrovsky /* Enough space to fit pagetables for the low memory linear map */ 80*1e2dd572SThomas Gleixner const unsigned long limit = __pa_nodebug(_end) + 811e620f9bSBoris Ostrovsky (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT); 821e620f9bSBoris Ostrovsky #ifdef CONFIG_X86_PAE 83*1e2dd572SThomas Gleixner pmd_t pl2, *pl2p = (pmd_t *)__pa_nodebug(initial_pg_pmd); 841e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pmd = (val); } 851e620f9bSBoris Ostrovsky #else 86*1e2dd572SThomas Gleixner pgd_t pl2, *pl2p = (pgd_t *)__pa_nodebug(initial_page_table); 871e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pgd = (val); } 881e620f9bSBoris Ostrovsky #endif 891e620f9bSBoris Ostrovsky 90*1e2dd572SThomas Gleixner ptep = (pte_t *)__pa_nodebug(__brk_base); 911e620f9bSBoris Ostrovsky pte.pte = PTE_IDENT_ATTR; 921e620f9bSBoris Ostrovsky 931e620f9bSBoris Ostrovsky while ((pte.pte & PTE_PFN_MASK) < limit) { 941e620f9bSBoris Ostrovsky 951e620f9bSBoris Ostrovsky SET_PL2(pl2, (unsigned long)ptep | PDE_IDENT_ATTR); 961e620f9bSBoris Ostrovsky *pl2p = pl2; 971e620f9bSBoris Ostrovsky #ifndef CONFIG_X86_PAE 981e620f9bSBoris Ostrovsky /* Kernel PDE entry */ 991e620f9bSBoris Ostrovsky *(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2; 1001e620f9bSBoris Ostrovsky #endif 1011e620f9bSBoris Ostrovsky for (i = 0; i < PTRS_PER_PTE; i++) { 1021e620f9bSBoris Ostrovsky *ptep = pte; 1031e620f9bSBoris Ostrovsky pte.pte += PAGE_SIZE; 1041e620f9bSBoris Ostrovsky ptep++; 1051e620f9bSBoris Ostrovsky } 1061e620f9bSBoris Ostrovsky 1071e620f9bSBoris Ostrovsky pl2p++; 1081e620f9bSBoris Ostrovsky } 1091e620f9bSBoris Ostrovsky 110*1e2dd572SThomas Gleixner ptr = (unsigned long *)__pa_nodebug(&max_pfn_mapped); 1111e620f9bSBoris Ostrovsky /* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */ 1121e620f9bSBoris Ostrovsky *ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT; 1131e620f9bSBoris Ostrovsky 114*1e2dd572SThomas Gleixner ptr = (unsigned long *)__pa_nodebug(&_brk_end); 1151e620f9bSBoris Ostrovsky *ptr = (unsigned long)ptep + PAGE_OFFSET; 1161e620f9bSBoris Ostrovsky } 1171e620f9bSBoris Ostrovsky 118