dev_mp.cc Source File

Back to the index.

dev_mp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * COMMENT: Generic Multi-processor controller for the test machines
29  *
30  * This is a fake multiprocessor (MP) device. It can be useful for
31  * theoretical experiments, but probably bares no resemblance to any
32  * multiprocessor controller used in any real machine.
33  *
34  * NOTE: The devinit irq string should be the part _after_ "cpu[%i].".
35  * For MIPS, it will be MIPS_IPI_INT.
36  */
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "cpu.h"
43 #include "device.h"
44 #include "machine.h"
45 #include "interrupt.h"
46 #include "memory.h"
47 #include "misc.h"
48 
49 #include "testmachine/dev_mp.h"
50 
51 
52 struct mp_data {
53  struct cpu **cpus;
54  uint64_t startup_addr;
55  uint64_t stack_addr;
56  uint64_t pause_addr;
57 
58  /* Each CPU has an array of pending ipis. */
60  int **ipi;
61 
62  /* Connections to all CPUs' IPI pins: */
63  struct interrupt *ipi_irq;
64 };
65 
66 
67 extern int single_step;
68 
69 
71 {
72  struct mp_data *d = (struct mp_data *) extra;
73  int i, which_cpu;
74  uint64_t idata = 0, odata = 0;
75 
76  if (writeflag == MEM_WRITE)
77  idata = memory_readmax64(cpu, data, len);
78 
79  /*
80  * NOTE: It is up to the user of this device to read or write
81  * correct addresses. (A write to NCPUS is pretty useless,
82  * for example.)
83  */
84 
85  switch (relative_addr) {
86 
87  case DEV_MP_WHOAMI:
88  odata = cpu->cpu_id;
89  break;
90 
91  case DEV_MP_NCPUS:
92  odata = cpu->machine->ncpus;
93  break;
94 
95  case DEV_MP_STARTUPCPU:
96  which_cpu = idata;
97  d->cpus[which_cpu]->pc = d->startup_addr;
98  switch (cpu->machine->arch) {
99  case ARCH_MIPS:
100  d->cpus[which_cpu]->cd.mips.gpr[MIPS_GPR_SP] =
101  d->stack_addr;
102  break;
103  case ARCH_PPC:
104  d->cpus[which_cpu]->cd.ppc.gpr[1] = d->stack_addr;
105  break;
106  default:
107  fatal("dev_mp(): DEV_MP_STARTUPCPU: not for this"
108  " arch yet!\n");
109  exit(1);
110  }
111  d->cpus[which_cpu]->running = 1;
112  /* debug("[ dev_mp: starting up cpu%i at 0x%llx ]\n",
113  which_cpu, (long long)d->startup_addr); */
114  break;
115 
116  case DEV_MP_STARTUPADDR:
117  if (len==4 && (idata >> 32) == 0 && (idata & 0x80000000ULL))
118  idata |= 0xffffffff00000000ULL;
119  d->startup_addr = idata;
120  break;
121 
122  case DEV_MP_PAUSE_ADDR:
123  d->pause_addr = idata;
124  break;
125 
126  case DEV_MP_PAUSE_CPU:
127  /* Pause all cpus except a specific CPU: */
128  which_cpu = idata;
129 
130  for (i=0; i<cpu->machine->ncpus; i++)
131  if (i != which_cpu)
132  d->cpus[i]->running = 0;
133  break;
134 
135  case DEV_MP_UNPAUSE_CPU:
136  /* Unpause a specific CPU: */
137  which_cpu = idata;
138 
139  if (which_cpu >= 0 && which_cpu <cpu->machine->ncpus)
140  d->cpus[which_cpu]->running = 1;
141  break;
142 
143  case DEV_MP_STARTUPSTACK:
144  if (len == 4 && (idata >> 32) == 0 && (idata & 0x80000000ULL))
145  idata |= 0xffffffff00000000ULL;
146  d->stack_addr = idata;
147  break;
148 
150  /*
151  * Return (up to) 64 bits of "hardware random":
152  *
153  * NOTE: Remember that random() is (usually) 31 bits of
154  * random data, _NOT_ 32, hence this construction.
155  */
156  odata = random();
157  odata = (odata << 31) ^ random();
158  odata = (odata << 31) ^ random();
159  break;
160 
161  case DEV_MP_MEMORY:
162  /*
163  * Return the number of bytes of memory in the system.
164  *
165  * (It is assumed to be located at physical address 0.
166  * It is actually located at machine->memory_offset_in_mb
167  * but that is only used for SGI emulation so far.)
168  */
169  odata = cpu->machine->physical_ram_in_mb * 1048576ULL;
170  break;
171 
172  case DEV_MP_IPI_ONE:
173  case DEV_MP_IPI_MANY:
174  /*
175  * idata should be of the form:
176  *
177  * (IPI_nr << 16) | cpu_id
178  *
179  * This will send an Inter-processor interrupt to a specific
180  * CPU. (DEV_MP_IPI_MANY sends to all _except_ the specific
181  * CPU.)
182  *
183  * Sending an IPI means adding the IPI last in the list of
184  * pending IPIs, and asserting the IPI "pin".
185  */
186  which_cpu = (idata & 0xffff);
187  for (i=0; i<cpu->machine->ncpus; i++) {
188  int send_it = 0;
189  if (relative_addr == DEV_MP_IPI_ONE && i == which_cpu)
190  send_it = 1;
191  if (relative_addr == DEV_MP_IPI_MANY && i != which_cpu)
192  send_it = 1;
193  if (send_it) {
194  d->n_pending_ipis[i] ++;
195  CHECK_ALLOCATION(d->ipi[i] = (int *) realloc(d->ipi[i],
196  d->n_pending_ipis[i] * sizeof(int)));
197 
198  /* Add the IPI last in the array: */
199  d->ipi[i][d->n_pending_ipis[i] - 1] =
200  idata >> 16;
201 
202  INTERRUPT_ASSERT(d->ipi_irq[i]);
203  }
204  }
205  break;
206 
207  case DEV_MP_IPI_READ:
208  /*
209  * If the current CPU has any IPIs pending, accessing this
210  * address reads the IPI value. (Writing to this address
211  * discards _all_ pending IPIs.) If there is no pending
212  * IPI, then 0 is returned. Usage of the value 0 for real
213  * IPIs should thus be avoided.
214  */
215  if (writeflag == MEM_WRITE) {
216  d->n_pending_ipis[cpu->cpu_id] = 0;
217  }
218  odata = 0;
219  if (d->n_pending_ipis[cpu->cpu_id] > 0) {
220  odata = d->ipi[cpu->cpu_id][0];
221  if (d->n_pending_ipis[cpu->cpu_id]-- > 1)
222  memmove(&d->ipi[cpu->cpu_id][0],
223  &d->ipi[cpu->cpu_id][1],
224  d->n_pending_ipis[cpu->cpu_id]);
225  }
226 
227  /* Deassert the interrupt, if there are no pending IPIs: */
228  if (d->n_pending_ipis[cpu->cpu_id] == 0)
230  break;
231 
232  case DEV_MP_NCYCLES:
233  /*
234  * Return _approximately_ the number of cycles executed
235  * on this CPU.
236  *
237  * (This value is not updated for each instruction.)
238  */
239  odata = cpu->ninstrs;
240  break;
241 
242  default:
243  fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",
244  relative_addr);
245  }
246 
247  if (writeflag == MEM_READ)
248  memory_writemax64(cpu, data, len, odata);
249 
250  return 1;
251 }
252 
253 
255 {
256  struct mp_data *d;
257  int n, i;
258 
259  CHECK_ALLOCATION(d = (struct mp_data *) malloc(sizeof(struct mp_data)));
260  memset(d, 0, sizeof(struct mp_data));
261 
262  d->cpus = devinit->machine->cpus;
265 
266  n = devinit->machine->ncpus;
267 
268  /* Connect to all CPUs' IPI pins: */
269  CHECK_ALLOCATION(d->ipi_irq = (struct interrupt *)
270  malloc(n * sizeof(struct interrupt)));
271 
272  for (i=0; i<n; i++) {
273  char tmpstr[200];
274  snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%s",
276  INTERRUPT_CONNECT(tmpstr, d->ipi_irq[i]);
277  }
278 
279  CHECK_ALLOCATION(d->n_pending_ipis = (int *) malloc(n * sizeof(int)));
280  memset(d->n_pending_ipis, 0, sizeof(int) * n);
281 
282  CHECK_ALLOCATION(d->ipi = (int **) malloc(n * sizeof(int *)));
283  memset(d->ipi, 0, sizeof(int *) * n);
284 
286  devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, DM_DEFAULT, NULL);
287 
288  return 1;
289 }
290 
data
u_short data
Definition: siireg.h:79
cpu::ninstrs
int64_t ninstrs
Definition: cpu.h:340
ARCH_PPC
#define ARCH_PPC
Definition: machine.h:204
INTERRUPT_CONNECT
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
cpu::cpu_id
int cpu_id
Definition: cpu.h:359
INTERRUPT_ASSERT
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
cpu::running
uint8_t running
Definition: cpu.h:353
DEV_MP_NCYCLES
#define DEV_MP_NCYCLES
Definition: dev_mp.h:43
DEV_MP_NCPUS
#define DEV_MP_NCPUS
Definition: dev_mp.h:31
single_step
int single_step
Definition: debugger.cc:68
machine::cpus
struct cpu ** cpus
Definition: machine.h:140
machine::physical_ram_in_mb
int physical_ram_in_mb
Definition: machine.h:147
DEV_MP_UNPAUSE_CPU
#define DEV_MP_UNPAUSE_CPU
Definition: dev_mp.h:36
devinit::addr
uint64_t addr
Definition: device.h:46
memory_device_register
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
MEM_READ
#define MEM_READ
Definition: memory.h:116
DEV_MP_PAUSE_CPU
#define DEV_MP_PAUSE_CPU
Definition: dev_mp.h:35
DM_DEFAULT
#define DM_DEFAULT
Definition: memory.h:130
devinit::machine
struct machine * machine
Definition: device.h:41
cpu::mips
struct mips_cpu mips
Definition: cpu.h:443
DEV_MP_IPI_READ
#define DEV_MP_IPI_READ
Definition: dev_mp.h:42
device.h
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
devinit::interrupt_path
char * interrupt_path
Definition: device.h:50
ARCH_MIPS
#define ARCH_MIPS
Definition: machine.h:203
interrupt.h
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
misc.h
DEV_MP_HARDWARE_RANDOM
#define DEV_MP_HARDWARE_RANDOM
Definition: dev_mp.h:38
memory_readmax64
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
cpu::cd
union cpu::@1 cd
DEV_MP_STARTUPCPU
#define DEV_MP_STARTUPCPU
Definition: dev_mp.h:32
DEVINIT
DEVINIT(mp)
Definition: dev_mp.cc:254
machine.h
machine
Definition: machine.h:97
MIPS_GPR_SP
#define MIPS_GPR_SP
Definition: MIPS_CPUComponent.h:102
devinit::name
char * name
Definition: device.h:43
dev_mp.h
DEV_MP_PAUSE_ADDR
#define DEV_MP_PAUSE_ADDR
Definition: dev_mp.h:34
devinit
Definition: device.h:40
DEV_MP_WHOAMI
#define DEV_MP_WHOAMI
Definition: dev_mp.h:30
cpu.h
machine::path
char * path
Definition: machine.h:108
cpu::ppc
struct ppc_cpu ppc
Definition: cpu.h:444
machine::memory
struct memory * memory
Definition: machine.h:126
mp_data::cpus
struct cpu ** cpus
Definition: dev_mp.cc:53
cpu::machine
struct machine * machine
Definition: cpu.h:328
mp_data::stack_addr
uint64_t stack_addr
Definition: dev_mp.cc:55
mp_data::ipi
int ** ipi
Definition: dev_mp.cc:60
DEV_MP_IPI_ONE
#define DEV_MP_IPI_ONE
Definition: dev_mp.h:40
INITIAL_STACK_POINTER
#define INITIAL_STACK_POINTER
Definition: cpu_mips.h:69
mips_cpu::gpr
uint64_t gpr[N_MIPS_GPRS]
Definition: cpu_mips.h:209
INTERRUPT_DEASSERT
#define INTERRUPT_DEASSERT(istruct)
Definition: interrupt.h:75
DEV_MP_STARTUPSTACK
#define DEV_MP_STARTUPSTACK
Definition: dev_mp.h:37
ppc_cpu::gpr
uint64_t gpr[PPC_NGPRS]
Definition: cpu_ppc.h:124
mp_data::n_pending_ipis
int * n_pending_ipis
Definition: dev_mp.cc:59
mp_data::pause_addr
uint64_t pause_addr
Definition: dev_mp.cc:56
interrupt
Definition: interrupt.h:36
mp_data
Definition: dev_mp.cc:52
memory_writemax64
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
DEVICE_ACCESS
DEVICE_ACCESS(mp)
Definition: dev_mp.cc:70
DEV_MP_MEMORY
#define DEV_MP_MEMORY
Definition: dev_mp.h:39
cpu
Definition: cpu.h:326
INITIAL_PC
#define INITIAL_PC
Definition: cpu_mips.h:68
mp_data::startup_addr
uint64_t startup_addr
Definition: dev_mp.cc:54
mp_data::ipi_irq
struct interrupt * ipi_irq
Definition: dev_mp.cc:63
DEV_MP_IPI_MANY
#define DEV_MP_IPI_MANY
Definition: dev_mp.h:41
DEV_MP_STARTUPADDR
#define DEV_MP_STARTUPADDR
Definition: dev_mp.h:33
machine::arch
int arch
Definition: machine.h:110
cpu::pc
uint64_t pc
Definition: cpu.h:383
DEV_MP_LENGTH
#define DEV_MP_LENGTH
Definition: dev_mp.h:23
memory.h
machine::ncpus
int ncpus
Definition: machine.h:139
CHECK_ALLOCATION
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239

Generated on Tue Mar 24 2020 14:04:48 for GXemul by doxygen 1.8.17