fips_canister.c revision 296465
1/* ====================================================================
2 * Copyright (c) 2005 The OpenSSL Project. Rights for redistribution
3 * and usage in source and binary forms are granted according to the
4 * OpenSSL license.
5 */
6
7#include <stdio.h>
8#if defined(__DECC)
9# include <c_asm.h>
10# pragma __nostandard
11#endif
12
13#include "e_os.h"
14
15#if !defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
16# if    (defined(__sun) && (defined(__sparc) || defined(__sparcv9)))    || \
17        (defined(__sgi) && (defined(__mips) || defined(mips)))          || \
18        (defined(__osf__) && defined(__alpha))                          || \
19        (defined(__linux) && (defined(__arm) || defined(__arm__)))      || \
20        (defined(__i386) || defined(__i386__))                          || \
21        (defined(__x86_64) || defined(__x86_64__))                      || \
22        defined(__ANDROID__)                                            || \
23        (defined(vax) || defined(__vax__))
24#  define POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION
25# endif
26#endif
27
28#if defined(__xlC__) && __xlC__>=0x600 && (defined(_POWER) || defined(_ARCH_PPC))
29static void *instruction_pointer_xlc(void);
30# pragma mc_func instruction_pointer_xlc {\
31        "7c0802a6"      /* mflr r0  */  \
32        "48000005"      /* bl   $+4 */  \
33        "7c6802a6"      /* mflr r3  */  \
34        "7c0803a6"      /* mtlr r0  */  }
35# pragma reg_killed_by instruction_pointer_xlc gr0 gr3
36# define INSTRUCTION_POINTER_IMPLEMENTED(ret) (ret=instruction_pointer_xlc());
37#endif
38
39#ifdef FIPS_START
40# define FIPS_ref_point FIPS_text_start
41/*
42 * Some compilers put string literals into a separate segment. As we are
43 * mostly interested to hash AES tables in .rodata, we declare reference
44 * points accordingly. In case you wonder, the values are big-endian encoded
45 * variable names, just to prevent these arrays from being merged by linker.
46 */
47const unsigned int FIPS_rodata_start[] =
48    { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 };
49#else
50# define FIPS_ref_point FIPS_text_end
51const unsigned int FIPS_rodata_end[] =
52    { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b };
53#endif
54
55/*
56 * I declare reference function as static in order to avoid certain
57 * pitfalls in -dynamic linker behaviour...
58 */
59static void *instruction_pointer(void)
60{
61    void *ret = NULL;
62    /*
63     * These are ABI-neutral CPU-specific snippets. ABI-neutrality means that
64     * they are designed to work under any OS running on particular CPU,
65     * which is why you don't find any #ifdef THIS_OR_THAT_OS in this
66     * function.
67     */
68#if     defined(INSTRUCTION_POINTER_IMPLEMENTED)
69    INSTRUCTION_POINTER_IMPLEMENTED(ret);
70#elif   defined(__GNUC__) && __GNUC__>=2
71# if    defined(__alpha) || defined(__alpha__)
72#  define INSTRUCTION_POINTER_IMPLEMENTED
73    __asm __volatile("br     %0,1f\n1:":"=r"(ret));
74# elif  defined(__i386) || defined(__i386__)
75#  define INSTRUCTION_POINTER_IMPLEMENTED
76    __asm __volatile("call 1f\n1:    popl %0":"=r"(ret));
77    ret = (void *)((size_t)ret & ~3UL); /* align for better performance */
78# elif  defined(__ia64) || defined(__ia64__)
79#  define INSTRUCTION_POINTER_IMPLEMENTED
80    __asm __volatile("mov    %0=ip":"=r"(ret));
81# elif  defined(__hppa) || defined(__hppa__) || defined(__pa_risc)
82#  define INSTRUCTION_POINTER_IMPLEMENTED
83    __asm __volatile("blr    %%r0,%0\n\tnop":"=r"(ret));
84    ret = (void *)((size_t)ret & ~3UL); /* mask privilege level */
85# elif  defined(__mips) || defined(__mips__)
86#  define INSTRUCTION_POINTER_IMPLEMENTED
87    void *scratch;
88    __asm __volatile("move   %1,$31\n\t" /* save ra */
89                     "bal    .+8; nop\n\t" "move   %0,$31\n\t"
90                     /* restore ra */
91                     "move   $31,%1":"=r"(ret), "=r"(scratch));
92# elif  defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \
93        defined(__POWERPC__) || defined(_POWER) || defined(__PPC__) || \
94        defined(__PPC64__) || defined(__powerpc64__)
95#  define INSTRUCTION_POINTER_IMPLEMENTED
96    void *scratch;
97    __asm __volatile("mfspr  %1,8\n\t" /* save lr */
98                     "bl     $+4\n\t" "mfspr  %0,8\n\t" /* mflr ret */
99                     "mtspr  8,%1" /* restore lr */
100                     :"=r"(ret), "=r"(scratch));
101# elif  defined(__s390__) || defined(__s390x__)
102#  define INSTRUCTION_POINTER_IMPLEMENTED
103    __asm __volatile("bras   %0,1f\n1:":"=r"(ret));
104    ret = (void *)((size_t)ret & ~3UL);
105# elif  defined(__sparc) || defined(__sparc__) || defined(__sparcv9)
106#  define INSTRUCTION_POINTER_IMPLEMENTED
107    void *scratch;
108    __asm __volatile("mov    %%o7,%1\n\t"
109                     "call   .+8; nop\n\t"
110                     "mov    %%o7,%0\n\t"
111                     "mov    %1,%%o7":"=r"(ret), "=r"(scratch));
112# elif  defined(__x86_64) || defined(__x86_64__)
113#  define INSTRUCTION_POINTER_IMPLEMENTED
114    __asm __volatile("leaq   0(%%rip),%0":"=r"(ret));
115    ret = (void *)((size_t)ret & ~3UL); /* align for better performance */
116# endif
117#elif   defined(__DECC) && defined(__alpha)
118# define INSTRUCTION_POINTER_IMPLEMENTED
119    ret = (void *)(size_t)asm("br %v0,1f\n1:");
120#elif   defined(_MSC_VER) && defined(_M_IX86)
121# define INSTRUCTION_POINTER_IMPLEMENTED
122    void *scratch;
123    _asm {
124    call self
125            self:pop eax
126            mov scratch, eax} ret = (void *)((size_t)scratch & ~3UL);
127#endif
128    return ret;
129}
130
131/*
132 * This function returns pointer to an instruction in the vicinity of
133 * its entry point, but not outside this object module. This guarantees
134 * that sequestered code is covered...
135 */
136void *FIPS_ref_point()
137{
138#if     defined(INSTRUCTION_POINTER_IMPLEMENTED)
139    return instruction_pointer();
140    /*
141     * Below we essentially cover vendor compilers which do not support
142     * inline assembler...
143     */
144#elif   defined(_AIX)
145    struct {
146        void *ip, *gp, *env;
147    } *p = (void *)instruction_pointer;
148    return p->ip;
149#elif   defined(_HPUX_SOURCE)
150# if    defined(__hppa) || defined(__hppa__)
151    struct {
152        void *i[4];
153    } *p = (void *)FIPS_ref_point;
154
155    if (sizeof(p) == 8)         /* 64-bit */
156        return p->i[2];
157    else if ((size_t)p & 2) {
158        p = (void *)((size_t)p & ~3UL);
159        return p->i[0];
160    } else
161        return (void *)p;
162# elif  defined(__ia64) || defined(__ia64__)
163    struct {
164        unsigned long long ip, gp;
165    } *p = (void *)instruction_pointer;
166    return (void *)(size_t)p->ip;
167# endif
168#elif   (defined(__VMS) || defined(VMS)) && !(defined(vax) || defined(__vax__))
169    /* applies to both alpha and ia64 */
170    struct {
171        unsigned __int64 opaque, ip;
172    } *p = (void *)instruction_pointer;
173    return (void *)(size_t)p->ip;
174#elif   defined(__VOS__)
175    /* applies to both pa-risc and ia32 */
176    struct {
177        void *dp, *ip, *gp;
178    } *p = (void *)instruction_pointer;
179    return p->ip;
180#elif   defined(_WIN32)
181# if    defined(_WIN64) && defined(_M_IA64)
182    struct {
183        void *ip, *gp;
184    } *p = (void *)FIPS_ref_point;
185    return p->ip;
186# else
187    return (void *)FIPS_ref_point;
188# endif
189    /*
190     * In case you wonder why there is no #ifdef __linux. All Linux targets
191     * are GCC-based and therefore are covered by instruction_pointer above
192     * [well, some are covered by by the one below]...
193     */
194#elif   defined(POINTER_TO_FUNCTION_IS_POINTER_TO_1ST_INSTRUCTION)
195    return (void *)instruction_pointer;
196#else
197    return NULL;
198#endif
199}
200