From nobody Fri Aug 21 21:26:31 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1787229688; cv=none; d=zohomail.com; s=zohoarc; b=R1wmVacZaUkpcw1sI830RgNN+w1cPVBqXmXzyQxWjg4ihC497SiixV+YR89vpkepaURzdSb+w9YV4JTwaDPCkxMDCVSE2kMXFOXfUQPakTIvgRcjTmwUAFGcZvGlXOwVsQUgualVRmOVD7ntaFCPWYnc+QcVIxbHp1mGH3CWXGc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1787229688; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=7O1SDwJPhyM/cxU16CBQbBz7mUsV9rM5wrJOKeWl8xI=; b=fDkSRrPKjVAQK30CTWiFt9csHR92qpfxgz1YrBq2nb5kLS/4SGhijLekhAhDuDj6ozx6yNi89NFa6jsgApsPtEJpJaOcZBAFnjmnCuv0YTmEVWdvb02oFV+BqdkjxkT2JnXt2Dr1uh7fukQYCzCSFWhXrOD5c06mI6D4EOeElBo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1787229688426787.6246923161551; Thu, 20 Aug 2026 05:41:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wx250-00016P-Is; Thu, 20 Aug 2026 08:41:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wx1rS-0003Ni-7w for qemu-devel@nongnu.org; Thu, 20 Aug 2026 08:27:10 -0400 Received: from mail-wr1-x42c.google.com ([2a00:1450:4864:20::42c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wx1rP-0003IQ-2e for qemu-devel@nongnu.org; Thu, 20 Aug 2026 08:27:09 -0400 Received: by mail-wr1-x42c.google.com with SMTP id ffacd0b85a97d-4799b3f7c83so1512604f8f.2 for ; Thu, 20 Aug 2026 05:27:06 -0700 (PDT) Received: from localhost.localdomain (p2003010827046e07f1219fbed82e562c.dip0.t-ipconnect.de. [2003:108:2704:6e07:f121:9fbe:d82e:562c]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-482b14b8022sm10536183f8f.18.2026.08.20.05.27.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 05:27:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787228825; x=1787833625; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7O1SDwJPhyM/cxU16CBQbBz7mUsV9rM5wrJOKeWl8xI=; b=iWPlVjB9929+0rpelW6kzlkaKatfrj6SCLo1wxfVW5Bf/vLOT2UpTL81dRIHiGP6eM I4gLEIDqzHVRNkv6V9OCaaAP0XQgseDoJL9J0zjb4Hk8784P8wWBK8O45wQpEn9vcyNe bvkTrPXplY1xc63HkPVqAw9EXSjMFxKc2BWALTke7MFyJyRFCas3fsXNiMFDfrRvXQlU OCc/22qXPQ197yvLTdK/Z2CvZqhU3hEnwVHh4cyx0NhuNLhL/PGHgzGnCpMrJCwGeHT+ 4zFTvoaI34fhkn8NfKHIw118r8jeMDoQjKDwJ8r79l11s72BMk3CgBCDQxYdwLUOCQvL YvAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787228825; x=1787833625; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=7O1SDwJPhyM/cxU16CBQbBz7mUsV9rM5wrJOKeWl8xI=; b=Xv9InypqkI+NurFFh7DR4JsECfWuYnx3d2CWqayBQZDmt92VonXSGKRkGNOmoulSiO aj/b5KTCqaWah1Vs8QcnKL1RRmjaZojNl/NtpBzaHmMSZNjyRvVKqagQrdhfR6IAzkC2 xYZKD3sy3uNN2Xjjf7v3uo8BT7xVpj1tBTZDlGh/Yw3oSAReqy4NUUAJreoTqcJzsc+z fsJRGRgMmJIj4jExaWOaUYnNuDbzuLZaGRari/Da36FPDJaTaPfWIvEuSZA6+1iyBMIw wJxUQA1Z0jQcAP/ZnU3GVrIlOdwXSJwl/3WAH5wjsnBROIRgoXfHqi+gxTaUpPnRdspX SABQ== X-Gm-Message-State: AFuF++kBupAMeF+nM9EJlPQDQoTFGUYk1FV0lETfAGoiq7aaqliC4KPB vsb60gSHQbDnpYxWTLLNI6hOThLAarHTgIGPpmlz/s0knyx+p3a3Z4W9w1ZQT56p X-Gm-Gg: AR+sD10m7G5ZrQEj7Ih2/Pp/f+rXH/hYebPznY4V2nDU2c1mUwMtjwZVHx9FbJUPuJs sc8Oc6v7Xat+H1y+x5udZEEPFe5wX3p0DgBcLnfd/KDExJdojLVe3/y9QiOifLmFkcBqmTCh8bu ahhCkqtVBrh46FeC8vwmI2jBv9LOdKJjxZLb4I8cyN3Zpk5IjpYSTJmOc0zchu2fL4aYJVewF3i EzibqKeITiaiah8XEGpvVzXj7yknfBynIgoyWJC6WaDzor1+ZYdKam4RoP1Locv+L+mB0Yo4RC3 vYC0Kloh6hthYgEhaNXsnZEaMwOWJMGybK+MtdqmKHQXrd7L2SxCamcVSg7NrCuF0WRCmwQb5X5 XMUWWdbGOPO6jkfrVwxhnmVO+hYl4J5nQFHu5ulX4IItccNhvungzncIIcWjZ+BMuxsA3uyTtzU 1SklniV1oRaQKu/w40+TMucOA3b/LjrS3sH27Vu9bbTx0h9kaiXFfjpoSII/DWuaTf/9XDJb2n5 1MwvTwPRGN3j3NnOIAUlqwj/Z60awEQZDTucIYHVqdrrXnDM+xNPC9qAoJTbB5IR0FDTUErOG5m XI90UcQER1leQHh4I2oqWIQ0jSdLZj7K+a9zB39Z1jV0cxxpALm+TJBZg7Il2LrRjTJeaZ8lOi1 LNIo= X-Received: by 2002:a05:6000:41f6:b0:47d:eedb:ee62 with SMTP id ffacd0b85a97d-482b1fd3b69mr24471727f8f.14.1787228825204; Thu, 20 Aug 2026 05:27:05 -0700 (PDT) From: Bernard Ladenthin To: qemu-devel@nongnu.org Cc: npiggin@gmail.com, harshpb@linux.ibm.com, qemu-ppc@nongnu.org, Bernard Ladenthin , qemu-stable@nongnu.org Subject: [PATCH 1/2] spapr_vscsi: fix data corruption on transfers above 128 KiB Date: Thu, 20 Aug 2026 14:26:43 +0200 Message-ID: <20260820122644.19691-2-bernard.ladenthin@gmail.com> X-Mailer: git-send-email 2.49.0.windows.1 In-Reply-To: <20260820122644.19691-1-bernard.ladenthin@gmail.com> References: <20260820122644.19691-1-bernard.ladenthin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::42c; envelope-from=bernard.ladenthin@gmail.com; helo=mail-wr1-x42c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 20 Aug 2026 08:41:08 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1787229690449158500 Content-Type: text/plain; charset="utf-8" scsi-disk hands the HBA at most SCSI_DMA_BUF_SIZE (128 KiB) per vscsi_transfer_data() callback, so a single SCSI command carrying more than that arrives in several chunks. vscsi_srp_direct_data() remembers how far into the descriptor it already is in req->cur_desc_offset -- but that field is uint16_t, so the very first 128 KiB chunk does req->cur_desc_offset +=3D 0x20000; /* 0x20000 & 0xFFFF =3D=3D 0 */ and wraps straight back to zero. Every following chunk of the same command is then fetched with buf_offset 0 and DMA'd over the START of the guest buffer: the tail of the transfer overwrites the head, and the rest of the buffer is never written at all. The command still completes with status 0 and no sense data, so the guest cannot notice. Linux never hits this. Its ibmvscsi initiator uses INDIRECT descriptors for anything multi-page, and the indirect path resets cur_desc_offset to 0 at every descriptor boundary, so the counter never reaches 65536. A guest that describes the whole transfer with a single DIRECT descriptor and issues 256 KiB commands does hit it on the first command. Measured with a READ_10 of 2098 sectors, traced with spapr_vscsi_transfer_data and spapr_vscsi_fetch_desc_done: queue_cmd tag 0x2 CMD 0x28=3DREAD_10 LUN 0 ret: 262144 transfer_data tag=3D0x2 len=3D0x20000 fetch_desc cur=3D0 offs=3D0x0 ret { va=3D0x84d28 len=3D0x40000 } transfer_data tag=3D0x2 len=3D0x20000 fetch_desc cur=3D0 offs=3D0x0 ret { va=3D0x84d28 len=3D0x40000 } cmd_complete tag=3D0x2 status=3D0x0 Same tag, same request, same target address twice. The guest buffer ends up holding the second half of the transfer at offset 0 and zeroes above it. struct srp_direct_buf.len is already uint32_t and vscsi_fetch_desc() already takes buf_offset as unsigned, so widening the field is all that is required. The VMSTATE entries for cur_desc_num/cur_desc_offset are commented out upstream, so the migration format is unaffected. Fixes: 8ca8a17c9a16 ("pseries: rework PAPR virtual SCSI") Cc: qemu-stable@nongnu.org Signed-off-by: Bernard Ladenthin --- This is my first QEMU submission. Corrections on anything I got wrong in the process are welcome. diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 978eb856d7..1f0c2a3b64 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -86,7 +86,14 @@ typedef struct vscsi_req { uint16_t total_desc; uint16_t cdb_offset; uint16_t cur_desc_num; - uint16_t cur_desc_offset; + /* + * Byte offset reached inside the current descriptor. Must be at + * least 32 bit: scsi-disk delivers a command in SCSI_DMA_BUF_SIZE + * (128 KiB) chunks, so a DIRECT descriptor larger than 64 KiB would + * wrap a uint16_t back to zero and make every chunk after the first + * overwrite the head of the guest buffer. + */ + uint32_t cur_desc_offset; } vscsi_req; =20 #define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi" From nobody Fri Aug 21 21:26:31 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1787229694; cv=none; d=zohomail.com; s=zohoarc; b=adYLUFUTW89z1REbVlnNrhokJGzhPpy6YXhicwPMD3PMlK0B3bujwiDMWEhppJeW85AIbJcEbtfMx22PhSaSifYEu1MxsKUJFgGw8G0ycuJzv/F+OP8hMBGDw57GEWeO9jwa2eaNmquw7+LDVb0cdZCW6ypXuak3WsI1wIy8/ks= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1787229694; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=TGWKF7Q4E594lvCa4E679e4UsbL54zM8kjCTmcNuopQ=; b=EtshKl1VJEsuCzM4B3mWTvsZnJIMsS4Czg1Xib9dyAbKusle9HWgb0XhQrOo36XLzPjUVyHQagKlQhO2A16k0oh/fYPQOCltq2KfldiDSIk4rfr/19Nr2OK8H7xF9xVut65XQaPOD0zNIr874k7TIU2Kq0slt27GtEMwgVQ+ako= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17872296942703.91756784851475; Thu, 20 Aug 2026 05:41:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wx253-00018R-4w; Thu, 20 Aug 2026 08:41:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wx1rU-0003P4-PR for qemu-devel@nongnu.org; Thu, 20 Aug 2026 08:27:12 -0400 Received: from mail-wm1-x329.google.com ([2a00:1450:4864:20::329]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wx1rR-0003JU-N0 for qemu-devel@nongnu.org; Thu, 20 Aug 2026 08:27:12 -0400 Received: by mail-wm1-x329.google.com with SMTP id 5b1f17b1804b1-499ae1c6471so12832135e9.3 for ; Thu, 20 Aug 2026 05:27:09 -0700 (PDT) Received: from localhost.localdomain (p2003010827046e07f1219fbed82e562c.dip0.t-ipconnect.de. [2003:108:2704:6e07:f121:9fbe:d82e:562c]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-482b14b8022sm10536183f8f.18.2026.08.20.05.27.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 05:27:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787228828; x=1787833628; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=TGWKF7Q4E594lvCa4E679e4UsbL54zM8kjCTmcNuopQ=; b=myflPqBFMcaIL0PRJ6htsxbNOrPqW6/OqvUsNWqQXTI6a61qcQxTPYheIZ2JbRtrKJ P1T9tBiFC7iAk7xPQk+LPPUtgt+EhdzYuLC5oOiY/Ba9hC/8Z8sGNgK2KpZoNRyp03YW ROpqi3MbQmUHnOqn42B74fj8zg7ae411f3t18ge5irnAx9wlmCqWFoW589SO6bcT5I4r 8W5tzgiSuZdtC3DMjAvuuJEWbi6Pdu2JbkLL2zoTzEpBFwZ5KYs6A9eyUq07uuSVtBv+ eRXTfzLVC3BIgUlbPODaSzHsNPz4FnKCDZzAJMXJj80GndSlJQ5/WtS7vW0J5uj4SFPS ZBcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787228828; x=1787833628; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=TGWKF7Q4E594lvCa4E679e4UsbL54zM8kjCTmcNuopQ=; b=O4TgaBlAxgRl+7YPvUHxOXxidmFAJNTL1Z43oIPu76TfgsqHBXNbPUqSO8aAH72E7T 5RGaaHiarQzcZlxgnTjL9vfRqLNQdCfRGRyUdCA6gWLd9wx+nhpjxM1786FrEysi1YIM z9XouFzzFmJXE8ajgHtMYP8vABM0ShbVbs7KllGSWcNDxSfYubf0H2IK9CmWFS7LEKA2 XehuYwCIelgVHTQtSX1F/hNRNU9HHYUvFn0LRjkuYMQZtaQSjqeDleYgk6JeBkukmFO7 T2MkPESgVP3Rgnk8Zu5MZrfxcYEOrRDefCtFCeH4Z9K1cJTJcnsiwysEXL+mW822qgoE P5bA== X-Gm-Message-State: AOJu0YwRZ4uKToq3ICnpIyLVnmpjLA8WI7I6xB/qjhux6ioLBX3NYZrz MH3p4tJcLC+9gGG4vLzlhJunrmfQuSM/maBKrJ2DQF46PV/O+j6ur2R5gW2reR33 X-Gm-Gg: AR+sD13nz+LFlpOK2IpVz41SFBORif1tAem7DzQ7swCkcFPRzNgQQEHxYs6BmY634WT pxkz8c8DjctjR43Ub5qInE5usHHbyx5w6jjwv9v5Zv7w0OGG5bNp9QljRG7nwz7DAICZ5ATzPTr AseK3ApXzrDPFnO8hTQnVTG8i8iry5QgwtlP2ziqd/NuQn8khCX+yAdxRk7G215V9UMYuGqC49L 4DEAhr7g+TX5BGE+sAOYBR3EL8pRx6Bp1eRLNfaQEtLN1oRmplzlNfDdkfOGuz2RJE8sUsJrNo1 7XgtxMd61YeLAMM2dIVfJg0jWxggUVkq/OpKH2qVghgq6tPSFxGiGfnXq6yrFSNhoyzqnFdtUBy VmCg9PtyaRkNjr4mxVRg7pkHwKT3qXflTFnDcspWKoOas+Yksxkgm1ROVSo75vePy8TIq5PYeWA D7KnFpOhyS3Fe8eNRDzy/91ln4bJ3htmk4hWOEFgxaYCzGYQ6Je2xEyLR4eaEXOFufzjzyvWBi0 ZVDWvb/W+rivYCkHbwXYQ5SnmoPQt3eZvfq17fMdiMDZkwsIMUiMhsRrzsf9wzT7hRiplejUKTj Gx9TquATLAGkvgs5dtk06t95dlRHPlWj31Up37Oe3wxw1vfj7BNpILjVA/xCMhzOSYA= X-Received: by 2002:a05:600c:4e55:b0:499:a07d:a482 with SMTP id 5b1f17b1804b1-499aa1a28efmr247225225e9.10.1787228827863; Thu, 20 Aug 2026 05:27:07 -0700 (PDT) From: Bernard Ladenthin To: qemu-devel@nongnu.org Cc: npiggin@gmail.com, harshpb@linux.ibm.com, qemu-ppc@nongnu.org, Bernard Ladenthin Subject: [PATCH 2/2] tests/spapr: add bare-metal reproducers for pseries machine behaviour Date: Thu, 20 Aug 2026 14:26:44 +0200 Message-ID: <20260820122644.19691-3-bernard.ladenthin@gmail.com> X-Mailer: git-send-email 2.49.0.windows.1 In-Reply-To: <20260820122644.19691-1-bernard.ladenthin@gmail.com> References: <20260820122644.19691-1-bernard.ladenthin@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::329; envelope-from=bernard.ladenthin@gmail.com; helo=mail-wm1-x329.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Thu, 20 Aug 2026 08:41:08 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1787229696312158500 Content-Type: text/plain; charset="utf-8" These are small PowerPC payloads booted with -kernel on -M pseries. They drive the hypervisor interface directly -- hypercalls, CRQ, SRP -- so no guest operating system is involved and a failure is attributable to one function in QEMU rather than to something a kernel did on the way there. vscsibig.S is the first. It registers a CRQ, identity-maps its pages with H_PUT_TCE, clears the power-on unit attention, then issues a single 256 KiB READ_10 described by one DIRECT descriptor and checks where the data landed. The buffer is poisoned with 0xeeeeeeee first, which separates "the DMA never happened" from "the disk really holds zeros". Following tests/multiboot, the built payload is committed so the test can be run without a PowerPC cross toolchain, and run_test.sh is a standalone scri= pt rather than a meson target. The ELF is 920 bytes: linking with -N keeps the loader from page-aligning the load segment, which would otherwise pad a 584-byte payload out to 65 KiB of zeros. "make check-reproducible" rebuilds from source and compares against the committed binary, so the .S and the .elf cannot drift apart unnoticed. Signed-off-by: Bernard Ladenthin --- MAINTAINERS | 1 + tests/spapr/Makefile | 62 +++++++++ tests/spapr/link.ld | 3 + tests/spapr/run_test.sh | 108 +++++++++++++++ tests/spapr/vscsibig.S | 285 +++++++++++++++++++++++++++++++++++++++ tests/spapr/vscsibig.elf | Bin 0 -> 920 bytes 6 files changed, 459 insertions(+) create mode 100644 tests/spapr/Makefile create mode 100644 tests/spapr/link.ld create mode 100644 tests/spapr/run_test.sh create mode 100644 tests/spapr/vscsibig.S create mode 100644 tests/spapr/vscsibig.elf diff --git a/MAINTAINERS b/MAINTAINERS index 902db77218..e226d254b3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1658,6 +1658,7 @@ F: pc-bios/slof.bin F: docs/system/ppc/pseries.rst F: docs/specs/ppc-spapr-* F: tests/qtest/spapr* +F: tests/spapr/ F: tests/qtest/libqos/*spapr* F: tests/qtest/rtas* F: tests/qtest/libqos/rtas* diff --git a/tests/spapr/Makefile b/tests/spapr/Makefile new file mode 100644 index 0000000000..60af7f903f --- /dev/null +++ b/tests/spapr/Makefile @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Bare-metal reproducers for pseries (sPAPR) machine behaviour. +# +# These are tiny PowerPC payloads booted with -kernel on -M pseries. They +# talk to the hypervisor interface directly -- hypercalls, CRQ, SRP -- so +# they exercise QEMU's sPAPR implementation with no guest operating system +# anywhere in the picture. That makes a failure attributable to one +# function in QEMU rather than to something a kernel did on the way there. +# +# The built payloads are committed so the tests can be run without a +# PowerPC cross toolchain, following tests/multiboot. They are small: +# linking with -N keeps the loader from page-aligning the load segment, +# which would otherwise pad a 584-byte payload out to 65 KiB of zeros. +# +# Rebuild with: +# make CROSS=3Dpowerpc64-linux-gnu- +# +# and confirm the committed binary still matches its source with: +# make check-reproducible + +CROSS ?=3D powerpc64-linux-gnu- +AS =3D $(CROSS)as +LD =3D $(CROSS)ld +STRIP =3D $(CROSS)strip + +ASFLAGS =3D -many +LDFLAGS =3D -N -T link.ld + +PAYLOADS =3D vscsibig +ELFS =3D $(PAYLOADS:%=3D%.elf) + +all: $(ELFS) + +%.o: %.S + $(AS) $(ASFLAGS) -o $@ $< + +%.elf: %.o link.ld + $(LD) $(LDFLAGS) -o $@ $< + $(STRIP) $@ + +# The payloads are position-fixed and self-contained, so rebuilding from +# the same source must produce the same bytes. If this fails, the +# committed ELF and the committed .S have drifted apart and one of them is +# lying about what was tested. +check-reproducible: $(ELFS) + @for p in $(PAYLOADS); do \ + cp $$p.elf $$p.elf.committed; \ + $(MAKE) --no-print-directory -B $$p.elf CROSS=3D$(CROSS) >/dev/null; \ + if cmp -s $$p.elf $$p.elf.committed; then \ + echo " $$p.elf: reproducible"; \ + else \ + echo " $$p.elf: DIFFERS from the committed binary"; \ + mv $$p.elf.committed $$p.elf; exit 1; \ + fi; \ + mv $$p.elf.committed $$p.elf; \ + done + +clean: + rm -f *.o *.elf.committed vscsidisk.raw *.monitor.txt + +.PHONY: all clean check-reproducible diff --git a/tests/spapr/link.ld b/tests/spapr/link.ld new file mode 100644 index 0000000000..e901962834 --- /dev/null +++ b/tests/spapr/link.ld @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +ENTRY(_start) +SECTIONS { . =3D 0x400000; .text : { *(.text) } } diff --git a/tests/spapr/run_test.sh b/tests/spapr/run_test.sh new file mode 100644 index 0000000000..935b0fc2e4 --- /dev/null +++ b/tests/spapr/run_test.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Run the bare-metal sPAPR reproducers and check the words each leaves +# behind. +# +# Each payload boots with -kernel on -M pseries, drives the hypervisor +# interface directly, and writes its results to physical 0x01000000. This +# script reads that buffer back through the QEMU monitor and compares it +# against the expected words. +# +# Not wired into meson or CI, the same as tests/multiboot: it needs a +# machine, it takes a few seconds per payload, and its value is in being +# runnable by hand when someone doubts a claim. +# +# Usage: +# ./run_test.sh [/path/to/qemu-system-ppc64] +# +# Exit status is 0 only if every assertion held. + +set -u + +QEMU=3D${1:-${QEMU:-../../build/qemu-system-ppc64}} +SETTLE=3D${SETTLE:-15} + +if [ ! -x "$QEMU" ]; then + echo "qemu-system-ppc64 not found at: $QEMU" >&2 + echo "pass the path as \$1 or set \$QEMU" >&2 + exit 2 +fi + +fail=3D0 +pass=3D0 + +# Backing disk for vscsibig: sector s starts with the big-endian word +# 0xA5000000|s, so a chunk that lands at the wrong offset names the sector +# it really came from. Generated rather than committed -- it is 2 MiB of +# almost nothing. +make_disk() { + perl -e ' + open(my $f, ">", "vscsidisk.raw") or die; + binmode $f; + for my $s (0 .. 4095) { + print $f pack("N", 0xA5000000 | $s), (chr(0) x 508); + } + close $f; + ' +} + +# $1 payload $2 words to dump $3.. "index:expected:description" +run_payload() { + local name=3D$1 words=3D$2; shift 2 + local out=3D"$name.monitor.txt" + + ( sleep "$SETTLE"; printf 'x /%dxw 0x1000000\nquit\n' "$words" ) | \ + "$QEMU" -M pseries -cpu POWER7 -m 512 \ + -display none -vga none -nodefaults -serial none \ + -kernel "$name.elf" \ + -device spapr-vscsi,id=3Dscsi0 \ + -drive file=3Dvscsidisk.raw,if=3Dnone,id=3Dd0,format=3Draw \ + -device scsi-hd,bus=3Dscsi0.0,drive=3Dd0 \ + -monitor stdio >"$out" 2>/dev/null + + # The monitor prints "0000000001000000: 0x00000000 0x00000000 ..." and, + # being a readline monitor on a pipe, echoes every typed character + # wrapped in cursor-control escapes. Pulling out each 0x-prefixed + # 8-digit token sidesteps both: the echoed command contains 0x1000000, + # which is seven digits and does not match. + local got n + got=3D$(grep -oE '0x[0-9a-f]{8}' "$out" | sed 's/^0x//') + n=3D$(printf '%s\n' "$got" | grep -c .) + + if [ "$n" -lt "$words" ]; then + echo " $name: NOTHING MEASURED -- expected $words words, got $n" + echo " A short read means the payload did not finish or the" + echo " dump failed. Raise \$SETTLE and look at $out." + fail=3D$((fail + 1)) + return + fi + + local spec idx expect desc actual + for spec in "$@"; do + idx=3D${spec%%:*}; spec=3D${spec#*:} + expect=3D${spec%%:*}; desc=3D${spec#*:} + actual=3D$(echo "$got" | sed -n "$((idx + 1))p") + if [ "$actual" =3D "$expect" ]; then + echo " PASS $desc" + pass=3D$((pass + 1)) + else + echo " FAIL $desc" + echo " expected $expect, got ${actual:-}" + fail=3D$((fail + 1)) + fi + done +} + +echo "=3D=3D=3D vscsibig: a >128 KiB transfer must not be folded onto the" +echo " start of the guest buffer =3D=3D=3D" +make_disk +run_payload vscsibig 20 \ + "1:00000000:H_REG_CRQ registered the queue on the vSCSI adapter" \ + "11:00000000:the 256 KiB READ_10 reports SRP status 0 either way" \ + "13:a5000000:sector 0 landed at buffer offset 0" \ + "15:a5000100:sector 256 landed at buffer offset 0x20000" + +echo +echo "$pass passed, $fail failed" +[ "$fail" -eq 0 ] diff --git a/tests/spapr/vscsibig.S b/tests/spapr/vscsibig.S new file mode 100644 index 0000000000..6474d31f0e --- /dev/null +++ b/tests/spapr/vscsibig.S @@ -0,0 +1,285 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * vscsibig.S -- guest-free reproducer for defect 7: + * spapr_vscsi silently drops data on any transfer larger than 128 KiB. + * + * struct vscsi_req::cur_desc_offset is uint16_t. scsi-disk delivers a + * command in SCSI_DMA_BUF_SIZE (128 KiB) chunks, so vscsi_srp_direct_data= () + * does + * req->cur_desc_offset +=3D 0x20000; / 0x20000 & 0xFFFF =3D=3D = 0 / + * and wraps back to zero: every chunk after the first is DMA'd over the + * START of the guest buffer. The command still completes with status 0 a= nd + * no sense data. + * + * This payload speaks CRQ + SRP directly -- no guest OS, no SLOF client + * interface. QEMU's vscsi_process_srp_iu() dispatches SRP_CMD without + * requiring a prior LOGIN, and SPAPR_VIO_LIOBN(reg) =3D=3D reg, so the wh= ole + * thing is: free any CRQ SLOF left behind, register our own, identity-map + * the pages we touch with H_PUT_TCE, clear the power-on UNIT ATTENTION wi= th + * a TEST UNIT READY, then send one READ_10 of 512 blocks (=3D 256 KiB) + * described by a single DIRECT descriptor. + * + * The backing disk is written by mkvscsidisk.py so that sector s starts w= ith + * the big-endian word 0xA5000000|s. Therefore: + * + * +0x30 data[0] RED 0xa5000100 (the 2nd chunk landed at offset = 0) + * GREEN 0xa5000000 (sector 0, where it belongs) + * +0x38 data[0x20000] RED 0xeeeeeeee (poison -- never written at all) + * GREEN 0xa5000100 (sector 256) + * + * Poison rather than zero matters: it separates "the DMA never happened" + * from "the disk really holds zeros", which is exactly the distinction th= at + * cost two measurement rounds when this was first chased through AIX. + * + * Results at physical 0x01000000; read with the monitor: x /10xg 0x1000000 + * +0x00 H_REG_CRQ return code (0 =3D registered) + * +0x08 the VIO unit address that answered (0x71000000 + n) + * +0x10 return code of the last H_PUT_TCE + * +0x18 H_SEND_CRQ return code for the READ + * +0x20 poll iterations spent waiting for the READ response + * (0x04000000 =3D the cap: it timed out, all below is void) + * +0x28 SRP RSP status byte of the READ -- must be 0; 2 =3D CHECK CON= DITION + * +0x30 data[0] + * +0x38 data[0x20000] + * +0x40 SRP RSP status byte of the TEST UNIT READY (2 is normal: it ea= ts the + * power-on UNIT ATTENTION, which is exactly why it is sent first) + * +0x48 poll iterations spent waiting for the TEST UNIT READY response + * + * Physical map: payload 0x00400000 (relocated by spapr, harmless -- every + * address here is absolute), results 0x01000000, CRQ queue 0x02000000, TUR + * IU 0x02002000, READ IU 0x02001000, data buffer 0x02100000 + 256 KiB. R= un + * at -m 512 or more. + */ + .section .text + .globl _start +_start: + /* r11 =3D result buffer 0x01000000 */ + lis 11, 0x0100 + /* r20 =3D CRQ queue 0x02000000 */ + lis 20, 0x0200 + /* r21 =3D READ IU 0x02001000 */ + addi 21, 20, 0x1000 + /* r19 =3D TUR IU 0x02002000 */ + addi 19, 20, 0x2000 + /* r22 =3D data buffer 0x02100000 */ + lis 22, 0x0210 + + /* ---- clear the result buffer (80 bytes) ---- */ + li 0, 0 + li 9, 0 +1: stdx 0, 11, 9 + addi 9, 9, 8 + cmpwi 9, 80 + blt 1b + + /* ---- clear the CRQ queue page: we poll it, so it must start empty -= --- */ + li 0, 0 + li 9, 0 +2: stdx 0, 20, 9 + addi 9, 9, 8 + cmpwi 9, 0x1000 + blt 2b + + /* ---- poison the whole 256 KiB data buffer ---- */ + lis 8, 0xEEEE + ori 8, 8, 0xEEEE + li 9, 0 + /* 0x00040000 bytes */ + lis 10, 0x0004 +3: stwx 8, 22, 9 + addi 9, 9, 4 + cmpw 9, 10 + blt 3b + + /* ---- find the vSCSI unit: H_FREE_CRQ, then H_REG_CRQ ---- + * H_REG_CRQ gives H_PARAMETER for a unit that does not exist, + * H_NOT_FOUND for one without a CRQ (a vty), so the first success + * is the vSCSI adapter. The unit that answered is recorded, so a + * wrong guess is visible rather than silent. */ + /* candidate unit 0x71000000 */ + lis 23, 0x7100 + li 24, 0 +/* H_FREE_CRQ */ +4: li 3, 0x100 + mr 4, 23 + sc 1 + /* H_REG_CRQ */ + li 3, 0xFC + mr 4, 23 + /* queue address (IOVA) */ + mr 5, 20 + li 6, 0 + /* queue length 4096 */ + ori 6, 6, 0x1000 + sc 1 + cmpdi 3, 0 + beq 5f + addi 23, 23, 1 + addi 24, 24, 1 + cmpwi 24, 8 + blt 4b + /* no unit answered -- record and stop */ + std 3, 0(11) + b 99f +/* +0x00 H_REG_CRQ rc */ +5: std 3, 0(11) + /* +0x08 unit that answered */ + std 23, 8(11) + + /* ---- identity-map 0x02000000..0x02200000 into the TCE window ---- + * SPAPR_VIO_LIOBN(reg) =3D=3D reg, page shift 12, window base 0, + * so ioba =3D=3D phys. */ + lis 25, 0x0200 + li 26, 0 +/* H_PUT_TCE */ +6: li 3, 0x20 + /* liobn =3D=3D unit */ + mr 4, 23 + /* ioba */ + mr 5, 25 + /* tce =3D page | read | write */ + ori 6, 25, 3 + sc 1 + addi 25, 25, 0x1000 + addi 26, 26, 1 + cmpwi 26, 512 + blt 6b + /* +0x10 last H_PUT_TCE rc */ + std 3, 16(11) + + /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 1. TEST UNIT RE= ADY, to eat the UNIT ATTENTION =3D=3D=3D=3D=3D=3D=3D=3D=3D + * A freshly reset SCSI device answers its first command with + * sense key 0x06 / ASC 0x29 (power on, reset or bus device reset). W= ithout + * it the READ below fails with CHECK CONDITION and transfers + * nothing. */ + li 0, 0 + li 9, 0 +7: stdx 0, 19, 9 + addi 9, 9, 8 + cmpwi 9, 48 + blt 7b + li 0, 0x02 + /* opcode =3D SRP_CMD */ + stb 0, 0(19) + /* buf_fmt 0 =3D no data */ + lis 0, 0x8000 + /* lun =3D 0x8000000000000000 */ + stw 0, 20(19) + /* cdb[0] +32 =3D TEST UNIT READY */ + /* H_SEND_CRQ (0x104 is H_VIO_SIGNAL!) */ + li 3, 0x108 + mr 4, 23 + lis 5, 0x8001 + sldi 5, 5, 32 + /* 80 01 00 00 0000 0030 (IU_length 48) */ + ori 5, 5, 0x0030 + mr 6, 19 + sc 1 + + li 27, 0 + /* poll cap ~67M */ + lis 28, 0x0400 +/* response lands in queue slot 0 */ +8: lbz 0, 0(20) + cmpwi 0, 0 + bne 9f + addi 27, 27, 1 + cmpd 27, 28 + blt 8b +/* +0x48 TUR poll iterations */ +9: std 27, 72(11) + /* srp_rsp.status */ + lbz 0, 19(19) + /* +0x40 TUR status (2 =3D the UA) */ + std 0, 64(11) + + /* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 2. the READ_10 that reproduces= the defect =3D=3D=3D=3D=3D=3D=3D=3D */ + li 0, 0 + li 9, 0 +10: stdx 0, 21, 9 + addi 9, 9, 8 + cmpwi 9, 64 + blt 10b + + li 0, 0x02 + /* opcode =3D SRP_CMD */ + stb 0, 0(21) + li 0, 0x01 + /* buf_fmt: data-in =3D DIRECT */ + stb 0, 5(21) + li 0, 0 + /* data_out_desc_cnt =3D 0 */ + stb 0, 6(21) + li 0, 1 + /* data_in_desc_cnt =3D 1 */ + stb 0, 7(21) + lis 0, 0x1122 + ori 0, 0, 0x3344 + /* tag (any) */ + stw 0, 8(21) + lis 0, 0x5566 + ori 0, 0, 0x7788 + stw 0, 12(21) + lis 0, 0x8000 + /* lun =3D 0x8000000000000000 (SAM-5 LU) */ + stw 0, 20(21) + li 0, 0 + stw 0, 24(21) + /* add_cdb_len at +31 stays 0 */ + li 0, 0x28 + /* cdb[0] =3D READ(10) */ + stb 0, 32(21) + li 0, 0x02 + /* cdb[7..8] =3D 0x0200 =3D 512 blocks */ + stb 0, 39(21) + + /* srp_direct_buf { va, key, len } at add_data (+48) */ + li 0, 0 + stw 0, 48(21) + /* va =3D 0x02100000 */ + stw 22, 52(21) + /* key =3D 0 */ + stw 0, 56(21) + lis 0, 0x0004 + /* len =3D 0x00040000 =3D 256 KiB */ + stw 0, 60(21) + + /* H_SEND_CRQ */ + li 3, 0x108 + mr 4, 23 + lis 5, 0x8001 + sldi 5, 5, 32 + /* 80 01 00 00 0000 0040 (IU_length 64) */ + ori 5, 5, 0x0040 + mr 6, 21 + sc 1 + /* +0x18 H_SEND_CRQ rc */ + std 3, 24(11) + + /* the TUR response took slot 0, so this one lands in slot 1 (offset 1= 6) */ + addi 29, 20, 16 + li 27, 0 + lis 28, 0x0400 +11: lbz 0, 0(29) + cmpwi 0, 0 + bne 12f + addi 27, 27, 1 + cmpd 27, 28 + blt 11b +/* +0x20 READ poll iterations */ +12: std 27, 32(11) + /* srp_rsp.status -- must be 0 */ + lbz 0, 19(21) + /* +0x28 */ + std 0, 40(11) + + /* ---- the two witnesses ---- */ + lwz 0, 0(22) + /* +0x30 data[0] */ + std 0, 48(11) + lis 8, 0x0002 + lwzx 0, 22, 8 + /* +0x38 data[0x20000] */ + std 0, 56(11) + +99: b 99b diff --git a/tests/spapr/vscsibig.elf b/tests/spapr/vscsibig.elf new file mode 100644 index 0000000000000000000000000000000000000000..b0d472adca3298a9e78f64c701e= 71156bdcc3e96 GIT binary patch literal 920 zcmb_bKWGzC9RA)*YOciL%H=3D{3g`?71C4@jbT=3DFjID^y9LLzga{t`&>WNqgXdX?he2 z8H-cEMUc9DqA`~AM(-|yYK{l}|MIA_p@!zMc+ zq-Il#e~TFjmog-B;N+{^Ld*kU8c$rAvf!P>$`GvOGqfX)=3D81`B;GjL^rb|f;2j~`8 z9yK1qs7_*SDZ2cn`BKK4P<#vH@uo2ztD2TXey_Yzqq=3D-|axIRxM=3Dv0#r%SVX-#>-R zz_jb*LfO5;_n|uk{8JN(uigii4sf^m8%$KdsudVCIp~n z*`N6mKAlBQ^$-mcVuNb$a5aBKHGef(+3u*Pn)tv1JVZFMP@)|T)z5nuvGBNX>K~)t z+kPAGEPP-w%A;Qbs-#CAz!a~+x?-f}{5;=3D5r*FYJD?;kKvh_Tv=3Dh2s?I2+iQPj8N}?*=3D`x z_u*r#hwh~!PDn$h>)tQ7zg^*mewP}Q64 literal 0 HcmV?d00001 --=20 2.49.0.windows.1