linux-old/include/asm-parisc/processor.h
<<
>>
Prefs
   1/*
   2 * include/asm-parisc/processor.h
   3 *
   4 * Copyright (C) 1994 Linus Torvalds
   5 * Copyright (C) 2001 Grant Grundler
   6 */
   7
   8#ifndef __ASM_PARISC_PROCESSOR_H
   9#define __ASM_PARISC_PROCESSOR_H
  10
  11#ifndef __ASSEMBLY__
  12#include <linux/config.h>
  13#include <linux/threads.h>
  14
  15#include <asm/hardware.h>
  16#include <asm/page.h>
  17#include <asm/pdc.h>
  18#include <asm/ptrace.h>
  19#include <asm/types.h>
  20#include <asm/system.h>
  21#ifdef CONFIG_SMP
  22#include <asm/spinlock_t.h>
  23#endif
  24#endif /* __ASSEMBLY__ */
  25
  26/*
  27 * Default implementation of macro that returns current
  28 * instruction pointer ("program counter").
  29 */
  30
  31/* We cannot use MFIA as it was added for PA2.0 - prumpf
  32
  33   At one point there were no "0f/0b" type local symbols in gas for
  34   PA-RISC.  This is no longer true, but this still seems like the
  35   nicest way to implement this. */
  36
  37#define current_text_addr() ({ void *pc; __asm__("\n\tblr 0,%0\n\tnop":"=r" (pc)); pc; })
  38
  39#define TASK_SIZE               (current->thread.task_size)
  40#define DEFAULT_TASK_SIZE       (0xFFF00000UL)
  41
  42#define TASK_UNMAPPED_BASE      (current->thread.map_base)
  43#define DEFAULT_MAP_BASE        (0x40000000UL)
  44
  45#ifndef __ASSEMBLY__
  46
  47/*
  48** Data detected about CPUs at boot time which is the same for all CPU's.
  49** HP boxes are SMP - ie identical processors.
  50**
  51** FIXME: some CPU rev info may be processor specific...
  52*/
  53struct system_cpuinfo_parisc {
  54        unsigned int    cpu_count;
  55        unsigned int    cpu_hz;
  56        unsigned int    hversion;
  57        unsigned int    sversion;
  58        enum cpu_type   cpu_type;
  59
  60        struct {
  61                struct pdc_model model;
  62                unsigned long versions;
  63                unsigned long cpuid;
  64                unsigned long capabilities;
  65                char   sys_model_name[81]; /* PDC-ROM returnes this model name */
  66        } pdc;
  67
  68        char            *cpu_name;      /* e.g. "PA7300LC (PCX-L2)" */
  69        char            *family_name;   /* e.g. "1.1e" */
  70};
  71
  72
  73/*
  74** Per CPU data structure - ie varies per CPU.
  75*/
  76struct cpuinfo_parisc {
  77
  78        unsigned long it_value;     /* Interval Timer value at last timer Intr */
  79        unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
  80        unsigned long irq_count;    /* number of IRQ's since boot */
  81        unsigned long irq_max_cr16; /* longest time to handle a single IRQ */
  82        unsigned long cpuid;        /* aka slot_number or set to NO_PROC_ID */
  83        unsigned long hpa;          /* Host Physical address */
  84        unsigned long txn_addr;     /* MMIO addr of EIR or id_eid */
  85#ifdef CONFIG_SMP
  86        spinlock_t lock;            /* synchronization for ipi's */
  87        unsigned long pending_ipi;  /* bitmap of type ipi_message_type */
  88        unsigned long ipi_count;    /* number ipi Interrupts */
  89#endif
  90        unsigned long bh_count;     /* number of times bh was invoked */
  91        unsigned long prof_counter; /* per CPU profiling support */
  92        unsigned long prof_multiplier;  /* per CPU profiling support */
  93        unsigned long fp_rev;
  94        unsigned long fp_model;
  95        unsigned int state;
  96        struct parisc_device *dev;
  97};
  98
  99extern struct system_cpuinfo_parisc boot_cpu_data;
 100extern struct cpuinfo_parisc cpu_data[NR_CPUS];
 101#define current_cpu_data cpu_data[smp_processor_id()]
 102
 103#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
 104
 105#ifdef CONFIG_EISA
 106extern int EISA_bus;
 107#else
 108#define EISA_bus 0
 109#endif
 110
 111#define MCA_bus 0
 112#define MCA_bus__is_a_macro /* for versions in ksyms.c */
 113
 114typedef struct {
 115        int seg;  
 116} mm_segment_t;
 117
 118struct thread_struct {
 119        struct pt_regs regs;
 120        unsigned long  task_size;
 121        unsigned long  map_base;
 122        unsigned long  flags;
 123}; 
 124
 125/* Thread struct flags. */
 126#define PARISC_KERNEL_DEATH     (1UL << 31)     /* see die_if_kernel()... */
 127
 128#define INIT_THREAD { \
 129        regs:   {       gr: { 0, }, \
 130                        fr: { 0, }, \
 131                        sr: { 0, }, \
 132                        iasq: { 0, }, \
 133                        iaoq: { 0, }, \
 134                        cr27: 0, \
 135                }, \
 136        task_size:      DEFAULT_TASK_SIZE, \
 137        map_base:       DEFAULT_MAP_BASE, \
 138        flags:          0 \
 139        }
 140
 141/*
 142 * Return saved PC of a blocked thread.  This is used by ps mostly.
 143 */
 144
 145static inline unsigned long thread_saved_pc(struct thread_struct *t)
 146{
 147        return 0xabcdef;
 148}
 149
 150/*
 151 * Start user thread in another space.
 152 *
 153 * Note that we set both the iaoq and r31 to the new pc. When
 154 * the kernel initially calls execve it will return through an
 155 * rfi path that will use the values in the iaoq. The execve
 156 * syscall path will return through the gateway page, and
 157 * that uses r31 to branch to.
 158 *
 159 * For ELF we clear r23, because the dynamic linker uses it to pass
 160 * the address of the finalizer function.
 161 *
 162 * We also initialize sr3 to an illegal value (illegal for our
 163 * implementation, not for the architecture).
 164 */
 165
 166#define start_thread_som(regs, new_pc, new_sp) do {     \
 167        unsigned long *sp = (unsigned long *)new_sp;    \
 168        __u32 spaceid = (__u32)current->mm->context;    \
 169        unsigned long pc = (unsigned long)new_pc;       \
 170        /* offset pc for priv. level */                 \
 171        pc |= 3;                                        \
 172                                                        \
 173        set_fs(USER_DS);                                \
 174        regs->iasq[0] = spaceid;                        \
 175        regs->iasq[1] = spaceid;                        \
 176        regs->iaoq[0] = pc;                             \
 177        regs->iaoq[1] = pc + 4;                         \
 178        regs->sr[2] = LINUX_GATEWAY_SPACE;              \
 179        regs->sr[3] = 0xffff;                           \
 180        regs->sr[4] = spaceid;                          \
 181        regs->sr[5] = spaceid;                          \
 182        regs->sr[6] = spaceid;                          \
 183        regs->sr[7] = spaceid;                          \
 184        regs->gr[ 0] = USER_PSW;                        \
 185        regs->gr[30] = ((new_sp)+63)&~63;               \
 186        regs->gr[31] = pc;                              \
 187                                                        \
 188        get_user(regs->gr[26],&sp[0]);                  \
 189        get_user(regs->gr[25],&sp[-1]);                 \
 190        get_user(regs->gr[24],&sp[-2]);                 \
 191        get_user(regs->gr[23],&sp[-3]);                 \
 192} while(0)
 193
 194/* The ELF abi wants things done a "wee bit" differently than
 195 * som does.  Supporting this behavior here avoids
 196 * having our own version of create_elf_tables.
 197 *
 198 * Oh, and yes, that is not a typo, we are really passing argc in r25
 199 * and argv in r24 (rather than r26 and r25).  This is because that's
 200 * where __libc_start_main wants them.
 201 *
 202 * Duplicated from dl-machine.h for the benefit of readers:
 203 *
 204 *  Our initial stack layout is rather different from everyone else's
 205 *  due to the unique PA-RISC ABI.  As far as I know it looks like
 206 *  this:
 207
 208   -----------------------------------  (user startup code creates this frame)
 209   |         32 bytes of magic       |
 210   |---------------------------------|
 211   | 32 bytes argument/sp save area  |
 212   |---------------------------------| (bprm->p)
 213   |        ELF auxiliary info       |
 214   |         (up to 28 words)        |
 215   |---------------------------------|
 216   |               NULL              |
 217   |---------------------------------|
 218   |       Environment pointers      |
 219   |---------------------------------|
 220   |               NULL              |
 221   |---------------------------------|
 222   |        Argument pointers        |
 223   |---------------------------------| <- argv
 224   |          argc (1 word)          |
 225   |---------------------------------| <- bprm->exec (HACK!)
 226   |         N bytes of slack        |
 227   |---------------------------------|
 228   |    filename passed to execve    |
 229   |---------------------------------| (mm->env_end)
 230   |           env strings           |
 231   |---------------------------------| (mm->env_start, mm->arg_end)
 232   |           arg strings           |
 233   |---------------------------------|
 234   | additional faked arg strings if |
 235   | we're invoked via binfmt_script |
 236   |---------------------------------| (mm->arg_start)
 237   stack base is at TASK_SIZE - rlim_max.
 238
 239on downward growing arches, it looks like this:
 240   stack base at TASK_SIZE
 241   | filename passed to execve
 242   | env strings
 243   | arg strings
 244   | faked arg strings
 245   | slack
 246   | ELF
 247   | envps
 248   | argvs
 249   | argc
 250
 251 *  The pleasant part of this is that if we need to skip arguments we
 252 *  can just decrement argc and move argv, because the stack pointer
 253 *  is utterly unrelated to the location of the environment and
 254 *  argument vectors.
 255 *
 256 * Note that the S/390 people took the easy way out and hacked their
 257 * GCC to make the stack grow downwards.
 258 */
 259
 260#define start_thread(regs, new_pc, new_sp) do {         \
 261        elf_addr_t *sp = (elf_addr_t *)new_sp;          \
 262        __u32 spaceid = (__u32)current->mm->context;    \
 263        elf_addr_t pc = (elf_addr_t)new_pc | 3;         \
 264        elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1;      \
 265                                                        \
 266        set_fs(USER_DS);                                \
 267        regs->iasq[0] = spaceid;                        \
 268        regs->iasq[1] = spaceid;                        \
 269        regs->iaoq[0] = pc;                             \
 270        regs->iaoq[1] = pc + 4;                         \
 271        regs->sr[2] = LINUX_GATEWAY_SPACE;              \
 272        regs->sr[3] = 0xffff;                           \
 273        regs->sr[4] = spaceid;                          \
 274        regs->sr[5] = spaceid;                          \
 275        regs->sr[6] = spaceid;                          \
 276        regs->sr[7] = spaceid;                          \
 277        regs->gr[ 0] = USER_PSW;                        \
 278        regs->fr[ 0] = 0LL;                             \
 279        regs->fr[ 1] = 0LL;                             \
 280        regs->fr[ 2] = 0LL;                             \
 281        regs->fr[ 3] = 0LL;                             \
 282        regs->gr[30] = ((unsigned long)sp + 63) &~ 63;  \
 283        regs->gr[31] = pc;                              \
 284                                                        \
 285        get_user(regs->gr[25], (argv - 1));             \
 286        regs->gr[24] = (long) argv;                     \
 287        regs->gr[23] = 0;                               \
 288} while(0)
 289
 290struct task_struct;
 291struct mm_struct;
 292
 293/* Free all resources held by a thread. */
 294extern void release_thread(struct task_struct *);
 295extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 296
 297extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
 298
 299#define copy_segments(tsk, mm)  do { \
 300                                        if (tsk->personality == PER_HPUX)  \
 301                                            map_hpux_gateway_page(tsk,mm); \
 302                                } while (0)
 303#define release_segments(mm)    do { } while (0)
 304
 305static inline unsigned long get_wchan(struct task_struct *p)
 306{
 307        return 0xdeadbeef; /* XXX */
 308}
 309
 310#define KSTK_EIP(tsk)   ((tsk)->thread.regs.iaoq[0])
 311#define KSTK_ESP(tsk)   ((tsk)->thread.regs.gr[30])
 312
 313#endif /* __ASSEMBLY__ */
 314
 315#ifdef  CONFIG_PA20
 316#define ARCH_HAS_PREFETCH
 317extern inline void prefetch(const void *addr)
 318{
 319        __asm__("ldw 0(%0), %%r0" : : "r" (addr));
 320}
 321
 322#define ARCH_HAS_PREFETCHW
 323extern inline void prefetchw(const void *addr)
 324{
 325        __asm__("ldd 0(%0), %%r0" : : "r" (addr));
 326}
 327#endif
 328
 329/* Be sure to hunt all references to this down when you change the size of
 330 * the kernel stack */
 331
 332#define THREAD_SIZE     (4*PAGE_SIZE)
 333
 334#define alloc_task_struct() \
 335        ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
 336#define free_task_struct(p)     free_pages((unsigned long)(p),2)
 337#define get_task_struct(tsk)    atomic_inc(&virt_to_page(tsk)->count)
 338
 339#define init_task (init_task_union.task) 
 340#define init_stack (init_task_union.stack)
 341
 342#define cpu_relax()     do { } while (0)
 343
 344#endif /* __ASM_PARISC_PROCESSOR_H */
 345
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.