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 1387e81786SThomas Gleixner #include <asm/desc.h> 14a4c81cf6SYinghai Lu #include <asm/setup.h> 15a4c81cf6SYinghai Lu #include <asm/sections.h> 1666441bd3SIngo Molnar #include <asm/e820/api.h> 17816c25e7SThomas Gleixner #include <asm/page.h> 18de934103SThomas Gleixner #include <asm/apic.h> 19de934103SThomas Gleixner #include <asm/io_apic.h> 2047a3d5daSThomas Gleixner #include <asm/bios_ebda.h> 21b40827faSBorislav Petkov #include <asm/tlbflush.h> 225dcd14ecSH. Peter Anvin #include <asm/bootparam_utils.h> 2347a3d5daSThomas Gleixner 2447a3d5daSThomas Gleixner static void __init i386_default_early_setup(void) 2547a3d5daSThomas Gleixner { 26421f91d2SUwe Kleine-König /* Initialize 32bit specific setup functions */ 2747a3d5daSThomas Gleixner x86_init.resources.reserve_resources = i386_reserve_resources; 2847a3d5daSThomas Gleixner x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc; 2947a3d5daSThomas Gleixner } 30a4c81cf6SYinghai Lu 312605fc21SAndi Kleen asmlinkage __visible void __init i386_start_kernel(void) 32700efc1bSEric W. Biederman { 339c48c096SThomas Gleixner /* Make sure IDT is set up before any exception happens */ 3487e81786SThomas Gleixner idt_setup_early_handler(); 3587e81786SThomas Gleixner 369c48c096SThomas Gleixner cr4_init_shadow(); 379c48c096SThomas Gleixner 385dcd14ecSH. Peter Anvin sanitize_boot_params(&boot_params); 395dcd14ecSH. Peter Anvin 408d152e7aSLuis R. Rodriguez x86_early_init_platform_quirks(); 418d152e7aSLuis R. Rodriguez 4247a3d5daSThomas Gleixner /* Call the subarch specific early setup function */ 4347a3d5daSThomas Gleixner switch (boot_params.hdr.hardware_subarch) { 44712b6aa8SKuppuswamy Sathyanarayanan case X86_SUBARCH_INTEL_MID: 45712b6aa8SKuppuswamy Sathyanarayanan x86_intel_mid_early_setup(); 463f4110a4SThomas Gleixner break; 47c751e17bSThomas Gleixner case X86_SUBARCH_CE4100: 48c751e17bSThomas Gleixner x86_ce4100_early_setup(); 49c751e17bSThomas Gleixner break; 5047a3d5daSThomas Gleixner default: 5147a3d5daSThomas Gleixner i386_default_early_setup(); 5247a3d5daSThomas Gleixner break; 5347a3d5daSThomas Gleixner } 54a4c81cf6SYinghai Lu 55700efc1bSEric W. Biederman start_kernel(); 56700efc1bSEric W. Biederman } 571e620f9bSBoris Ostrovsky 581e620f9bSBoris Ostrovsky /* 591e620f9bSBoris Ostrovsky * Initialize page tables. This creates a PDE and a set of page 601e620f9bSBoris Ostrovsky * tables, which are located immediately beyond __brk_base. The variable 611e620f9bSBoris Ostrovsky * _brk_end is set up to point to the first "safe" location. 621e620f9bSBoris Ostrovsky * Mappings are created both at virtual address 0 (identity mapping) 631e620f9bSBoris Ostrovsky * and PAGE_OFFSET for up to _end. 641e620f9bSBoris Ostrovsky * 651e620f9bSBoris Ostrovsky * In PAE mode initial_page_table is statically defined to contain 661e620f9bSBoris Ostrovsky * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3 671e620f9bSBoris Ostrovsky * entries). The identity mapping is handled by pointing two PGD entries 681e620f9bSBoris Ostrovsky * to the first kernel PMD. Note the upper half of each PMD or PTE are 691e620f9bSBoris Ostrovsky * always zero at this stage. 701e620f9bSBoris Ostrovsky */ 711e620f9bSBoris Ostrovsky void __init mk_early_pgtbl_32(void) 721e620f9bSBoris Ostrovsky { 731e620f9bSBoris Ostrovsky #ifdef __pa 741e620f9bSBoris Ostrovsky #undef __pa 751e620f9bSBoris Ostrovsky #endif 761e620f9bSBoris Ostrovsky #define __pa(x) ((unsigned long)(x) - PAGE_OFFSET) 771e620f9bSBoris Ostrovsky pte_t pte, *ptep; 781e620f9bSBoris Ostrovsky int i; 791e620f9bSBoris Ostrovsky unsigned long *ptr; 801e620f9bSBoris Ostrovsky /* Enough space to fit pagetables for the low memory linear map */ 811e620f9bSBoris Ostrovsky const unsigned long limit = __pa(_end) + 821e620f9bSBoris Ostrovsky (PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT); 831e620f9bSBoris Ostrovsky #ifdef CONFIG_X86_PAE 841e620f9bSBoris Ostrovsky pmd_t pl2, *pl2p = (pmd_t *)__pa(initial_pg_pmd); 851e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pmd = (val); } 861e620f9bSBoris Ostrovsky #else 871e620f9bSBoris Ostrovsky pgd_t pl2, *pl2p = (pgd_t *)__pa(initial_page_table); 881e620f9bSBoris Ostrovsky #define SET_PL2(pl2, val) { (pl2).pgd = (val); } 891e620f9bSBoris Ostrovsky #endif 901e620f9bSBoris Ostrovsky 911e620f9bSBoris Ostrovsky ptep = (pte_t *)__pa(__brk_base); 921e620f9bSBoris Ostrovsky pte.pte = PTE_IDENT_ATTR; 931e620f9bSBoris Ostrovsky 941e620f9bSBoris Ostrovsky while ((pte.pte & PTE_PFN_MASK) < limit) { 951e620f9bSBoris Ostrovsky 961e620f9bSBoris Ostrovsky SET_PL2(pl2, (unsigned long)ptep | PDE_IDENT_ATTR); 971e620f9bSBoris Ostrovsky *pl2p = pl2; 981e620f9bSBoris Ostrovsky #ifndef CONFIG_X86_PAE 991e620f9bSBoris Ostrovsky /* Kernel PDE entry */ 1001e620f9bSBoris Ostrovsky *(pl2p + ((PAGE_OFFSET >> PGDIR_SHIFT))) = pl2; 1011e620f9bSBoris Ostrovsky #endif 1021e620f9bSBoris Ostrovsky for (i = 0; i < PTRS_PER_PTE; i++) { 1031e620f9bSBoris Ostrovsky *ptep = pte; 1041e620f9bSBoris Ostrovsky pte.pte += PAGE_SIZE; 1051e620f9bSBoris Ostrovsky ptep++; 1061e620f9bSBoris Ostrovsky } 1071e620f9bSBoris Ostrovsky 1081e620f9bSBoris Ostrovsky pl2p++; 1091e620f9bSBoris Ostrovsky } 1101e620f9bSBoris Ostrovsky 1111e620f9bSBoris Ostrovsky ptr = (unsigned long *)__pa(&max_pfn_mapped); 1121e620f9bSBoris Ostrovsky /* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */ 1131e620f9bSBoris Ostrovsky *ptr = (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT; 1141e620f9bSBoris Ostrovsky 1151e620f9bSBoris Ostrovsky ptr = (unsigned long *)__pa(&_brk_end); 1161e620f9bSBoris Ostrovsky *ptr = (unsigned long)ptep + PAGE_OFFSET; 1171e620f9bSBoris Ostrovsky } 1181e620f9bSBoris Ostrovsky 119