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 */ 72a62f4ca1SThomas Gleixner #ifdef CONFIG_X86_PAE 73a62f4ca1SThomas Gleixner typedef pmd_t pl2_t; 74a62f4ca1SThomas Gleixner #define pl2_base initial_pg_pmd 75a62f4ca1SThomas Gleixner #define SET_PL2(val) { .pmd = (val), } 76a62f4ca1SThomas Gleixner #else 77a62f4ca1SThomas Gleixner typedef pgd_t pl2_t; 78a62f4ca1SThomas Gleixner #define pl2_base initial_page_table 79a62f4ca1SThomas Gleixner #define SET_PL2(val) { .pgd = (val), } 80a62f4ca1SThomas Gleixner #endif 81242db758SThomas Gleixner 82*69ba866dSThomas Gleixner static __init __no_stack_protector pte_t init_map(pte_t pte, pte_t **ptep, pl2_t **pl2p, 83*69ba866dSThomas Gleixner const unsigned long limit) 84*69ba866dSThomas Gleixner { 85*69ba866dSThomas Gleixner while ((pte.pte & PTE_PFN_MASK) < limit) { 86*69ba866dSThomas Gleixner pl2_t pl2 = SET_PL2((unsigned long)*ptep | PDE_IDENT_ATTR); 87*69ba866dSThomas Gleixner int i; 88*69ba866dSThomas Gleixner 89*69ba866dSThomas Gleixner **pl2p = pl2; 90*69ba866dSThomas Gleixner if (!IS_ENABLED(CONFIG_X86_PAE)) { 91*69ba866dSThomas Gleixner /* Kernel PDE entry */ 92*69ba866dSThomas Gleixner *(*pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2; 93*69ba866dSThomas Gleixner } 94*69ba866dSThomas Gleixner 95*69ba866dSThomas Gleixner for (i = 0; i < PTRS_PER_PTE; i++) { 96*69ba866dSThomas Gleixner **ptep = pte; 97*69ba866dSThomas Gleixner pte.pte += PAGE_SIZE; 98*69ba866dSThomas Gleixner (*ptep)++; 99*69ba866dSThomas Gleixner } 100*69ba866dSThomas Gleixner (*pl2p)++; 101*69ba866dSThomas Gleixner } 102*69ba866dSThomas Gleixner return pte; 103*69ba866dSThomas Gleixner } 104*69ba866dSThomas Gleixner 105242db758SThomas Gleixner void __init __no_stack_protector mk_early_pgtbl_32(void) 1061e620f9bSBoris Ostrovsky { 1071e620f9bSBoris Ostrovsky /* Enough space to fit pagetables for the low memory linear map */ 1081e2dd572SThomas Gleixner const unsigned long limit = __pa_nodebug(_end) + 1091e620f9bSBoris Ostrovsky (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT); 110a62f4ca1SThomas Gleixner pte_t pte, *ptep = (pte_t *)__pa_nodebug(__brk_base); 111a62f4ca1SThomas Gleixner pl2_t *pl2p = (pl2_t *)__pa_nodebug(pl2_base); 112a62f4ca1SThomas Gleixner unsigned long *ptr; 1131e620f9bSBoris Ostrovsky 1141e620f9bSBoris Ostrovsky pte.pte = PTE_IDENT_ATTR; 115*69ba866dSThomas Gleixner pte = init_map(pte, &ptep, &pl2p, limit); 1161e620f9bSBoris Ostrovsky 1171e2dd572SThomas Gleixner ptr = (unsigned long *)__pa_nodebug(&max_pfn_mapped); 1181e620f9bSBoris Ostrovsky /* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */ 1191e620f9bSBoris Ostrovsky *ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT; 1201e620f9bSBoris Ostrovsky 1211e2dd572SThomas Gleixner ptr = (unsigned long *)__pa_nodebug(&_brk_end); 1221e620f9bSBoris Ostrovsky *ptr = (unsigned long)ptep + PAGE_OFFSET; 1231e620f9bSBoris Ostrovsky } 124