2008-02-23 09:58:20 +01:00
/*
* linux / arch / i386 / kernel / head32 . c - - prepare to run common code
*
* Copyright ( C ) 2000 Andrea Arcangeli < andrea @ suse . de > SuSE
* Copyright ( C ) 2007 Eric Biederman < ebiederm @ xmission . com >
*/
# include <linux/init.h>
# include <linux/start_kernel.h>
x86: Make sure free_init_pages() frees pages on page boundary
When CONFIG_NO_BOOTMEM=y, it could use memory more effiently, or
in a more compact fashion.
Example:
Allocated new RAMDISK: 00ec2000 - 0248ce57
Move RAMDISK from 000000002ea04000 - 000000002ffcee56 to 00ec2000 - 0248ce56
The new RAMDISK's end is not page aligned.
Last page could be shared with other users.
When free_init_pages are called for initrd or .init, the page
could be freed and we could corrupt other data.
code segment in free_init_pages():
| for (; addr < end; addr += PAGE_SIZE) {
| ClearPageReserved(virt_to_page(addr));
| init_page_count(virt_to_page(addr));
| memset((void *)(addr & ~(PAGE_SIZE-1)),
| POISON_FREE_INITMEM, PAGE_SIZE);
| free_page(addr);
| totalram_pages++;
| }
last half page could be used as one whole free page.
So page align the boundaries.
-v2: make the original initramdisk to be aligned, according to
Johannes, otherwise we have the chance to lose one page.
we still need to keep initrd_end not aligned, otherwise it could
confuse decompressor.
-v3: change to WARN_ON instead, suggested by Johannes.
-v4: use PAGE_ALIGN, suggested by Johannes.
We may fix that macro name later to PAGE_ALIGN_UP, and PAGE_ALIGN_DOWN
Add comments about assuming ramdisk start is aligned
in relocate_initrd(), change to re get ramdisk_image instead of save it
to make diff smaller. Add warning for wrong range, suggested by Johannes.
-v6: remove one WARN()
We need to align beginning in free_init_pages()
do not copy more than ramdisk_size, noticed by Johannes
Reported-by: Stanislaw Gruszka <sgruszka@redhat.com>
Tested-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: David Miller <davem@davemloft.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
LKML-Reference: <1269830604-26214-3-git-send-email-yinghai@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-28 19:42:55 -07:00
# include <linux/mm.h>
2010-08-25 13:39:17 -07:00
# include <linux/memblock.h>
2008-02-23 09:58:20 +01:00
2017-08-28 08:47:48 +02:00
# include <asm/desc.h>
2008-05-18 01:18:57 -07:00
# include <asm/setup.h>
# include <asm/sections.h>
2017-01-27 10:27:10 +01:00
# include <asm/e820/api.h>
2009-08-19 14:36:27 +02:00
# include <asm/page.h>
2009-08-20 09:27:29 +02:00
# include <asm/apic.h>
# include <asm/io_apic.h>
2009-08-29 15:03:59 +02:00
# include <asm/bios_ebda.h>
2010-08-28 15:58:33 +02:00
# include <asm/tlbflush.h>
2013-01-29 01:05:24 -08:00
# include <asm/bootparam_utils.h>
2009-08-29 15:03:59 +02:00
static void __init i386_default_early_setup ( void )
{
2010-06-11 12:17:00 +02:00
/* Initialize 32bit specific setup functions */
2009-08-29 15:03:59 +02:00
x86_init . resources . reserve_resources = i386_reserve_resources ;
x86_init . mpparse . setup_ioapic_ids = setup_ioapic_ids_from_mpc ;
}
2008-05-18 01:18:57 -07:00
2014-05-02 00:44:37 +02:00
asmlinkage __visible void __init i386_start_kernel ( void )
2008-02-23 09:58:20 +01:00
{
2014-10-24 15:58:08 -07:00
cr4_init_shadow ( ) ;
2017-08-28 08:47:48 +02:00
idt_setup_early_handler ( ) ;
2013-01-29 01:05:24 -08:00
sanitize_boot_params ( & boot_params ) ;
2016-04-13 17:04:34 -07:00
x86_early_init_platform_quirks ( ) ;
2009-08-29 15:03:59 +02:00
/* Call the subarch specific early setup function */
switch ( boot_params . hdr . hardware_subarch ) {
2013-10-17 15:35:29 -07:00
case X86_SUBARCH_INTEL_MID :
x86_intel_mid_early_setup ( ) ;
2009-08-29 14:54:20 +02:00
break ;
2010-11-09 12:08:04 -08:00
case X86_SUBARCH_CE4100 :
x86_ce4100_early_setup ( ) ;
break ;
2009-08-29 15:03:59 +02:00
default :
i386_default_early_setup ( ) ;
break ;
}
2008-05-18 01:18:57 -07:00
2008-02-23 09:58:20 +01:00
start_kernel ( ) ;
}
2016-12-08 11:44:31 -05:00
/*
* Initialize page tables . This creates a PDE and a set of page
* tables , which are located immediately beyond __brk_base . The variable
* _brk_end is set up to point to the first " safe " location .
* Mappings are created both at virtual address 0 ( identity mapping )
* and PAGE_OFFSET for up to _end .
*
* In PAE mode initial_page_table is statically defined to contain
* enough entries to cover the VMSPLIT option ( that is the top 1 , 2 or 3
* entries ) . The identity mapping is handled by pointing two PGD entries
* to the first kernel PMD . Note the upper half of each PMD or PTE are
* always zero at this stage .
*/
void __init mk_early_pgtbl_32 ( void )
{
# ifdef __pa
# undef __pa
# endif
# define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
pte_t pte , * ptep ;
int i ;
unsigned long * ptr ;
/* Enough space to fit pagetables for the low memory linear map */
const unsigned long limit = __pa ( _end ) +
( PAGE_TABLE_SIZE ( LOWMEM_PAGES ) < < PAGE_SHIFT ) ;
# ifdef CONFIG_X86_PAE
pmd_t pl2 , * pl2p = ( pmd_t * ) __pa ( initial_pg_pmd ) ;
# define SET_PL2(pl2, val) { (pl2).pmd = (val); }
# else
pgd_t pl2 , * pl2p = ( pgd_t * ) __pa ( initial_page_table ) ;
# define SET_PL2(pl2, val) { (pl2).pgd = (val); }
# endif
ptep = ( pte_t * ) __pa ( __brk_base ) ;
pte . pte = PTE_IDENT_ATTR ;
while ( ( pte . pte & PTE_PFN_MASK ) < limit ) {
SET_PL2 ( pl2 , ( unsigned long ) ptep | PDE_IDENT_ATTR ) ;
* pl2p = pl2 ;
# ifndef CONFIG_X86_PAE
/* Kernel PDE entry */
* ( pl2p + ( ( PAGE_OFFSET > > PGDIR_SHIFT ) ) ) = pl2 ;
# endif
for ( i = 0 ; i < PTRS_PER_PTE ; i + + ) {
* ptep = pte ;
pte . pte + = PAGE_SIZE ;
ptep + + ;
}
pl2p + + ;
}
ptr = ( unsigned long * ) __pa ( & max_pfn_mapped ) ;
/* Can't use pte_pfn() since it's a call with CONFIG_PARAVIRT */
* ptr = ( pte . pte & PTE_PFN_MASK ) > > PAGE_SHIFT ;
ptr = ( unsigned long * ) __pa ( & _brk_end ) ;
* ptr = ( unsigned long ) ptep + PAGE_OFFSET ;
}