Chinaunix首页 | 论坛 | 博客
  • 博客访问: 439295
  • 博文数量: 123
  • 博客积分: 2686
  • 博客等级: 少校
  • 技术积分: 1349
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-23 22:11
文章分类
文章存档

2012年(3)

2011年(10)

2010年(100)

2009年(10)

我的朋友

分类: LINUX

2010-10-15 11:49:58

The setup_arch() function in arch/i386/kernel/setup.c is cast to the __init type where it runs only once at system initialization time. The setup_arch() function takes in a pointer to any Linux command-line data entered at boot time and initializes many of the architecture-specific subsystems, such as memory, I/O, processors, and consoles:

/*
 * Determine if we were loaded by an EFI loader. If so, then we have also been
 * passed the efi memmap, systab, etc., so we should use these data structures
 * for initialization. Note, the efi init code path is determined by the
 * global efi_enabled. This allows the same kernel image to be used on existing
 * systems (with a traditional BIOS) as well as on EFI systems.
 */
/*
 * setup_arch - architecture-specific boot-time initializations
 *
 * Note: On x86_64, fixmaps are ready for use even before this is called.
 */

void __init setup_arch(char **cmdline_p)
{
    int acpi = 0;
    int k8 = 0;

#ifdef CONFIG_X86_32

//see below comment 1

    memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
    visws_early_detect();
#else

//see below comment 2
    printk(KERN_INFO "Command line: %s\n", boot_command_line);
#endif

    /* VMI may relocate the fixmap; do this before touching ioremap area */
    vmi_init();

    early_trap_init();
    early_cpu_init();//Identify the specific processor

    early_ioremap_init();
//see below comment 3, ROOT_DEV is a global variable
    ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev);
    screen_info = boot_params.screen_info;
    edid_info = boot_params.edid_info;
#ifdef CONFIG_X86_32
    apm_info.bios = boot_params.apm_bios_info;
    ist_info = boot_params.ist_info;
    if (boot_params.sys_desc_table.length != 0) {
        set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
        machine_id = boot_params.sys_desc_table.table[0];
        machine_submodel_id = boot_params.sys_desc_table.table[1];
        BIOS_revision = boot_params.sys_desc_table.table[2];
    }
#endif
    saved_video_mode = boot_params.hdr.vid_mode;
    bootloader_type = boot_params.hdr.type_of_loader;
    if ((bootloader_type >> 4) == 0xe) {
        bootloader_type &= 0xf;
        bootloader_type |= (boot_params.hdr.ext_loader_type+0x10) << 4;
    }
    bootloader_version = bootloader_type & 0xf;
    bootloader_version |= boot_params.hdr.ext_loader_ver << 4;

#ifdef CONFIG_BLK_DEV_RAM
    rd_image_start = boot_params.hdr.ram_size & RAMDISK_IMAGE_START_MASK;
    rd_prompt = ((boot_params.hdr.ram_size & RAMDISK_PROMPT_FLAG) != 0);
    rd_doload = ((boot_params.hdr.ram_size & RAMDISK_LOAD_FLAG) != 0);
#endif
#ifdef CONFIG_EFI
    if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
#ifdef CONFIG_X86_32
         "EL32",
#else
         "EL64",
#endif
     4)) {
        efi_enabled = 1;
        efi_reserve_early();
    }
#endif

    x86_init.oem.arch_setup();


//see below comment 4
    setup_memory_map();

//parse boot_params
    parse_setup_data();
    /* update the e820_saved too */
    e820_reserve_setup_data();
/**
 * copy_edd() - Copy the BIOS EDD information
 *              from boot_params into a safe place.
 */
    copy_edd();

    if (!boot_params.hdr.root_flags)
        root_mountflags &= ~MS_RDONLY;

//see below comment 5,Initialize memory-management structs from the BIOS-provided memory map.
    init_mm.start_code = (unsigned long) _text;
    init_mm.end_code = (unsigned long) _etext;
    init_mm.end_data = (unsigned long) _edata;
    init_mm.brk = _brk_end;

    code_resource.start = virt_to_phys(_text);
    code_resource.end = virt_to_phys(_etext)-1;
    data_resource.start = virt_to_phys(_etext);
    data_resource.end = virt_to_phys(_edata)-1;
    bss_resource.start = virt_to_phys(&__bss_start);
    bss_resource.end = virt_to_phys(&__bss_stop)-1;

#ifdef CONFIG_CMDLINE_BOOL
#ifdef CONFIG_CMDLINE_OVERRIDE
    strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
    if (builtin_cmdline[0]) {
        /* append boot loader cmdline to builtin */
        strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
        strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
        strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
    }
#endif
#endif

    strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
    *cmdline_p = command_line;

    /*
     * x86_configure_nx() is called before parse_early_param() to detect
     * whether hardware doesn't support NX (so that the early EHCI debug
     * console setup can safely call set_fixmap()). It may then be called
     * again from within noexec_setup() during parsing early parameters
     * to honor the respective command line option.
     */
    x86_configure_nx();

//see below comment 6
    parse_early_param();

    x86_report_nx();

    /* Must be before kernel pagetables are setup */
    vmi_activate();

    /* after early param, so could get panic from serial */
    reserve_early_setup_data();

    if (acpi_mps_check()) {
#ifdef CONFIG_X86_LOCAL_APIC
        disable_apic = 1;
#endif
        setup_clear_cpu_cap(X86_FEATURE_APIC);
    }

#ifdef CONFIG_PCI
    if (pci_early_dump_regs)
        early_dump_pci_devices();
#endif

    finish_e820_parsing();

    if (efi_enabled)
        efi_init();

    dmi_scan_machine();

    dmi_check_system(bad_bios_dmi_table);

    /*
     * VMware detection requires dmi to be available, so this
     * needs to be done after dmi_scan_machine, for the BP.
     */
    init_hypervisor_platform();

    x86_init.resources.probe_roms();

    /* after parse_early_param, so could debug it */
    insert_resource(&iomem_resource, &code_resource);
    insert_resource(&iomem_resource, &data_resource);
    insert_resource(&iomem_resource, &bss_resource);

    trim_bios_range();
#ifdef CONFIG_X86_32
    if (ppro_with_ram_bug()) {
        e820_update_range(0x70000000ULL, 0x40000ULL, E820_RAM,
                 E820_RESERVED);
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
        printk(KERN_INFO "fixed physical RAM map:\n");
        e820_print_map("bad_ppro");
    }
#else
    early_gart_iommu_check();
#endif

    /*
     * partially used pages are not usable - thus
     * we are rounding upwards:
     */
    max_pfn = e820_end_of_ram_pfn();

    /* preallocate 4k for mptable mpc */
    early_reserve_e820_mpc_new();
    /* update e820 for memory not covered by WB MTRRs */
    mtrr_bp_init();
    if (mtrr_trim_uncached_memory(max_pfn))
        max_pfn = e820_end_of_ram_pfn();

#ifdef CONFIG_X86_32
    /* max_low_pfn get updated here */
    find_low_pfn_range();
#else
    num_physpages = max_pfn;

    check_x2apic();

    /* How many end-of-memory variables you have, grandma! */
    /* need this before calling reserve_initrd */
    if (max_pfn > (1UL<<(32 - PAGE_SHIFT)))
        max_low_pfn = e820_end_of_low_ram_pfn();
    else
        max_low_pfn = max_pfn;

    high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
    max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
#endif

#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
    setup_bios_corruption_check();
#endif

    printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
            max_pfn_mapped<
    reserve_brk();

    /*
     * Find and reserve possible boot-time SMP configuration:
     */
    find_smp_config();

    reserve_ibft_region();

    reserve_trampoline_memory();

#ifdef CONFIG_ACPI_SLEEP
    /*
     * Reserve low memory region for sleep support.
     * even before init_memory_mapping
     */
    acpi_reserve_wakeup_memory();
#endif
    init_gbpages();

    /* max_pfn_mapped is updated here */
    max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<     max_pfn_mapped = max_low_pfn_mapped;

#ifdef CONFIG_X86_64
    if (max_pfn > max_low_pfn) {
        max_pfn_mapped = init_memory_mapping(1UL<<32,
                         max_pfn<         /* can we preseve max_low_pfn ?*/
        max_low_pfn = max_pfn;
    }
#endif

    /*
     * NOTE: On x86-32, only from this point on, fixmaps are ready for use.
     */

#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
    if (init_ohci1394_dma_early)
        init_ohci1394_dma_on_all_controllers();
#endif

    reserve_initrd();

    reserve_crashkernel();

    vsmp_init();

    io_delay_init();

    /*
     * Parse the ACPI tables for possible boot-time SMP configuration.
     */
    acpi_boot_table_init();

    early_acpi_boot_init();

#ifdef CONFIG_ACPI_NUMA
    /*
     * Parse SRAT to discover nodes.
     */
    acpi = acpi_numa_init();
#endif

#ifdef CONFIG_K8_NUMA
    if (!acpi)
        k8 = !k8_numa_init(0, max_pfn);
#endif

    initmem_init(0, max_pfn, acpi, k8);
#ifndef CONFIG_NO_BOOTMEM
    early_res_to_bootmem(0, max_low_pfn< #endif

    dma32_reserve_bootmem();

#ifdef CONFIG_KVM_CLOCK
    kvmclock_init();
#endif

    x86_init.paging.pagetable_setup_start(swapper_pg_dir);
    paging_init();
    x86_init.paging.pagetable_setup_done(swapper_pg_dir);

    tboot_probe();

#ifdef CONFIG_X86_64
    map_vsyscall();
#endif

    generic_apic_probe();

    early_quirks();

    /*
     * Read APIC and some other early information from ACPI tables.
     */
    acpi_boot_init();

    sfi_init();

    /*
     * get boot-time SMP configuration:
     */
    if (smp_found_config)
        get_smp_config();

    prefill_possible_map();

#ifdef CONFIG_X86_64
    init_cpu_to_node();
#endif

    init_apic_mappings();
    ioapic_init_mappings();

    /* need to wait for io_apic is mapped */
    probe_nr_irqs_gsi();

    kvm_guest_init();

    e820_reserve_resources();
    e820_mark_nosave_regions(max_low_pfn);

    x86_init.resources.reserve_resources();

    e820_setup_gap();

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
    if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
        conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
    conswitchp = &dummy_con;
#endif
#endif
    x86_init.oem.banner();

    mcheck_init();
}


Comment 1:
new_cpu_data, boot_cpu_data are defined in arch/x86/kernel/setup.c, boot_cpu_data is filled at boot time.

#ifdef CONFIG_X86_32
/* cpu data as detected by the assembly code in head.S */
struct cpuinfo_x86 new_cpu_data __cpuinitdata = {0, 0, 0, 0, -1, 1, 0, 0, -1};
/* common cpu data for all cpus */
struct cpuinfo_x86 boot_cpu_data __read_mostly = {0, 0, 0, 0, -1, 1, 0, 0, -1};
EXPORT_SYMBOL(boot_cpu_data);


processor.h

/*
 * CPU type and hardware bug flags. Kept separately for each CPU.
 * Members of this structure are referenced in head.S, so think twice
 * before touching them. [mj]
 */

struct cpuinfo_x86 {
    __u8            x86;        /* CPU family */
    __u8            x86_vendor;    /* CPU vendor */
    __u8            x86_model;
    __u8            x86_mask;
#ifdef CONFIG_X86_32
    char            wp_works_ok;    /* It doesn't on 386's */

    /* Problems on some 486Dx4's and old 386's: */
    char            hlt_works_ok;
    char            hard_math;
    char            rfu;
    char            fdiv_bug;
    char            f00f_bug;
    char            coma_bug;
    char            pad0;
#else
    /* Number of 4K pages in DTLB/ITLB combined(in pages): */
    int            x86_tlbsize;
#endif
    __u8            x86_virt_bits;
    __u8            x86_phys_bits;
    /* CPUID returned core id bits: */
    __u8            x86_coreid_bits;
    /* Max extended CPUID function supported: */
    __u32            extended_cpuid_level;
    /* Maximum supported CPUID level, -1=no CPUID: */
    int            cpuid_level;
    __u32            x86_capability[NCAPINTS];
    char            x86_vendor_id[16];
    char            x86_model_id[64];
    /* in KB - valid for CPUS which support this call: */
    int            x86_cache_size;
    int            x86_cache_alignment;    /* In bytes */
    int            x86_power;
    unsigned long        loops_per_jiffy;
#ifdef CONFIG_SMP
    /* cpus sharing the last level cache: */
    cpumask_var_t        llc_shared_map;
#endif
    /* cpuid returned max cores value: */
    u16             x86_max_cores;
    u16            apicid;
    u16            initial_apicid;
    u16            x86_clflush_size;
#ifdef CONFIG_SMP
    /* number of cores as seen by the OS: */
    u16            booted_cores;
    /* Physical processor id: */
    u16            phys_proc_id;
    /* Core id: */
    u16            cpu_core_id;
    /* Index into per_cpu list: */
    u16            cpu_index;
#endif
} __attribute__((__aligned__(SMP_CACHE_BYTES)));




Comment 2:
boot_command_line is defined in init/main.c

/* Untouched command line saved by arch-specific code. */
char __initdata boot_command_line[COMMAND_LINE_SIZE];


Comment 3:
Global variable boot_params defined in arch/x86/kernel/setup.c

struct boot_params __initdata boot_params;


/* The so-called "zeropage" */
struct boot_params {
    struct screen_info screen_info;            /* 0x000 */
    struct apm_bios_info apm_bios_info;        /* 0x040 */
    __u8 _pad2[4];                    /* 0x054 */
    __u64 tboot_addr;                /* 0x058 */
    struct ist_info ist_info;            /* 0x060 */
    __u8 _pad3[16];                /* 0x070 */
    __u8 hd0_info[16];    /* obsolete! */        /* 0x080 */
    __u8 hd1_info[16];    /* obsolete! */        /* 0x090 */
    struct sys_desc_table sys_desc_table;        /* 0x0a0 */
    __u8 _pad4[144];                /* 0x0b0 */
    struct edid_info edid_info;            /* 0x140 */
    struct efi_info efi_info;            /* 0x1c0 */
    __u32 alt_mem_k;                /* 0x1e0 */
    __u32 scratch;        /* Scratch field! */    /* 0x1e4 */
    __u8 e820_entries;                /* 0x1e8 */
    __u8 eddbuf_entries;                /* 0x1e9 */
    __u8 edd_mbr_sig_buf_entries;            /* 0x1ea */
    __u8 _pad6[6];                    /* 0x1eb */
    struct setup_header hdr; /* setup header */    /* 0x1f1 */
    __u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
    __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];    /* 0x290 */
    struct e820entry e820_map[E820MAX];        /* 0x2d0 */
    __u8 _pad8[48];                /* 0xcd0 */
    struct edd_info eddbuf[EDDMAXNR];        /* 0xd00 */
    __u8 _pad9[276];                /* 0xeec */
} __attribute__((packed));



Comment 4:


dmesg | grep BIOS, print following message:

lee@LEE:~$ dmesg |grep BIOS
[    0.000000] BIOS-provided physical RAM map:
[    0.000000]  BIOS-e820: 0000000000000000 - 000000000009e400 (usable)
[    0.000000]  BIOS-e820: 000000000009e400 - 00000000000a0000 (reserved)
[    0.000000]  BIOS-e820: 00000000000dc000 - 0000000000100000 (reserved)
[    0.000000]  BIOS-e820: 0000000000100000 - 000000007d6a1000 (usable)
[    0.000000]  BIOS-e820: 000000007d6a1000 - 000000007d6a7000 (reserved)
[    0.000000]  BIOS-e820: 000000007d6a7000 - 000000007d7bd000 (usable)
[    0.000000]  BIOS-e820: 000000007d7bd000 - 000000007d80f000 (reserved)
[    0.000000]  BIOS-e820: 000000007d80f000 - 000000007d908000 (usable)
[    0.000000]  BIOS-e820: 000000007d908000 - 000000007db0f000 (reserved)
[    0.000000]  BIOS-e820: 000000007db0f000 - 000000007db19000 (usable)
[    0.000000]  BIOS-e820: 000000007db19000 - 000000007db1f000 (reserved)
[    0.000000]  BIOS-e820: 000000007db1f000 - 000000007db64000 (usable)
[    0.000000]  BIOS-e820: 000000007db64000 - 000000007db9f000 (ACPI NVS)
[    0.000000]  BIOS-e820: 000000007db9f000 - 000000007dc00000 (ACPI data)
[    0.000000]  BIOS-e820: 000000007dc00000 - 000000007de00000 (reserved)
[    0.000000]  BIOS-e820: 000000007e000000 - 0000000080000000 (reserved)
[    0.000000]  BIOS-e820: 00000000e0000000 - 00000000f0000000 (reserved)
[    0.000000]  BIOS-e820: 00000000fec00000 - 00000000fec10000 (reserved)
[    0.000000]  BIOS-e820: 00000000fed00000 - 00000000fed00400 (reserved)
[    0.000000]  BIOS-e820: 00000000fed10000 - 00000000fed14000 (reserved)
[    0.000000]  BIOS-e820: 00000000fed18000 - 00000000fed1a000 (reserved)
[    0.000000]  BIOS-e820: 00000000fed1c000 - 00000000fed90000 (reserved)
[    0.000000]  BIOS-e820: 00000000fee00000 - 00000000fee01000 (reserved)
[    0.000000]  BIOS-e820: 00000000ff800000 - 0000000100000000 (reserved)

Those message is printed in function setup_memory_map():

void __init setup_memory_map(void)
{
    char *who;

    who = x86_init.resources.memory_setup();
    memcpy(&e820_saved, &e820, sizeof(struct e820map));
    printk(KERN_INFO "BIOS-provided physical RAM map:\n");
    e820_print_map(who);
}


x86_init is a global variable defined in arch/x86/kernel/x86_init.c



/*
 * The platform setup functions are preset with the default functions
 * for standard PC hardware.
 */
struct x86_init_ops x86_init __initdata = {

    .resources = {
        .probe_roms        = x86_init_noop,
        .reserve_resources    = reserve_standard_io_resources,
        .memory_setup        = default_machine_specific_memory_setup,
    },

    .mpparse = {
        .mpc_record        = x86_init_uint_noop,
        .setup_ioapic_ids    = x86_init_noop,
        .mpc_apic_id        = default_mpc_apic_id,
        .smp_read_mpc_oem    = default_smp_read_mpc_oem,
        .mpc_oem_bus_info    = default_mpc_oem_bus_info,
        .find_smp_config    = default_find_smp_config,
        .get_smp_config        = default_get_smp_config,
    },

    .irqs = {
        .pre_vector_init    = init_ISA_irqs,
        .intr_init        = native_init_IRQ,
        .trap_init        = x86_init_noop,
    },

    .oem = {
        .arch_setup        = x86_init_noop,
        .banner            = default_banner,
    },

    .paging = {
        .pagetable_setup_start    = native_pagetable_setup_start,
        .pagetable_setup_done    = native_pagetable_setup_done,
    },

    .timers = {
        .setup_percpu_clockev    = setup_boot_APIC_clock,
        .tsc_pre_init        = x86_init_noop,
        .timer_init        = hpet_time_init,
    },

    .iommu = {
        .iommu_init        = iommu_init_noop,
    },

    .pci = {
        .init            = x86_default_pci_init,
        .init_irq        = x86_default_pci_init_irq,
        .fixup_irqs        = x86_default_pci_fixup_irqs,
    },
};


default_machine_specific_memory_setup() is defined in arch/x86/kernel/e820.c

char *__init default_machine_specific_memory_setup(void)
{
    char *who = "BIOS-e820";
    u32 new_nr;
    /*
     * Try to copy the BIOS-supplied E820-map.
     *
     * Otherwise fake a memory map; one section from 0k->640k,
     * the next section from 1mb->appropriate_mem_k
     */
    new_nr = boot_params.e820_entries;
    sanitize_e820_map(boot_params.e820_map,
            ARRAY_SIZE(boot_params.e820_map),
            &new_nr);
    boot_params.e820_entries = new_nr;
    if (append_e820_map(boot_params.e820_map, boot_params.e820_entries)
     < 0) {
        u64 mem_size;

        /* compare results from other methods and take the greater */
        if (boot_params.alt_mem_k
         < boot_params.screen_info.ext_mem_k) {
            mem_size = boot_params.screen_info.ext_mem_k;
            who = "BIOS-88";
        } else {
            mem_size = boot_params.alt_mem_k;
            who = "BIOS-e801";
        }

        e820.nr_map = 0;
        e820_add_region(0, LOWMEMSIZE(), E820_RAM);
        e820_add_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
    }

    /* In case someone cares... */
    return who;
}



Comment 5:
First, init_mm is a struct_mm type, define in init-mm.c, which belongs to process 0.

struct mm_struct init_mm = {
    .mm_rb        = RB_ROOT,
    .pgd        = swapper_pg_dir,
    .mm_users    = ATOMIC_INIT(2),
    .mm_count    = ATOMIC_INIT(1),
    .mmap_sem    = __RWSEM_INITIALIZER(init_mm.mmap_sem),
    .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
    .mmlist        = LIST_HEAD_INIT(init_mm.mmlist),
    .cpu_vm_mask    = CPU_MASK_ALL,
};


Second, _text, _textd, _datad represent kernel code segment and data segment.

阅读(1661) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-10-15 17:48:09

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com

chinaunix网友2010-10-15 17:47:59

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com