dev_8259.cc Source File

Back to the index.

dev_8259.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-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: Intel 8259 Programmable Interrupt Controller
29  *
30  * See the following URL for more details:
31  * http://www.nondot.org/sabre/os/files/MiscHW/8259pic.txt
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "cpu.h"
39 #include "device.h"
40 #include "devices.h"
41 #include "emul.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 
46 
47 #define DEV_8259_LENGTH 2
48 
49 /* #define DEV_8259_DEBUG */
50 
51 
53 {
54  struct pic8259_data *d = (struct pic8259_data *) extra;
55  uint64_t idata = 0, odata = 0;
56  int i;
57 
58  if (writeflag == MEM_WRITE)
59  idata = memory_readmax64(cpu, data, len);
60 
61 #ifdef DEV_8259_DEBUG
62  if (writeflag == MEM_READ)
63  fatal("[ 8259: read from 0x%x ]\n", (int)relative_addr);
64  else
65  fatal("[ 8259: write to 0x%x: 0x%x ]\n",
66  (int)relative_addr, (int)idata);
67 #endif
68 
69  switch (relative_addr) {
70  case 0x00:
71  if (writeflag == MEM_WRITE) {
72  if ((idata & 0x10) == 0x10) {
73  /* Bit 3: 0=edge, 1=level */
74  if (idata & 0x08)
75  fatal("[ 8259: TODO: Level "
76  "triggered (MCA bus) ]\n");
77  if (idata & 0x04)
78  fatal("[ 8259: WARNING: Bit 2 set ]\n");
79  /* Bit 1: 0=cascade, 1=single */
80  /* Bit 0: 1=4th init byte */
81  /* This happens on non-x86 systems:
82  if (!(idata & 0x01))
83  fatal("[ 8259: WARNING: Bit 0 NOT set!"
84  "!! ]\n"); */
85  d->init_state = 1;
86  break;
87  }
88 
89  /* TODO: Is it ok to abort init state when there
90  is a non-init command? */
91  if (d->init_state)
92  fatal("[ 8259: WARNING: Was in init-state, but"
93  " it was aborted? ]\n");
94  d->init_state = 0;
95 
96  if (idata == 0x0a) {
97  d->current_command = 0x0a;
98  } else if (idata == 0x0b) {
99  d->current_command = 0x0b;
100  } else if (idata == 0x0c) {
101  /* Put Master in Buffered Mode */
102  d->current_command = 0x0c;
103  } else if (idata == 0x20) {
104  int old_irr = d->irr;
105  /* End Of Interrupt */
106  /* TODO: in buffered mode, is this an EOI 0? */
107  d->irr &= ~d->isr;
108  d->isr = 0;
109  /* Recalculate interrupt assertions,
110  if necessary: */
111  if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) {
112  if (d->irr & ~d->ier)
113  INTERRUPT_ASSERT(d->irq);
114  else
116  }
117  } else if ((idata >= 0x21 && idata <= 0x27) ||
118  (idata >= 0x60 && idata <= 0x67) ||
119  (idata >= 0xe0 && idata <= 0xe7)) {
120  /* Specific EOI */
121  int old_irr = d->irr;
122  d->irr &= ~(1 << (idata & 7));
123  d->isr &= ~(1 << (idata & 7));
124  /* Recalc. int assertions, if necessary: */
125  if ((old_irr & ~d->ier) != (d->irr & ~d->ier)) {
126  if (d->irr & ~d->ier)
127  INTERRUPT_ASSERT(d->irq);
128  else
130  }
131  } else if (idata == 0x68) {
132  /* Set Special Mask Mode */
133  /* TODO */
134  } else if (idata >= 0xc0 && idata <= 0xc7) {
135  /* Set IRQ Priority Order */
136  /* TODO */
137  } else {
138  fatal("[ 8259: unimplemented command 0x%02x"
139  " ]\n", (int)idata);
140  cpu->running = 0;
141  }
142  } else {
143  switch (d->current_command) {
144  case 0x0a:
145  odata = d->irr;
146  break;
147  case 0x0b:
148  odata = d->isr;
149  break;
150  case 0x0c:
151  /* Buffered mode. */
152  odata = 0x00;
153  for (i=0; i<8; i++)
154  if ((d->irr >> i) & 1) {
155  odata = 0x80 | i;
156  break;
157  }
158  break;
159  default:
160  odata = 0x00;
161  for (i=0; i<8; i++)
162  if ((d->irr >> i) & 1) {
163  odata = 0x80 | i;
164  break;
165  }
166  break;
167  /*
168  * TODO: The "default" label should really do
169  * something like this:
170  *
171  * fatal("[ 8259: unimplemented command 0x%02x"
172  * " while reading ]\n", d->current_command);
173  * cpu->running = 0;
174  *
175  * but Linux seems to read from the secondary PIC
176  * in a manner which works better the way things
177  * are coded right now.
178  */
179  }
180  }
181  break;
182  case 0x01:
183  if (d->init_state > 0) {
184  if (d->init_state == 1) {
185  d->irq_base = idata & 0xf8;
186  /* This happens on non-x86 machines:
187  if (idata & 7)
188  fatal("[ 8259: WARNING! Lowest"
189  " bits in Init Cmd 1 are"
190  " non-zero! ]\n"); */
191  d->init_state = 2;
192  } else if (d->init_state == 2) {
193  /* Slave attachment. TODO */
194  d->init_state = 3;
195  } else if (d->init_state == 3) {
196  if (idata & 0x02) {
197  /* Should not be set in PCs, but
198  on CATS, for example, it is set. */
199  debug("[ 8259: WARNING! Bit 1 i"
200  "n Init Cmd 4 is set! ]\n");
201  }
202  if (!(idata & 0x01))
203  fatal("[ 8259: WARNING! Bit 0 "
204  "in Init Cmd 4 is not"
205  " set! ]\n");
206  d->init_state = 0;
207  }
208  break;
209  }
210 
211  if (writeflag == MEM_WRITE) {
212  int old_ier = d->ier;
213  d->ier = idata;
214 
215  /* Recalculate interrupt assertions,
216  if necessary: */
217  if ((d->irr & ~old_ier) != (d->irr & ~d->ier)) {
218  if (d->irr & ~d->ier)
219  INTERRUPT_ASSERT(d->irq);
220  else
222  }
223  } else {
224  odata = d->ier;
225  }
226  break;
227  default:
228  if (writeflag == MEM_WRITE) {
229  fatal("[ 8259: unimplemented write to address 0x%x"
230  " data=0x%02x ]\n", (int)relative_addr, (int)idata);
231  cpu->running = 0;
232  } else {
233  fatal("[ 8259: unimplemented read from address 0x%x "
234  "]\n", (int)relative_addr);
235  cpu->running = 0;
236  }
237  }
238 
239  if (writeflag == MEM_READ)
240  memory_writemax64(cpu, data, len, odata);
241 
242  return 1;
243 }
244 
245 
246 /*
247  * devinit_8259():
248  *
249  * Initialize an 8259 PIC. Important notes:
250  *
251  * x) Most systems use _TWO_ 8259 PICs. These should be registered
252  * as separate devices.
253  *
254  * x) The irq number specified is the number used to re-calculate
255  * CPU interrupt assertions. It is _not_ the irq number at
256  * which the PIC is connected. (That is left to machine specific
257  * code in src/machine.c.)
258  */
259 DEVINIT(8259)
260 {
261  struct pic8259_data *d;
262  char *name2;
263  size_t nlen = strlen(devinit->name) + 20;
264 
265  CHECK_ALLOCATION(d = (struct pic8259_data *) malloc(sizeof(struct pic8259_data)));
266  memset(d, 0, sizeof(struct pic8259_data));
267 
269 
270  CHECK_ALLOCATION(name2 = (char *) malloc(nlen));
271  snprintf(name2, nlen, "%s", devinit->name);
272  if ((devinit->addr & 0xfff) == 0xa0) {
273  strlcat(name2, " [secondary]", nlen);
274  d->irq_base = 8;
275  }
276 
278  devinit->addr, DEV_8259_LENGTH, dev_8259_access, d,
279  DM_DEFAULT, NULL);
280 
281  devinit->return_ptr = d;
282  return 1;
283 }
284 
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
void fatal(const char *fmt,...)
Definition: main.cc:152
#define DM_DEFAULT
Definition: memory.h:130
int init_state
Definition: devices.h:69
char * name
Definition: device.h:43
#define MEM_READ
Definition: memory.h:116
struct memory * memory
Definition: machine.h:126
uint8_t isr
Definition: devices.h:73
void * return_ptr
Definition: device.h:56
DEVICE_ACCESS(8259)
Definition: dev_8259.cc:52
struct interrupt irq
Definition: devices.h:64
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
uint8_t irr
Definition: devices.h:72
#define DEV_8259_LENGTH
Definition: dev_8259.cc:47
int irq_base
Definition: devices.h:66
u_short data
Definition: siireg.h:79
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
uint8_t running
Definition: cpu.h:353
#define MEM_WRITE
Definition: memory.h:117
Definition: device.h:40
#define debug
Definition: dev_adb.cc:57
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
Definition: cpu.h:326
struct machine * machine
Definition: device.h:41
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
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
uint8_t ier
Definition: devices.h:74
uint64_t addr
Definition: device.h:46
int current_command
Definition: devices.h:67
DEVINIT(8259)
Definition: dev_8259.cc:259
char * interrupt_path
Definition: device.h:50
#define INTERRUPT_DEASSERT(istruct)
Definition: interrupt.h:75

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13