From nobody Fri Dec 19 20:18:23 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746611009; cv=none; d=zohomail.com; s=zohoarc; b=JxzgOr2BOH7fnrOOP9jV9srw0yrvSlIdcl3qQ3J8LVMXFyX6GgrTOje3lTvIzFgaH5FqmQjLsc7Fr46PT8sDVMqCa7+XP4RnMSXMI7RbV/wevZM4M4h1MlLYaR5ympm+151R2Q4+MvoHb6HehYkaHvSUsBtBK0tluhBDn1Jy/iQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746611009; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=O8Y83zKrsmgv8ZOMTDE8RmHuDTLf5jyr/esqnFH6tRs=; b=X9tFrs/rCfcfdNNZ03OPmUUtTFFxkpMtRIPtCtdbkv6Ii5L48Q9JFdOrNq/w8uzNwtpCOmvK2bkIBG7dZM8Mc7e9KZz1SzOo+suBHrJti/x3RXcPpDDityOSrYgykznAX098elKvJ8r7ItO/OAilPFng5jF7HOk2hXcAGw3lV+g= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1746611009792632.5767354241394; Wed, 7 May 2025 02:43:29 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.978417.1365218 (Exim 4.92) (envelope-from ) id 1uCbJ2-0006GM-UK; Wed, 07 May 2025 09:43:12 +0000 Received: by outflank-mailman (output) from mailman id 978417.1365218; Wed, 07 May 2025 09:43:12 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ2-0006GF-RG; Wed, 07 May 2025 09:43:12 +0000 Received: by outflank-mailman (input) for mailman id 978417; Wed, 07 May 2025 09:43:11 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ1-00062U-7Z for xen-devel@lists.xenproject.org; Wed, 07 May 2025 09:43:11 +0000 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [2a00:1450:4864:20::436]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id af60407f-2b27-11f0-9eb4-5ba50f476ded; Wed, 07 May 2025 11:43:09 +0200 (CEST) Received: by mail-wr1-x436.google.com with SMTP id ffacd0b85a97d-3a0b135d18eso777822f8f.2 for ; Wed, 07 May 2025 02:43:09 -0700 (PDT) Received: from localhost.localdomain (172.74.6.51.dyn.plus.net. [51.6.74.172]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a099b16f00sm16051290f8f.84.2025.05.07.02.43.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 May 2025 02:43:08 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: af60407f-2b27-11f0-9eb4-5ba50f476ded DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746610989; x=1747215789; darn=lists.xenproject.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; bh=O8Y83zKrsmgv8ZOMTDE8RmHuDTLf5jyr/esqnFH6tRs=; b=GhkmmV1dXqOFpSej9FTnu88VIvy79fMJ/RhGfd60Hvz4zmB5XKsNSRBr8tNlF048iG m2iLBSaKIfQtoXJWvjY3Qtka+pTIqYod7zbnZu+ilnjjHrn5HV1ShQvgzDnHBahDZGP+ hiOvTfxqL6PO3aLeojFpzE95nJ68X3kIaN78bxDP308VsXZcJMhetmsqTv63xWbX4+10 8hNFXaOvBWptEPC//Dd01Rh1EtdDHnpXHUVlROk2MEEjSSGeW4JO/W23C2wbfbFOVALW naSjzuqPm6AtZCdwbBSrwltVXPUGUCTmHWuS2z3ttqjHZKjlNg3mLRGFEueJPQqpz1LP PNUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746610989; x=1747215789; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=O8Y83zKrsmgv8ZOMTDE8RmHuDTLf5jyr/esqnFH6tRs=; b=sZPJJOqGLPsLKffVAgVhotEqbIw6uwoDo8ZdZrvZhx4ZIwXK+XGTonWIV3j/I2nYeq 8o+065Yomc/fbTusmMSFfYfHu62HEmWb0YbkA/AcgJDmXOeYcDWr08tGqauXwEbE4TdX BtoX7cm3ySYjTzO4mlgR0/2oCTJf4idWZZwzRyEvceSNQVtlE8MDskboHRyU4JcX72/4 7H2GwKbsHPf1ixEPlAV/nTJIaKjiuQ36LhSMiVklD5MBhTMQHyiC9u5zP2RA/SocSIeJ +rd7gdAabqM/zSD7YQqw51TfNvwNVe4o+pabzH/vTduC4HFX8d9PwDq85d5aavKf9xk0 AKsA== X-Gm-Message-State: AOJu0YweIQLgBTEaJYWNu7Ge1R5xogfG79Tr+rggT4m55CgSmfEKRr4U Qowmrkr9oNZ2YcURH3oofNl26tYBkctP4ewQ59liosvCpPZvasuw2H86rHFrnNg= X-Gm-Gg: ASbGncuSGaSiu5sbPo1PoomVy+fjP1fl27jzux0b5XFqg8MLZu9zKNnvKcdUyqYUcDR NFsqdVi5MpVFpz8wgoNodu8KnXs7I9AIau/CUSWgHO7eMveDvJLVrGn6a4+WNL0t0XVQxTjmIXX q5k8o07X4d62aEXIOUQShyQa0F9FPoNtcq0tLyjzXvVlXYbl3vQGpGyZromyNUaQG2yphm1qX7l x3cRRv4LhiUw2e6ZFjdq3FB0hyRXZoQqlKIxKMf1T8l21hlUR5ugs7ZDp70zc3IAM88jXWHYxPp Oh6t0Gw+gcR52Be4bUoYoL7VzCEHq9ZRdps7EJpyuLQX93BsEsDA31OBRwho5CGcnICUOfiW X-Google-Smtp-Source: AGHT+IGCSM81Wqk/bepwSce6eX56XNmXveWuiq4VMa3x/g4flpfQF2He/n7rzyqGSoi4dGTtSTqLVQ== X-Received: by 2002:a05:6000:401f:b0:391:10c5:d1a9 with SMTP id ffacd0b85a97d-3a0b4a18f10mr2203929f8f.31.1746610988677; Wed, 07 May 2025 02:43:08 -0700 (PDT) From: Frediano Ziglio To: xen-devel@lists.xenproject.org Cc: Ross Lagerwall , Andrew Cooper , Anthony PERARD , Michal Orzel , Jan Beulich , Julien Grall , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Stefano Stabellini Subject: [PATCH v2 1/4] xen/lib: Export additional sha256 functions Date: Wed, 7 May 2025 10:42:46 +0100 Message-ID: <20250507094253.10395-2-freddy77@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250507094253.10395-1-freddy77@gmail.com> References: <20250507094253.10395-1-freddy77@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746611010983019000 Content-Type: text/plain; charset="utf-8" From: Ross Lagerwall In future, some code needs to generate a digest over several separate buffe= rs so export the necessary functions to do so. Signed-off-by: Ross Lagerwall --- xen/include/xen/sha2.h | 12 ++++++++++++ xen/lib/sha2-256.c | 17 ++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/xen/include/xen/sha2.h b/xen/include/xen/sha2.h index 47d97fbf01..cb30e8f8d7 100644 --- a/xen/include/xen/sha2.h +++ b/xen/include/xen/sha2.h @@ -12,4 +12,16 @@ void sha2_256_digest(uint8_t digest[SHA2_256_DIGEST_SIZE], const void *msg, size_t len); =20 +struct sha2_256_state { + uint32_t state[SHA2_256_DIGEST_SIZE / sizeof(uint32_t)]; + uint8_t buf[64]; + size_t count; /* Byte count. */ +}; + +void sha2_256_init(struct sha2_256_state *s); +void sha2_256_update(struct sha2_256_state *s, const void *msg, + size_t len); +void sha2_256_final(struct sha2_256_state *s, + uint8_t digest[SHA2_256_DIGEST_SIZE]); + #endif /* XEN_SHA2_H */ diff --git a/xen/lib/sha2-256.c b/xen/lib/sha2-256.c index 19e8252188..e55e297eff 100644 --- a/xen/lib/sha2-256.c +++ b/xen/lib/sha2-256.c @@ -10,12 +10,6 @@ #include #include =20 -struct sha2_256_state { - uint32_t state[SHA2_256_DIGEST_SIZE / sizeof(uint32_t)]; - uint8_t buf[64]; - size_t count; /* Byte count. */ -}; - static uint32_t choose(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); @@ -131,7 +125,7 @@ static void sha2_256_transform(uint32_t *state, const v= oid *_input) state[4] +=3D e; state[5] +=3D f; state[6] +=3D g; state[7] +=3D h; } =20 -static void sha2_256_init(struct sha2_256_state *s) +void sha2_256_init(struct sha2_256_state *s) { *s =3D (struct sha2_256_state){ .state =3D { @@ -147,8 +141,8 @@ static void sha2_256_init(struct sha2_256_state *s) }; } =20 -static void sha2_256_update(struct sha2_256_state *s, const void *msg, - size_t len) +void sha2_256_update(struct sha2_256_state *s, const void *msg, + size_t len) { unsigned int partial =3D s->count & 63; =20 @@ -177,9 +171,10 @@ static void sha2_256_update(struct sha2_256_state *s, = const void *msg, memcpy(s->buf + partial, msg, len); } =20 -static void sha2_256_final(struct sha2_256_state *s, void *_dst) +void sha2_256_final(struct sha2_256_state *s, + uint8_t digest[SHA2_256_DIGEST_SIZE]) { - uint32_t *dst =3D _dst; + uint32_t *dst =3D (uint32_t *)digest; unsigned int i, partial =3D s->count & 63; =20 /* Start padding */ --=20 2.43.0 From nobody Fri Dec 19 20:18:23 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746611011; cv=none; d=zohomail.com; s=zohoarc; b=m6zIdTzeCeIbSzJ0SxylybYngt61DlrIGjdU2ZwwjzLRn/uAIZIATKUFsJyvvdNNLnpioo2GJCjJ4TbvXdW7qbanUSZmDSz10iw0bNPCY9VVE7sXGshkn1EX8P5k0iWTpOHbQdoOSSdFwGDdT2xkkgm3m7emTxWhJ07T0/PXQTU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746611011; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Oe/MYIRtB4rlJzUi92AgVF2o13CiBT7GoXGbiEvmSqY=; b=WpZBAvIc7Rccl3B7MUu2YrTGQWW1UMjF0OpSUhB1pp9y9OjfSYgiO1guS2N9u4kuPmQDaX6F7Cwr7OTrMKP3kOCsuKP7kKu/cTNYMI5cG2PEbPiKNQmZ+PZOGaP5ksR6iZbzeJt+43/RTjIpDFbY7UOYyHr+2hV8bIHeqhwrTWE= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1746611011555810.636204458204; Wed, 7 May 2025 02:43:31 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.978418.1365229 (Exim 4.92) (envelope-from ) id 1uCbJ5-0006V0-52; Wed, 07 May 2025 09:43:15 +0000 Received: by outflank-mailman (output) from mailman id 978418.1365229; Wed, 07 May 2025 09:43:15 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ5-0006Ur-1b; Wed, 07 May 2025 09:43:15 +0000 Received: by outflank-mailman (input) for mailman id 978418; Wed, 07 May 2025 09:43:13 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ2-00062T-SK for xen-devel@lists.xenproject.org; Wed, 07 May 2025 09:43:12 +0000 Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [2a00:1450:4864:20::32f]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id b04d5aec-2b27-11f0-9ffb-bf95429c2676; Wed, 07 May 2025 11:43:11 +0200 (CEST) Received: by mail-wm1-x32f.google.com with SMTP id 5b1f17b1804b1-43edecbfb46so38224605e9.0 for ; Wed, 07 May 2025 02:43:11 -0700 (PDT) Received: from localhost.localdomain (172.74.6.51.dyn.plus.net. [51.6.74.172]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a099b16f00sm16051290f8f.84.2025.05.07.02.43.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 May 2025 02:43:09 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b04d5aec-2b27-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746610990; x=1747215790; darn=lists.xenproject.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; bh=Oe/MYIRtB4rlJzUi92AgVF2o13CiBT7GoXGbiEvmSqY=; b=CeiKakjF0bHVxKkAH6G2Fu0zmOjxXdp6gxBmbTeDdPrpANN0dy1x8M51AU79invQkz G2aOEE/IV+Fwjd78XDJnJOcwrYNkxzIEO03eufw+ITSmtTocKuu5n5229Y+9YsVNWPFP d7jHsgR10DXpNqWPqKqcFqeJXPIDFteGPLzUlfRrYAw/vCj58uHq53NJW2eXL5fS7jwI EHhl+UH6BaZIDoUVg5snZhJMc74jIH3R6Z/42AsMl+hlAKudzauo3UMUzaIlztexYJz/ lc4CMW5+ssQr9GW5H5bQRIxJ44iExkS3uWwFFbkm6ueXOhce3Z/Bv7JgVSnvAipv7y8l vlJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746610990; x=1747215790; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Oe/MYIRtB4rlJzUi92AgVF2o13CiBT7GoXGbiEvmSqY=; b=FCHgupVt+eSLS8hD3DlhfskG6PC0yJCYc7VZtu/tG14cBXCUSg/xMTp0b3ZumYEYl5 GJUc65vik3zPmD/XW/LhS5acfwV64EumLCVEaIhN+G8TUtbsvoXTHf9EbA2/85+6BE5B Gzo1Hb5ElRJzIxRlt6LbDc0JMA6SyzHVIwgbBsyYVE1nNfZ+zeUEZbxWpEp91i5G/HEL 6Pjr5NZ5psNBlEO09Rq88yskOe6Hrn1nqpGkkgwCcoY61rfTXmrR2Dcob8yuvuvksR/S UkZxOYHfTkUJOtXhLYwx2eR/lLP3O5aF8/mPgVOu4Mggf7AnlhGgxrklx8VdHIVCqZJ8 FBKg== X-Gm-Message-State: AOJu0YzFYD+dO+BfRTZXC/P6Gq8BSlXhJN5w8TPV2NC4wSqlrO/riKN7 94pVfjtm0SjG//wh5giFBP/Tavxf3hgm95v9fw+qtIWlKJ0ZO/5nGeC+HefV4kQ= X-Gm-Gg: ASbGncvaFcJ5/a832DqTCM6oqT5LWsLAFso6jhaCDz99MN3Eq7uMRiYxsU5t6DfBseH uD4dahR6cl5qAL84JwcLxTfQYymaQWKnVXP/5z7v0wsx3Pc3QZNj40IxARDNMjo4QXaOWcTfwtI 0apevf+PtiR3qsuQGcbA6T2UoN7Wt6lIkm7jg4YEcDmHXHsFU/Dq3EOA5UeInxIcjt3xQIYXGVt vOq6v+g0Gd54jXpiVhD3KSuIweg4d46ycXmLWIaTpM5+irwT4nkb4IYFouddZe/6fyJiJgBqUQk fqZurXVXR6rLUB+Vx6l/2l+evOhf2zHOyGfAl+wgv5WWaKGsuVzvRbWXAiFmQvSV43X/KTRZ X-Google-Smtp-Source: AGHT+IHX2EGNIBKnFFgCqJpTyBEHK31aOzzismyK3ci2pQZLueaBc2npHo9DOYf2wTY4GpKQsusXmg== X-Received: by 2002:a05:600c:a409:b0:441:d4e8:76cd with SMTP id 5b1f17b1804b1-441d4e877e1mr15195655e9.29.1746610990080; Wed, 07 May 2025 02:43:10 -0700 (PDT) From: Frediano Ziglio To: xen-devel@lists.xenproject.org Cc: Ross Lagerwall , Jan Beulich , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Anthony PERARD , Michal Orzel , Julien Grall , Stefano Stabellini Subject: [PATCH v2 2/4] kexec: Include purgatory in Xen Date: Wed, 7 May 2025 10:42:47 +0100 Message-ID: <20250507094253.10395-3-freddy77@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250507094253.10395-1-freddy77@gmail.com> References: <20250507094253.10395-1-freddy77@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746611013091116600 Content-Type: text/plain; charset="utf-8" From: Ross Lagerwall Purgatory is a binary that runs between two kernels during kexec. When Secu= re Boot is enabled, it should be signed and verified before being loaded and executed. Currently, purgatory is built as part of kexec-tools and dynamically modifi= ed before being loaded. This prevents signing it at build time. To fix this, b= uild purgatory as a separate object in Xen and modify it at load time in Xen its= elf. This is the same approach used by Linux. No behavioural change with this patch other than the puratory binary being included in Xen. Signed-off-by: Ross Lagerwall --- xen/arch/x86/Makefile | 1 + xen/arch/x86/purgatory/.gitignore | 3 + xen/arch/x86/purgatory/Makefile | 64 +++++++++++++++ xen/arch/x86/purgatory/config.h | 37 +++++++++ xen/arch/x86/purgatory/entry64.S | 108 ++++++++++++++++++++++++++ xen/arch/x86/purgatory/purgatory.c | 59 ++++++++++++++ xen/arch/x86/purgatory/setup-x86_64.S | 63 +++++++++++++++ xen/arch/x86/purgatory/stack.S | 21 +++++ xen/lib/sha2-256.c | 2 +- 9 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 xen/arch/x86/purgatory/.gitignore create mode 100644 xen/arch/x86/purgatory/Makefile create mode 100644 xen/arch/x86/purgatory/config.h create mode 100644 xen/arch/x86/purgatory/entry64.S create mode 100644 xen/arch/x86/purgatory/purgatory.c create mode 100644 xen/arch/x86/purgatory/setup-x86_64.S create mode 100644 xen/arch/x86/purgatory/stack.S diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c2f1dcf301..b3ee871ba1 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -1,6 +1,7 @@ obj-y +=3D acpi/ obj-y +=3D boot/ obj-y +=3D cpu/ +obj-$(CONFIG_KEXEC) +=3D purgatory/ obj-y +=3D efi/ obj-y +=3D genapic/ obj-$(CONFIG_GUEST) +=3D guest/ diff --git a/xen/arch/x86/purgatory/.gitignore b/xen/arch/x86/purgatory/.gi= tignore new file mode 100644 index 0000000000..9353e3ff26 --- /dev/null +++ b/xen/arch/x86/purgatory/.gitignore @@ -0,0 +1,3 @@ +purgatory.chk +kexec-purgatory.S +purgatory.ro diff --git a/xen/arch/x86/purgatory/Makefile b/xen/arch/x86/purgatory/Makef= ile new file mode 100644 index 0000000000..211264e4da --- /dev/null +++ b/xen/arch/x86/purgatory/Makefile @@ -0,0 +1,64 @@ +cc_common_flags =3D -Wall -Os -g0 \ + -nostdinc \ + -mcmodel=3Dlarge \ + -fno-builtin \ + -ffreestanding \ + -fno-zero-initialized-in-bss \ + -fno-stack-protector \ + -fno-PIC \ + -fno-PIE \ + -fno-tree-vectorize \ + -D__XEN__ \ + -D__PURGATORY__ \ + -include $(srctree)/include/xen/config.h \ + -I$(srctree)/$(src) \ + -I$(objtree)/include \ + -I$(srctree)/include \ + -I$(objtree)/arch/x86/include \ + -I$(srctree)/arch/x86/include \ + -I$(objtree)/arch/x86/include/generated + +cmd_cc_purg =3D $(CC) $(cc_common_flags) \ + -c $< -o $@ + +cmd_cc_as_purg =3D $(CC) $(cc_common_flags) \ + -D__ASSEMBLY__ \ + -c $< -o $@ + +cmd_ld_purg =3D $(LD) --no-undefined \ + -z nodefaultlib \ + -z noexecstack \ + -e purgatory_start \ + -S $(real-prereqs) -o $@ + +cmd_ldr_purg =3D $(cmd_ld_purg) -r + +purgatory-y :=3D purgatory.o stack.o setup-x86_64.o sha2-256.o entry64.o m= emcmp.o +PURGATORY_OBJS =3D $(addprefix $(obj)/,$(purgatory-y)) + +$(obj)/%.o: $(src)/%.c $(src)/config.h + $(call if_changed,cc_purg) + +$(obj)/%.o: $(src)/%.S $(src)/config.h + $(call if_changed,cc_as_purg) + +$(obj)/sha2-256.o: $(srctree)/lib/sha2-256.c $(src)/config.h + $(call if_changed,cc_purg) + +$(obj)/memcmp.o: $(srctree)/lib/memcmp.c $(src)/config.h + $(call if_changed,cc_purg) + +$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE + $(call if_changed,ldr_purg) + +$(obj)/purgatory.chk: $(obj)/purgatory.ro FORCE + $(call if_changed,ld_purg) + +$(obj)/kexec-purgatory.o: $(obj)/purgatory.ro $(obj)/purgatory.chk + +$(obj)/kexec-purgatory.S: $(srctree)/tools/binfile FORCE + $(call if_changed,binfile,$(obj)/purgatory.ro kexec_purgatory) + +targets +=3D kexec-purgatory.S + +obj-y +=3D kexec-purgatory.o diff --git a/xen/arch/x86/purgatory/config.h b/xen/arch/x86/purgatory/confi= g.h new file mode 100644 index 0000000000..f1f9f41aad --- /dev/null +++ b/xen/arch/x86/purgatory/config.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (C) 2025 Cloud Software Group Inc. + */ + +#ifndef __PURGATORY_CONFIG_H__ +#define __PURGATORY_CONFIG_H__ + +#define BALIGN(size) .balign size + +#undef ENTRY +#define ENTRY(name) \ + name: + +#define END(name) \ + name##_end: + +#undef GLOBAL +#define GLOBAL(name) \ + .globl name; \ + ENTRY(name) + +#define GLOBAL_END(name) \ + .globl name##_end; \ + END(name) + +#define SYM_T_DATA 1 + +#define ASM_INT(name, val) \ + .type name, SYM_T_DATA; \ + BALIGN(4); \ + .hidden name; \ + GLOBAL(name) \ + .long (val); \ + .size name, . - name + +#endif // __PURGATORY_CONFIG_H__ diff --git a/xen/arch/x86/purgatory/entry64.S b/xen/arch/x86/purgatory/entr= y64.S new file mode 100644 index 0000000000..7256cb6a91 --- /dev/null +++ b/xen/arch/x86/purgatory/entry64.S @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com) + * Copyright (C) 2014 Red Hat Inc. + * Copyright (C) 2025 Cloud Software Group Inc. + + * Author(s): Vivek Goyal + * + * This code has been adapted from kexec-tools and Linux. + */ + +#include "config.h" + + .text + .code64 + +BALIGN(16) +GLOBAL(entry64) + /* Setup a gdt that should be preserved */ + lgdt gdt(%rip) + + /* load the data segments */ + movl $0x18, %eax /* data segment */ + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + /* Setup new stack */ + leaq stack_init(%rip), %rsp + pushq $0x10 /* CS */ + leaq new_cs_exit(%rip), %rax + pushq %rax + lretq +ENTRY(new_cs_exit) + + /* Load the registers */ + movq rax(%rip), %rax + movq rbx(%rip), %rbx + movq rcx(%rip), %rcx + movq rdx(%rip), %rdx + movq rsi(%rip), %rsi + movq rdi(%rip), %rdi + movq rsp(%rip), %rsp + movq rbp(%rip), %rbp + movq r8(%rip), %r8 + movq r9(%rip), %r9 + movq r10(%rip), %r10 + movq r11(%rip), %r11 + movq r12(%rip), %r12 + movq r13(%rip), %r13 + movq r14(%rip), %r14 + movq r15(%rip), %r15 + + /* Jump to the new code... */ + jmpq *rip(%rip) +END(entry64) + + .section ".rodata" + +BALIGN(4) +GLOBAL(entry64_regs) +rax: .quad 0x0 +rbx: .quad 0x0 +rcx: .quad 0x0 +rdx: .quad 0x0 +rsi: .quad 0x0 +rdi: .quad 0x0 +rsp: .quad 0x0 +rbp: .quad 0x0 +r8: .quad 0x0 +r9: .quad 0x0 +r10: .quad 0x0 +r11: .quad 0x0 +r12: .quad 0x0 +r13: .quad 0x0 +r14: .quad 0x0 +r15: .quad 0x0 +rip: .quad 0x0 +END(entry64_regs) + .size entry64_regs, entry64_regs_end - entry64_regs + + /* GDT */ + .section ".rodata" + +BALIGN(16) +ENTRY(gdt) + /* + * 0x00 unusable segment + * 0x08 unused + * so use them as gdt ptr + */ + .word gdt_end - gdt - 1 + .quad gdt + .word 0, 0, 0 + + /* 0x10 4GB flat code segment */ + .word 0xFFFF, 0x0000, 0x9A00, 0x00AF + + /* 0x18 4GB flat data segment */ + .word 0xFFFF, 0x0000, 0x9200, 0x00CF +END(gdt) + +ENTRY(stack) + .quad 0, 0 +END(stack) +ENTRY(stack_init) diff --git a/xen/arch/x86/purgatory/purgatory.c b/xen/arch/x86/purgatory/pu= rgatory.c new file mode 100644 index 0000000000..8b9a3cdb11 --- /dev/null +++ b/xen/arch/x86/purgatory/purgatory.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * purgatory: Runs between two kernels + * + * Copyright (C) 2014 Red Hat Inc. + * Copyright (C) 2025 Cloud Software Group Inc. + * + * Author: + * Vivek Goyal + * + * This code has been imported from kexec-tools. + */ + +#include +#include + +struct sha256_region { + uint64_t start; + uint64_t len; +}; + +typedef uint8_t sha256_digest_t[SHA2_256_DIGEST_SIZE]; + +#define SHA256_REGIONS 16 + +struct sha256_region sha256_regions[SHA256_REGIONS] =3D {}; +sha256_digest_t sha256_digest =3D { }; + +int verify_sha256_digest(void) +{ + struct sha256_region *ptr, *end; + sha256_digest_t digest; + struct sha2_256_state ctx; + sha2_256_init(&ctx); + end =3D &sha256_regions[sizeof(sha256_regions) / sizeof(sha256_regions= [0])]; + + for ( ptr =3D sha256_regions; ptr < end; ptr++ ) + sha2_256_update(&ctx, (uint8_t *)((uintptr_t)ptr->start), ptr->len= ); + + sha2_256_final(&ctx, digest); + + if ( memcmp(digest, sha256_digest, sizeof(digest)) !=3D 0 ) + return 1; + + return 0; +} + +void purgatory(void) +{ + int ret; + + ret =3D verify_sha256_digest(); + if ( ret ) + { + /* loop forever */ + for ( ; ; ) + ; + } +} diff --git a/xen/arch/x86/purgatory/setup-x86_64.S b/xen/arch/x86/purgatory= /setup-x86_64.S new file mode 100644 index 0000000000..c36be25656 --- /dev/null +++ b/xen/arch/x86/purgatory/setup-x86_64.S @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * purgatory: setup code + * + * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com) + * Copyright (C) 2014 Red Hat Inc. + * Copyright (C) 2025 Cloud Software Group Inc. + * + * This code has been adapted from kexec-tools and Linux. + */ + +#include "config.h" + + .text + .code64 + +BALIGN(16) +GLOBAL(purgatory_start) + + /* Load a gdt so I know what the segment registers are */ + lgdt gdt(%rip) + + /* load the data segments */ + movl $0x18, %eax /* data segment */ + movl %eax, %ds + movl %eax, %es + movl %eax, %ss + movl %eax, %fs + movl %eax, %gs + + /* Setup a stack */ + leaq lstack_end(%rip), %rsp + + /* Call the C code */ + call purgatory + jmp entry64 +END(purgatory_start) + + .section ".rodata" + +BALIGN(16) +ENTRY(gdt) + /* 0x00 unusable segment + * 0x08 unused + * so use them as the gdt ptr + */ + .word gdt_end - gdt - 1 + .quad gdt + .word 0, 0, 0 + + /* 0x10 4GB flat code segment */ + .word 0xFFFF, 0x0000, 0x9A00, 0x00AF + + /* 0x18 4GB flat data segment */ + .word 0xFFFF, 0x0000, 0x9200, 0x00CF +END(gdt) + + .bss + +BALIGN(4096) +ENTRY(lstack) + .skip 4096 +END(lstack) diff --git a/xen/arch/x86/purgatory/stack.S b/xen/arch/x86/purgatory/stack.S new file mode 100644 index 0000000000..6ac7685cd5 --- /dev/null +++ b/xen/arch/x86/purgatory/stack.S @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * purgatory: stack + * + * Copyright (C) 2014 Red Hat Inc. + * Copyright (C) 2025 Cloud Software Group Inc. + * + * This code has been adapted from kexec-tools and Linux. + */ + +#include "config.h" + + /* A stack for the loaded kernel. + * Separate and in the data section so it can be prepopulated. + */ + .data + +BALIGN(4096) +GLOBAL(stack) + .skip 4096 +GLOBAL_END(stack) diff --git a/xen/lib/sha2-256.c b/xen/lib/sha2-256.c index e55e297eff..09c033f97f 100644 --- a/xen/lib/sha2-256.c +++ b/xen/lib/sha2-256.c @@ -209,7 +209,7 @@ void sha2_256_digest(uint8_t digest[SHA2_256_DIGEST_SIZ= E], sha2_256_final(&s, digest); } =20 -#ifdef CONFIG_SELF_TESTS +#if defined(CONFIG_SELF_TESTS) && !defined(__PURGATORY__) =20 #include #include --=20 2.43.0 From nobody Fri Dec 19 20:18:23 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746611018; cv=none; d=zohomail.com; s=zohoarc; b=N9jW8nIVxw7OUkxx73ySw7Ua3XJGCAJmVr6vu4Mo2shHR7UqVgzwJe53Ww9IhjTvGxAMil7m/lEDYBmElMGCEa8Jp6BI+9n4R1erR+8bZzcE3bAIIiDRwYzNU5P1O+L+QIh1WVRcBSDdIvNIkjFRbKZJE9Wy2nXqqkzKQsc7XQc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746611018; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=GvgGQEXxmwdDOq95Q9FxVo61JDyQYafFqqrzIkZ3gxA=; b=l95yg1zzVwes3BsbctZhbUYEu0m8/UVGp5qeoFhJqjr05zkWM+th5d9TUCZAR9CdnorK7J8Ur527H3jn7gP81OCSQH6SOnc7rnlI0Z2zzTiskWYojEvb/41W9Smssgh9bkXDlrLAOCqZwxLiIvo4BUGloby6YAcasNW+avmSd1w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1746611018076859.5488130238034; Wed, 7 May 2025 02:43:38 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.978419.1365239 (Exim 4.92) (envelope-from ) id 1uCbJ6-0006kp-K2; Wed, 07 May 2025 09:43:16 +0000 Received: by outflank-mailman (output) from mailman id 978419.1365239; Wed, 07 May 2025 09:43:16 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ6-0006kg-Fe; Wed, 07 May 2025 09:43:16 +0000 Received: by outflank-mailman (input) for mailman id 978419; Wed, 07 May 2025 09:43:15 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ4-00062T-OT for xen-devel@lists.xenproject.org; Wed, 07 May 2025 09:43:14 +0000 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [2a00:1450:4864:20::42b]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id b132f369-2b27-11f0-9ffb-bf95429c2676; Wed, 07 May 2025 11:43:12 +0200 (CEST) Received: by mail-wr1-x42b.google.com with SMTP id ffacd0b85a97d-39c1ef4ae3aso467418f8f.1 for ; Wed, 07 May 2025 02:43:12 -0700 (PDT) Received: from localhost.localdomain (172.74.6.51.dyn.plus.net. [51.6.74.172]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a099b16f00sm16051290f8f.84.2025.05.07.02.43.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 May 2025 02:43:10 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b132f369-2b27-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746610992; x=1747215792; darn=lists.xenproject.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; bh=GvgGQEXxmwdDOq95Q9FxVo61JDyQYafFqqrzIkZ3gxA=; b=GJUr5YVICfDhbq8NYkdyET4oegEDXH7eSo9zI9dnFl7pZAb4F68qD/vXSEb2L/0KTy hkhWbVs/RObjs5QdSbHjHzbOUa0YKJ53C/0VOA321KXRXFq5TUCJnxiTtyFGBcXyd8Ay ThxENbMAA3yp0o9XJqLRw7Wd7eZKKDJFVFCHU7w3KcWI4iZPo0SOTHiU5LQxLlTgyEQX 3tcl767J6cNXaGLIFULQfpYWRK1RrwrSMXmDWbICaMPkRiuhgj87rIC1Qec+Se8kmp5k jcDXQpmA3IHYGDQUq064Yby7r54E2wqfnW1LCh8jvhVgwd7uGQZaGgyjwsJaNlsGR8nw 4Ong== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746610992; x=1747215792; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GvgGQEXxmwdDOq95Q9FxVo61JDyQYafFqqrzIkZ3gxA=; b=qXdUOJDQ3YYCxpVXS85CLsHL33vYRPrrVCBgzHicXAI8AQSjPnCYVxoQo2D/1PXRbI EQwswBHh7c1fdi6lU1D2EB8crLGskXb2YRRBWBRaYMU8vOdQFEylqo0MkPmSkUXOENzg OT3ulniwDGONNuorGLNWd/ui5UabthCTn6AboccxSoHV5hh0/sfTsUpbfAv84v8svD7L 4ZXU3sFYzwMOP2UHQ5WdHsaPILTT4NZUyLGStUMVlB/bUdpg+QX5Rgrhbr+iIcZDcfiB V1+NEfcl6FXctIBcmcPSDYSK1FT84C51AjGs7pAqpSdYREWrqbQqAgmACV/OlzNMAlOH UHRQ== X-Gm-Message-State: AOJu0YxAh7qopIC92o70V929Lef03LtvyqQcbD8l1tYk3W1vB9xy89r9 1WeTNv7xRHoEbZPUbdcgu2EkUViaNXQSP6zSRK0Q/meKKPmQ0j8lNT7FUz85NGY= X-Gm-Gg: ASbGncvA3+Q8rRzAfrUes+tTXyUc7h7gplBHKdtBc8zOc1tWRUH3c0hly5DKsMUJu6p jgdO4haYXuoJgLziLq5iiyxVxqRJXnjiHS2oW5kqhvzMlIUsuXHuaTkW1A0WMyMcrKrf4IDuH1I 8FAx2SmnKy1nkx7v0HfVunFyS7eRey6nVfFxVQEphs2W30pZZUeVgq2skIbid2sPWQAsarCBGvG sIUl2KVykSsGRk1DDG8iBjVCfG+rwXPSYOQS+xyl4TG4D6affQxZxp8mMaQbnWKmaZ2DL34d+ur zokA+9fi+Pl43UKUoKdq4kw0h+QFdJhs/zLNeDLY5hKTvhFZZArmIRg9QoaZGH5/mJmFBmAb X-Google-Smtp-Source: AGHT+IG03r2HP1/gVZCiODuvJ0+xqiZYzO8vzfAdMNoeAaGrDhDDyDdYFGV8qSz1Qjj4fx9nzwU9/w== X-Received: by 2002:a5d:5885:0:b0:3a0:9dda:c2e2 with SMTP id ffacd0b85a97d-3a0b53eb0b8mr2170979f8f.22.1746610991521; Wed, 07 May 2025 02:43:11 -0700 (PDT) From: Frediano Ziglio To: xen-devel@lists.xenproject.org Cc: Ross Lagerwall , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Andrew Cooper , Anthony PERARD , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Gerald Elder-Vass Subject: [PATCH v2 3/4] kexec: Implement new EFI load types Date: Wed, 7 May 2025 10:42:48 +0100 Message-ID: <20250507094253.10395-4-freddy77@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250507094253.10395-1-freddy77@gmail.com> References: <20250507094253.10395-1-freddy77@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746611019481019000 Content-Type: text/plain; charset="utf-8" From: Ross Lagerwall Add two new EFI load types for kexec. These load types are suitable for use when Secure Boot is enabled. When these load types are used, the caller should not pass purgatory as one= of the kexec segments. Instead, Xen will prepare and supply purgatory itself. Preparing purgatory involves loading it, applying relocations, and calculat= ing and embedding the checksums of the segments. Signed-off-by: Ross Lagerwall Signed-off-by: Gerald Elder-Vass --- xen/arch/arm/Makefile | 1 + xen/arch/arm/kexec.c | 27 ++ xen/arch/x86/Makefile | 1 + xen/arch/x86/bzimage.c | 40 +-- xen/arch/x86/kexec.c | 125 +++++++ xen/common/Kconfig | 1 + xen/common/kexec.c | 10 + xen/common/kimage.c | 632 +++++++++++++++++++++++++++++++++++- xen/include/public/kexec.h | 23 +- xen/include/xen/kimage.h | 42 +++ xen/include/xen/x86-linux.h | 62 ++++ 11 files changed, 908 insertions(+), 56 deletions(-) create mode 100644 xen/arch/arm/kexec.c create mode 100644 xen/arch/x86/kexec.c create mode 100644 xen/include/xen/x86-linux.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 129a109d6e..0e652d9594 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -36,6 +36,7 @@ obj-y +=3D io.o obj-$(CONFIG_IOREQ_SERVER) +=3D ioreq.o obj-y +=3D irq.o obj-y +=3D kernel.init.o +obj-$(CONFIG_KEXEC) +=3D kexec.o obj-$(CONFIG_LIVEPATCH) +=3D livepatch.o obj-$(CONFIG_LLC_COLORING) +=3D llc-coloring.o obj-$(CONFIG_VM_EVENT) +=3D mem_access.o diff --git a/xen/arch/arm/kexec.c b/xen/arch/arm/kexec.c new file mode 100644 index 0000000000..f8847e16e0 --- /dev/null +++ b/xen/arch/arm/kexec.c @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2025, Cloud Software Group + */ + +#include +#include +#include +#include + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, const Elf_Shdr *re= lsec, + const Elf_Shdr *symtabsec) +{ + return -ENOSYS; +} + + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index b3ee871ba1..6b11364150 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -42,6 +42,7 @@ obj-y +=3D hypercall.o obj-y +=3D i387.o obj-y +=3D i8259.o obj-y +=3D io_apic.o +obj-$(CONFIG_KEXEC) +=3D kexec.o obj-$(CONFIG_LIVEPATCH) +=3D alternative.o livepatch.o obj-y +=3D msi.o obj-y +=3D msr.o diff --git a/xen/arch/x86/bzimage.c b/xen/arch/x86/bzimage.c index 66f648f311..f4d5b584cb 100644 --- a/xen/arch/x86/bzimage.c +++ b/xen/arch/x86/bzimage.c @@ -6,6 +6,7 @@ #include #include #include +#include #include =20 static __init unsigned long output_length(void *image, unsigned long image= _len) @@ -13,45 +14,6 @@ static __init unsigned long output_length(void *image, u= nsigned long image_len) return *(uint32_t *)(image + image_len - 4); } =20 -struct __packed setup_header { - uint8_t _pad0[0x1f1]; /* skip uninteresting stuf= f */ - uint8_t setup_sects; - uint16_t root_flags; - uint32_t syssize; - uint16_t ram_size; - uint16_t vid_mode; - uint16_t root_dev; - uint16_t boot_flag; - uint16_t jump; - uint32_t header; -#define HDR_MAGIC "HdrS" -#define HDR_MAGIC_SZ 4 - uint16_t version; -#define VERSION(h,l) (((h)<<8) | (l)) - uint32_t realmode_swtch; - uint16_t start_sys; - uint16_t kernel_version; - uint8_t type_of_loader; - uint8_t loadflags; - uint16_t setup_move_size; - uint32_t code32_start; - uint32_t ramdisk_image; - uint32_t ramdisk_size; - uint32_t bootsect_kludge; - uint16_t heap_end_ptr; - uint16_t _pad1; - uint32_t cmd_line_ptr; - uint32_t initrd_addr_max; - uint32_t kernel_alignment; - uint8_t relocatable_kernel; - uint8_t _pad2[3]; - uint32_t cmdline_size; - uint32_t hardware_subarch; - uint64_t hardware_subarch_data; - uint32_t payload_offset; - uint32_t payload_length; - }; - static __init int bzimage_check(struct setup_header *hdr, unsigned long le= n) { if ( len < sizeof(struct setup_header) ) diff --git a/xen/arch/x86/kexec.c b/xen/arch/x86/kexec.c new file mode 100644 index 0000000000..5ce70af06d --- /dev/null +++ b/xen/arch/x86/kexec.c @@ -0,0 +1,125 @@ +/* + * SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2025, Cloud Software Group + * + * Parts have been derived from Linux's arch/x86/kernel/machine_kexec_64.c + */ + +#include +#include +#include +#include + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, const Elf_Shdr *re= lsec, + const Elf_Shdr *symtabsec) +{ + unsigned int i; + Elf64_Rela *rel; + Elf64_Sym *sym; + void *location; + unsigned long address, sec_base, value; + const char *strtab, *name, *shstrtab; + const Elf_Shdr *sechdrs; + const Elf_Ehdr *ehdr =3D (const Elf_Ehdr *)kexec_purgatory; + + /* String & section header string table */ + sechdrs =3D (void *)ehdr + ehdr->e_shoff; + strtab =3D (char *)ehdr + sechdrs[symtabsec->sh_link].sh_offset; + shstrtab =3D (char *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; + + rel =3D (void *)ehdr + relsec->sh_offset; + + dprintk(XENLOG_DEBUG, "Applying relocate section %s to %u\n", + shstrtab + relsec->sh_name, relsec->sh_info); + + for ( i =3D 0; i < relsec->sh_size / sizeof(*rel); i++) { + + /* + * rel[i].r_offset contains byte offset from beginning + * of section to the storage unit affected. + * + * This is location to update. This is temporary buffer + * where section is currently loaded. This will finally be + * loaded to a different address later, pointed to by + * ->sh_addr. kimage_purgatory_move takes care of moving it + */ + location =3D pi->buffer; + location +=3D section->sh_offset; + location +=3D rel[i].r_offset; + + /* Final address of the location */ + address =3D section->sh_addr + rel[i].r_offset; + + /* + * rel[i].r_info contains information about symbol table index + * w.r.t which relocation must be made and type of relocation + * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get + * these respectively. + */ + sym =3D (void *)ehdr + symtabsec->sh_offset; + sym +=3D ELF64_R_SYM(rel[i].r_info); + + if ( sym->st_name ) + name =3D strtab + sym->st_name; + else + name =3D shstrtab + sechdrs[sym->st_shndx].sh_name; + + dprintk(XENLOG_DEBUG, "Symbol: %s info: %02x shndx: %02x value=3D%= lx size: %lx\n", + name, sym->st_info, sym->st_shndx, sym->st_value, + sym->st_size); + + if ( sym->st_shndx =3D=3D SHN_UNDEF ) { + printk("Undefined symbol: %s\n", name); + return -ENOEXEC; + } + + if ( sym->st_shndx =3D=3D SHN_COMMON ) { + printk("symbol '%s' in common section\n", name); + return -ENOEXEC; + } + + if ( sym->st_shndx =3D=3D SHN_ABS ) + sec_base =3D 0; + else if ( sym->st_shndx >=3D ehdr->e_shnum ) { + printk("Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } else + sec_base =3D pi->sechdrs[sym->st_shndx].sh_addr; + + value =3D sym->st_value; + value +=3D sec_base; + value +=3D rel[i].r_addend; + + switch ( ELF64_R_TYPE(rel[i].r_info) ) { + case R_X86_64_NONE: + break; + case R_X86_64_64: + *(u64 *)location =3D value; + break; + case R_X86_64_PC32: + case R_X86_64_PLT32: + value -=3D (u64)address; + *(u32 *)location =3D value; + break; + default: + printk("Unknown rela relocation: %lu\n", + ELF64_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} + + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 4bec78c6f2..674c2bace1 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -318,6 +318,7 @@ config KEXEC bool "kexec support" default y depends on HAS_KEXEC + select CRYPTO help Allows a running Xen hypervisor to be replaced with another OS without rebooting. This is primarily used to execute a crash diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 84fe8c3597..158f8da6fd 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -1132,6 +1132,16 @@ static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) u= arg) if ( ret < 0 ) goto error; =20 + if ( load.type =3D=3D KEXEC_TYPE_DEFAULT_EFI || + load.type =3D=3D KEXEC_TYPE_CRASH_EFI ) + { + ret =3D kimage_setup_purgatory(kimage, load.parameters); + if (ret) + return ret; + } + + kimage_terminate(kimage); + ret =3D kexec_load_slot(kimage); if ( ret < 0 ) goto error; diff --git a/xen/common/kimage.c b/xen/common/kimage.c index 9961eac187..212f5bd068 100644 --- a/xen/common/kimage.c +++ b/xen/common/kimage.c @@ -19,10 +19,23 @@ #include #include #include +#include #include +#include +#include +#include =20 #include =20 +#define KIMAGE_SHA256_REGIONS 16 + +typedef struct +{ + uint64_t start; + uint64_t len; +} +sha256_region_t; + /* * When kexec transitions to the new kernel there is a one-to-one * mapping between physical and virtual addresses. On processors @@ -214,17 +227,12 @@ static int kimage_normal_alloc(struct kexec_image **r= image, paddr_t entry, KEXEC_TYPE_DEFAULT); } =20 -static int kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry, - unsigned long nr_segments, - xen_kexec_segment_t *segments) +static int do_kimage_crash_alloc(struct kexec_image **rimage, paddr_t entr= y, + unsigned long nr_segments, + xen_kexec_segment_t *segments) { unsigned long i; =20 - /* Verify we have a valid entry point */ - if ( (entry < kexec_crash_area.start) - || (entry > kexec_crash_area.start + kexec_crash_area.size)) - return -EADDRNOTAVAIL; - /* * Verify we have good destination addresses. Normally * the caller is responsible for making certain we don't @@ -254,6 +262,25 @@ static int kimage_crash_alloc(struct kexec_image **rim= age, paddr_t entry, KEXEC_TYPE_CRASH); } =20 +static int kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry, + unsigned long nr_segments, + xen_kexec_segment_t *segments) +{ + /* Verify we have a valid entry point */ + if ( (entry < kexec_crash_area.start) + || (entry > kexec_crash_area.start + kexec_crash_area.size)) + return -EADDRNOTAVAIL; + + return do_kimage_crash_alloc(rimage, entry, nr_segments, segments); +} + +static int kimage_crash_alloc_efi(struct kexec_image **rimage, paddr_t ent= ry, + unsigned long nr_segments, + xen_kexec_segment_t *segments) +{ + return do_kimage_crash_alloc(rimage, entry, nr_segments, segments); +} + static int kimage_is_destination_range(struct kexec_image *image, paddr_t start, paddr_t end) @@ -476,7 +503,7 @@ static void kimage_free_extra_pages(struct kexec_image = *image) kimage_free_page_list(&image->unusable_pages); } =20 -static void kimage_terminate(struct kexec_image *image) +void kimage_terminate(struct kexec_image *image) { kimage_entry_t *entries; =20 @@ -542,6 +569,8 @@ void kimage_free(struct kexec_image *image) kimage_free_all_entries(image); kimage_free_page_list(&image->control_pages); xfree(image->segments); + xfree(image->pi.buffer); + xfree(image->pi.sechdrs); xfree(image); } =20 @@ -748,7 +777,8 @@ static int kimage_load_crash_segment(struct kexec_image= *image, if ( !dest_va ) return -EINVAL; =20 - ret =3D copy_from_guest_offset(dest_va, segment->buf.h, src_offset= , schunk); + ret =3D copy_from_guest_offset(dest_va, segment->buf.h, + src_offset, schunk); memset(dest_va + schunk, 0, dchunk - schunk); =20 unmap_domain_page(dest_va); @@ -764,7 +794,8 @@ static int kimage_load_crash_segment(struct kexec_image= *image, return 0; } =20 -static int kimage_load_segment(struct kexec_image *image, xen_kexec_segmen= t_t *segment) +static int kimage_load_segment(struct kexec_image *image, + xen_kexec_segment_t *segment) { int result =3D -ENOMEM; paddr_t addr; @@ -802,11 +833,16 @@ int kimage_alloc(struct kexec_image **rimage, uint8_t= type, uint16_t arch, switch( type ) { case KEXEC_TYPE_DEFAULT: + case KEXEC_TYPE_DEFAULT_EFI: result =3D kimage_normal_alloc(rimage, entry_maddr, nr_segments, s= egment); break; case KEXEC_TYPE_CRASH: result =3D kimage_crash_alloc(rimage, entry_maddr, nr_segments, se= gment); break; + case KEXEC_TYPE_CRASH_EFI: + result =3D kimage_crash_alloc_efi(rimage, entry_maddr, + nr_segments, segment); + break; default: result =3D -EINVAL; break; @@ -829,7 +865,6 @@ int kimage_load_segments(struct kexec_image *image) if ( result < 0 ) return result; } - kimage_terminate(image); return 0; } =20 @@ -938,6 +973,579 @@ done: return ret; } =20 +static int kimage_purgatory_alloc(struct kexec_image *image) +{ + const Elf_Ehdr *ehdr =3D (const Elf_Ehdr *)kexec_purgatory; + const Elf_Shdr *sechdrs; + unsigned long bss_align; + unsigned long bss_sz; + unsigned long align; + int i; + struct purgatory_info *pi =3D &image->pi; + + dprintk(XENLOG_DEBUG, "purgatory_alloc 0x%lx 0x%lx %u\n", + (unsigned long)kexec_purgatory, (unsigned long)ehdr, + kexec_purgatory_size); + + sechdrs =3D (void *)ehdr + ehdr->e_shoff; + pi->buf_align =3D bss_align =3D 1; + pi->bufsz =3D bss_sz =3D 0; + + for ( i =3D 0; i < ehdr->e_shnum; i++ ) { + if ( !(sechdrs[i].sh_flags & SHF_ALLOC) ) + continue; + + align =3D sechdrs[i].sh_addralign; + if ( sechdrs[i].sh_type !=3D SHT_NOBITS ) { + if ( pi->buf_align < align ) + pi->buf_align =3D align; + pi->bufsz =3D ROUNDUP(pi->bufsz, align); + pi->bufsz +=3D sechdrs[i].sh_size; + } else { + if ( bss_align < align ) + bss_align =3D align; + bss_sz =3D ROUNDUP(bss_sz, align); + bss_sz +=3D sechdrs[i].sh_size; + } + } + pi->bufsz =3D ROUNDUP(pi->bufsz, bss_align); + pi->memsz =3D pi->bufsz + bss_sz; + if ( pi->buf_align < bss_align ) + pi->buf_align =3D bss_align; + + pi->buffer =3D xzalloc_bytes(pi->bufsz); + if ( !pi->buffer ) + return -ENOMEM; + + return 0; +} + +static int kimage_purgatory_copy(struct kexec_image *image) +{ + unsigned long bss_addr; + unsigned long offset; + unsigned long align; + size_t sechdrs_size; + Elf_Shdr *sechdrs; + int i; + struct purgatory_info *pi =3D &image->pi; + const Elf_Ehdr *ehdr =3D (const Elf_Ehdr *)kexec_purgatory; + const char *shstrtab; + + /* + * The section headers in kexec_purgatory are read-only. In order to + * have them modifiable make a temporary copy. + */ + sechdrs_size =3D sizeof(Elf_Shdr) * ehdr->e_shnum; + sechdrs =3D xmalloc_bytes(sechdrs_size); + if ( !sechdrs ) + return -ENOMEM; + + memcpy(sechdrs, (void *)ehdr + ehdr->e_shoff, sechdrs_size); + pi->sechdrs =3D sechdrs; + + shstrtab =3D (char *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset; + + offset =3D 0; + bss_addr =3D pi->dest + pi->bufsz; + image->entry_maddr =3D ehdr->e_entry; + + for ( i =3D 0; i < ehdr->e_shnum; i++ ) { + if ( !(sechdrs[i].sh_flags & SHF_ALLOC) ) + continue; + + align =3D sechdrs[i].sh_addralign; + if ( sechdrs[i].sh_type =3D=3D SHT_NOBITS ) { + bss_addr =3D ROUNDUP(bss_addr, align); + sechdrs[i].sh_addr =3D bss_addr; + bss_addr +=3D sechdrs[i].sh_size; + continue; + } + + offset =3D ROUNDUP(offset, align); + + if ( sechdrs[i].sh_flags & SHF_EXECINSTR && + ehdr->e_entry >=3D sechdrs[i].sh_addr && + ehdr->e_entry < (sechdrs[i].sh_addr + sechdrs[i].sh_size) = ) { + BUG_ON(image->entry_maddr !=3D ehdr->e_entry); + image->entry_maddr -=3D sechdrs[i].sh_addr; + image->entry_maddr +=3D pi->dest + offset; + } + + memcpy(pi->buffer + offset, + (void *)ehdr + sechdrs[i].sh_offset, + sechdrs[i].sh_size); + + sechdrs[i].sh_addr =3D pi->dest + offset; + sechdrs[i].sh_offset =3D offset; + offset +=3D sechdrs[i].sh_size; + + dprintk(XENLOG_DEBUG, "Load %s at 0x%08lx\n", + shstrtab + sechdrs[i].sh_name, sechdrs[i].sh_addr); + } + + dprintk(XENLOG_DEBUG, "image entry maddr 0x%lx\n", image->entry_maddr); + + return 0; +} + +static int kimage_purgatory_apply_relocations(struct kexec_image *image) +{ + const Elf_Ehdr *ehdr =3D (const Elf_Ehdr *)kexec_purgatory; + int i, ret; + struct purgatory_info *pi =3D &image->pi; + const Elf_Shdr *sechdrs; + + sechdrs =3D (void *)ehdr + ehdr->e_shoff; + + for ( i =3D 0; i < ehdr->e_shnum; i++ ) { + const Elf_Shdr *relsec; + const Elf_Shdr *symtab; + Elf_Shdr *section; + + relsec =3D sechdrs + i; + + if ( relsec->sh_type !=3D SHT_RELA && + relsec->sh_type !=3D SHT_REL ) + continue; + + /* + * For section of type SHT_RELA/SHT_REL, + * ->sh_link contains section header index of associated + * symbol table. And ->sh_info contains section header + * index of section to which relocations apply. + */ + if ( relsec->sh_info >=3D ehdr->e_shnum || + relsec->sh_link >=3D ehdr->e_shnum ) + return -ENOEXEC; + + section =3D pi->sechdrs + relsec->sh_info; + symtab =3D sechdrs + relsec->sh_link; + + if ( !(section->sh_flags & SHF_ALLOC) ) + continue; + + /* + * symtab->sh_link contain section header index of associated + * string table. + */ + if ( symtab->sh_link >=3D ehdr->e_shnum ) + /* Invalid section number? */ + continue; + + /* + * Respective architecture needs to provide support for applying + * relocations of type SHT_RELA. + */ + if ( relsec->sh_type =3D=3D SHT_RELA ) + ret =3D arch_kexec_apply_relocations_add(pi, section, + relsec, symtab); + else if ( relsec->sh_type =3D=3D SHT_REL ) + ret =3D -ENOEXEC; + if ( ret ) + return ret; + } + + return 0; +} + +static const Elf_Sym *kimage_purgatory_find_symbol(const char *name) +{ + const Elf_Shdr *sechdrs; + const Elf_Ehdr *ehdr =3D (const Elf_Ehdr *)kexec_purgatory; + const Elf_Sym *syms; + const char *strtab; + int i, k; + + sechdrs =3D (void *)ehdr + ehdr->e_shoff; + + for ( i =3D 0; i < ehdr->e_shnum; i++ ) { + if ( sechdrs[i].sh_type !=3D SHT_SYMTAB ) + continue; + + if ( sechdrs[i].sh_link >=3D ehdr->e_shnum ) + /* Invalid strtab section number */ + continue; + + strtab =3D (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset; + syms =3D (void *)ehdr + sechdrs[i].sh_offset; + + /* Go through symbols for a match */ + for ( k =3D 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++ ) { + if ( ELF_ST_BIND(syms[k].st_info) !=3D STB_GLOBAL ) + continue; + + if ( strcmp(strtab + syms[k].st_name, name) !=3D 0 ) + continue; + + if ( syms[k].st_shndx =3D=3D SHN_UNDEF || + syms[k].st_shndx >=3D ehdr->e_shnum ) { + printk("Symbol: %s has bad section index %d.\n", + name, syms[k].st_shndx); + return NULL; + } + + /* Found the symbol we are looking for */ + return &syms[k]; + } + } + + return NULL; +} + +static int kimage_purgatory_get_symbol_addr(struct kexec_image *image, + const char *name, void **addr) +{ + struct purgatory_info *pi =3D &image->pi; + const Elf_Sym *sym; + Elf_Shdr *sechdr; + + sym =3D kimage_purgatory_find_symbol(name); + if ( !sym ) + return -EINVAL; + + sechdr =3D &pi->sechdrs[sym->st_shndx]; + + /* + * Update addr with the address where symbol will finally be loaded af= ter + * kimage_purgatory_move() + */ + *addr =3D (void *)(sechdr->sh_addr + sym->st_value); + return 0; +} + +/* + * Get or set value of a symbol. If "get_value" is true, symbol value is + * returned in buf otherwise symbol value is set based on value in buf. + */ +static int kimage_purgatory_get_set_symbol(struct kexec_image *image, cons= t char *name, + void *buf, unsigned int size, bool get_value) +{ + struct purgatory_info *pi =3D &image->pi; + const Elf_Sym *sym; + Elf_Shdr *sec; + char *sym_buf; + + sym =3D kimage_purgatory_find_symbol(name); + if ( !sym ) + return -EINVAL; + + if ( sym->st_size !=3D size ) { + printk("symbol %s size mismatch: expected %lu actual %u\n", + name, (unsigned long)sym->st_size, size); + return -EINVAL; + } + + sec =3D pi->sechdrs + sym->st_shndx; + + if ( sec->sh_type =3D=3D SHT_NOBITS ) { + printk("symbol %s is in a bss section. Cannot %s\n", name, + get_value ? "get" : "set"); + return -EINVAL; + } + + sym_buf =3D (char *)pi->buffer + sec->sh_offset + sym->st_value; + + if ( get_value ) + memcpy((void *)buf, sym_buf, size); + else + memcpy((void *)sym_buf, buf, size); + + return 0; +} + +static int kimage_purgatory_find_hole(struct kexec_image *image) +{ + paddr_t hole_start, hole_end, mstart, mend; + struct purgatory_info *pi =3D &image->pi; + unsigned long i; + + pi->dest =3D 0; + hole_start =3D PAGE_ALIGN(image->next_crash_page); + hole_end =3D hole_start + pi->memsz; + while ( hole_end <=3D kexec_crash_area.start + kexec_crash_area.size ) + { + /* See if the hole overlaps any of the segments. */ + for ( i =3D 0; i < image->nr_segments; i++ ) + { + mstart =3D image->segments[i].dest_maddr; + mend =3D mstart + image->segments[i].dest_size; + if ( (hole_end > mstart) && (hole_start < mend) ) + { + /* Advance the hole to the end of the segment. */ + hole_start =3D PAGE_ALIGN(mend); + hole_end =3D hole_start + pi->memsz; + break; + } + } + + /* If the hole doesn't overlap any segments I have found my hole! = */ + if ( i =3D=3D image->nr_segments && + hole_end <=3D kexec_crash_area.start + kexec_crash_area.size ) + { + pi->dest =3D hole_start; + image->next_crash_page =3D PAGE_ALIGN(hole_end); + break; + } + } + + return pi->dest; +} + +/* Load purgatory as an ELF binary and relocate it. */ +static int kimage_load_purgatory_image(struct kexec_image *image) +{ + int ret; + + ret =3D kimage_purgatory_alloc(image); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_find_hole(image); + if ( !ret ) + return -ENOMEM; + + ret =3D kimage_purgatory_copy(image); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_apply_relocations(image); + if ( ret ) + return ret; + + return 0; +} + +/* + * Update the loaded purgatory with the digest and locations of the segmen= ts. + */ +static int kimage_purgatory_calc_one_digest(struct sha2_256_state *ctx, + struct kimage_segment *segment) +{ + paddr_t dest; + unsigned long sbytes; + unsigned int dest_offset; + int ret =3D 0; + + sbytes =3D segment->buf_size; + dest =3D segment->dest_maddr + segment->dest_offset; + dest_offset =3D segment->dest_offset; + + while ( sbytes ) + { + unsigned long dest_mfn; + void *dest_va; + size_t schunk, dchunk; + + dest_mfn =3D dest >> PAGE_SHIFT; + + dchunk =3D PAGE_SIZE - dest_offset; + schunk =3D min(dchunk, sbytes); + + dest_va =3D map_domain_page(_mfn(dest_mfn)); + if ( !dest_va ) + return -EINVAL; + + sha2_256_update(ctx, dest_va + dest_offset, schunk); + + unmap_domain_page(dest_va); + if ( ret ) + return -EFAULT; + + sbytes -=3D schunk; + dest +=3D dchunk; + dest_offset =3D 0; + } + return 0; +} + +static int kimage_purgatory_calc_digest(struct kexec_image *image) +{ + int ret; + sha256_region_t regions[KIMAGE_SHA256_REGIONS] =3D {{0}}; + struct sha2_256_state ctx; + uint8_t digest[SHA2_256_DIGEST_SIZE]; + unsigned int s; + + if ( image->nr_segments > KIMAGE_SHA256_REGIONS ) + { + dprintk(XENLOG_DEBUG, "More segments than allocated SHA256 regions= \n"); + return -E2BIG; + } + + + sha2_256_init(&ctx); + + for ( s =3D 0; s < image->nr_segments; s++ ) { + ret =3D kimage_purgatory_calc_one_digest(&ctx, &image->segments[s]= ); + if ( ret ) + return ret; + + regions[s].start =3D image->segments[s].dest_maddr + + image->segments[s].dest_offset; + regions[s].len =3D image->segments[s].buf_size; + } + + sha2_256_final(&ctx, digest); + + ret =3D kimage_purgatory_get_set_symbol(image, "sha256_regions", + regions, sizeof(regions), 0); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_get_set_symbol(image, "sha256_digest", + &digest, sizeof(digest), 0); + if ( ret ) + return ret; + + return 0; +} + +/* + * Find the entry point to the new kernel, we need to map the crash region= into + * memory in order to read the kernel header. + */ +#define KERNEL_SEGMENT_IDX 0 +static uint64_t kimage_find_kernel_entry_maddr(struct kexec_image *image) +{ + uint64_t alignment_addr; + uint32_t alignment; + unsigned long dest_mfn; + void *dest_va; + + alignment_addr =3D image->segments[KERNEL_SEGMENT_IDX].dest_maddr + + image->segments[KERNEL_SEGMENT_IDX].dest_offset + + offsetof(struct setup_header, kernel_alignment); + + dest_mfn =3D alignment_addr >> PAGE_SHIFT; + dest_va =3D map_domain_page(_mfn(dest_mfn)); + if ( !dest_va ) + return -EINVAL; + + alignment =3D *((uint32_t *) ((uint8_t *) dest_va + + PAGE_OFFSET(alignment_addr= ))); + + unmap_domain_page(dest_va); + + /* + * Ensure the kernel alignment is a valid LOAD_PHYSICAL_ADDR, + * which ranges from 0x200000 (2MiB) to 0x1000000 (16Mib) on 64-bit sy= stems + * as defined in the kernel x86 Kconfig + */ + if ( alignment % 0x200000 !=3D 0 || + alignment < 0x200000 || + alignment > 0x1000000 ) + return -EINVAL; + + return ROUNDUP(image->segments[KERNEL_SEGMENT_IDX].dest_maddr + + image->segments[KERNEL_SEGMENT_IDX].dest_offset, + alignment) + + 0x200; +} + +/* + * Configure purgatory with the register values that will be set before ju= mping + * into the new kernel. + */ +static int kimage_purgatory_set_register_block(struct kexec_image *image, = uint64_t parameters) +{ + int ret; + uint64_t rip; + void *stack; + + rip =3D kimage_find_kernel_entry_maddr(image); + if ( rip < 0 ) + return -EINVAL; + + ret =3D kimage_purgatory_get_symbol_addr(image, "stack_end", &stack); + BUG_ON(ret < 0); + + /* Clear the registers */ + memset(&image->regs, 0, sizeof(image->regs)); + + image->regs.rsp =3D (uint64_t)stack; + image->regs.rsi =3D parameters; // Kernel parameters + image->regs.rip =3D rip; + + return kimage_purgatory_get_set_symbol(image, "entry64_regs", + &image->regs, sizeof(image->reg= s), + 0); +} + +/* + * Move the loaded purgatory into its final destination as an additional k= image + * segment. + */ +static int kimage_purgatory_move(struct kexec_image *image) +{ + struct purgatory_info *pi =3D &image->pi; + paddr_t dest; + unsigned long sbytes; + unsigned long src_offset =3D 0; + int result =3D 0; + paddr_t addr; + + sbytes =3D pi->bufsz; + dest =3D pi->dest; + + while ( dest < (pi->dest + pi->memsz) ) + { + unsigned long dest_mfn; + void *dest_va; + size_t schunk, dchunk; + + dest_mfn =3D dest >> PAGE_SHIFT; + + dchunk =3D PAGE_SIZE; + schunk =3D min(dchunk, sbytes); + + dest_va =3D map_domain_page(_mfn(dest_mfn)); + if ( !dest_va ) + return -EINVAL; + + memcpy(dest_va, pi->buffer + src_offset, schunk); + memset(dest_va + schunk, 0, dchunk - schunk); + + unmap_domain_page(dest_va); + + sbytes -=3D schunk; + dest +=3D dchunk; + src_offset +=3D schunk; + } + + for ( addr =3D pi->dest & PAGE_MASK; + addr < pi->dest + pi->memsz; addr +=3D PAGE_SIZE ) { + result =3D machine_kexec_add_page(image, addr, addr); + if ( result < 0 ) + break; + } + + return result; +} + +int kimage_setup_purgatory(struct kexec_image *image, uint64_t parameters) +{ + int ret; + + ret =3D kimage_load_purgatory_image(image); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_calc_digest(image); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_set_register_block(image, parameters); + if ( ret ) + return ret; + + ret =3D kimage_purgatory_move(image); + if ( ret ) + return ret; + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h index 40d79e936b..9bc94c6fd6 100644 --- a/xen/include/public/kexec.h +++ b/xen/include/public/kexec.h @@ -56,15 +56,24 @@ /* * Kexec supports two types of operation: * - kexec into a regular kernel, very similar to a standard reboot - * - KEXEC_TYPE_DEFAULT is used to specify this type + * - KEXEC_TYPE_DEFAULT or KEXEC_TYPE_DEFAULT_EFI are used to specify + * this type + * - in case of KEXEC_TYPE_DEFAULT_EFI the first segment will + * point to full kernel to load and entry point will point to + * parameters * - kexec into a special "crash kernel", aka kexec-on-panic - * - KEXEC_TYPE_CRASH is used to specify this type + * - KEXEC_TYPE_CRASH or KEXEC_TYPE_CRASH_EFI are used to specify this + * type + * - see above for differences between KEXEC_TYPE_CRASH and + * KEXEC_TYPE_CRASH_EFI * - parts of our system may be broken at kexec-on-panic time * - the code should be kept as simple and self-contained as possible */ =20 -#define KEXEC_TYPE_DEFAULT 0 -#define KEXEC_TYPE_CRASH 1 +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 +#define KEXEC_TYPE_DEFAULT_EFI 2 +#define KEXEC_TYPE_CRASH_EFI 3 =20 =20 /* The kexec implementation for Xen allows the user to load two @@ -195,7 +204,11 @@ typedef struct xen_kexec_load { XEN_GUEST_HANDLE(xen_kexec_segment_t) h; uint64_t _pad; } segments; - uint64_t entry_maddr; /* image entry point machine address. */ + /* image entry point machine address or parameters in case of EFI. */ + union { + uint64_t entry_maddr; + uint64_t parameters; + }; } xen_kexec_load_t; DEFINE_XEN_GUEST_HANDLE(xen_kexec_load_t); =20 diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h index 348f07f5c8..6626058f8b 100644 --- a/xen/include/xen/kimage.h +++ b/xen/include/xen/kimage.h @@ -11,12 +11,45 @@ =20 #include #include +#include #include =20 #define KEXEC_SEGMENT_MAX 16 =20 +extern const char kexec_purgatory[]; +extern const unsigned int kexec_purgatory_size; + typedef paddr_t kimage_entry_t; =20 +struct purgatory_info { + uint64_t dest; + void *buffer; + uint64_t bufsz; + uint64_t memsz; + uint64_t buf_align; + Elf_Shdr *sechdrs; +}; + +typedef struct xen_kexec_regs { + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t rsp; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; +} xen_kexec_regs_t; + struct kexec_image { uint8_t type; uint16_t arch; @@ -37,6 +70,9 @@ struct kexec_image { =20 /* Address of next control page to allocate for crash kernels. */ paddr_t next_crash_page; + + struct purgatory_info pi; + xen_kexec_regs_t regs; }; =20 int kimage_alloc(struct kexec_image **rimage, uint8_t type, uint16_t arch, @@ -52,6 +88,12 @@ mfn_t kimage_entry_mfn(kimage_entry_t *entry, bool compa= t); unsigned long kimage_entry_ind(kimage_entry_t *entry, bool compat); int kimage_build_ind(struct kexec_image *image, mfn_t ind_mfn, bool compat); +int kimage_setup_purgatory(struct kexec_image *image, uint64_t parameters); +void kimage_terminate(struct kexec_image *image); + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, const Elf_Shdr *re= lsec, + const Elf_Shdr *symtabsec); =20 #endif /* __ASSEMBLY__ */ =20 diff --git a/xen/include/xen/x86-linux.h b/xen/include/xen/x86-linux.h new file mode 100644 index 0000000000..940d830323 --- /dev/null +++ b/xen/include/xen/x86-linux.h @@ -0,0 +1,62 @@ +/* + * This file was extracted from x86-linux.h in kexec-tools + * + * Copyright (C) 2003-2010 Eric Biederman (ebiederm@xmission.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef X86_LINUX_H +#define X86_LINUX_H + +struct __packed setup_header { + uint8_t _pad0[0x1f1]; /* skip uninteresting stuff */ + uint8_t setup_sects; + uint16_t root_flags; + uint32_t syssize; + uint16_t ram_size; + uint16_t vid_mode; + uint16_t root_dev; + uint16_t boot_flag; + uint16_t jump; + uint32_t header; +#define HDR_MAGIC "HdrS" +#define HDR_MAGIC_SZ 4 + uint16_t version; +#define VERSION(h,l) (((h)<<8) | (l)) + uint32_t realmode_swtch; + uint16_t start_sys; + uint16_t kernel_version; + uint8_t type_of_loader; + uint8_t loadflags; + uint16_t setup_move_size; + uint32_t code32_start; + uint32_t ramdisk_image; + uint32_t ramdisk_size; + uint32_t bootsect_kludge; + uint16_t heap_end_ptr; + uint16_t _pad1; + uint32_t cmd_line_ptr; + uint32_t initrd_addr_max; + uint32_t kernel_alignment; + uint8_t relocatable_kernel; + uint8_t _pad2[3]; + uint32_t cmdline_size; + uint32_t hardware_subarch; + uint64_t hardware_subarch_data; + uint32_t payload_offset; + uint32_t payload_length; +}; + +#endif /* X86_LINUX_H */ --=20 2.43.0 From nobody Fri Dec 19 20:18:23 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1746611013; cv=none; d=zohomail.com; s=zohoarc; b=VDZVFJiqWPHVmLIowb4ZmTpKxSWrDRcA5bxtIocjZLt9QuZS4cbw3hEq6/JNkBm5nrb/mCo8n2UAp31NfpOh6oSopF0AKYibA0QNJO91XRct/9gnSqQW50imsGfRe2apDRUEp3nPmU3NtyMP+FCIKXMOabjad0zMUEDdyceoqi0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746611013; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=CL/ZVVVxEx78jS9Cw9s8DTLqhKzVHZ6dBkuD0mXe5Pk=; b=lcyBppp9lAkB92ruaO4tUlMtF9np9U3C1JhmeBLqPa7MZdlz2GoA6M6b+j1qUuuvR+11PqOXU/RCLKf0cbgq5eKT0MtOXbvxZ6Rz66/is4q/PCg8hy+KRx32yitP4eaJ2yT1wPEu9CTeMBpIOq3ETSwfZveJmTOHeQUsuXgN8Es= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1746611013311634.0518185211356; Wed, 7 May 2025 02:43:33 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.978420.1365246 (Exim 4.92) (envelope-from ) id 1uCbJ7-0006oY-2i; Wed, 07 May 2025 09:43:17 +0000 Received: by outflank-mailman (output) from mailman id 978420.1365246; Wed, 07 May 2025 09:43:17 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ6-0006nn-Ol; Wed, 07 May 2025 09:43:16 +0000 Received: by outflank-mailman (input) for mailman id 978420; Wed, 07 May 2025 09:43:15 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uCbJ5-00062T-Fy for xen-devel@lists.xenproject.org; Wed, 07 May 2025 09:43:15 +0000 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [2a00:1450:4864:20::32a]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id b1dda231-2b27-11f0-9ffb-bf95429c2676; Wed, 07 May 2025 11:43:13 +0200 (CEST) Received: by mail-wm1-x32a.google.com with SMTP id 5b1f17b1804b1-43cfebc343dso45150755e9.2 for ; Wed, 07 May 2025 02:43:13 -0700 (PDT) Received: from localhost.localdomain (172.74.6.51.dyn.plus.net. [51.6.74.172]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a099b16f00sm16051290f8f.84.2025.05.07.02.43.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 May 2025 02:43:11 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b1dda231-2b27-11f0-9ffb-bf95429c2676 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1746610993; x=1747215793; darn=lists.xenproject.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; bh=CL/ZVVVxEx78jS9Cw9s8DTLqhKzVHZ6dBkuD0mXe5Pk=; b=EtCFLM3H5hV+FgUdAJ2uLQhOp+lCrRFzszRvJqNIzCEPZe+PdWbe1bsYra4e7T7dM9 r4j2PKTFehYclm13Xa69B6jQ3QKaeSdhZwx6H0gVAGh96witL9DiXdL0P/nsxcfi9vTX A8NUzbDXaULe2hzvG3/lSopIa0YVDvN4pyRiencZ0NhKPiVEyGRNYRusvdwNESiJOoVJ wEq9Ks9ebB2Hn/JqWkxqx1yAPwnir1QsLu+G2zZFimdwilvK1G/TAnPYLDfaWTnhl6LY cyeTNnXlYWtCyBYN+DLV6hEiB7JI663sBxpvR5AltXjsxTTY0NqOTW1bGHupVD44rF+M 9D6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746610993; x=1747215793; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CL/ZVVVxEx78jS9Cw9s8DTLqhKzVHZ6dBkuD0mXe5Pk=; b=C3rHXFbeZ248FRVL+kp7XpXkep/IpWefkSaCYApsxjzRqgwG010p9no0w4edxS4l45 tXiyNQT/fQr3zIVmdlZDpVb+GRabCh8ceDiro41Gz4aYfhp4bV8JURsDP+k/LM2AYTzG K1//HPWFrGovszO9Buyq7lctB+WP4RRYyy3nhwpI1dICneADvm8wpY/PKT0uBuOsYjRP rQyCJ86pJHGJSCFy4coXaHAvIxVojHRl5/L65etKkYhGjAKQNXz9swJl2SvgVt4SjA6V 34QKnLoEUsozMpSCnsAwMhG0gxncoBDKeTaOV4JhuaGRHnP7fwR9v/p1sqmnFXt7FKJL +J+g== X-Gm-Message-State: AOJu0Yzb2e8XRtQF0wB28ApTpt2JB5VJM26t+xt9W98dqZ/5+Q6Oy9YE 40P+H+0du11hVRix5DtXjML/XVzSQXP6FrxqL1fRqVHW2MYY/d07rdS582XobA0= X-Gm-Gg: ASbGncs5dx9MlVqWFDNAgb89LQORlEuYEdqBWmjZ4nhfUCB2xrjfO2FFrk29KoKeB09 h9qzsCYXLIq9i5xlhhtWpLv6aWamMwzIY+PLM94PATxxIQ2Tv4b8XAwx87V+SwbcGLJbbTM38Yx 4pgBbGBAf/UwhKG8LczSUZbNjl41e+5I9gTlMh/E/eV5XrR1GFmVimse2eV+y82XNsDuSEvfNR8 tOXLQOCBvuwNWOp8nQltnCSJLV1jJVyy1eIijrCoF7PeZeHtqIMcq2qRxymGye1gZ+8nbEoqO+u tzWkP6Iy99WZvWvTZSsy5jIQoFiwr9zbUW0pMGAI1z37pyiVmxwS3f2B2EKSETCEU7ttUIosx2d EpgWq/UY= X-Google-Smtp-Source: AGHT+IFnh7HIuyj9gVufq4X9Yg9+nJEUrlpMCQNzd042cCEhvk4KRLaC+BeppB1APVtjXQo8/3PvhQ== X-Received: by 2002:a05:600c:3f0d:b0:441:d228:1fe5 with SMTP id 5b1f17b1804b1-441d44e5896mr13778825e9.33.1746610992804; Wed, 07 May 2025 02:43:12 -0700 (PDT) From: Frediano Ziglio To: xen-devel@lists.xenproject.org Cc: Ross Lagerwall , Andrew Cooper Subject: [PATCH v2 4/4] kexec: Support non-page-aligned kexec segments Date: Wed, 7 May 2025 10:42:49 +0100 Message-ID: <20250507094253.10395-5-freddy77@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250507094253.10395-1-freddy77@gmail.com> References: <20250507094253.10395-1-freddy77@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1746611015076116600 Content-Type: text/plain; charset="utf-8" From: Ross Lagerwall With Secure Boot, userspace passes in the entire kernel loaded for verifica= tion purposes. However, the kernel's startup32 function needs to be aligned (e.g= . to 16 MiB) and this results in the start of the segment not being page-aligned (depending on where the startup32 function lands in the kernel binary). Rel= ax this restriction in Xen to support this use case. Signed-off-by: Ross Lagerwall --- xen/common/kexec.c | 23 +++++++----- xen/common/kimage.c | 81 +++++++++++++++++++++------------------- xen/include/xen/kimage.h | 15 +++++++- 3 files changed, 70 insertions(+), 49 deletions(-) diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 158f8da6fd..a7b3958c74 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -910,7 +910,7 @@ static uint16_t kexec_load_v1_arch(void) } =20 static int kexec_segments_add_segment(unsigned int *nr_segments, - xen_kexec_segment_t *segments, + struct kimage_segment *segments, mfn_t mfn) { paddr_t maddr =3D mfn_to_maddr(mfn); @@ -936,7 +936,7 @@ static int kexec_segments_add_segment(unsigned int *nr_= segments, =20 static int kexec_segments_from_ind_page(mfn_t mfn, unsigned int *nr_segments, - xen_kexec_segment_t *segments, + struct kimage_segment *segments, bool compat) { void *page; @@ -991,7 +991,7 @@ done: static int kexec_do_load_v1(xen_kexec_load_v1_t *load, int compat) { struct kexec_image *kimage =3D NULL; - xen_kexec_segment_t *segments; + struct kimage_segment *segments; uint16_t arch; unsigned int nr_segments =3D 0; mfn_t ind_mfn =3D maddr_to_mfn(load->image.indirection_page); @@ -1001,7 +1001,7 @@ static int kexec_do_load_v1(xen_kexec_load_v1_t *load= , int compat) if ( arch =3D=3D EM_NONE ) return -ENOSYS; =20 - segments =3D xmalloc_array(xen_kexec_segment_t, KEXEC_SEGMENT_MAX); + segments =3D xmalloc_array(struct kimage_segment, KEXEC_SEGMENT_MAX); if ( segments =3D=3D NULL ) return -ENOMEM; =20 @@ -1103,9 +1103,10 @@ static int kexec_load_v1_compat(XEN_GUEST_HANDLE_PAR= AM(void) uarg) static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) uarg) { xen_kexec_load_t load; - xen_kexec_segment_t *segments; + struct kimage_segment *segments; struct kexec_image *kimage =3D NULL; int ret; + unsigned int i; =20 if ( copy_from_guest(&load, uarg, 1) ) return -EFAULT; @@ -1113,14 +1114,18 @@ static int kexec_load(XEN_GUEST_HANDLE_PARAM(void) = uarg) if ( load.nr_segments >=3D KEXEC_SEGMENT_MAX ) return -EINVAL; =20 - segments =3D xmalloc_array(xen_kexec_segment_t, load.nr_segments); + segments =3D xmalloc_array(struct kimage_segment, load.nr_segments); if ( segments =3D=3D NULL ) return -ENOMEM; =20 - if ( copy_from_guest(segments, load.segments.h, load.nr_segments) ) + for ( i =3D 0; i < load.nr_segments; i++ ) { - ret =3D -EFAULT; - goto error; + if ( copy_from_guest_offset((xen_kexec_segment_t *)&segments[i], + load.segments.h, i, 1) ) + { + ret =3D -EFAULT; + goto error; + } } =20 ret =3D kimage_alloc(&kimage, load.type, load.arch, load.entry_maddr, diff --git a/xen/common/kimage.c b/xen/common/kimage.c index 212f5bd068..296febeb09 100644 --- a/xen/common/kimage.c +++ b/xen/common/kimage.c @@ -96,7 +96,7 @@ static struct page_info *kimage_alloc_zeroed_page(unsigne= d memflags) =20 static int do_kimage_alloc(struct kexec_image **rimage, paddr_t entry, unsigned long nr_segments, - xen_kexec_segment_t *segments, uint8_t type) + struct kimage_segment *segments, uint8_t type) { struct kexec_image *image; unsigned long i; @@ -119,29 +119,6 @@ static int do_kimage_alloc(struct kexec_image **rimage= , paddr_t entry, INIT_PAGE_LIST_HEAD(&image->dest_pages); INIT_PAGE_LIST_HEAD(&image->unusable_pages); =20 - /* - * Verify we have good destination addresses. The caller is - * responsible for making certain we don't attempt to load the new - * image into invalid or reserved areas of RAM. This just - * verifies it is an address we can use. - * - * Since the kernel does everything in page size chunks ensure the - * destination addresses are page aligned. Too many special cases - * crop of when we don't do this. The most insidious is getting - * overlapping destination addresses simply because addresses are - * changed to page size granularity. - */ - result =3D -EADDRNOTAVAIL; - for ( i =3D 0; i < nr_segments; i++ ) - { - paddr_t mstart, mend; - - mstart =3D image->segments[i].dest_maddr; - mend =3D mstart + image->segments[i].dest_size; - if ( (mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK) ) - goto out; - } - /* * Verify our destination addresses do not overlap. If we allowed * overlapping destination addresses through very weird things can @@ -221,7 +198,7 @@ out: =20 static int kimage_normal_alloc(struct kexec_image **rimage, paddr_t entry, unsigned long nr_segments, - xen_kexec_segment_t *segments) + struct kimage_segment *segments) { return do_kimage_alloc(rimage, entry, nr_segments, segments, KEXEC_TYPE_DEFAULT); @@ -229,7 +206,7 @@ static int kimage_normal_alloc(struct kexec_image **rim= age, paddr_t entry, =20 static int do_kimage_crash_alloc(struct kexec_image **rimage, paddr_t entr= y, unsigned long nr_segments, - xen_kexec_segment_t *segments) + struct kimage_segment *segments) { unsigned long i; =20 @@ -264,7 +241,7 @@ static int do_kimage_crash_alloc(struct kexec_image **r= image, paddr_t entry, =20 static int kimage_crash_alloc(struct kexec_image **rimage, paddr_t entry, unsigned long nr_segments, - xen_kexec_segment_t *segments) + struct kimage_segment *segments) { /* Verify we have a valid entry point */ if ( (entry < kexec_crash_area.start) @@ -276,7 +253,7 @@ static int kimage_crash_alloc(struct kexec_image **rima= ge, paddr_t entry, =20 static int kimage_crash_alloc_efi(struct kexec_image **rimage, paddr_t ent= ry, unsigned long nr_segments, - xen_kexec_segment_t *segments) + struct kimage_segment *segments) { return do_kimage_crash_alloc(rimage, entry, nr_segments, segments); } @@ -694,16 +671,18 @@ found: } =20 static int kimage_load_normal_segment(struct kexec_image *image, - xen_kexec_segment_t *segment) + struct kimage_segment *segment) { unsigned long to_copy; unsigned long src_offset; + unsigned int dest_offset; paddr_t dest, end; int ret; =20 to_copy =3D segment->buf_size; src_offset =3D 0; dest =3D segment->dest_maddr; + dest_offset =3D segment->dest_offset; =20 ret =3D kimage_set_destination(image, dest); if ( ret < 0 ) @@ -718,7 +697,7 @@ static int kimage_load_normal_segment(struct kexec_imag= e *image, =20 dest_mfn =3D dest >> PAGE_SHIFT; =20 - size =3D min_t(unsigned long, PAGE_SIZE, to_copy); + size =3D min_t(unsigned long, PAGE_SIZE - dest_offset, to_copy); =20 page =3D kimage_alloc_page(image, dest); if ( !page ) @@ -728,7 +707,7 @@ static int kimage_load_normal_segment(struct kexec_imag= e *image, return ret; =20 dest_va =3D __map_domain_page(page); - ret =3D copy_from_guest_offset(dest_va, segment->buf.h, src_offset= , size); + ret =3D copy_from_guest_offset(dest_va + dest_offset, segment->buf= .h, src_offset, size); unmap_domain_page(dest_va); if ( ret ) return -EFAULT; @@ -736,6 +715,7 @@ static int kimage_load_normal_segment(struct kexec_imag= e *image, to_copy -=3D size; src_offset +=3D size; dest +=3D PAGE_SIZE; + dest_offset =3D 0; } =20 /* Remainder of the destination should be zeroed. */ @@ -747,7 +727,7 @@ static int kimage_load_normal_segment(struct kexec_imag= e *image, } =20 static int kimage_load_crash_segment(struct kexec_image *image, - xen_kexec_segment_t *segment) + struct kimage_segment *segment) { /* * For crash dumps kernels we simply copy the data from user space @@ -755,12 +735,14 @@ static int kimage_load_crash_segment(struct kexec_ima= ge *image, */ paddr_t dest; unsigned long sbytes, dbytes; + unsigned int dest_offset; int ret =3D 0; unsigned long src_offset =3D 0; =20 sbytes =3D segment->buf_size; dbytes =3D segment->dest_size; dest =3D segment->dest_maddr; + dest_offset =3D segment->dest_offset; =20 while ( dbytes ) { @@ -770,14 +752,16 @@ static int kimage_load_crash_segment(struct kexec_ima= ge *image, =20 dest_mfn =3D dest >> PAGE_SHIFT; =20 - dchunk =3D PAGE_SIZE; + dchunk =3D PAGE_SIZE - dest_offset; schunk =3D min(dchunk, sbytes); =20 dest_va =3D map_domain_page(_mfn(dest_mfn)); if ( !dest_va ) return -EINVAL; =20 - ret =3D copy_from_guest_offset(dest_va, segment->buf.h, + if ( dest_offset ) + memset(dest_va, 0, dest_offset); + ret =3D copy_from_guest_offset(dest_va + dest_offset, segment->buf= .h, src_offset, schunk); memset(dest_va + schunk, 0, dchunk - schunk); =20 @@ -785,17 +769,18 @@ static int kimage_load_crash_segment(struct kexec_ima= ge *image, if ( ret ) return -EFAULT; =20 - dbytes -=3D dchunk; + dbytes -=3D dchunk + dest_offset; sbytes -=3D schunk; - dest +=3D dchunk; + dest +=3D dchunk + dest_offset; src_offset +=3D schunk; + dest_offset =3D 0; } =20 return 0; } =20 static int kimage_load_segment(struct kexec_image *image, - xen_kexec_segment_t *segment) + struct kimage_segment *segment) { int result =3D -ENOMEM; paddr_t addr; @@ -826,9 +811,29 @@ static int kimage_load_segment(struct kexec_image *ima= ge, =20 int kimage_alloc(struct kexec_image **rimage, uint8_t type, uint16_t arch, uint64_t entry_maddr, - uint32_t nr_segments, xen_kexec_segment_t *segment) + uint32_t nr_segments, struct kimage_segment *segment) { int result; + unsigned int i; + + for ( i =3D 0; i < nr_segments; i++ ) + { + paddr_t mend; + + /* + * Stash the destination offset-in-page for use when copying the + * buffer later. + */ + segment[i].dest_offset =3D PAGE_OFFSET(segment[i].dest_maddr); + + /* + * Align down the start address to page size and align up the end + * address to page size. + */ + mend =3D segment[i].dest_maddr + segment[i].dest_size; + segment[i].dest_maddr &=3D PAGE_MASK; + segment[i].dest_size =3D ROUNDUP(mend, PAGE_SIZE) - segment[i].des= t_maddr; + } =20 switch( type ) { diff --git a/xen/include/xen/kimage.h b/xen/include/xen/kimage.h index 6626058f8b..3099b489b5 100644 --- a/xen/include/xen/kimage.h +++ b/xen/include/xen/kimage.h @@ -30,6 +30,17 @@ struct purgatory_info { Elf_Shdr *sechdrs; }; =20 +struct kimage_segment { + union { + XEN_GUEST_HANDLE(const_void) h; + uint64_t _pad; + } buf; + uint64_t buf_size; + uint64_t dest_maddr; + uint64_t dest_size; + unsigned int dest_offset; +}; + typedef struct xen_kexec_regs { uint64_t rax; uint64_t rbx; @@ -55,7 +66,7 @@ struct kexec_image { uint16_t arch; uint64_t entry_maddr; uint32_t nr_segments; - xen_kexec_segment_t *segments; + struct kimage_segment *segments; =20 kimage_entry_t head; struct page_info *entry_page; @@ -77,7 +88,7 @@ struct kexec_image { =20 int kimage_alloc(struct kexec_image **rimage, uint8_t type, uint16_t arch, uint64_t entry_maddr, - uint32_t nr_segments, xen_kexec_segment_t *segment); + uint32_t nr_segments, struct kimage_segment *segment); void kimage_free(struct kexec_image *image); int kimage_load_segments(struct kexec_image *image); struct page_info *kimage_alloc_control_page(struct kexec_image *image, --=20 2.43.0