From patchwork Thu Apr 26 16:26:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Babu Moger X-Patchwork-Id: 905235 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=amd.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=amdcloud.onmicrosoft.com header.i=@amdcloud.onmicrosoft.com header.b="rdLsT7Um"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40X30Y6yCvz9s02 for ; Fri, 27 Apr 2018 02:48:13 +1000 (AEST) Received: from localhost ([::1]:43469 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fBk43-00016W-Ur for incoming@patchwork.ozlabs.org; Thu, 26 Apr 2018 12:48:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45028) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fBjjg-0000L5-2M for qemu-devel@nongnu.org; Thu, 26 Apr 2018 12:27:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fBjjc-0003Fa-CS for qemu-devel@nongnu.org; Thu, 26 Apr 2018 12:27:08 -0400 Received: from mail-sn1nam01on0075.outbound.protection.outlook.com ([104.47.32.75]:12173 helo=NAM01-SN1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fBjjc-0003Be-44 for qemu-devel@nongnu.org; Thu, 26 Apr 2018 12:27:04 -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=+oyGcmycKSNdphI6jSX4Q/D21NMJngzJ2bg073KOSE4=; b=rdLsT7UmZ57YiRvoxFHidsWSOvHQjnpvBtDzHNYKjrkEe/KFfCercNWD9DbFu4LT6qcl8HzKa0kJ7PUH4VgCk7XDWxsaPxYFYLs2YP+Z45x83ewlxmcg/8IazB+MdvYhrC2COV0IArG6GysosmefB/nMpWWXWIlBul3WlbYqsoY= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Babu.Moger@amd.com; Received: from bmoger-ubuntu.amd.com (165.204.78.1) by SN1PR12MB2479.namprd12.prod.outlook.com (2603:10b6:802:29::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.696.13; Thu, 26 Apr 2018 16:26:58 +0000 From: Babu Moger To: mst@redhat.com, marcel@redhat.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, mtosatti@redhat.com Date: Thu, 26 Apr 2018 11:26:41 -0500 Message-Id: <1524760009-24710-2-git-send-email-babu.moger@amd.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1524760009-24710-1-git-send-email-babu.moger@amd.com> References: <1524760009-24710-1-git-send-email-babu.moger@amd.com> MIME-Version: 1.0 X-Originating-IP: [165.204.78.1] X-ClientProxiedBy: CY4PR1801CA0020.namprd18.prod.outlook.com (2603:10b6:910:74::33) To SN1PR12MB2479.namprd12.prod.outlook.com (2603:10b6:802:29::18) 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:SN1PR12MB2479; X-Microsoft-Exchange-Diagnostics: 1; SN1PR12MB2479; 3:+enL6nTlcI7PzTPVkofN4aHZ3nPDPkTp9rJgNrRNliZTXs/NqQLSYBazTfcHKbeT6MvuAQUmTt0EinIpNXTuTxyMsMoOQqvBomr0shrD6FahByYhvyUotKiZ4OZJf5YyFufwKAolmQOURATKlP3lexu8f7BLaFfCCmh5f+EnqRrzqo3oKZmFfGfj6Z8R56rtYq9y9+9VuwwIzZv3W3iO178dTy73USLDzNKpeFyrovohZOn5zVpc+1PEkBOjgMAH; 25:55UX4XKjMvUB7KhM+6M14EaAOQgilhmTNf6lwkkHFLA/1BNbSnTSOHHq8G9GvT7i25TSFMpi3rLJGTxMPM5Fd8JMN9bqga7zQRgb6vr0D0yEPqgqjLtaPogk+BzgZA3nXPEgD5dADHvRbrUA5b5F0NDxg8BeRQ9t2TlveXweJ3aQSqZgIl6J3OEzYiClYqILrLlshdMxHg+PE4BX84n5wG7CNKKtm5fpnBhy1BdesLxpr5InqnR97Y+BiWgYT8CA29Bin8Zt0mgVF34kEc5lrSDK+IXOG5X1yTobJ3Yy4B6IVFHsIICNPDZ9dY5x1No/tN6DkagG2mXs8Ra3xWwcow==; 31:ru6gKUjpIk93qBZBK1CSP8TALSdH6OaJ/0BUA94euONNIZ+T2Lkq1Q+DxkJ930HHbbPtnrNCPz+5iBH9KtIar5TcV+8QubNiJlsolqPFE7gFEu/mvuYiqzEJN5CZ7jD74u41i7cx93CfFnXd9zMrZ/itrt3/2nRyUEiDsZy5zTaCqRLR3nZ3Hshj19tYhbISgnAZ+fjejJEPT7LxgCjM2khNIXgavUb4tIrG0kRxNEk= X-MS-TrafficTypeDiagnostic: SN1PR12MB2479: X-Microsoft-Exchange-Diagnostics: 1; SN1PR12MB2479; 20:27P6LJnaKFM7WWMiXKh0/tP4NC5C1TUJoywhAnhZzs5dn8+IGOSyvLhE+dvDf++Ge1yKO13AtEy/DKuT7+iFAbhs1sWG/aJd4C0rmwjLCVM7Yt4+Ep+MEs0CPe1dagdXggJbY7AdgNYTfV4WyLpHnVszkqV6ZKywQnHF757ff/rosV/uYjxYZhseZWtmxt+y8yd/NbkDcPSbiNCtdm3psVBhaXEAyEhJIlP69ttl80PaDHwiRGK0WHow8zN4d7mbYPKqW3YzoSpgxutYX/EyoPM9ZvJpsMokFHPncHqANeDMZk/L671fxMKneU/dCzRhCJK0vVA572QFq7BZ+xYoo0JrT6ca9tcl7Hn8vyHgOs0Zj2EtYrqxzsO9zWeE1IW3c9+l87Rr7mzAxq6UMY+5NqhzW6VqWnfE+8FQKYWFIFELJPYyLs+sua94e4TR7dhNcG3lw26kIeqQSCXySI87ycuuH0THiwXJgO2323a5MdqsNYT5fV2Ieb6jejRKBzBz; 4:9m6p/FiBbpfRAU34vel+MrH6qxGaXLL38m4nSJY3g+mLik8f264ZI+m+iuQX4+wJaZGlKo1oKys2nvpnwlWAK+o4zYNSsj0/UvCKilpKi8DTvkD7qrHVNdQNIxP6w/PK882S884TYBt8bsZ4T+WO3RPy0c42HrNCH+T03+siMx5JR9phw2dPVxMaOCY2m9ULMwfZ7VXlcGfxN/fvG05QkIyDysfTh/M3ZsJBdf9pledjnE3YKWWfqAo2YjbfzHqftpvMyh4VAmCJ0OaYptGE49ZkOIncFtTlbVrL5iEaqVp8W30M0KWie5UIN8ypSZC0 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)(10201501046)(3002001)(3231232)(944501410)(52105095)(6055026)(6041310)(20161123560045)(20161123558120)(20161123564045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(6072148)(201708071742011); SRVR:SN1PR12MB2479; BCL:0; PCL:0; RULEID:; SRVR:SN1PR12MB2479; X-Forefront-PRVS: 0654257CF5 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(39380400002)(366004)(376002)(396003)(39860400002)(346002)(189003)(199004)(68736007)(8676002)(2906002)(6116002)(76176011)(8936002)(5660300001)(316002)(3846002)(4326008)(81156014)(50226002)(81166006)(386003)(956004)(16526019)(7416002)(52116002)(476003)(97736004)(59450400001)(186003)(25786009)(86362001)(446003)(7696005)(11346002)(51416003)(26005)(48376002)(36756003)(16586007)(47776003)(53416004)(486006)(44832011)(106356001)(7736002)(575784001)(6666003)(72206003)(2616005)(6486002)(105586002)(66066001)(478600001)(305945005)(53936002)(50466002)(19627235001); DIR:OUT; SFP:1101; SCL:1; SRVR:SN1PR12MB2479; H:bmoger-ubuntu.amd.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; SN1PR12MB2479; 23:6p5l9klyTTCiA2KZOCxJeGgZcZIX2IVD+R/qNP3ob?= d53OH8JcrVqP1voYlgtAlydwU5L4ZpnKRBfPDa/UGB5n6rP21cM/Ij/omBW2tIrfkpXZDf5cgrKLPqt136bswXSCBvl9VN5EYnkfCKKQz5xFSKMh/GPS/ob0SPm5hpqMkVG5qeIMpq9dEy/6WY+iHIPQLjA3sBXyqyBCFkVYc7s0JNbvfJ6T793mMgJOTB4EiMBx+n/w6FoLB/aqtJn9n3ig2xt46EUo2kkWoHuIQMK0dW/CVREWwL9IxAunDt0VVJMAw3aRRLGPgGbNkAjiKn0NxnixkpdHfbrj5HF31mVhDQ97BVnGAtIrFVJ84DuDhInWfVeSGzn2CDX3qcmzgjmXFs5t1+UiKynSxbtZhlLRqfbpJSaaubD+ELLUbjL6iNORJeeKmauVQW/O5k15MYui7AxUVgnkji8Id4eF+uUTcxBKMu7rUsKzCgCaTKqMoEzNS1d7aol0lh4PYgX1KVLMQ9+hRFsAFTkfU0mk6NmxJ8jUN4CfQEKvBsR9Xy93t3cDgiqQolUUxnP6YHIrcRWjcI00N0z4K3s8Bm4HlPQ64EsB9RnexVQP25mwq9q08gi/Ls3BRvm8MhWGqnbGcnE+6sxWJnrcmuRCoihkYdh9HP+VQvIkoYaLjdhLD/5P0V+fdqK3GSUkMGYMa43bmlFkKU/yVvo430HOA1V5XK7nT8t6MbqAyUWn8yHOciOEZzVFZHBQBVPRGYOzPUdecUkgB248fGLqGYhyLyeRQwVIoROKnFly7sA4E2SODL+JzwJrPf5TGGorO/u7iyHnXW/NisTD5V0uuYbNaizRuLlANeMx85BZw4xqPsJGCMwd1UL/4q2beS3XNRWAG263U0ZI5i1mbsHlSFG9/uoWR5hmvSiSISKBwfW7FQm54CcKCwcLO0ev6vc0KmX/i3WF/TdWX3pA3gAfpxhhuoaB2/DARKq4HJKF6kqsiS6dqALiL05dsP8jy49F9t/NwDm85AcX7w81IsOifcETSRu2yrwIFmSKpe84/t6TqwNIRNrsVlYHlG9JPlnPg/YPYVOPL+yT8rpVWpcQg9ZS1SAGN8AwZr+R7ihBS2w7Q8Vjb+2I+yolhsTtTfmlbOwl3cVbEHx90ndhAj6KjMxuqXuEWCf1wL1vWvrsc50d1At/cfaaQYfiqXBv9RaTDj2tH4Oc0NwgauEXhTrRbCGsafN9LmSuvaMrHXN4hSdlP2zgKh6HYggIpyrQvAQfVXaHlJbyTdiyHEAVbLHmr14CvrcQYFT2A== X-Microsoft-Antispam-Message-Info: A/MaZPpABVsOeIyVs/CbzBf3C4mnfgfZw8cz3Kh+zNjGdksATtGmARidal6cKFwMvYvfW1QAxJCIZIjDQBfFcvmoFhq/qboy6oi+lmwY4fXn8okWWHKCqJYlGyIK4V88Vd0SvRI4c8BCmIfn16ggY9V0dTOewKtpT5/j60hYqb09114YBFiTJMsJ+gyA6GQP X-Microsoft-Exchange-Diagnostics: 1; SN1PR12MB2479; 6:gqXtcUZ3tXbYY6lDGl6YAwSPVPoIHJIEZl7k6+jBP/QwrnGpmdV8glru7J8CVLnRbNrsHtk3ItoITfvFcTM2aEX9n8W1SdTgsenvoReX17iff+rA3/8EJ5Z01DSu82BAIoTI0ELNbn9Z+t2fqDg1vCeimCfxPN+vF9LCU01utjlmpjaKupQXnYsMwJKw0L6sD24vx+IV8RSWbKbDWLeuLhNSQU+xeHwpMROgp2P7T7DKr3BREQTUIdCvyYo5PzYoaxMOOnE4jlpYfhJBFL4LsuXnPwn6itC0velMG009QYjBb6jjW5IK1U67xNx9Zuw709frEr+BY+uIsT2GeSo1Lz+14v+p7eNsC5BGmPlwiwOzvRMSoi/ztNn27/b9nZdBvwL+PglomnykThauXGatjPtTCA2NRk0xdNHhiBIzU5X1gX6xg9v6xJW5zTRvfldYfPzc+KChj2urDgml4sswjQ==; 5:FdMVSrJ14jJwKvMnrCgIRls4w/qVRsV3LshuqfEGvus09HyUo++a6DASZOtxDjRrQKhgu4tlIZxDeja3QYnN7PJ75fwzr9evmY03SYQ7WkA/hOzHhrQwB/lbMyB8Pe5K9Tc7oqzRpmRzr/wyF4Cue6dbp7nzyXCm/MTQ23h3j0c=; 24:Sb0o9lJvIJ2eUJJVdSG8+WSUFmpDBALYlaG9yt6vSnahqZE5GmmDmzE57iPZj59Ty1Ij4+VpdakslF2ejKQ3sEIBx2DNiT6cZr/MRK1+Rc0= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; SN1PR12MB2479; 7:NLGQroAmH2GX8kTyo5lOm+clQhl0XhHMAZ0dhAwlEtL+cssWqC8BjVFF9DQ0Wva/0gz96CbcpkHlT3rH0a0mfEJ9jyGVInu9J3CyzPYVoPc4GVnQh6/qVVjdNa/RnfSWM+jjbH76z3fCy468G9ZSbVQA60oek3JZDN6naflB3kGlJYAkXdVOnPA2MavQYKLOpXFKccPCkKBGNV5vfe1YcVPtVSBBfhxtvbRnUZuJKJzd5lezFwRqdFLpJbfoDYMJ; 20:V2n3d7cI3zIaK4DLuPkcDGcxuaQrMIRPGiiwhUNGGNk2ig2t61SHdF9Kt0Tq1YVCkalknoegptNrNKOk/bYYHFmgpi7+jLUoM4AleEqg4Csf9XN2JKJN62cpX3mIbGiPiVay/rEGGSOumybgQnm3rl9PmSdKBXbrca91U/4ZBFuFtchMjHWGezXFxwFNV/srlTYFfJuLcjs8rfHBJL+inJUJl2R/0yqBk4pgYqexj1jz/ldyKdz1QU0Xp3boKm51 X-MS-Office365-Filtering-Correlation-Id: e18c6c28-48ea-42ec-3bb4-08d5ab9288ed X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Apr 2018 16:26:58.4866 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: e18c6c28-48ea-42ec-3bb4-08d5ab9288ed X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN1PR12MB2479 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.32.75 Subject: [Qemu-devel] [PATCH v7 1/9] i386: Helpers to encode cache information consistently X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: geoff@hostfission.com, babu.moger@amd.com, kash@tripleback.net, qemu-devel@nongnu.org, kvm@vger.kernel.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 a20fe26..b6c1592 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: */ @@ -3301,85 +3591,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 */ @@ -3583,10 +3841,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) */ @@ -3602,18 +3858,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 1b219fa..fa03e2c 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];