1700efc1bSEric W. Biederman /* 2700efc1bSEric W. Biederman * linux/arch/i386/kernel/head32.c -- prepare to run common code 3700efc1bSEric W. Biederman * 4700efc1bSEric W. Biederman * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 5700efc1bSEric W. Biederman * Copyright (C) 2007 Eric Biederman <ebiederm@xmission.com> 6700efc1bSEric W. Biederman */ 7700efc1bSEric W. Biederman 8700efc1bSEric W. Biederman #include <linux/init.h> 9700efc1bSEric W. Biederman #include <linux/start_kernel.h> 10c967da6aSYinghai Lu #include <linux/mm.h> 1172d7c3b3SYinghai Lu #include <linux/memblock.h> 12700efc1bSEric W. Biederman 13a4c81cf6SYinghai Lu #include <asm/setup.h> 14a4c81cf6SYinghai Lu #include <asm/sections.h> 1566441bd3SIngo Molnar #include <asm/e820/api.h> 16816c25e7SThomas Gleixner #include <asm/page.h> 17de934103SThomas Gleixner #include <asm/apic.h> 18de934103SThomas Gleixner #include <asm/io_apic.h> 1947a3d5daSThomas Gleixner #include <asm/bios_ebda.h> 20b40827faSBorislav Petkov #include <asm/tlbflush.h> 215dcd14ecSH. Peter Anvin #include <asm/bootparam_utils.h> 2247a3d5daSThomas Gleixner 2347a3d5daSThomas Gleixner static void __init i386_default_early_setup(void) 2447a3d5daSThomas Gleixner { 25421f91d2SUwe Kleine-König /* Initialize 32bit specific setup functions */ 2647a3d5daSThomas Gleixner x86_init.resources.reserve_resources = i386_reserve_resources; 2747a3d5daSThomas Gleixner x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; 2847a3d5daSThomas Gleixner } 29a4c81cf6SYinghai Lu 302605fc21SAndi Kleen asmlinkage __visible void __init i386_start_kernel(void) 31700efc1bSEric W. Biederman { 321e02ce4cSAndy Lutomirski cr4_init_shadow(); 335dcd14ecSH. Peter Anvin sanitize_boot_params(&boot_params); 345dcd14ecSH. Peter Anvin 358d152e7aSLuis R. Rodriguez x86_early_init_platform_quirks(); 368d152e7aSLuis R. Rodriguez 3747a3d5daSThomas Gleixner /* Call the subarch specific early setup function */ 3847a3d5daSThomas Gleixner switch (boot_params.hdr.hardware_subarch) { 39712b6aa8SKuppuswamy Sathyanarayanan case X86_SUBARCH_INTEL_MID: 40712b6aa8SKuppuswamy Sathyanarayanan x86_intel_mid_early_setup(); 413f4110a4SThomas Gleixner break; 42c751e17bSThomas Gleixner case X86_SUBARCH_CE4100: 43c751e17bSThomas Gleixner x86_ce4100_early_setup(); 44c751e17bSThomas Gleixner break; 4547a3d5daSThomas Gleixner default: 4647a3d5daSThomas Gleixner i386_default_early_setup(); 4747a3d5daSThomas Gleixner break; 4847a3d5daSThomas Gleixner } 49a4c81cf6SYinghai Lu 50700efc1bSEric W. Biederman start_kernel(); 51700efc1bSEric W. Biederman } 521e620f9bSBoris Ostrovsky 531e620f9bSBoris Ostrovsky /* 541e620f9bSBoris Ostrovsky * Initialize page tables. This creates a PDE and a set of page 551e620f9bSBoris Ostrovsky * tables, which are located immediately beyond __brk_base. The variable 561e620f9bSBoris Ostrovsky * _brk_end is set up to point to the first "safe" location. 571e620f9bSBoris Ostrovsky * Mappings are created both at virtual address 0 (identity mapping) 581e620f9bSBoris Ostrovsky * and PAGE_OFFSET for up to _end. 591e620f9bSBoris Ostrovsky * 601e620f9bSBoris Ostrovsky * In PAE mode initial_page_table is statically defined to contain 611e620f9bSBoris Ostrovsky * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 621e620f9bSBoris Ostrovsky * entries). The identity mapping is handled by pointing two PGD entries 631e620f9bSBoris Ostrovsky * to the first kernel PMD. Note the upper half of each PMD or PTE are 641e620f9bSBoris Ostrovsky * always zero at this stage. 651e620f9bSBoris Ostrovsky */ 661e620f9bSBoris Ostrovsky void __init mk_early_pgtbl_32(void) 671e620f9bSBoris Ostrovsky { 681e620f9bSBoris Ostrovsky #ifdef __pa 691e620f9bSBoris Ostrovsky #undef __pa 701e620f9bSBoris Ostrovsky #endif 711e620f9bSBoris Ostrovsky #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) 721e620f9bSBoris Ostrovsky pte_t pte, *ptep; 731e620f9bSBoris Ostrovsky int i; 741e620f9bSBoris Ostrovsky unsigned long *ptr; 751e620f9bSBoris Ostrovsky /* Enough space to fit pagetables for the low memory linear map */ 761e620f9bSBoris Ostrovsky const unsigned long limit = __pa(_end) + 771e620f9bSBoris Ostrovsky (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT); 781e620f9bSBoris Ostrovsky #ifdef CONFIG_X86_PAE 791e620f9bSBoris Ostrovsky pmd_t pl2, *pl2p = (pmd_t *)__pa(initial_pg_pmd); 801e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pmd = (val); } 811e620f9bSBoris Ostrovsky #else 821e620f9bSBoris Ostrovsky pgd_t pl2, *pl2p = (pgd_t *)__pa(initial_page_table); 831e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pgd = (val); } 841e620f9bSBoris Ostrovsky #endif 851e620f9bSBoris Ostrovsky 861e620f9bSBoris Ostrovsky ptep = (pte_t *)__pa(__brk_base); 871e620f9bSBoris Ostrovsky pte.pte = PTE_IDENT_ATTR; 881e620f9bSBoris Ostrovsky 891e620f9bSBoris Ostrovsky while ((pte.pte & PTE_PFN_MASK) < limit) { 901e620f9bSBoris Ostrovsky 911e620f9bSBoris Ostrovsky SET_PL2(pl2, (unsigned long)ptep | PDE_IDENT_ATTR); 921e620f9bSBoris Ostrovsky *pl2p = pl2; 931e620f9bSBoris Ostrovsky #ifndef CONFIG_X86_PAE 941e620f9bSBoris Ostrovsky /* Kernel PDE entry */ 951e620f9bSBoris Ostrovsky *(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2; 961e620f9bSBoris Ostrovsky #endif 971e620f9bSBoris Ostrovsky for (i = 0; i < PTRS_PER_PTE; i++) { 981e620f9bSBoris Ostrovsky *ptep = pte; 991e620f9bSBoris Ostrovsky pte.pte += PAGE_SIZE; 1001e620f9bSBoris Ostrovsky ptep++; 1011e620f9bSBoris Ostrovsky } 1021e620f9bSBoris Ostrovsky 1031e620f9bSBoris Ostrovsky pl2p++; 1041e620f9bSBoris Ostrovsky } 1051e620f9bSBoris Ostrovsky 1061e620f9bSBoris Ostrovsky ptr = (unsigned long *)__pa(&max_pfn_mapped); 1071e620f9bSBoris Ostrovsky /* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */ 1081e620f9bSBoris Ostrovsky *ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT; 1091e620f9bSBoris Ostrovsky 1101e620f9bSBoris Ostrovsky ptr = (unsigned long *)__pa(&_brk_end); 1111e620f9bSBoris Ostrovsky *ptr = (unsigned long)ptep + PAGE_OFFSET; 1121e620f9bSBoris Ostrovsky } 1131e620f9bSBoris Ostrovsky 114