diff --git a/arch/x86/kernel/cpu.c b/arch/x86/kernel/cpu.c index 0818c210..067433f5 100644 --- a/arch/x86/kernel/cpu.c +++ b/arch/x86/kernel/cpu.c @@ -1834,4 +1834,22 @@ mod_nmi_ctx(void *nmi_ctx, void (*func)()) l[i++] = (unsigned long)(l + 27); // ols rsp l[i++] = 0x28; // KERNEL DS } + +int arch_cpu_read_write_register( + struct mcctrl_os_cpu_register *desc, + enum mcctrl_os_cpu_operation op) +{ + if (op == MCCTRL_OS_CPU_READ_REGISTER) { + desc->val = rdmsr(desc->addr); + } + else if (op == MCCTRL_OS_CPU_WRITE_REGISTER) { + wrmsr(desc->addr, desc->val); + } + else { + return -1; + } + + return 0; +} + /*** end of file ***/ diff --git a/executer/kernel/mcctrl/control.c b/executer/kernel/mcctrl/control.c index e3bbe693..55af3160 100644 --- a/executer/kernel/mcctrl/control.c +++ b/executer/kernel/mcctrl/control.c @@ -40,6 +40,7 @@ #include #include "../../config.h" #include "mcctrl.h" +#include "mcctrl_public.h" #include //#define DEBUG @@ -1937,3 +1938,149 @@ void mcexec_prepare_ack(ihk_os_t os, unsigned long arg, int err) mcctrl_put_per_proc_data(ppd); } +/* Per-CPU register manipulation functions */ +struct mcctrl_os_cpu_response { + int done; + unsigned long val; + wait_queue_head_t wq; +}; + +int mcctrl_get_request_os_cpu(ihk_os_t *ret_os, int *ret_cpu) +{ + ihk_os_t os; + struct mcctrl_usrdata *usrdata; + struct mcctrl_per_proc_data *ppd; + struct ikc_scd_packet *packet; + struct ihk_ikc_channel_desc *ch; + int ret = 0; + + /* Look up IHK OS structure + * TODO: iterate all possible indeces, currently only for OS 0 + */ + os = ihk_host_find_os(0, NULL); + if (!os) { + printk("%s: ERROR: no OS found for index 0\n", __FUNCTION__); + return -EINVAL; + } + + /* Look up per-OS mcctrl structure */ + usrdata = ihk_host_os_get_usrdata(os); + if (!usrdata) { + printk("%s: ERROR: no usrdata found for OS %p\n", __FUNCTION__, os); + return -EINVAL; + } + + /* Look up per-process structure */ + ppd = mcctrl_get_per_proc_data(usrdata, task_tgid_vnr(current)); + if (!ppd) { + kprintf("%s: ERROR: no per-process structure for PID %d??\n", + __FUNCTION__, task_tgid_vnr(current)); + return -EINVAL; + } + + /* Look up per-thread structure */ + packet = (struct ikc_scd_packet *)mcctrl_get_per_thread_data(ppd, current); + if (!packet) { + ret = -EINVAL; + printk("%s: ERROR: no packet registered for TID %d\n", + __FUNCTION__, task_pid_vnr(current)); + goto out_put_ppd; + } + + *ret_os = os; + /* TODO: define a new IHK query function instead of + * accessing internals directly */ + ch = (usrdata->channels + packet->ref)->c; + *ret_cpu = ch->send.queue->read_cpu; + ret = 0; + + printk("%s: OS: %p, CPU: %d\n", __FUNCTION__, os, *ret_cpu); + +out_put_ppd: + mcctrl_put_per_proc_data(ppd); + + return ret; +} + +EXPORT_SYMBOL(mcctrl_get_request_os_cpu); + +void mcctrl_os_read_write_cpu_response(ihk_os_t os, + struct ikc_scd_packet *pisp) +{ + struct mcctrl_os_cpu_response *resp; + + /* XXX: What if caller thread is unblocked by a signal + * before this message arrives? */ + resp = pisp->resp; + if (!resp) { + return; + } + + resp->val = pisp->desc.val; + resp->done = 1; + wake_up_interruptible(&resp->wq); +} + +int __mcctrl_os_read_write_cpu_register(ihk_os_t os, int cpu, + struct mcctrl_os_cpu_register *desc, + enum mcctrl_os_cpu_operation op) +{ + struct ikc_scd_packet isp; + struct mcctrl_os_cpu_response resp; + int ret = -EINVAL; + + memset(&isp, '\0', sizeof(struct ikc_scd_packet)); + isp.msg = SCD_MSG_CPU_RW_REG; + isp.op = op; + isp.desc = *desc; + isp.resp = &resp; + + resp.done = 0; + init_waitqueue_head(&resp.wq); + + mb(); + ret = mcctrl_ikc_send(os, cpu, &isp); + if (ret < 0) { + printk("%s: ERROR sending IKC msg: %d\n", __FUNCTION__, ret); + goto out; + } + + /* Wait for response */ + ret = wait_event_interruptible(resp.wq, resp.done); + if (ret < 0) { + printk("%s: ERROR after wait: %d\n", __FUNCTION__, ret); + goto out; + } + + /* Update if read */ + if (ret == 0 && op == MCCTRL_OS_CPU_READ_REGISTER) { + desc->val = resp.val; + } + + printk("%s: MCCTRL_OS_CPU_%s_REGISTER: reg: 0x%lx, val: 0x%lx\n", + __FUNCTION__, + (op == MCCTRL_OS_CPU_READ_REGISTER ? "READ" : "WRITE"), + desc->addr, desc->val); + +out: + return ret; +} + +int mcctrl_os_read_cpu_register(ihk_os_t os, int cpu, + struct mcctrl_os_cpu_register *desc) +{ + return __mcctrl_os_read_write_cpu_register(os, cpu, + desc, MCCTRL_OS_CPU_READ_REGISTER); +} + +EXPORT_SYMBOL(mcctrl_os_read_cpu_register); + +int mcctrl_os_write_cpu_register(ihk_os_t os, int cpu, + struct mcctrl_os_cpu_register *desc) +{ + return __mcctrl_os_read_write_cpu_register(os, cpu, + desc, MCCTRL_OS_CPU_WRITE_REGISTER); +} + +EXPORT_SYMBOL(mcctrl_os_write_cpu_register); + diff --git a/executer/kernel/mcctrl/ikc.c b/executer/kernel/mcctrl/ikc.c index 89263c02..f245c1e2 100644 --- a/executer/kernel/mcctrl/ikc.c +++ b/executer/kernel/mcctrl/ikc.c @@ -54,6 +54,8 @@ static void mcctrl_ikc_init(ihk_os_t os, int cpu, unsigned long rphys, struct ih int mcexec_syscall(struct mcctrl_usrdata *ud, struct ikc_scd_packet *packet); void sig_done(unsigned long arg, int err); void mcctrl_perf_ack(ihk_os_t os, struct ikc_scd_packet *packet); +void mcctrl_os_read_write_cpu_response(ihk_os_t os, + struct ikc_scd_packet *pisp); /* XXX: this runs in atomic context! */ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, @@ -113,6 +115,11 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, case SCD_MSG_PERF_ACK: mcctrl_perf_ack(__os, pisp); break; + + case SCD_MSG_CPU_RW_REG_RESP: + mcctrl_os_read_write_cpu_response(__os, pisp); + break; + default: printk(KERN_ERR "mcctrl:syscall_packet_handler:" "unknown message (%d.%d.%d.%d.%d.%#lx)\n", diff --git a/executer/kernel/mcctrl/mcctrl.h b/executer/kernel/mcctrl/mcctrl.h index 155f9937..f38acb3c 100644 --- a/executer/kernel/mcctrl/mcctrl.h +++ b/executer/kernel/mcctrl/mcctrl.h @@ -44,6 +44,7 @@ #include #include #include "sysfs.h" +#include "mcctrl_public.h" #define SCD_MSG_PREPARE_PROCESS 0x1 #define SCD_MSG_PREPARE_PROCESS_ACKED 0x2 @@ -95,6 +96,9 @@ #define SCD_MSG_PERF_CTRL 0x50 #define SCD_MSG_PERF_ACK 0x51 +#define SCD_MSG_CPU_RW_REG 0x52 +#define SCD_MSG_CPU_RW_REG_RESP 0x53 + #define DMA_PIN_SHIFT 21 #define DO_USER_MODE @@ -106,6 +110,12 @@ struct coretable { unsigned long addr; }; +enum mcctrl_os_cpu_operation { + MCCTRL_OS_CPU_READ_REGISTER, + MCCTRL_OS_CPU_WRITE_REGISTER, + MCCTRL_OS_CPU_MAX_OP +}; + struct ikc_scd_packet { int msg; int err; @@ -131,6 +141,13 @@ struct ikc_scd_packet { struct { int ttid; }; + + /* SCD_MSG_CPU_RW_REG */ + struct { + struct mcctrl_os_cpu_register desc; + enum mcctrl_os_cpu_operation op; + void *resp; + }; }; char padding[12]; }; diff --git a/executer/kernel/mcctrl/mcctrl_public.h b/executer/kernel/mcctrl/mcctrl_public.h new file mode 100644 index 00000000..7a5ba71f --- /dev/null +++ b/executer/kernel/mcctrl/mcctrl_public.h @@ -0,0 +1,20 @@ +#ifndef __MCCTRL_PUBLIC_H +#define __MCCTRL_PUBLIC_H + +#include +#include + +struct mcctrl_os_cpu_register { + unsigned long addr; + unsigned long val; + unsigned long addr_ext; +}; + +int mcctrl_os_read_cpu_register(ihk_os_t os, int cpu, + struct mcctrl_os_cpu_register *desc); +int mcctrl_os_write_cpu_register(ihk_os_t os, int cpu, + struct mcctrl_os_cpu_register *desc); +int mcctrl_get_request_os_cpu(ihk_os_t *os, int *cpu); + + +#endif // __MCCTRL_PUBLIC_H diff --git a/kernel/host.c b/kernel/host.c index d4896d75..6234ae68 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -644,6 +644,17 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, ret = 0; break; + case SCD_MSG_CPU_RW_REG: + + pckt.msg = SCD_MSG_CPU_RW_REG_RESP; + memcpy(&pckt.desc, &packet->desc, + sizeof(struct mcctrl_os_cpu_register)); + pckt.resp = packet->resp; + pckt.err = arch_cpu_read_write_register(&pckt.desc, pckt.op); + + ihk_ikc_send(resp_channel, &pckt, 0); + break; + default: kprintf("syscall_pakcet_handler:unknown message " "(%d.%d.%d.%d.%d.%#lx)\n", diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index 182542c1..8f9a6259 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -78,6 +78,9 @@ #define SCD_MSG_PERF_CTRL 0x50 #define SCD_MSG_PERF_ACK 0x51 +#define SCD_MSG_CPU_RW_REG 0x52 +#define SCD_MSG_CPU_RW_REG_RESP 0x53 + /* Cloning flags. */ # define CSIGNAL 0x000000ff /* Signal mask to be sent at exit. */ # define CLONE_VM 0x00000100 /* Set if VM shared between processes. */ @@ -210,6 +213,18 @@ struct syscall_request { unsigned long args[6]; }; +struct mcctrl_os_cpu_register { + unsigned long addr; + unsigned long val; + unsigned long addr_ext; +}; + +enum mcctrl_os_cpu_operation { + MCCTRL_OS_CPU_READ_REGISTER, + MCCTRL_OS_CPU_WRITE_REGISTER, + MCCTRL_OS_CPU_MAX_OP +}; + struct ikc_scd_packet { int msg; int err; @@ -235,6 +250,13 @@ struct ikc_scd_packet { struct { int ttid; }; + + /* SCD_MSG_CPU_RW_REG */ + struct { + struct mcctrl_os_cpu_register desc; + enum mcctrl_os_cpu_operation op; + void *resp; + }; }; char padding[12]; }; @@ -412,6 +434,8 @@ int do_shmget(key_t key, size_t size, int shmflg); struct process_vm; int arch_map_vdso(struct process_vm *vm); /* arch dependent */ int arch_setup_vdso(void); +int arch_cpu_read_write_register(struct mcctrl_os_cpu_register *desc, + enum mcctrl_os_cpu_operation op); #define VDSO_MAXPAGES 2 struct vdso {