diff options
Diffstat (limited to 'bsps/powerpc/include/libcpu')
-rw-r--r-- | bsps/powerpc/include/libcpu/bat.h | 85 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/byteorder.h | 54 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/c_clock.h | 56 | ||||
-rwxr-xr-x | bsps/powerpc/include/libcpu/cpuIdent.h | 158 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/e500_mmu.h | 230 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/io.h | 139 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/irq.h | 199 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/mmu.h | 304 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/page.h | 66 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/pgtable.h | 144 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/powerpc-utility.h | 985 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/pte121.h | 265 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/raw_exception.h | 161 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/spr.h | 78 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/stackTrace.h | 8 | ||||
-rw-r--r-- | bsps/powerpc/include/libcpu/vectors.h | 115 |
16 files changed, 3047 insertions, 0 deletions
diff --git a/bsps/powerpc/include/libcpu/bat.h b/bsps/powerpc/include/libcpu/bat.h new file mode 100644 index 0000000000..2a27e810ee --- /dev/null +++ b/bsps/powerpc/include/libcpu/bat.h @@ -0,0 +1,85 @@ +/* + * bat.h + * + * This file contains declaration of C function to + * Instantiate 60x/7xx ppc Block Address Translation (BAT) registers. + * More detailed information can be found on motorola + * site and more precisely in the following book : + * + * MPC750 + * Risc Microporcessor User's Manual + * Motorola REF : MPC750UM/AD 8/97 + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_BAT_H +#define _LIBCPU_BAT_H + +#include <libcpu/mmu.h> +#include <libcpu/pgtable.h> + +#define IO_PAGE (_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW) + +#ifndef ASM +/* Take no risks -- the essential parts of this routine run with + * interrupts disabled! + * + * The routine does basic parameter checks: + * - Index must be 0..3 (0..7 on 7455, 7457). + * If an index > 3 is requested the 745x is + * programmed to enable the higher BATs. + * - Size must be a power of two and <= 1<<28 + * (<=1<<31 on 7455, 7457. Also, on these processors + * the special value 0xffffffff is allowed which stands + * for 1<<32). + * If a size > 1<<28 is requested, the 745x is + * programmed to enable the larger block sizes. + * - Bat ranges must not overlap. + * - Physical & virtual addresses must be aligned + * to the size. + * + * RETURNS: zero on success, nonzero on failure. + */ +extern int setdbat(int bat_index, unsigned long virt, unsigned long phys, + unsigned int size, int flags); + +/* Same as setdbat but sets IBAT */ +extern int setibat(int bat_index, unsigned long virt, unsigned long phys, + unsigned int size, int flags); + +/* read DBAT # 'idx' into *pu / *pl. NULL pointers may be passed. + * If pu and pl are NULL, the bat contents are dumped to the console (printk). + * + * RETURNS: upper BAT contents or (-1) if index is invalid + */ +extern int getdbat(int bat_index, unsigned long *pu, unsigned long *pl); + +/* Same as getdbat but reads IBAT */ +extern int getibat(int bat_index, unsigned long *pu, unsigned long *pl); + +/* Do not use the asm-routines; they are obsolete; use setdbat() instead */ +extern void asm_setdbat0(unsigned int uperPart, unsigned int lowerPart); +extern void asm_setdbat1(unsigned int uperPart, unsigned int lowerPart); +extern void asm_setdbat2(unsigned int uperPart, unsigned int lowerPart); +extern void asm_setdbat3(unsigned int uperPart, unsigned int lowerPart); +#else + +/* Initialize all bats (upper and lower) to zero. This routine should *only* + * be called during early BSP initialization when no C-ABI is available + * yet. + * This routine clobbers r3 and r4. + * NOTE: on 7450 CPUs all 8 dbat/ibat units are cleared. On 601 CPUs only + * 4 ibats. + */ + .globl CPU_clear_bats_early + .type CPU_clear_bats_early,@function + +#endif + +#endif /* _LIBCPU_BAT_H */ diff --git a/bsps/powerpc/include/libcpu/byteorder.h b/bsps/powerpc/include/libcpu/byteorder.h new file mode 100644 index 0000000000..0654fefb58 --- /dev/null +++ b/bsps/powerpc/include/libcpu/byteorder.h @@ -0,0 +1,54 @@ +/* + * byteorder.h + * + * This file contains inline implementation of function to + * deal with endian conversion. + * + * It is a stripped down version of linux ppc file... + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_BYTEORDER_H +#define _LIBCPU_BYTEORDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +static inline unsigned ld_le16(volatile uint16_t *addr) +{ + unsigned val; + + __asm__ volatile ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); + return val; +} + +static inline void st_le16(volatile uint16_t *addr, unsigned val) +{ + __asm__ volatile ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); +} + +static inline unsigned ld_le32(volatile uint32_t *addr) +{ + unsigned val; + + __asm__ volatile ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr)); + return val; +} + +static inline void st_le32(volatile uint32_t *addr, unsigned val) +{ + __asm__ volatile ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBCPU_BYTEORDER_H */ diff --git a/bsps/powerpc/include/libcpu/c_clock.h b/bsps/powerpc/include/libcpu/c_clock.h new file mode 100644 index 0000000000..bd4918fb44 --- /dev/null +++ b/bsps/powerpc/include/libcpu/c_clock.h @@ -0,0 +1,56 @@ +/* + * Clock Tick Device Driver + * + * This routine utilizes the Decrementer Register common to the PPC family. + * + * The tick frequency is directly programmed to the configured number of + * microseconds per tick. + * + * COPYRIGHT (c) 1989-1997. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may in + * the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * Modified to support the MPC750. + * Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr + */ + +#ifndef _LIBCPU_C_CLOCK_H +#define _LIBCPU_C_CLOCK_H + +#include <rtems.h> + +/* + * These functions and variables represent the API exported by the + * CPU to the BSP. + */ + +extern void clockOff (void* unused); +extern void clockOn (void* unused); +extern void clockIsr (void* unused); +/* bookE decrementer is slightly different */ +extern void clockIsrBookE (void *unused); +extern int clockIsOn (void* unused); + +/* + * These functions and variables represent the assumptions of this + * driver on the BSP. + */ + +extern int BSP_disconnect_clock_handler (void); +/* + * PCI Bus Frequency + */ +extern unsigned int BSP_bus_frequency; +/* + * processor clock frequency + */ +extern unsigned int BSP_processor_frequency; +/* + * Time base divisior (how many tick for 1 second). + */ +extern unsigned int BSP_time_base_divisor; + +#endif diff --git a/bsps/powerpc/include/libcpu/cpuIdent.h b/bsps/powerpc/include/libcpu/cpuIdent.h new file mode 100755 index 0000000000..e051deba92 --- /dev/null +++ b/bsps/powerpc/include/libcpu/cpuIdent.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * Added MPC8260 Andy Dachs <a.dachs@sstl.co.uk> + * Surrey Satellite Technology Limited + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_CPUIDENT_H +#define _LIBCPU_CPUIDENT_H + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ASM +typedef enum +{ + PPC_601 = 0x1, + PPC_5XX = 0x2, + PPC_603 = 0x3, + PPC_604 = 0x4, + PPC_603e = 0x6, + PPC_603ev = 0x7, + PPC_750 = 0x8, + PPC_750_IBM = 0x7000, + PPC_604e = 0x9, + PPC_604r = 0xA, + PPC_7400 = 0xC, + PPC_405 = 0x2001, /* Xilinx Virtex-II Pro or -4 */ + PPC_405EX = 0x1291, /* + 405EXr */ + PPC_405GP = 0x4011, /* + 405CR */ + PPC_405GPr = 0x5091, + PPC_405EZ = 0x4151, + PPC_405EP = 0x5121, + PPC_440 = 0x7ff2, /* Xilinx Virtex-5*/ + PPC_7455 = 0x8001, /* Kate Feng */ + PPC_7457 = 0x8002, + PPC_620 = 0x16, + PPC_860 = 0x50, + PPC_821 = PPC_860, + PPC_823 = PPC_860, + PPC_8260 = 0x81, + PPC_8240 = PPC_8260, + PPC_8245 = 0x8081, + PPC_8540 = 0x8020, + PPC_e500v2 = 0x8021, + PPC_e6500 = 0x8040, + PPC_603le = 0x8082, /* 603le core, in MGT5100 and MPC5200 */ + PPC_e300c1 = 0x8083, /* e300c1 core, in MPC83xx*/ + PPC_e300c2 = 0x8084, /* e300c2 core */ + PPC_e300c3 = 0x8085, /* e300c3 core */ + PPC_e200z0 = 0x8170, + PPC_e200z1 = 0x8140, + PPC_e200z4 = 0x8150, + PPC_e200z6 = 0x8110, + PPC_e200z7 = 0x8160, + PPC_PSIM = 0xfffe, /* GDB PowerPC simulator -- fake version */ + PPC_UNKNOWN = 0xffff +} ppc_cpu_id_t; + +/* Bitfield of for identifying features or groups of cpu flavors. + * DO NOT USE DIRECTLY (as implementation may change) + * only use the 'ppc_is_xxx() / ppc_has_xxx()' macros/inlines + * below. + */ + +typedef struct { + unsigned has_altivec : 1; + unsigned has_fpu : 1; + unsigned has_hw_ptbl_lkup : 1; +#define PPC_BOOKE_405 1 /* almost like booke but with some significant differences */ +#define PPC_BOOKE_STD 2 +#define PPC_BOOKE_E500 3 /* bookE with extensions */ + unsigned is_bookE : 2; + unsigned has_16byte_clne : 1; + unsigned is_60x : 1; + unsigned has_8_bats : 1; + unsigned has_epic : 1; + unsigned has_shadowed_gprs : 1; +} ppc_feature_t; + +extern ppc_feature_t current_ppc_features; +extern ppc_cpu_id_t current_ppc_cpu; + +typedef unsigned short ppc_cpu_revision_t; + +extern ppc_cpu_id_t get_ppc_cpu_type (void); +extern const char *get_ppc_cpu_type_name(ppc_cpu_id_t cpu); +extern ppc_cpu_revision_t get_ppc_cpu_revision (void); +extern ppc_cpu_revision_t current_ppc_revision; + +/* PUBLIC ACCESS ROUTINES */ +#define _PPC_FEAT_DECL(x) \ +static inline unsigned ppc_cpu_##x(void) { \ + if ( PPC_UNKNOWN == current_ppc_cpu ) \ + get_ppc_cpu_type(); \ + return current_ppc_features.x; \ +} + +_PPC_FEAT_DECL(has_altivec) +/* has_fpu not implemented yet */ +_PPC_FEAT_DECL(has_hw_ptbl_lkup) +_PPC_FEAT_DECL(is_bookE) +_PPC_FEAT_DECL(is_60x) +_PPC_FEAT_DECL(has_8_bats) +_PPC_FEAT_DECL(has_epic) +_PPC_FEAT_DECL(has_shadowed_gprs) + +#undef _PPC_FEAT_DECL + +static inline ppc_cpu_id_t ppc_cpu_current(void) +{ + return current_ppc_cpu; +} + +static inline bool ppc_cpu_is_e200(void) +{ + return (ppc_cpu_current() & 0xff80) == 0x8100; +} + +static inline bool ppc_cpu_is_specific_e200(ppc_cpu_id_t id) +{ + return (ppc_cpu_current() & 0xfff0) == id; +} + +static inline bool ppc_cpu_is_e300(void) +{ + return ppc_cpu_current() == PPC_e300c1 + || ppc_cpu_current() == PPC_e300c2 + || ppc_cpu_current() == PPC_e300c3; +} + +static inline bool ppc_cpu_is_e500(void) +{ + return ppc_cpu_current() == PPC_8540 + || ppc_cpu_current() == PPC_e500v2; +} + +static inline bool ppc_cpu_is(ppc_cpu_id_t cpu) +{ + return ppc_cpu_current() == cpu; +} + +#endif /* ASM */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsps/powerpc/include/libcpu/e500_mmu.h b/bsps/powerpc/include/libcpu/e500_mmu.h new file mode 100644 index 0000000000..84920e0d14 --- /dev/null +++ b/bsps/powerpc/include/libcpu/e500_mmu.h @@ -0,0 +1,230 @@ +#ifndef RTEMS_E500_MMU_DRIVER_H +#define RTEMS_E500_MMU_DRIVER_H + +/* + * Routines to manipulate e500 TLBs; TLB0 (fixed 4k page size) + * is not very useful so we mostly focus on TLB1 (variable page size) + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <inttypes.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Some routines require or return a index 'key'. This + * is simply the TLB entry # ORed with E500_SELTLB_0 + * or E500_SELTLB_1 specifying an entry in TLB0 or TLB1, + * respectively. + */ +typedef int rtems_e500_tlb_idx; +#define E500_SELTLB_0 0x0000 +#define E500_SELTLB_1 0x1000 + +/* Cache the relevant TLB1 entries so that we can + * make sure the user cannot create conflicting + * (overlapping) entries. + * Keep them public for informational purposes. + */ +typedef struct { + struct { + uint32_t va_epn: 20; + uint32_t va_tid: 12; + } va; + uint32_t rpn; + struct { + uint32_t sz: 4; + uint32_t ts: 1; + uint32_t v: 1; + uint32_t perm: 10; + uint32_t wimge: 7; + } att; +} E500_tlb_va_cache_t; + +extern E500_tlb_va_cache_t rtems_e500_tlb_va_cache[16]; + +/* + * Dump (cleartext) content info from cached TLB entries + * to a file (stdout if f==NULL). + */ +void +rtems_e500_dmptlbc(FILE *f); + +/* + * Read a TLB entry from the hardware; if it is a TLB1 entry + * then the current settings are stored in the + * rtems_e500_tlb_va_cache[] structure. + * + * The routine can perform this operation quietly or + * print information to a file. + * + * 'key': TLB entry index ORed with selector bit + * (E500_SELTLB_0 for TLB0, E500_SELTLB_1 for TLB1). + * 'quiet': perform operation silently (no info printed) + * if nonzero. + * 'f': open FILE where to print information. May be + * NULL in which case 'stdout' is used. + * + * RETURNS: + * 0: success; TLB entry is VALID + * +1: success but TLB entry is INVALID + * < 0: error (-1: invalid argument) + */ +int +rtems_e500_prtlb(rtems_e500_tlb_idx key, int quiet, FILE *f); + +/* Initialize cache; verify that TLB0 is unused; + * + * RETURNS: zero on success, nonzero on error (TLB0 + * seems to be in use); in this case the + * driver will refuse to change TLB1 entries + * (other than disabling them). + */ +int +rtems_e500_initlb(void); + +/* + * Write TLB1 entry (can also be used to disable an entry). + * + * The routine checks against the cached data in + * rtems_e500_tlb_va[] to prevent the user from generating + * overlapping entries. + * + * 'idx': TLB 1 entry # to manipulate + * 'ea': Effective address (must be page aligned) + * 'pa': Physical address (must be page aligned) + * 'sz': Page size selector; page size is + * 1024 * 2^(2*sz) bytes. + * 'sz' may also be one of the following: + * - page size in bytes ( >= 1024 ); the selector + * value is then computed by this routine. + * However, 'sz' must be a valid page size + * or -1 will be returned. + * - a value < 0 to invalidate/disable the + * TLB entry. + * 'attr': Page attributes; ORed combination of WIMGE, + * PERMissions, TID and TS. Use ATTR_xxx macros + * + * RETURNS: 0 on success, nonzero on error: + * + * >0: requested mapping would overlap with + * existing mapping in other entry. Return + * value gives conflicting entry + 1; i.e., + * if a value of 4 is returned then the request + * conflicts with existing mapping in entry 3. + * -1: invalid argument + * -3: driver not initialized (or initialization + * failed because TLB0 is in use). + * <0: other error + * + */ +#define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f) /* includes user bits */ +#define E500_TLB_ATTR_WIMGE_GET(x) ((x)&0x7f) +#define E500_TLB_ATTR_TS (1<<7) +#define E500_TLB_ATTR_PERM(x) (((x)&0x3ff)<<8) +#define E500_TLB_ATTR_PERM_GET(x) (((x)>>8)&0x3ff) +#define E500_TLB_ATTR_TID(x) (((x)&0xfff)<<20) +#define E500_TLB_ATTR_TID_GET(x) (((x)>>20)&0xfff) + +int +rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr); + +/* + * Check if a ts/tid/ea/sz mapping overlaps + * with an existing entry. + * + * ASSUMPTION: all TLB0 (fixed 4k pages) are invalid and always unused. + * + * NOTE: 'sz' is the 'logarithmic' size selector; the page size + * is 1024*2^(2*sz). + * + * RETURNS: + * >= 0: index of TLB1 entry that already provides a mapping + * which overlaps within the ea range. + * -1: SUCCESS (no conflicting entry found) + * <=-2: ERROR (invalid input) + */ +int +rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz); + +/* Find TLB index that maps 'ea/as' combination + * + * RETURNS: index 'key'; i.e., the index number plus + * a bit (E500_SELTLB_1) which indicates whether + * the mapping was found in TLB0 (4k fixed page + * size) or in TLB1 (variable page size). + * + * On error (no mapping) -1 is returned. + */ +rtems_e500_tlb_idx +rtems_e500_ftlb(uint32_t ea, int as); + +/* Mark TLB entry as invalid ('disabled'). Unlike + * rtems_e500_wrtlb() with a negative size argument + * this routine also can disable TLB0 entries. + * + * 'key': TLB entry index ORed with selector bit + * (E500_SELTLB_0 for TLB0, E500_SELTLB_1 for TLB1). + * + * RETURNS: zero on success, nonzero on error (TLB + * unchanged). + * + * NOTE: If a TLB1 entry is disabled the associated + * entry in rtems_e500_va_cache[] is also + * marked as disabled. + */ +int +rtems_e500_clrtlb(rtems_e500_tlb_idx key); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/bsps/powerpc/include/libcpu/io.h b/bsps/powerpc/include/libcpu/io.h new file mode 100644 index 0000000000..841df81f47 --- /dev/null +++ b/bsps/powerpc/include/libcpu/io.h @@ -0,0 +1,139 @@ +/* + * io.h + * + * This file contains inline implementation of function to + * deal with IO. + * + * It is a stripped down version of linux ppc file... + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +#ifndef _LIBCPU_IO_H +#define _LIBCPU_IO_H + + +#define PREP_ISA_IO_BASE 0x80000000 +#define PREP_ISA_MEM_BASE 0xc0000000 +#define PREP_PCI_DRAM_OFFSET 0x80000000 + +#define CHRP_ISA_IO_BASE 0xfe000000 +#define CHRP_ISA_MEM_BASE 0xfd000000 +#define CHRP_PCI_DRAM_OFFSET 0x00000000 + +/* _IO_BASE, _ISA_MEM_BASE, PCI_DRAM_OFFSET are now defined by bsp.h */ + +#ifndef ASM + +#include <bsp.h> /* for _IO_BASE & friends */ +#include <stdint.h> + +/* NOTE: The use of these macros is DISCOURAGED. + * you should consider e.g. using in_xxx / out_xxx + * with a device specific base address that is + * defined by the BSP. This makes drivers easier + * to port. + */ +#define inb(port) in_8((uint8_t *)((port)+_IO_BASE)) +#define outb(val, port) out_8((uint8_t *)((port)+_IO_BASE), (val)) +#define inw(port) in_le16((uint16_t *)((port)+_IO_BASE)) +#define outw(val, port) out_le16((uint16_t *)((port)+_IO_BASE), (val)) +#define inl(port) in_le32((uint32_t *)((port)+_IO_BASE)) +#define outl(val, port) out_le32((uint32_t *)((port)+_IO_BASE), (val)) + +/* + * Enforce In-order Execution of I/O: + * Acts as a barrier to ensure all previous I/O accesses have + * completed before any further ones are issued. + */ +static inline void eieio(void) +{ + __asm__ __volatile__ ("eieio"); +} + + +/* Enforce in-order execution of data I/O. + * No distinction between read/write on PPC; use eieio for all three. + */ +#define iobarrier_rw() eieio() +#define iobarrier_r() eieio() +#define iobarrier_w() eieio() + +/* + * 8, 16 and 32 bit, big and little endian I/O operations, with barrier. + */ +static inline uint8_t in_8(const volatile uint8_t *addr) +{ + uint8_t ret; + + __asm__ __volatile__("lbz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr)); + return ret; +} + +static inline void out_8(volatile uint8_t *addr, uint8_t val) +{ + __asm__ __volatile__("stb%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val)); +} + +static inline uint16_t in_le16(const volatile uint16_t *addr) +{ + uint16_t ret; + + __asm__ __volatile__("lhbrx %0,0,%1; eieio" : "=r" (ret) : + "r" (addr), "m" (*addr)); + return ret; +} + +static inline uint16_t in_be16(const volatile uint16_t *addr) +{ + uint16_t ret; + + __asm__ __volatile__("lhz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr)); + return ret; +} + +static inline void out_le16(volatile uint16_t *addr, uint16_t val) +{ + __asm__ __volatile__("sthbrx %1,0,%2; eieio" : "=m" (*addr) : + "r" (val), "r" (addr)); +} + +static inline void out_be16(volatile uint16_t *addr, uint16_t val) +{ + __asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val)); +} + +static inline uint32_t in_le32(const volatile uint32_t *addr) +{ + uint32_t ret; + + __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) : + "r" (addr), "m" (*addr)); + return ret; +} + +static inline uint32_t in_be32(const volatile uint32_t *addr) +{ + uint32_t ret; + + __asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr)); + return ret; +} + +static inline void out_le32(volatile uint32_t *addr, uint32_t val) +{ + __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) : + "r" (val), "r" (addr)); +} + +static inline void out_be32(volatile uint32_t *addr, uint32_t val) +{ + __asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val)); +} + +#endif /* ASM */ +#endif /* _LIBCPU_IO_H */ diff --git a/bsps/powerpc/include/libcpu/irq.h b/bsps/powerpc/include/libcpu/irq.h new file mode 100644 index 0000000000..ab06041d24 --- /dev/null +++ b/bsps/powerpc/include/libcpu/irq.h @@ -0,0 +1,199 @@ +/* + * irq.h + * + * This include file describe the data structure and the functions implemented + * by rtems to write interrupt handlers. + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/irq/irq.h: + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * This code is heavilly inspired by the public specification of STREAM V2 + * that can be found at : + * + * <http://www.chorus.com/Documentation/index.html> by following + * the STREAM API Specification Document link. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_IRQ_H +#define _LIBCPU_IRQ_H + +#include <rtems/irq.h> + +#define CPU_ASM_IRQ_VECTOR_BASE 0x0 + +#ifndef ASM + +extern volatile unsigned int ppc_cached_irq_mask; + +/* + * Symblolic IRQ names and related definitions. + */ + + /* + * Base vector for our USIU IRQ handlers. + */ +#define CPU_USIU_VECTOR_BASE (CPU_ASM_IRQ_VECTOR_BASE) + /* + * USIU IRQ handler related definitions + */ +#define CPU_USIU_IRQ_COUNT (16) /* 16 reserved but in the future... */ +#define CPU_USIU_IRQ_MIN_OFFSET (0) +#define CPU_USIU_IRQ_MAX_OFFSET (CPU_USIU_IRQ_MIN_OFFSET + CPU_USIU_IRQ_COUNT - 1) + /* + * UIMB IRQ handlers related definitions + */ +#define CPU_UIMB_IRQ_COUNT (32 - 8) /* first 8 overlap USIU */ +#define CPU_UIMB_IRQ_MIN_OFFSET (CPU_USIU_IRQ_COUNT + CPU_USIU_VECTOR_BASE) +#define CPU_UIMB_IRQ_MAX_OFFSET (CPU_UIMB_IRQ_MIN_OFFSET + CPU_UIMB_IRQ_COUNT - 1) + /* + * PowerPc exceptions handled as interrupt where a rtems managed interrupt + * handler might be connected + */ +#define CPU_PROC_IRQ_COUNT (1) +#define CPU_PROC_IRQ_MIN_OFFSET (CPU_UIMB_IRQ_MAX_OFFSET + 1) +#define CPU_PROC_IRQ_MAX_OFFSET (CPU_PROC_IRQ_MIN_OFFSET + CPU_PROC_IRQ_COUNT - 1) + /* + * Summary + */ +#define CPU_IRQ_COUNT (CPU_PROC_IRQ_MAX_OFFSET + 1) +#define CPU_MIN_OFFSET (CPU_USIU_IRQ_MIN_OFFSET) +#define CPU_MAX_OFFSET (CPU_PROC_IRQ_MAX_OFFSET) + /* + * USIU IRQ symbolic name definitions. + */ +#define CPU_USIU_EXT_IRQ_0 (CPU_USIU_IRQ_MIN_OFFSET + 0) +#define CPU_USIU_INT_IRQ_0 (CPU_USIU_IRQ_MIN_OFFSET + 1) + +#define CPU_USIU_EXT_IRQ_1 (CPU_USIU_IRQ_MIN_OFFSET + 2) +#define CPU_USIU_INT_IRQ_1 (CPU_USIU_IRQ_MIN_OFFSET + 3) + +#define CPU_USIU_EXT_IRQ_2 (CPU_USIU_IRQ_MIN_OFFSET + 4) +#define CPU_USIU_INT_IRQ_2 (CPU_USIU_IRQ_MIN_OFFSET + 5) + +#define CPU_USIU_EXT_IRQ_3 (CPU_USIU_IRQ_MIN_OFFSET + 6) +#define CPU_USIU_INT_IRQ_3 (CPU_USIU_IRQ_MIN_OFFSET + 7) + +#define CPU_USIU_EXT_IRQ_4 (CPU_USIU_IRQ_MIN_OFFSET + 8) +#define CPU_USIU_INT_IRQ_4 (CPU_USIU_IRQ_MIN_OFFSET + 9) + +#define CPU_USIU_EXT_IRQ_5 (CPU_USIU_IRQ_MIN_OFFSET + 10) +#define CPU_USIU_INT_IRQ_5 (CPU_USIU_IRQ_MIN_OFFSET + 11) + +#define CPU_USIU_EXT_IRQ_6 (CPU_USIU_IRQ_MIN_OFFSET + 12) +#define CPU_USIU_INT_IRQ_6 (CPU_USIU_IRQ_MIN_OFFSET + 13) + +#define CPU_USIU_EXT_IRQ_7 (CPU_USIU_IRQ_MIN_OFFSET + 14) +#define CPU_USIU_INT_IRQ_7 (CPU_USIU_IRQ_MIN_OFFSET + 15) + + /* + * Symbolic names for UISU interrupt sources. + */ +#define CPU_PERIODIC_TIMER (CPU_USIU_INT_IRQ_6) +#define CPU_UIMB_INTERRUPT (CPU_USIU_INT_IRQ_7) + + /* + * UIMB IRQ symbolic name definitions. The first 8 sources are aliases to + * the USIU interrupts of the same number, because they are detected in + * the USIU pending register rather than the UIMB pending register. + */ +#define CPU_UIMB_IRQ_0 (CPU_USIU_INT_IRQ_0) +#define CPU_UIMB_IRQ_1 (CPU_USIU_INT_IRQ_1) +#define CPU_UIMB_IRQ_2 (CPU_USIU_INT_IRQ_2) +#define CPU_UIMB_IRQ_3 (CPU_USIU_INT_IRQ_3) +#define CPU_UIMB_IRQ_4 (CPU_USIU_INT_IRQ_4) +#define CPU_UIMB_IRQ_5 (CPU_USIU_INT_IRQ_5) +#define CPU_UIMB_IRQ_6 (CPU_USIU_INT_IRQ_6) +#define CPU_UIMB_IRQ_7 (CPU_USIU_INT_IRQ_7) + +#define CPU_UIMB_IRQ_8 (CPU_UIMB_IRQ_MIN_OFFSET+ 0) +#define CPU_UIMB_IRQ_9 (CPU_UIMB_IRQ_MIN_OFFSET+ 1) +#define CPU_UIMB_IRQ_10 (CPU_UIMB_IRQ_MIN_OFFSET+ 2) +#define CPU_UIMB_IRQ_11 (CPU_UIMB_IRQ_MIN_OFFSET+ 3) +#define CPU_UIMB_IRQ_12 (CPU_UIMB_IRQ_MIN_OFFSET+ 4) +#define CPU_UIMB_IRQ_13 (CPU_UIMB_IRQ_MIN_OFFSET+ 5) +#define CPU_UIMB_IRQ_14 (CPU_UIMB_IRQ_MIN_OFFSET+ 6) +#define CPU_UIMB_IRQ_15 (CPU_UIMB_IRQ_MIN_OFFSET+ 7) +#define CPU_UIMB_IRQ_16 (CPU_UIMB_IRQ_MIN_OFFSET+ 8) +#define CPU_UIMB_IRQ_17 (CPU_UIMB_IRQ_MIN_OFFSET+ 9) +#define CPU_UIMB_IRQ_18 (CPU_UIMB_IRQ_MIN_OFFSET+ 0) +#define CPU_UIMB_IRQ_19 (CPU_UIMB_IRQ_MIN_OFFSET+11) +#define CPU_UIMB_IRQ_20 (CPU_UIMB_IRQ_MIN_OFFSET+12) +#define CPU_UIMB_IRQ_21 (CPU_UIMB_IRQ_MIN_OFFSET+13) +#define CPU_UIMB_IRQ_22 (CPU_UIMB_IRQ_MIN_OFFSET+14) +#define CPU_UIMB_IRQ_23 (CPU_UIMB_IRQ_MIN_OFFSET+15) +#define CPU_UIMB_IRQ_24 (CPU_UIMB_IRQ_MIN_OFFSET+16) +#define CPU_UIMB_IRQ_25 (CPU_UIMB_IRQ_MIN_OFFSET+17) +#define CPU_UIMB_IRQ_26 (CPU_UIMB_IRQ_MIN_OFFSET+18) +#define CPU_UIMB_IRQ_27 (CPU_UIMB_IRQ_MIN_OFFSET+19) +#define CPU_UIMB_IRQ_28 (CPU_UIMB_IRQ_MIN_OFFSET+20) +#define CPU_UIMB_IRQ_29 (CPU_UIMB_IRQ_MIN_OFFSET+21) +#define CPU_UIMB_IRQ_30 (CPU_UIMB_IRQ_MIN_OFFSET+22) +#define CPU_UIMB_IRQ_31 (CPU_UIMB_IRQ_MIN_OFFSET+23) + + /* + * Symbolic names for UIMB interrupt sources. + */ +#define CPU_IRQ_SCI (CPU_UIMB_IRQ_5) + + /* + * Processor exceptions handled as rtems IRQ symbolic name definitions. + */ +#define CPU_DECREMENTER (CPU_PROC_IRQ_MIN_OFFSET) + +/* + * Convert an rtems_irq_number constant to an interrupt level + * suitable for programming into an I/O device's interrupt level field. + */ +int CPU_irq_level_from_symbolic_name(const rtems_irq_number name); + +/*-------------------------------------------------------------------------+ +| Function Prototypes. ++--------------------------------------------------------------------------*/ + +extern void CPU_rtems_irq_mng_init(unsigned cpuId); + +typedef struct MPC5XX_Interrupt_frame { + uint32_t stacklink; /* Ensure this is a real frame (also reg1 save) */ + uint32_t calleeLr; /* link register used by callees: SVR4/EABI */ + + /* This is what is left out of the primary contexts */ + uint32_t gpr0; + uint32_t gpr2; /* play safe */ + uint32_t gpr3; + uint32_t gpr4; + uint32_t gpr5; + uint32_t gpr6; + uint32_t gpr7; + uint32_t gpr8; + uint32_t gpr9; + uint32_t gpr10; + uint32_t gpr11; + uint32_t gpr12; + uint32_t gpr13; /* Play safe */ + uint32_t gpr28; /* For internal use by the IRQ handler */ + uint32_t gpr29; /* For internal use by the IRQ handler */ + uint32_t gpr30; /* For internal use by the IRQ handler */ + uint32_t gpr31; /* For internal use by the IRQ handler */ + uint32_t cr; /* Bits of this are volatile, so no-one may save */ + uint32_t ctr; + uint32_t xer; + uint32_t lr; + uint32_t pc; + uint32_t msr; + uint32_t pad[3]; +} MPC5XX_Interrupt_frame; + +void C_dispatch_irq_handler(MPC5XX_Interrupt_frame *frame, unsigned int excNum); + +#endif + +#endif diff --git a/bsps/powerpc/include/libcpu/mmu.h b/bsps/powerpc/include/libcpu/mmu.h new file mode 100644 index 0000000000..d3081316eb --- /dev/null +++ b/bsps/powerpc/include/libcpu/mmu.h @@ -0,0 +1,304 @@ +/* + * mmu.h + * + * PowerPC memory management structures + * + * It is a stripped down version of linux ppc file... + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_MMU_H +#define _LIBCPU_MMU_H + +#ifndef ASM +/* Hardware Page Table Entry */ +typedef struct _PTE { + unsigned long v:1; /* Entry is valid */ + unsigned long vsid:24; /* Virtual segment identifier */ + unsigned long h:1; /* Hash algorithm indicator */ + unsigned long api:6; /* Abbreviated page index */ + unsigned long rpn:20; /* Real (physical) page number */ + unsigned long :3; /* Unused */ + unsigned long r:1; /* Referenced */ + unsigned long c:1; /* Changed */ + unsigned long w:1; /* Write-thru cache mode */ + unsigned long i:1; /* Cache inhibited */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page protection */ +} PTE; + +/* Values for PP (assumes Ks=0, Kp=1) */ +#define PP_RWXX 0 /* Supervisor read/write, User none */ +#define PP_RWRX 1 /* Supervisor read/write, User read */ +#define PP_RWRW 2 /* Supervisor read/write, User read/write */ +#define PP_RXRX 3 /* Supervisor read, User read */ + +/* Segment Register */ +typedef struct _SEGREG { + unsigned long t:1; /* Normal or I/O type */ + unsigned long ks:1; /* Supervisor 'key' (normally 0) */ + unsigned long kp:1; /* User 'key' (normally 1) */ + unsigned long n:1; /* No-execute */ + unsigned long :4; /* Unused */ + unsigned long vsid:24; /* Virtual Segment Identifier */ +} SEGREG; + +/* Block Address Translation (BAT) Registers */ +typedef struct _P601_BATU { /* Upper part of BAT for 601 processor */ + unsigned long bepi:15; /* Effective page index (virtual address) */ + unsigned long :8; /* unused */ + unsigned long w:1; + unsigned long i:1; /* Cache inhibit */ + unsigned long m:1; /* Memory coherence */ + unsigned long ks:1; /* Supervisor key (normally 0) */ + unsigned long kp:1; /* User key (normally 1) */ + unsigned long pp:2; /* Page access protections */ +} P601_BATU; + +typedef struct _BATU { /* Upper part of BAT (all except 601) */ + unsigned long bepi:15; /* Effective page index (virtual address) */ + unsigned long :4; /* Unused */ + unsigned long bl:11; /* Block size mask */ + unsigned long vs:1; /* Supervisor valid */ + unsigned long vp:1; /* User valid */ +} BATU; + +typedef struct _P601_BATL { /* Lower part of BAT for 601 processor */ + unsigned long brpn:15; /* Real page index (physical address) */ + unsigned long :10; /* Unused */ + unsigned long v:1; /* Valid bit */ + unsigned long bl:6; /* Block size mask */ +} P601_BATL; + +typedef struct _BATL { /* Lower part of BAT (all except 601) */ + unsigned long brpn:15; /* Real page index (physical address) */ + unsigned long :10; /* Unused */ + unsigned long w:1; /* Write-thru cache */ + unsigned long i:1; /* Cache inhibit */ + unsigned long m:1; /* Memory coherence */ + unsigned long g:1; /* Guarded (MBZ in IBAT) */ + unsigned long :1; /* Unused */ + unsigned long pp:2; /* Page access protections */ +} BATL; + +typedef struct _BAT { + BATU batu; /* Upper register */ + BATL batl; /* Lower register */ +} BAT; + +typedef struct _P601_BAT { + P601_BATU batu; /* Upper register */ + P601_BATL batl; /* Lower register */ +} P601_BAT; + +/* Block size masks */ +#define BL_128K 0x000 +#define BL_256K 0x001 +#define BL_512K 0x003 +#define BL_1M 0x007 +#define BL_2M 0x00F +#define BL_4M 0x01F +#define BL_8M 0x03F +#define BL_16M 0x07F +#define BL_32M 0x0FF +#define BL_64M 0x1FF +#define BL_128M 0x3FF +#define BL_256M 0x7FF + +/* BAT Access Protection */ +#define BPP_XX 0x00 /* No access */ +#define BPP_RX 0x01 /* Read only */ +#define BPP_RW 0x02 /* Read/write */ + +/* + * Simulated two-level MMU. This structure is used by the kernel + * to keep track of MMU mappings and is used to update/maintain + * the hardware HASH table which is really a cache of mappings. + * + * The simulated structures mimic the hardware available on other + * platforms, notably the 80x86 and 680x0. + */ + +typedef struct _pte { + unsigned long page_num:20; + unsigned long flags:12; /* Page flags (some unused bits) */ +} pte; + +#define PD_SHIFT (10+12) /* Page directory */ +#define PD_MASK 0x03FF +#define PT_SHIFT (12) /* Page Table */ +#define PT_MASK 0x03FF +#define PG_SHIFT (12) /* Page Entry */ + + +/* MMU context */ + +typedef struct _MMU_context { + SEGREG segs[16]; /* Segment registers */ + pte **pmap; /* Two-level page-map structure */ +} MMU_context; + +/* Used to set up SDR1 register */ +#define HASH_TABLE_SIZE_64K 0x00010000 +#define HASH_TABLE_SIZE_128K 0x00020000 +#define HASH_TABLE_SIZE_256K 0x00040000 +#define HASH_TABLE_SIZE_512K 0x00080000 +#define HASH_TABLE_SIZE_1M 0x00100000 +#define HASH_TABLE_SIZE_2M 0x00200000 +#define HASH_TABLE_SIZE_4M 0x00400000 +#define HASH_TABLE_MASK_64K 0x000 +#define HASH_TABLE_MASK_128K 0x001 +#define HASH_TABLE_MASK_256K 0x003 +#define HASH_TABLE_MASK_512K 0x007 +#define HASH_TABLE_MASK_1M 0x00F +#define HASH_TABLE_MASK_2M 0x01F +#define HASH_TABLE_MASK_4M 0x03F + +/* invalidate a TLB entry */ +static inline void _tlbie(unsigned long va) +{ + asm volatile ("tlbie %0" : : "r"(va)); +} + +extern void _tlbia(void); /* invalidate all TLB entries */ +#endif /* ASM */ + +/* Control/status registers for the MPC8xx. + * A write operation to these registers causes serialized access. + * During software tablewalk, the registers used perform mask/shift-add + * operations when written/read. A TLB entry is created when the Mx_RPN + * is written, and the contents of several registers are used to + * create the entry. + */ +#define MI_CTR 784 /* Instruction TLB control register */ +#define MI_GPM 0x80000000 /* Set domain manager mode */ +#define MI_PPM 0x40000000 /* Set subpage protection */ +#define MI_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */ +#define MI_RSV4I 0x08000000 /* Reserve 4 TLB entries */ +#define MI_PPCS 0x02000000 /* Use MI_RPN prob/priv state */ +#define MI_IDXMASK 0x00001f00 /* TLB index to be loaded */ +#define MI_RESETVAL 0x00000000 /* Value of register at reset */ + +/* These are the Ks and Kp from the PowerPC books. For proper operation, + * Ks = 0, Kp = 1. + */ +#define MI_AP 786 +#define MI_Ks 0x80000000 /* Should not be set */ +#define MI_Kp 0x40000000 /* Should always be set */ + +/* The effective page number register. When read, contains the information + * about the last instruction TLB miss. When MI_RPN is written, bits in + * this register are used to create the TLB entry. + */ +#define MI_EPN 787 +#define MI_EPNMASK 0xfffff000 /* Effective page number for entry */ +#define MI_EVALID 0x00000200 /* Entry is valid */ +#define MI_ASIDMASK 0x0000000f /* ASID match value */ + /* Reset value is undefined */ + +/* A "level 1" or "segment" or whatever you want to call it register. + * For the instruction TLB, it contains bits that get loaded into the + * TLB entry when the MI_RPN is written. + */ +#define MI_TWC 789 +#define MI_APG 0x000001e0 /* Access protection group (0) */ +#define MI_GUARDED 0x00000010 /* Guarded storage */ +#define MI_PSMASK 0x0000000c /* Mask of page size bits */ +#define MI_PS8MEG 0x0000000c /* 8M page size */ +#define MI_PS512K 0x00000004 /* 512K page size */ +#define MI_PS4K_16K 0x00000000 /* 4K or 16K page size */ +#define MI_SVALID 0x00000001 /* Segment entry is valid */ + /* Reset value is undefined */ + +/* Real page number. Defined by the pte. Writing this register + * causes a TLB entry to be created for the instruction TLB, using + * additional information from the MI_EPN, and MI_TWC registers. + */ +#define MI_RPN 790 + +/* Define an RPN value for mapping kernel memory to large virtual + * pages for boot initialization. This has real page number of 0, + * large page size, shared page, cache enabled, and valid. + * Also mark all subpages valid and write access. + */ +#define MI_BOOTINIT 0x000001fd + +#define MD_CTR 792 /* Data TLB control register */ +#define MD_GPM 0x80000000 /* Set domain manager mode */ +#define MD_PPM 0x40000000 /* Set subpage protection */ +#define MD_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */ +#define MD_WTDEF 0x10000000 /* Set writethrough when MMU dis */ +#define MD_RSV4I 0x08000000 /* Reserve 4 TLB entries */ +#define MD_TWAM 0x04000000 /* Use 4K page hardware assist */ +#define MD_PPCS 0x02000000 /* Use MI_RPN prob/priv state */ +#define MD_IDXMASK 0x00001f00 /* TLB index to be loaded */ +#define MD_RESETVAL 0x04000000 /* Value of register at reset */ + +#define M_CASID 793 /* Address space ID (context) to match */ +#define MC_ASIDMASK 0x0000000f /* Bits used for ASID value */ + + +/* These are the Ks and Kp from the PowerPC books. For proper operation, + * Ks = 0, Kp = 1. + */ +#define MD_AP 794 +#define MD_Ks 0x80000000 /* Should not be set */ +#define MD_Kp 0x40000000 /* Should always be set */ + +/* The effective page number register. When read, contains the information + * about the last instruction TLB miss. When MD_RPN is written, bits in + * this register are used to create the TLB entry. + */ +#define MD_EPN 795 +#define MD_EPNMASK 0xfffff000 /* Effective page number for entry */ +#define MD_EVALID 0x00000200 /* Entry is valid */ +#define MD_ASIDMASK 0x0000000f /* ASID match value */ + /* Reset value is undefined */ + +/* The pointer to the base address of the first level page table. + * During a software tablewalk, reading this register provides the address + * of the entry associated with MD_EPN. + */ +#define M_TWB 796 +#define M_L1TB 0xfffff000 /* Level 1 table base address */ +#define M_L1INDX 0x00000ffc /* Level 1 index, when read */ + /* Reset value is undefined */ + +/* A "level 1" or "segment" or whatever you want to call it register. + * For the data TLB, it contains bits that get loaded into the TLB entry + * when the MD_RPN is written. It is also provides the hardware assist + * for finding the PTE address during software tablewalk. + */ +#define MD_TWC 797 +#define MD_L2TB 0xfffff000 /* Level 2 table base address */ +#define MD_L2INDX 0xfffffe00 /* Level 2 index (*pte), when read */ +#define MD_APG 0x000001e0 /* Access protection group (0) */ +#define MD_GUARDED 0x00000010 /* Guarded storage */ +#define MD_PSMASK 0x0000000c /* Mask of page size bits */ +#define MD_PS8MEG 0x0000000c /* 8M page size */ +#define MD_PS512K 0x00000004 /* 512K page size */ +#define MD_PS4K_16K 0x00000000 /* 4K or 16K page size */ +#define MD_WT 0x00000002 /* Use writethrough page attribute */ +#define MD_SVALID 0x00000001 /* Segment entry is valid */ + /* Reset value is undefined */ + + +/* Real page number. Defined by the pte. Writing this register + * causes a TLB entry to be created for the data TLB, using + * additional information from the MD_EPN, and MD_TWC registers. + */ +#define MD_RPN 798 + +/* This is a temporary storage register that could be used to save + * a processor working register during a tablewalk. + */ +#define M_TW 799 +#endif /* _LIBCPU_MMU_H */ diff --git a/bsps/powerpc/include/libcpu/page.h b/bsps/powerpc/include/libcpu/page.h new file mode 100644 index 0000000000..3efbdef5bc --- /dev/null +++ b/bsps/powerpc/include/libcpu/page.h @@ -0,0 +1,66 @@ +/* + * page.h + * + * PowerPC memory management structures + * + * It is a stripped down version of linux ppc file... + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_PAGE_H +#define _LIBCPU_PAGE_H + +/* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#define PAGE_OFFSET 0xc0000000 + + +#ifndef ASM +/* + * .. while these make it easier on the compiler + */ +typedef unsigned long pte_t; +typedef unsigned long pmd_t; +typedef unsigned long pgd_t; +typedef unsigned long pgprot_t; + +#define pte_val(x) (x) +#define pmd_val(x) (x) +#define pgd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pmd(x) (x) +#define __pgd(x) (x) +#define __pgprot(x) (x) + + +/* align addr on a size boundry - adjust address up if needed -- Cort */ +#define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1))) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +/* map phys->virtual and virtual->phys for RAM pages */ + +#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) +#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) + +#define MAP_NR(addr) (((unsigned long)addr-PAGE_OFFSET) >> PAGE_SHIFT) +#define MAP_PAGE_RESERVED (1<<15) + +extern unsigned long get_zero_page_fast(void); +#endif /* ASM */ +#endif /* _LIBCPU_PAGE_H */ diff --git a/bsps/powerpc/include/libcpu/pgtable.h b/bsps/powerpc/include/libcpu/pgtable.h new file mode 100644 index 0000000000..5be5874b4f --- /dev/null +++ b/bsps/powerpc/include/libcpu/pgtable.h @@ -0,0 +1,144 @@ +/* + * pgtable.h + * + * PowerPC memory management structures + * + * It is a stripped down version of linux ppc file... + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_PGTABLE_H +#define _LIBCPU_PGTABLE_H + +/* + * The PowerPC MMU uses a hash table containing PTEs, together with + * a set of 16 segment registers (on 32-bit implementations), to define + * the virtual to physical address mapping. + * + * We use the hash table as an extended TLB, i.e. a cache of currently + * active mappings. We maintain a two-level page table tree, much like + * that used by the i386, for the sake of the Linux memory management code. + * Low-level assembler code in head.S (procedure hash_page) is responsible + * for extracting ptes from the tree and putting them into the hash table + * when necessary, and updating the accessed and modified bits in the + * page table tree. + * + * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk. + * We also use the two level tables, but we can put the real bits in them + * needed for the TLB and tablewalk. These definitions require Mx_CTR.PPM = 0, + * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1. The level 2 descriptor has + * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit + * based upon user/super access. The TLB does not have accessed nor write + * protect. We assume that if the TLB get loaded with an entry it is + * accessed, and overload the changed bit for write protect. We use + * two bits in the software pte that are supposed to be set to zero in + * the TLB entry (24 and 25) for these indicators. Although the level 1 + * descriptor contains the guarded and writethrough/copyback bits, we can + * set these at the page level since they get copied from the Mx_TWC + * register when the TLB entry is loaded. We will use bit 27 for guard, since + * that is where it exists in the MD_TWC, and bit 26 for writethrough. + * These will get masked from the level 2 descriptor at TLB load time, and + * copied to the MD_TWC before it gets loaded. + */ + +/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */ +#define PMD_SHIFT 22 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * entries per page directory level: our page-table tree is two-level, so + * we don't really have any PMD directory. + */ +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PMD 1 +#define PTRS_PER_PGD 1024 +#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE) + +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 64MB value just means that there will be a 64MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + * + * We no longer map larger than phys RAM with the BATs so we don't have + * to worry about the VMALLOC_OFFSET causing problems. We do have to worry + * about clashes between our early calls to ioremap() that start growing down + * from ioremap_base being run into the VM area allocations (growing upwards + * from VMALLOC_START). For this reason we have ioremap_bot to check when + * we actually run into our mappings setup in the early boot with the VM + * system. This really does become a problem for machines with good amounts + * of RAM. -- Cort + */ +#define VMALLOC_OFFSET (0x4000000) /* 64M */ +#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END ioremap_bot + +/* + * Bits in a linux-style PTE. These match the bits in the + * (hardware-defined) PowerPC PTE as closely as possible. + */ +#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */ +#define _PAGE_USER 0x002 /* matches one of the PP bits */ +#define _PAGE_RW 0x004 /* software: user write access allowed */ +#define _PAGE_GUARDED 0x008 +#define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */ +#define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */ +#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */ +#define _PAGE_DIRTY 0x080 /* C: page changed */ +#define _PAGE_ACCESSED 0x100 /* R: page referenced */ +#define _PAGE_HWWRITE 0x200 /* software: _PAGE_RW & _PAGE_DIRTY */ +#define _PAGE_SHARED 0 + +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) + +#define _PAGE_BASE _PAGE_PRESENT | _PAGE_ACCESSED +#define _PAGE_WRENABLE _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE + +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) + +#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | \ + _PAGE_SHARED) +#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER) +#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED) +#define PAGE_KERNEL_CI __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_SHARED | \ + _PAGE_NO_CACHE ) + +/* + * The PowerPC can only do execute protection on a segment (256MB) basis, + * not on a page basis. So we consider execute permission the same as read. + * Also, write permissions imply read permissions. + * This is the closest we can get.. + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED +#endif /* _LIBCPU_PGTABLE_H */ diff --git a/bsps/powerpc/include/libcpu/powerpc-utility.h b/bsps/powerpc/include/libcpu/powerpc-utility.h new file mode 100644 index 0000000000..4d6af38485 --- /dev/null +++ b/bsps/powerpc/include/libcpu/powerpc-utility.h @@ -0,0 +1,985 @@ +/** + * @file + * + * @ingroup powerpc_shared + * + * @brief General purpose assembler macros, linker command file support and + * some inline functions for direct register access. + */ + +/* + * Copyright (c) 2008-2015 embedded brains GmbH. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * access function for Device Control Registers inspired by "ppc405common.h" + * from Michael Hamel ADInstruments May 2008 + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +/** + * @defgroup powerpc_shared Shared PowerPC Code + */ + +#ifndef __LIBCPU_POWERPC_UTILITY_H +#define __LIBCPU_POWERPC_UTILITY_H + +#if !defined(ASM) + #include <rtems.h> +#endif + +#include <rtems/score/cpu.h> +#include <rtems/powerpc/registers.h> +#include <rtems/powerpc/powerpc.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(ASM) + +#include <rtems/bspIo.h> +#include <rtems/system.h> + +#include <libcpu/cpuIdent.h> + +#define LINKER_SYMBOL(sym) extern char sym []; + +/** + * @brief Read one byte from @a src. + */ +static inline uint8_t ppc_read_byte(const volatile void *src) +{ + uint8_t value; + + __asm__ volatile ( + "lbz %0, 0(%1)" + : "=r" (value) + : "b" (src) + ); + + return value; +} + +/** + * @brief Read one half word from @a src. + */ +static inline uint16_t ppc_read_half_word(const volatile void *src) +{ + uint16_t value; + + __asm__ volatile ( + "lhz %0, 0(%1)" + : "=r" (value) + : "b" (src) + ); + + return value; +} + +/** + * @brief Read one word from @a src. + */ +static inline uint32_t ppc_read_word(const volatile void *src) +{ + uint32_t value; + + __asm__ volatile ( + "lwz %0, 0(%1)" + : "=r" (value) + : "b" (src) + ); + + return value; +} + +/** + * @brief Write one byte @a value to @a dest. + */ +static inline void ppc_write_byte(uint8_t value, volatile void *dest) +{ + __asm__ volatile ( + "stb %0, 0(%1)" + : + : "r" (value), "b" (dest) + ); +} + +/** + * @brief Write one half word @a value to @a dest. + */ +static inline void ppc_write_half_word(uint16_t value, volatile void *dest) +{ + __asm__ volatile ( + "sth %0, 0(%1)" + : + : "r" (value), "b" (dest) + ); +} + +/** + * @brief Write one word @a value to @a dest. + */ +static inline void ppc_write_word(uint32_t value, volatile void *dest) +{ + __asm__ volatile ( + "stw %0, 0(%1)" : + : "r" (value), "b" (dest) + ); +} + + +static inline void *ppc_stack_pointer(void) +{ + void *sp; + + __asm__ volatile ( + "mr %0, 1" + : "=r" (sp) + ); + + return sp; +} + +static inline void ppc_set_stack_pointer(void *sp) +{ + __asm__ volatile ( + "mr 1, %0" + : + : "r" (sp) + ); +} + +static inline void *ppc_link_register(void) +{ + void *lr; + + __asm__ volatile ( + "mflr %0" + : "=r" (lr) + ); + + return lr; +} + +static inline void ppc_set_link_register(void *lr) +{ + __asm__ volatile ( + "mtlr %0" + : + : "r" (lr) + ); +} + +static inline uint32_t ppc_machine_state_register(void) +{ + uint32_t msr; + + __asm__ volatile ( + "mfmsr %0" + : "=r" (msr) + ); + + return msr; +} + +static inline void ppc_set_machine_state_register(uint32_t msr) +{ + __asm__ volatile ( + "mtmsr %0" + : + : "r" (msr) + ); +} + +static inline void ppc_synchronize_data(void) +{ + RTEMS_COMPILER_MEMORY_BARRIER(); + + __asm__ volatile ("sync"); +} + +static inline void ppc_light_weight_synchronize(void) +{ + RTEMS_COMPILER_MEMORY_BARRIER(); + + __asm__ volatile ("lwsync"); +} + +static inline void ppc_synchronize_instructions(void) +{ + RTEMS_COMPILER_MEMORY_BARRIER(); + + __asm__ volatile ("isync"); +} + +static inline void ppc_enforce_in_order_execution_of_io(void) +{ + RTEMS_COMPILER_MEMORY_BARRIER(); + + __asm__ volatile ("eieio"); +} + +static inline void ppc_data_cache_block_flush(void *addr) +{ + __asm__ volatile ( + "dcbf 0, %0" + : + : "r" (addr) + : "memory" + ); +} + +static inline void ppc_data_cache_block_flush_2( + void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbf %0, %1" + : + : "b" (base), "r" (offset) + : "memory" + ); +} + +static inline void ppc_data_cache_block_invalidate(void *addr) +{ + __asm__ volatile ( + "dcbi 0, %0" + : + : "r" (addr) + : "memory" + ); +} + +static inline void ppc_data_cache_block_invalidate_2( + void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbi %0, %1" + : + : "b" (base), "r" (offset) + : "memory" + ); +} + +static inline void ppc_data_cache_block_store(const void *addr) +{ + __asm__ volatile ( + "dcbst 0, %0" + : + : "r" (addr) + ); +} + +static inline void ppc_data_cache_block_store_2( + const void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbst %0, %1" + : + : "b" (base), "r" (offset) + ); +} + +static inline void ppc_data_cache_block_touch(const void *addr) +{ + __asm__ volatile ( + "dcbt 0, %0" + : + : "r" (addr) + ); +} + +static inline void ppc_data_cache_block_touch_2( + const void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbt %0, %1" + : + : "b" (base), "r" (offset) + ); +} + +static inline void ppc_data_cache_block_touch_for_store(const void *addr) +{ + __asm__ volatile ( + "dcbtst 0, %0" + : + : "r" (addr) + ); +} + +static inline void ppc_data_cache_block_touch_for_store_2( + const void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbtst %0, %1" + : + : "b" (base), "r" (offset) + ); +} + +static inline void ppc_data_cache_block_clear_to_zero(void *addr) +{ + __asm__ volatile ( + "dcbz 0, %0" + : + : "r" (addr) + : "memory" + ); +} + +static inline void ppc_data_cache_block_clear_to_zero_2( + void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "dcbz %0, %1" + : + : "b" (base), "r" (offset) + : "memory" + ); +} + +static inline void ppc_instruction_cache_block_invalidate(void *addr) +{ + __asm__ volatile ( + "icbi 0, %0" + : + : "r" (addr) + ); +} + +static inline void ppc_instruction_cache_block_invalidate_2( + void *base, + uintptr_t offset +) +{ + __asm__ volatile ( + "icbi %0, %1" + : + : "b" (base), "r" (offset) + ); +} + +/** + * @brief Enables external exceptions. + * + * You can use this function to enable the external exceptions and restore the + * machine state with ppc_external_exceptions_disable() later. + */ +static inline uint32_t ppc_external_exceptions_enable(void) +{ + uint32_t current_msr; + uint32_t new_msr; + + RTEMS_COMPILER_MEMORY_BARRIER(); + + __asm__ volatile ( + "mfmsr %0;" + "ori %1, %0, 0x8000;" + "mtmsr %1" + : "=r" (current_msr), "=r" (new_msr) + ); + + return current_msr; +} + +/** + * @brief Restores machine state. + * + * @see ppc_external_exceptions_enable() + */ +static inline void ppc_external_exceptions_disable(uint32_t msr) +{ + ppc_set_machine_state_register(msr); + + RTEMS_COMPILER_MEMORY_BARRIER(); +} + +static inline uint32_t ppc_count_leading_zeros(uint32_t value) +{ + uint32_t count; + + __asm__ ( + "cntlzw %0, %1;" + : "=r" (count) + : "r" (value) + ); + + return count; +} + +/* + * Simple spin delay in microsecond units for device drivers. + * This is very dependent on the clock speed of the target. + */ + +#if defined(mpx8xx) || defined(mpc860) || defined(mpc821) +/* Wonderful bookE doesn't have mftb/mftbu; they only + * define the TBRU/TBRL SPRs so we use these. Luckily, + * we run in supervisory mode so that should work on + * all CPUs. In user mode we'd have a problem... + * 2007/11/30, T.S. + * + * OTOH, PSIM currently lacks support for reading + * SPRs 268/269. You need GDB patch sim/2376 to avoid + * a crash... + * OTOH, the MPC8xx do not allow to read the timebase registers via mfspr. + * we NEED a mftb to access the time base. + * 2009/10/30 Th. D. + */ +#define CPU_Get_timebase_low( _value ) \ + __asm__ volatile( "mftb %0" : "=r" (_value) ) +#else +#define CPU_Get_timebase_low( _value ) \ + __asm__ volatile( "mfspr %0,268" : "=r" (_value) ) +#endif + +/* Must be provided for rtems_bsp_delay to work */ +extern uint32_t bsp_clicks_per_usec; + +#define rtems_bsp_delay( _microseconds ) \ + do { \ + uint32_t start, ticks, now; \ + CPU_Get_timebase_low( start ) ; \ + ticks = (_microseconds) * bsp_clicks_per_usec; \ + do \ + CPU_Get_timebase_low( now ) ; \ + while (now - start < ticks); \ + } while (0) + +#define rtems_bsp_delay_in_bus_cycles( _cycles ) \ + do { \ + uint32_t start, now; \ + CPU_Get_timebase_low( start ); \ + do \ + CPU_Get_timebase_low( now ); \ + while (now - start < (_cycles)); \ + } while (0) + +/* + * Routines to access the decrementer register + */ + +#define PPC_Set_decrementer( _clicks ) \ + do { \ + __asm__ volatile( "mtdec %0" : : "r" ((_clicks)) ); \ + } while (0) + +#define PPC_Get_decrementer( _clicks ) \ + __asm__ volatile( "mfdec %0" : "=r" (_clicks) ) + +/* + * Routines to access the time base register + */ + +static inline uint64_t PPC_Get_timebase_register( void ) +{ + uint32_t tbr_low; + uint32_t tbr_high; + uint32_t tbr_high_old; + uint64_t tbr; + + do { +#if defined(mpx8xx) || defined(mpc860) || defined(mpc821) +/* See comment above (CPU_Get_timebase_low) */ + __asm__ volatile( "mftbu %0" : "=r" (tbr_high_old)); + __asm__ volatile( "mftb %0" : "=r" (tbr_low)); + __asm__ volatile( "mftbu %0" : "=r" (tbr_high)); +#else + __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high_old)); + __asm__ volatile( "mfspr %0, 268" : "=r" (tbr_low)); + __asm__ volatile( "mfspr %0, 269" : "=r" (tbr_high)); +#endif + } while ( tbr_high_old != tbr_high ); + + tbr = tbr_high; + tbr <<= 32; + tbr |= tbr_low; + return tbr; +} + +static inline void PPC_Set_timebase_register (uint64_t tbr) +{ + uint32_t tbr_low; + uint32_t tbr_high; + + tbr_low = (uint32_t) tbr; + tbr_high = (uint32_t) (tbr >> 32); + __asm__ volatile( "mtspr 284, %0" : : "r" (tbr_low)); + __asm__ volatile( "mtspr 285, %0" : : "r" (tbr_high)); + +} + +static inline uint32_t ppc_decrementer_register(void) +{ + uint32_t dec; + + PPC_Get_decrementer(dec); + + return dec; +} + +static inline void ppc_set_decrementer_register(uint32_t dec) +{ + PPC_Set_decrementer(dec); +} + +/** + * @brief Preprocessor magic for stringification of @a x. + */ +#define PPC_STRINGOF(x) #x + +/** + * @brief Returns the value of the Special Purpose Register with number @a spr. + * + * @note This macro uses a GNU C extension. + */ +#define PPC_SPECIAL_PURPOSE_REGISTER(spr) \ + ({ \ + uint32_t val; \ + __asm__ volatile (\ + "mfspr %0, " PPC_STRINGOF(spr) \ + : "=r" (val) \ + ); \ + val;\ + } ) + +/** + * @brief Sets the Special Purpose Register with number @a spr to the value in + * @a val. + */ +#define PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val) \ + do { \ + __asm__ volatile (\ + "mtspr " PPC_STRINGOF(spr) ", %0" \ + : \ + : "r" (val) \ + ); \ + } while (0) + +/** + * @brief Sets in the Special Purpose Register with number @a spr all bits + * which are set in @a bits. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + _ISR_Local_disable(level); \ + val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \ + val |= mybits; \ + PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +/** + * @brief Sets in the Special Purpose Register with number @a spr all bits + * which are set in @a bits. The previous register value will be masked with + * @a mask. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS_MASKED(spr, bits, mask) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + uint32_t mymask = mask; \ + _ISR_Local_disable(level); \ + val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \ + val &= ~mymask; \ + val |= mybits; \ + PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +/** + * @brief Clears in the Special Purpose Register with number @a spr all bits + * which are set in @a bits. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_CLEAR_SPECIAL_PURPOSE_REGISTER_BITS(spr, bits) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + _ISR_Local_disable(level); \ + val = PPC_SPECIAL_PURPOSE_REGISTER(spr); \ + val &= ~mybits; \ + PPC_SET_SPECIAL_PURPOSE_REGISTER(spr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +/** + * @brief Returns the value of the Thread Management Register with number @a tmr. + * + * @note This macro uses a GNU C extension. + */ +#define PPC_THREAD_MGMT_REGISTER(tmr) \ + ({ \ + uint32_t val; \ + __asm__ volatile (\ + "mftmr %0, " PPC_STRINGOF(tmr) \ + : "=r" (val) \ + ); \ + val;\ + } ) + +/** + * @brief Sets the Thread Management Register with number @a tmr to the value in + * @a val. + */ +#define PPC_SET_THREAD_MGMT_REGISTER(tmr, val) \ + do { \ + __asm__ volatile (\ + "mttmr " PPC_STRINGOF(tmr) ", %0" \ + : \ + : "r" (val) \ + ); \ + } while (0) + +/** + * @brief Returns the value of the Device Control Register with number @a dcr. + * + * The PowerPC 4XX family has Device Control Registers. + * + * @note This macro uses a GNU C extension. + */ +#define PPC_DEVICE_CONTROL_REGISTER(dcr) \ + ({ \ + uint32_t val; \ + __asm__ volatile (\ + "mfdcr %0, " PPC_STRINGOF(dcr) \ + : "=r" (val) \ + ); \ + val;\ + } ) + +/** + * @brief Sets the Device Control Register with number @a dcr to the value in + * @a val. + * + * The PowerPC 4XX family has Device Control Registers. + */ +#define PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val) \ + do { \ + __asm__ volatile (\ + "mtdcr " PPC_STRINGOF(dcr) ", %0" \ + : \ + : "r" (val) \ + ); \ + } while (0) + +/** + * @brief Sets in the Device Control Register with number @a dcr all bits + * which are set in @a bits. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + _ISR_Local_disable(level); \ + val = PPC_DEVICE_CONTROL_REGISTER(dcr); \ + val |= mybits; \ + PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +/** + * @brief Sets in the Device Control Register with number @a dcr all bits + * which are set in @a bits. The previous register value will be masked with + * @a mask. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_SET_DEVICE_CONTROL_REGISTER_BITS_MASKED(dcr, bits, mask) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + uint32_t mymask = mask; \ + _ISR_Local_disable(level); \ + val = PPC_DEVICE_CONTROL_REGISTER(dcr); \ + val &= ~mymask; \ + val |= mybits; \ + PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +/** + * @brief Clears in the Device Control Register with number @a dcr all bits + * which are set in @a bits. + * + * Interrupts are disabled throughout this operation. + */ +#define PPC_CLEAR_DEVICE_CONTROL_REGISTER_BITS(dcr, bits) \ + do { \ + ISR_Level level; \ + uint32_t val; \ + uint32_t mybits = bits; \ + _ISR_Local_disable(level); \ + val = PPC_DEVICE_CONTROL_REGISTER(dcr); \ + val &= ~mybits; \ + PPC_SET_DEVICE_CONTROL_REGISTER(dcr, val); \ + _ISR_Local_enable(level); \ + } while (0) + +static inline uint32_t ppc_time_base(void) +{ + uint32_t val; + + CPU_Get_timebase_low(val); + + return val; +} + +static inline void ppc_set_time_base(uint32_t val) +{ + PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWL, val); +} + +static inline uint32_t ppc_time_base_upper(void) +{ + return PPC_SPECIAL_PURPOSE_REGISTER(TBRU); +} + +static inline void ppc_set_time_base_upper(uint32_t val) +{ + PPC_SET_SPECIAL_PURPOSE_REGISTER(TBWU, val); +} + +static inline uint64_t ppc_time_base_64(void) +{ + return PPC_Get_timebase_register(); +} + +static inline void ppc_set_time_base_64(uint64_t val) +{ + PPC_Set_timebase_register(val); +} + +static inline uint32_t ppc_alternate_time_base(void) +{ + return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBL); +} + +static inline uint32_t ppc_alternate_time_base_upper(void) +{ + return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_ATBU); +} + +static inline uint64_t ppc_alternate_time_base_64(void) +{ + uint32_t atbl; + uint32_t atbu_0; + uint32_t atbu_1; + + do { + atbu_0 = ppc_alternate_time_base_upper(); + atbl = ppc_alternate_time_base(); + atbu_1 = ppc_alternate_time_base_upper(); + } while (atbu_0 != atbu_1); + + return (((uint64_t) atbu_1) << 32) | ((uint64_t) atbl); +} + +static inline uint32_t ppc_processor_id(void) +{ + return PPC_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR); +} + +static inline void ppc_set_processor_id(uint32_t val) +{ + PPC_SET_SPECIAL_PURPOSE_REGISTER(BOOKE_PIR, val); +} + +static inline uint32_t ppc_fsl_system_version(void) +{ + return PPC_SPECIAL_PURPOSE_REGISTER(FSL_EIS_SVR); +} + +static inline uint32_t ppc_fsl_system_version_cid(uint32_t svr) +{ + return (svr >> 28) & 0xf; +} + +static inline uint32_t ppc_fsl_system_version_sid(uint32_t svr) +{ + return (svr >> 16) & 0xfff; +} + +static inline uint32_t ppc_fsl_system_version_proc(uint32_t svr) +{ + return (svr >> 12) & 0xf; +} + +static inline uint32_t ppc_fsl_system_version_mfg(uint32_t svr) +{ + return (svr >> 8) & 0xf; +} + +static inline uint32_t ppc_fsl_system_version_mjrev(uint32_t svr) +{ + return (svr >> 4) & 0xf; +} + +static inline uint32_t ppc_fsl_system_version_mnrev(uint32_t svr) +{ + return (svr >> 0) & 0xf; +} + +void ppc_code_copy(void *dest, const void *src, size_t n); + +/* FIXME: Do not use this function */ +void printBAT(int bat, uint32_t upper, uint32_t lower); + +/* FIXME: Do not use this function */ +void ShowBATS(void); + +#endif /* ifndef ASM */ + +#if defined(ASM) +#include <rtems/asm.h> + +.macro LA reg, addr +#if defined(__powerpc64__) + lis \reg, (\addr)@highest + ori \reg, \reg, (\addr)@higher + rldicr \reg, \reg, 32, 31 + oris \reg, \reg, (\addr)@h + ori \reg, \reg, (\addr)@l +#else + lis \reg, (\addr)@h + ori \reg, \reg, (\addr)@l +#endif +.endm + +.macro LA32 reg, addr + lis \reg, (\addr)@h + ori \reg, \reg, (\addr)@l +.endm + +.macro LWI reg, value + lis \reg, (\value)@h + ori \reg, \reg, (\value)@l +.endm + +.macro LW reg, addr + lis \reg, \addr@ha + lwz \reg, \addr@l(\reg) +.endm + +/* + * Tests the bits in reg1 against the bits set in mask. A match is indicated + * by EQ = 0 in CR0. A mismatch is indicated by EQ = 1 in CR0. The register + * reg2 is used to load the mask. + */ +.macro TSTBITS reg1, reg2, mask + LWI \reg2, \mask + and \reg1, \reg1, \reg2 + cmplw \reg1, \reg2 +.endm + +.macro SETBITS reg1, reg2, mask + LWI \reg2, \mask + or \reg1, \reg1, \reg2 +.endm + +.macro CLRBITS reg1, reg2, mask + LWI \reg2, \mask + andc \reg1, \reg1, \reg2 +.endm + +.macro GLOBAL_FUNCTION name + .global \name + .type \name, @function +\name: +.endm + +/* + * Obtain interrupt mask + */ +.macro GET_INTERRUPT_MASK mask + lis \mask, _PPC_INTERRUPT_DISABLE_MASK@h + ori \mask, \mask, _PPC_INTERRUPT_DISABLE_MASK@l +.endm + +/* + * Disables all asynchronous exeptions (interrupts) which may cause a context + * switch. + */ +.macro INTERRUPT_DISABLE level, mask + mfmsr \level + GET_INTERRUPT_MASK mask=\mask + andc \mask, \level, \mask + mtmsr \mask +.endm + +/* + * Restore previous machine state. + */ +.macro INTERRUPT_ENABLE level + mtmsr \level +.endm + +.macro SET_SELF_CPU_CONTROL reg_0, reg_1 +#if defined(RTEMS_SMP) + /* Use Book E Processor ID Register (PIR) */ + mfspr \reg_0, 286 + slwi \reg_0, \reg_0, PER_CPU_CONTROL_SIZE_LOG2 +#if defined(__powerpc64__) + LA \reg_1, _Per_CPU_Information + add \reg_0, \reg_0, \reg_1 +#else + addis \reg_0, \reg_0, _Per_CPU_Information@ha + addi \reg_0, \reg_0, _Per_CPU_Information@l +#endif + mtspr PPC_PER_CPU_CONTROL_REGISTER, \reg_0 +#endif +.endm + +.macro GET_SELF_CPU_CONTROL reg +#if defined(RTEMS_SMP) + mfspr \reg, PPC_PER_CPU_CONTROL_REGISTER +#else + lis \reg, _Per_CPU_Information@h + ori \reg, \reg, _Per_CPU_Information@l +#endif +.endm + +#define LINKER_SYMBOL(sym) .extern sym + +#endif /* ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBCPU_POWERPC_UTILITY_H */ diff --git a/bsps/powerpc/include/libcpu/pte121.h b/bsps/powerpc/include/libcpu/pte121.h new file mode 100644 index 0000000000..a07e063f03 --- /dev/null +++ b/bsps/powerpc/include/libcpu/pte121.h @@ -0,0 +1,265 @@ +#ifndef _LIBCPU_PTE121_H +#define _LIBCPU_PTE121_H + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann <strauman@slac.stanford.edu>, 4/2002, 2003, 2004, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * This software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +/* Rudimentary page/hash table support for Powerpc + * + * A simple, static (i.e. no 'per-process' virtual + * address space etc.) page table providing + * one-to-one effective <-> virtual <-> physical + * address mapping. + * + * PURPOSE: + * 1) allow write-protection of text/read-only data areas + * 2) provide more effective-address space in case + * the BATs are not enough + * 3) allow 'alias' mappings. Such aliases can only use + * the upper bits of the VSID since VSID & 0xf and the + * PI are always mapped 1:1 to the RPN. + * LIMITATIONS: + * - no PTE replacement (makes no sense in a real-time + * environment, anyway) -> the page table just MUST + * be big enough!. + * - only one page table supported. + * - no locking implemented. If multiple threads modify + * the page table, it is the user's responsibility to + * implement exclusive access. + */ + + +/* I don't include mmu.h here because it says it's derived from linux + * and I want to avoid licensing problems + */ + +/* Abstract handle for a page table */ +typedef struct Triv121PgTblRec_ *Triv121PgTbl; + +/* A PTE entry */ +typedef struct PTERec_ { + volatile unsigned long v:1, vsid:24, h:1, api: 6; + volatile unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2; +} PTERec, *APte; + +/* Initialize a trivial page table + * using 2^ldSize bytes of memory starting at + * 'base'. + * + * RETURNS: a handle to the internal data structure + * used to manage the page table. NULL on + * error. + * + * NOTES: - 'base' must be aligned to the size + * - minimal ldSize is 16 (== 64k) + * - this routine maps the page table itself + * with read-only access. While this prevents + * the CPU from overwriting the page table, + * it can still be corrupted by PCI bus masters + * (like DMA engines, [VME] bridges etc.) and + * even by this CPU if either the MMU is off + * or if there is a DBAT mapping granting write + * access... + */ +Triv121PgTbl +triv121PgTblInit(unsigned long base, unsigned ldSize); + +/* get the log2 of the minimal page table size needed + * for mapping 'size' bytes. + * + * EXAMPLE: create a page table which maps the entire + * physical memory. The page table itself shall + * be allocated at the top of the available + * memory (assuming 'memsize' is a power of two): + * + * ldSize = triv121PgTblLdMinSize(memsize); + * memsize -= (1<<ldSize); / * reduce memory available to RTEMS * / + * pgTbl = triv121PgTblInit(memsize,ldSize); + * + */ +unsigned long +triv121PgTblLdMinSize(unsigned long size); + +/* Map an address range 1:1 in pgTbl with the given protection; + * + * RETURNS: -1 (TRIV121_MAP_SUCCESS) on success; the page index + * for which no PTE could be allocated, on failure. + * + * NOTES: - This routine returns MINUS ONE ON SUCCESS + * - (parts) of a mapping which overlap with + * already existing PTEs are silently ignored. + * + * Therefore, you can e.g. first create + * a couple of write protected maps and + * finally map the entire memory r/w. This + * will leave the write protected maps + * intact. + */ +long +triv121PgTblMap( + Triv121PgTbl pgTbl, /* handle, returned by Init or Get */ + + long vsid, /* vsid for this mapping (contains topmost 4 bits of EA); + * + * NOTE: it is allowed to pass a VSID < 0 to tell this + * routine it should use a VSID corresponding to a + * 1:1:1 effective - virtual - physical mapping + */ + + unsigned long start, /* segment offset (lowermost 28 bits of EA) of address range + * + * NOTE: if VSID < 0 (TRIV121_121_VSID), 'start' is inter- + * preted as an effective address (EA), i.e. all 32 + * bits are used - the most significant four going into + * to the VSID... + */ + + unsigned long numPages, /* number of pages to map */ + + unsigned wimgAttr, /* 'wimg' attributes + * (Write thru, cache Inhibit, coherent Memory, + * Guarded memory) + */ + + unsigned protection /* 'pp' access protection: Super User + * + * 0 r/w none + * 1 r/w ro + * 2 r/w r/w + * 3 ro ro + */ +); + +#define TRIV121_ATTR_W 8 +#define TRIV121_ATTR_I 4 +#define TRIV121_ATTR_M 2 +#define TRIV121_ATTR_G 1 + +/* for I/O pages (e.g. PCI, VME addresses) use cache inhibited + * and guarded pages. RTM about the 'eieio' instruction! + */ +#define TRIV121_ATTR_IO_PAGE (TRIV121_ATTR_I|TRIV121_ATTR_G) + +#define TRIV121_PP_RO_PAGE (1) /* read-only for key = 1, unlocked by key=0 */ +#define TRIV121_PP_RW_PAGE (2) /* read-write for key = 1/0 */ + +#define TRIV121_121_VSID (-1) /* use 1:1 effective<->virtual address mapping */ +#define TRIV121_SEG_VSID (-2) /* lookup VSID in the segment register */ + +#define TRIV121_MAP_SUCCESS (-1) /* triv121PgTblMap() returns this on SUCCESS */ + +/* get a handle to the one and only page table + * (must have been initialized/allocated) + * + * RETURNS: NULL if the page table has not been initialized/allocated. + */ +Triv121PgTbl +triv121PgTblGet(void); + +/* + * compute the SDR1 register value for the page table + */ + +unsigned long +triv121PgTblSDR1(Triv121PgTbl pgTbl); + +/* + * Activate the page table: + * - set up the segment registers for a 1:1 effective <-> virtual address mapping, + * give user and supervisor keys. + * - set up the SDR1 register + * - flush all tlbs + * - 'lock' pgTbl, i.e. prevent all further modifications. + * + * NOTE: This routine does not change any BATs. Since these + * have priority over the page table, the user + * may have to switch overlapping BATs OFF in order + * for the page table mappings to take effect. + */ +void triv121PgTblActivate(Triv121PgTbl pgTbl); + +/* Find the PTE for a EA and print its contents to stdout + * RETURNS: pte for EA or NULL if no entry was found. + */ +APte triv121DumpEa(unsigned long ea); + +/* Find and return a PTE for a vsid/pi combination + * RETURNS: pte or NULL if no entry was found + */ +APte triv121FindPte(unsigned long vsid, unsigned long pi); + +/* + * Unmap an effective address + * + * RETURNS: pte that mapped the ea or NULL if no + * mapping existed. + */ +APte triv121UnmapEa(unsigned long ea); + +/* + * Change the WIMG and PP attributes of the page containing 'ea' + * + * NOTES: The 'wimg' and 'pp' may be <0 to indicate that no + * change is desired. + * + * RETURNS: Pointer to modified PTE or NULL if 'ea' is not mapped. + */ +APte triv121ChangeEaAttributes(unsigned long ea, int wimg, int pp); + +/* Make the whole page table writable + * NOTES: If the page table has not been initialized yet, + * this routine has no effect (i.e., after + * initialization the page table will still be read-only). + */ +void triv121MakePgTblRW(void); + +/* Make the whole page table read-only + */ +void triv121MakePgTblRO(void); + +/* Dump a pte to stdout */ +long triv121DumpPte(APte pte); + +#endif diff --git a/bsps/powerpc/include/libcpu/raw_exception.h b/bsps/powerpc/include/libcpu/raw_exception.h new file mode 100644 index 0000000000..dd0c483b0d --- /dev/null +++ b/bsps/powerpc/include/libcpu/raw_exception.h @@ -0,0 +1,161 @@ +/* + * raw_execption.h + * + * This file contains implementation of C function to + * Instantiate mpc5xx primary exception entries. + * More detailled information can be found on the Motorola + * site and more precisely in the following book: + * + * MPC555/MPC556 User's Manual + * Motorola REF : MPC555UM/D Rev. 3, 2000 October 15 + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libcpu/powerpc/mpc8xx/exceptions/raw_exception.h: + * + * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) + * Canon Centre Recherche France. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _LIBCPU_RAW_EXCEPTION_H +#define _LIBCPU_RAW_EXCEPTION_H + +#include <libcpu/vectors.h> + +/* + * Exception Vectors as defined in the MPC555 User's Manual + */ + +#define ASM_RESET_VECTOR 0x01 +#define ASM_MACH_VECTOR 0x02 + +#define ASM_EXT_VECTOR 0x05 +#define ASM_ALIGN_VECTOR 0x06 +#define ASM_PROG_VECTOR 0x07 +#define ASM_FLOAT_VECTOR 0x08 +#define ASM_DEC_VECTOR 0x09 + +#define ASM_SYS_VECTOR 0x0C +#define ASM_TRACE_VECTOR 0x0D +#define ASM_FLOATASSIST_VECTOR 0x0E + +#define ASM_SOFTEMUL_VECTOR 0x10 + +#define ASM_IPROT_VECTOR 0x13 +#define ASM_DPROT_VECTOR 0x14 + +#define ASM_DBREAK_VECTOR 0x1C +#define ASM_IBREAK_VECTOR 0x1D +#define ASM_MEBREAK_VECTOR 0x1E +#define ASM_NMEBREAK_VECTOR 0x1F + +#define LAST_VALID_EXC ASM_NMEBREAK_VECTOR + +#ifndef ASM + +/* + * Type definition for raw exceptions. + */ + +typedef unsigned char rtems_vector; +struct __rtems_raw_except_connect_data__; +typedef unsigned char rtems_raw_except_hdl_size; + +typedef struct { + rtems_vector vector; + rtems_exception_handler_t* raw_hdl; +}rtems_raw_except_hdl; + +typedef void (*rtems_raw_except_enable) (const struct __rtems_raw_except_connect_data__*); +typedef void (*rtems_raw_except_disable) (const struct __rtems_raw_except_connect_data__*); +typedef int (*rtems_raw_except_is_enabled) (const struct __rtems_raw_except_connect_data__*); + +typedef struct __rtems_raw_except_connect_data__{ + /* + * Exception vector (As defined in the manual) + */ + rtems_vector exceptIndex; + /* + * Exception raw handler. See comment on handler properties below in function prototype. + */ + rtems_raw_except_hdl hdl; + /* + * function for enabling raw exceptions. In order to be consistent + * with the fact that the raw connexion can defined in the + * libcpu library, this library should have no knowledge of + * board specific hardware to manage exceptions and thus the + * "on" routine must enable the except at processor level only. + * + */ + rtems_raw_except_enable on; + /* + * function for disabling raw exceptions. In order to be consistent + * with the fact that the raw connexion can defined in the + * libcpu library, this library should have no knowledge of + * board specific hardware to manage exceptions and thus the + * "on" routine must disable the except both at device and PIC level. + * + */ + rtems_raw_except_disable off; + /* + * function enabling to know what exception may currently occur + */ + rtems_raw_except_is_enabled isOn; +}rtems_raw_except_connect_data; + +typedef struct { + /* + * size of all the table fields (*Tbl) described below. + */ + unsigned int exceptSize; + /* + * Default handler used when disconnecting exceptions. + */ + rtems_raw_except_connect_data defaultRawEntry; + /* + * Table containing initials/current value. + */ + rtems_raw_except_connect_data* rawExceptHdlTbl; +}rtems_raw_except_global_settings; + +/* + * C callable function enabling to set up one raw idt entry + */ +extern int mpc5xx_set_exception (const rtems_raw_except_connect_data*); + +/* + * C callable function enabling to get one current raw idt entry + */ +extern int mpc5xx_get_current_exception (rtems_raw_except_connect_data*); + +/* + * C callable function enabling to remove one current raw idt entry + */ +extern int mpc5xx_delete_exception (const rtems_raw_except_connect_data*); + +/* + * C callable function enabling to check if vector is valid + */ +extern int mpc5xx_vector_is_valid(rtems_vector vector); + +inline static void* mpc5xx_get_vector_addr(rtems_vector vector) +{ + return ((void*) (((unsigned) vector) << 8)); +} +/* + * Exception global init. + */ +extern int mpc5xx_init_exceptions (rtems_raw_except_global_settings* config); +extern int mpc5xx_get_exception_config (rtems_raw_except_global_settings** config); + +# endif /* ASM */ + +#define SIZEOF_ + +#endif diff --git a/bsps/powerpc/include/libcpu/spr.h b/bsps/powerpc/include/libcpu/spr.h new file mode 100644 index 0000000000..6c81d0ee91 --- /dev/null +++ b/bsps/powerpc/include/libcpu/spr.h @@ -0,0 +1,78 @@ +/* + * spr.h -- Access to special purpose registers. + * + * Copyright (C) 1998 Gabriel Paubert, paubert@iram.es + * + * Modified to compile in RTEMS development environment + * by Eric Valette + * + * Copyright (C) 1999 Eric Valette. valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + */ + + +#ifndef _LIBCPU_SPR_H +#define _LIBCPU_SPR_H + +#include <rtems/powerpc/registers.h> + +#define __MFSPR(reg, val) \ + __asm__ __volatile__("mfspr %0,"#reg : "=r" (val)) + +#define __MTSPR(val, reg) \ + __asm__ __volatile__("mtspr "#reg",%0" : : "r" (val)) + + +#define SPR_RW(reg) \ +static inline unsigned long _read_##reg(void) \ +{\ + unsigned long val;\ + __MFSPR(reg, val);\ + return val;\ +}\ +static inline void _write_##reg(unsigned long val)\ +{\ + __MTSPR(val,reg);\ + return;\ +} + +#define SPR_RO(reg) \ +static inline unsigned long _read_##reg(void) \ +{\ + unsigned long val;\ + __MFSPR(reg,val);\ + return val;\ +} + +static inline unsigned long _read_MSR(void) +{ + unsigned long val; + asm volatile("mfmsr %0" : "=r" (val)); + return val; +} + +static inline void _write_MSR(unsigned long val) +{ + asm volatile("mtmsr %0" : : "r" (val)); + return; +} + +static inline unsigned long _read_SR(void * va) +{ + unsigned long val; + asm volatile("mfsrin %0,%1" : "=r" (val): "r" (va)); + return val; +} + +static inline void _write_SR(unsigned long val, void * va) +{ + asm volatile("mtsrin %0,%1" : : "r"(val), "r" (va): "memory"); + return; +} + + +#endif diff --git a/bsps/powerpc/include/libcpu/stackTrace.h b/bsps/powerpc/include/libcpu/stackTrace.h new file mode 100644 index 0000000000..f73dc2eff2 --- /dev/null +++ b/bsps/powerpc/include/libcpu/stackTrace.h @@ -0,0 +1,8 @@ +#ifndef _LIBCPU_STACKTRACE_H +#define _LIBCPU_STACKTRACE_H + +void CPU_stack_take_snapshot(void **stack, int size, void *pc, void *lr, void *r1); + +void CPU_print_stack(void); + +#endif diff --git a/bsps/powerpc/include/libcpu/vectors.h b/bsps/powerpc/include/libcpu/vectors.h new file mode 100644 index 0000000000..2c8914e2a4 --- /dev/null +++ b/bsps/powerpc/include/libcpu/vectors.h @@ -0,0 +1,115 @@ +/* + * vectors.h Exception frame related contant and API. + * + * This include file describe the data structure and the functions implemented + * by rtems to handle exceptions. + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/vectors/vectors.h: + * + * CopyRight (C) 1999 valette@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ +#ifndef _LIBCPU_VECTORS_H +#define _LIBCPU_VECTORS_H + + +/* + * Size of hardware vector table. + */ +#define NUM_EXCEPTIONS 0x20 + +/* + * The callee (high level exception code written in C) + * will store the Link Registers (return address) at entry r1 + 4 !!!. + * So let room for it!!!. + */ +#define LINK_REGISTER_CALLEE_UPDATE_ROOM 4 +#define SRR0_FRAME_OFFSET 8 +#define SRR1_FRAME_OFFSET 12 +#define EXCEPTION_NUMBER_OFFSET 16 +#define EXC_CR_OFFSET 20 +#define EXC_CTR_OFFSET 24 +#define EXC_XER_OFFSET 28 +#define EXC_LR_OFFSET 32 +#define GPR0_OFFSET 36 +#define GPR1_OFFSET 40 +#define GPR2_OFFSET 44 +#define GPR3_OFFSET 48 +#define GPR4_OFFSET 52 +#define GPR5_OFFSET 56 +#define GPR6_OFFSET 60 +#define GPR7_OFFSET 64 +#define GPR8_OFFSET 68 +#define GPR9_OFFSET 72 +#define GPR10_OFFSET 76 +#define GPR11_OFFSET 80 +#define GPR12_OFFSET 84 +#define GPR13_OFFSET 88 +#define GPR14_OFFSET 92 +#define GPR15_OFFSET 96 +#define GPR16_OFFSET 100 +#define GPR17_OFFSET 104 +#define GPR18_OFFSET 108 +#define GPR19_OFFSET 112 +#define GPR20_OFFSET 116 +#define GPR21_OFFSET 120 +#define GPR22_OFFSET 124 +#define GPR23_OFFSET 128 +#define GPR24_OFFSET 132 +#define GPR25_OFFSET 136 +#define GPR26_OFFSET 140 +#define GPR27_OFFSET 144 +#define GPR28_OFFSET 148 +#define GPR29_OFFSET 152 +#define GPR30_OFFSET 156 +#define GPR31_OFFSET 160 +/* + * maintain the EABI requested 8 bytes aligment + * As SVR4 ABI requires 16, make it 16 (as some + * exception may need more registers to be processed...) + */ +#define EXCEPTION_FRAME_END 176 + +#ifndef ASM + +#include <rtems.h> + +/* + * default raw exception handlers + */ + +extern void default_exception_vector_code_prolog(void); +extern int default_exception_vector_code_prolog_size; +extern void initialize_exceptions(void); + +typedef void rtems_exception_handler_t (CPU_Exception_frame* excPtr); +/*DEBUG typedef rtems_exception_handler_t cpuExcHandlerType; */ + +/* + * Exception handler table. + * + * This table contains pointers to assembly-language exception handlers. + * The common exception prologue in vectors.S looks up an entry in this + * table and jumps to it. No return address is saved, so the handlers in + * this table must return directly to the interrupted code. + * + * On entry to an exception handler, R1 points to a new exception stack + * frame in which R3, R4, and LR have been saved. R4 holds the exception + * number. + */ +extern rtems_exception_handler_t* exception_handler_table[NUM_EXCEPTIONS]; + +/* for compatability -- XXX remove */ +typedef rtems_exception_handler_t *cpuExcHandlerType; +extern cpuExcHandlerType *globalExceptHdl; + +#endif /* ASM */ + +#endif /* _LIBCPU_VECTORS_H */ |