diff --git a/kboot/Makefile b/kboot/Makefile index 312ffb7e..cced4065 100644 --- a/kboot/Makefile +++ b/kboot/Makefile @@ -1,6 +1,6 @@ DEST=$(O)/kboot OBJS=$(DEST)/main.o $(DEST)/data.o -CFLAGS=-mno-sse -mno-mmx -mno-sse2 -mno-3dnow +CFLAGS=-mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mcmodel=large $(if $(O),,$(error Specify the target directory)) diff --git a/kernel/Makefile.build b/kernel/Makefile.build index 905a3035..144367da 100644 --- a/kernel/Makefile.build +++ b/kernel/Makefile.build @@ -1,5 +1,6 @@ AALDIR=$(AALBASE)/$(TARGET) -OBJS=init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o +OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o +OBJS += process.o DEPSRCS=$(wildcard $(SRC)/*.c) include $(SRC)/configs/config.$(TARGET) diff --git a/kernel/ap.c b/kernel/ap.c index 4ac99459..72c4bcce 100644 --- a/kernel/ap.c +++ b/kernel/ap.c @@ -47,6 +47,7 @@ void ap_init(void) kprintf("BSP HW ID = %d, ", bsp_hw_id); kprintf("AP Booting :"); + for (i = 0; i < cpu_info->ncpus; i++) { if (cpu_info->hw_ids[i] == bsp_hw_id) { continue; diff --git a/kernel/host.c b/kernel/host.c new file mode 100644 index 00000000..87724599 --- /dev/null +++ b/kernel/host.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Communication with host + */ +static void process_msg_prepare_process(unsigned long rphys) +{ + unsigned long phys, sz, s, e, up; + struct program_load_desc *p, *pn; + int i, npages, n; + struct process *proc; + + sz = sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * 16; + npages = (sz + PAGE_SIZE - 1) >> PAGE_SHIFT; + + phys = aal_mc_map_memory(NULL, rphys, sz); + p = aal_mc_map_virtual(phys, npages, PTATTR_WRITABLE); + + n = p->num_sections; + kprintf("# of sections: %d\n", n); + + pn = aal_mc_allocate(sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * n, 0); + memcpy_long(pn, p, sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * n); + + proc = create_process(p->entry); + proc->pid = p->pid; + + for (i = 0; i < n; i++) { + s = (pn->sections[i].vaddr) & PAGE_MASK; + e = (pn->sections[i].vaddr + pn->sections[i].len + + PAGE_SIZE - 1) & PAGE_MASK; + up = virt_to_phys(aal_mc_alloc_pages((e - s) >> PAGE_SHIFT, 0)); + + add_process_memory_range(proc, s, e, up, 0); + p->sections[i].remote_pa = up; + + /* TODO: Maybe we need flag */ + if (i == 0) { + proc->region.text_start = s; + proc->region.text_end = e; + } else if (i == 1) { + proc->region.data_start = s; + proc->region.data_end = e; + } else { + proc->region.data_start = + (s < proc->region.data_start ? + s : proc->region.data_start); + proc->region.data_end = + (e > proc->region.data_end ? + e : proc->region.data_end); + } + } + proc->region.brk_start = proc->region.brk_end = proc->region.data_end; + proc->region.map_start = proc->region.map_end = + (USER_END / 3) & PAGE_MASK; + + p->rprocess = (unsigned long)proc; + init_process_stack(proc); + + kprintf("new process : %p [%d] / table : %p\n", proc, proc->pid, + proc->page_table); + + aal_mc_free(pn); + + aal_mc_unmap_virtual(p, npages); + aal_mc_unmap_memory(NULL, phys, sz); +} + +static void process_msg_init(struct ikc_scd_init_param *pcp) +{ + struct syscall_params *lparam; + + lparam = &cpu_local_var(scp); + lparam->response_va = allocate_pages(1, 0); + lparam->response_pa = virt_to_phys(lparam->response_va); + + pcp->request_page = 0; + pcp->doorbell_page = 0; + pcp->response_page = lparam->response_pa; +} + +static void process_msg_init_acked(unsigned long pphys) +{ + struct ikc_scd_init_param *param = (void *)pphys; + struct syscall_params *lparam; + + lparam = &cpu_local_var(scp); + lparam->request_rpa = param->request_page; + lparam->request_pa = aal_mc_map_memory(NULL, param->request_page, + PAGE_SIZE); + lparam->request_va = aal_mc_map_virtual(lparam->request_pa, 1, + PTATTR_WRITABLE); + + lparam->doorbell_rpa = param->doorbell_page; + lparam->doorbell_pa = aal_mc_map_memory(NULL, param->doorbell_page, + PAGE_SIZE); + lparam->doorbell_va = aal_mc_map_virtual(lparam->doorbell_pa, 1, + PTATTR_WRITABLE); + + kprintf("Syscall parameters:\n"); + kprintf(" Response: %lx, %p\n", + lparam->response_pa, lparam->response_va); + kprintf(" Request : %lx, %lx, %p\n", + lparam->request_pa, lparam->request_rpa, lparam->request_va); + kprintf(" Doorbell: %lx, %lx, %p\n", + lparam->doorbell_pa, lparam->doorbell_rpa, lparam->doorbell_va); + +} + +static void syscall_channel_send(struct aal_ikc_channel_desc *c, + struct ikc_scd_packet *packet) +{ + aal_ikc_send(c, packet, 0); +} + +static int syscall_packet_handler(struct aal_ikc_channel_desc *c, + void *__packet, void *aal_os) +{ + struct ikc_scd_packet *packet = __packet; + struct ikc_scd_packet pckt; + + switch (packet->msg) { + case SCD_MSG_INIT_CHANNEL_ACKED: + kprintf("init channel acked!\n"); + process_msg_init_acked(packet->arg); + return 0; + + case SCD_MSG_PREPARE_PROCESS: + process_msg_prepare_process(packet->arg); + + pckt.msg = SCD_MSG_PREPARE_PROCESS_ACKED; + pckt.ref = packet->ref; + pckt.arg = packet->arg; + syscall_channel_send(c, &pckt); + + return 0; + + case SCD_MSG_SCHEDULE_PROCESS: + kprintf("next one : %lx\n", packet->arg); + cpu_local_var(next) = (struct process *)packet->arg; + return 0; + } + return 0; +} + +void init_host_syscall_channel(void) +{ + struct aal_ikc_connect_param param; + struct ikc_scd_packet pckt; + + param.port = 501; + param.pkt_size = sizeof(struct ikc_scd_packet); + param.queue_size = PAGE_SIZE; + param.magic = 0x1129; + param.handler = syscall_packet_handler; + + kprintf("(syscall) Trying to connect host ..."); + while (aal_ikc_connect(NULL, ¶m) != 0) { + kprintf("."); + aal_mc_delay_us(1000 * 1000); + } + kprintf("connected.\n"); + + get_this_cpu_local_var()->syscall_channel = param.channel; + + process_msg_init(&cpu_local_var(iip)); + pckt.msg = SCD_MSG_INIT_CHANNEL; + pckt.ref = aal_mc_get_processor_id(); + pckt.arg = virt_to_phys(&cpu_local_var(iip)); + syscall_channel_send(param.channel, &pckt); +} diff --git a/kernel/include/cls.h b/kernel/include/cls.h index efba7195..e3c279fd 100644 --- a/kernel/include/cls.h +++ b/kernel/include/cls.h @@ -1,5 +1,8 @@ #ifndef __HEADER_CLS_H #define __HEADER_CLS_H + +#include +#include /* * CPU Local Storage (cls) */ @@ -12,7 +15,16 @@ struct malloc_header { struct cpu_local_var { /* malloc */ struct malloc_header free_list; - /* Align to 64-byte */ + + struct process idle; + + struct process *current; + struct process *next; + + struct aal_ikc_channel_desc *syscall_channel; + + struct syscall_params scp; + struct ikc_scd_init_param iip; } __attribute__((aligned(64))); diff --git a/kernel/include/process.h b/kernel/include/process.h new file mode 100644 index 00000000..81a82615 --- /dev/null +++ b/kernel/include/process.h @@ -0,0 +1,52 @@ +#ifndef HEADER_PROCESS_H +#define HEADER_PROCESS_H + +#include +#include +#include +#include + +#define VR_STACK 1 + +struct vm_range { + struct list_head list; + unsigned long start, end; + unsigned long phys; + unsigned long flag; +}; + +struct vm_regions { + unsigned long text_start, text_end; + unsigned long data_start, data_end; + unsigned long brk_start, brk_end; + unsigned long map_start, map_end; + unsigned long stack_start, stack_end; +}; + +struct process { + int pid; + int status; + + struct page_table *page_table; + struct list_head vm_range_list; + + struct vm_regions region; + + aal_mc_kernel_context_t ctx; + aal_mc_user_context_t *uctx; +}; + +struct process *create_process(unsigned long user_pc); +int add_process_memory_range(struct process *process, + unsigned long start, unsigned long end, + unsigned long phys, unsigned long flag); +int remove_process_region(struct process *proc, + unsigned long start, unsigned long end); +void init_process_stack(struct process *process); +unsigned long extend_process_region(struct process *proc, + unsigned long start, unsigned long end, + unsigned long address); + +void schedule(void); + +#endif diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h new file mode 100644 index 00000000..a999856e --- /dev/null +++ b/kernel/include/syscall.h @@ -0,0 +1,65 @@ +#ifndef __HEADER_SYSCALL_H +#define __HEADER_SYSCALL_H + +#define NUM_SYSCALLS 255 + +#define SCD_MSG_PREPARE_PROCESS 0x1 +#define SCD_MSG_PREPARE_PROCESS_ACKED 0x2 +#define SCD_MSG_SCHEDULE_PROCESS 0x3 + +#define SCD_MSG_INIT_CHANNEL 0x5 +#define SCD_MSG_INIT_CHANNEL_ACKED 0x6 + +#define SCD_MSG_SYSCALL_ONESIDE 0x4 + +struct ikc_scd_packet { + int msg; + int ref; + unsigned long arg; +}; + +struct program_image_section { + unsigned long vaddr; + unsigned long len; + unsigned long remote_pa; + unsigned long filesz, offset; + void *source; +}; + +struct program_load_desc { + int num_sections; + int status; + int cpu; + int pid; + unsigned long entry; + unsigned long rprocess; + struct program_image_section sections[0]; +}; + +struct ikc_scd_init_param { + unsigned long request_page; + unsigned long response_page; + unsigned long doorbell_page; +}; + +struct syscall_request { + unsigned long number; + unsigned long args[5]; +}; + +struct syscall_response { + unsigned long status; + long ret; +}; + +struct syscall_params { + unsigned long request_rpa, request_pa; + struct syscall_request *request_va; + unsigned long response_pa; + struct syscall_response *response_va; + + unsigned long doorbell_rpa, doorbell_pa; + unsigned long *doorbell_va; +}; + +#endif diff --git a/kernel/init.c b/kernel/init.c index 14eda559..7060a5a1 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include extern struct aal_kmsg_buf kmsg_buf; @@ -18,36 +21,98 @@ extern void mc_ikc_init(void); extern void cpu_local_var_init(void); extern void kmalloc_init(void); extern void ap_start(void); +extern void aal_mc_dma_init(void); +extern void init_host_syscall_channel(void); +extern void sched_init(void); -static aal_mc_kernel_context_t idle_ctx; - -static void idle(void) -{ - while (1) { - cpu_enable_interrupt(); - cpu_halt(); - } -} - -extern int syscall(int, aal_mc_user_context_t *); +extern long syscall(int, aal_mc_user_context_t *); static void handler_init(void) { aal_mc_set_syscall_handler(syscall); } +unsigned long data[1024] __attribute__((aligned(64))); + +static void dma_test(void) +{ + struct aal_dma_request req; + unsigned long fin = 0; + + memset(&req, 0, sizeof(req)); + req.src_phys = virt_to_phys(data); + req.dest_phys = virt_to_phys(data + 256); + req.size = 64; + req.notify = (void *)virt_to_phys(&fin); + req.priv = (void *)0x2984; + + aal_mc_dma_request(0, &req); + + while (!fin) { + barrier(); + } +} + +static void pc_test(void) +{ + int i; + int kmode = PERFCTR_USER_MODE; + int x[2][4] = { { APT_TYPE_L1D_MISS, APT_TYPE_L1I_MISS, + APT_TYPE_L2_MISS, APT_TYPE_INSTRUCTIONS, }, + { APT_TYPE_STALL, APT_TYPE_L1I_MISS, + APT_TYPE_L2_MISS, APT_TYPE_INSTRUCTIONS, }}; + + for (i = 0; i < 4; i++) { + aal_mc_perfctr_init(i, x[1][i], kmode); + } + aal_mc_perfctr_start(0xf); +/* + aal_mc_perfctr_read_mask(0x0f, st); + for (i = 0; i < 100000; i++) { + data[i & 1023] += i; + asm volatile("" : : : "memory"); + } + aal_mc_perfctr_read_mask(0x0f, ed); + aal_mc_perfctr_stop(1); + + kprintf("INS = %ld, %ld, %ld\n", st[0], ed[0], ed[0] - st[0]); + kprintf("L2M = %ld, %ld, %ld\n", st[1], ed[1], ed[1] - st[1]); +*/ +} + static void rest_init(void) { handler_init(); + aal_mc_dma_init(); + dma_test(); + pc_test(); + ap_init(); cpu_local_var_init(); kmalloc_init(); + + ikc_master_init(); mc_ikc_init(); + sched_init(); ap_start(); } +int host_ikc_inited = 0; + +static void post_init(void) +{ + cpu_enable_interrupt(); + + while (!host_ikc_inited) { + barrier(); + cpu_pause(); + } + + init_host_syscall_channel(); +} + int main(void) { kmsg_init(); @@ -58,16 +123,15 @@ int main(void) mem_init(); - ikc_master_init(); - rest_init(); arch_ready(); + post_init(); + kputs("MCK/AAL booted.\n"); - aal_mc_init_context(&idle_ctx, NULL, idle); - aal_mc_switch_context(NULL, &idle_ctx); + schedule(); return 0; } diff --git a/kernel/listeners.c b/kernel/listeners.c index 4948d4cd..b98b29c8 100644 --- a/kernel/listeners.c +++ b/kernel/listeners.c @@ -40,6 +40,7 @@ static int test_packet_handler(struct aal_ikc_channel_desc *c, { struct ikc_test_packet *packet = __packet; struct ikc_test_packet p; + int i; unsigned long a, pp, *v; if (packet->msg == 0x11110011) { @@ -56,7 +57,9 @@ static int test_packet_handler(struct aal_ikc_channel_desc *c, aal_mc_unmap_memory(NULL, pp, 4 * 1024 * 1024); } else if (packet->msg == 0x11110012) { p.msg = 0x11110013; - aal_ikc_send(c, &p, 0); + for (i = 0; i < 10; i++) { + aal_ikc_send(c, &p, 0); + } } return 0; diff --git a/kernel/mem.c b/kernel/mem.c index 2f301473..187226d1 100644 --- a/kernel/mem.c +++ b/kernel/mem.c @@ -100,7 +100,10 @@ void *aal_mc_map_virtual(unsigned long phys, int npages, enum aal_mc_pt_attribute attr) { void *p; - unsigned long i; + unsigned long i, offset; + + offset = (phys & (PAGE_SIZE - 1)); + phys = phys & PAGE_MASK; p = (void *)aal_pagealloc_alloc(vmap_allocator, npages); if (!p) { @@ -110,13 +113,14 @@ void *aal_mc_map_virtual(unsigned long phys, int npages, aal_mc_pt_set_page(NULL, (char *)p + (i << PAGE_SHIFT), phys + (i << PAGE_SHIFT), attr); } - return p; + return (char *)p + offset; } void aal_mc_unmap_virtual(void *va, int npages) { unsigned long i; + va = (void *)((unsigned long)va & PAGE_MASK); for (i = 0; i < npages; i++) { aal_mc_pt_clear_page(NULL, (char *)va + (i << PAGE_SHIFT)); } diff --git a/kernel/process.c b/kernel/process.c new file mode 100644 index 00000000..4ef08701 --- /dev/null +++ b/kernel/process.c @@ -0,0 +1,189 @@ +#include +#include +#include +#include +#include +#include +#include + +struct process *create_process(unsigned long user_pc) +{ + struct process *proc; + + proc = aal_mc_alloc_pages(1, 0); + + memset(proc, 0, sizeof(struct process)); + + aal_mc_init_user_process(&proc->ctx, &proc->uctx, + ((char *)proc) + PAGE_SIZE, user_pc, 0); + + INIT_LIST_HEAD(&proc->vm_range_list); + proc->page_table = aal_mc_pt_create(); + + return proc; +} + +void update_process_page_table(struct process *process, struct vm_range *range) +{ + unsigned long p, pa = range->phys; + + p = range->start; + while (p < range->end) { + aal_mc_pt_set_page(process->page_table, (void *)p, + pa, PTATTR_WRITABLE | PTATTR_USER); + + pa += PAGE_SIZE; + p += PAGE_SIZE; + } +} + +int add_process_memory_range(struct process *process, + unsigned long start, unsigned long end, + unsigned long phys, unsigned long flag) +{ + struct vm_range *range; + + range = kmalloc(sizeof(struct vm_range), 0); + if (!range) { + return -ENOMEM; + } + INIT_LIST_HEAD(&range->list); + range->start = start; + range->end = end; + range->phys = phys; + range->flag = flag; + + kprintf("range: %lx - %lx => %lx - %lx\n", + range->start, range->end, range->phys, range->phys + + range->end - range->start); + + update_process_page_table(process, range); + + list_add_tail(&range->list, &process->vm_range_list); + + return 0; +} + +void init_process_stack(struct process *process) +{ + char *stack = aal_mc_alloc_pages(1, 0); + unsigned long *p = (unsigned long *)(stack + PAGE_SIZE); + + memset(stack, 0, PAGE_SIZE); + + add_process_memory_range(process, USER_END - PAGE_SIZE, + USER_END, + virt_to_phys(p), VR_STACK); + + /* TODO: fill with actual value of argc, argv, envp */ + + p[-1] = 0; /* env: "" */ + p[-2] = 0x41; /* argv(0): "a" */ + p[-3] = USER_END - sizeof(unsigned long); /* envp: END - 8 */ + p[-4] = 0; /* argv[1] = NULL */ + p[-5] = USER_END - sizeof(unsigned long) * 2; /* argv[0] = END - 16 */ + p[-6] = 1; /* argc */ + + aal_mc_modify_user_context(process->uctx, AAL_UCR_STACK_POINTER, + USER_END - sizeof(unsigned long) * 6); + process->region.stack_end = USER_END; + process->region.stack_start = USER_END - PAGE_SIZE; +} + + +unsigned long extend_process_region(struct process *proc, + unsigned long start, unsigned long end, + unsigned long address) +{ + unsigned long aligned_end, aligned_new_end; + void *p; + + if (!address || address < start || address >= USER_END) { + return end; + } + + aligned_end = ((end + PAGE_SIZE - 1) & PAGE_MASK); + + if (aligned_end >= address) { + return address; + } + + aligned_new_end = (address + PAGE_SIZE - 1) & PAGE_MASK; + + p = allocate_pages((aligned_new_end - aligned_end) >> PAGE_SHIFT, + 0); + if (!p) { + return end; + } + + add_process_memory_range(proc, aligned_end, aligned_new_end, + virt_to_phys(p), 0); + return address; +} + +int remove_process_region(struct process *proc, + unsigned long start, unsigned long end) +{ + if ((start & (PAGE_SIZE - 1)) || (end & (PAGE_SIZE - 1))) { + return -EINVAL; + } + + while (start < end) { + aal_mc_pt_clear_page(proc->page_table, (void *)start); + start += PAGE_SIZE; + } + + return 0; +} + +static void idle(void) +{ + while (1) { + cpu_enable_interrupt(); + schedule(); + cpu_halt(); + } +} + +void sched_init(void) +{ + struct process *idle_process = &cpu_local_var(idle); + + memset(idle_process, 0, sizeof(struct process)); + + aal_mc_init_context(&idle_process->ctx, NULL, idle); + + cpu_local_var(next) = idle_process; +} + +void schedule(void) +{ + struct cpu_local_var *v = get_this_cpu_local_var(); + struct process *next, *prev; + int switch_ctx = 0; + + cpu_disable_interrupt(); + if (v->next && v->next != v->current) { + prev = v->current; + next = v->next; + + switch_ctx = 1; + + v->current = next; + v->next = NULL; + } + cpu_enable_interrupt(); + + if (switch_ctx) { + kprintf("schedule: %p => %p \n", prev, next); + aal_mc_load_page_table(next->page_table); + + if (prev) { + aal_mc_switch_context(&prev->ctx, &next->ctx); + } else { + aal_mc_switch_context(NULL, &next->ctx); + } + } +} + + diff --git a/kernel/scripts/mkimage.mee b/kernel/scripts/mkimage.mee index d503c8ef..f0a26965 100644 --- a/kernel/scripts/mkimage.mee +++ b/kernel/scripts/mkimage.mee @@ -5,6 +5,8 @@ set -e O=`pwd` make -C $3/../kboot O=$O clean -make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x3a001000 +#make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x3a001000 +#make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x101001000 +make -C $3/../kboot O=$O KIMAGE="$O/$1" LOAD_PA=0x901001000 cat $3/../elfboot/elfboot kboot/kboot.elf > $2 diff --git a/kernel/syscall.c b/kernel/syscall.c index c69d5354..49f48983 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -3,11 +3,308 @@ #include #include #include +#include #include +#include +#include +#include -int syscall(int num, aal_mc_user_context_t *ctx) +static void send_syscall(struct syscall_request *req) { - kprintf("System call #%d\n", num); + struct ikc_scd_packet packet; + struct syscall_response *res = cpu_local_var(scp).response_va; - return -ENOSYS; + res->status = 0; + /* TODO: copy by DMA */ + memcpy_long(cpu_local_var(scp).request_va, req, sizeof(*req)); + + packet.msg = SCD_MSG_SYSCALL_ONESIDE; + packet.ref = aal_mc_get_processor_id(); + packet.arg = cpu_local_var(scp).request_rpa; + + aal_ikc_send(cpu_local_var(syscall_channel), &packet, 0); +} + +static int do_syscall(struct syscall_request *req) +{ + struct syscall_response *res = cpu_local_var(scp).response_va; + + send_syscall(req); + + while (!res->status) { + cpu_pause(); + } + + return res->ret; +} + +long sys_brk(int n, aal_mc_user_context_t *ctx) +{ + unsigned long address = aal_mc_syscall_arg0(ctx); + struct vm_regions *region = &cpu_local_var(current)->region; + + region->brk_end = + extend_process_region(cpu_local_var(current), + region->brk_start, region->brk_end, + address); + return region->brk_end; + +} + +#define SYSCALL_DECLARE(name) long sys_##name(int n, aal_mc_user_context_t *ctx) +#define SYSCALL_HEADER struct syscall_request request; \ + request.number = n +#define SYSCALL_ARG_D(n) request.args[n] = aal_mc_syscall_arg##n(ctx) +#define SYSCALL_ARG_MO(n) \ + do { \ + unsigned long __phys; \ + if (aal_mc_pt_virt_to_phys(cpu_local_var(current)->page_table, \ + (void *)aal_mc_syscall_arg##n(ctx),\ + &__phys)) { \ + return -EFAULT; \ + }\ + request.args[n] = __phys; \ + } while(0) +#define SYSCALL_ARG_MI(n) \ + do { \ + unsigned long __phys; \ + if (aal_mc_pt_virt_to_phys(cpu_local_var(current)->page_table, \ + (void *)aal_mc_syscall_arg##n(ctx),\ + &__phys)) { \ + return -EFAULT; \ + }\ + request.args[n] = __phys; \ + } while(0) + + +#define SYSCALL_ARGS_1(a0) SYSCALL_ARG_##a0(0) +#define SYSCALL_ARGS_2(a0, a1) SYSCALL_ARG_##a0(0); SYSCALL_ARG_##a1(1) +#define SYSCALL_ARGS_3(a0, a1, a2) SYSCALL_ARG_##a0(0); SYSCALL_ARG_##a1(1); \ + SYSCALL_ARG_##a2(2) +#define SYSCALL_ARGS_4(a0, a1, a2, a3) \ + SYSCALL_ARG_##a0(0); SYSCALL_ARG_##a1(1); \ + SYSCALL_ARG_##a2(2); SYSCALL_ARG_##a3(3) + +#define SYSCALL_FOOTER return do_syscall(&request) + +SYSCALL_DECLARE(fstat) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_2(D, MO); + SYSCALL_FOOTER; +} + +static int stop(void) +{ + while(1); + return 0; +} + +SYSCALL_DECLARE(open) +{ + SYSCALL_HEADER; + + SYSCALL_ARGS_3(MI, D, D); + + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(ioctl) +{ + SYSCALL_HEADER; + + /* Very ad-hoc for termios */ + switch(aal_mc_syscall_arg1(ctx)) { + case 0x5401: + SYSCALL_ARGS_3(D, D, MO); + SYSCALL_FOOTER; + } + + return -EINVAL; +} + +SYSCALL_DECLARE(read) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_3(D, MO, D); + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(pread) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_4(D, MO, D, D); + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(write) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_3(D, MI, D); + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(pwrite) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_4(D, MI, D, D); + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(close) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_1(D); + SYSCALL_FOOTER; +} + +SYSCALL_DECLARE(lseek) +{ + SYSCALL_HEADER; + SYSCALL_ARGS_3(D, D, D); + SYSCALL_FOOTER; +} + + +SYSCALL_DECLARE(exit_group) +{ + SYSCALL_HEADER; + send_syscall(&request); + + cpu_local_var(current) = NULL; + cpu_local_var(next) = &cpu_local_var(idle); + schedule(); + + return 0; +} + +SYSCALL_DECLARE(mmap) +{ + unsigned long address, ret; + struct vm_regions *region = &cpu_local_var(current)->region; + + /* anonymous */ + if (aal_mc_syscall_arg3(ctx) & 0x22) { + ret = region->map_end; + address = region->map_end + aal_mc_syscall_arg1(ctx); + + region->map_end = + extend_process_region(cpu_local_var(current), + region->map_start, + region->map_end, + address); + if (region->map_end == address) { + return ret; + } else { + return -EINVAL; + } + } + kprintf("Non-anonymous mmap: fd = %lx, %lx\n", + aal_mc_syscall_arg4(ctx), aal_mc_syscall_arg5(ctx)); + while(1); +} + +SYSCALL_DECLARE(munmap) +{ + unsigned long address, len; + + address = aal_mc_syscall_arg0(ctx); + len = aal_mc_syscall_arg1(ctx); + + return remove_process_region(cpu_local_var(current), address, + address + len); +} + +SYSCALL_DECLARE(getpid) +{ + return cpu_local_var(current)->pid; +} + +long sys_uname(int n, aal_mc_user_context_t *ctx) +{ + struct syscall_request request; + unsigned long phys; + + if (aal_mc_pt_virt_to_phys(cpu_local_var(current)->page_table, + (void *)aal_mc_syscall_arg0(ctx), &phys)) { + return -EFAULT; + } + + request.number = n; + request.args[0] = phys; + + return do_syscall(&request); +} + +long sys_getxid(int n, aal_mc_user_context_t *ctx) +{ + struct syscall_request request; + + request.number = n; + + return do_syscall(&request); +} + +long sys_arch_prctl(int n, aal_mc_user_context_t *ctx) +{ + unsigned long code = aal_mc_syscall_arg0(ctx); + unsigned long address = aal_mc_syscall_arg1(ctx); + + switch (code) { + case 0x1002: + return aal_mc_arch_set_special_register(AAL_ASR_X86_FS, + address); + + case 0x1003: + return aal_mc_arch_get_special_register(AAL_ASR_X86_FS, + (unsigned long *) + address); + } + + return -EINVAL; +} + +static long (*syscall_table[])(int, aal_mc_user_context_t *) = { + [0] = sys_read, + [1] = sys_write, + [2] = sys_open, + [3] = sys_close, + [5] = sys_fstat, + [8] = sys_lseek, + [9] = sys_mmap, + [11] = sys_munmap, + [12] = sys_brk, + [16] = sys_ioctl, + [17] = sys_pread, + [18] = sys_pwrite, + [39] = sys_getpid, + [63] = sys_uname, + [102] = sys_getxid, + [104] = sys_getxid, + [107] = sys_getxid, + [108] = sys_getxid, + [110] = sys_getxid, + [111] = sys_getxid, + [158] = sys_arch_prctl, + [231] = sys_exit_group, +}; + +long syscall(int num, aal_mc_user_context_t *ctx) +{ + long l; + + cpu_enable_interrupt(); + + if (syscall_table[num]) { + l = syscall_table[num](num, ctx); + return l; + } else { + kprintf("USC[%3d](%lx, %lx, %lx, %lx, %lx) @ %lx | %lx\n", num, + aal_mc_syscall_arg0(ctx), aal_mc_syscall_arg1(ctx), + aal_mc_syscall_arg2(ctx), aal_mc_syscall_arg3(ctx), + aal_mc_syscall_arg4(ctx), aal_mc_syscall_pc(ctx), + aal_mc_syscall_sp(ctx)); + while(1); + return -ENOSYS; + } } diff --git a/linux/executer/Makefile b/linux/executer/Makefile new file mode 100644 index 00000000..ef502e60 --- /dev/null +++ b/linux/executer/Makefile @@ -0,0 +1,6 @@ +CFLAGS = -O3 + +all: mcexec + +mcexec: mcexec.c + $(CC) $(CFLAGS) -o $@ $^ diff --git a/linux/executer/mcexec.c b/linux/executer/mcexec.c new file mode 100644 index 00000000..d13e1280 --- /dev/null +++ b/linux/executer/mcexec.c @@ -0,0 +1,418 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/uprotocol.h" +#include + +#include +#include +#include +#include +#include + +#ifndef DEBUG +#define __dprint(msg, ...) +#define __dprintf(arg, ...) +#define __eprint(msg, ...) +#define __eprinf(format, ...) +#else +#define __dprint(msg, ...) printf("%s: " msg, __FUNCTION__) +#define __dprintf(format, ...) printf("%s: " format, __FUNCTION__, \ + __VA_ARGS__) +#define __eprint(msg, ...) fprintf(stderr, "%s: " msg, __FUNCTION__) +#define __eprintf(format, ...) fprintf(stderr, "%s: " format, __FUNCTION__, \ + __VA_ARGS__) +#endif + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#ifdef NCCS +#undef NCCS +#endif + +#define NCCS 19 +struct kernel_termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +int main_loop(int fd, int cpu); + +struct program_load_desc *load_elf(FILE *fp) +{ + Elf64_Ehdr hdr; + Elf64_Phdr phdr; + int i, j, nhdrs = 0; + struct program_load_desc *desc; + + if (fread(&hdr, sizeof(hdr), 1, fp) < 1) { + __eprint("Cannot read Ehdr.\n"); + return NULL; + } + if (memcmp(hdr.e_ident, ELFMAG, SELFMAG)) { + __eprint("ELFMAG mismatched.\n"); + return NULL; + } + fseek(fp, hdr.e_phoff, SEEK_SET); + for (i = 0; i < hdr.e_phnum; i++) { + if (fread(&phdr, sizeof(phdr), 1, fp) < 1) { + __eprintf("Loading phdr failed (%d)\n", i); + return NULL; + } + if (phdr.p_type == PT_LOAD) { + nhdrs++; + } + } + + desc = malloc(sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * nhdrs); + fseek(fp, hdr.e_phoff, SEEK_SET); + j = 0; + desc->num_sections = nhdrs; + for (i = 0; i < hdr.e_phnum; i++) { + if (fread(&phdr, sizeof(phdr), 1, fp) < 1) { + __eprintf("Loading phdr failed (%d)\n", i); + return NULL; + } + if (phdr.p_type == PT_LOAD) { + desc->sections[j].vaddr = phdr.p_vaddr; + desc->sections[j].filesz = phdr.p_filesz; + desc->sections[j].offset = phdr.p_offset; + desc->sections[j].len = phdr.p_memsz; + + __dprintf("%d: %lx, %lx, %lx, %lx\n", + j, desc->sections[j].vaddr, + desc->sections[j].filesz, + desc->sections[j].offset, + desc->sections[j].len); + j++; + } + } + desc->pid = getpid(); + desc->entry = hdr.e_entry; + + return desc; +} + +unsigned char *dma_buf; + + +#define PAGE_SIZE 4096 +#define PAGE_MASK ~((unsigned long)PAGE_SIZE - 1) + +void transfer_image(FILE *fp, int fd, struct program_load_desc *desc) +{ + struct program_transfer pt; + unsigned long s, e, flen, rpa; + int i, l, lr; + + for (i = 0; i < desc->num_sections; i++) { + s = (desc->sections[i].vaddr) & PAGE_MASK; + e = (desc->sections[i].vaddr + desc->sections[i].len + + PAGE_SIZE - 1) & PAGE_MASK; + rpa = desc->sections[i].remote_pa; + + fseek(fp, desc->sections[i].offset, SEEK_SET); + flen = desc->sections[i].filesz; + + __dprintf("seeked to %lx | size %lx\n", + desc->sections[i].offset, flen); + + while (s < e) { + pt.dest = rpa; + pt.src = dma_buf; + pt.sz = PAGE_SIZE; + + memset(dma_buf, 0, PAGE_SIZE); + if (s < desc->sections[i].vaddr) { + l = desc->sections[i].vaddr + & (PAGE_SIZE - 1); + lr = PAGE_SIZE - l; + if (lr > flen) { + lr = flen; + } + fread(dma_buf + l, 1, lr, fp); + flen -= lr; + } else if (flen > 0) { + if (flen > PAGE_SIZE) { + lr = PAGE_SIZE; + } else { + lr = flen; + } + fread(dma_buf, 1, lr, fp); + flen -= lr; + } + s += PAGE_SIZE; + rpa += PAGE_SIZE; + + if (ioctl(fd, MCEXEC_UP_LOAD_IMAGE, + (unsigned long)&pt)) { + perror("dma"); + break; + } + } + + } +} + +void print_desc(struct program_load_desc *desc) +{ + int i; + + __dprintf("Desc (%p)\n", desc); + __dprintf("Status = %d, CPU = %d, pid = %d, entry = %lx, rp = %lx\n", + desc->status, desc->cpu, desc->pid, desc->entry, + desc->rprocess); + for (i = 0; i < desc->num_sections; i++) { + __dprintf("%lx, %lx, %lx\n", desc->sections[i].vaddr, + desc->sections[i].len, desc->sections[i].remote_pa); + } +} + +#define PIN_SHIFT 16 +#define PIN_SIZE (1 << PIN_SHIFT) +#define PIN_MASK ~(unsigned long)(PIN_SIZE - 1) + +unsigned long dma_buf_pa; + +int main(int argc, char **argv) +{ + int fd, fdm; + FILE *fp; + struct program_load_desc *desc; + long r; + + if (argc < 2) { + fprintf(stderr, "Usage: %s (program) [args...]\n", + argv[0]); + return 1; + } + + fp = fopen(argv[1], "rb"); + if (!fp) { + fprintf(stderr, "Error: Failed to open %s\n", argv[1]); + return 1; + } + desc = load_elf(fp); + if (!desc) { + fclose(fp); + fprintf(stderr, "Error: Failed to parse ELF!\n"); + return 1; + } + + __dprintf("# of sections: %d\n", desc->num_sections); + + fd = open("/dev/mcos0", O_RDWR); + if (fd < 0) { + fprintf(stderr, "Error: Failed to open /dev/mcctrl.\n"); + return 1; + } + fdm = open("/dev/mem", O_RDWR); + if (fdm < 0) { + fprintf(stderr, "Error: Failed to open /dev/mem.\n"); + return 1; + } + + if ((r = ioctl(fd, MCEXEC_UP_PREPARE_DMA, + (unsigned long)&dma_buf_pa)) < 0) { + perror("prepare_dma"); + close(fd); + return 1; + } + + dma_buf = mmap(NULL, PIN_SIZE, PROT_READ | PROT_WRITE, + MAP_SHARED, fdm, dma_buf_pa); + __dprintf("DMA Buffer: %lx, %p\n", dma_buf_pa, dma_buf); + + if (ioctl(fd, MCEXEC_UP_PREPARE_IMAGE, (unsigned long)desc) != 0) { + perror("prepare"); + close(fd); + return 1; + } + + print_desc(desc); + transfer_image(fp, fd, desc); + fflush(stdout); + fflush(stderr); + + if (ioctl(fd, MCEXEC_UP_START_IMAGE, (unsigned long)desc) != 0) { + perror("exec"); + close(fd); + return 1; + } + + return main_loop(fd, desc->cpu); +} + +void do_syscall_return(int fd, int cpu, + int ret, int n, unsigned long src, unsigned long dest, + unsigned long sz) +{ + struct syscall_ret_desc desc; + + desc.cpu = cpu; + desc.ret = ret; + desc.src = src; + desc.dest = dest; + desc.size = sz; + + if (ioctl(fd, MCEXEC_UP_RET_SYSCALL, (unsigned long)&desc) != 0) { + perror("ret"); + } +} + +void do_syscall_load(int fd, int cpu, unsigned long dest, unsigned long src, + unsigned long sz) +{ + struct syscall_load_desc desc; + + desc.cpu = cpu; + desc.src = src; + desc.dest = dest; + desc.size = sz; + + if (ioctl(fd, MCEXEC_UP_LOAD_SYSCALL, (unsigned long)&desc) != 0){ + perror("load"); + } +} + +int main_loop(int fd, int cpu) +{ + struct syscall_wait_desc w; + int ret; + + w.cpu = cpu; + + while (ioctl(fd, MCEXEC_UP_WAIT_SYSCALL, (unsigned long)&w) == 0) { + switch (w.sr.number) { + case __NR_open: + dma_buf[256] = 0; + do_syscall_load(fd, cpu, dma_buf_pa, w.sr.args[0], 256); + + while (!dma_buf[256]) { + asm volatile ("" : : : "memory"); + } + ret = open(dma_buf, w.sr.args[1], w.sr.args[2]); + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + case __NR_close: + ret = close(w.sr.args[0]); + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + case __NR_read: + ret = read(w.sr.args[0], dma_buf, w.sr.args[2]); + do_syscall_return(fd, cpu, ret, 1, dma_buf_pa, + w.sr.args[1], w.sr.args[2]); + break; + + case __NR_write: + dma_buf[w.sr.args[2]] = 0; + do_syscall_load(fd, cpu, dma_buf_pa, + w.sr.args[1], w.sr.args[2]); + + while (!dma_buf[w.sr.args[2]]) { + asm volatile ("" : : : "memory"); + } + + ret = write(w.sr.args[0], dma_buf, w.sr.args[2]); + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + case __NR_lseek: + ret = lseek64(w.sr.args[0], w.sr.args[1], w.sr.args[2]); + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + case __NR_pread64: + ret = pread(w.sr.args[0], dma_buf, w.sr.args[2], + w.sr.args[3]); + do_syscall_return(fd, cpu, ret, 1, dma_buf_pa, + w.sr.args[1], w.sr.args[2]); + break; + + case __NR_pwrite64: + dma_buf[w.sr.args[2]] = 0; + do_syscall_load(fd, cpu, dma_buf_pa, + w.sr.args[1], w.sr.args[2]); + + while (!dma_buf[w.sr.args[2]]) { + asm volatile ("" : : : "memory"); + } + + ret = pwrite(w.sr.args[0], dma_buf, w.sr.args[2], + w.sr.args[3]); + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + + case __NR_fstat: + ret = fstat(w.sr.args[0], (void *)dma_buf); + if (ret == -1) { + ret = -errno; + } + do_syscall_return(fd, cpu, ret, 1, dma_buf_pa, + w.sr.args[1], sizeof(struct stat)); + break; + + case __NR_ioctl: + if (w.sr.args[1] == TCGETS) { + ret = ioctl(w.sr.args[0], w.sr.args[1], + (unsigned long)dma_buf); + if (ret == -1) { + ret = -errno; + } + do_syscall_return(fd, cpu, ret, 1, dma_buf_pa, + w.sr.args[2], + sizeof(struct kernel_termios) + ); + } + break; + + case __NR_getgid: + case __NR_getuid: + case __NR_geteuid: + case __NR_getegid: + case __NR_getppid: + case __NR_getpgrp: + ret = syscall(w.sr.number); + if (ret == -1) { + ret = -errno; + } + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + case __NR_exit: + case __NR_exit_group: + return w.sr.args[0]; + + case __NR_uname: + ret = uname((void *)dma_buf); + if (ret == -1) { + ret = -errno; + } + do_syscall_return(fd, + cpu, ret, 1, dma_buf_pa, w.sr.args[0], + sizeof(struct utsname)); + break; + default: + printf("Unhandled system calls: %ld\n", w.sr.number); + break; + + } + } +} diff --git a/linux/include/uprotocol.h b/linux/include/uprotocol.h new file mode 100644 index 00000000..e5bc8bcf --- /dev/null +++ b/linux/include/uprotocol.h @@ -0,0 +1,67 @@ +#ifndef HEADER_UPROTOCOL_H +#define HEADER_UPROTOCOL_H + +#define MCEXEC_UP_PREPARE_IMAGE 0x30a02900 +#define MCEXEC_UP_LOAD_IMAGE 0x30a02901 +#define MCEXEC_UP_START_IMAGE 0x30a02902 +#define MCEXEC_UP_WAIT_SYSCALL 0x30a02903 +#define MCEXEC_UP_RET_SYSCALL 0x30a02904 +#define MCEXEC_UP_LOAD_SYSCALL 0x30a02905 + +#define MCEXEC_UP_PREPARE_DMA 0x30a02910 + +struct program_transfer { + unsigned long dest; + void *src; + unsigned long sz; +}; + +struct program_image_section { + unsigned long vaddr; + unsigned long len; + unsigned long remote_pa; + unsigned long filesz, offset; + void *source; +}; + +struct program_load_desc { + int num_sections; + int status; + int cpu; + int pid; + unsigned long entry; + unsigned long rprocess; + struct program_image_section sections[0]; +}; + +struct syscall_request { + unsigned long number; + unsigned long args[5]; +}; + +struct syscall_wait_desc { + unsigned long cpu; + struct syscall_request sr; +}; + +struct syscall_load_desc { + unsigned long cpu; + unsigned long src; + unsigned long dest; + unsigned long size; +}; + +struct syscall_response { + unsigned long status; + long ret; +}; + +struct syscall_ret_desc { + long cpu; + long ret; + unsigned long src; + unsigned long dest; + unsigned long size; +}; + +#endif diff --git a/linux/mod_mcctrl/Makefile b/linux/mod_mcctrl/Makefile index f82a87e0..aa51ced8 100644 --- a/linux/mod_mcctrl/Makefile +++ b/linux/mod_mcctrl/Makefile @@ -6,7 +6,7 @@ endif obj-m += mcctrl.o -mcctrl-objs := driver.o control.o +mcctrl-objs := driver.o control.o ikc.o AAL_BASE=$(src)/../../../aal EXTRA_CFLAGS = -I$(AAL_BASE)/host/include -I$(AAL_BASE)/ikc/include -I$(src)/../include diff --git a/linux/mod_mcctrl/control.c b/linux/mod_mcctrl/control.c index f9ffc74b..0751d1b2 100644 --- a/linux/mod_mcctrl/control.c +++ b/linux/mod_mcctrl/control.c @@ -1,51 +1,279 @@ #include #include #include +#include +#include #include +#include #include "mcctrl.h" -static struct aal_ikc_listen_param __listen_param = { - .port = 501, - .handler = test_handler, - .pkt_size = sizeof(struct ikc_test_packet), - .queue_size = 4096, - .magic = 0x29, -}; +static DECLARE_WAIT_QUEUE_HEAD(wq_prepare); +extern struct mcctrl_channel *channels; +int mcctrl_ikc_set_recv_cpu(int cpu); -static long mcexec_prepare_image(struct mcctrl_priv *data, +static long mcexec_prepare_image(aal_os_t os, struct program_load_desc * __user udesc) { - struct program_load_desc desc; + struct program_load_desc desc, *pdesc; + struct ikc_scd_packet isp; - if (!copy_from_user(&desc, udesc, + if (copy_from_user(&desc, udesc, sizeof(struct program_load_desc))) { return -EFAULT; } if (desc.num_sections <= 0 || desc.num_sections > 16) { + printk("# of sections: %d\n", desc.num_sections); return -EINVAL; } - data->desc = kmalloc(sizeof(struct program_load_desc) + - sizeof(struct program_image_section) - * desc.num_sections, GFP_KERNEL); - memcpy(data->desc, &desc, sizeof(struct program_load_desc)); - if (!copy_from_user(data->desc->sections, udesc->sections, - sizeof(struct program_image_section) - * desc.num_sections)) { - kfree(data->desc); + pdesc = kmalloc(sizeof(struct program_load_desc) + + sizeof(struct program_image_section) + * desc.num_sections, GFP_KERNEL); + memcpy(pdesc, &desc, sizeof(struct program_load_desc)); + if (copy_from_user(pdesc->sections, udesc->sections, + sizeof(struct program_image_section) + * desc.num_sections)) { + kfree(pdesc); + return -EFAULT; + } + + pdesc->pid = task_tgid_vnr(current); + + isp.msg = SCD_MSG_PREPARE_PROCESS; + isp.ref = pdesc->cpu; + isp.arg = virt_to_phys(pdesc); + + printk("# of sections: %d\n", pdesc->num_sections); + printk("%p (%lx)\n", pdesc, isp.arg); + + pdesc->status = 0; + mcctrl_ikc_send(pdesc->cpu, &isp); + + wait_event_interruptible(wq_prepare, pdesc->status); + + copy_to_user(udesc, pdesc, sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * desc.num_sections); + + kfree(pdesc); + + return 0; +} + +int mcexec_load_image(aal_os_t os, struct program_transfer *__user upt) +{ + struct program_transfer pt; + unsigned long dma_status = 0; + aal_dma_channel_t channel; + struct aal_dma_request request; + void *p; + + channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0); + if (!channel) { + return -EINVAL; + } + + if (copy_from_user(&pt, upt, sizeof(pt))) { + return -EFAULT; + } + p = (void *)__get_free_page(GFP_KERNEL); + + if (copy_from_user(p, pt.src, PAGE_SIZE)) { + return -EFAULT; + } + + memset(&request, 0, sizeof(request)); + request.src_os = NULL; + request.src_phys = virt_to_phys(p); + request.dest_os = os; + request.dest_phys = pt.dest; + request.size = PAGE_SIZE; + request.notify = (void *)virt_to_phys(&dma_status); + request.priv = (void *)1; + + aal_dma_request(channel, &request); + + while (!dma_status) { + mb(); + udelay(1); + } + + free_page((unsigned long)p); + + return 0; +} + +static long mcexec_start_image(aal_os_t os, + struct program_load_desc * __user udesc) +{ + struct program_load_desc desc; + struct ikc_scd_packet isp; + + if (copy_from_user(&desc, udesc, + sizeof(struct program_load_desc))) { + return -EFAULT; + } + + mcctrl_ikc_set_recv_cpu(desc.cpu); + + isp.msg = SCD_MSG_SCHEDULE_PROCESS; + isp.ref = desc.cpu; + isp.arg = desc.rprocess; + + mcctrl_ikc_send(desc.cpu, &isp); + + return 0; +} + +int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg) +{ + c->req = 1; + wake_up(&c->wq_syscall); + + return 0; +} + +int mcexec_wait_syscall(aal_os_t os, struct syscall_wait_desc *__user req) +{ + struct syscall_wait_desc swd; + struct mcctrl_channel *c; + + if (copy_from_user(&swd, req, sizeof(swd.cpu))) { + return -EFAULT; + } + + c = channels + swd.cpu; + + wait_event_interruptible(c->wq_syscall, c->req); + c->req = 0; + + if (copy_to_user(&req->sr, c->param.request_va, + sizeof(struct syscall_request))) { return -EFAULT; } return 0; } -long __mcctrl_control(struct mcctrl_priv *data, unsigned int req, - unsigned long arg) +long mcexec_pin_region(aal_os_t os, unsigned long *__user uaddress) +{ + int pin_shift = 16; + unsigned long a; + + a = __get_free_pages(GFP_KERNEL, pin_shift - PAGE_SHIFT); + if (!a) { + return -ENOMEM; + } + + a = virt_to_phys((void *)a); + + if (copy_to_user(uaddress, &a, sizeof(unsigned long))) { + return -EFAULT; + } + return 0; +} + +long mcexec_load_syscall(aal_os_t os, struct syscall_load_desc *__user arg) +{ + struct syscall_load_desc desc; + aal_dma_channel_t channel; + struct aal_dma_request request; + + channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0); + if (!channel) { + return -EINVAL; + } + + if (copy_from_user(&desc, arg, sizeof(struct syscall_load_desc))) { + return -EFAULT; + } + + memset(&request, 0, sizeof(request)); + request.src_os = os; + request.src_phys = desc.src; + request.dest_os = NULL; + request.dest_phys = desc.dest; + request.size = desc.size; + request.notify = (void *)(desc.dest + desc.size); + request.priv = (void *)1; + + aal_dma_request(channel, &request); + + return 0; +} + +long mcexec_ret_syscall(aal_os_t os, struct syscall_ret_desc *__user arg) +{ + struct syscall_ret_desc ret; + aal_dma_channel_t channel; + struct aal_dma_request request; + struct mcctrl_channel *mc; + + channel = aal_device_get_dma_channel(aal_os_to_dev(os), 0); + if (!channel) { + return -EINVAL; + } + + if (copy_from_user(&ret, arg, sizeof(struct syscall_ret_desc))) { + return -EFAULT; + } + mc = channels + ret.cpu; + if (!mc) { + return -EINVAL; + } + + mc->param.response_va->ret = ret.ret; + + if (ret.size > 0) { + memset(&request, 0, sizeof(request)); + request.src_os = NULL; + request.src_phys = ret.src; + request.dest_os = os; + request.dest_phys = ret.dest; + request.size = ret.size; + request.notify = (void *)mc->param.response_pa; + request.priv = (void *)1; + + aal_dma_request(channel, &request); + } else { + mc->param.response_va->status = 1; + } + + return 0; +} + +long __mcctrl_control(aal_os_t os, unsigned int req, unsigned long arg) { switch (req) { case MCEXEC_UP_PREPARE_IMAGE: - return mcexec_prepare_image((struct mcctrl_priv *)data, + return mcexec_prepare_image(os, (struct program_load_desc *)arg); + case MCEXEC_UP_LOAD_IMAGE: + return mcexec_load_image(os, (struct program_transfer *)arg); + + case MCEXEC_UP_START_IMAGE: + return mcexec_start_image(os, (struct program_load_desc *)arg); + + case MCEXEC_UP_WAIT_SYSCALL: + return mcexec_wait_syscall(os, (struct syscall_wait_desc *)arg); + + case MCEXEC_UP_RET_SYSCALL: + return mcexec_ret_syscall(os, (struct syscall_ret_desc *)arg); + + case MCEXEC_UP_LOAD_SYSCALL: + return mcexec_load_syscall(os, (struct syscall_load_desc *)arg); + + case MCEXEC_UP_PREPARE_DMA: + return mcexec_pin_region(os, (unsigned long *)arg); + } return -EINVAL; } +void mcexec_prepare_ack(unsigned long arg) +{ + struct program_load_desc *desc = phys_to_virt(arg); + + desc->status = 1; + + wake_up_all(&wq_prepare); +} + diff --git a/linux/mod_mcctrl/driver.c b/linux/mod_mcctrl/driver.c index 010e1970..be8bf941 100644 --- a/linux/mod_mcctrl/driver.c +++ b/linux/mod_mcctrl/driver.c @@ -9,63 +9,51 @@ #include #include "mcctrl.h" -extern long __mcctrl_control(struct mcctrl_priv *, unsigned int, unsigned long); +extern long __mcctrl_control(aal_os_t, unsigned int, unsigned long); +extern int prepare_ikc_channels(aal_os_t os); -static int mcctrl_open(struct inode *inode, struct file *file) -{ - struct mcctrl_priv *mcc_data; - - mcc_data = kzalloc(sizeof(struct mcctrl_priv), GFP_KERNEL); - if (!mcc_data) { - return -ENOMEM; - } - - file->private_data = mcc_data; - return 0; -} - -static int mcctrl_release(struct inode *inode, struct file *file) -{ - struct mcctrl_priv *mcc_data = file->private_data; - - if (mcc_data) { - if (mcc_data->desc) { - kfree(mcc_data->desc); - } - kfree(mcc_data); - } - - return 0; -} - -static long mcctrl_ioctl(struct file *file, unsigned int request, +static long mcctrl_ioctl(aal_os_t os, unsigned int request, void *priv, unsigned long arg) { - struct mcctrl_priv *mcc_data = file->private_data; - - return __mcctrl_control(mcc_data, request, arg); + return __mcctrl_control(os, request, arg); } -static struct file_operations mcctrl_ops = { - .open = mcctrl_open, - .unlocked_ioctl = mcctrl_ioctl, - .release = mcctrl_release, +static struct aal_os_user_call_handler mcctrl_uchs[] = { + { .request = MCEXEC_UP_PREPARE_IMAGE, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_LOAD_IMAGE, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_START_IMAGE, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_WAIT_SYSCALL, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_RET_SYSCALL, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_LOAD_SYSCALL, .func = mcctrl_ioctl }, + { .request = MCEXEC_UP_PREPARE_DMA, .func = mcctrl_ioctl }, }; -static struct miscdevice mcctrl_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "mcctrl", - .fops = &mcctrl_ops, +static struct aal_os_user_call mcctrl_uc = { + .num_handlers = sizeof(mcctrl_uchs) / sizeof(mcctrl_uchs[0]), + .handlers = mcctrl_uchs, }; +static aal_os_t os; + static int __init mcctrl_init(void) { - return misc_register(&mcctrl_dev); + os = aal_host_find_os(0, NULL); + if (!os) { + printk("OS #0 not found.\n"); + return -ENOENT; + } + if (prepare_ikc_channels(os) != 0) { + printk("Preparing syscall channels failed.\n"); + return -EINVAL; + } + + + return aal_os_register_user_call_handlers(os, &mcctrl_uc); } static void __exit mcctrl_exit(void) { - misc_deregister(&mcctrl_dev); + aal_os_unregister_user_call_handlers(os, &mcctrl_uc); } MODULE_LICENSE("GPL v2"); diff --git a/linux/mod_mcctrl/ikc.c b/linux/mod_mcctrl/ikc.c new file mode 100644 index 00000000..98cd6741 --- /dev/null +++ b/linux/mod_mcctrl/ikc.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include +#include "mcctrl.h" +#include +#include + +static int num_channels; + +struct mcctrl_channel *channels; + +void mcexec_prepare_ack(unsigned long arg); +static void mcctrl_ikc_init(aal_os_t os, int cpu, unsigned long rphys); +int mcexec_syscall(struct mcctrl_channel *c, unsigned long arg); + +static int syscall_packet_handler(struct aal_ikc_channel_desc *c, + void *__packet, void *__os) +{ + struct ikc_scd_packet *pisp = __packet; + + switch (pisp->msg) { + case SCD_MSG_INIT_CHANNEL: + mcctrl_ikc_init(__os, pisp->ref, pisp->arg); + break; + + case SCD_MSG_PREPARE_PROCESS_ACKED: + mcexec_prepare_ack(pisp->arg); + break; + + case SCD_MSG_SYSCALL_ONESIDE: + mcexec_syscall(channels + pisp->ref, pisp->arg); + break; + } + + return 0; +} + +int mcctrl_ikc_send(int cpu, struct ikc_scd_packet *pisp) +{ + if (cpu < 0 || cpu >= num_channels || !channels[cpu].c) { + return -EINVAL; + } + return aal_ikc_send(channels[cpu].c, pisp, 0); +} + +int mcctrl_ikc_set_recv_cpu(int cpu) +{ + aal_ikc_channel_set_cpu(channels[cpu].c, + aal_ikc_get_processor_id()); + kprintf("Setting the target to %d\n", + aal_ikc_get_processor_id()); + return 0; +} + +static void mcctrl_ikc_init(aal_os_t os, int cpu, unsigned long rphys) +{ + struct ikc_scd_packet packet; + struct mcctrl_channel *pmc = channels + cpu; + unsigned long phys; + struct ikc_scd_init_param *rpm; + + if (!pmc) { + return; + } + + phys = aal_device_map_memory(aal_os_to_dev(os), rphys, + sizeof(struct ikc_scd_init_param)); + rpm = ioremap_wc(phys, sizeof(struct ikc_scd_init_param)); + + pmc->param.request_va = (void *)__get_free_page(GFP_KERNEL); + pmc->param.request_pa = virt_to_phys(pmc->param.request_va); + pmc->param.doorbell_va = (void *)__get_free_page(GFP_KERNEL); + pmc->param.doorbell_pa = virt_to_phys(pmc->param.doorbell_va); + + pmc->param.response_rpa = rpm->response_page; + pmc->param.response_pa + = aal_device_map_memory(aal_os_to_dev(os), + pmc->param.response_rpa, + PAGE_SIZE); + pmc->param.response_va = ioremap_wc(pmc->param.response_pa, + PAGE_SIZE); + + rpm->request_page = pmc->param.request_pa; + rpm->doorbell_page = pmc->param.doorbell_pa; + + packet.msg = SCD_MSG_INIT_CHANNEL_ACKED; + packet.ref = cpu; + packet.arg = rphys; + + aal_ikc_send(pmc->c, &packet, 0); + + iounmap(rpm); + + aal_device_unmap_memory(aal_os_to_dev(os), phys, + sizeof(struct ikc_scd_init_param)); +} + +static int connect_handler(struct aal_ikc_channel_info *param) +{ + struct aal_ikc_channel_desc *c; + int cpu; + + c = param->channel; + cpu = c->send.queue->read_cpu; + + if (cpu < 0 || cpu >= num_channels) { + kprintf("Invalid connect source processor: %d\n", cpu); + return 1; + } + param->packet_handler = syscall_packet_handler; + init_waitqueue_head(&channels[cpu].wq_syscall); + + channels[cpu].c = c; + kprintf("syscall: MC CPU %d connected.\n", cpu); + + return 0; +} + +static struct aal_ikc_listen_param listen_param = { + .port = 501, + .handler = connect_handler, + .pkt_size = sizeof(struct ikc_scd_packet), + .queue_size = PAGE_SIZE, + .magic = 0x1129, +}; + +int prepare_ikc_channels(aal_os_t os) +{ + struct aal_cpu_info *info; + + info = aal_os_get_cpu_info(os); + if (!info) { + printk("Error: cannot retrieve CPU info.\n"); + return -EINVAL; + } + if (info->n_cpus < 1) { + printk("Error: # of cpu is invalid.\n"); + return -EINVAL; + } + + num_channels = info->n_cpus; + channels = kzalloc(sizeof(struct mcctrl_channel) * num_channels, + GFP_KERNEL); + if (!channels) { + printk("Error: cannot allocate channels.\n"); + return -ENOMEM; + } + + aal_ikc_listen_port(os, &listen_param); + return 0; +} diff --git a/linux/mod_mcctrl/mcctrl.h b/linux/mod_mcctrl/mcctrl.h index 167cd42a..eeddd3f2 100644 --- a/linux/mod_mcctrl/mcctrl.h +++ b/linux/mod_mcctrl/mcctrl.h @@ -3,10 +3,53 @@ #include #include +#include + +#define SCD_MSG_PREPARE_PROCESS 0x1 +#define SCD_MSG_PREPARE_PROCESS_ACKED 0x2 +#define SCD_MSG_SCHEDULE_PROCESS 0x3 + +#define SCD_MSG_INIT_CHANNEL 0x5 +#define SCD_MSG_INIT_CHANNEL_ACKED 0x6 + +#define SCD_MSG_SYSCALL_ONESIDE 0x4 + +struct ikc_scd_packet { + int msg; + int ref; + unsigned long arg; +}; struct mcctrl_priv { aal_os_t os; struct program_load_desc *desc; }; +struct ikc_scd_init_param { + unsigned long request_page; + unsigned long response_page; + unsigned long doorbell_page; +}; + +struct syscall_params { + unsigned long request_pa; + struct syscall_request *request_va; + unsigned long response_rpa, response_pa; + struct syscall_response *response_va; + + unsigned long doorbell_pa; + unsigned long *doorbell_va; +}; + +struct mcctrl_channel { + struct aal_ikc_channel_desc *c; + struct syscall_params param; + struct ikc_scd_init_param init; + + int req; + wait_queue_head_t wq_syscall; +}; + +int mcctrl_ikc_send(int cpu, struct ikc_scd_packet *pisp); + #endif