From patchwork Tue Apr 10 23:16:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Moger, Babu" X-Patchwork-Id: 10334517 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E276E6053C for ; Tue, 10 Apr 2018 23:16:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D96E82856A for ; Tue, 10 Apr 2018 23:16:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CB94E2856F; Tue, 10 Apr 2018 23:16:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 53DC82856A for ; Tue, 10 Apr 2018 23:16:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755166AbeDJXQ1 (ORCPT ); Tue, 10 Apr 2018 19:16:27 -0400 Received: from mail-by2nam01on0081.outbound.protection.outlook.com ([104.47.34.81]:40576 "EHLO NAM01-BY2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1754568AbeDJXQW (ORCPT ); Tue, 10 Apr 2018 19:16:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=mJH4Pg0qEhNRu4ktOwvvK9sFg8rWZFAM8zzTrtNKCso=; b=yBK/gd3CL2ky3iQ1fihM7WzawmQrwd/bR0QFuadmuteHYrb56AJQ92weF36aZCfaODs6FQhozvA8czvMLLbQjIvd4BSrz5mRs+FOgZTG9RXwbRULVFbrEF1rojEGfYY1vLJY2T71bFCFexJv5vdRC2nF4JO2aJ7VwZ9dYSKlksw= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Babu.Moger@amd.com; Received: from linux-pyp0.amd.com (165.204.77.1) by CY4PR12MB1767.namprd12.prod.outlook.com (2603:10b6:903:122::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.653.12; Tue, 10 Apr 2018 23:16:19 +0000 From: Babu Moger To: mst@redhat.com, marcel@redhat.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, mtosatti@redhat.com Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, kash@tripleback.net, geoff@hostfission.com, babu.moger@amd.com Subject: [PATCH v6 1/9] i386: Helpers to encode cache information consistently Date: Tue, 10 Apr 2018 19:16:01 -0400 Message-Id: <1523402169-113351-2-git-send-email-babu.moger@amd.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1523402169-113351-1-git-send-email-babu.moger@amd.com> References: <1523402169-113351-1-git-send-email-babu.moger@amd.com> MIME-Version: 1.0 X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: MWHPR2201CA0048.namprd22.prod.outlook.com (2603:10b6:301:16::22) To CY4PR12MB1767.namprd12.prod.outlook.com (2603:10b6:903:122::9) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(5600026)(4534165)(4627221)(201703031133081)(201702281549075)(48565401081)(2017052603328)(7153060)(7193020); SRVR:CY4PR12MB1767; X-Microsoft-Exchange-Diagnostics: 1; CY4PR12MB1767; 3:TQmoYtk8pQ0a4RuLWT0AMRBUSYzhdkQ5ziH8BgaTMOhF8UChEM2uZmtV788Ozmk0fZknsvpKQ/5Wbn2HkA8IKNO4Q1fptYiRv78PJXK3asJXfSx16oVUu/pnr+/JDu6l69me3GBpt2jIfBADV6cWuSwPYx7M6i2JbqkSXwwPUgA7UZQ6muMbPDJrVXQyoChQ8EPOeXcPPWnCXoLCeMPA5p6Sb0JTj+C0TpHD0pFs0kBmcBIuLwLHiPsBYa5VzU71; 25:8NKLWCvzCFKrPNQNpXaUbA50CskjALiGI6wUhX1G+hj11uHSguI9ozj3jGepMwXDUlFEKkLmhA+stYABUqyXZd5Dd09grtZuL8tegkUd6UlMV9jbOs4eCBuk3lngBkLnQtaztd9Xr6SzSMpF6FQ4u68acMtSN4vnMiuUSxBDFkWNxLwICaVfgE4QpZPgbbtCFa9FvPI0yL4acXZOuxqIn0CMt2WJuRUCWJL6ipf7Cc/2Sa8QSkO7wKlQP8GpN9z9p27tSLjgUAYX1g7hBtDff1Cx4A1XJh82Gm/u7jOqhSA8rvBHOfSjYkpRGLeKBfKuBGWAa1iio7aD8UFDYL49xg==; 31:aKrsWBDXfQ6rjGUptoMyIVeqCnvQIW6pwSSAN2YYp3pw0fnRsCb5vOvtf/wLhaj493kJ1K7sT+84O7vsmEeBPpYr0eNJKmrkcxsCnYnWnCw9fe4sq1v9q7zp7l8474We9rR6ADo1E5aP/T+7YGNzpKSCn2K4ADsNU63o1Z9qQS8765lnJSVHQ8vnrcNfTW1BX+QXhiXuScSXzgEV3d9RNab1lR4ZtypXQFamcUtmPSI= X-MS-TrafficTypeDiagnostic: CY4PR12MB1767: X-Microsoft-Exchange-Diagnostics: 1; CY4PR12MB1767; 20:Zy7IiVWyitdvqAzHdZp9nj6MXFi9f2YLGy/aYiaJ2AQy2Y8n0I+QkMjiSfj7/MOQFWFO4HIH9FplxqhgVnh7R8gPQubmxWemqC5Vx5n4gVAk3QtMIkM85XQPT35oZm0MYSjKZV2WcivUilQwMMyRi05tP7f6DtTKuJGEMaQNqHZxk7h0UDgqmArmHXgJzo8rBTWrUePIfII8w92pYsmeG/Muy8CIz0j/axaxZhfKp5TXCVOkif7HCRLdg4uQvgmqjXlTlpOojYqtCMeQzINmaEN4oPDdP0U6ExTwKY5rjO4suekZmlwLhV/0fZaRXjxqgeuTT3Nvcaun7t9BGLthV6ZEokclDqzIXm5mmQq2CuCW5DrW+Upi5l1FAKB2pOM9S1FIS4Bqo+hI9JIYTQ4hTQ/w06ENHsnqkU1+EPjErWcqL+H6qvWZvz/FHf51UM0/mI00zdHul4qYzdbKRtUjuVcRth4qfFRQk3GpkjiHuDvS1J6WF35K10lThI6I+L4k; 4:gz0glMey8LOqC42vND3YMfSd2Vgxu2Lf6oHzeOb8jimrNmcCCRUNVJ0UJd9kWCpfWks7nnnm5JM9cPaG9aBXDEDkpSHt0Wc0LsBpbSvi1THFBi36zBxGuaDuSfMHbRlCVQDiCEuoRI7x9W2ZqcxP2PZX5BFqMbV7XeC973wv7/s9Nv6XBDv12/186bNr5xLv3iK1/KX4z+ZoFX2BcCVM6ZgAQ9P5jn4z5yRwQ8O/uWVPFHtOlJKtWNuIoBMklk8yIFTMkC75pyDDtkx0Dbfr9utuuVJuATcP2njx9sjT0/i2BcVW1fnUdZ5POXBb2CdJ X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(93006095)(93001095)(3231221)(944501327)(52105095)(3002001)(10201501046)(6055026)(6041310)(20161123560045)(20161123564045)(20161123558120)(20161123562045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011); SRVR:CY4PR12MB1767; BCL:0; PCL:0; RULEID:; SRVR:CY4PR12MB1767; X-Forefront-PRVS: 0638FD5066 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(979002)(346002)(376002)(366004)(39860400002)(39380400002)(396003)(199004)(189003)(476003)(2906002)(52116002)(26005)(86362001)(50466002)(50226002)(305945005)(5660300001)(186003)(48376002)(7736002)(16526019)(6666003)(25786009)(575784001)(6116002)(446003)(11346002)(105586002)(4720700003)(2616005)(6486002)(4326008)(956004)(3846002)(66066001)(53416004)(8936002)(386003)(72206003)(478600001)(316002)(16586007)(8676002)(81156014)(81166006)(59450400001)(97736004)(36756003)(47776003)(76176011)(106356001)(7416002)(7696005)(51416003)(68736007)(53936002)(486006)(19627235001)(969003)(989001)(999001)(1009001)(1019001); DIR:OUT; SFP:1101; SCL:1; SRVR:CY4PR12MB1767; H:linux-pyp0.amd.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY4PR12MB1767; 23:FLsFdUnq+Ntal+ycW90sYDFV5iYxkTYxO151PEZZJ?= =?us-ascii?Q?GApCM5E85EX2qF4481xv3248XJ3AdxoFHnrLh55RMePkV5HYtbKIn2VHXu/O?= =?us-ascii?Q?H3QK8iptNe0skAAEyQF1QhN1BlRL2aGQTLhDLZugS61+OAPaElaqJyMPy9S4?= =?us-ascii?Q?JWUFlTPDAfFdg+zYfQ87XSnD5LGti3gj9y+1L08ME99Xxqq5oFcWQgQtsVEO?= =?us-ascii?Q?rTZKPeh0fWXTvj5NfOh+yzDi4Ebe9DAPPfkSEzTD87WZRD3M6lRGVfy7a+yw?= =?us-ascii?Q?LJ0YfQKguisE7TF6RMhAjhsbciQ2rsHKjN3nDgcQcOlvGeV7kd0ehV1rJ0DN?= =?us-ascii?Q?nsjmcTHFXgcD2uQutTOluwhOXMM6AaI2lrAMreFlJ5IazQkey9HtlfQAKWaL?= =?us-ascii?Q?5oWYVAPpQvY7PRnZmGdXI3fm+KA9qdmrUu2D2dsASZwv5bxYTaQdPrP9/57U?= =?us-ascii?Q?5AFU7arTjwCgwwBQLhXc+Q+GMTRwOAdzeznyi81C1NKsUm+eJm+vLOl+EhSn?= =?us-ascii?Q?BZ3bltItd/Jtpa/1W28MVWeognSLfNtt62MTDnGTxb5JIfFBjKObQ4SL/OD1?= =?us-ascii?Q?FiZVGeIe6tYd2V8P6mpZ7KH2b/VruoP/mJUmcJ59I1xs5minXGCX8YxuideV?= =?us-ascii?Q?ZgA7jL4mUmCmkoNQjzqn7yoDFm509hWHptq8DTyQzsH56G8DvTUQCuTyjAXJ?= =?us-ascii?Q?O84bgTaN2NnJLjEgqyXYEivPHKSr/uoOfUfg0e9DhZwS79WjWFwT4KBwn1Cx?= =?us-ascii?Q?2kkZkHMeTc+YgdUFEnJsGAbIhaevwBSjjinH6rLhp/wzNvVF4bKo0o7zG0HA?= =?us-ascii?Q?jgD/9Z0rOGusWgfhR/7OvFsPaeH/0pwUOiPY/0+BulMfr1Wam0loUNzhr3aw?= =?us-ascii?Q?xWRQu0CUEzUbqrVr1TSEPnd5qISEhBs63+NCQZTQWzPA1ckHFCEpruLdT+h+?= =?us-ascii?Q?dd/hZ9ngs1rhv2gKex5YPQD6NwdE3CjjCIC5VpffO+v7MJsjAjV6hjpEF0TF?= =?us-ascii?Q?dd+zaZhaHbEijzNWCKz7fiq8e98+siqMaZ1UEpIJ1LgpfJwuCR+nGRxw+O6p?= =?us-ascii?Q?zVVz7laT1xeFwDTjfA0JAGkigfjdEp75obzRRXcuC8DwTJop037Gb4JVCjoD?= =?us-ascii?Q?Xy3USkxkajANkO3EEvDXwI9wkSxz13h0AV0NdwOAyOWYRpzRyTQA9ebqvBv1?= =?us-ascii?Q?t9E48LlwjRJI1utJoXf3rnwK6EzAlFCagihRRufocpCJrIcs8+n22q602Glh?= =?us-ascii?Q?Zag9BKi//sDVS84RDv/dC7z6kBg5fFB+gYrpf5Wc9F7LoY+5EUX/cVIrCGYO?= =?us-ascii?Q?POQYViqj/nuEd/nx2ibc+hb3xXzlO0bGzRisOgFxUXIDRtD7cjnP557jvNpk?= =?us-ascii?Q?+lpvhDlTc1TxnimQzOuG6fWXj5eWain05n3CPI4FuZEGcdT?= X-Microsoft-Antispam-Message-Info: O8Y8OkEMrpBX933lVyhz50Ea4bMX5O2SMLSLgoYBrrFeNZQOWn5I2h/PnoqNxgmCqhKwgqa5iuN7/a6QNbgGRMWd+9HmOqPN8Ohlu9Ghs76RsToWaHiOlJQKX9+eq4m+lt0iCqJVoIJlagrxMyGCAwkY3tv3BwOw0SJE0pjy8BILH0r0wvwVge6ZQJLeLi7Y X-Microsoft-Exchange-Diagnostics: 1; CY4PR12MB1767; 6:NVetAPNG6jPOrNXHM3vAnMtnK+IzVCqdKIM30A5N9v9D30duDwWVtWLd78hbL2l2sf12I8aB54VL1uhLiAxSuh2RggQ6d8eLsIYiQNmQlQA7NZOo1vhT3cx2Uqoh7ZYlquS50P3V5ASYtJCSoXMConkiwY6mt+3QUGep428skoiF4w+bHv/gNs1qHKQgMfZb0AT0j+R294hXuMJjh05xq1cgu8LK+a91z/oPsanKq0kFlFMSMmwCNRWIBnG+BZjZu7ul+vHXwa5wyJUuxcNoqxau8+vcTCa+dS1iuZWleC6M6jAkgri6ey/5z+4UP6zQdnnsw3mw6KTZEfSXS2IL1lAT94bNtiMuXUnDXvYEMzl+bFkkG/IMMZePlV1GnuQiq2kqQRbkI8mtTLb+Xf4BhOF6ZotLj8w601zDsog8NXjkDkeF/20RaY864AH4AMauiAMb6RljKa4wuKkU03+gCw==; 5:m132OIYsGmImf0zVJbdF0ExkHx+uWiQk9WXS5ZVwvlAc4Rwg/pq0BdFiDI3OPl9YC3/xNmUgBkYfPUxGy0N9A8fQBSO5IQeTosqJXgmt1mxAru0ncKoXQIfxNDq4lV9V7VCjmPXRijztVCHeytTCAqDZPnTdVa93IV0ccDpekJY=; 24:FH5WpxxRgpFNOZEm4D5N82n8ZhNORhYI9e5oRBLZrZroWE60FK0+FbpsQB0ovCgq6DoKyITtp53Rq8BO/wlY6/lh0AnrOHU4jiyZiy6Rdfc= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; CY4PR12MB1767; 7:/WMCMgpuf67Dyh+QCKMi5g3uN/ZwgfcgJu5ohYm/6oJmrTGpoGk/XdogwDRHSDsLQ3htZKXGi0amzz6MZ6me+8zb+oLUfvm+rqO3HAcAtAhVIEN7Llet7QDMOW48qvNNZ+7rbEf5UOk1mfgcxe0GeCFkfTOzABMQEn2IKJMkFPk+Au3026kK+eXMtat0hS4O/wEOwxe9/jgtpOPkDEEW39yeV/D64gdMBpmp/Hlf+PrcrV49UrfSrEzzLc7a50PS; 20:EOmibgl8kTOkz0eEzpYUAWG7djhfWMfzHFZrPP0BbvCMFqdj1rdYHdaLLY1fq3oo6OsKHyQC6RSNsRdyaf3zq3AkvyvfpkHpRfdroSsidcMu+huUUzn0tWTMG28KZwb3jA89Lm01Oy4zV8J8nOhaqjzP734BG1GrF3691Rg2E4kFCxLN6a1I0makFP7iAy9DtbewY0qyj1Ewd1XWxmE5tUcYK5Gr5+Vw1d3brzY7eQYDbs1rrNApOGg7quVbevAD X-MS-Office365-Filtering-Correlation-Id: 7dc1d7ef-6900-4c19-ccfd-08d59f3911ee X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Apr 2018 23:16:19.4670 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7dc1d7ef-6900-4c19-ccfd-08d59f3911ee X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR12MB1767 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Eduardo Habkost Instead of having a collection of macros that need to be used in complex expressions to build CPUID data, define a CPUCacheInfo struct that can hold information about a given cache. Helper functions will take a CPUCacheInfo struct as input to encode CPUID leaves for a cache. This will help us ensure consistency between cache information CPUID leaves, and make the existing inconsistencies in CPUID info more visible. Signed-off-by: Eduardo Habkost Signed-off-by: Babu Moger Tested-by: Geoffrey McRae --- target/i386/cpu.c | 495 ++++++++++++++++++++++++++++++++++++++++-------------- target/i386/cpu.h | 53 ++++++ 2 files changed, 424 insertions(+), 124 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 555ae79..2d3d7d8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -56,33 +56,240 @@ #include "disas/capstone.h" +/* Helpers for building CPUID[2] descriptors: */ + +struct CPUID2CacheDescriptorInfo { + enum CacheType type; + int level; + int size; + int line_size; + int associativity; +}; -/* Cache topology CPUID constants: */ +#define KiB 1024 +#define MiB (1024 * 1024) -/* CPUID Leaf 2 Descriptors */ +/* + * Known CPUID 2 cache descriptors. + * From Intel SDM Volume 2A, CPUID instruction + */ +struct CPUID2CacheDescriptorInfo cpuid2_cache_descriptors[] = { + [0x06] = { .level = 1, .type = ICACHE, .size = 8 * KiB, + .associativity = 4, .line_size = 32, }, + [0x08] = { .level = 1, .type = ICACHE, .size = 16 * KiB, + .associativity = 4, .line_size = 32, }, + [0x09] = { .level = 1, .type = ICACHE, .size = 32 * KiB, + .associativity = 4, .line_size = 64, }, + [0x0A] = { .level = 1, .type = DCACHE, .size = 8 * KiB, + .associativity = 2, .line_size = 32, }, + [0x0C] = { .level = 1, .type = DCACHE, .size = 16 * KiB, + .associativity = 4, .line_size = 32, }, + [0x0D] = { .level = 1, .type = DCACHE, .size = 16 * KiB, + .associativity = 4, .line_size = 64, }, + [0x0E] = { .level = 1, .type = DCACHE, .size = 24 * KiB, + .associativity = 6, .line_size = 64, }, + [0x1D] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, + .associativity = 2, .line_size = 64, }, + [0x21] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, + .associativity = 8, .line_size = 64, }, + /* lines per sector is not supported cpuid2_cache_descriptor(), + * so descriptors 0x22, 0x23 are not included + */ + [0x24] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 16, .line_size = 64, }, + /* lines per sector is not supported cpuid2_cache_descriptor(), + * so descriptors 0x25, 0x20 are not included + */ + [0x2C] = { .level = 1, .type = DCACHE, .size = 32 * KiB, + .associativity = 8, .line_size = 64, }, + [0x30] = { .level = 1, .type = ICACHE, .size = 32 * KiB, + .associativity = 8, .line_size = 64, }, + [0x41] = { .level = 2, .type = UNIFIED_CACHE, .size = 128 * KiB, + .associativity = 4, .line_size = 32, }, + [0x42] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, + .associativity = 4, .line_size = 32, }, + [0x43] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 4, .line_size = 32, }, + [0x44] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 4, .line_size = 32, }, + [0x45] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 4, .line_size = 32, }, + [0x46] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, + .associativity = 4, .line_size = 64, }, + [0x47] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, + .associativity = 8, .line_size = 64, }, + [0x48] = { .level = 2, .type = UNIFIED_CACHE, .size = 3 * MiB, + .associativity = 12, .line_size = 64, }, + /* Descriptor 0x49 depends on CPU family/model, so it is not included */ + [0x4A] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, + .associativity = 12, .line_size = 64, }, + [0x4B] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, + .associativity = 16, .line_size = 64, }, + [0x4C] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, + .associativity = 12, .line_size = 64, }, + [0x4D] = { .level = 3, .type = UNIFIED_CACHE, .size = 16 * MiB, + .associativity = 16, .line_size = 64, }, + [0x4E] = { .level = 2, .type = UNIFIED_CACHE, .size = 6 * MiB, + .associativity = 24, .line_size = 64, }, + [0x60] = { .level = 1, .type = DCACHE, .size = 16 * KiB, + .associativity = 8, .line_size = 64, }, + [0x66] = { .level = 1, .type = DCACHE, .size = 8 * KiB, + .associativity = 4, .line_size = 64, }, + [0x67] = { .level = 1, .type = DCACHE, .size = 16 * KiB, + .associativity = 4, .line_size = 64, }, + [0x68] = { .level = 1, .type = DCACHE, .size = 32 * KiB, + .associativity = 4, .line_size = 64, }, + [0x78] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 4, .line_size = 64, }, + /* lines per sector is not supported cpuid2_cache_descriptor(), + * so descriptors 0x79, 0x7A, 0x7B, 0x7C are not included. + */ + [0x7D] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 8, .line_size = 64, }, + [0x7F] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 2, .line_size = 64, }, + [0x80] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 8, .line_size = 64, }, + [0x82] = { .level = 2, .type = UNIFIED_CACHE, .size = 256 * KiB, + .associativity = 8, .line_size = 32, }, + [0x83] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 8, .line_size = 32, }, + [0x84] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 8, .line_size = 32, }, + [0x85] = { .level = 2, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 8, .line_size = 32, }, + [0x86] = { .level = 2, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 4, .line_size = 64, }, + [0x87] = { .level = 2, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 8, .line_size = 64, }, + [0xD0] = { .level = 3, .type = UNIFIED_CACHE, .size = 512 * KiB, + .associativity = 4, .line_size = 64, }, + [0xD1] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 4, .line_size = 64, }, + [0xD2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 4, .line_size = 64, }, + [0xD6] = { .level = 3, .type = UNIFIED_CACHE, .size = 1 * MiB, + .associativity = 8, .line_size = 64, }, + [0xD7] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 8, .line_size = 64, }, + [0xD8] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, + .associativity = 8, .line_size = 64, }, + [0xDC] = { .level = 3, .type = UNIFIED_CACHE, .size = 1.5 * MiB, + .associativity = 12, .line_size = 64, }, + [0xDD] = { .level = 3, .type = UNIFIED_CACHE, .size = 3 * MiB, + .associativity = 12, .line_size = 64, }, + [0xDE] = { .level = 3, .type = UNIFIED_CACHE, .size = 6 * MiB, + .associativity = 12, .line_size = 64, }, + [0xE2] = { .level = 3, .type = UNIFIED_CACHE, .size = 2 * MiB, + .associativity = 16, .line_size = 64, }, + [0xE3] = { .level = 3, .type = UNIFIED_CACHE, .size = 4 * MiB, + .associativity = 16, .line_size = 64, }, + [0xE4] = { .level = 3, .type = UNIFIED_CACHE, .size = 8 * MiB, + .associativity = 16, .line_size = 64, }, + [0xEA] = { .level = 3, .type = UNIFIED_CACHE, .size = 12 * MiB, + .associativity = 24, .line_size = 64, }, + [0xEB] = { .level = 3, .type = UNIFIED_CACHE, .size = 18 * MiB, + .associativity = 24, .line_size = 64, }, + [0xEC] = { .level = 3, .type = UNIFIED_CACHE, .size = 24 * MiB, + .associativity = 24, .line_size = 64, }, +}; + +/* + * "CPUID leaf 2 does not report cache descriptor information, + * use CPUID leaf 4 to query cache parameters" + */ +#define CACHE_DESCRIPTOR_UNAVAILABLE 0xFF -#define CPUID_2_L1D_32KB_8WAY_64B 0x2c -#define CPUID_2_L1I_32KB_8WAY_64B 0x30 -#define CPUID_2_L2_2MB_8WAY_64B 0x7d -#define CPUID_2_L3_16MB_16WAY_64B 0x4d +/* + * Return a CPUID 2 cache descriptor for a given cache. + * If no known descriptor is found, return CACHE_DESCRIPTOR_UNAVAILABLE + */ +static uint8_t cpuid2_cache_descriptor(CPUCacheInfo *cache) +{ + int i; + + assert(cache->size > 0); + assert(cache->level > 0); + assert(cache->line_size > 0); + assert(cache->associativity > 0); + for (i = 0; i < ARRAY_SIZE(cpuid2_cache_descriptors); i++) { + struct CPUID2CacheDescriptorInfo *d = &cpuid2_cache_descriptors[i]; + if (d->level == cache->level && d->type == cache->type && + d->size == cache->size && d->line_size == cache->line_size && + d->associativity == cache->associativity) { + return i; + } + } + return CACHE_DESCRIPTOR_UNAVAILABLE; +} /* CPUID Leaf 4 constants: */ /* EAX: */ -#define CPUID_4_TYPE_DCACHE 1 -#define CPUID_4_TYPE_ICACHE 2 -#define CPUID_4_TYPE_UNIFIED 3 +#define CACHE_TYPE_D 1 +#define CACHE_TYPE_I 2 +#define CACHE_TYPE_UNIFIED 3 -#define CPUID_4_LEVEL(l) ((l) << 5) +#define CACHE_LEVEL(l) (l << 5) -#define CPUID_4_SELF_INIT_LEVEL (1 << 8) -#define CPUID_4_FULLY_ASSOC (1 << 9) +#define CACHE_SELF_INIT_LEVEL (1 << 8) /* EDX: */ -#define CPUID_4_NO_INVD_SHARING (1 << 0) -#define CPUID_4_INCLUSIVE (1 << 1) -#define CPUID_4_COMPLEX_IDX (1 << 2) +#define CACHE_NO_INVD_SHARING (1 << 0) +#define CACHE_INCLUSIVE (1 << 1) +#define CACHE_COMPLEX_IDX (1 << 2) + +/* Encode CacheType for CPUID[4].EAX */ +#define CACHE_TYPE(t) (((t) == DCACHE) ? CACHE_TYPE_D : \ + ((t) == ICACHE) ? CACHE_TYPE_I : \ + ((t) == UNIFIED_CACHE) ? CACHE_TYPE_UNIFIED : \ + 0 /* Invalid value */) + + +/* Encode cache info for CPUID[4] */ +static void encode_cache_cpuid4(CPUCacheInfo *cache, + int num_apic_ids, int num_cores, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + assert(cache->size == cache->line_size * cache->associativity * + cache->partitions * cache->sets); + + assert(num_apic_ids > 0); + *eax = CACHE_TYPE(cache->type) | + CACHE_LEVEL(cache->level) | + (cache->self_init ? CACHE_SELF_INIT_LEVEL : 0) | + ((num_cores - 1) << 26) | + ((num_apic_ids - 1) << 14); + + assert(cache->line_size > 0); + assert(cache->partitions > 0); + assert(cache->associativity > 0); + /* We don't implement fully-associative caches */ + assert(cache->associativity < cache->sets); + *ebx = (cache->line_size - 1) | + ((cache->partitions - 1) << 12) | + ((cache->associativity - 1) << 22); + + assert(cache->sets > 0); + *ecx = cache->sets - 1; + + *edx = (cache->no_invd_sharing ? CACHE_NO_INVD_SHARING : 0) | + (cache->inclusive ? CACHE_INCLUSIVE : 0) | + (cache->complex_indexing ? CACHE_COMPLEX_IDX : 0); +} + +/* Encode cache info for CPUID[0x80000005].ECX or CPUID[0x80000005].EDX */ +static uint32_t encode_cache_cpuid80000005(CPUCacheInfo *cache) +{ + assert(cache->size % 1024 == 0); + assert(cache->lines_per_tag > 0); + assert(cache->associativity > 0); + assert(cache->line_size > 0); + return ((cache->size / 1024) << 24) | (cache->associativity << 16) | + (cache->lines_per_tag << 8) | (cache->line_size); +} #define ASSOC_FULL 0xFF @@ -100,57 +307,140 @@ a == ASSOC_FULL ? 0xF : \ 0 /* invalid value */) +/* + * Encode cache info for CPUID[0x80000006].ECX and CPUID[0x80000006].EDX + * @l3 can be NULL. + */ +static void encode_cache_cpuid80000006(CPUCacheInfo *l2, + CPUCacheInfo *l3, + uint32_t *ecx, uint32_t *edx) +{ + assert(l2->size % 1024 == 0); + assert(l2->associativity > 0); + assert(l2->lines_per_tag > 0); + assert(l2->line_size > 0); + *ecx = ((l2->size / 1024) << 16) | + (AMD_ENC_ASSOC(l2->associativity) << 12) | + (l2->lines_per_tag << 8) | (l2->line_size); + + if (l3) { + assert(l3->size % (512 * 1024) == 0); + assert(l3->associativity > 0); + assert(l3->lines_per_tag > 0); + assert(l3->line_size > 0); + *edx = ((l3->size / (512 * 1024)) << 18) | + (AMD_ENC_ASSOC(l3->associativity) << 12) | + (l3->lines_per_tag << 8) | (l3->line_size); + } else { + *edx = 0; + } +} /* Definitions of the hardcoded cache entries we expose: */ /* L1 data cache: */ -#define L1D_LINE_SIZE 64 -#define L1D_ASSOCIATIVITY 8 -#define L1D_SETS 64 -#define L1D_PARTITIONS 1 -/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ -#define L1D_DESCRIPTOR CPUID_2_L1D_32KB_8WAY_64B +static CPUCacheInfo l1d_cache = { + .type = DCACHE, + .level = 1, + .size = 32 * KiB, + .self_init = 1, + .line_size = 64, + .associativity = 8, + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, +}; + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ -#define L1D_LINES_PER_TAG 1 -#define L1D_SIZE_KB_AMD 64 -#define L1D_ASSOCIATIVITY_AMD 2 +static CPUCacheInfo l1d_cache_amd = { + .type = DCACHE, + .level = 1, + .size = 64 * KiB, + .self_init = 1, + .line_size = 64, + .associativity = 2, + .sets = 512, + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, +}; /* L1 instruction cache: */ -#define L1I_LINE_SIZE 64 -#define L1I_ASSOCIATIVITY 8 -#define L1I_SETS 64 -#define L1I_PARTITIONS 1 -/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 32KiB */ -#define L1I_DESCRIPTOR CPUID_2_L1I_32KB_8WAY_64B +static CPUCacheInfo l1i_cache = { + .type = ICACHE, + .level = 1, + .size = 32 * KiB, + .self_init = 1, + .line_size = 64, + .associativity = 8, + .sets = 64, + .partitions = 1, + .no_invd_sharing = true, +}; + /*FIXME: CPUID leaf 0x80000005 is inconsistent with leaves 2 & 4 */ -#define L1I_LINES_PER_TAG 1 -#define L1I_SIZE_KB_AMD 64 -#define L1I_ASSOCIATIVITY_AMD 2 +static CPUCacheInfo l1i_cache_amd = { + .type = ICACHE, + .level = 1, + .size = 64 * KiB, + .self_init = 1, + .line_size = 64, + .associativity = 2, + .sets = 512, + .partitions = 1, + .lines_per_tag = 1, + .no_invd_sharing = true, +}; /* Level 2 unified cache: */ -#define L2_LINE_SIZE 64 -#define L2_ASSOCIATIVITY 16 -#define L2_SETS 4096 -#define L2_PARTITIONS 1 -/* Size = LINE_SIZE*ASSOCIATIVITY*SETS*PARTITIONS = 4MiB */ +static CPUCacheInfo l2_cache = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 4 * MiB, + .self_init = 1, + .line_size = 64, + .associativity = 16, + .sets = 4096, + .partitions = 1, + .no_invd_sharing = true, +}; + /*FIXME: CPUID leaf 2 descriptor is inconsistent with CPUID leaf 4 */ -#define L2_DESCRIPTOR CPUID_2_L2_2MB_8WAY_64B +static CPUCacheInfo l2_cache_cpuid2 = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 2 * MiB, + .line_size = 64, + .associativity = 8, +}; + + /*FIXME: CPUID leaf 0x80000006 is inconsistent with leaves 2 & 4 */ -#define L2_LINES_PER_TAG 1 -#define L2_SIZE_KB_AMD 512 +static CPUCacheInfo l2_cache_amd = { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, + .line_size = 64, + .lines_per_tag = 1, + .associativity = 8, + .sets = 1024, + .partitions = 1, +}; /* Level 3 unified cache: */ -#define L3_SIZE_KB 0 /* disabled */ -#define L3_ASSOCIATIVITY 0 /* disabled */ -#define L3_LINES_PER_TAG 0 /* disabled */ -#define L3_LINE_SIZE 0 /* disabled */ -#define L3_N_LINE_SIZE 64 -#define L3_N_ASSOCIATIVITY 16 -#define L3_N_SETS 16384 -#define L3_N_PARTITIONS 1 -#define L3_N_DESCRIPTOR CPUID_2_L3_16MB_16WAY_64B -#define L3_N_LINES_PER_TAG 1 -#define L3_N_SIZE_KB_AMD 16384 +static CPUCacheInfo l3_cache = { + .type = UNIFIED_CACHE, + .level = 3, + .size = 16 * MiB, + .line_size = 64, + .associativity = 16, + .sets = 16384, + .partitions = 1, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .complex_indexing = true, +}; /* TLB definitions: */ @@ -3294,85 +3584,53 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, if (!cpu->enable_l3_cache) { *ecx = 0; } else { - *ecx = L3_N_DESCRIPTOR; + *ecx = cpuid2_cache_descriptor(&l3_cache); } - *edx = (L1D_DESCRIPTOR << 16) | \ - (L1I_DESCRIPTOR << 8) | \ - (L2_DESCRIPTOR); + *edx = (cpuid2_cache_descriptor(&l1d_cache) << 16) | + (cpuid2_cache_descriptor(&l1i_cache) << 8) | + (cpuid2_cache_descriptor(&l2_cache_cpuid2)); break; case 4: /* cache info: needed for Core compatibility */ if (cpu->cache_info_passthrough) { host_cpuid(index, count, eax, ebx, ecx, edx); + /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ *eax &= ~0xFC000000; + if ((*eax & 31) && cs->nr_cores > 1) { + *eax |= (cs->nr_cores - 1) << 26; + } } else { *eax = 0; switch (count) { case 0: /* L1 dcache info */ - *eax |= CPUID_4_TYPE_DCACHE | \ - CPUID_4_LEVEL(1) | \ - CPUID_4_SELF_INIT_LEVEL; - *ebx = (L1D_LINE_SIZE - 1) | \ - ((L1D_PARTITIONS - 1) << 12) | \ - ((L1D_ASSOCIATIVITY - 1) << 22); - *ecx = L1D_SETS - 1; - *edx = CPUID_4_NO_INVD_SHARING; + encode_cache_cpuid4(&l1d_cache, + 1, cs->nr_cores, + eax, ebx, ecx, edx); break; case 1: /* L1 icache info */ - *eax |= CPUID_4_TYPE_ICACHE | \ - CPUID_4_LEVEL(1) | \ - CPUID_4_SELF_INIT_LEVEL; - *ebx = (L1I_LINE_SIZE - 1) | \ - ((L1I_PARTITIONS - 1) << 12) | \ - ((L1I_ASSOCIATIVITY - 1) << 22); - *ecx = L1I_SETS - 1; - *edx = CPUID_4_NO_INVD_SHARING; + encode_cache_cpuid4(&l1i_cache, + 1, cs->nr_cores, + eax, ebx, ecx, edx); break; case 2: /* L2 cache info */ - *eax |= CPUID_4_TYPE_UNIFIED | \ - CPUID_4_LEVEL(2) | \ - CPUID_4_SELF_INIT_LEVEL; - if (cs->nr_threads > 1) { - *eax |= (cs->nr_threads - 1) << 14; - } - *ebx = (L2_LINE_SIZE - 1) | \ - ((L2_PARTITIONS - 1) << 12) | \ - ((L2_ASSOCIATIVITY - 1) << 22); - *ecx = L2_SETS - 1; - *edx = CPUID_4_NO_INVD_SHARING; + encode_cache_cpuid4(&l2_cache, + cs->nr_threads, cs->nr_cores, + eax, ebx, ecx, edx); break; case 3: /* L3 cache info */ - if (!cpu->enable_l3_cache) { - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; + pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); + if (cpu->enable_l3_cache) { + encode_cache_cpuid4(&l3_cache, + (1 << pkg_offset), cs->nr_cores, + eax, ebx, ecx, edx); break; } - *eax |= CPUID_4_TYPE_UNIFIED | \ - CPUID_4_LEVEL(3) | \ - CPUID_4_SELF_INIT_LEVEL; - pkg_offset = apicid_pkg_offset(cs->nr_cores, cs->nr_threads); - *eax |= ((1 << pkg_offset) - 1) << 14; - *ebx = (L3_N_LINE_SIZE - 1) | \ - ((L3_N_PARTITIONS - 1) << 12) | \ - ((L3_N_ASSOCIATIVITY - 1) << 22); - *ecx = L3_N_SETS - 1; - *edx = CPUID_4_INCLUSIVE | CPUID_4_COMPLEX_IDX; - break; + /* fall through */ default: /* end of info */ - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; + *eax = *ebx = *ecx = *edx = 0; break; } } - - /* QEMU gives out its own APIC IDs, never pass down bits 31..26. */ - if ((*eax & 31) && cs->nr_cores > 1) { - *eax |= (cs->nr_cores - 1) << 26; - } break; case 5: /* mwait info: needed for Core compatibility */ @@ -3576,10 +3834,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, (L1_ITLB_2M_ASSOC << 8) | (L1_ITLB_2M_ENTRIES); *ebx = (L1_DTLB_4K_ASSOC << 24) | (L1_DTLB_4K_ENTRIES << 16) | \ (L1_ITLB_4K_ASSOC << 8) | (L1_ITLB_4K_ENTRIES); - *ecx = (L1D_SIZE_KB_AMD << 24) | (L1D_ASSOCIATIVITY_AMD << 16) | \ - (L1D_LINES_PER_TAG << 8) | (L1D_LINE_SIZE); - *edx = (L1I_SIZE_KB_AMD << 24) | (L1I_ASSOCIATIVITY_AMD << 16) | \ - (L1I_LINES_PER_TAG << 8) | (L1I_LINE_SIZE); + *ecx = encode_cache_cpuid80000005(&l1d_cache_amd); + *edx = encode_cache_cpuid80000005(&l1i_cache_amd); break; case 0x80000006: /* cache info (L2 cache) */ @@ -3595,18 +3851,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, (L2_DTLB_4K_ENTRIES << 16) | \ (AMD_ENC_ASSOC(L2_ITLB_4K_ASSOC) << 12) | \ (L2_ITLB_4K_ENTRIES); - *ecx = (L2_SIZE_KB_AMD << 16) | \ - (AMD_ENC_ASSOC(L2_ASSOCIATIVITY) << 12) | \ - (L2_LINES_PER_TAG << 8) | (L2_LINE_SIZE); - if (!cpu->enable_l3_cache) { - *edx = ((L3_SIZE_KB / 512) << 18) | \ - (AMD_ENC_ASSOC(L3_ASSOCIATIVITY) << 12) | \ - (L3_LINES_PER_TAG << 8) | (L3_LINE_SIZE); - } else { - *edx = ((L3_N_SIZE_KB_AMD / 512) << 18) | \ - (AMD_ENC_ASSOC(L3_N_ASSOCIATIVITY) << 12) | \ - (L3_N_LINES_PER_TAG << 8) | (L3_N_LINE_SIZE); - } + encode_cache_cpuid80000006(&l2_cache_amd, + cpu->enable_l3_cache ? &l3_cache : NULL, + ecx, edx); break; case 0x80000007: *eax = 0; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 78db1b8..eaed287 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1044,6 +1044,59 @@ typedef enum TPRAccess { TPR_ACCESS_WRITE, } TPRAccess; +/* Cache information data structures: */ + +enum CacheType { + DCACHE, + ICACHE, + UNIFIED_CACHE +}; + +typedef struct CPUCacheInfo { + enum CacheType type; + uint8_t level; + /* Size in bytes */ + uint32_t size; + /* Line size, in bytes */ + uint16_t line_size; + /* + * Associativity. + * Note: representation of fully-associative caches is not implemented + */ + uint8_t associativity; + /* Physical line partitions. CPUID[0x8000001D].EBX, CPUID[4].EBX */ + uint8_t partitions; + /* Number of sets. CPUID[0x8000001D].ECX, CPUID[4].ECX */ + uint32_t sets; + /* + * Lines per tag. + * AMD-specific: CPUID[0x80000005], CPUID[0x80000006]. + * (Is this synonym to @partitions?) + */ + uint8_t lines_per_tag; + + /* Self-initializing cache */ + bool self_init; + /* + * WBINVD/INVD is not guaranteed to act upon lower level caches of + * non-originating threads sharing this cache. + * CPUID[4].EDX[bit 0], CPUID[0x8000001D].EDX[bit 0] + */ + bool no_invd_sharing; + /* + * Cache is inclusive of lower cache levels. + * CPUID[4].EDX[bit 1], CPUID[0x8000001D].EDX[bit 1]. + */ + bool inclusive; + /* + * A complex function is used to index the cache, potentially using all + * address bits. CPUID[4].EDX[bit 2]. + */ + bool complex_indexing; +} CPUCacheInfo; + + + typedef struct CPUX86State { /* standard registers */ target_ulong regs[CPU_NB_REGS];