/** * \file kernel/init.c * License details are found in the file LICENSE. * \brief * main function and initializer * \author Taku Shimosawa \par * Copyright (C) 2011 - 2012 Taku Shimosawa * \author Balazs Gerofi \par * Copyright (C) 2012 RIKEN AICS * \author Tomoki Shirasawa \par * Copyright (C) 2012 - 2013 Hitachi, Ltd. * \author Balazs Gerofi \par * Copyright (C) 2013 The University of Tokyo */ /* * HISTORY: * 2013/09/02 shirasawa add terminate thread * 2013/06/02 balazs resolved merge conflicts with futex code * 2013/05/20 simin exchange the dcfa stuff init/exit order in mcexec */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define IOCTL_FUNC_EXTENSION #ifdef IOCTL_FUNC_EXTENSION #include #endif //#define DEBUG_PRINT_INIT #ifdef DEBUG_PRINT_INIT #define dkprintf(...) do { kprintf(__VA_ARGS__); } while (0) #define ekprintf(...) do { kprintf(__VA_ARGS__); } while (0) #else #define dkprintf(...) do { } while (0) #define ekprintf(...) do { kprintf(__VA_ARGS__); } while (0) #endif #define DUMP_LEVEL_USER_UNUSED_EXCLUDE 24 extern unsigned long ihk_mc_get_ns_per_tsc(void); extern long syscall(int, ihk_mc_user_context_t *); struct ihk_os_monitor *monitor; struct rusage_global *rusage; static void handler_init(void) { ihk_mc_set_syscall_handler(syscall); } unsigned long data[1024] __attribute__((aligned(64))); #ifdef USE_DMA static void dma_test(void) { struct ihk_dma_request req; unsigned long fin = 0; int i, j; for (j = 0; j < 2; ++j) { fin = 0; memset(data, 0, 1024 * sizeof(unsigned long)); for (i = 0; i < 8; i++) { data[i] = i; } kprintf("DMA Test Started.\n"); memset(&req, 0, sizeof(req)); req.src_os = IHK_THIS_OS; req.src_phys = virt_to_phys(data); req.dest_os = IHK_THIS_OS; req.dest_phys = virt_to_phys(&data[256]); req.size = 64; req.notify = (void *)virt_to_phys(&fin); req.notify_os = IHK_THIS_OS; req.priv = (void *)0x2984; kprintf("VtoP : %p, %lx\n", data, virt_to_phys(data)); kprintf("notify : %p, %lx (%lx)\n", &fin, virt_to_phys(&fin), sizeof(req)); if (ihk_mc_dma_request(0, &req) != 0) { kprintf("Failed to request DMA!\n"); } kprintf("DMA Test Wait.\n"); while (!fin) { barrier(); } kprintf("DMA Test End.\n"); for (i = 0; i < 8; i++) { if (data[i] != data[256 + i]) { kprintf("DMA result is inconsistent!\n"); panic(""); } } } } #endif extern char *ihk_get_kargs(void); char *find_command_line(char *name) { char *cmdline = ihk_get_kargs(); if (!cmdline) { return NULL; } return strstr(cmdline, name); } extern int safe_kernel_map; static void parse_kargs(void) { char *ptr; char *key_dump_level = "dump_level="; unsigned int dump_level = DUMP_LEVEL_USER_UNUSED_EXCLUDE; kprintf("KCommand Line: %s\n", ihk_get_kargs()); /* parse dump_level option */ ptr = find_command_line(key_dump_level); if (ptr) { ptr += strlen(key_dump_level); dump_level = 0; while (('0' <= *ptr) && (*ptr <= '9')) { dump_level *= 10; dump_level += *ptr++ - '0'; } } ihk_mc_set_dump_level(dump_level); ptr = find_command_line("safe_kernel_map"); if (ptr) { safe_kernel_map = 1; } /* idle_halt option */ ptr = find_command_line("idle_halt"); if (ptr) { idle_halt = 1; } /* allow_oversubscribe option */ ptr = find_command_line("allow_oversubscribe"); if (ptr) { allow_oversubscribe = 1; } } extern void ihk_mc_get_boot_time(unsigned long *tv_sec, unsigned long *tv_nsec); extern unsigned long ihk_mc_get_ns_per_tsc(void); static void time_init(void) { unsigned long tv_sec, tv_nsec; unsigned long ns_per_kclock; unsigned long tsc; ihk_mc_get_boot_time(&tv_sec, &tv_nsec); ns_per_kclock = ihk_mc_get_ns_per_tsc(); tod_data.origin.tv_sec = tv_sec; tod_data.origin.tv_nsec = tv_nsec; if (ns_per_kclock) { tod_data.clocks_per_sec = (1000L * NS_PER_SEC) / ns_per_kclock; tsc = rdtsc(); tod_data.origin.tv_sec -= tsc / tod_data.clocks_per_sec; tod_data.origin.tv_nsec -= NS_PER_SEC * (tsc % tod_data.clocks_per_sec) / tod_data.clocks_per_sec; if (tod_data.origin.tv_nsec < 0) { --tod_data.origin.tv_sec; tod_data.origin.tv_nsec += NS_PER_SEC; } } if (!ns_per_kclock) { gettime_local_support = 0; } if (gettime_local_support) { tod_data.do_local = 1; } return; } #ifdef POSTK_DEBUG_TEMP_FIX_73 /* NULL access for *monitor fix */ void monitor_init(void) #else /* POSTK_DEBUG_TEMP_FIX_73 */ static void monitor_init() #endif /* POSTK_DEBUG_TEMP_FIX_73 */ { int z; unsigned long phys; #ifdef POSTK_DEBUG_TEMP_FIX_73 /* NULL access for *monitor fix */ const struct ihk_mc_cpu_info *cpu_info = ihk_mc_get_cpu_info(); if (!cpu_info) { panic("PANIC: in monitor_init() ihk_mc_cpu_info is NULL."); return; } z = sizeof(struct ihk_os_monitor) + sizeof(struct ihk_os_cpu_monitor) * (cpu_info->ncpus - 1); z = (z + PAGE_SIZE -1) >> PAGE_SHIFT; monitor = ihk_mc_alloc_pages(z, IHK_MC_AP_CRITICAL); memset(monitor, 0, z * PAGE_SIZE); monitor->num_processors = (cpu_info->ncpus - 1); phys = virt_to_phys(monitor); ihk_set_monitor(phys, sizeof(struct ihk_os_monitor) + sizeof(struct ihk_os_cpu_monitor) * (cpu_info->ncpus - 1)); return; #else /* POSTK_DEBUG_TEMP_FIX_73 */ z = sizeof(struct ihk_os_monitor) + sizeof(struct ihk_os_cpu_monitor) * num_processors; z = (z + PAGE_SIZE -1) >> PAGE_SHIFT; monitor = ihk_mc_alloc_pages(z, IHK_MC_AP_CRITICAL); memset(monitor, 0, z * PAGE_SIZE); monitor->num_processors = num_processors; phys = virt_to_phys(monitor); ihk_set_monitor(phys, sizeof(struct ihk_os_monitor) + sizeof(struct ihk_os_cpu_monitor) * num_processors); #endif /* POSTK_DEBUG_TEMP_FIX_73 */ } int nmi_mode; static void nmi_init() { unsigned long phys; phys = virt_to_phys(&nmi_mode); ihk_set_nmi_mode_addr(phys); } static void rest_init(void) { handler_init(); #ifdef USE_DMA ihk_mc_dma_init(); dma_test(); #endif ap_init(); #ifndef POSTK_DEBUG_TEMP_FIX_73 /* NULL access for *monitor fix */ monitor_init(); #endif /* !POSTK_DEBUG_TEMP_FIX_73 */ cpu_local_var_init(); nmi_init(); time_init(); kmalloc_init(); ihk_ikc_master_init(); proc_init(); sched_init(); } static void setup_remote_snooping_samples(void) { static long lvalue = 0xf123456789abcde0; static char *svalue = "string(remote)"; int error; struct sysfs_bitmap_param param; error = sysfs_createf(SYSFS_SNOOPING_OPS_d32, &lvalue, 0444, "/sys/test/remote/d32"); if (error) { panic("setup_remote_snooping_samples: d32"); } error = sysfs_createf(SYSFS_SNOOPING_OPS_d64, &lvalue, 0444, "/sys/test/remote/d64"); if (error) { panic("setup_remote_snooping_samples: d64"); } error = sysfs_createf(SYSFS_SNOOPING_OPS_u32, &lvalue, 0444, "/sys/test/remote/u32"); if (error) { panic("setup_remote_snooping_samples: u32"); } error = sysfs_createf(SYSFS_SNOOPING_OPS_u64, &lvalue, 0444, "/sys/test/remote/u64"); if (error) { panic("setup_remote_snooping_samples: u64"); } error = sysfs_createf(SYSFS_SNOOPING_OPS_s, svalue, 0444, "/sys/test/remote/s"); if (error) { panic("setup_remote_snooping_samples: s"); } param.nbits = 40; param.ptr = &lvalue; error = sysfs_createf(SYSFS_SNOOPING_OPS_pbl, ¶m, 0444, "/sys/test/remote/pbl"); if (error) { panic("setup_remote_snooping_samples: pbl"); } param.nbits = 40; param.ptr = &lvalue; error = sysfs_createf(SYSFS_SNOOPING_OPS_pb, ¶m, 0444, "/sys/test/remote/pb"); if (error) { panic("setup_remote_snooping_samples: pb"); } error = sysfs_createf(SYSFS_SNOOPING_OPS_u32K, &lvalue, 0444, "/sys/test/remote/u32K"); if (error) { panic("setup_remote_snooping_samples: u32K"); } return; } /* setup_remote_snooping_samples() */ static void populate_sysfs(void) { cpu_sysfs_setup(); numa_sysfs_setup(); //setup_remote_snooping_samples(); } /* populate_sysfs() */ int host_ikc_inited = 0; extern int num_processors; static void post_init(void) { cpu_enable_interrupt(); while (!host_ikc_inited) { barrier(); cpu_pause(); } if (find_command_line("hidos")) { int ikc_cpu = ihk_mc_get_ikc_cpu(ihk_mc_get_processor_id()); if(ikc_cpu < 0) { ekprintf("%s,ihk_mc_get_ikc_cpu failed\n", __FUNCTION__); } init_host_ikc2mckernel(); init_host_ikc2linux(ikc_cpu); } arch_setup_vdso(); arch_start_pvclock(); ap_start(); sysfs_init(); populate_sysfs(); } #ifdef DCFA_RUN extern void user_main(); #endif #ifdef DCFA_KMOD extern int mc_cmd_client_init(void); extern void ibmic_cmd_init(void); #endif int main(void) { arch_init(); /* * In attached-mic, * bootparam is not mapped until arch_init() is finished. * In builtin-mic and builtin-x86, * virtual address of bootparam is changed in arch_init(). */ parse_kargs(); mem_init(); rest_init(); arch_ready(); post_init(); futex_init(); done_init(); kputs("IHK/McKernel booted.\n"); #ifdef DCFA_KMOD mc_cmd_client_init(); #ifdef CMD_DCFA ibmic_cmd_init(); #endif #endif #ifdef DCFA_RUN kputs("DCFA begin\n"); user_main(); kputs("DCFA end\n"); #else schedule(); #endif return 0; }