VirtualBox

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

Last change on this file since 66146 was 64393, checked in by vboxsync, 8 years ago

PDMPCIDEV: s/config/abConfig/ everywhere, removing the legacy alias.

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