+++ /dev/null
-#include <lwk/kernel.h>
-#include <lwk/init.h>
-#include <lwk/cpuinfo.h>
-#include <lwk/bootmem.h>
-#include <lwk/smp.h>
-#include <arch/bootsetup.h>
-#include <arch/e820.h>
-#include <arch/page.h>
-#include <arch/sections.h>
-#include <arch/proto.h>
-#include <arch/mpspec.h>
-#include <arch/pda.h>
-#include <arch/io_apic.h>
-
-/**
- * Bitmap of of PTE/PMD entry flags that are supported.
- * This is AND'ed with a PTE/PMD entry before it is installed.
- */
-unsigned long __supported_pte_mask __read_mostly = ~0UL;
-
-/**
- * Bitmap of features enabled in the CR4 register.
- */
-unsigned long mmu_cr4_features;
-
-/**
- * Start and end addresses of the initrd image.
- */
-paddr_t __initdata initrd_start;
-paddr_t __initdata initrd_end;
-
-/**
- * The init_task ELF image.
- */
-paddr_t __initdata init_elf_image;
-
-/**
- * Base address and size of the Extended BIOS Data Area.
- */
-paddr_t __initdata ebda_addr;
-size_t __initdata ebda_size;
-#define EBDA_ADDR_POINTER 0x40E
-
-/**
- * Finds the address and length of the Extended BIOS Data Area.
- */
-static void __init
-discover_ebda(void)
-{
- /*
- * There is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E
- */
- ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
- ebda_addr <<= 4;
-
- ebda_size = *(unsigned short *)__va(ebda_addr);
-
- /* Round EBDA up to pages */
- if (ebda_size == 0)
- ebda_size = 1;
- ebda_size <<= 10;
- ebda_size = round_up(ebda_size + (ebda_addr & ~PAGE_MASK), PAGE_SIZE);
- if (ebda_size > 64*1024)
- ebda_size = 64*1024;
-}
-
-/**
- * This sets up the bootstrap memory allocator. It is a simple
- * bitmap based allocator that tracks memory at a page grandularity.
- * Once the bootstrap process is complete, each unallocated page
- * is added to the real memory allocator's free pool. Memory allocated
- * during bootstrap remains allocated forever, unless explicitly
- * freed before turning things over to the real memory allocator.
- */
-static void __init
-setup_bootmem_allocator(
- unsigned long start_pfn,
- unsigned long end_pfn
-)
-{
- unsigned long bootmap_size, bootmap;
-
- bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
- bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
- if (bootmap == -1L)
- panic("Cannot find bootmem map of size %ld\n",bootmap_size);
- bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
- e820_bootmem_free(0, end_pfn << PAGE_SHIFT);
- reserve_bootmem(bootmap, bootmap_size);
-}
-
-/**
- * Mark in-use memory regions as reserved.
- * This prevents the bootmem allocator from allocating them.
- */
-static void __init
-reserve_memory(void)
-{
- /* Reserve the kernel page table memory */
- reserve_bootmem(table_start << PAGE_SHIFT,
- (table_end - table_start) << PAGE_SHIFT);
-
- /* Reserve kernel memory */
- reserve_bootmem(__pa_symbol(&_text),
- __pa_symbol(&_end) - __pa_symbol(&_text));
-
- /* Reserve physical page 0... it's a often a special BIOS page */
- reserve_bootmem(0, PAGE_SIZE);
-
- /* Reserve the Extended BIOS Data Area memory */
- if (ebda_addr)
- reserve_bootmem(ebda_addr, ebda_size);
-
- /* Reserve SMP trampoline */
- reserve_bootmem(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
-
- /* Find and reserve boot-time SMP configuration */
- find_mp_config();
-
- /* Reserve memory used by the initrd image */
- if (LOADER_TYPE && INITRD_START) {
- if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
- printk(KERN_DEBUG
- "reserving memory used by initrd image\n");
- printk(KERN_DEBUG
- " INITRD_START=0x%lx, INITRD_SIZE=%ld bytes\n",
- (unsigned long) INITRD_START,
- (unsigned long) INITRD_SIZE);
- reserve_bootmem(INITRD_START, INITRD_SIZE);
- initrd_start = INITRD_START;
- initrd_end = initrd_start+INITRD_SIZE;
- init_elf_image = initrd_start;
- } else {
- printk(KERN_ERR
- "initrd extends beyond end of memory "
- "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
- (unsigned long)(INITRD_START + INITRD_SIZE),
- (unsigned long)(end_pfn << PAGE_SHIFT));
- initrd_start = 0;
- }
- }
-}
-
-/**
- * This initializes a per-CPU area for each CPU.
- *
- * TODO: The PDA and per-CPU areas are pretty tightly wound. It should be
- * possible to make the per-CPU area *be* the PDA, or put another way,
- * point %GS at the per-CPU area rather than the PDA. All of the PDA's
- * current contents would become normal per-CPU variables.
- */
-static void __init
-setup_per_cpu_areas(void)
-{
- int i;
- size_t size;
-
- /*
- * There is an ELF section containing all per-CPU variables
- * surrounded by __per_cpu_start and __per_cpu_end symbols.
- * We create a copy of this ELF section for each CPU.
- */
- size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
-
- for_each_cpu_mask (i, cpu_present_map) {
- char *ptr;
-
- ptr = alloc_bootmem_aligned(size, PAGE_SIZE);
- if (!ptr)
- panic("Cannot allocate cpu data for CPU %d\n", i);
-
- /*
- * Pre-bias data_offset by subtracting its offset from
- * __per_cpu_start. Later, per_cpu() will calculate a
- * per_cpu variable's address with:
- *
- * addr = offset_in_percpu_ELF_section + data_offset
- * = (__per_cpu_start + offset) + (ptr - __per_cpu_start)
- * = offset + ptr
- */
- cpu_pda(i)->data_offset = ptr - __per_cpu_start;
-
- memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
- }
-}
-
-static inline int get_family(int cpuid)
-{
- int base = (cpuid>>8) & 0xf;
- int extended = (cpuid>>20) &0xff;
-
- return (0xf == base) ? base + extended : base;
-}
-
-/**
- * Architecture specific initialization.
- * This is called from start_kernel() in init/main.c.
- *
- * NOTE: Ordering is usually important. Do not move things
- * around unless you know what you are doing.
- */
-void __init
-setup_arch(void)
-{
- /*
- * Figure out which memory regions are usable and which are reserved.
- * This builds the "e820" map of memory from info provided by the
- * BIOS.
- */
- setup_memory_region();
-
- /*
- * Get the bare minimum info about the bootstrap CPU... the
- * one we're executing on right now. Latter on, the full
- * boot_cpu_data and cpu_info[boot_cpu_id] structures will be
- * filled in completely.
- */
- boot_cpu_data.logical_id = 0;
- early_identify_cpu(&boot_cpu_data);
-
- /*
- * Find the Extended BIOS Data Area.
- * (Not sure why exactly we need this, probably don't.)
- */
- discover_ebda();
-
- /*
- * Initialize the kernel page tables.
- * The kernel page tables map an "identity" map of all physical memory
- * starting at virtual address PAGE_OFFSET. When the kernel executes,
- * it runs inside of the identity map... memory below PAGE_OFFSET is
- * from whatever task was running when the kernel got invoked.
- */
- init_kernel_pgtables(0, (end_pfn_map << PAGE_SHIFT));
-
- /*
- * Initialize the bootstrap dynamic memory allocator.
- * alloc_bootmem() will work after this.
- */
- setup_bootmem_allocator(0, end_pfn);
- reserve_memory();
-
- /*
- * Get the multiprocessor configuration...
- * number of CPUs, PCI bus info, APIC info, etc.
- */
- get_mp_config();
-
- /*
- * Initialize resources. Resources reserve sections of normal memory
- * (iomem) and I/O ports (ioport) for devices and other system
- * resources. For each resource type, there is a tree which tracks
- * which regions are in use. This eliminates the possiblity of
- * conflicts... e.g., two devices trying to use the same iomem region.
- */
- init_resources();
-
- /*
- * Initialize per-CPU areas, one per CPU.
- * Variables defined with DEFINE_PER_CPU() end up in the per-CPU area.
- * This provides a mechanism for different CPUs to refer to their
- * private copy of the variable using the same name
- * (e.g., get_cpu_var(foo)).
- */
- setup_per_cpu_areas();
-
- /*
- * Initialize the IDT table and interrupt handlers.
- */
- interrupts_init();
-
- /*
- * Map the APICs into the kernel page tables.
- *
- * Each CPU has its own Local APIC. All Local APICs are memory mapped
- * to the same virtual address region. A CPU accesses its Local APIC by
- * accessing the region. A CPU cannot access another CPU's Local APIC.
- *
- * Each Local APIC is connected to all IO APICs in the system. Each IO
- * APIC is mapped to a different virtual address region. A CPU accesses
- * a given IO APIC by accessing the appropriate region. All CPUs can
- * access all IO APICs.
- */
- lapic_map();
- ioapic_map();
-
- /*
- * Initialize the virtual system call code/data page.
- * The vsyscall page is mapped into every task's address space at a
- * well-known address. User code can call functions in this page
- * directly, providing a light-weight mechanism for read-only system
- * calls such as gettimeofday().
- */
- vsyscall_map();
-
- cpu_init();
-
- current->cpumask = cpu_present_map;
-
- ioapic_init();
-
- lapic_set_timer(1000000000);
-}
-