/*************************************************************************** * * Copyright (C) 2001 International Business Machines * All rights reserved. * * This file is part of the GPFS mmfslinux kernel module. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *************************************************************************** */ /* @(#)86 1.19.1.5 src/avs/fs/mmfs/ts/kernext/gpl-linux/ia64/ss_ia64.c, mmfs, avs_rgpfs24, rgpfs24s008a 11/17/06 10:04:58 */ /* * Implementation of shared segment for GPFS daemon and GPFS kernel code. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef LEVEL_1 struct ia64_pfs { __u64 reserved0 : 62; __u64 ppl : 2; }; # define ia64_pfs(regs) ((struct ia64_pfs *) &(regs)->ar_pfs) #endif int set_privilege_level(unsigned long progLevel) { #ifdef LEVEL_1 unsigned long cpl; unsigned long new_cpl; unsigned long ipsr; unsigned long new_ipsr; unsigned long pfs; unsigned long new_pfs; struct pt_regs *regs; if (progLevel < 0 || progLevel > 3 || !cxiIsSuperUser()) return -1; #if LINUX_KERNEL_VERSION > 2061600 regs = task_pt_regs(current); #else regs = ia64_task_regs(current); #endif cpl = ia64_psr(regs)->cpl; ipsr = regs->cr_ipsr; pfs = regs->ar_pfs; ia64_psr(regs)->cpl = progLevel; // set current privilege level ia64_pfs(regs)->ppl = progLevel; // set previous privilege level new_ipsr = regs->cr_ipsr; new_pfs = regs->ar_pfs; TRACE5(TRACE_SHARED, 2, TRCID_SS_022, "set_privilege_level: cpl 0x%lX ipsr 0x%lX pfs 0x%lX new_ipsr 0x%lX new_pfs 0x%lX\n", cpl, ipsr, pfs, new_ipsr, new_pfs); #endif return 0; } int get_privilege_level() { unsigned long cpl; struct pt_regs *regs; unsigned long ipsr; unsigned long pfs; #if LINUX_KERNEL_VERSION > 2061600 regs = task_pt_regs(current); #else regs = ia64_task_regs(current); #endif cpl = ia64_psr(regs)->cpl; ipsr = regs->cr_ipsr; pfs = regs->ar_pfs; TRACE3(TRACE_SHARED, 2, TRCID_SS_022X, "get_privilege_level: cpl 0x%lX ipsr 0x%lX pfs 0x%lX\n", cpl, ipsr, pfs); return cpl; } int kxSaveThreadInfo(int tid, void* regP) { struct sigcontext *sc = (struct sigcontext *)regP; struct task_struct *g, *p; struct pt_regs *pt; int rc = ENOENT; read_lock(&tasklist_lock); DO_EACH_THREAD(g,p) { if (PROCESS_GROUP(current) == PROCESS_GROUP(p) && current->pid != tid && p->pid == tid) { #if LINUX_KERNEL_VERSION > 2061600 pt = task_pt_regs(p); #else pt = ia64_task_regs(p); #endif read_unlock(&tasklist_lock); rc = __put_user(pt->cr_iip, &sc->sc_ip); rc |= __put_user(pt->ar_bspstore, &sc->sc_ar_bsp); rc |= __put_user(pt->ar_pfs, &sc->sc_cfm); return rc; } } WHILE_EACH_THREAD(g,p); read_unlock(&tasklist_lock); return -1; } /* TLB flush routines for a single page or an address range. These are not exported by the kernel (like flush_tlb_all) and we want to do this at a finer granularity than flushing the entire TLB cache. The kernel serializes tlb cache flushes with the ptcg_lock, but we don't have access to this. */ void flush_tlb_page_ia64(unsigned long start_addr) { unsigned long addr = start_addr & ~(PAGE_SIZE - 1); /* page align */ /* ptc commands expect flush size starting at bit 2 of register */ #ifdef CONFIG_SMP __asm__ __volatile__ ("ptc.ga %0, %1;;" : : "r"(addr), "r"(PAGE_SHIFT << 2) : "memory"); #else __asm__ __volatile__ ("ptc.l %0, %1;;" : : "r"(addr), "r"(PAGE_SHIFT << 2) : "memory"); #endif /* CONFIG_SMP */ /* need to serialize */ __asm__ __volatile__ ("srlz.i;;" : : : "memory"); } void flush_tlb_range_ia64(unsigned long start_addr, unsigned long end_addr) { unsigned long addr = start_addr & ~(PAGE_SIZE - 1); /* page align */ while (addr < end_addr) { /* ptc commands expect flush size starting at bit 2 of register */ #ifdef CONFIG_SMP __asm__ __volatile__ ("ptc.ga %0, %1;;" : : "r"(addr), "r"(PAGE_SHIFT << 2) : "memory"); #else __asm__ __volatile__ ("ptc.l %0, %1;;" : : "r"(addr), "r"(PAGE_SHIFT << 2) : "memory"); #endif /* CONFIG_SMP */ /* need to serialize */ __asm__ __volatile__ ("srlz.i;;" : : : "memory"); addr += PAGE_SIZE; } }