VirtualBox

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

Last change on this file since 60422 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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