linux/arch/e2k/p2v/boot_head.c

508 lines
14 KiB
C

/* $Id: boot_head.c,v 1.41 2009/02/24 15:15:42 atic Exp $
*
* Control of boot-time initialization.
*
* Copyright (C) 2001 Salavat Guiliazov <atic@mcst.ru>
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <stdarg.h>
#include <asm/types.h>
#include <asm/boot_head.h>
#include <asm/boot_init.h>
#include <asm/errors_hndl.h>
#include <asm/console.h>
#include <asm/current.h>
#include <asm/thread_info.h>
#include <asm/atomic.h>
#include <asm/e2k_debug.h>
#include <asm/console.h>
#include <asm/bootinfo.h>
#include <asm/regs_state.h>
#ifdef CONFIG_RECOVERY
#include <asm/boot_recovery.h>
#include <asm/cnt_point.h>
#endif /* CONFIG_RECOVERY */
#include <asm/mmu_regs_access.h>
#undef DEBUG_BOOT_MODE
#undef boot_printk
#undef DebugB
#undef DEBUG_BOOT_INFO_MODE
#define DEBUG_BOOT_MODE 0 /* Boot process */
#define DEBUG_BOOT_INFO_MODE 0 /* Boot info */
#define boot_printk if (DEBUG_BOOT_MODE) do_boot_printk
#define DebugB if (DEBUG_BOOT_MODE) printk
#undef DebugSMP
#undef DEBUG_BOOT_SMP_MODE
#define DEBUG_BOOT_SMP_MODE 0
#define DebugSMP if (DEBUG_BOOT_SMP_MODE) do_boot_printk
extern void start_kernel(void);
static void __init boot_setup(bootblock_struct_t *bootblock);
static void __init init_switch_to_kernel_stack(int cpuid);
static void __init boot_init_sequel(void);
/*
* Current CPU logical number and total number of active CPUs
*/
atomic_t boot_cpucount = ATOMIC_INIT(0);
static raw_spinlock_t __initdata boot_cpu_hotplug_lock =
__RAW_SPIN_LOCK_UNLOCKED(boot_cpu_hotplug_lock);
#ifndef CONFIG_SMP
unsigned char boot_init_started = 0; /* boot-time initialization */
/* has been started */
unsigned char _va_support_on = 0; /* virtual addressing support */
/* has turned on */
#else
unsigned char boot_init_started[NR_CPUS] = { [0 ... (NR_CPUS-1)] = 0 };
/* boot-time initialization */
/* has been started on CPU */
unsigned char _va_support_on[NR_CPUS] = { [0 ... (NR_CPUS-1)] = 0 };
/* virtual addressing support */
/* has turned on on CPU */
#endif /* CONFIG_SMP */
bootblock_struct_t *bootblock_phys; /* bootblock structure */
/* physical pointer */
bootblock_struct_t *bootblock_virt; /* bootblock structure */
/* virtual pointer */
/*
* Control process of boot-time initialization.
* Loader or bootloader program should call this function to start boot
* process of the system. The function provide for virtual memory support
* and switching to execution into the virtual space. The following part
* of initialization should be made by 'boot_init_sequel()' function, which
* will be run with virtula environment support.
*/
void __init
boot_init(bootblock_struct_t *bootblock)
{
register int cpuid;
cpuid = boot_smp_get_processor_id();
boot_smp_set_processor_id(cpuid);
#ifndef CONFIG_SMP
if (!IS_BOOT_STRAP_CPU()) {
boot_atomic_dec(&boot_cpucount);
while (1) /* Idle if not boot CPU */
cpu_relax();
} else {
#endif /* !CONFIG_SMP */
boot_set_cpu_possible(cpuid);
boot_set_cpu_present(cpuid);
#ifndef CONFIG_SMP
}
#endif /* !CONFIG_SMP */
/*
* Preserve recursive call of boot, if some trap occured
* while trap table is not installed
*/
if (boot_boot_init_started) {
if (boot_va_support_on) {
INIT_BUG_POINT("boot_init");
INIT_BUG("Recursive call of boot_init(), perhaps, due "
"to trap\n");
} else {
BOOT_BUG_POINT("boot_init");
BOOT_BUG("Recursive call of boot_init(), perhaps, due "
"to trap\n");
}
} else {
boot_boot_init_started = 1;
}
/*
* Initialize virtual memory support for farther system boot and
* switch sequel initialization to the function 'boot_init_sequel()'
* into the real virtual space. Should not be return here.
*/
boot_printk("Kernel boot-time initialization started\n");
boot_setup(bootblock);
boot_mem_init(boot_init_sequel);
}
/*
* Setup the needed things to start boot-time initialization.
*/
#ifdef CONFIG_SMP
static atomic_t __initdata boot_info_setup_finished = ATOMIC_INIT(0);
#endif /* CONFIG_SMP */
static void __init
boot_setup(bootblock_struct_t *bootblock)
{
register boot_info_t *boot_info = &bootblock->info;
register e2k_rwap_lo_struct_t reg_lo = {{ 0 }};
register e2k_rwap_hi_struct_t reg_hi = {{ 0 }};
register e2k_addr_t addr;
register e2k_size_t size;
#ifdef CONFIG_NUMA
unsigned int cpuid;
#endif
/*
* Set 'data/bss' segment CPU registers OSGD & GD
* to kernel image unit
*/
addr = (e2k_addr_t)_sdata;
if (addr & E2K_ALIGN_OS_GLOBALS_MASK) {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("Kernel 'data' segment start address 0x%lx is not "
"aligned to alignment mask 0x%lx\n",
addr, E2K_ALIGN_OS_GLOBALS_MASK);
}
addr = (e2k_addr_t)boot_vp_to_pp(_sdata);
reg_lo.GD_lo_base = addr;
reg_lo._GD_lo_rw = E2K_GD_RW_PROTECTIONS;
size = (e2k_addr_t)_end - (e2k_addr_t)_sdata;
size = ALIGN_MASK(size, E2K_ALIGN_OS_GLOBALS_MASK);
reg_hi.GD_hi_size = size;
reg_hi._GD_hi_curptr = 0;
WRITE_GD_REG(reg_hi, reg_lo);
WRITE_OSGD_REG(reg_hi, reg_lo);
boot_printk("Kernel DATA/BSS segment pointers OSGD & GD are set to "
"base physical address 0x%lx size 0x%lx\n",
addr, size);
#ifdef CONFIG_SMP
boot_printk("Kernel boot-time initialization in progress on CPU %d "
"APIC id %d\n",
boot_smp_processor_id(), GET_APIC_ID(arch_apic_read(APIC_ID)));
#endif /* CONFIG_SMP */
#ifdef CONFIG_NUMA
/*
* Do initialization of CPUs possible and present masks again because
* these masks could be cleared while BSS cleaning
*/
cpuid = boot_smp_processor_id();
boot_set_cpu_possible(cpuid);
boot_set_cpu_present(cpuid);
/*
* Do this initialization after BSS is cleared but before
* .node.data is duplicated.
*/
boot___cpu_to_node[cpuid] = boot_numa_node_id();
#endif
/*
* Set 'text' segment CPU registers OSCUD & CUD
* to kernel image unit
*/
addr = (e2k_addr_t)_start;
if (addr & E2K_ALIGN_OSCU_MASK) {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("Kernel 'text' segment start address 0x%lx is not "
"aligned to alignment mask 0x%lx\n",
addr, E2K_ALIGN_OSCU_MASK);
}
addr = (e2k_addr_t)boot_vp_to_pp(_start);
reg_lo.CUD_lo_base = addr;
reg_lo.CUD_lo_c = E2K_CUD_CHECKED_FLAG;
reg_lo._CUD_lo_rw = E2K_CUD_RW_PROTECTIONS;
size = (e2k_addr_t)_etext - (e2k_addr_t)_start;
size = ALIGN_MASK(size, E2K_ALIGN_OSCU_MASK);
reg_hi.CUD_hi_size = size;
reg_hi._CUD_hi_curptr = 0;
WRITE_CUD_REG(reg_hi, reg_lo);
WRITE_OSCUD_REG(reg_hi, reg_lo);
boot_printk("Kernel TEXT segment pointers OSCUD & CUD are set to "
"base physical address 0x%lx size 0x%lx\n",
addr, size);
if (addr != bootblock->info.kernel_base) {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("Kernel start address 0x%lx is not the same as "
"base address to load kernel in bootblock structure "
"0x%lx\n",
addr, bootblock->info.kernel_base);
}
if (size > bootblock->info.kernel_size) {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("Kernel size 0x%lx is not the same as size to load "
"kernel in bootblock structure 0x%lx\n",
size, bootblock->info.kernel_size);
}
/*
* Set Trap Cellar pointer and MMU register to kernel image area
* and reset Trap Counter register
* In NUMA mode now we set pointer to base trap cellar on
* bootstrap nnode
*/
set_MMU_TRAP_POINT(boot_trap_cellar);
reset_MMU_TRAP_COUNT();
boot_printk("Kernel trap cellar set to physical address 0x%lx "
"MMU_TRAP_CELLAR_MAX_SIZE 0x%x kernel_trap_cellar 0x%lx\n",
boot_kernel_trap_cellar, MMU_TRAP_CELLAR_MAX_SIZE,
KERNEL_TRAP_CELLAR);
/*
* Remember phys. address of boot information block in
* an appropriate data structure.
*/
#ifdef CONFIG_SMP
if (IS_BOOT_STRAP_CPU()) {
#endif /* CONFIG_SMP */
boot_bootinfo_phys_base = (e2k_addr_t) bootblock;
/*
* error for 18 compiler
boot_bootblock_phys = bootblock;
*/
boot_bootblock_phys_write = bootblock;
boot_printk("Boot information physical address: 0x%lx\n",
boot_info);
if (boot_info->signature == ROMLOADER_SIGNATURE) {
boot_printk("Boot information passed by ROMLOADER\n");
} else if (boot_info->signature == X86BOOT_SIGNATURE) {
boot_printk("Boot information passed by BIOS (x86)\n");
} else {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("Boot information passed by unknown loader\n");
}
if (DEBUG_BOOT_INFO_MODE) {
int i;
for (i = 0; i < sizeof(bootblock_struct_t) / 8; i ++) {
do_boot_printk("boot_info[%d] = 0x%lx\n",
i, ((u64 *)boot_info)[i]);
}
}
#ifdef CONFIG_RECOVERY
boot_recovery_cnt_points(bootblock);
#endif /* CONFIG_RECOVERY */
#ifdef CONFIG_SMP
boot_setup_smp_cpu_config();
boot_set_event(&boot_info_setup_finished);
} else {
boot_wait_for_event(&boot_info_setup_finished);
if (boot_smp_processor_id() >= NR_CPUS) {
BOOT_BUG_POINT("boot_setup()");
BOOT_BUG("CPU #%d : this processor number >= than "
"max supported CPU number %d\n",
boot_smp_processor_id(),
NR_CPUS);
}
}
#endif /* CONFIG_SMP */
}
/*
* Sequel of process of initialization. This function is run into virtual
* space and controls farther system boot
*/
static void __init
boot_init_sequel(void)
{
#ifdef CONFIG_SMP
register volatile int cpuid;
#else
#define cpuid 0
#endif /* CONFIG_SMP */
va_support_on = 1;
#ifdef CONFIG_SMP
cpuid = init_smp_processor_id();
#endif /* CONFIG_SMP */
/*
* Sometimes boot forgets to pass CPUs through MP table, so one should
* setup some variables manually.
*/
#if defined(CONFIG_SMP) || defined(CONFIG_L_X86_64)
early_per_cpu(x86_cpu_to_apicid, cpuid) = cpuid;
early_per_cpu(x86_bios_cpu_apicid, cpuid) = cpuid;
#endif
EARLY_BOOT_TRACEPOINT("SYNCHRONIZATION POINT #3");
#ifdef CONFIG_SMP
/*
* SYNCHRONIZATION POINT #3
* At this point all processors should complete switching to
* virtual memory
* After synchronization all processors can terminate
* boot-time initialization of virtual memory support
*/
(void) boot_sync_all_processors(BOOT_NO_ERROR_FLAG);
#endif /* CONFIG_SMP */
#ifdef CONFIG_SMP
if (IS_BOOT_STRAP_CPU())
#endif
EARLY_BOOT_TRACEPOINT("kernel boot-time init finished");
/*
* Initialize dump_printk() - simple printk() which
* outputs straight to the serial port.
*/
#if defined(CONFIG_SERIAL_PRINTK)
setup_serial_dump_console(&bootblock_virt->info);
#endif
/*
* Set pointer of current task structure to kernel initial task
*/
#ifdef CONFIG_SMP
if (IS_BOOT_STRAP_CPU()) {
#endif /* CONFIG_SMP */
set_current_thread_info(&init_thread_info, &init_task);
DebugB("'current' thread pointer is set to initial kernel "
"thread structure virtual address 0x%p size 0x%lx\n",
&init_thread_info, THREAD_SIZE);
set_task_thread_info(&init_task, &init_thread_info);
#ifdef CONFIG_SMP
init_tasks[cpuid] = &init_task;
current_thread_info()->cpu = cpuid;
E2K_SET_DGREG_NV(19, (u64) cpuid);
E2K_WAIT_ALL;
SAVE_USER_ONLY_REGS(current); /* to save initial state of */
/* debugging registers to enable */
/* hardware breakpoints */
init_reset_smp_processors_num();
}
#endif /* CONFIG_SMP */
/*
* Show disabled caches
*/
#ifdef CONFIG_SMP
if (IS_BOOT_STRAP_CPU()) {
#endif /* CONFIG_SMP */
if (disable_caches != _MMU_CD_EN) {
if (disable_caches == _MMU_CD_D1_DIS)
pr_info("Disable L1 cache\n");
else if (disable_caches == _MMU_CD_D_DIS)
pr_info("Disable L1 and L2 caches\n");
else if (disable_caches == _MMU_CD_DIS)
pr_info("Disable L1, L2 and L3 caches\n");
}
if (disable_secondary_caches)
pr_info("Disable secondary INTEL caches\n");
if (disable_IP == _MMU_IPD_DIS)
pr_info("Disable IB prefetch\n");
DebugB("MMU CR 0x%llx\n", READ_MMU_CR());
#ifdef CONFIG_SMP
}
#endif /* CONFIG_SMP */
/*
* Flush instruction and data cashes to delete all physical
* instruction and data pages
*/
flush_ICACHE_all();
/*
* Terminate boot-time initialization of virtual memory support
*/
init_mem_term(cpuid);
/*
* Switch from boot-time stacks to kernel initial stacks and
* start kernel initialization process.
*/
init_switch_to_kernel_stack(cpuid);
#ifndef CONFIG_SMP
#undef cpuid
#endif /* CONFIG_SMP */
}
#ifdef CONFIG_SMP
static void __init
init_start_secondary_cpu(int cpuid)
{
DebugSMP("init_start_secondary_cpu() cpuid %d, machine id 0x%x virt "
"id 0x%x\n",
cpuid, machine_id, virt_machine_id);
if (!IS_VIRT_CPU_ENABLED(cpuid)) {
raw_spin_lock(&boot_cpu_hotplug_lock);
DebugSMP("CPU present number is %d, physical map: 0x%lx\n",
phys_cpu_present_num,
physids_coerce(&phys_cpu_present_map));
set_cpu_present(cpuid, 0);
physid_clear(cpuid, phys_cpu_present_map);
phys_cpu_present_num --;
DebugSMP("new CPU present number is %d, physical map: 0x%lx\n",
phys_cpu_present_num,
physids_coerce(&phys_cpu_present_map));
raw_spin_unlock(&boot_cpu_hotplug_lock);
#ifdef CONFIG_HOTPLUG_CPU
e2k_up_secondary(cpuid);
#endif /* CONFIG_HOTPLUG_CPU */
} else {
e2k_start_secondary(cpuid);
}
}
#endif
/*
* Switch from boot-time stacks to kernel initial stacks and start kernel
* initialization process.
* This stack will be cpu_idle() stack later
*/
static void __init
init_switch_to_kernel_stack(int cpuid)
{
SWITCH_TO_KERNEL_STACK(
kernel_init_ps_virt_base(cpuid), kernel_init_ps_size(cpuid),
kernel_init_pcs_virt_base(cpuid), kernel_init_pcs_size(cpuid),
kernel_init_stack_virt_base(cpuid),
kernel_init_stack_size(cpuid));
/*
* Start kernel initialization on bootstrap processor.
* Other processors will do some internal initialization and wait
* for commands from bootstrap processor.
*/
#ifdef CONFIG_SMP
if (IS_BOOT_STRAP_CPU()) {
#endif /* CONFIG_SMP */
#if defined (CONFIG_RECOVERY) && (CONFIG_CNT_POINTS_NUM < 2)
if (dump_analyze_opt)
init_dump_analyze_mode();
#endif /* CONFIG_RECOVERY && (CNT_POINTS_NUM < 2) */
start_kernel();
#ifdef CONFIG_SMP
} else {
init_start_secondary_cpu(cpuid);
}
#endif /* CONFIG_SMP */
/*
* Never should be here
*/
BUG();
}