/* * Copyright 2010 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for * more details. */ #include <linux/fs.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/rwsem.h>#include <linux/kprobes.h>#include <linux/sched.h>#include <linux/hardirq.h>#include <linux/uaccess.h>#include <linux/smp.h>#include <linux/cdev.h>#include <linux/compat.h>#include <asm/hardwall.h>#include <asm/traps.h>#include <asm/siginfo.h>#include <asm/irq_regs.h> #include <arch/interrupts.h>#include <arch/spr_def.h> /* * Implement a per-cpu "hardwall" resource class such as UDN or IPI. * We use "hardwall" nomenclature throughout for historical reasons. * The lock here controls access to the list data structure as well as * to the items on the list. */struct hardwall_type { int index; int is_xdn; int is_idn; int disabled; const char *name; struct list_head list; spinlock_t lock; struct proc_dir_entry *proc_dir;}; enum hardwall_index { HARDWALL_UDN = 0,#ifndef __tilepro__ HARDWALL_IDN = 1, HARDWALL_IPI = 2,#endif _HARDWALL_TYPES}; static struct hardwall_type hardwall_types[] = { { /* user-space access to UDN */ 0, 1, 0, 0, "udn", LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_UDN].lock), NULL },#ifndef __tilepro__ { /* user-space access to IDN */ 1, 1, 1, 1, /* disabled pending hypervisor support */ "idn", LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IDN].lock), NULL }, { /* access to user-space IPI */ 2, 0, 0, 0, "ipi", LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IPI].lock), NULL },#endif}; /* * This data structure tracks the cpu data, etc., associated * one-to-one with a "struct file *" from opening a hardwall device file. * Note that the file's private data points back to this structure. */struct hardwall_info { struct list_head list; /* for hardwall_types.list */ struct list_head task_head; /* head of tasks in this hardwall */ struct hardwall_type *type; /* type of this resource */ struct cpumask cpumask; /* cpus reserved */ int id; /* integer id for this hardwall */ int teardown_in_progress; /* are we tearing this one down? */ /* Remaining fields only valid for user-network resources. */ int ulhc_x; /* upper left hand corner x coord */ int ulhc_y; /* upper left hand corner y coord */ int width; /* rectangle width */ int height; /* rectangle height */#if CHIP_HAS_REV1_XDN() atomic_t xdn_pending_count; /* cores in phase 1 of drain */#endif}; /* /proc/tile/hardwall */static struct proc_dir_entry *hardwall_proc_dir; /* Functions to manage files in /proc/tile/hardwall. */static void hardwall_add_proc(struct hardwall_info *);static void hardwall_remove_proc(struct hardwall_info *); /* Allow disabling UDN access. */static int __init noudn(char *str){ pr_info("User-space UDN access is disabled\n"); hardwall_types[HARDWALL_UDN].disabled = 1; return 0;}early_param("noudn", noudn); #ifndef __tilepro__/* Allow disabling IDN access. */static int __init noidn(char *str){ pr_info("User-space IDN access is disabled\n"); hardwall_types[HARDWALL_IDN].disabled = 1; return 0;}early_param("noidn", noidn); /* Allow disabling IPI access. */static int __init noipi(char *str){ pr_info("User-space IPI access is disabled\n"); hardwall_types[HARDWALL_IPI].disabled = 1; return 0;}early_param("noipi", noipi);#endif /* * Low-level primitives for UDN/IDN */ #ifdef __tilepro__#define mtspr_XDN(hwt, name, val) \ do { (void)(hwt); __insn_mtspr(SPR_UDN_##name, (val)); } while (0)#define mtspr_MPL_XDN(hwt, name, val) \ do { (void)(hwt); __insn_mtspr(SPR_MPL_UDN_##name, (val)); } while (0)#define mfspr_XDN(hwt, name) \ ((void)(hwt), __insn_mfspr(SPR_UDN_##name))#else#define mtspr_XDN(hwt, name, val) \ do { \ if ((hwt)->is_idn) \ __insn_mtspr(SPR_IDN_##name, (val)); \ else \ __insn_mtspr(SPR_UDN_##name, (val)); \ } while (0)#define mtspr_MPL_XDN(hwt, name, val) \ do { \ if ((hwt)->is_idn) \ __insn_mtspr(SPR_MPL_IDN_##name, (val)); \ else \ __insn_mtspr(SPR_MPL_UDN_##name, (val)); \ } while (0)#define mfspr_XDN(hwt, name) \ ((hwt)->is_idn ? __insn_mfspr(SPR_IDN_##name) : __insn_mfspr(SPR_UDN_##name))#endif /* Set a CPU bit if the CPU is online. */#define cpu_online_set(cpu, dst) do { \ if (cpu_online(cpu)) \ cpumask_set_cpu(cpu, dst); \} while (0) /* Does the given rectangle contain the given x,y coordinate? */static int contains(struct hardwall_info *r, int x, int y){ return (x >= r->ulhc_x && x < r->ulhc_x + r->width) && (y >= r->ulhc_y && y < r->ulhc_y + r->height);} /* Compute the rectangle parameters and validate the cpumask. */static int check_rectangle(struct hardwall_info *r, struct cpumask *mask){ int x, y, cpu, ulhc, lrhc; /* The first cpu is the ULHC, the last the LRHC. */ ulhc = find_first_bit(cpumask_bits(mask), nr_cpumask_bits); lrhc = find_last_bit(cpumask_bits(mask), nr_cpumask_bits); /* Compute the rectangle attributes from the cpus. */ r->ulhc_x = cpu_x(ulhc); r->ulhc_y = cpu_y(ulhc); r->width = cpu_x(lrhc) - r->ulhc_x + 1; r->height = cpu_y(lrhc) - r->ulhc_y + 1; /* Width and height must be positive */ if (r->width <= 0 || r->height <= 0) return -EINVAL; /* Confirm that the cpumask is exactly the rectangle. */ for (y = 0, cpu = 0; y < smp_height; ++y) for (x = 0; x < smp_width; ++x, ++cpu) if (cpumask_test_cpu(cpu, mask) != contains(r, x, y)) return -EINVAL; /* * Note that offline cpus can't be drained when this user network * rectangle eventually closes. We used to detect this * situation and print a warning, but it annoyed users and * they ignored it anyway, so now we just return without a * warning. */ return 0;} /* * Hardware management of hardwall setup, teardown, trapping, * and enabling/disabling PL0 access to the networks. */ /* Bit field values to mask together for writes to SPR_XDN_DIRECTION_PROTECT */enum direction_protect { N_PROTECT = (1 << 0), E_PROTECT = (1 << 1), S_PROTECT = (1 << 2), W_PROTECT = (1 << 3), C_PROTECT = (1 << 4),}; static inline int xdn_which_interrupt(struct hardwall_type *hwt){#ifndef __tilepro__ if (hwt->is_idn) return INT_IDN_FIREWALL;#endif return INT_UDN_FIREWALL;} static void enable_firewall_interrupts(struct hardwall_type *hwt){ arch_local_irq_unmask_now(xdn_which_interrupt(hwt));} static void disable_firewall_interrupts(struct hardwall_type *hwt){ arch_local_irq_mask_now(xdn_which_interrupt(hwt));} /* Set up hardwall on this cpu based on the passed hardwall_info. */static void hardwall_setup_func(void *info){ struct hardwall_info *r = info; struct hardwall_type *hwt = r->type; int cpu = smp_processor_id(); /* on_each_cpu disables preemption */ int x = cpu_x(cpu); int y = cpu_y(cpu); int bits = 0; if (x == r->ulhc_x) bits |= W_PROTECT; if (x == r->ulhc_x + r->width - 1) bits |= E_PROTECT; if (y == r->ulhc_y) bits |= N_PROTECT; if (y == r->ulhc_y + r->height - 1) bits |= S_PROTECT; BUG_ON(bits == 0); mtspr_XDN(hwt, DIRECTION_PROTECT, bits); enable_firewall_interrupts(hwt);} /* Set up all cpus on edge of rectangle to enable/disable hardwall SPRs. */static void hardwall_protect_rectangle(struct hardwall_info *r){ int x, y, cpu, delta; struct cpumask rect_cpus; cpumask_clear(&rect_cpus); /* First include the top and bottom edges */ cpu = r->ulhc_y * smp_width + r->ulhc_x; delta = (r->height - 1) * smp_width; for (x = 0; x < r->width; ++x, ++cpu) { cpu_online_set(cpu, &rect_cpus); cpu_online_set(cpu + delta, &rect_cpus); } /* Then the left and right edges */ cpu -= r->width; delta = r->width - 1; for (y = 0; y < r->height; ++y, cpu += smp_width) { cpu_online_set(cpu, &rect_cpus); cpu_online_set(cpu + delta, &rect_cpus); } /* Then tell all the cpus to set up their protection SPR */ on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1);} /* Entered from INT_xDN_FIREWALL interrupt vector with irqs disabled. */void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num){ struct hardwall_info *rect; struct hardwall_type *hwt; struct task_struct *p; struct siginfo info; int cpu = smp_processor_id(); int found_processes; struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); /* Figure out which network trapped. */ switch (fault_num) {#ifndef __tilepro__ case INT_IDN_FIREWALL: hwt = &hardwall_types[HARDWALL_IDN]; break;#endif case INT_UDN_FIREWALL: hwt = &hardwall_types[HARDWALL_UDN]; break; default: BUG(); } BUG_ON(hwt->disabled); /* This tile trapped a network access; find the rectangle. */ spin_lock(&hwt->lock); list_for_each_entry(rect, &hwt->list, list) { if (cpumask_test_cpu(cpu, &rect->cpumask)) break; } /* * It shouldn't be possible not to find this cpu on the * rectangle list, since only cpus in rectangles get hardwalled. * The hardwall is only removed after the user network is drained. */ BUG_ON(&rect->list == &hwt->list); /* * If we already started teardown on this hardwall, don't worry; * the abort signal has been sent and we are just waiting for things * to quiesce. */ if (rect->teardown_in_progress) { pr_notice("cpu %d: detected %s hardwall violation %#lx" " while teardown already in progress\n", cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); goto done; } /* * Kill off any process that is activated in this rectangle. * We bypass security to deliver the signal, since it must be * one of the activated processes that generated the user network * message that caused this trap, and all the activated * processes shared a single open file so are pretty tightly * bound together from a security point of view to begin with. */ rect->teardown_in_progress = 1; wmb(); /* Ensure visibility of rectangle before notifying processes. */ pr_notice("cpu %d: detected %s hardwall violation %#lx...\n", cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_HARDWALL; found_processes = 0; list_for_each_entry(p, &rect->task_head, thread.hardwall[hwt->index].list) { BUG_ON(p->thread.hardwall[hwt->index].info != rect); if (!(p->flags & PF_EXITING)) { found_processes = 1; pr_notice("hardwall: killing %d\n", p->pid); do_send_sig_info(info.si_signo, &info, p, false); } } if (!found_processes) pr_notice("hardwall: no associated processes!\n"); done: spin_unlock(&hwt->lock); /* * We have to disable firewall interrupts now, or else when we * return from this handler, we will simply re-interrupt back to * it. However, we can't clear the protection bits, since we * haven't yet drained the network, and that would allow packets * to cross out of the hardwall region. */ disable_firewall_interrupts(hwt); irq_exit(); set_irq_regs(old_regs);} /* Allow access from user space to the user network. */void grant_hardwall_mpls(struct hardwall_type *hwt){#ifndef __tilepro__ if (!hwt->is_xdn) { __insn_mtspr(SPR_MPL_IPI_0_SET_0, 1); return; }#endif mtspr_MPL_XDN(hwt, ACCESS_SET_0, 1); mtspr_MPL_XDN(hwt, AVAIL_SET_0, 1); mtspr_MPL_XDN(hwt, COMPLETE_SET_0, 1); mtspr_MPL_XDN(hwt, TIMER_SET_0, 1);#if !CHIP_HAS_REV1_XDN() mtspr_MPL_XDN(hwt, REFILL_SET_0, 1); mtspr_MPL_XDN(hwt, CA_SET_0, 1);#endif} /* Deny access from user space to the user network. */void restrict_hardwall_mpls(struct hardwall_type *hwt){#ifndef __tilepro__ if (!hwt->is_xdn) { __insn_mtspr(SPR_MPL_IPI_0_SET_1, 1); return; }#endif mtspr_MPL_XDN(hwt, ACCESS_SET_1, 1); mtspr_MPL_XDN(hwt, AVAIL_SET_1, 1); mtspr_MPL_XDN(hwt, COMPLETE_SET_1, 1); mtspr_MPL_XDN(hwt, TIMER_SET_1, 1);#if !CHIP_HAS_REV1_XDN() mtspr_MPL_XDN(hwt, REFILL_SET_1, 1); mtspr_MPL_XDN(hwt, CA_SET_1, 1);#endif} /* Restrict or deny as necessary for the task we're switching to. */void hardwall_switch_tasks(struct task_struct *prev, struct task_struct *next){ int i; for (i = 0; i < HARDWALL_TYPES; ++i) { if (prev->thread.hardwall[i].info != NULL) { if (next->thread.hardwall[i].info == NULL) restrict_hardwall_mpls(&hardwall_types[i]); } else if (next->thread.hardwall[i].info != NULL) { grant_hardwall_mpls(&hardwall_types[i]); } }} /* Does this task have the right to IPI the given cpu? */int hardwall_ipi_valid(int cpu){#ifdef __tilegx__ struct hardwall_info *info = current->thread.hardwall[HARDWALL_IPI].info; return info && cpumask_test_cpu(cpu, &info->cpumask);#else return 0;#endif} /* * Code to create, activate, deactivate, and destroy hardwall resources. */ /* Create a hardwall for the given resource */static struct hardwall_info *hardwall_create(struct hardwall_type *hwt, size_t size, const unsigned char __user *bits){ struct hardwall_info *iter, *info; struct cpumask mask; unsigned long flags; int rc; /* Reject crazy sizes out of hand, a la sys_mbind(). */ if (size > PAGE_SIZE) return ERR_PTR(-EINVAL);Lines 1–500 of 1101. Load more
/* * Copyright 2010 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for * more details. */ #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/rwsem.h> #include <linux/kprobes.h> #include <linux/sched.h> #include <linux/hardirq.h> #include <linux/uaccess.h> #include <linux/smp.h> #include <linux/cdev.h> #include <linux/compat.h> #include <asm/hardwall.h> #include <asm/traps.h> #include <asm/siginfo.h> #include <asm/irq_regs.h> #include <arch/interrupts.h> #include <arch/spr_def.h> /* * Implement a per-cpu "hardwall" resource class such as UDN or IPI. * We use "hardwall" nomenclature throughout for historical reasons. * The lock here controls access to the list data structure as well as * to the items on the list. */ struct hardwall_type { int index; int is_xdn; int is_idn; int disabled; const char *name; struct list_head list; spinlock_t lock; struct proc_dir_entry *proc_dir; }; enum hardwall_index { HARDWALL_UDN = 0, #ifndef __tilepro__ HARDWALL_IDN = 1, HARDWALL_IPI = 2, #endif _HARDWALL_TYPES }; static struct hardwall_type hardwall_types[] = { { /* user-space access to UDN */ 0, 1, 0, 0, "udn", LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_UDN].lock), NULL }, #ifndef __tilepro__ { /* user-space access to IDN */ 1, 1, 1, 1, /* disabled pending hypervisor support */ "idn", LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IDN].lock), NULL }, { /* access to user-space IPI */ 2, 0, 0, 0, "ipi", LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list), __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IPI].lock), NULL }, #endif }; /* * This data structure tracks the cpu data, etc., associated * one-to-one with a "struct file *" from opening a hardwall device file. * Note that the file's private data points back to this structure. */ struct hardwall_info { struct list_head list; /* for hardwall_types.list */ struct list_head task_head; /* head of tasks in this hardwall */ struct hardwall_type *type; /* type of this resource */ struct cpumask cpumask; /* cpus reserved */ int id; /* integer id for this hardwall */ int teardown_in_progress; /* are we tearing this one down? */ /* Remaining fields only valid for user-network resources. */ int ulhc_x; /* upper left hand corner x coord */ int ulhc_y; /* upper left hand corner y coord */ int width; /* rectangle width */ int height; /* rectangle height */ #if CHIP_HAS_REV1_XDN() atomic_t xdn_pending_count; /* cores in phase 1 of drain */ #endif }; /* /proc/tile/hardwall */ static struct proc_dir_entry *hardwall_proc_dir; /* Functions to manage files in /proc/tile/hardwall. */ static void hardwall_add_proc(struct hardwall_info *); static void hardwall_remove_proc(struct hardwall_info *); /* Allow disabling UDN access. */ static int __init noudn(char *str) { pr_info("User-space UDN access is disabled\n"); hardwall_types[HARDWALL_UDN].disabled = 1; return 0; } early_param("noudn", noudn); #ifndef __tilepro__ /* Allow disabling IDN access. */ static int __init noidn(char *str) { pr_info("User-space IDN access is disabled\n"); hardwall_types[HARDWALL_IDN].disabled = 1; return 0; } early_param("noidn", noidn); /* Allow disabling IPI access. */ static int __init noipi(char *str) { pr_info("User-space IPI access is disabled\n"); hardwall_types[HARDWALL_IPI].disabled = 1; return 0; } early_param("noipi", noipi); #endif /* * Low-level primitives for UDN/IDN */ #ifdef __tilepro__ #define mtspr_XDN(hwt, name, val) \ do { (void)(hwt); __insn_mtspr(SPR_UDN_##name, (val)); } while (0) #define mtspr_MPL_XDN(hwt, name, val) \ do { (void)(hwt); __insn_mtspr(SPR_MPL_UDN_##name, (val)); } while (0) #define mfspr_XDN(hwt, name) \ ((void)(hwt), __insn_mfspr(SPR_UDN_##name)) #else #define mtspr_XDN(hwt, name, val) \ do { \ if ((hwt)->is_idn) \ __insn_mtspr(SPR_IDN_##name, (val)); \ else \ __insn_mtspr(SPR_UDN_##name, (val)); \ } while (0) #define mtspr_MPL_XDN(hwt, name, val) \ do { \ if ((hwt)->is_idn) \ __insn_mtspr(SPR_MPL_IDN_##name, (val)); \ else \ __insn_mtspr(SPR_MPL_UDN_##name, (val)); \ } while (0) #define mfspr_XDN(hwt, name) \ ((hwt)->is_idn ? __insn_mfspr(SPR_IDN_##name) : __insn_mfspr(SPR_UDN_##name)) #endif /* Set a CPU bit if the CPU is online. */ #define cpu_online_set(cpu, dst) do { \ if (cpu_online(cpu)) \ cpumask_set_cpu(cpu, dst); \ } while (0) /* Does the given rectangle contain the given x,y coordinate? */ static int contains(struct hardwall_info *r, int x, int y) { return (x >= r->ulhc_x && x < r->ulhc_x + r->width) && (y >= r->ulhc_y && y < r->ulhc_y + r->height); } /* Compute the rectangle parameters and validate the cpumask. */ static int check_rectangle(struct hardwall_info *r, struct cpumask *mask) { int x, y, cpu, ulhc, lrhc; /* The first cpu is the ULHC, the last the LRHC. */ ulhc = find_first_bit(cpumask_bits(mask), nr_cpumask_bits); lrhc = find_last_bit(cpumask_bits(mask), nr_cpumask_bits); /* Compute the rectangle attributes from the cpus. */ r->ulhc_x = cpu_x(ulhc); r->ulhc_y = cpu_y(ulhc); r->width = cpu_x(lrhc) - r->ulhc_x + 1; r->height = cpu_y(lrhc) - r->ulhc_y + 1; /* Width and height must be positive */ if (r->width <= 0 || r->height <= 0) return -EINVAL; /* Confirm that the cpumask is exactly the rectangle. */ for (y = 0, cpu = 0; y < smp_height; ++y) for (x = 0; x < smp_width; ++x, ++cpu) if (cpumask_test_cpu(cpu, mask) != contains(r, x, y)) return -EINVAL; /* * Note that offline cpus can't be drained when this user network * rectangle eventually closes. We used to detect this * situation and print a warning, but it annoyed users and * they ignored it anyway, so now we just return without a * warning. */ return 0; } /* * Hardware management of hardwall setup, teardown, trapping, * and enabling/disabling PL0 access to the networks. */ /* Bit field values to mask together for writes to SPR_XDN_DIRECTION_PROTECT */ enum direction_protect { N_PROTECT = (1 << 0), E_PROTECT = (1 << 1), S_PROTECT = (1 << 2), W_PROTECT = (1 << 3), C_PROTECT = (1 << 4), }; static inline int xdn_which_interrupt(struct hardwall_type *hwt) { #ifndef __tilepro__ if (hwt->is_idn) return INT_IDN_FIREWALL; #endif return INT_UDN_FIREWALL; } static void enable_firewall_interrupts(struct hardwall_type *hwt) { arch_local_irq_unmask_now(xdn_which_interrupt(hwt)); } static void disable_firewall_interrupts(struct hardwall_type *hwt) { arch_local_irq_mask_now(xdn_which_interrupt(hwt)); } /* Set up hardwall on this cpu based on the passed hardwall_info. */ static void hardwall_setup_func(void *info) { struct hardwall_info *r = info; struct hardwall_type *hwt = r->type; int cpu = smp_processor_id(); /* on_each_cpu disables preemption */ int x = cpu_x(cpu); int y = cpu_y(cpu); int bits = 0; if (x == r->ulhc_x) bits |= W_PROTECT; if (x == r->ulhc_x + r->width - 1) bits |= E_PROTECT; if (y == r->ulhc_y) bits |= N_PROTECT; if (y == r->ulhc_y + r->height - 1) bits |= S_PROTECT; BUG_ON(bits == 0); mtspr_XDN(hwt, DIRECTION_PROTECT, bits); enable_firewall_interrupts(hwt); } /* Set up all cpus on edge of rectangle to enable/disable hardwall SPRs. */ static void hardwall_protect_rectangle(struct hardwall_info *r) { int x, y, cpu, delta; struct cpumask rect_cpus; cpumask_clear(&rect_cpus); /* First include the top and bottom edges */ cpu = r->ulhc_y * smp_width + r->ulhc_x; delta = (r->height - 1) * smp_width; for (x = 0; x < r->width; ++x, ++cpu) { cpu_online_set(cpu, &rect_cpus); cpu_online_set(cpu + delta, &rect_cpus); } /* Then the left and right edges */ cpu -= r->width; delta = r->width - 1; for (y = 0; y < r->height; ++y, cpu += smp_width) { cpu_online_set(cpu, &rect_cpus); cpu_online_set(cpu + delta, &rect_cpus); } /* Then tell all the cpus to set up their protection SPR */ on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); } /* Entered from INT_xDN_FIREWALL interrupt vector with irqs disabled. */ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) { struct hardwall_info *rect; struct hardwall_type *hwt; struct task_struct *p; struct siginfo info; int cpu = smp_processor_id(); int found_processes; struct pt_regs *old_regs = set_irq_regs(regs); irq_enter(); /* Figure out which network trapped. */ switch (fault_num) { #ifndef __tilepro__ case INT_IDN_FIREWALL: hwt = &hardwall_types[HARDWALL_IDN]; break; #endif case INT_UDN_FIREWALL: hwt = &hardwall_types[HARDWALL_UDN]; break; default: BUG(); } BUG_ON(hwt->disabled); /* This tile trapped a network access; find the rectangle. */ spin_lock(&hwt->lock); list_for_each_entry(rect, &hwt->list, list) { if (cpumask_test_cpu(cpu, &rect->cpumask)) break; } /* * It shouldn't be possible not to find this cpu on the * rectangle list, since only cpus in rectangles get hardwalled. * The hardwall is only removed after the user network is drained. */ BUG_ON(&rect->list == &hwt->list); /* * If we already started teardown on this hardwall, don't worry; * the abort signal has been sent and we are just waiting for things * to quiesce. */ if (rect->teardown_in_progress) { pr_notice("cpu %d: detected %s hardwall violation %#lx" " while teardown already in progress\n", cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); goto done; } /* * Kill off any process that is activated in this rectangle. * We bypass security to deliver the signal, since it must be * one of the activated processes that generated the user network * message that caused this trap, and all the activated * processes shared a single open file so are pretty tightly * bound together from a security point of view to begin with. */ rect->teardown_in_progress = 1; wmb(); /* Ensure visibility of rectangle before notifying processes. */ pr_notice("cpu %d: detected %s hardwall violation %#lx...\n", cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_HARDWALL; found_processes = 0; list_for_each_entry(p, &rect->task_head, thread.hardwall[hwt->index].list) { BUG_ON(p->thread.hardwall[hwt->index].info != rect); if (!(p->flags & PF_EXITING)) { found_processes = 1; pr_notice("hardwall: killing %d\n", p->pid); do_send_sig_info(info.si_signo, &info, p, false); } } if (!found_processes) pr_notice("hardwall: no associated processes!\n"); done: spin_unlock(&hwt->lock); /* * We have to disable firewall interrupts now, or else when we * return from this handler, we will simply re-interrupt back to * it. However, we can't clear the protection bits, since we * haven't yet drained the network, and that would allow packets * to cross out of the hardwall region. */ disable_firewall_interrupts(hwt); irq_exit(); set_irq_regs(old_regs); } /* Allow access from user space to the user network. */ void grant_hardwall_mpls(struct hardwall_type *hwt) { #ifndef __tilepro__ if (!hwt->is_xdn) { __insn_mtspr(SPR_MPL_IPI_0_SET_0, 1); return; } #endif mtspr_MPL_XDN(hwt, ACCESS_SET_0, 1); mtspr_MPL_XDN(hwt, AVAIL_SET_0, 1); mtspr_MPL_XDN(hwt, COMPLETE_SET_0, 1); mtspr_MPL_XDN(hwt, TIMER_SET_0, 1); #if !CHIP_HAS_REV1_XDN() mtspr_MPL_XDN(hwt, REFILL_SET_0, 1); mtspr_MPL_XDN(hwt, CA_SET_0, 1); #endif } /* Deny access from user space to the user network. */ void restrict_hardwall_mpls(struct hardwall_type *hwt) { #ifndef __tilepro__ if (!hwt->is_xdn) { __insn_mtspr(SPR_MPL_IPI_0_SET_1, 1); return; } #endif mtspr_MPL_XDN(hwt, ACCESS_SET_1, 1); mtspr_MPL_XDN(hwt, AVAIL_SET_1, 1); mtspr_MPL_XDN(hwt, COMPLETE_SET_1, 1); mtspr_MPL_XDN(hwt, TIMER_SET_1, 1); #if !CHIP_HAS_REV1_XDN() mtspr_MPL_XDN(hwt, REFILL_SET_1, 1); mtspr_MPL_XDN(hwt, CA_SET_1, 1); #endif } /* Restrict or deny as necessary for the task we're switching to. */ void hardwall_switch_tasks(struct task_struct *prev, struct task_struct *next) { int i; for (i = 0; i < HARDWALL_TYPES; ++i) { if (prev->thread.hardwall[i].info != NULL) { if (next->thread.hardwall[i].info == NULL) restrict_hardwall_mpls(&hardwall_types[i]); } else if (next->thread.hardwall[i].info != NULL) { grant_hardwall_mpls(&hardwall_types[i]); } } } /* Does this task have the right to IPI the given cpu? */ int hardwall_ipi_valid(int cpu) { #ifdef __tilegx__ struct hardwall_info *info = current->thread.hardwall[HARDWALL_IPI].info; return info && cpumask_test_cpu(cpu, &info->cpumask); #else return 0; #endif } /* * Code to create, activate, deactivate, and destroy hardwall resources. */ /* Create a hardwall for the given resource */ static struct hardwall_info *hardwall_create(struct hardwall_type *hwt, size_t size, const unsigned char __user *bits) { struct hardwall_info *iter, *info; struct cpumask mask; unsigned long flags; int rc; /* Reject crazy sizes out of hand, a la sys_mbind(). */ if (size > PAGE_SIZE) return ERR_PTR(-EINVAL);