VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/DevLPC.cpp@ 73494

Last change on this file since 73494 was 69502, checked in by vboxsync, 7 years ago

DevLPC: Added LGPL disclaimer text.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1/* $Id: DevLPC.cpp 69502 2017-10-28 16:14:09Z vboxsync $ */
2/** @file
3 * DevLPC - LPC device emulation
4 *
5 * @todo This needs to be _replaced_ by a proper chipset device one day. There
6 * are less than 10 C/C++ statements in this file doing active emulation.
7 */
8
9/*
10 * Copyright (C) 2006-2017 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 * --------------------------------------------------------------------
20 *
21 * This code is based on:
22 *
23 * Low Pin Count emulation
24 *
25 * Copyright (c) 2007 Alexander Graf
26 *
27 * This library is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU Lesser General Public
29 * License as published by the Free Software Foundation; either
30 * version 2 of the License, or (at your option) any later version.
31 *
32 * This library is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Lesser General Public License for more details.
36 *
37 * You should have received a copy of the GNU Lesser General Public
38 * License along with this library; if not, write to the Free Software
39 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40 *
41 * *****************************************************************
42 *
43 * This driver emulates an ICH-7 LPC partially. The LPC is basically the
44 * same as the ISA-bridge in the existing PIIX implementation, but
45 * more recent and includes support for HPET and Power Management.
46 *
47 */
48
49/*
50 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
51 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
52 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
53 * a choice of LGPL license versions is made available with the language indicating
54 * that LGPLv2 or any later version may be used, or where a choice of which version
55 * of the LGPL is applied is otherwise unspecified.
56 */
57
58
59/*********************************************************************************************************************************
60* Header Files *
61*********************************************************************************************************************************/
62#define LOG_GROUP LOG_GROUP_DEV_LPC
63#include <VBox/vmm/pdmdev.h>
64#include <VBox/log.h>
65#include <VBox/vmm/stam.h>
66#include <iprt/assert.h>
67#include <iprt/string.h>
68
69#include "VBoxDD2.h"
70
71#define RCBA_BASE UINT32_C(0xFED1C000)
72
73typedef struct
74{
75 /** PCI device structure. */
76 PDMPCIDEV dev;
77
78 /** Pointer to the device instance. - R3 ptr. */
79 PPDMDEVINSR3 pDevIns;
80
81 /* So far, not much of a state */
82} LPCState;
83
84
85#ifndef VBOX_DEVICE_STRUCT_TESTCASE
86
87
88static uint32_t rcba_ram_readl(LPCState* s, RTGCPHYS addr)
89{
90 RT_NOREF1(s);
91 Log(("rcba_read at %llx\n", (uint64_t)addr));
92 int32_t iIndex = (addr - RCBA_BASE);
93 uint32_t value = 0;
94
95 /* This is the HPET config pointer, HPAS in DSDT */
96 switch (iIndex)
97 {
98 case 0x3404:
99 Log(("rcba_read HPET_CONFIG_POINTER\n"));
100 value = 0xf0; /* enabled at 0xfed00000 */
101 break;
102 case 0x3410:
103 /* This is the HPET config pointer */
104 Log(("rcba_read GCS\n"));
105 value = 0;
106 break;
107 default:
108 Log(("Unknown RCBA read\n"));
109 break;
110 }
111
112 return value;
113}
114
115static void rcba_ram_writel(LPCState* s, RTGCPHYS addr, uint32_t value)
116{
117 RT_NOREF2(s, value);
118 Log(("rcba_write %llx = %#x\n", (uint64_t)addr, value));
119 int32_t iIndex = (addr - RCBA_BASE);
120
121 switch (iIndex)
122 {
123 case 0x3410:
124 Log(("rcba_write GCS\n"));
125 break;
126 default:
127 Log(("Unknown RCBA write\n"));
128 break;
129 }
130}
131
132/**
133 * I/O handler for memory-mapped read operations.
134 *
135 * @returns VBox status code.
136 *
137 * @param pDevIns The device instance.
138 * @param pvUser User argument.
139 * @param GCPhysAddr Physical address (in GC) where the read starts.
140 * @param pv Where to store the result.
141 * @param cb Number of bytes read.
142 * @thread EMT
143 */
144PDMBOTHCBDECL(int) lpcMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
145{
146 RT_NOREF2(pvUser, cb);
147 LPCState *s = PDMINS_2_DATA(pDevIns, LPCState*);
148 Assert(cb == 4); Assert(!(GCPhysAddr & 3));
149 *(uint32_t*)pv = rcba_ram_readl(s, GCPhysAddr);
150 return VINF_SUCCESS;
151}
152
153/**
154 * Memory mapped I/O Handler for write operations.
155 *
156 * @returns VBox status code.
157 *
158 * @param pDevIns The device instance.
159 * @param pvUser User argument.
160 * @param GCPhysAddr Physical address (in GC) where the read starts.
161 * @param pv Where to fetch the value.
162 * @param cb Number of bytes to write.
163 * @thread EMT
164 */
165PDMBOTHCBDECL(int) lpcMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
166{
167 RT_NOREF1(pvUser);
168 LPCState *s = PDMINS_2_DATA(pDevIns, LPCState*);
169
170 switch (cb)
171 {
172 case 1:
173 case 2:
174 break;
175 case 4:
176 rcba_ram_writel(s, GCPhysAddr, *(uint32_t *)pv);
177 break;
178
179 default:
180 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
181 return VERR_INTERNAL_ERROR;
182 }
183 return VINF_SUCCESS;
184}
185
186#ifdef IN_RING3
187
188/**
189 * Info handler, device version.
190 *
191 * @param pDevIns Device instance which registered the info.
192 * @param pHlp Callback functions for doing output.
193 * @param pszArgs Argument string. Optional and specific to the handler.
194 */
195static DECLCALLBACK(void) lpcInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
196{
197 RT_NOREF1(pszArgs);
198 LPCState *pThis = PDMINS_2_DATA(pDevIns, LPCState *);
199 LogFlow(("lpcInfo: \n"));
200
201 if (pThis->dev.abConfig[0xde] == 0xbe && pThis->dev.abConfig[0xad] == 0xef)
202 pHlp->pfnPrintf(pHlp, "APIC backdoor activated\n");
203 else
204 pHlp->pfnPrintf(pHlp, "APIC backdoor closed: %02x %02x\n",
205 pThis->dev.abConfig[0xde], pThis->dev.abConfig[0xad]);
206
207
208 for (int iLine = 0; iLine < 8; ++iLine)
209 {
210
211 int iBase = iLine < 4 ? 0x60 : 0x64;
212 uint8_t iMap = PCIDevGetByte(&pThis->dev, iBase + iLine);
213
214 if ((iMap & 0x80) != 0)
215 pHlp->pfnPrintf(pHlp, "PIRQ%c disabled\n", 'A' + iLine);
216 else
217 pHlp->pfnPrintf(pHlp, "PIRQ%c -> IRQ%d\n", 'A' + iLine, iMap & 0xf);
218 }
219}
220
221/**
222 * @interface_method_impl{PDMDEVREG,pfnConstruct}
223 */
224static DECLCALLBACK(int) lpcConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
225{
226 RT_NOREF2(iInstance, pCfg);
227 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
228 LPCState *pThis = PDMINS_2_DATA(pDevIns, LPCState *);
229 int rc;
230 Assert(iInstance == 0);
231
232 pThis->pDevIns = pDevIns;
233
234 /*
235 * Register the PCI device.
236 */
237 PCIDevSetVendorId (&pThis->dev, 0x8086); /* Intel */
238 PCIDevSetDeviceId (&pThis->dev, 0x27b9);
239 PCIDevSetCommand (&pThis->dev, PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER);
240 PCIDevSetRevisionId (&pThis->dev, 0x02);
241 PCIDevSetClassSub (&pThis->dev, 0x01); /* PCI-to-ISA Bridge */
242 PCIDevSetClassBase (&pThis->dev, 0x06); /* Bridge */
243 PCIDevSetHeaderType (&pThis->dev, 0x80); /* normal, multifunction device (so that other devices can be its functions) */
244 PCIDevSetSubSystemVendorId(&pThis->dev, 0x8086);
245 PCIDevSetSubSystemId (&pThis->dev, 0x7270);
246 PCIDevSetInterruptPin (&pThis->dev, 0x00); /* The LPC device itself generates no interrupts */
247 PCIDevSetStatus (&pThis->dev, 0x0200); /* PCI_status_devsel_medium */
248
249 /** @todo rewrite using PCI accessors; Update, rewrite this device from
250 * scratch! Possibly against ICH9 or something else matching our
251 * chipset of choice. (Note that the exteremely partial emulation here
252 * is supposed to be of ICH7 if what's on the top of the file is
253 * anything to go by.) */
254 /* See p. 427 of ICH9 specification for register description */
255
256 /* 40h - 43h PMBASE 40-43 ACPI Base Address */
257 pThis->dev.abConfig[0x40] = 0x01; /* IO space */
258 pThis->dev.abConfig[0x41] = 0x80; /* base address / 128, see DevACPI.cpp */
259
260 /* 44h ACPI_CNTL ACPI Control */
261 pThis->dev.abConfig[0x44] = 0x00 | (1<<7); /* SCI is IRQ9, ACPI enabled */
262 /* 48h–4Bh GPIOBASE GPIO Base Address */
263
264 /* 4C GC GPIO Control */
265 pThis->dev.abConfig[0x4c] = 0x4d;
266 /* ???? */
267 pThis->dev.abConfig[0x4e] = 0x03;
268 pThis->dev.abConfig[0x4f] = 0x00;
269
270 /* 60h-63h PIRQ[n]_ROUT PIRQ[A-D] Routing Control */
271 pThis->dev.abConfig[0x60] = 0x0b; /* PCI A -> IRQ 11 */
272 pThis->dev.abConfig[0x61] = 0x09; /* PCI B -> IRQ 9 */
273 pThis->dev.abConfig[0x62] = 0x0b; /* PCI C -> IRQ 11 */
274 pThis->dev.abConfig[0x63] = 0x09; /* PCI D -> IRQ 9 */
275
276 /* 64h SIRQ_CNTL Serial IRQ Control 10h R/W, RO */
277 pThis->dev.abConfig[0x64] = 0x10;
278
279 /* 68h-6Bh PIRQ[n]_ROUT PIRQ[E-H] Routing Control */
280 pThis->dev.abConfig[0x68] = 0x80;
281 pThis->dev.abConfig[0x69] = 0x80;
282 pThis->dev.abConfig[0x6A] = 0x80;
283 pThis->dev.abConfig[0x6B] = 0x80;
284
285 /* 6C-6Dh LPC_IBDF IOxAPIC Bus:Device:Function 00F8h R/W */
286 pThis->dev.abConfig[0x70] = 0x80;
287 pThis->dev.abConfig[0x76] = 0x0c;
288 pThis->dev.abConfig[0x77] = 0x0c;
289 pThis->dev.abConfig[0x78] = 0x02;
290 pThis->dev.abConfig[0x79] = 0x00;
291 /* 80h LPC_I/O_DEC I/O Decode Ranges 0000h R/W */
292 /* 82h-83h LPC_EN LPC I/F Enables 0000h R/W */
293 /* 84h-87h GEN1_DEC LPC I/F Generic Decode Range 1 00000000h R/W */
294 /* 88h-8Bh GEN2_DEC LPC I/F Generic Decode Range 2 00000000h R/W */
295 /* 8Ch-8Eh GEN3_DEC LPC I/F Generic Decode Range 3 00000000h R/W */
296 /* 90h-93h GEN4_DEC LPC I/F Generic Decode Range 4 00000000h R/W */
297
298 /* A0h-CFh Power Management */
299 pThis->dev.abConfig[0xa0] = 0x08;
300 pThis->dev.abConfig[0xa2] = 0x00;
301 pThis->dev.abConfig[0xa3] = 0x00;
302 pThis->dev.abConfig[0xa4] = 0x00;
303 pThis->dev.abConfig[0xa5] = 0x00;
304 pThis->dev.abConfig[0xa6] = 0x00;
305 pThis->dev.abConfig[0xa7] = 0x00;
306 pThis->dev.abConfig[0xa8] = 0x0f;
307 pThis->dev.abConfig[0xaa] = 0x00;
308 pThis->dev.abConfig[0xab] = 0x00;
309 pThis->dev.abConfig[0xac] = 0x00;
310 pThis->dev.abConfig[0xae] = 0x00;
311
312 /* D0h-D3h FWH_SEL1 Firmware Hub Select 1 */
313 /* D4h-D5h FWH_SEL2 Firmware Hub Select 2 */
314 /* D8h-D9h FWH_DEC_EN1 Firmware Hub Decode Enable 1 */
315 /* DCh BIOS_CNTL BIOS Control */
316 /* E0h-E1h FDCAP Feature Detection Capability ID */
317 /* E2h FDLEN Feature Detection Capability Length */
318 /* E3h FDVER Feature Detection Version */
319 /* E4h-EBh FDVCT Feature Vector Description */
320
321 /* F0h-F3h RCBA Root Complex Base Address */
322 pThis->dev.abConfig[0xf0] = RT_BYTE1(RCBA_BASE | 1); /* enabled */
323 pThis->dev.abConfig[0xf1] = RT_BYTE2(RCBA_BASE);
324 pThis->dev.abConfig[0xf2] = RT_BYTE3(RCBA_BASE);
325 pThis->dev.abConfig[0xf3] = RT_BYTE4(RCBA_BASE);
326
327 rc = PDMDevHlpPCIRegisterEx(pDevIns, &pThis->dev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_NOT_MANDATORY_NO,
328 31 /*uPciDevNo*/, 0 /*uPciFunNo*/, "lpc");
329 if (RT_FAILURE(rc))
330 return rc;
331
332 /*
333 * Register the MMIO regions.
334 */
335 rc = PDMDevHlpMMIORegister(pDevIns, RCBA_BASE, 0x4000, pThis,
336 IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
337 lpcMMIOWrite, lpcMMIORead, "LPC Memory");
338 if (RT_FAILURE(rc))
339 return rc;
340
341 /* No state in the LPC right now */
342
343 /**
344 * @todo: Register statistics.
345 */
346 PDMDevHlpDBGFInfoRegister(pDevIns, "lpc", "Display LPC status. (no arguments)", lpcInfo);
347
348 return VINF_SUCCESS;
349}
350
351
352/**
353 * The device registration structure.
354 */
355const PDMDEVREG g_DeviceLPC =
356{
357 /* u32Version */
358 PDM_DEVREG_VERSION,
359 /* szName */
360 "lpc",
361 /* szRCMod */
362 "VBoxDD2RC.rc",
363 /* szR0Mod */
364 "VBoxDD2R0.r0",
365 /* pszDescription */
366 "Low Pin Count (LPC) Bus",
367 /* fFlags */
368 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36,
369 /* fClass */
370 PDM_DEVREG_CLASS_MISC,
371 /* cMaxInstances */
372 1,
373 /* cbInstance */
374 sizeof(LPCState),
375 /* pfnConstruct */
376 lpcConstruct,
377 /* pfnDestruct */
378 NULL,
379 /* pfnRelocate */
380 NULL,
381 /* pfnMemSetup */
382 NULL,
383 /* pfnPowerOn */
384 NULL,
385 /* pfnReset */
386 NULL,
387 /* pfnSuspend */
388 NULL,
389 /* pfnResume */
390 NULL,
391 /* pfnAttach */
392 NULL,
393 /* pfnDetach */
394 NULL,
395 /* pfnQueryInterface. */
396 NULL,
397 /* pfnInitComplete */
398 NULL,
399 /* pfnPowerOff */
400 NULL,
401 /* pfnSoftReset */
402 NULL,
403 /* u32VersionEnd */
404 PDM_DEVREG_VERSION
405};
406
407#endif /* IN_RING3 */
408
409#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette