gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
42namespace gem5
43{
44
45// The 8042 has a whopping 32 bytes of internal RAM.
46const uint8_t RamSize = 32;
47const 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++) {
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
84void
85X86ISA::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
108uint8_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
122Tick
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
141Tick
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
300void
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
311void
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:210
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:295
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
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
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
I8042Params Params
Definition i8042.hh:123
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)
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:79
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define warn(...)
Definition logging.hh:256
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 0 > p
Bitfield< 3 > addr
Definition types.hh:84
Bitfield< 0 > p
Definition pagetable.hh:151
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
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 Tue Jun 18 2024 16:24:04 for gem5 by doxygen 1.11.0