From 5cc8854bc94b22e52d747e67cc9b7ca310711181 Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 8 Jun 2009 02:01:51 +0300 Subject: [PATCH] added warm lib --- gp2x/sys_cacheflush.S | 29 +++++++++ gp2x/sys_cacheflush.h | 3 + gp2x/warm.c | 146 ++++++++++++++++++++++++++++++++++++++++++ gp2x/warm.h | 100 +++++++++++++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 gp2x/sys_cacheflush.S create mode 100644 gp2x/sys_cacheflush.h create mode 100644 gp2x/warm.c create mode 100644 gp2x/warm.h diff --git a/gp2x/sys_cacheflush.S b/gp2x/sys_cacheflush.S new file mode 100644 index 0000000..d26f81a --- /dev/null +++ b/gp2x/sys_cacheflush.S @@ -0,0 +1,29 @@ +@ vim:filetype=armasm +#include + + +.global sys_cacheflush @ void *start_addr, void *end_addr + +sys_cacheflush: + mov r2, #0 +#ifdef __ARM_EABI__ + /* EABI version */ + str r7, [sp, #-4]! + mov r7, #(__ARM_NR_cacheflush & 0xff) + orr r7, r7, #(__ARM_NR_cacheflush & 0x00ff00) + orr r7, r7, #(__ARM_NR_cacheflush & 0xff0000) + swi 0 + ldr r7, [sp], #4 +#else + /* OABI */ + swi __ARM_NR_cacheflush +#endif + bx lr + +.global spend_cycles +spend_cycles: + mov r0,r0,lsr #2 + 0:subs r0, r0, #1 + bne 0b + bx lr + diff --git a/gp2x/sys_cacheflush.h b/gp2x/sys_cacheflush.h new file mode 100644 index 0000000..27f3c4c --- /dev/null +++ b/gp2x/sys_cacheflush.h @@ -0,0 +1,3 @@ + +void sys_cacheflush(void *start_addr, void *end_addr); + diff --git a/gp2x/warm.c b/gp2x/warm.c new file mode 100644 index 0000000..197df0f --- /dev/null +++ b/gp2x/warm.c @@ -0,0 +1,146 @@ +/* + * wARM - exporting ARM processor specific privileged services to userspace + * userspace part + * + * Copyright (c) Gražvydas "notaz" Ignotas, 2009 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the organization nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WARM_CODE +#include "warm.h" +#include "sys_cacheflush.h" + +static int warm_fd = -1; + +int warm_init(void) +{ + struct utsname unm; + char buff[128]; + + warm_fd = open("/proc/warm", O_RDWR); + if (warm_fd >= 0) + return 0; + + memset(&unm, 0, sizeof(unm)); + uname(&unm); + snprintf(buff, sizeof(buff), "/sbin/insmod warm_%s.ko", unm.release); + + /* try to insmod */ + system(buff); + warm_fd = open("/proc/warm", O_RDWR); + if (warm_fd >= 0) + return 0; + + fprintf(stderr, "wARM: can't init, acting as sys_cacheflush wrapper\n"); + return -1; +} + +void warm_finish(void) +{ + if (warm_fd >= 0) + close(warm_fd); + system("rmmod warm"); +} + +int warm_cache_op_range(int op, void *addr, unsigned long size) +{ + struct warm_cache_op wop; + int ret; + + if (warm_fd < 0) { + sys_cacheflush(addr, (char *)addr + size); + return -1; + } + + wop.ops = op; + wop.addr = (unsigned long)addr; + wop.size = size; + + ret = ioctl(warm_fd, WARMC_CACHE_OP, &wop); + if (ret != 0) { + perror("WARMC_CACHE_OP failed"); + return -1; + } + + return 0; +} + +int warm_cache_op_all(int op) +{ + return warm_cache_op_range(op, NULL, (size_t)-1); +} + +int warm_change_cb_range(int cb, int is_set, void *addr, unsigned long size) +{ + struct warm_change_cb ccb; + int ret; + + if (warm_fd < 0) + return -1; + + ccb.addr = (unsigned long)addr; + ccb.size = size; + ccb.cb = cb; + ccb.is_set = is_set; + + ret = ioctl(warm_fd, WARMC_CHANGE_CB, &ccb); + if (ret != 0) { + perror("WARMC_CHANGE_CB failed"); + return -1; + } + + return 0; +} + +int warm_change_cb_upper(int cb, int is_set) +{ + return warm_change_cb_range(cb, is_set, 0, 0); +} + +unsigned long warm_virt2phys(const void *ptr) +{ + unsigned long ptrio; + int ret; + + ptrio = (unsigned long)ptr; + ret = ioctl(warm_fd, WARMC_VIRT2PHYS, &ptrio); + if (ret != 0) { + perror("WARMC_VIRT2PHYS failed"); + return (unsigned long)-1; + } + + return ptrio; +} + diff --git a/gp2x/warm.h b/gp2x/warm.h new file mode 100644 index 0000000..a3fdd6b --- /dev/null +++ b/gp2x/warm.h @@ -0,0 +1,100 @@ +/* + * wARM - exporting ARM processor specific privileged services to userspace + * library functions + * + * Copyright (c) Gražvydas "notaz" Ignotas, 2009 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the organization nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#ifndef __WARM_H__ +#define __WARM_H__ 1 + +/* cache operations (warm_cache_op_*): + * o clean - write dirty data to memory, but also leave in cache. + * o invalidate - throw away everything in cache, losing dirty data. + * + * Write buffer is always drained, no ops will only drain WB + */ +#define WOP_D_CLEAN (1 << 0) +#define WOP_D_INVALIDATE (1 << 1) +#define WOP_I_INVALIDATE (1 << 2) + +/* change C and B bits (warm_change_cb_*) + * if is_set in not zero, bits are set, else cleared. + * the address for range function is virtual address. + */ +#define WCB_C_BIT (1 << 0) +#define WCB_B_BIT (1 << 1) + +#ifndef __ASSEMBLER__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +int warm_init(void); + +int warm_cache_op_range(int ops, void *virt_addr, unsigned long size); +int warm_cache_op_all(int ops); + +int warm_change_cb_upper(int cb, int is_set); +int warm_change_cb_range(int cb, int is_set, void *virt_addr, unsigned long size); + +unsigned long warm_virt2phys(const void *ptr); + +void warm_finish(void); + +#ifdef __cplusplus +} +#endif + +/* internal */ +#ifdef WARM_CODE + +#include + +#define WARM_IOCTL_BASE 'A' + +struct warm_cache_op +{ + unsigned long addr; + unsigned long size; + int ops; +}; + +struct warm_change_cb +{ + unsigned long addr; + unsigned long size; + int cb; + int is_set; +}; + +#define WARMC_CACHE_OP _IOW(WARM_IOCTL_BASE, 0, struct warm_cache_op) +#define WARMC_CHANGE_CB _IOW(WARM_IOCTL_BASE, 1, struct warm_change_cb) +#define WARMC_VIRT2PHYS _IOWR(WARM_IOCTL_BASE, 2, unsigned long) + +#endif /* WARM_CODE */ +#endif /* !__ASSEMBLER__ */ +#endif /* __WARM_H__ */