/* host.c COPYRIGHT FUJITSU LIMITED 2015-2016 */ /** * \file host.c * License details are found in the file LICENSE. * \brief * host call handlers * \author Taku Shimosawa \par * Copyright (C) 2011 - 2012 Taku Shimosawa * \author Balazs Gerofi \par * Copyright (C) 2012 RIKEN AICS * \author Gou Nakamura \par * Copyright (C) 2013 Hitachi, Ltd. * \author Tomoki Shirasawa \par * Copyright (C) 2013 Hitachi, Ltd. */ /* * HISTORY: */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_PRINT_HOST #ifdef DEBUG_PRINT_HOST #define dkprintf kprintf #else #define dkprintf(...) do { if (0) kprintf(__VA_ARGS__); } while (0) #endif /* Linux channel table, indexec by Linux CPU id */ static struct ihk_ikc_channel_desc **ikc2linuxs = NULL; void check_mapping_for_proc(struct thread *thread, unsigned long addr) { unsigned long __phys; if (ihk_mc_pt_virt_to_phys(thread->vm->address_space->page_table, (void*)addr, &__phys)) { kprintf("check_map: no mapping for 0x%lX\n", addr); } else { kprintf("check_map: 0x%lX -> 0x%lX\n", addr, __phys); } } /* * Prepares the process ranges based on the ELF header described * in program_load_desc and updates physical address in "p" so that * host can copy program image. * It also prepares args, envs and the process stack. * * NOTE: if args, args_len, envs, envs_len are zero, * the function constructs them based on the descriptor */ int prepare_process_ranges_args_envs(struct thread *thread, struct program_load_desc *pn, struct program_load_desc *p, enum ihk_mc_pt_attribute attr, char *args, int args_len, char *envs, int envs_len) { char *args_envs, *args_envs_r; unsigned long args_envs_p, args_envs_rp; unsigned long s, e, up; char **argv; char **a; int i, n, argc, envc, args_envs_npages; char **env; int range_npages; void *up_v; unsigned long addr; unsigned long flags; uintptr_t interp_obase = -1; uintptr_t interp_nbase = -1; size_t map_size; struct process *proc = thread->proc; struct process_vm *vm = proc->vm; struct address_space *as = vm->address_space; long aout_base; int error; struct vm_range *range; unsigned long ap_flags; enum ihk_mc_pt_attribute ptattr; n = p->num_sections; aout_base = (pn->reloc)? vm->region.map_end: 0; for (i = 0; i < n; i++) { ap_flags = 0; if (pn->sections[i].interp && (interp_nbase == (uintptr_t)-1)) { interp_obase = pn->sections[i].vaddr; interp_obase -= (interp_obase % pn->interp_align); interp_nbase = vm->region.map_end; interp_nbase = (interp_nbase + pn->interp_align - 1) & ~(pn->interp_align - 1); } if (pn->sections[i].interp) { pn->sections[i].vaddr -= interp_obase; pn->sections[i].vaddr += interp_nbase; p->sections[i].vaddr = pn->sections[i].vaddr; } else{ pn->sections[i].vaddr += aout_base; p->sections[i].vaddr = pn->sections[i].vaddr; } s = (pn->sections[i].vaddr) & PAGE_MASK; e = (pn->sections[i].vaddr + pn->sections[i].len + PAGE_SIZE - 1) & PAGE_MASK; range_npages = ((pn->sections[i].vaddr - s) + pn->sections[i].filesz + PAGE_SIZE - 1) >> PAGE_SHIFT; flags = VR_NONE; flags |= PROT_TO_VR_FLAG(pn->sections[i].prot); flags |= VRFLAG_PROT_TO_MAXPROT(flags); flags |= VR_DEMAND_PAGING; /* Non-TEXT sections that are large respect user allocation policy * unless user explicitly requests otherwise */ if (i >= 1 && pn->sections[i].len >= pn->mpol_threshold && !(pn->mpol_flags & MPOL_NO_BSS)) { dkprintf("%s: section: %d size: %d pages -> IHK_MC_AP_USER\n", __FUNCTION__, i, range_npages); ap_flags = IHK_MC_AP_USER; flags |= VR_AP_USER; } if (add_process_memory_range(vm, s, e, NOPHYS, flags, NULL, 0, pn->sections[i].len > LARGE_PAGE_SIZE ? LARGE_PAGE_SHIFT : PAGE_SHIFT, &range) != 0) { kprintf("ERROR: adding memory range for ELF section %i\n", i); goto err; } if ((up_v = ihk_mc_alloc_pages_user(range_npages, IHK_MC_AP_NOWAIT | ap_flags, s)) == NULL) { kprintf("ERROR: alloc pages for ELF section %i\n", i); goto err; } up = virt_to_phys(up_v); ptattr = arch_vrflag_to_ptattr(range->flag, PF_POPULATE, NULL); error = ihk_mc_pt_set_range(vm->address_space->page_table, vm, (void *)range->start, (void *)range->start + (range_npages * PAGE_SIZE), up, ptattr, range->pgshift, range); if (error) { kprintf("%s: ihk_mc_pt_set_range failed. %d\n", __FUNCTION__, error); ihk_mc_free_pages_user(up_v, range_npages); goto err; } // memory_stat_rss_add() is called in ihk_mc_pt_set_range() p->sections[i].remote_pa = up; /* TODO: Maybe we need flag */ if (pn->sections[i].interp) { vm->region.map_end = e; } else if (i == 0) { vm->region.text_start = s; vm->region.text_end = e; } else if (i == 1) { vm->region.data_start = s; vm->region.data_end = e; } else { vm->region.data_start = (s < vm->region.data_start ? s : vm->region.data_start); vm->region.data_end = (e > vm->region.data_end ? e : vm->region.data_end); } if (aout_base) { vm->region.map_end = e; } } if (interp_nbase != (uintptr_t)-1) { pn->entry -= interp_obase; pn->entry += interp_nbase; p->entry = pn->entry; ihk_mc_modify_user_context(thread->uctx, IHK_UCR_PROGRAM_COUNTER, pn->entry); } if (aout_base) { pn->at_phdr += aout_base; pn->at_entry += aout_base; } vm->region.brk_start = vm->region.brk_end = (vm->region.data_end + LARGE_PAGE_SIZE - 1) & LARGE_PAGE_MASK; #if 0 { void *heap; dkprintf("%s: requested heap size: %lu\n", __FUNCTION__, proc->heap_extension); heap = ihk_mc_alloc_aligned_pages(proc->heap_extension >> PAGE_SHIFT, LARGE_PAGE_P2ALIGN, IHK_MC_AP_NOWAIT | (!(proc->mpol_flags & MPOL_NO_HEAP) ? IHK_MC_AP_USER : 0)); if (!heap) { kprintf("%s: error: allocating heap\n", __FUNCTION__); goto err; } flags = VR_PROT_READ | VR_PROT_WRITE; flags |= VRFLAG_PROT_TO_MAXPROT(flags); if (add_process_memory_range(vm, vm->region.brk_start, vm->region.brk_start + proc->heap_extension, virt_to_phys(heap), flags, NULL, 0, LARGE_PAGE_P2ALIGN, NULL) != 0) { ihk_mc_free_pages(heap, proc->heap_extension >> PAGE_SHIFT); kprintf("%s: error: adding memory range for heap\n", __FUNCTION__); goto err; } // heap: Add when memory_stat_rss_add() is called in downstream, i.e. add_process_memory_range() vm->region.brk_end_allocated = vm->region.brk_end + proc->heap_extension; dkprintf("%s: heap @ 0x%lx:%lu\n", __FUNCTION__, vm->region.brk_start, proc->heap_extension); } #else vm->region.brk_end_allocated = vm->region.brk_end; #endif /* Map, copy and update args and envs */ flags = VR_PROT_READ | VR_PROT_WRITE; flags |= VRFLAG_PROT_TO_MAXPROT(flags); addr = vm->region.map_start - PAGE_SIZE * SCD_RESERVED_COUNT; e = addr + PAGE_SIZE * ARGENV_PAGE_COUNT; if((args_envs = ihk_mc_alloc_pages_user(ARGENV_PAGE_COUNT, IHK_MC_AP_NOWAIT, -1)) == NULL){ kprintf("ERROR: allocating pages for args/envs\n"); goto err; } args_envs_p = virt_to_phys(args_envs); dkprintf("%s: args_envs: %d pages\n", __FUNCTION__, ARGENV_PAGE_COUNT); if(add_process_memory_range(vm, addr, e, args_envs_p, flags, NULL, 0, PAGE_SHIFT, NULL) != 0){ ihk_mc_free_pages_user(args_envs, ARGENV_PAGE_COUNT); kprintf("ERROR: adding memory range for args/envs\n"); goto err; } // memory_stat_rss_add() is called in downstream, i.e. add_process_memory_range() dkprintf("args_envs mapping\n"); dkprintf("args: 0x%lX, args_len: %d\n", p->args, p->args_len); /* Only map remote address if it wasn't specified as an argument */ if (!args) { // Map in remote physical addr of args and copy it map_size = ((uintptr_t)p->args & (PAGE_SIZE - 1)) + p->args_len; args_envs_npages = (map_size + PAGE_SIZE - 1) >> PAGE_SHIFT; dkprintf("args_envs_npages: %d\n", args_envs_npages); args_envs_rp = ihk_mc_map_memory(NULL, (unsigned long)p->args, p->args_len); dkprintf("args_envs_rp: 0x%lX\n", args_envs_rp); if ((args_envs_r = (char *)ihk_mc_map_virtual(args_envs_rp, args_envs_npages, attr)) == NULL){ goto err; } dkprintf("args_envs_r: 0x%lX\n", args_envs_r); } else { args_envs_r = args; p->args_len = args_len; } dkprintf("args copy, nr: %d\n", *((long *)args_envs_r)); memcpy_long(args_envs, args_envs_r, p->args_len + sizeof(long) - 1); /* Only unmap remote address if it wasn't specified as an argument */ if (!args) { ihk_mc_unmap_virtual(args_envs_r, args_envs_npages, 0); ihk_mc_unmap_memory(NULL, args_envs_rp, p->args_len); } flush_tlb(); dkprintf("envs: 0x%lX, envs_len: %d\n", p->envs, p->envs_len); /* Only map remote address if it wasn't specified as an argument */ if (!envs) { // Map in remote physical addr of envs and copy it after args map_size = ((uintptr_t)p->envs & (PAGE_SIZE - 1)) + p->envs_len; args_envs_npages = (map_size + PAGE_SIZE - 1) >> PAGE_SHIFT; dkprintf("args_envs_npages: %d\n", args_envs_npages); args_envs_rp = ihk_mc_map_memory(NULL, (unsigned long)p->envs, p->envs_len); dkprintf("args_envs_rp: 0x%lX\n", args_envs_rp); if ((args_envs_r = (char *)ihk_mc_map_virtual(args_envs_rp, args_envs_npages, attr)) == NULL) { goto err; } dkprintf("args_envs_r: 0x%lX\n", args_envs_r); } else { args_envs_r = envs; p->envs_len = envs_len; } dkprintf("envs copy, nr: %d\n", *((long *)args_envs_r)); memcpy_long(args_envs + p->args_len, args_envs_r, p->envs_len + sizeof(long) - 1); /* Only map remote address if it wasn't specified as an argument */ if (!envs) { ihk_mc_unmap_virtual(args_envs_r, args_envs_npages, 0); ihk_mc_unmap_memory(NULL, args_envs_rp, p->envs_len); } flush_tlb(); // Update variables argc = *((long *)(args_envs)); dkprintf("argc: %d\n", argc); argv = (char **)(args_envs + (sizeof(long))); if (proc->saved_cmdline) { kfree(proc->saved_cmdline); proc->saved_cmdline = NULL; proc->saved_cmdline_len = 0; } proc->saved_cmdline = kmalloc(p->args_len, IHK_MC_AP_NOWAIT); if (!proc->saved_cmdline) { goto err; } proc->saved_cmdline_len = p->args_len - ((argc + 2) * sizeof(char **)); memcpy(proc->saved_cmdline, (char *)args_envs + ((argc + 2) * sizeof(char **)), proc->saved_cmdline_len); dkprintf("%s: saved_cmdline: %s\n", __FUNCTION__, proc->saved_cmdline); for (a = argv; *a; a++) { *a = (char *)addr + (unsigned long)*a; // Process' address space! } envc = *((long *)(args_envs + p->args_len)); dkprintf("envc: %d\n", envc); env = (char **)(args_envs + p->args_len + sizeof(long)); while (*env) { char **_env = env; //dkprintf("%s\n", args_envs + p->args_len + (unsigned long)*env); *env = (char *)addr + p->args_len + (unsigned long)*env; env = ++_env; } env = (char **)(args_envs + p->args_len + sizeof(long)); dkprintf("env OK\n"); if (pn->enable_vdso) { error = arch_map_vdso(vm); if (error) { kprintf("ERROR: mapping vdso pages. %d\n", error); goto err; } } else { vm->vdso_addr = NULL; } p->rprocess = (unsigned long)thread; p->rpgtable = virt_to_phys(as->page_table); if (init_process_stack(thread, pn, argc, argv, envc, env) != 0) { goto err; } return 0; err: /* TODO: cleanup allocated ranges */ return -1; } /* * Communication with host */ static int process_msg_prepare_process(unsigned long rphys) { unsigned long phys, sz; struct program_load_desc *p, *pn; int npages, n; struct thread *thread; struct process *proc; struct process_vm *vm; enum ihk_mc_pt_attribute attr; attr = PTATTR_NO_EXECUTE | PTATTR_WRITABLE | PTATTR_FOR_USER; sz = sizeof(struct program_load_desc) + sizeof(struct program_image_section) * 16; npages = ((rphys + sz - 1) >> PAGE_SHIFT) - (rphys >> PAGE_SHIFT) + 1; phys = ihk_mc_map_memory(NULL, rphys, sz); if((p = ihk_mc_map_virtual(phys, npages, attr)) == NULL){ ihk_mc_unmap_memory(NULL, phys, sz); return -ENOMEM; } n = p->num_sections; if (n > 16 || 0 >= n) { kprintf("%s: ERROR: ELF sections other than 1 to 16 ??\n", __FUNCTION__); return -ENOMEM; } dkprintf("# of sections: %d\n", n); if((pn = kmalloc(sizeof(struct program_load_desc) + sizeof(struct program_image_section) * n, IHK_MC_AP_NOWAIT)) == NULL){ ihk_mc_unmap_virtual(p, npages, 0); ihk_mc_unmap_memory(NULL, phys, sz); return -ENOMEM; } memcpy_long(pn, p, sizeof(struct program_load_desc) + sizeof(struct program_image_section) * n); if ((thread = create_thread(p->entry, (unsigned long *)&p->cpu_set, sizeof(p->cpu_set))) == NULL) { kfree(pn); ihk_mc_unmap_virtual(p, npages, 1); ihk_mc_unmap_memory(NULL, phys, sz); return -ENOMEM; } proc = thread->proc; vm = thread->vm; proc->pid = pn->pid; proc->vm->address_space->pids[0] = pn->pid; proc->pgid = pn->pgid; proc->ruid = pn->cred[0]; proc->euid = pn->cred[1]; proc->suid = pn->cred[2]; proc->fsuid = pn->cred[3]; proc->rgid = pn->cred[4]; proc->egid = pn->cred[5]; proc->sgid = pn->cred[6]; proc->fsgid = pn->cred[7]; proc->termsig = SIGCHLD; proc->mpol_flags = pn->mpol_flags; proc->mpol_threshold = pn->mpol_threshold; proc->nr_processes = pn->nr_processes; proc->heap_extension = pn->heap_extension; /* Update NUMA binding policy if requested */ if (pn->mpol_bind_mask) { int bit; memset(&vm->numa_mask, 0, sizeof(vm->numa_mask)); for_each_set_bit(bit, &pn->mpol_bind_mask, sizeof(pn->mpol_bind_mask) * BITS_PER_BYTE) { if (bit >= ihk_mc_get_nr_numa_nodes()) { kprintf("%s: error: NUMA id %d is larger than mask size!\n", __FUNCTION__, bit); return -EINVAL; } set_bit(bit, &vm->numa_mask[0]); } vm->numa_mem_policy = MPOL_BIND; } #ifdef PROFILE_ENABLE proc->profile = pn->profile; thread->profile = pn->profile; #endif vm->region.user_start = pn->user_start; vm->region.user_end = pn->user_end; if(vm->region.user_end > USER_END) vm->region.user_end = USER_END; if(vm->region.user_start != 0UL || vm->region.user_end < TASK_UNMAPPED_BASE){ vm->region.map_start = (vm->region.user_start + (vm->region.user_end - vm->region.user_start) / 3) & LARGE_PAGE_MASK; } else{ vm->region.map_start = TASK_UNMAPPED_BASE; } vm->region.map_end = vm->region.map_start; memcpy(proc->rlimit, pn->rlimit, sizeof(struct rlimit) * MCK_RLIM_MAX); dkprintf("%s: rlim_cur: %ld, rlim_max: %ld, stack_premap: %ld\n", __FUNCTION__, proc->rlimit[MCK_RLIMIT_STACK].rlim_cur, proc->rlimit[MCK_RLIMIT_STACK].rlim_max, pn->stack_premap); if (prepare_process_ranges_args_envs(thread, pn, p, attr, NULL, 0, NULL, 0) != 0) { kprintf("error: preparing process ranges, args, envs, stack\n"); goto err; } dkprintf("new process : %p [%d] / table : %p\n", proc, proc->pid, vm->address_space->page_table); kfree(pn); ihk_mc_unmap_virtual(p, npages, 1); ihk_mc_unmap_memory(NULL, phys, sz); flush_tlb(); return 0; err: kfree(pn); ihk_mc_unmap_virtual(p, npages, 1); ihk_mc_unmap_memory(NULL, phys, sz); destroy_thread(thread); return -ENOMEM; } static void syscall_channel_send(struct ihk_ikc_channel_desc *c, struct ikc_scd_packet *packet) { ihk_ikc_send(c, packet, 0); } extern unsigned long do_kill(struct thread *, int, int, int, struct siginfo *, int ptracecont); extern void process_procfs_request(struct ikc_scd_packet *rpacket); extern void terminate_host(int pid); extern void debug_log(long); static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, void *__packet, void *ihk_os) { struct ikc_scd_packet *packet = __packet; struct ikc_scd_packet pckt; struct ihk_ikc_channel_desc *resp_channel = cpu_local_var(ikc2linux); int rc; struct mcs_rwlock_node_irqsave lock; struct thread *thread; struct process *proc; struct mcctrl_signal { int cond; int sig; int pid; int tid; struct siginfo info; } *sp, info; unsigned long pp; int cpuid; int ret = 0; struct perf_ctrl_desc *pcd; unsigned int mode = 0; switch (packet->msg) { case SCD_MSG_INIT_CHANNEL_ACKED: dkprintf("SCD_MSG_INIT_CHANNEL_ACKED\n"); ret = 0; break; case SCD_MSG_PREPARE_PROCESS: pckt.err = process_msg_prepare_process(packet->arg); pckt.msg = SCD_MSG_PREPARE_PROCESS_ACKED; pckt.reply = packet->reply; pckt.ref = packet->ref; pckt.arg = packet->arg; syscall_channel_send(resp_channel, &pckt); ret = 0; break; case SCD_MSG_SCHEDULE_PROCESS: thread = (struct thread *)packet->arg; cpuid = obtain_clone_cpuid(&thread->cpu_set); if (cpuid == -1) { kprintf("No CPU available\n"); ret = -1; break; } dkprintf("SCD_MSG_SCHEDULE_PROCESS: %lx\n", packet->arg); proc = thread->proc; thread->tid = proc->pid; proc->status = PS_RUNNING; thread->status = PS_RUNNING; chain_thread(thread); chain_process(proc); runq_add_thread(thread, cpuid); ret = 0; break; /* * Used for syscall offload reply message to explicitly schedule in * the waiting thread */ case SCD_MSG_WAKE_UP_SYSCALL_THREAD: thread = find_thread(0, packet->ttid, &lock); if (!thread) { kprintf("%s: WARNING: no thread for SCD reply? TID: %d\n", __FUNCTION__, packet->ttid); ret = -EINVAL; break; } thread_unlock(thread, &lock); dkprintf("%s: SCD_MSG_WAKE_UP_SYSCALL_THREAD: waking up tid %d\n", __FUNCTION__, packet->ttid); waitq_wakeup(&thread->scd_wq); ret = 0; break; case SCD_MSG_SEND_SIGNAL: pp = ihk_mc_map_memory(NULL, packet->arg, sizeof(struct mcctrl_signal)); sp = (struct mcctrl_signal *)ihk_mc_map_virtual(pp, 1, PTATTR_WRITABLE | PTATTR_ACTIVE); memcpy(&info, sp, sizeof(struct mcctrl_signal)); ihk_mc_unmap_virtual(sp, 1, 0); ihk_mc_unmap_memory(NULL, pp, sizeof(struct mcctrl_signal)); pckt.msg = SCD_MSG_SEND_SIGNAL_ACK; pckt.err = 0; pckt.ref = packet->ref; pckt.arg = packet->arg; pckt.reply = packet->reply; syscall_channel_send(resp_channel, &pckt); rc = do_kill(NULL, info.pid, info.tid, info.sig, &info.info, 0); dkprintf("SCD_MSG_SEND_SIGNAL: do_kill(pid=%d, tid=%d, sig=%d)=%d\n", info.pid, info.tid, info.sig, rc); ret = 0; break; case SCD_MSG_PROCFS_REQUEST: process_procfs_request(packet); ret = 0; break; case SCD_MSG_CLEANUP_PROCESS: dkprintf("SCD_MSG_CLEANUP_PROCESS pid=%d\n", packet->pid); terminate_host(packet->pid); ret = 0; break; case SCD_MSG_DEBUG_LOG: dkprintf("SCD_MSG_DEBUG_LOG code=%lx\n", packet->arg); debug_log(packet->arg); ret = 0; break; case SCD_MSG_SYSFS_REQ_SHOW: case SCD_MSG_SYSFS_REQ_STORE: case SCD_MSG_SYSFS_REQ_RELEASE: sysfss_packet_handler(c, packet->msg, packet->err, packet->sysfs_arg1, packet->sysfs_arg2, packet->sysfs_arg3); ret = 0; break; case SCD_MSG_PERF_CTRL: pp = ihk_mc_map_memory(NULL, packet->arg, sizeof(struct perf_ctrl_desc)); pcd = (struct perf_ctrl_desc *)ihk_mc_map_virtual(pp, 1, PTATTR_WRITABLE | PTATTR_ACTIVE); switch (pcd->ctrl_type) { case PERF_CTRL_SET: if (!pcd->exclude_kernel) { mode |= PERFCTR_KERNEL_MODE; } if (!pcd->exclude_user) { mode |= PERFCTR_USER_MODE; } ihk_mc_perfctr_init_raw(pcd->target_cntr, pcd->config, mode); ihk_mc_perfctr_stop(1 << pcd->target_cntr); ihk_mc_perfctr_reset(pcd->target_cntr); break; case PERF_CTRL_ENABLE: ihk_mc_perfctr_start(pcd->target_cntr_mask); break; case PERF_CTRL_DISABLE: ihk_mc_perfctr_stop(pcd->target_cntr_mask); break; case PERF_CTRL_GET: pcd->read_value = ihk_mc_perfctr_read(pcd->target_cntr); break; default: kprintf("%s: SCD_MSG_PERF_CTRL unexpected ctrl_type\n", __FUNCTION__); } ihk_mc_unmap_virtual(pcd, 1, 0); ihk_mc_unmap_memory(NULL, pp, sizeof(struct perf_ctrl_desc)); pckt.msg = SCD_MSG_PERF_ACK; pckt.err = 0; pckt.arg = packet->arg; pckt.reply = packet->reply; ihk_ikc_send(resp_channel, &pckt, 0); ret = 0; break; case SCD_MSG_CPU_RW_REG: pckt.msg = SCD_MSG_CPU_RW_REG_RESP; memcpy(&pckt.desc, &packet->desc, sizeof(struct ihk_os_cpu_register)); pckt.resp = packet->resp; pckt.err = arch_cpu_read_write_register(&pckt.desc, packet->op); ihk_ikc_send(resp_channel, &pckt, 0); break; default: kprintf("syscall_pakcet_handler:unknown message " "(%d.%d.%d.%d.%d.%#lx)\n", packet->msg, packet->ref, packet->osnum, packet->pid, packet->err, packet->arg); ret = 0; break; } ihk_ikc_release_packet((struct ihk_ikc_free_packet *)packet, c); return ret; } static int dummy_packet_handler(struct ihk_ikc_channel_desc *c, void *__packet, void *__os) { struct ikc_scd_packet *packet = __packet; ihk_ikc_release_packet((struct ihk_ikc_free_packet *)packet, c); return 0; } void init_host_ikc2linux(int linux_cpu) { struct ihk_ikc_connect_param param; struct ihk_ikc_channel_desc *c; /* Main thread allocates channel pointer table */ if (!ikc2linuxs) { ikc2linuxs = kmalloc(sizeof(*ikc2linuxs) * ihk_mc_get_nr_linux_cores(), IHK_MC_AP_NOWAIT); if (!ikc2linuxs) { kprintf("%s: error: allocating Linux channels\n", __FUNCTION__); panic(""); } memset(ikc2linuxs, 0, sizeof(*ikc2linuxs) * ihk_mc_get_nr_linux_cores()); } c = ikc2linuxs[linux_cpu]; if (!c) { param.port = 503; param.intr_cpu = linux_cpu; param.pkt_size = sizeof(struct ikc_scd_packet); param.queue_size = 2 * num_processors * sizeof(struct ikc_scd_packet); if (param.queue_size < PAGE_SIZE * 4) { param.queue_size = PAGE_SIZE * 4; } param.magic = 0x1129; param.handler = dummy_packet_handler; dkprintf("(ikc2linux) Trying to connect host ..."); while (ihk_ikc_connect(NULL, ¶m) != 0) { dkprintf("."); ihk_mc_delay_us(1000 * 1000); } dkprintf("connected.\n"); ikc2linuxs[linux_cpu] = param.channel; c = param.channel; } get_this_cpu_local_var()->ikc2linux = c; } void init_host_ikc2mckernel(void) { struct ihk_ikc_connect_param param; param.port = 501; param.intr_cpu = -1; param.pkt_size = sizeof(struct ikc_scd_packet); param.queue_size = PAGE_SIZE * 4; param.magic = 0x1329; param.handler = syscall_packet_handler; dkprintf("(ikc2mckernel) Trying to connect host ..."); while (ihk_ikc_connect(NULL, ¶m) != 0) { dkprintf("."); ihk_mc_delay_us(1000 * 1000); } dkprintf("connected.\n"); ihk_ikc_set_regular_channel(NULL, param.channel, ihk_ikc_get_processor_id()); }