summaryrefslogtreecommitdiffstats
path: root/smp.h
blob: 152068c64903fca4845427e9e10cc54e47a7a192 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/* **********************************************************
 * Copyright 2002 VMware, Inc.  All rights reserved. -- VMware Confidential
 * **********************************************************/


#ifndef _SMP_H_
#define _SMP_H_
#include "stdint.h"
#include "defs.h"
#define MAX_CPUS 16 // "16 CPUs ought to be enough for everybody."


#define FPSignature ('_' | 'M' << 8 | 'P' << 16 | '_' << 24)

typedef struct {
   uint32_t signature;   // "_MP_"
   uint32_t phys_addr;
   uint8_t  length;
   uint8_t  spec_rev;
   uint8_t  checksum;
   uint8_t  feature[5];
} floating_pointer_struct_t;

#define MPCSignature ('P' | 'C' << 8 | 'M' << 16 | 'P' << 24)
typedef struct {
   uint32_t signature;   // "PCMP"
   uint16_t length;
   uint8_t  spec_rev;
   uint8_t  checksum;
   char   oem[8];
   char   productid[12];
   uint32_t oem_ptr;
   uint16_t oem_size;
   uint16_t oem_count;
   uint32_t lapic_addr;
   uint32_t reserved;
} mp_config_table_header_t;

/* Followed by entries */

#define MP_PROCESSOR    0
#define MP_BUS          1
#define MP_IOAPIC       2
#define MP_INTSRC       3
#define MP_LINTSRC      4

typedef struct {
   uint8_t type;          /* MP_PROCESSOR */
   uint8_t apic_id;       /* Local APIC number */
   uint8_t apic_ver;      /* Its versions */
   uint8_t cpu_flag;
#define CPU_ENABLED             1       /* Processor is available */
#define CPU_BOOTPROCESSOR       2       /* Processor is the BP */
   uint32_t cpu_signature;           
#define CPU_STEPPING_MASK 0x0F
#define CPU_MODEL_MASK  0xF0
#define CPU_FAMILY_MASK 0xF00
   uint32_t featureflag;  /* CPUID feature value */
   uint32_t reserved[2];
} mp_processor_entry_t;


typedef struct {
   uint8_t type;   // has value MP_BUS
   uint8_t busid;
   char  bustype[6];
} mp_bus_entry_t;

#define BUSTYPE_EISA    "EISA"
#define BUSTYPE_ISA     "ISA"
#define BUSTYPE_INTERN  "INTERN"
#define BUSTYPE_MCA     "MCA"
#define BUSTYPE_VL      "VL"
#define BUSTYPE_PCI     "PCI"
#define BUSTYPE_PCMCIA  "PCMCIA"

/* We don't understand the others */

typedef struct {
   uint8_t  type;   // set to MP_IOAPIC
   uint8_t  apicid;
   uint8_t  apicver;
   uint8_t  flags;
#define MPC_APIC_USABLE         0x01
   uint32_t apicaddr;
} mp_io_apic_entry_t;


typedef struct {
   uint8_t  type;
   uint8_t  irqtype;
   uint16_t irqflag;
   uint8_t  srcbus;
   uint8_t  srcbusirq;
   uint8_t  dstapic;
   uint8_t  dstirq;
} mp_interrupt_entry_t;

#define MP_INT_VECTORED         0
#define MP_INT_NMI              1
#define MP_INT_SMI              2
#define MP_INT_EXTINT           3

#define MP_IRQDIR_DEFAULT       0
#define MP_IRQDIR_HIGH          1
#define MP_IRQDIR_LOW           3


typedef struct {
   uint8_t  type;
   uint8_t  irqtype;
   uint16_t irqflag;
   uint8_t  srcbusid;
   uint8_t  srcbusirq;
   uint8_t  destapic;     
#define MP_APIC_ALL     0xFF
   uint8_t  destapiclint;
} mp_local_interrupt_entry_t;

/* APIC definitions */
/*
 * APIC registers
 */
#define APICR_ID         0x02
#define APICR_ESR        0x28
#define APICR_ICRLO      0x30
#define APICR_ICRHI      0x31

/* APIC destination shorthands */
#define APIC_DEST_DEST        0
#define APIC_DEST_LOCAL       1
#define APIC_DEST_ALL_INC     2
#define APIC_DEST_ALL_EXC     3

/* APIC IPI Command Register format */
#define APIC_ICRHI_RESERVED		0x00ffffff
#define APIC_ICRHI_DEST_MASK		0xff000000
#define APIC_ICRHI_DEST_OFFSET		24

#define APIC_ICRLO_RESERVED		0xfff32000
#define APIC_ICRLO_DEST_MASK		0x000c0000
#define APIC_ICRLO_DEST_OFFSET		18
#define APIC_ICRLO_TRIGGER_MASK		0x00008000
#define APIC_ICRLO_TRIGGER_OFFSET	15
#define APIC_ICRLO_LEVEL_MASK		0x00004000
#define APIC_ICRLO_LEVEL_OFFSET		14
#define APIC_ICRLO_STATUS_MASK		0x00001000
#define APIC_ICRLO_STATUS_OFFSET	12
#define APIC_ICRLO_DESTMODE_MASK	0x00000800
#define APIC_ICRLO_DESTMODE_OFFSET	11
#define APIC_ICRLO_DELMODE_MASK		0x00000700
#define APIC_ICRLO_DELMODE_OFFSET	8
#define APIC_ICRLO_VECTOR_MASK		0x000000ff
#define APIC_ICRLO_VECTOR_OFFSET	0

/* APIC trigger types (edge/level) */
#define APIC_TRIGGER_EDGE     0
#define APIC_TRIGGER_LEVEL    1

/* APIC delivery modes */
#define APIC_DELMODE_FIXED    0
#define APIC_DELMODE_LOWEST   1
#define APIC_DELMODE_SMI      2
#define APIC_DELMODE_NMI      4
#define APIC_DELMODE_INIT     5
#define APIC_DELMODE_STARTUP  6
#define APIC_DELMODE_EXTINT   7
typedef uint32_t apic_register_t[4];

extern volatile apic_register_t *APIC;

unsigned smp_num_cpus();
unsigned smp_my_cpu_num();

void smp_init_bsp(void);
void smp_init_aps(void);

void smp_boot_ap(unsigned cpu_num);
void smp_ap_booted(unsigned cpu_num);

static inline void
__GET_CPUID(int ax, uint32_t *regs)
{
   __asm__ __volatile__("\t"
   	/* save ebx in case -fPIC is being used */
      "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
      : "=a" (regs[0]), "=D" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
      : "a" (ax)
      : "memory"
   );
}

#define GET_CPUID(_ax,_bx,_cx,_dx) { \
   uint32_t regs[4];                   \
   __GET_CPUID(_ax,regs);            \
   _ax = regs[0];                    \
   _bx = regs[1];                    \
   _cx = regs[2];                    \
   _dx = regs[3];                    \
}

/*
 * Checked against the Intel manual and GCC --hpreg
 *
 * volatile because the tsc always changes without the compiler knowing it.
 */
static inline uint64_t
RDTSC(void)
{
   uint64_t tim;

   __asm__ __volatile__(
      "rdtsc"
      : "=A" (tim)
   );

   return tim;
}

static inline uint64_t __GET_MSR(int cx)
{
   uint64_t msr;

   __asm__ __volatile__(
      "rdmsr"
      : "=A" (msr)
      : "c" (cx)
   );

   return msr;
}

#define __GCC_OUT(s, s2, port, val) do { \
   __asm__(                              \
      "out" #s " %" #s2 "1, %w0"         \
      :                                  \
      : "Nd" (port), "a" (val)           \
   );                                    \
} while (0)
#define OUTB(port, val) __GCC_OUT(b, b, port, val)

typedef struct {
        unsigned int slock;
} spinlock_t;

static inline void spin_lock(volatile spinlock_t *lock)
{
        asm volatile("\n1:\t"
                     " ; lock;decb %0\n\t"
                     "jns 3f\n"
                     "2:\t"
                     "rep;nop\n\t"
                     "cmpb $0,%0\n\t"
                     "jle 2b\n\t"
                     "jmp 1b\n"
                     "3:\n\t"
                     : "+m" (lock->slock) : : "memory");
}
static inline void spin_unlock(volatile spinlock_t *lock)
{
        asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");
}


#endif /* _SMP_H_ */