VirtualBox

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

Last change on this file since 40754 was 39135, checked in by vboxsync, 13 years ago

Changed PDMDevHlpMMIORegister to take flags and drop pfnFill. Added PDMDevHlpMMIORegisterEx for the one user of pfnFill.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use