gem5  v22.1.0.0
i8042.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * 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  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "dev/x86/i8042.hh"
30 
31 #include "base/bitunion.hh"
32 #include "base/trace.hh"
33 #include "debug/I8042.hh"
34 #include "mem/packet.hh"
35 #include "mem/packet_access.hh"
36 
42 namespace gem5
43 {
44 
45 // The 8042 has a whopping 32 bytes of internal RAM.
46 const uint8_t RamSize = 32;
47 const uint8_t NumOutputBits = 14;
48 
49 
51  : PioDevice(p), latency(p.pio_latency),
52  dataPort(p.data_port), commandPort(p.command_port),
53  mouse(p.mouse), keyboard(p.keyboard)
54 {
55  fatal_if(!mouse, "The i8042 model requires a mouse instance");
56  fatal_if(!keyboard, "The i8042 model requires a keyboard instance");
57 
58  statusReg.keyboardUnlocked = 1;
59 
60  commandByte.convertScanCodes = 1;
61  commandByte.disableMouse = 1;
62  commandByte.disableKeyboard = 1;
63 
64  for (int i = 0; i < p.port_keyboard_int_pin_connection_count; i++) {
65  keyboardIntPin.push_back(new IntSourcePin<I8042>(
66  csprintf("%s.keyboard_int_pin[%d]", name(), i), i, this));
67  }
68  for (int i = 0; i < p.port_mouse_int_pin_connection_count; i++) {
69  mouseIntPin.push_back(new IntSourcePin<I8042>(
70  csprintf("%s.mouse_int_pin[%d]", name(), i), i, this));
71  }
72 }
73 
74 
77 {
78  AddrRangeList ranges;
79  ranges.push_back(RangeSize(dataPort, 1));
80  ranges.push_back(RangeSize(commandPort, 1));
81  return ranges;
82 }
83 
84 void
85 X86ISA::I8042::writeData(uint8_t newData, bool mouse)
86 {
87  DPRINTF(I8042, "Set data %#02x.\n", newData);
88  dataReg = newData;
89  statusReg.outputFull = 1;
90  statusReg.mouseOutputFull = (mouse ? 1 : 0);
91  if (!mouse && commandByte.keyboardFullInt) {
92  DPRINTF(I8042, "Sending keyboard interrupt.\n");
93  for (auto *wire: keyboardIntPin) {
94  wire->raise();
95  //This is a hack
96  wire->lower();
97  }
98  } else if (mouse && commandByte.mouseFullInt) {
99  DPRINTF(I8042, "Sending mouse interrupt.\n");
100  for (auto *wire: mouseIntPin) {
101  wire->raise();
102  //This is a hack
103  wire->lower();
104  }
105  }
106 }
107 
108 uint8_t
110 {
111  uint8_t data = dataReg;
112  statusReg.outputFull = 0;
113  statusReg.mouseOutputFull = 0;
114  if (keyboard->hostDataAvailable()) {
115  writeData(keyboard->hostRead(), false);
116  } else if (mouse->hostDataAvailable()) {
117  writeData(mouse->hostRead(), true);
118  }
119  return data;
120 }
121 
122 Tick
124 {
125  assert(pkt->getSize() == 1);
126  Addr addr = pkt->getAddr();
127  if (addr == dataPort) {
128  uint8_t data = readDataOut();
129  //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
130  pkt->setLE<uint8_t>(data);
131  } else if (addr == commandPort) {
132  //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
133  pkt->setLE<uint8_t>((uint8_t)statusReg);
134  } else {
135  panic("Read from unrecognized port %#x.\n", addr);
136  }
137  pkt->makeAtomicResponse();
138  return latency;
139 }
140 
141 Tick
143 {
144  assert(pkt->getSize() == 1);
145  Addr addr = pkt->getAddr();
146  uint8_t data = pkt->getLE<uint8_t>();
147  if (addr == dataPort) {
148  statusReg.commandLast = 0;
149  switch (lastCommand) {
150  case NoCommand:
151  keyboard->hostWrite(data);
152  if (keyboard->hostDataAvailable())
153  writeData(keyboard->hostRead(), false);
154  break;
155  case WriteToMouse:
156  mouse->hostWrite(data);
157  if (mouse->hostDataAvailable())
158  writeData(mouse->hostRead(), true);
159  break;
160  case WriteCommandByte:
161  commandByte = data;
162  DPRINTF(I8042, "Got data %#02x for \"Write "
163  "command byte\" command.\n", data);
164  statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
165  break;
166  case WriteMouseOutputBuff:
167  DPRINTF(I8042, "Got data %#02x for \"Write "
168  "mouse output buffer\" command.\n", data);
169  writeData(data, true);
170  break;
171  case WriteKeyboardOutputBuff:
172  DPRINTF(I8042, "Got data %#02x for \"Write "
173  "keyboad output buffer\" command.\n", data);
174  writeData(data, false);
175  break;
176  case WriteOutputPort:
177  DPRINTF(I8042, "Got data %#02x for \"Write "
178  "output port\" command.\n", data);
179  panic_if(bits(data, 0) != 1, "Reset bit should be 1");
180  // Safe to ignore otherwise
181  break;
182  default:
183  panic("Data written for unrecognized "
184  "command %#02x\n", lastCommand);
185  }
186  lastCommand = NoCommand;
187  } else if (addr == commandPort) {
188  DPRINTF(I8042, "Got command %#02x.\n", data);
189  statusReg.commandLast = 1;
190  // These purposefully leave off the first byte of the controller RAM
191  // so it can be handled specially.
192  if (data > ReadControllerRamBase &&
193  data < ReadControllerRamBase + RamSize) {
194  panic("Attempted to use i8042 read controller RAM command to "
195  "get byte %d.\n", data - ReadControllerRamBase);
196  } else if (data > WriteControllerRamBase &&
197  data < WriteControllerRamBase + RamSize) {
198  panic("Attempted to use i8042 write controller RAM command to "
199  "get byte %d.\n", data - WriteControllerRamBase);
200  } else if (data >= PulseOutputBitBase &&
201  data < PulseOutputBitBase + NumOutputBits) {
202  panic("Attempted to use i8042 pulse output bit command to "
203  "to pulse bit %d.\n", data - PulseOutputBitBase);
204  }
205  switch (data) {
206  case GetCommandByte:
207  DPRINTF(I8042, "Getting command byte.\n");
208  writeData(commandByte);
209  break;
210  case WriteCommandByte:
211  DPRINTF(I8042, "Setting command byte.\n");
212  lastCommand = WriteCommandByte;
213  break;
214  case CheckForPassword:
215  panic("i8042 \"Check for password\" command not implemented.\n");
216  case LoadPassword:
217  panic("i8042 \"Load password\" command not implemented.\n");
218  case CheckPassword:
219  panic("i8042 \"Check password\" command not implemented.\n");
220  case DisableMouse:
221  DPRINTF(I8042, "Disabling mouse at controller.\n");
222  commandByte.disableMouse = 1;
223  break;
224  case EnableMouse:
225  DPRINTF(I8042, "Enabling mouse at controller.\n");
226  commandByte.disableMouse = 0;
227  break;
228  case TestMouse:
229  // The response to this is from the 8042, not the mouse.
230  // Hard code no errors detected.
231  writeData(0x00);
232  break;
233  case SelfTest:
234  // Exactly what this does is essentially undocumented, but this:
235  // https://www.os2museum.com/wp/
236  // ibm-pcat-8042-keyboard-controller-commands/
237  // says that this should essentially reset some values.
238  commandByte.convertScanCodes = 1;
239  commandByte.disableMouse = 1;
240  commandByte.disableKeyboard = 1;
241  commandByte.passedSelfTest = 1;
242  statusReg.passedSelfTest = 1;
243  writeData(0x55); // Self test passed.
244  break;
245  case InterfaceTest:
246  // Hard code no errors detected.
247  writeData(0x00);
248  break;
249  case DiagnosticDump:
250  panic("i8042 \"Diagnostic dump\" command not implemented.\n");
251  case DisableKeyboard:
252  DPRINTF(I8042, "Disabling keyboard at controller.\n");
253  commandByte.disableKeyboard = 1;
254  break;
255  case EnableKeyboard:
256  DPRINTF(I8042, "Enabling keyboard at controller.\n");
257  commandByte.disableKeyboard = 0;
258  break;
259  case ReadInputPort:
260  panic("i8042 \"Read input port\" command not implemented.\n");
261  case ContinuousPollLow:
262  panic("i8042 \"Continuous poll low\" command not implemented.\n");
263  case ContinuousPollHigh:
264  panic("i8042 \"Continuous poll high\" command not implemented.\n");
265  case ReadOutputPort:
266  panic("i8042 \"Read output port\" command not implemented.\n");
267  case WriteOutputPort:
268  lastCommand = WriteOutputPort;
269  break;
270  case WriteKeyboardOutputBuff:
271  lastCommand = WriteKeyboardOutputBuff;
272  break;
273  case WriteMouseOutputBuff:
274  DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
275  lastCommand = WriteMouseOutputBuff;
276  break;
277  case WriteToMouse:
278  DPRINTF(I8042, "Expecting mouse command.\n");
279  lastCommand = WriteToMouse;
280  break;
281  case DisableA20:
282  panic("i8042 \"Disable A20\" command not implemented.\n");
283  case EnableA20:
284  panic("i8042 \"Enable A20\" command not implemented.\n");
285  case ReadTestInputs:
286  panic("i8042 \"Read test inputs\" command not implemented.\n");
287  case SystemReset:
288  panic("i8042 \"System reset\" command not implemented.\n");
289  default:
290  warn("Write to unknown i8042 "
291  "(keyboard controller) command port.\n");
292  }
293  } else {
294  panic("Write to unrecognized port %#x.\n", addr);
295  }
296  pkt->makeAtomicResponse();
297  return latency;
298 }
299 
300 void
302 {
303  SERIALIZE_SCALAR(dataPort);
304  SERIALIZE_SCALAR(commandPort);
305  SERIALIZE_SCALAR(statusReg);
306  SERIALIZE_SCALAR(commandByte);
307  SERIALIZE_SCALAR(dataReg);
308  SERIALIZE_SCALAR(lastCommand);
309 }
310 
311 void
313 {
314  UNSERIALIZE_SCALAR(dataPort);
315  UNSERIALIZE_SCALAR(commandPort);
316  UNSERIALIZE_SCALAR(statusReg);
317  UNSERIALIZE_SCALAR(commandByte);
318  UNSERIALIZE_SCALAR(dataReg);
319  UNSERIALIZE_SCALAR(lastCommand);
320 }
321 
322 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition: packet.hh:815
void makeAtomicResponse()
Definition: packet.hh:1071
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
This device is the base class which all devices senstive to an address range inherit from.
Definition: io_device.hh:103
PioDeviceParams Params
Definition: io_device.hh:134
uint8_t readDataOut()
Definition: i8042.cc:109
ps2::Device * mouse
Definition: i8042.hh:116
void writeData(uint8_t newData, bool mouse=false)
Definition: i8042.cc:85
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: i8042.cc:312
ps2::Device * keyboard
Definition: i8042.hh:117
StatusReg statusReg
Definition: i8042.hh:105
I8042(const Params &p)
Definition: i8042.cc:50
std::vector< IntSourcePin< I8042 > * > keyboardIntPin
Definition: i8042.hh:114
std::vector< IntSourcePin< I8042 > * > mouseIntPin
Definition: i8042.hh:113
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:142
CommandByte commandByte
Definition: i8042.hh:106
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: i8042.cc:301
AddrRangeList getAddrRanges() const override
Every PIO device is obliged to provide an implementation that returns the address ranges the device r...
Definition: i8042.cc:76
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: i8042.cc:123
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:815
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:76
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define warn(...)
Definition: logging.hh:246
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 3 > addr
Definition: types.hh:84
Bitfield< 0 > p
Definition: pagetable.hh:151
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
const uint8_t NumOutputBits
Definition: i8042.cc:47
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
const uint8_t RamSize
Definition: i8042.cc:46
uint64_t Tick
Tick count type.
Definition: types.hh:58
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
Declaration of the Packet class.
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1