Changeset 83985 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 27, 2020 7:38:05 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 137552
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r83968 r83985 1076 1076 } DEV_TAB_BAR_T; 1077 1077 AssertCompileSize(DEV_TAB_BAR_T, 8); 1078 #define IOMMU_DEV_TAB_BAR_VALID_MASK UINT64_C(0x000ffffffffff1ff) 1078 #define IOMMU_DEV_TAB_BAR_VALID_MASK UINT64_C(0x000ffffffffff1ff) 1079 #define IOMMU_DEV_TAB_SEG_BAR_VALID_MASK UINT64_C(0x000ffffffffff0ff) 1079 1080 1080 1081 /** … … 1379 1380 1380 1381 /** 1381 * Device Table Segment Register (MMIO).1382 * In accordance with the AMD spec.1383 */1384 typedef union1385 {1386 struct1387 {1388 RT_GCC_EXTENSION uint64_t u8Size : 8; /**< Bits 7:0 - Size: Size of the Device Table segment. */1389 RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 11:8 - Reserved. */1390 RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - DevTabBase: Device Table Segment Base Address. */1391 RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */1392 } n;1393 /** The 64-bit unsigned integer view. */1394 uint64_t u64;1395 } DEV_TAB_SEG_BAR_T;1396 AssertCompileSize(DEV_TAB_SEG_BAR_T, 8);1397 #define IOMMU_DEV_TAB_SEG_BAR_VALID_MASK UINT64_C(0x000ffffffffff0ff)1398 1399 /**1400 1382 * Device-specific Feature Extension (DSFX) Register (MMIO). 1401 1383 * In accordance with the AMD spec. … … 1915 1897 /** @name PCI: Base capability block registers. 1916 1898 * @{ */ 1917 IOMMU_BAR_T IommuBar; /**< IOMMU base address register. */1899 IOMMU_BAR_T IommuBar; /**< IOMMU base address register. */ 1918 1900 /** @} */ 1919 1901 1920 1902 /** @name MMIO: Control and status registers. 1921 1903 * @{ */ 1922 DEV_TAB_BAR_T DevTabBaseAddr; /**< Device table base address register. */1923 CMD_BUF_BAR_T CmdBufBaseAddr; /**< Command buffer base address register. */1924 EVT_LOG_BAR_T EvtLogBaseAddr; /**< Event log base address register. */1925 IOMMU_CTRL_T Ctrl; /**< IOMMU control register. */1926 IOMMU_EXCL_RANGE_BAR_T ExclRangeBaseAddr; /**< IOMMU exclusion range base register. */1927 IOMMU_EXCL_RANGE_LIMIT_T ExclRangeLimit; /**< IOMMU exclusion range limit. */1928 IOMMU_EXT_FEAT_T ExtFeat; /**< IOMMU extended feature register. */1904 DEV_TAB_BAR_T aDevTabBaseAddrs[8]; /**< Device table base address registers. */ 1905 CMD_BUF_BAR_T CmdBufBaseAddr; /**< Command buffer base address register. */ 1906 EVT_LOG_BAR_T EvtLogBaseAddr; /**< Event log base address register. */ 1907 IOMMU_CTRL_T Ctrl; /**< IOMMU control register. */ 1908 IOMMU_EXCL_RANGE_BAR_T ExclRangeBaseAddr; /**< IOMMU exclusion range base register. */ 1909 IOMMU_EXCL_RANGE_LIMIT_T ExclRangeLimit; /**< IOMMU exclusion range limit. */ 1910 IOMMU_EXT_FEAT_T ExtFeat; /**< IOMMU extended feature register. */ 1929 1911 /** @} */ 1930 1912 1931 1913 /** @name MMIO: PPR Log registers. 1932 1914 * @{ */ 1933 PPR_LOG_BAR_T PprLogBaseAddr; /**< PPR Log base address register. */1934 IOMMU_HW_EVT_HI_T HwEvtHi; /**< IOMMU hardware event register (Hi). */1935 IOMMU_HW_EVT_LO_T HwEvtLo; /**< IOMMU hardware event register (Lo). */1936 IOMMU_HW_EVT_STATUS_T HwEvtStatus; /**< IOMMU hardware event status. */1915 PPR_LOG_BAR_T PprLogBaseAddr; /**< PPR Log base address register. */ 1916 IOMMU_HW_EVT_HI_T HwEvtHi; /**< IOMMU hardware event register (Hi). */ 1917 IOMMU_HW_EVT_LO_T HwEvtLo; /**< IOMMU hardware event register (Lo). */ 1918 IOMMU_HW_EVT_STATUS_T HwEvtStatus; /**< IOMMU hardware event status. */ 1937 1919 /** @} */ 1938 1920 … … 1941 1923 /** @name MMIO: Guest Virtual-APIC Log registers. 1942 1924 * @{ */ 1943 GALOG_BAR_T GALogBaseAddr; /**< Guest Virtual-APIC Log base address register. */1944 GALOG_TAIL_ADDR_T GALogTailAddr; /**< Guest Virtual-APIC Log Tail address register. */1925 GALOG_BAR_T GALogBaseAddr; /**< Guest Virtual-APIC Log base address register. */ 1926 GALOG_TAIL_ADDR_T GALogTailAddr; /**< Guest Virtual-APIC Log Tail address register. */ 1945 1927 /** @} */ 1946 1928 1947 1929 /** @name MMIO: Alternate PPR and Event Log registers. 1948 1930 * @{ */ 1949 PPR_LOG_B_BAR_T PprLogBBaseAddr; /**< PPR Log B base address register. */ 1950 EVT_LOG_B_BAR_T EvtLogBBaseAddr; /**< Event Log B base address register. */ 1951 /** @} */ 1952 1953 /** @name MMIO: Device table segment registers. 1954 * @{ */ 1955 DEV_TAB_SEG_BAR_T DevTabSeg[7]; /**< Device Table Segment base address register. */ 1931 PPR_LOG_B_BAR_T PprLogBBaseAddr; /**< PPR Log B base address register. */ 1932 EVT_LOG_B_BAR_T EvtLogBBaseAddr; /**< Event Log B base address register. */ 1956 1933 /** @} */ 1957 1934 1958 1935 /** @name MMIO: Device-specific feature registers. 1959 1936 * @{ */ 1960 DEV_SPECIFIC_FEAT_T DevSpecificFeat; /**< Device-specific feature extension register (DSFX). */1961 DEV_SPECIFIC_CTRL_T DevSpecificCtrl; /**< Device-specific control extension register (DSCX). */1962 DEV_SPECIFIC_STATUS_T DevSpecificStatus; /**< Device-specific status extension register (DSSX). */1937 DEV_SPECIFIC_FEAT_T DevSpecificFeat; /**< Device-specific feature extension register (DSFX). */ 1938 DEV_SPECIFIC_CTRL_T DevSpecificCtrl; /**< Device-specific control extension register (DSCX). */ 1939 DEV_SPECIFIC_STATUS_T DevSpecificStatus; /**< Device-specific status extension register (DSSX). */ 1963 1940 /** @} */ 1964 1941 1965 1942 /** @name MMIO: MSI Capability Block registers. 1966 1943 * @{ */ 1967 MSI_MISC_INFO_T MsiMiscInfo; /**< MSI Misc. info registers / MSI Vector registers. */1944 MSI_MISC_INFO_T MsiMiscInfo; /**< MSI Misc. info registers / MSI Vector registers. */ 1968 1945 /** @} */ 1969 1946 1970 1947 /** @name MMIO: Performance Optimization Control registers. 1971 1948 * @{ */ 1972 IOMMU_PERF_OPT_CTRL_T PerfOptCtrl; /**< IOMMU Performance optimization control register. */1949 IOMMU_PERF_OPT_CTRL_T PerfOptCtrl; /**< IOMMU Performance optimization control register. */ 1973 1950 /** @} */ 1974 1951 1975 1952 /** @name MMIO: x2APIC Control registers. 1976 1953 * @{ */ 1977 IOMMU_XT_GEN_INTR_CTRL_T XtGenIntrCtrl; /**< IOMMU X2APIC General interrupt control register. */1978 IOMMU_XT_PPR_INTR_CTRL_T XtPprIntrCtrl; /**< IOMMU X2APIC PPR interrupt control register. */1979 IOMMU_XT_GALOG_INTR_CTRL_T XtGALogIntrCtrl; /**< IOMMU X2APIC Guest Log interrupt control register. */1954 IOMMU_XT_GEN_INTR_CTRL_T XtGenIntrCtrl; /**< IOMMU X2APIC General interrupt control register. */ 1955 IOMMU_XT_PPR_INTR_CTRL_T XtPprIntrCtrl; /**< IOMMU X2APIC PPR interrupt control register. */ 1956 IOMMU_XT_GALOG_INTR_CTRL_T XtGALogIntrCtrl; /**< IOMMU X2APIC Guest Log interrupt control register. */ 1980 1957 /** @} */ 1981 1958 1982 1959 /** @name MMIO: MARC registers. 1983 1960 * @{ */ 1984 MARC_APER_T aMarcApers[4]; /**< MARC Aperture Registers. */1961 MARC_APER_T aMarcApers[4]; /**< MARC Aperture Registers. */ 1985 1962 /** @} */ 1986 1963 1987 1964 /** @name MMIO: Reserved register. 1988 1965 * @{ */ 1989 IOMMU_RSVD_REG_T RsvdReg; /**< IOMMU Reserved Register. */1966 IOMMU_RSVD_REG_T RsvdReg; /**< IOMMU Reserved Register. */ 1990 1967 /** @} */ 1991 1968 1992 1969 /** @name MMIO: Command and Event Log pointer registers. 1993 1970 * @{ */ 1994 CMD_BUF_HEAD_PTR_T CmdBufHeadPtr; /**< Command buffer head pointer register. */1995 CMD_BUF_TAIL_PTR_T CmdBufTailPtr; /**< Command buffer tail pointer register. */1996 EVT_LOG_HEAD_PTR_T EvtLogHeadPtr; /**< Event log head pointer register. */1997 EVT_LOG_TAIL_PTR_T EvtLogTailPtr; /**< Event log tail pointer register. */1971 CMD_BUF_HEAD_PTR_T CmdBufHeadPtr; /**< Command buffer head pointer register. */ 1972 CMD_BUF_TAIL_PTR_T CmdBufTailPtr; /**< Command buffer tail pointer register. */ 1973 EVT_LOG_HEAD_PTR_T EvtLogHeadPtr; /**< Event log head pointer register. */ 1974 EVT_LOG_TAIL_PTR_T EvtLogTailPtr; /**< Event log tail pointer register. */ 1998 1975 /** @} */ 1999 1976 2000 1977 /** @name MMIO: Command and Event Status register. 2001 1978 * @{ */ 2002 IOMMU_STATUS_T Status; /**< IOMMU status register. */1979 IOMMU_STATUS_T Status; /**< IOMMU status register. */ 2003 1980 /** @} */ 2004 1981 2005 1982 /** @name MMIO: PPR Log Head and Tail pointer registers. 2006 1983 * @{ */ 2007 PPR_LOG_HEAD_PTR_T PprLogHeadPtr; /**< IOMMU PPR log head pointer register. */2008 PPR_LOG_TAIL_PTR_T PprLogTailPtr; /**< IOMMU PPR log tail pointer register. */1984 PPR_LOG_HEAD_PTR_T PprLogHeadPtr; /**< IOMMU PPR log head pointer register. */ 1985 PPR_LOG_TAIL_PTR_T PprLogTailPtr; /**< IOMMU PPR log tail pointer register. */ 2009 1986 /** @} */ 2010 1987 2011 1988 /** @name MMIO: Guest Virtual-APIC Log Head and Tail pointer registers. 2012 1989 * @{ */ 2013 GALOG_HEAD_PTR_T GALogHeadPtr; /**< Guest Virtual-APIC log head pointer register. */2014 GALOG_TAIL_PTR_T GALogTailPtr; /**< Guest Virtual-APIC log tail pointer register. */1990 GALOG_HEAD_PTR_T GALogHeadPtr; /**< Guest Virtual-APIC log head pointer register. */ 1991 GALOG_TAIL_PTR_T GALogTailPtr; /**< Guest Virtual-APIC log tail pointer register. */ 2015 1992 /** @} */ 2016 1993 2017 1994 /** @name MMIO: PPR Log B Head and Tail pointer registers. 2018 1995 * @{ */ 2019 PPR_LOG_B_HEAD_PTR_T PprLogBHeadPtr; /**< PPR log B head pointer register. */2020 PPR_LOG_B_TAIL_PTR_T PprLogBTailPtr; /**< PPR log B tail pointer register. */1996 PPR_LOG_B_HEAD_PTR_T PprLogBHeadPtr; /**< PPR log B head pointer register. */ 1997 PPR_LOG_B_TAIL_PTR_T PprLogBTailPtr; /**< PPR log B tail pointer register. */ 2021 1998 /** @} */ 2022 1999 2023 2000 /** @name MMIO: Event Log B Head and Tail pointer registers. 2024 2001 * @{ */ 2025 EVT_LOG_B_HEAD_PTR_T EvtLogBHeadPtr; /**< Event log B head pointer register. */2026 EVT_LOG_B_TAIL_PTR_T EvtLogBTailPtr; /**< Event log B tail pointer register. */2002 EVT_LOG_B_HEAD_PTR_T EvtLogBHeadPtr; /**< Event log B head pointer register. */ 2003 EVT_LOG_B_TAIL_PTR_T EvtLogBTailPtr; /**< Event log B tail pointer register. */ 2027 2004 /** @} */ 2028 2005 … … 2118 2095 * Indexed by the device table segment index. 2119 2096 */ 2120 static uint16_t const g_auDevTabSeg Sizes[] = { 0x1ff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f };2097 static uint16_t const g_auDevTabSegMaxSizes[] = { 0x1ff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f }; 2121 2098 2122 2099 … … 2196 2173 RTGCPHYS const GCPhysDevTab = DevTabBaseAddr.n.u40Base; 2197 2174 if (!(GCPhysDevTab & X86_PAGE_4K_OFFSET_MASK)) 2198 pThis-> DevTabBaseAddr.u64 = DevTabBaseAddr.u64;2175 pThis->aDevTabBaseAddrs[0].u64 = DevTabBaseAddr.u64; 2199 2176 else 2200 2177 Log((IOMMU_LOG_PFX ": Device table base address (%#RX64) misaligned -> Ignored\n", GCPhysDevTab)); … … 2429 2406 2430 2407 /* Figure out which segment is being written. */ 2431 uint8_t const idxDevTabSeg= (iReg - IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST) >> 3;2432 uint8_t const idxSegment = idxDevTabSeg+ 1;2433 Assert(idx DevTabSeg < RT_ELEMENTS(pThis->DevTabSeg));2408 uint8_t const offSegment = (iReg - IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST) >> 3; 2409 uint8_t const idxSegment = offSegment + 1; 2410 Assert(idxSegment < RT_ELEMENTS(pThis->aDevTabBaseAddrs)); 2434 2411 2435 2412 /* Mask out all unrecognized bits. */ 2436 2413 u64Value &= IOMMU_DEV_TAB_SEG_BAR_VALID_MASK; 2437 DEV_TAB_ SEG_BAR_T DevTabSegBar;2414 DEV_TAB_BAR_T DevTabSegBar; 2438 2415 DevTabSegBar.u64 = u64Value; 2439 2416 … … 2443 2420 { 2444 2421 /* Validate the size. */ 2445 uint16_t const uSegSize = DevTabSegBar.n.u 8Size;2446 uint16_t const uMaxSegSize = g_auDevTabSeg Sizes[idxSegment];2422 uint16_t const uSegSize = DevTabSegBar.n.u9Size; 2423 uint16_t const uMaxSegSize = g_auDevTabSegMaxSizes[idxSegment]; 2447 2424 if (uSegSize <= uMaxSegSize) 2448 2425 { 2449 2426 /* Finally, update the segment register. */ 2450 pThis-> DevTabSeg[idxDevTabSeg].u64 = u64Value;2427 pThis->aDevTabBaseAddrs[idxSegment].u64 = u64Value; 2451 2428 } 2452 2429 else … … 2792 2769 switch (off) 2793 2770 { 2794 case IOMMU_MMIO_OFF_DEV_TAB_BAR: uReg = pThis-> DevTabBaseAddr.u64;break;2771 case IOMMU_MMIO_OFF_DEV_TAB_BAR: uReg = pThis->aDevTabBaseAddrs[0].u64; break; 2795 2772 case IOMMU_MMIO_OFF_CMD_BUF_BAR: uReg = pThis->CmdBufBaseAddr.u64; break; 2796 2773 case IOMMU_MMIO_OFF_EVT_LOG_BAR: uReg = pThis->EvtLogBaseAddr.u64; break; … … 2814 2791 case IOMMU_MMIO_OFF_DEV_TAB_SEG_LAST: 2815 2792 { 2816 uint8_t const idxDevTabSeg = (off - IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST) >> 3; 2817 Assert(idxDevTabSeg < RT_ELEMENTS(pThis->DevTabSeg)); 2818 uReg = pThis->DevTabSeg[idxDevTabSeg].u64; 2793 uint8_t const offDevTabSeg = (off - IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST) >> 3; 2794 uint8_t const idxDevTabSeg = offDevTabSeg + 1; 2795 Assert(idxDevTabSeg < RT_ELEMENTS(pThis->aDevTabBaseAddrs)); 2796 uReg = pThis->aDevTabBaseAddrs[idxDevTabSeg].u64; 2819 2797 break; 2820 2798 } … … 2926 2904 *puResult = uReg; 2927 2905 return VINF_SUCCESS; 2928 }2929 2930 2931 /**2932 * Reads a device table segment (0-7) from guest memory.2933 *2934 * @returns VBox status code.2935 * @param pDevIns The IOMMU device instance.2936 * @param idxSeg The device table segment index.2937 * @param pvBuf Where to store the device table segment.2938 * @param cbBuf The size of the buffer in bytes.2939 *2940 * @thread Any.2941 */2942 static int iommuAmdReadDeviceTableSegment(PPDMDEVINS pDevIns, uint8_t idxSeg, void *pvBuf, uint32_t cbBuf)2943 {2944 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);2945 2946 /* Validate. */2947 Assert(pvBuf);2948 Assert(cbBuf <= _2M);2949 Assert(!idxSeg || pThis->ExtFeat.n.u2DevTabSegSup);2950 Assert(!idxSeg || idxSeg < g_acDevTabSegs[pThis->ExtFeat.n.u2DevTabSegSup]);2951 2952 /* Get the base address and size of the segment. */2953 RTGCPHYS GCPhysDevTab;2954 uint32_t cbDevTab;2955 if (!idxSeg)2956 {2957 GCPhysDevTab = pThis->DevTabBaseAddr.n.u40Base;2958 cbDevTab = IOMMU_GET_DEV_TAB_SIZE(pThis->DevTabBaseAddr.n.u9Size);2959 }2960 else2961 {2962 GCPhysDevTab = pThis->DevTabSeg[idxSeg].n.u40Base;2963 cbDevTab = IOMMU_GET_DEV_TAB_SIZE(pThis->DevTabSeg[idxSeg].n.u8Size);2964 }2965 2966 /* Validate that the destination buffer is large enough to hold the segment. */2967 Assert(cbBuf >= cbDevTab);2968 2969 /* Copy the device table to the buffer. */2970 int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhysDevTab, pvBuf, cbDevTab);2971 if (RT_FAILURE(rc))2972 {2973 Log((IOMMU_LOG_PFX ": iommuAmdFetchDeviceTable: Failed to read device table segment. idxSeg=%u GCPhys=%#RGp rc=%Rrc",2974 idxSeg, GCPhysDevTab, rc));2975 }2976 2977 return rc;2978 }2979 2980 2981 /**2982 * Calculates and returns the total size of the device table.2983 * This includes device table segments if they are used.2984 *2985 * @returns The size of the device table in bytes.2986 * @param pDevIns The IOMMU device instance.2987 *2988 * @thread Any.2989 */2990 static uint32_t iommuAmdCalcTotalDevTabSize(PPDMDEVINS pDevIns)2991 {2992 PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);2993 IOMMU_CTRL_T const Ctrl = iommuAmdGetCtrl(pThis);2994 2995 /* The base address register always exists. */2996 uint32_t cbDevTabSize = IOMMU_GET_DEV_TAB_SIZE(pThis->DevTabBaseAddr.n.u9Size);2997 2998 /* If segmentation is enabled, add the size of each segments. */2999 uint8_t const uSegmentsEnabled = Ctrl.n.u3DevTabSegEn;3000 if (uSegmentsEnabled)3001 {3002 Assert(uSegmentsEnabled < RT_ELEMENTS(g_acDevTabSegs));3003 uint8_t const cSegments = g_acDevTabSegs[uSegmentsEnabled] - 1;3004 for (uint8_t idxSegment = 0; idxSegment < cSegments - 1; idxSegment++)3005 cbDevTabSize += IOMMU_GET_DEV_TAB_SIZE(pThis->DevTabSeg[idxSegment].n.u8Size);3006 }3007 3008 return cbDevTabSize;3009 2906 } 3010 2907 … … 3193 3090 3194 3091 pHlp->pfnPrintf(pHlp, "AMD-IOMMU:\n"); 3195 /* Device Table Base Address. */ 3196 { 3197 DEV_TAB_BAR_T const DevTabBar = pThis->DevTabBaseAddr; 3198 pHlp->pfnPrintf(pHlp, " Device Table BAR = %#RX64\n", DevTabBar.u64); 3092 /* Device Table Base Addresses (all segments). */ 3093 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aDevTabBaseAddrs); i++) 3094 { 3095 DEV_TAB_BAR_T const DevTabBar = pThis->aDevTabBaseAddrs[i]; 3096 pHlp->pfnPrintf(pHlp, " Device Table BAR [%u] = %#RX64\n", i, DevTabBar.u64); 3199 3097 if (fVerbose) 3200 3098 { … … 3430 3328 } 3431 3329 } 3432 /* Device Table Segment Registers. */3433 for (unsigned i = 0; i < RT_ELEMENTS(pThis->DevTabSeg); i++)3434 {3435 DEV_TAB_SEG_BAR_T const DevTabSeg = pThis->DevTabSeg[i];3436 pHlp->pfnPrintf(pHlp, " Device Table Segment BAR [%u] = %#RX64\n", DevTabSeg.u64);3437 if (fVerbose)3438 {3439 pHlp->pfnPrintf(pHlp, " Base address = %#RX64\n", DevTabSeg.n.u40Base);3440 pHlp->pfnPrintf(pHlp, " Size = %#x (%u bytes)\n", DevTabSeg.n.u8Size,3441 IOMMU_GET_DEV_TAB_SIZE(DevTabSeg.n.u8Size));3442 }3443 }3444 3330 /* Device-Specific Feature Extension Register. */ 3445 3331 { … … 3774 3660 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev); 3775 3661 3776 pThis->DevTabBaseAddr.u64 = 0;3662 memset(&pThis->aDevTabBaseAddrs[0], 0, sizeof(pThis->aDevTabBaseAddrs)); 3777 3663 3778 3664 pThis->CmdBufBaseAddr.u64 = 0; … … 3838 3724 pThis->EvtLogBBaseAddr.n.u40Base = 0; 3839 3725 pThis->EvtLogBBaseAddr.n.u4Len = 8; 3840 3841 memset(&pThis->DevTabSeg[0], 0, sizeof(pThis->DevTabSeg));3842 3726 3843 3727 pThis->DevSpecificFeat.u64 = 0;
Note:
See TracChangeset
for help on using the changeset viewer.