From patchwork Thu Jul 18 08:57:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813257 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 601C77A715 for ; Thu, 18 Jul 2024 08:58:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293116; cv=none; b=Aftam3G/KlkWlrQDBnMrK/WDsp3C8kqiEsvdLZuP1M2COa7dBVrbT0p9nTeTsPk9VI+oa+S0zpyn6z//1rRy0Z03bZ9T/I29oNvbsoitxCbR3JYpJqxs9IzJqHrmswy7D27YwnlKxlL1yQ33uG3j+h3lCfodN3DJP8ETWIoCgBY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293116; c=relaxed/simple; bh=jNKWwma2wIB7xOoVow0y9HbAhCuv6AZL500cFtiHR6E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P3EAOz+rMAi6g2zwa9Hg5C6Iy5/aRlc69oWRW7GqjdQDqSwHJFSJcANx1dn1ZW2ucoIwx00SW7sf8JYTEbFTEt6Mza5IBytn9MgZzz5Mz613KdHj3gTiAyGLg5ixXCXSkRIwfa4+KSlvueV7cRdlJpPeVnpkSxuaxK3TxDzBGlM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=PBHgm4l2; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PBHgm4l2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293113; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rHkCyYGA8QyQuIMDt9RDR9WI4HDg50V1gQCoq7GDYhk=; b=PBHgm4l21Ebf48zClqRZ9CqRguD+iUAcrL2Q/pO0LFQRFiTNTJCQiKuaYTdpGwEfr//lWT p9u/Wqih/TZEM7lioFdC9gby+BWcOn4Z8JaJDdF7yVBwTmiSbI1XIw03KGYwxhQ3O2qoVE qLpmPTgw+QdpGR+4a3Powz+hTQKSB44= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-146-WrBIWUkwNUmEQKRxTQm2Rw-1; Thu, 18 Jul 2024 04:58:28 -0400 X-MC-Unique: WrBIWUkwNUmEQKRxTQm2Rw-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D8AD91955BFC; Thu, 18 Jul 2024 08:58:26 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 50E993000186; Thu, 18 Jul 2024 08:58:17 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 1/7] efi/libstub: Ask efi_random_alloc() to skip unusable memory Date: Thu, 18 Jul 2024 16:57:51 +0800 Message-ID: <20240718085759.13247-2-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 efi_random_alloc() demands EFI_ALLOCATE_ADDRESS when allocate_pages(), but the current implement can not ensure the selected target locates inside free area, that is to exclude EFI_BOOT_SERVICES_*, EFI_RUNTIME_SERVICES_* etc. Fix the issue by checking md->type. Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- drivers/firmware/efi/libstub/randomalloc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c index c41e7b2091cdd..7304e767688f2 100644 --- a/drivers/firmware/efi/libstub/randomalloc.c +++ b/drivers/firmware/efi/libstub/randomalloc.c @@ -79,6 +79,8 @@ efi_status_t efi_random_alloc(unsigned long size, efi_memory_desc_t *md = (void *)map->map + map_offset; unsigned long slots; + if (!(md->type & (EFI_CONVENTIONAL_MEMORY || EFI_PERSISTENT_MEMORY))) + continue; slots = get_entry_num_slots(md, size, ilog2(align), alloc_min, alloc_max); MD_NUM_SLOTS(md) = slots; @@ -111,6 +113,9 @@ efi_status_t efi_random_alloc(unsigned long size, efi_physical_addr_t target; unsigned long pages; + if (!(md->type & (EFI_CONVENTIONAL_MEMORY || EFI_PERSISTENT_MEMORY))) + continue; + if (total_mirrored_slots > 0 && !(md->attribute & EFI_MEMORY_MORE_RELIABLE)) continue; From patchwork Thu Jul 18 08:57:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813466 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8709A7A715 for ; Thu, 18 Jul 2024 08:58:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293125; cv=none; b=KQKw0SIH5N9l5ZYHtNJaMgGffVB10OObm/FDB31hrqmXl+w0C7wWbfAQPp6+px7q/RuHpGW3nnjuVPgYMgiuv7ik5mV8Sx5uYmNID5yeJUpCd6ir9M1mUUmmTsvfcQTfMWhFKfBe1TIh4c1MB1A+tmyrjhkm7E+azBCNPT/NfiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293125; c=relaxed/simple; bh=fBrp5iDu610M0ODjEvFQW3GZr/y9VjeDVmnBgLVG3dI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UOT5FrLNIM3vYYW++kGmzb6zR5mk6VMandmTpzgeCUKKabVgJRBMiSqZt7U9fmtmQyiY76X/Czlv6VdYuYE1vjszFKk3qABb4iy3QCQ4FheMnXlhO7gK7S2RVzj2LhsKNkbxxgniPwd0fGYg5HDOgH81vqL7idTYYHezD8W0tYU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=aGW/hFXA; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="aGW/hFXA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293122; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/9TZSR+BUCVNWRBqfa4q3I7rRgSk04YNeRsJlv/xLrE=; b=aGW/hFXAOLbfrU4B3d3rlYIi/2BRpVEKsD8s/+y2igKCrDqrzn9D4D1l0+tQYsa0SuEw93 7jFFBAxtV0Q12n0e+yvMQalJu88JfXnNKa5tgCiD70+VIKAVLTLJK4IAzzJwK2iy/V+zqJ rRAPIa50/k992RKiithKLv/cITmI44I= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-152-ygGD_SQxMmeyRCAbDROY2A-1; Thu, 18 Jul 2024 04:58:37 -0400 X-MC-Unique: ygGD_SQxMmeyRCAbDROY2A-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AA0631954225; Thu, 18 Jul 2024 08:58:35 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8E5473000185; Thu, 18 Jul 2024 08:58:27 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 2/7] debug/libstub: cheats to step around some boot service Date: Thu, 18 Jul 2024 16:57:52 +0800 Message-ID: <20240718085759.13247-3-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 For POC, step around these four function, hence the corresponding boot services. Later those services should be implemented and this patch should be drop. Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- drivers/firmware/efi/libstub/efi-stub-helper.c | 3 +++ drivers/firmware/efi/libstub/efi-stub.c | 2 ++ drivers/firmware/efi/libstub/random.c | 2 ++ drivers/firmware/efi/libstub/tpm.c | 4 ++++ 4 files changed, 11 insertions(+) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index de659f6a815fd..19b31a4c7fcea 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -615,6 +615,9 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, efi_status_t status = EFI_SUCCESS; struct linux_efi_initrd initrd, *tbl; + efi_info("cheat in efi_load_initrd()\n"); + return EFI_SUCCESS; + if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd) return EFI_SUCCESS; diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 958a680e0660d..190d280e634e9 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -59,6 +59,8 @@ static struct screen_info *setup_graphics(void) void **gop_handle = NULL; struct screen_info *si = NULL; + efi_info("cheat in setup_graphics\n"); + return NULL; size = 0; status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL, &gop_proto, NULL, &size, gop_handle); diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c index 7109b8a2dcba8..3a647fea2fdd3 100644 --- a/drivers/firmware/efi/libstub/random.c +++ b/drivers/firmware/efi/libstub/random.c @@ -73,6 +73,8 @@ efi_status_t efi_random_get_seed(void) efi_rng_protocol_t *rng = NULL; efi_status_t status; + efi_info("cheat in efi_random_get_seed\n"); + return EFI_UNSUPPORTED; status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng); if (status != EFI_SUCCESS) seed_size = 0; diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index df3182f2e63a5..0c585466c0b85 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -33,6 +33,8 @@ void efi_enable_reset_attack_mitigation(void) efi_status_t status; unsigned long datasize = 0; + efi_info("cheat in efi_enable_reset_attack_mitigation\n"); + return; status = get_efi_var(efi_MemoryOverWriteRequest_name, &var_guid, NULL, &datasize, NULL); @@ -155,6 +157,8 @@ void efi_retrieve_eventlog(void) efi_bool_t truncated; efi_status_t status; + efi_info("cheat in efi_retrieve_eventlog\n"); + return; status = efi_bs_call(locate_protocol, &tpm2_guid, NULL, (void **)&tpm2); if (status == EFI_SUCCESS) { status = efi_call_proto(tpm2, get_event_log, version, &log_location, From patchwork Thu Jul 18 08:57:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813256 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73B8E7A715 for ; Thu, 18 Jul 2024 08:58:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293136; cv=none; b=UjytPSZwdjvBOIuooZYPZjVrhOvnTfQfMfniP0Ec/uwJQGLWyh9zlkX7uc7e+ZWnJoZc3VYtwRxd46UKFqdfv6k6IWXVq50N/Vnhag971JctBZCfcZjABg2lZIeIwtwzMDxel3JzTYKI+jRRz6oxiUwa1tdQkZRpYO3xCPxNH+4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293136; c=relaxed/simple; bh=4lDsaA2aKHlJ61vz50kJ3jYASP3OQf7A0s2Kva+RhHw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mun1Two0+EtNt0DE9cwyvQiTVENOKbmPlvZ+Bi/IxDORmrvWl841JGPhnRrizI1hQvGXBGw+R0IH6vmPm0Q0O8vEMcQjB6lCX1oMrquJXMZd7P0oGtHxVYEbnjtztAgTdnL4IY/z8qi5L4gZhFFt5J7qXaSacLS0WmMEN8h5+gc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=XEM9FS0e; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="XEM9FS0e" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293131; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OwOnHPkmxLOYtjt6MO8OWx7h5LkIIkcp51BsdFCiSNk=; b=XEM9FS0eErruaQIW4sfrurjPtzvMcNXFAwQzdokvEe5w2kouZPL1lhlQu+CNggP15dRcXN jb35M7XEmg1vk/s8+TeXZhyWSOrr8rpZHg7J8/yvMKn0DnlZhLGNptleHfc1MPG3xc5Vht O3YVKIR1V24Pecx6OXxD56PVAtodc54= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-58-FbkKMEPzOCym2v-wDC6Xhg-1; Thu, 18 Jul 2024 04:58:48 -0400 X-MC-Unique: FbkKMEPzOCym2v-wDC6Xhg-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AB55D1955D56; Thu, 18 Jul 2024 08:58:45 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7EEC83000187; Thu, 18 Jul 2024 08:58:36 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 3/7] efi/emulator: Initial rountines to emulate EFI boot time service Date: Thu, 18 Jul 2024 16:57:53 +0800 Message-ID: <20240718085759.13247-4-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 From: Pingfan Liu efi emulator aims to serve the kexec if the kernel wrapped by efistub. It is paired with efistub, so only implements the minimus set of EFI boot service which merely enough boots up efistub. To simplify the code, the task such as the building of page table etc is shift to the first kernel as more as possible. (This part is implement in the later patch in this series) To do: -1. a simple memory allocator -2. a few extra efi boot service. Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/efi_emulator/Makefile | 98 +++++ .../firmware/efi/efi_emulator/amba-pl011.c | 80 ++++ .../efi_emulator/arm64_emulator_service.lds | 45 ++ .../firmware/efi/efi_emulator/config_table.c | 23 ++ drivers/firmware/efi/efi_emulator/core.c | 211 ++++++++++ drivers/firmware/efi/efi_emulator/earlycon.h | 19 + .../firmware/efi/efi_emulator/efi_emulator.S | 12 + drivers/firmware/efi/efi_emulator/emulator.h | 66 +++ drivers/firmware/efi/efi_emulator/entry.c | 57 +++ drivers/firmware/efi/efi_emulator/head.S | 10 + drivers/firmware/efi/efi_emulator/initrd.c | 15 + drivers/firmware/efi/efi_emulator/lib.c | 73 ++++ drivers/firmware/efi/efi_emulator/memory.c | 27 ++ .../firmware/efi/efi_emulator/memory_api.c | 73 ++++ drivers/firmware/efi/efi_emulator/misc.c | 76 ++++ drivers/firmware/efi/efi_emulator/pe_loader.c | 124 ++++++ drivers/firmware/efi/efi_emulator/printf.c | 389 ++++++++++++++++++ .../efi/efi_emulator/runtime_service.c | 28 ++ include/linux/efi_emulator.h | 45 ++ include/linux/kexec.h | 2 + 21 files changed, 1474 insertions(+) create mode 100644 drivers/firmware/efi/efi_emulator/Makefile create mode 100644 drivers/firmware/efi/efi_emulator/amba-pl011.c create mode 100644 drivers/firmware/efi/efi_emulator/arm64_emulator_service.lds create mode 100644 drivers/firmware/efi/efi_emulator/config_table.c create mode 100644 drivers/firmware/efi/efi_emulator/core.c create mode 100644 drivers/firmware/efi/efi_emulator/earlycon.h create mode 100644 drivers/firmware/efi/efi_emulator/efi_emulator.S create mode 100644 drivers/firmware/efi/efi_emulator/emulator.h create mode 100644 drivers/firmware/efi/efi_emulator/entry.c create mode 100644 drivers/firmware/efi/efi_emulator/head.S create mode 100644 drivers/firmware/efi/efi_emulator/initrd.c create mode 100644 drivers/firmware/efi/efi_emulator/lib.c create mode 100644 drivers/firmware/efi/efi_emulator/memory.c create mode 100644 drivers/firmware/efi/efi_emulator/memory_api.c create mode 100644 drivers/firmware/efi/efi_emulator/misc.c create mode 100644 drivers/firmware/efi/efi_emulator/pe_loader.c create mode 100644 drivers/firmware/efi/efi_emulator/printf.c create mode 100644 drivers/firmware/efi/efi_emulator/runtime_service.c create mode 100644 include/linux/efi_emulator.h diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index a2d0009560d0f..eb2a5d864f416 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o obj-$(CONFIG_UEFI_CPER) += cper.o cper_cxl.o obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o subdir-$(CONFIG_EFI_STUB) += libstub +obj-y += efi_emulator/ obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o obj-$(CONFIG_EFI_TEST) += test/ obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o diff --git a/drivers/firmware/efi/efi_emulator/Makefile b/drivers/firmware/efi/efi_emulator/Makefile new file mode 100644 index 0000000000000..e37472004a2b5 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/Makefile @@ -0,0 +1,98 @@ +# non-x86 reuses KBUILD_CFLAGS, x86 does not +cflags-y := $(KBUILD_CFLAGS) + +cflags-$(CONFIG_X86_32) := -march=i386 +cflags-$(CONFIG_X86_64) := -mcmodel=small +cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ \ + -fno-strict-aliasing -mno-red-zone \ + -mno-mmx -mno-sse -fshort-wchar \ + -Wno-pointer-sign \ + $(call cc-disable-warning, address-of-packed-member) \ + $(call cc-disable-warning, gnu) \ + -fno-asynchronous-unwind-tables \ + $(CLANG_FLAGS) + +# arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly +# disable the stackleak plugin +cflags-$(CONFIG_ARM64) += $(DISABLE_STACKLEAK_PLUGIN) \ + -fno-unwind-tables -fno-asynchronous-unwind-tables +cflags-$(CONFIG_ARM) += -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \ + -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \ + -DEFI_HAVE_STRCMP -fno-builtin \ + $(call cc-option,-mno-single-pic-base) +cflags-$(CONFIG_RISCV) += -DNO_ALTERNATIVE -mno-relax +cflags-$(CONFIG_LOONGARCH) += + +cflags-$(CONFIG_EFI_PARAMS_FROM_FDT) += -I$(srctree)/scripts/dtc/libfdt + +cflags-y += -I drivers/firmware/efi/libstub + +KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(cflags-y)) \ + -Os -DDISABLE_BRANCH_PROFILING \ + -D__NO_FORTIFY \ + -ffreestanding \ + -fno-stack-protector \ + $(call cc-option,-fno-addrsig) \ + -D__DISABLE_EXPORTS + +# +# struct randomization only makes sense for Linux internal types, which the EFI +# stub code never touches, so let's turn off struct randomization for the stub +# altogether +# +KBUILD_CFLAGS := $(filter-out $(RANDSTRUCT_CFLAGS), $(KBUILD_CFLAGS)) + +# remove SCS flags from all objects in this directory +KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_SCS), $(KBUILD_CFLAGS)) +# disable CFI +KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_CFI), $(KBUILD_CFLAGS)) +# disable LTO +KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO), $(KBUILD_CFLAGS)) + +GCOV_PROFILE := n +# Sanitizer runtimes are unavailable and cannot be linked here. +KASAN_SANITIZE := n +KCSAN_SANITIZE := n +KMSAN_SANITIZE := n +UBSAN_SANITIZE := n +OBJECT_FILES_NON_STANDARD := y + +# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. +KCOV_INSTRUMENT := n + +OBJECT_FILES_NON_STANDARD := y +emulator-y := head.o entry.o \ + core.o pe_loader.o misc.o memory.o memory_api.o runtime_service.o config_table.o \ + lib.o printf.o \ + amba-pl011.o +obj-y := efi_emulator.o + + +EMULATOR_OBJS = $(addprefix $(obj)/,$(emulator-y)) + +quiet_cmd_ar_emulator = PAD $@ + cmd_ar_emulator = $(AR) rcSTP $@ $^ + +$(obj)/emulator.a: $(EMULATOR_OBJS) + $(call if_changed,ar_emulator) + + +quiet_cmd_link_emulator = PAD $@ + cmd_link_emulator = ld -z norelro -z noexecstack -shared --no-undefined -X -Bsymbolic -z notext --emit-relocs --no-apply-dynamic-relocs \ + -T $(srctree)/drivers/firmware/efi/efi_emulator/arm64_emulator_service.lds \ + --whole-archive $< --no-whole-archive -o $@ + + +$(obj)/emulator.ro: $(obj)/emulator.a FORCE + $(call if_changed,link_emulator) + + +$(obj)/emulator.raw: $(obj)/emulator.ro FORCE + objcopy -O binary -R .note -R .note.gnu.build-id -R .comment -g $< $@ + +$(obj)/efi_emulator.o: $(obj)/emulator.raw + + +targets += $(emulator-y) + + diff --git a/drivers/firmware/efi/efi_emulator/amba-pl011.c b/drivers/firmware/efi/efi_emulator/amba-pl011.c new file mode 100644 index 0000000000000..334b25e177081 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/amba-pl011.c @@ -0,0 +1,80 @@ + +#include +#include +#include "earlycon.h" + +#define SERIAL_IO_MEM32 3 +#define UPIO_MEM32 SERIAL_IO_MEM32 + +struct uart_port { + unsigned long iobase; /* in/out[bwl] */ + unsigned char __iomem *membase; /* read/write[bwl] */ + unsigned char iotype; /* io access style */ +}; + +static struct uart_port pl011_port; + +static void pl011_putc(struct uart_port *port, unsigned char c) +{ + while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + cpu_relax(); + if (port->iotype == UPIO_MEM32) + writel(c, port->membase + UART01x_DR); + else + writeb(c, port->membase + UART01x_DR); + while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) + cpu_relax(); +} + +static int pl011_put_str(const char *str, void *data) +{ + char *p = (char *)str; + struct uart_port *port = (struct uart_port *)data; + + for (; *p != '\0'; p++) + pl011_putc(port, *p); + + return (p - str); +} + +static void pl011_write(struct uart_port *port, unsigned int reg, unsigned int val) +{ + void __iomem *addr = port->membase + reg; + + if (port->iotype == UPIO_MEM32) + writel_relaxed(val, addr); + else + writew_relaxed(val, addr); +} + +static bool pl011_match(struct efi_emulator_param *param, const char *name) +{ + struct uart_port *port = &pl011_port; + + if (strcmp(param->earlycon_name, name)) + return false; + + port->iotype = UPIO_MEM32; + port->membase = (unsigned char *)param->earlycon_reg_base; + return true; +} + +static void pl011_reset(void *data) +{ + struct uart_port *port = data; + + /* disable DMA */ + pl011_write(port, UART011_DMACR, 0); + /* disable interrupt */ + pl011_write(port, UART011_IMSC, 0); + /* Skip: set clk rate */ + /* Now, pl011 can be used in poll mode */ +} + +struct earlycon pl011 = { + .match = pl011_match, + .reset = pl011_reset, + .put_str = pl011_put_str, + .data = &pl011_port, + .name = "amba-pl011", +}; diff --git a/drivers/firmware/efi/efi_emulator/arm64_emulator_service.lds b/drivers/firmware/efi/efi_emulator/arm64_emulator_service.lds new file mode 100644 index 0000000000000..82d7659346af5 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/arm64_emulator_service.lds @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +ENTRY(emulator_entry) +EMULATOR_BASE_ADDR = 0x0; + +SECTIONS +{ + . = EMULATOR_BASE_ADDR; + .head : ALIGN(4096) { + *(.head.text) + } + + .text : { + *(.text* .init.text*) + } + + .rodata : ALIGN(8) { + *(.rodata* .init.rodata* .srodata*) + + _etext = ALIGN(4096); + . = _etext; + } + + .rela.dyn : ALIGN(4096) { + _rela_start = .; + *(.rela .rela*) + _rela_end = .; + } + + .data : ALIGN(4096) { + *(.data* .init.data*) + _edata = ALIGN(512); + . = _edata; + } + + .bss : { + *(.bss* .init.bss*) + _end = ALIGN(512); + . = _end; + } + + /DISCARD/ : { + *(.modinfo .init.modinfo) + } +} diff --git a/drivers/firmware/efi/efi_emulator/config_table.c b/drivers/firmware/efi/efi_emulator/config_table.c new file mode 100644 index 0000000000000..3efe76cbd86fd --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/config_table.c @@ -0,0 +1,23 @@ + +#include "emulator.h" + + +static efi_status_t conjoin_memreserve_table(void *table, efi_config_table_t *t) +{ + struct linux_efi_memreserve *prev, *next; + + prev = (struct linux_efi_memreserve *)t->table; + next = (struct linux_efi_memreserve *)table; + + prev->next = (phys_addr_t)next; + next->next = 0; + return EFI_SUCCESS; +} + +efi_status_t conjoin_table(efi_guid_t *uuid, void *table, efi_config_table_t *t) +{ + if (!efi_guidcmp(t->guid, LINUX_EFI_MEMRESERVE_TABLE_GUID)) + return conjoin_memreserve_table(table, t); + + return EFI_OUT_OF_RESOURCES; +} diff --git a/drivers/firmware/efi/efi_emulator/core.c b/drivers/firmware/efi/efi_emulator/core.c new file mode 100644 index 0000000000000..29f3671a2db26 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/core.c @@ -0,0 +1,211 @@ +#include +#include + +#include "emulator.h" + +int emulator_initialize(void); + +struct efi_emulator_param *emulator_param; + +static efi_loaded_image_t loaded_image; +static bool print_enabled; + +/* The 1st kernel convert cmdline to utf16 and pass to emulator */ +static efi_status_t handle_protocol_loaded_image(efi_handle_t h, void **data) +{ + loaded_image.load_options = emulator_param->cmdline; + loaded_image.load_options_size = emulator_param->sz_in_byte; + /* loaded address */ + loaded_image.image_base = 0x0; + + *data = &loaded_image; + return EFI_SUCCESS; + +} + + +static efi_status_t __efiapi emulator_handle_protocol(efi_handle_t h, + efi_guid_t *uuid, void **data) +{ + if (!efi_guidcmp(*uuid, LOADED_IMAGE_PROTOCOL_GUID)) + return handle_protocol_loaded_image(h, data); + + return EFI_UNSUPPORTED; +} + +//The LocateProtocol() function finds the first device handle that support Protocol, and returns a +// pointer to the protocol interface from that handle in Interface. If no protocol instances are found, then Interface is set to NULL. +static efi_status_t __efiapi emulator_locate_protocol(efi_guid_t *uuid, + void *registration, void **interface) +{ + if (!efi_guidcmp(*uuid, EFI_TCG2_PROTOCOL_GUID)) { + *interface = &emulator_tcg2; + return EFI_SUCCESS; + } else if (!efi_guidcmp(*uuid, EFI_CC_MEASUREMENT_PROTOCOL_GUID)) { + *interface = &emulator_cc; + return EFI_SUCCESS; + } else if (!efi_guidcmp(*uuid, EFI_RNG_PROTOCOL_GUID)) { + *interface = &emulator_rng; + return EFI_SUCCESS; + } + + return EFI_UNSUPPORTED; +} + +// 2do +static efi_status_t __efiapi emulator_allocate_pages(int alloc_type, int mem_type, + unsigned long nr_pages, efi_physical_addr_t *addr) +{ + return __emulator_allocate_pages(alloc_type, mem_type, nr_pages, addr); +} + +// 2do +static efi_status_t __efiapi emulator_free_pages(efi_physical_addr_t addr, + unsigned long nr_4KB) +{ + return EFI_SUCCESS; + +} + +static efi_status_t __efiapi emulator_allocate_pool(int mem_type, unsigned long sz, + void **pool) +{ + return __emulator_allocate_pool(mem_type, sz, pool); + +} + +static efi_status_t __efiapi emulator_free_pool(void *pool) +{ + return EFI_SUCCESS; + +} + +/* memmove() alias as memcpy() */ +static void __efiapi emulator_copy_mem(void *dest, const void *src, unsigned long count) +{ + char *tmp; + const char *s; + + if (dest <= src) { + tmp = dest; + s = src; + while (count--) + *tmp++ = *s++; + } else { + tmp = dest; + tmp += count; + s = src; + s += count; + while (count--) + *--tmp = *--s; + } + +} + +static void __efiapi emulator_set_mem(void *dst, unsigned long cnt, unsigned char val) +{ + unsigned char *dst_ptr = (char *)dst; + unsigned long i; + + for (i = 0; i < cnt; i++) + dst_ptr[i] = val; +} + +static efi_status_t __efiapi emulator_install_configuration_table(efi_guid_t *uuid, + void *table) +{ + efi_config_table_t *t = (efi_config_table_t *)systabs.tables; + int i; + + for (i = 0; i < systabs.nr_tables; i++, t++) { + if (!efi_guidcmp(t->guid, *uuid)) + return conjoin_table(uuid, table, t); + } + t->guid = *uuid; + t->table = table; + systabs.nr_tables++; + + return EFI_SUCCESS; +} + +/* + * As the final stage, destroy the boottime context, e.g. release the memory + * occupied by some data struct. + */ +static efi_status_t __efiapi emulator_exit_boot_services(efi_handle_t handle, + unsigned long map_key) +{ + return EFI_SUCCESS; +} + +static efi_boot_services_t bt_services = { + .handle_protocol = emulator_handle_protocol, + .locate_protocol = emulator_locate_protocol, + .allocate_pool = emulator_allocate_pool, + .free_pool = emulator_free_pool, + .allocate_pages = emulator_allocate_pages, + .free_pages = emulator_free_pages, + .copy_mem = emulator_copy_mem, + .set_mem = emulator_set_mem, + .get_memory_map = emulator_get_memory_map, + .install_configuration_table = emulator_install_configuration_table, + .exit_boot_services = emulator_exit_boot_services, +}; + +/* UCS-2 (Universal Coded Character Set) */ +static efi_status_t __efiapi output_string(efi_simple_text_output_protocol_t * simple, + efi_char16_t *str) +{ + if (print_enabled) + print_ucs2_string(str); + return EFI_SUCCESS; +} + +static efi_simple_text_output_protocol_t text_out = { + .output_string = output_string, +}; + +efi_system_table_t systabs = { + .hdr = { + .signature = EFI_SYSTEM_TABLE_SIGNATURE, + }, + + .con_out = &text_out, + .runtime = NULL, + .boottime = &bt_services, + .nr_tables = 0, + .tables = 0, + +}; + +static efi_rt_properties_table_t rt_support = { + .runtime_services_supported = 0, +}; + +int initialize_emulator_service(struct efi_emulator_param *param) +{ + + efi_config_table_t *tables; + unsigned int i; + + printf("initialize_emulator_service, dtb=0x%lx, mempool_start=0x%lx, end:0x%lx\n", + param->dtb, param->mempool_start, param->mempool_start + param->mempool_sz); + emulator_param = param; + print_enabled = param->print_enabled; + i = param->rt_info.systab_nr_tables; + systabs.tables = (unsigned long)¶m->rt_info.systab_tables; + tables = param->rt_info.systab_tables; + tables[i].guid = DEVICE_TREE_GUID; + tables[i].table = (void *)param->dtb; + i++; + if (!param->noefi_boot) { + rt_support.runtime_services_supported = param->rt_info.runtime_supported_mask; + } + tables[i].guid = EFI_RT_PROPERTIES_TABLE_GUID; + tables[i].table = (void *)&rt_support; + i++; + systabs.nr_tables = i; + + systabs.runtime = (efi_runtime_services_t *)param->rt_info.runtime; + return 0; +} diff --git a/drivers/firmware/efi/efi_emulator/earlycon.h b/drivers/firmware/efi/efi_emulator/earlycon.h new file mode 100644 index 0000000000000..189af549d5af2 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/earlycon.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include +#include +#include +#include + +struct earlycon { + bool (*match)(struct efi_emulator_param *param, const char *name); + int (*put_str)(const char *str, void *data); + void (*reset)(void *data); + void *data; + const char *name; +}; + +extern struct earlycon pl011; + +extern int pl011_puts(const char *str); +void setup_earlycon(struct efi_emulator_param *param); diff --git a/drivers/firmware/efi/efi_emulator/efi_emulator.S b/drivers/firmware/efi/efi_emulator/efi_emulator.S new file mode 100644 index 0000000000000..fb52593ba3b2e --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/efi_emulator.S @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + + .section .rodata, "a" + + .align 8 +_efi_emulator_start: + .globl _efi_emulator_start + .incbin "drivers/firmware/efi/efi_emulator/emulator.raw" + + .align 8 +_efi_emulator_end: + .globl _efi_emulator_end diff --git a/drivers/firmware/efi/efi_emulator/emulator.h b/drivers/firmware/efi/efi_emulator/emulator.h new file mode 100644 index 0000000000000..e524cbd92180c --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/emulator.h @@ -0,0 +1,66 @@ +#include +#include + +/* Included from drivers/firmware/efi/libstub */ +#include + +#define EMULATOR_BASE_ADDR 0 + +typedef union efi_rng_protocol efi_rng_protocol_t; + +union efi_rng_protocol { + struct { + efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *, + unsigned long *, + efi_guid_t *); + efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *, + efi_guid_t *, unsigned long, + u8 *out); + }; + struct { + u32 get_info; + u32 get_rng; + } mixed_mode; +}; + +struct uki_info { + unsigned long initrd_base; + unsigned long initrd_sz; + unsigned long cmdline_base; + unsigned long cmdline_sz; +}; + +extern struct efi_emulator_param *emulator_param; +extern efi_tcg2_protocol_t emulator_tcg2; +extern efi_cc_protocol_t emulator_cc; +extern efi_rng_protocol_t emulator_rng; +extern efi_system_table_t systabs; +extern efi_runtime_services_t rt_services; +extern char *heap_start, *heap_end, *heap_cur; + +void *aligned_alloc(size_t alignment, size_t size); +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +int strcmp(const char *cs, const char *ct); +size_t wcslen(const wchar_t *str); +int wcscmp(const wchar_t *s1, const wchar_t *s2); +int printf(const char *format, ...); +void print_ucs2_string(efi_char16_t* ucs2_str); + +efi_status_t __emulator_allocate_pages(int alloc_type, int mem_type, + unsigned long nr_pages, efi_physical_addr_t *addr); +efi_status_t __emulator_allocate_pool(int mem_type, unsigned long sz, + void **pool); +efi_status_t emulator_get_memory_map(unsigned long *map_sz, + void *memmap, unsigned long *map_key, unsigned long *desc_sz, + unsigned int *desc_version); + +efi_status_t conjoin_table(efi_guid_t *uuid, void *table, efi_config_table_t *t); + +int initialize_emulator_service(struct efi_emulator_param *param); +void initialize_heap(struct efi_emulator_param *param); +void load_kernel_pe(char *kern_buf, unsigned long sz, efi_system_table_t *systabs); +void load_kernel_from_mem(efi_system_table_t *systabs); +void emulator_main(struct efi_emulator_param *param); +void emulator_entry(struct efi_emulator_param *param); + diff --git a/drivers/firmware/efi/efi_emulator/entry.c b/drivers/firmware/efi/efi_emulator/entry.c new file mode 100644 index 0000000000000..c851a9acafa77 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/entry.c @@ -0,0 +1,57 @@ +//SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include + +#include "emulator.h" +#include "earlycon.h" + +extern void enable_sctlr_el1(unsigned long scratch_reg); +static void arch_handle_mmu(struct efi_emulator_param *param) +{ + if (!param->mmu_on && param->pgd_root) { + } +} + +extern const Elf64_Rela _rela_start[], _rela_end[]; + +static void noinline arch_reloc_fixup(long delta) +{ + unsigned long *apply_addr, res; + Elf64_Rela *rela; + + /* fix rela */ + for (rela = (Elf64_Rela *)_rela_start; rela < _rela_end; rela++) { + //todo counterpart of R_AARCH64_RELATIVE on riscv + if (ELF64_R_TYPE(rela->r_info) != R_AARCH64_RELATIVE) + continue; + apply_addr = (unsigned long *)(rela->r_offset + delta); + res = rela->r_addend + delta; + *apply_addr = res; + } + // todo flush cache + +} + +/* + * Ensure this entry and @param is in the mapping before jump to it. + * It should be PIC and at the beginning of emulator. + * It should be memory aligned + */ +void emulator_main(struct efi_emulator_param *param) +{ + long delta = param->load_address - EMULATOR_BASE_ADDR; + + arch_handle_mmu(param); + arch_reloc_fixup(delta); + setup_earlycon(param); + printf("param:0x%lx, delta=0x%lx\n", (unsigned long)param, delta); + printf("kernel_img_start:0x%lx, sz:0x%lx\n", (unsigned long)param->kernel_img_start, (unsigned long)param->kernel_img_sz); + initialize_emulator_service(param); + initialize_heap(param); + load_kernel_pe((char *)param->kernel_img_start, param->kernel_img_sz, + &systabs); +} diff --git a/drivers/firmware/efi/efi_emulator/head.S b/drivers/firmware/efi/efi_emulator/head.S new file mode 100644 index 0000000000000..8efa10f483a7c --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/head.S @@ -0,0 +1,10 @@ + +.section ".head.text","ax" + +/* x0 holds the physical address of emulator_param */ +emulator_entry: + ldr x1, [x0] + mov sp, x1 + adrp x2, emulator_main + add x2, x2, #:lo12:emulator_main + br x2 diff --git a/drivers/firmware/efi/efi_emulator/initrd.c b/drivers/firmware/efi/efi_emulator/initrd.c new file mode 100644 index 0000000000000..771b6f8954e33 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/initrd.c @@ -0,0 +1,15 @@ +// this file is a place holder to implment EFI_LOAD_FILE2_PROTOCOL.LoadFile(), not linked in yet + +static efi_status_t load_file(efi_load_file2_protocol_t *this, + efi_device_path_protocol_t *dp, bool boot_policy, + unsigned long buffer_sz, void *buffer) +{ + + struct efi_vendor_dev_path p = dp; + + if (!efiguid_cmp(p->vendorguid , LINUX_EFI_INITRD_MEDIA_GUID)) + if (uki_info.initrd_sz) { + memcpy(buffer, uki_info.initrd_base, uki_info.initrd_sz); + return; + } +} diff --git a/drivers/firmware/efi/efi_emulator/lib.c b/drivers/firmware/efi/efi_emulator/lib.c new file mode 100644 index 0000000000000..f12aa40405650 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/lib.c @@ -0,0 +1,73 @@ +//SPDX-License-Identifier: GPL-2.0 +#include "emulator.h" + +void *memcpy(void *dest, const void *src, size_t count) +{ + char *tmp = dest; + const char *s = src; + + while (count--) + *tmp++ = *s++; + return dest; +} + +void *memset(void *s, int c, size_t count) +{ + char *xs = s; + + while (count--) + *xs++ = c; + return s; +} + +int memcmp(const void *cs, const void *ct, size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} + +size_t strlen(const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +int strcmp(const char *cs, const char *ct) +{ + unsigned char c1, c2; + + while (1) { + c1 = *cs++; + c2 = *ct++; + if (c1 != c2) + return c1 < c2 ? -1 : 1; + if (!c1) + break; + } + return 0; +} + +int wcscmp(const wchar_t *s1, const wchar_t *s2) +{ + while (*s1 && (*s1 == *s2)) { + s1++; + s2++; + } + return (int)(*s1 - *s2); +} + +size_t wcslen(const wchar_t *str) +{ + const wchar_t *s; + + for (s = str; *s; ++s); + return (s - str); +} diff --git a/drivers/firmware/efi/efi_emulator/memory.c b/drivers/firmware/efi/efi_emulator/memory.c new file mode 100644 index 0000000000000..518ab7f30020e --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/memory.c @@ -0,0 +1,27 @@ +//SPDX-License-Identifier: GPL-2.0 +#include "emulator.h" + +char *heap_start, *heap_end, *heap_cur; + +void initialize_heap(struct efi_emulator_param *param) +{ + heap_start = (char *)param->mempool_start; + heap_end = heap_start + param->mempool_sz; + heap_cur = heap_start; +} + +//2do, the memory management is more complicated since we need to distinguish EFI_BOOT_SERVICE, RUNTIME, LOADER memory descr + +void *aligned_alloc(size_t alignment, size_t size) +{ + char *p; + + p = (char *)ALIGN((unsigned long)heap_cur, alignment); + heap_cur = p + size; + + //todo, update the efi_memory_desc to include this page, if it crosses the PAGE boundary + //as EFI_BOOT_SERVICE, + return p; +} + + diff --git a/drivers/firmware/efi/efi_emulator/memory_api.c b/drivers/firmware/efi/efi_emulator/memory_api.c new file mode 100644 index 0000000000000..709bbddaa4679 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/memory_api.c @@ -0,0 +1,73 @@ +#include +#include + +#include "emulator.h" + +/* + * mem_type affects the allocated chunk in efi_memory_desc_t's type. Later, + * kernel can know whether to reclaim them. + */ +efi_status_t __emulator_allocate_pages(int alloc_type, int mem_type, + unsigned long nr_pages, efi_physical_addr_t *addr) +{ + efi_physical_addr_t res; + efi_status_t status; + + if (alloc_type == EFI_ALLOCATE_ANY_PAGES) { + res = (efi_physical_addr_t)aligned_alloc(PAGE_SIZE, nr_pages << PAGE_SHIFT); + *addr = res; + status = EFI_SUCCESS; + } else if (alloc_type == EFI_ALLOCATE_MAX_ADDRESS) { + //tmp + res = (efi_physical_addr_t)aligned_alloc(PAGE_SIZE, nr_pages << PAGE_SHIFT); + *addr = res; + status = EFI_SUCCESS; + /* e.g. aarch64 kimage loaded alignment */ + } else if (alloc_type == EFI_ALLOCATE_ADDRESS) { + //tmp, just aligned on 2MB as aarch64 boot protocol + res = (efi_physical_addr_t)aligned_alloc(1<<21, nr_pages << PAGE_SHIFT); + *addr = res; + status = EFI_SUCCESS; + } + + return status; +} + +//todo +efi_status_t __emulator_allocate_pool(int mem_type, unsigned long sz, + void **pool) +{ + void *res; + + res = aligned_alloc(sizeof(unsigned long), sz); + *pool = res; + return EFI_SUCCESS; +} + +/* @memmap: only holds efi_memory_desc */ +efi_status_t emulator_get_memory_map(unsigned long *map_sz, + void *memmap, unsigned long *map_key, unsigned long *desc_sz, + unsigned int *desc_version) +{ + //todo rt_info.memmap will be accessed by kernel, so it should be marked as reserved + struct efi_boot_memmap *p = &emulator_param->rt_info.memmap; + //efi_memory_desc_t *desc = p->map; + + if (!map_sz || !desc_sz) + return EFI_INVALID_PARAMETER; + if (*map_sz < p->map_size || !memmap) { + *map_sz = p->map_size; + *desc_sz = p->desc_size; + return EFI_BUFFER_TOO_SMALL; + } + + /* desc range size*/ + *map_sz = p->map_size; + memcpy(memmap, p->map, p->map_size); + if (!!desc_sz) + *desc_sz = p->desc_size; + if (!!desc_version) + *desc_version = p->desc_ver; + + return EFI_SUCCESS; +} diff --git a/drivers/firmware/efi/efi_emulator/misc.c b/drivers/firmware/efi/efi_emulator/misc.c new file mode 100644 index 0000000000000..5a82adb6b193c --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/misc.c @@ -0,0 +1,76 @@ + +#include +#include + +#include "emulator.h" + +static efi_status_t __efiapi emulator_tcg2_hash_log_extend_event( + efi_tcg2_protocol_t *this, u64 flags, + efi_physical_addr_t data_to_hash, u64 data_to_hash_len, + const efi_tcg2_event_t *efi_td_event) +{ + + return EFI_SUCCESS; + +} + +efi_tcg2_protocol_t emulator_tcg2 = { + .hash_log_extend_event = emulator_tcg2_hash_log_extend_event, +}; + +static efi_status_t __efiapi emulator_cc_map_pcr_to_mr_index(efi_cc_protocol_t *this, + u32 pcr_index, efi_cc_mr_index_t *mr_index) +{ + return EFI_SUCCESS; +} + +static efi_status_t __efiapi emulator_cc_hash_log_extend_event( + efi_cc_protocol_t *this, u64 flags, + efi_physical_addr_t data_to_hash, u64 data_to_hash_len, + const efi_cc_event_t *efi_td_event) +{ + + return EFI_SUCCESS; +} + +efi_cc_protocol_t emulator_cc = { + .hash_log_extend_event = emulator_cc_hash_log_extend_event, + .map_pcr_to_mr_index = emulator_cc_map_pcr_to_mr_index, +}; + +static efi_status_t __efiapi emulator_get_rng(efi_rng_protocol_t * this, + efi_guid_t *uuid, unsigned long size, + u8 *out) +{ + //in fact, disable aslr + *out = 0; + return EFI_SUCCESS; +} + +efi_rng_protocol_t emulator_rng = { + .get_rng = emulator_get_rng, +}; + +static efi_status_t __efiapi emulator_get_memory_attributes( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64 *) +{ + return EFI_SUCCESS; +} + +static efi_status_t __efiapi emulator_set_memory_attributes( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64) +{ + return EFI_SUCCESS; +} + +static efi_status_t __efiapi emulator_clear_memory_attributes( + efi_memory_attribute_protocol_t *, efi_physical_addr_t, u64, u64) +{ + return EFI_SUCCESS; +} + +efi_memory_attribute_protocol_t emulator_memory_attribute = { + .get_memory_attributes = emulator_get_memory_attributes, + .set_memory_attributes = emulator_set_memory_attributes, + .clear_memory_attributes = emulator_clear_memory_attributes, +}; diff --git a/drivers/firmware/efi/efi_emulator/pe_loader.c b/drivers/firmware/efi/efi_emulator/pe_loader.c new file mode 100644 index 0000000000000..ff921d611a287 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/pe_loader.c @@ -0,0 +1,124 @@ + +#include +#include +#include +#include "emulator.h" + +#define VALID_PAYLOAD (IMAGE_SCN_CNT_CODE |IMAGE_SCN_CNT_INITIALIZED_DATA |IMAGE_SCN_CNT_UNINITIALIZED_DATA) + +typedef efi_status_t (*uefi_pe_entry)(efi_handle_t handle, efi_system_table_t *systab); + +struct pe_instance { + uefi_pe_entry entry; + efi_handle_t handle; +}; + +#if 0 +static struct uki_info uki_info; +#endif + +static int load_pe(char *buf, unsigned long buf_sz, unsigned long pe_hdr_offset, + struct pe_instance *inst, efi_system_table_t *systab) +{ + unsigned long exec_sz, load_addr, delta; + struct pe_hdr *pe_hdr; + struct pe32plus_opt_hdr *opt_hdr; + struct section_header *sect_hdr; + int section_nr, i; + char *src, *dst; + + pe_hdr = (struct pe_hdr *)buf; + section_nr = pe_hdr->sections; + opt_hdr = (struct pe32plus_opt_hdr *)(buf + sizeof(struct pe_hdr)); + sect_hdr = (struct section_header *)((char *)opt_hdr + pe_hdr->opt_hdr_size); + exec_sz = opt_hdr->image_size - opt_hdr->header_size; + + /* + * The allocated memory should meet the section aligment requirement. + * The first section is loaded at load_addr. + */ + load_addr = (unsigned long)aligned_alloc(opt_hdr->section_align, exec_sz); + + delta = load_addr - sect_hdr->virtual_address; + /*copy section to segment */ + //opt_hdr->section_align; + for (i = 0; i < section_nr; i++) { + if (!(sect_hdr->flags & VALID_PAYLOAD)) { + sect_hdr++; + continue; + } + /* data_addr is relative to the whole file */ + src = buf + sect_hdr->data_addr - pe_hdr_offset; + dst = (char *)(sect_hdr->virtual_address + delta); + memcpy(dst, src, sect_hdr->raw_data_size); + memset(dst + sect_hdr->raw_data_size, 0, sect_hdr->virtual_size - sect_hdr->raw_data_size); +#if 0 + //2do, for UKI + if (strcmp(sect_hdr->name, ".initrd")) { + uki_info.initrd_base = dst; + uki_info.initrd_sz = sect_hdr->raw_data_size; + } + if (strcmp(sect_hdr->name, ".cmdline")) { + uki_info.cmdline_base = dst; + uki_info.cmdline_sz = sect_hdr->raw_data_size; + } +#endif + sect_hdr++; + } + + /* no need to resolve relocation */ + + /* As for SP, using the current value */ + + inst->entry = (uefi_pe_entry)(opt_hdr->entry_point + delta); + inst->handle = (efi_handle_t)load_addr; + + printf("entry_point:0x%lx, delta:0x%lx, final inst's entry at:0x%lx\n", + opt_hdr->entry_point, delta, inst->entry); + return 0; +} + +static int launch_pe(char *pe_buf, u64 buf_sz, unsigned long pe_hdr_offset, efi_system_table_t *systab) +{ + struct pe_instance inst; + + load_pe(pe_buf, buf_sz, pe_hdr_offset, &inst, systab); + inst.entry(inst.handle, systab); + return 0; +} + +struct input_param_passed_by { + u64 kernel_pa_start; + u64 kernel_sz; + u64 pgtable; + u64 memory_descs; +}; + + +/* see drivers/firmware/efi/libstub/zboot-header.S */ +struct linux_pe_zboot_header { + uint32_t mz_magic; + uint32_t image_type; + uint32_t payload_offset; + uint32_t payload_size; + uint32_t reserved[2]; + uint32_t compress_type; +}; + +void load_kernel_pe(char *kern_buf, unsigned long sz, efi_system_table_t *systabs) +{ + struct linux_pe_zboot_header *hdr; + u32 pe_hdr_offset; + char *buf = kern_buf; + + hdr = (struct linux_pe_zboot_header *)buf; + /* Check mz signature */ + if (memcmp(&hdr->image_type, "zimg", sizeof(hdr->image_type))) + return; + pe_hdr_offset = *((u32 *)(buf + 0x3c)); + /* */ + buf += pe_hdr_offset; + sz -= pe_hdr_offset; + launch_pe(buf, sz, pe_hdr_offset, systabs); +} + diff --git a/drivers/firmware/efi/efi_emulator/printf.c b/drivers/firmware/efi/efi_emulator/printf.c new file mode 100644 index 0000000000000..367d1ede98422 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/printf.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* The most of this file is copied from arch/x86/boot/printf.c */ + +#include +#include + +#include "earlycon.h" +#include "emulator.h" + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SMALL 32 /* Must be 32 == 0x20 */ +#define SPECIAL 64 /* 0x */ + +#define __do_div(n, base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char *number(char *str, long num, int base, int size, int precision, + int type) +{ + /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ + static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ + + char tmp[66]; + char c, sign, locase; + int i; + + /* locase = 0 or 0x20. ORing digits or letters with 'locase' + * produces same digits or (maybe lowercased) letters */ + locase = (type & SMALL); + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 16) + return NULL; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = (digits[__do_div(num, base)] | locase); + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base == 8) + *str++ = '0'; + else if (base == 16) { + *str++ = '0'; + *str++ = ('X' | locase); + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char *str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str = buf; *fmt; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'x': + flags |= SMALL; + fallthrough; + case 'X': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short)va_arg(args, int); + if (flags & SIGN) + num = (short)num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str - buf; +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + return i; +} + +static struct earlycon *con; + +static int puts(const char *s) +{ + if (con) + return con->put_str(s, con->data); + else + return 0; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} + + +static size_t utf16_to_ascii(char *s, efi_char16_t c16) +{ + unsigned char lead; + size_t len; + + if (c16 < 0x80) { + /* 1-byte sequence */ + if (s) *s = c16; + len = 1; + } else if (c16 < 0x800) { + /* 2-byte sequence */ + lead = 0xC0; + len = 2; + } else { + /* 3-byte sequence */ + lead = 0xE0; + len = 3; + } + + if (s) { + switch (len) { + case 3: + s[2] = 0x80 | (c16 & 0x3F); + c16 >>= 6; + fallthrough; + case 2: + s[1] = 0x80 | (c16 & 0x3F); + c16 >>= 6; + fallthrough; + case 1: + s[0] = lead | c16; + } + } + return len; +} + +/* Convert the UCS-2 string to a UTF-8 string */ +void print_ucs2_string(efi_char16_t* ucs2_str) +{ + char utf8_str[1024]; + char* p = utf8_str; + + while (*ucs2_str) + p += utf16_to_ascii(p, *ucs2_str++); + + /* Null-terminate the UTF-8 string */ + *p = '\0'; + /* Print the UTF-8 string */ + printf("%s\n", utf8_str); +} + +static struct earlycon *all_con_types[] = { &pl011, }; + +void setup_earlycon(struct efi_emulator_param *param) +{ + struct earlycon *p; + int i; + + for (i = 0; i < sizeof(all_con_types) / sizeof(struct earlycon *); i++) { + + p = all_con_types[i]; + if (p->match(param, p->name)) { + con = p; + p->reset(p->data); + break; + } + } +} diff --git a/drivers/firmware/efi/efi_emulator/runtime_service.c b/drivers/firmware/efi/efi_emulator/runtime_service.c new file mode 100644 index 0000000000000..87e49a8d4e2db --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/runtime_service.c @@ -0,0 +1,28 @@ +//SPDX-License-Identifier: GPL-2.0 + +#include "emulator.h" + +static efi_status_t emulator_get_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 *attr, unsigned long *data_size, void *data) +{ + if (!efi_guidcmp(*vendor, EFI_GLOBAL_VARIABLE_GUID)) { + if (wcscmp(name, L"SecureBoot")) + return EFI_NOT_FOUND; + } + return EFI_NOT_FOUND; +} + +static efi_status_t emulator_set_virtual_address_map(unsigned long memory_map_size, + unsigned long descriptor_size, + u32 descriptor_version, + efi_memory_desc_t *virtual_map) +{ + /* The first kernel has called this one-shot service */ + return EFI_NOT_FOUND; +} + +efi_runtime_services_t rt_services = { + .set_virtual_address_map = emulator_set_virtual_address_map, + .get_variable = emulator_get_variable, + +}; diff --git a/include/linux/efi_emulator.h b/include/linux/efi_emulator.h new file mode 100644 index 0000000000000..cb977539cf05f --- /dev/null +++ b/include/linux/efi_emulator.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_EFI_EMULATOR_H +#define _LINUX_EFI_EMULATOR_H + +#include +#include +#include + +//todo, arch abstraction, for x86, it is efi_info +struct efi_rt_info { + const efi_runtime_services_t *runtime; /* EFI runtime services table */ + unsigned int runtime_version; /* Runtime services version */ + u32 runtime_supported_mask; + /* Build systab tables from the following */ + unsigned int systab_nr_tables; + efi_config_table_t systab_tables[20]; + struct efi_boot_memmap memmap; +}; + +/* 1st kernel passes information through this struct */ +struct efi_emulator_param { + unsigned long sp; + /* Should be page-aligned */ + unsigned long load_address; + unsigned int sz_in_byte; + wchar_t cmdline[512]; + bool noefi_boot; + bool print_enabled; + char earlycon_name[16]; + phys_addr_t earlycon_reg_base; + unsigned long earlycon_reg_sz; + + bool mmu_on; + /* root of pgtable */ + phys_addr_t pgd_root; + phys_addr_t kernel_img_start; + unsigned long kernel_img_sz; + phys_addr_t dtb; + phys_addr_t mempool_start; + unsigned long mempool_sz; + struct efi_rt_info rt_info; +}; + +extern unsigned char _efi_emulator_start[], _efi_emulator_end[]; +#endif diff --git a/include/linux/kexec.h b/include/linux/kexec.h index f0e9f8eda7a3c..cff6b6869498b 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -325,6 +325,7 @@ struct kimage { unsigned int hotplug_support:1; #endif + bool is_pe; #ifdef ARCH_HAS_KIMAGE_ARCH struct kimage_arch arch; #endif @@ -462,6 +463,7 @@ static inline int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, g static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { } #endif +extern phys_addr_t arch_emulator_prepare_pgtable(struct kimage *kimage); extern bool kexec_file_dbg_print; #define kexec_dprintk(fmt, arg...) \ From patchwork Thu Jul 18 08:57:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813465 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 839C07A715 for ; Thu, 18 Jul 2024 08:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293141; cv=none; b=qBfUswdMCJEXn3dYbP+yuFIS70/oZeKjW5pmgOZmSiZyPcUgogYEiWXe7ETJdWfcbxueilIo4YPhdxSnSUoqQnCaWX1NwzMuPZ4F8j2jXXaLCIOqvtPbxbw3IDQrsBi33V8yHQxIOVdKUwlNcx2OzUQMex2BbaYNPgaZMqSKCHU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293141; c=relaxed/simple; bh=WvM6ksWWkq/FNg3fLLzue/bhMJ5E/AhlOLtKYPvMRfU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pvRu4lCRme3suOJeS75mn08CFTnNwqBQCbE08oll22BYAwbKI7oPA+ikgE70EKC/hgyt43XqYzGy2aP/zg6gsMpYuzaeEeVRrfo5x6t8Gb6ZxWXj8+ezeReMtaOVIo3D/ArA57KaLu9Z1k3vKy4GYJP8vnu1r2qgD2smToNUWHk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=MOOITPmb; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="MOOITPmb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293138; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ON75peU/bs1K8lvZg4F3KV8/U1IV42h+4HalwWFCbTc=; b=MOOITPmbn5M9n95OOzfp8fEj0WjjD51sxSTr7W5ofy6SFQtkYC/qnDUCEAxX4FFZTsBRq8 6jymIeJRZqanN/+sbSw0gf4Dt0mHCDZRVP/UQXd674WgKTgvGRgQXFRWRbK0QEygy4V4Xl h1Y+PQAXhJb8FtsYx8CJS+6mY2A55Kk= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-13-AC18grf3O964ewF1iYDe3Q-1; Thu, 18 Jul 2024 04:58:55 -0400 X-MC-Unique: AC18grf3O964ewF1iYDe3Q-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9E4BB1955D56; Thu, 18 Jul 2024 08:58:53 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 825A03000185; Thu, 18 Jul 2024 08:58:46 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 4/7] efi/emulator: Turn on mmu for arm64 Date: Thu, 18 Jul 2024 16:57:54 +0800 Message-ID: <20240718085759.13247-5-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 On arm64, when kexec switches to the new kernel, the mmu is off. So the efi emulator should turn on the mmu to enable the identity mapping at the first stage. In fact, the kexec switching can run with mmu-on if it enters emulator, but that requires the re-arrangement of the relocate_kernel.S [1]. After that, this patch can be drop. But let us focus on emulator itself and keep things simple for the time being. [1]: https://lore.kernel.org/linux-arm-kernel/20240328115656.24090-1-piliu@redhat.com/ Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- drivers/firmware/efi/efi_emulator/Makefile | 2 +- .../firmware/efi/efi_emulator/arm64_proc.S | 172 ++++++++++++++++++ drivers/firmware/efi/efi_emulator/entry.c | 7 + 3 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/efi/efi_emulator/arm64_proc.S diff --git a/drivers/firmware/efi/efi_emulator/Makefile b/drivers/firmware/efi/efi_emulator/Makefile index e37472004a2b5..b78a6241182fc 100644 --- a/drivers/firmware/efi/efi_emulator/Makefile +++ b/drivers/firmware/efi/efi_emulator/Makefile @@ -64,7 +64,7 @@ OBJECT_FILES_NON_STANDARD := y emulator-y := head.o entry.o \ core.o pe_loader.o misc.o memory.o memory_api.o runtime_service.o config_table.o \ lib.o printf.o \ - amba-pl011.o + amba-pl011.o arm64_proc.o obj-y := efi_emulator.o diff --git a/drivers/firmware/efi/efi_emulator/arm64_proc.S b/drivers/firmware/efi/efi_emulator/arm64_proc.S new file mode 100644 index 0000000000000..93618637e4935 --- /dev/null +++ b/drivers/firmware/efi/efi_emulator/arm64_proc.S @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Based on arch/arm/mm/proc.S + * + * Copyright (C) 2001 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * Author: Catalin Marinas + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARM64_64K_PAGES +#define TCR_TG_FLAGS TCR_TG0_64K | TCR_TG1_64K +#elif defined(CONFIG_ARM64_16K_PAGES) +#define TCR_TG_FLAGS TCR_TG0_16K | TCR_TG1_16K +#else /* CONFIG_ARM64_4K_PAGES */ +#define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K +#endif + +#ifdef CONFIG_RANDOMIZE_BASE +#define TCR_KASLR_FLAGS TCR_NFD1 +#else +#define TCR_KASLR_FLAGS 0 +#endif + +#define TCR_SMP_FLAGS TCR_SHARED + +/* PTWs cacheable, inner/outer WBWA */ +#define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA + +#ifdef CONFIG_KASAN_SW_TAGS +#define TCR_KASAN_SW_FLAGS TCR_TBI1 | TCR_TBID1 +#else +#define TCR_KASAN_SW_FLAGS 0 +#endif + +#ifdef CONFIG_KASAN_HW_TAGS +#define TCR_MTE_FLAGS TCR_TCMA1 | TCR_TBI1 | TCR_TBID1 +#elif defined(CONFIG_ARM64_MTE) +/* + * The mte_zero_clear_page_tags() implementation uses DC GZVA, which relies on + * TBI being enabled at EL1. + */ +#define TCR_MTE_FLAGS TCR_TBI1 | TCR_TBID1 +#else +#define TCR_MTE_FLAGS 0 +#endif + +/* + * Default MAIR_EL1. MT_NORMAL_TAGGED is initially mapped as Normal memory and + * changed during mte_cpu_setup to Normal Tagged if the system supports MTE. + */ +#define MAIR_EL1_SET \ + (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRnE, MT_DEVICE_nGnRnE) | \ + MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \ + MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \ + MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \ + MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL_TAGGED)) + + +SYM_FUNC_START(__cpu_setup) + tlbi vmalle1 // Invalidate local TLB + dsb nsh + + msr cpacr_el1, xzr // Reset cpacr_el1 + mov x1, #1 << 12 // Reset mdscr_el1 and disable + msr mdscr_el1, x1 // access to the DCC from EL0 + reset_pmuserenr_el0 x1 // Disable PMU access from EL0 + reset_amuserenr_el0 x1 // Disable AMU access from EL0 + + /* + * Default values for VMSA control registers. These will be adjusted + * below depending on detected CPU features. + */ + mair .req x17 + tcr .req x16 + mov_q mair, MAIR_EL1_SET + mov_q tcr, TCR_T0SZ(IDMAP_VA_BITS) | TCR_T1SZ(VA_BITS_MIN) | TCR_CACHE_FLAGS | \ + TCR_SMP_FLAGS | TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ + TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS + + tcr_clear_errata_bits tcr, x9, x5 + +#ifdef CONFIG_ARM64_VA_BITS_52 + mov x9, #64 - VA_BITS +alternative_if ARM64_HAS_VA52 + tcr_set_t1sz tcr, x9 +#ifdef CONFIG_ARM64_LPA2 + orr tcr, tcr, #TCR_DS +#endif +alternative_else_nop_endif +#endif + + /* + * Set the IPS bits in TCR_EL1. + */ + tcr_compute_pa_size tcr, #TCR_IPS_SHIFT, x5, x6 +#ifdef CONFIG_ARM64_HW_AFDBM + /* + * Enable hardware update of the Access Flags bit. + * Hardware dirty bit management is enabled later, + * via capabilities. + */ + mrs x9, ID_AA64MMFR1_EL1 + and x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK + cbz x9, 1f + orr tcr, tcr, #TCR_HA // hardware Access flag update +1: +#endif /* CONFIG_ARM64_HW_AFDBM */ + msr mair_el1, mair + msr tcr_el1, tcr + + mrs_s x1, SYS_ID_AA64MMFR3_EL1 + ubfx x1, x1, #ID_AA64MMFR3_EL1_S1PIE_SHIFT, #4 + cbz x1, .Lskip_indirection + + /* + * The PROT_* macros describing the various memory types may resolve to + * C expressions if they include the PTE_MAYBE_* macros, and so they + * can only be used from C code. The PIE_E* constants below are also + * defined in terms of those macros, but will mask out those + * PTE_MAYBE_* constants, whether they are set or not. So #define them + * as 0x0 here so we can evaluate the PIE_E* constants in asm context. + */ + +#define PTE_MAYBE_NG 0 +#define PTE_MAYBE_SHARED 0 + + mov_q x0, PIE_E0 + msr REG_PIRE0_EL1, x0 + mov_q x0, PIE_E1 + msr REG_PIR_EL1, x0 + +#undef PTE_MAYBE_NG +#undef PTE_MAYBE_SHARED + + mov x0, TCR2_EL1x_PIE + msr REG_TCR2_EL1, x0 + +.Lskip_indirection: + + /* + * Prepare SCTLR + */ + mov_q x0, INIT_SCTLR_EL1_MMU_ON + ret // return to head.S + + .unreq mair + .unreq tcr +SYM_FUNC_END(__cpu_setup) + +SYM_FUNC_START(enable_sctlr_el1) + stp x29, x30, [sp, #-16]! + bl __cpu_setup + set_sctlr_el1 x0 + ldp x29, x30, [sp], #16 + ret +SYM_FUNC_END(enable_sctlr_el1) + diff --git a/drivers/firmware/efi/efi_emulator/entry.c b/drivers/firmware/efi/efi_emulator/entry.c index c851a9acafa77..a72a746805666 100644 --- a/drivers/firmware/efi/efi_emulator/entry.c +++ b/drivers/firmware/efi/efi_emulator/entry.c @@ -13,6 +13,13 @@ extern void enable_sctlr_el1(unsigned long scratch_reg); static void arch_handle_mmu(struct efi_emulator_param *param) { if (!param->mmu_on && param->pgd_root) { + unsigned long scratch_reg = 0; + // in fact, we need SYM_FUNC_START(__cpu_setup), later, set SCTLR_EL1 + // At present, the mmu is not ON + write_sysreg(param->pgd_root, ttbr0_el1); + isb(); + /* scratch_reg asks the C compiler to save x0 */ + enable_sctlr_el1(scratch_reg); } } From patchwork Thu Jul 18 08:57:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813255 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D9147A715 for ; Thu, 18 Jul 2024 08:59:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293152; cv=none; b=fsJJ5N2ju6eJxkExwNgufvDqfzurkNhNc7E2GJ7JSyi1L2HNprKpX38VQZo6IMIqL25T6PIGy56VNP7d29wseJDohFLI6KXN+BiUmI0tMqg1P56qR06bYnNeOIW6Mw7w+1aPmfv7y4lU6udmszaash4CzpCvOgSoHCdOQu9oTzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293152; c=relaxed/simple; bh=pLbTxH8m3Pu5d2m2lDWp6Z1THC/A+jDNHTYZyc+OQUY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fUNsRDnd8Q6RZiZu4AFG/QYpYx5jX8p4LutJQ1vw0qsJzyE6Vj3HMIc436IVAW7K1GunD+YNFeSBqRLA+YA+e4Y9u5UNecvbrzxsRyN726KfTvCX/rBdQOemJdVcgKufrTdaBTjibgxnMPn73pKjIKnRTd8ZFuyrIkASlbB1DBA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=XMcQjuhW; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="XMcQjuhW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293149; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zCmuPnEyTzB6M7DQihQfFxfvOrguOlS28iXHft0X5VU=; b=XMcQjuhWfJGr85MabQcSsYXDlxynnspHc8am4HL2xo6ChVVxWueOtWCCU3NXR9aLu6XVCl zq/ZWNMtVxSvq0RrmMYyzxcR56Q50SUBr7Be0qyWJ2pYEoNLAT+E+M/CJLl1IXpvb+S51j vS+10yUjAD5P+nZ14SvfnKaNwdwBh2M= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-582-ya1IOQc7NVm-WgfSceEv2g-1; Thu, 18 Jul 2024 04:59:04 -0400 X-MC-Unique: ya1IOQc7NVm-WgfSceEv2g-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4ABFE1955BED; Thu, 18 Jul 2024 08:59:02 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6EBBC3000185; Thu, 18 Jul 2024 08:58:54 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 5/7] arm64: mm: Change to prototype of Date: Thu, 18 Jul 2024 16:57:55 +0800 Message-ID: <20240718085759.13247-6-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 The current allocator of __create_pgd_mapping_locked() takes only one parameter, which reflects the current level of page table. But kexec_page_alloc() should extra control information from the parameter kimage. In order to make kexec_page_alloc() as an allocator, re-shape the prototype of the allocator and hence of the __create_pgd_mapping_locked(). Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- arch/arm64/include/asm/mmu.h | 6 ++++ arch/arm64/mm/mmu.c | 67 ++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 65977c7783c58..4b908e0650105 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -64,6 +64,12 @@ extern void arm64_memblock_init(void); extern void paging_init(void); extern void bootmem_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); +extern void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, + unsigned long virt, phys_addr_t size, + pgprot_t prot, + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, + int flags); extern void create_mapping_noalloc(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot); extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index c927e9312f102..875e2bc0cfb39 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -106,7 +106,7 @@ pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, } EXPORT_SYMBOL(phys_mem_access_prot); -static phys_addr_t __init early_pgtable_alloc(int shift) +static phys_addr_t __init early_pgtable_alloc(int shift, void *unused) { phys_addr_t phys; @@ -190,7 +190,8 @@ static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end, static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), + phys_addr_t (*pgtable_alloc)(int, void *arg), + void *arg, int flags) { unsigned long next; @@ -205,7 +206,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, if (flags & NO_EXEC_MAPPINGS) pmdval |= PMD_TABLE_PXN; BUG_ON(!pgtable_alloc); - pte_phys = pgtable_alloc(PAGE_SHIFT); + pte_phys = pgtable_alloc(PAGE_SHIFT, arg); ptep = pte_set_fixmap(pte_phys); init_clear_pgtable(ptep); ptep += pte_index(addr); @@ -241,7 +242,9 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), int flags) + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, + int flags) { unsigned long next; @@ -263,7 +266,7 @@ static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, READ_ONCE(pmd_val(*pmdp)))); } else { alloc_init_cont_pte(pmdp, addr, next, phys, prot, - pgtable_alloc, flags); + pgtable_alloc, arg, flags); BUG_ON(pmd_val(old_pmd) != 0 && pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp))); @@ -275,7 +278,9 @@ static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end, static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), int flags) + phys_addr_t (*pgtable_alloc)(int, void *), + void * arg, + int flags) { unsigned long next; pud_t pud = READ_ONCE(*pudp); @@ -292,7 +297,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, if (flags & NO_EXEC_MAPPINGS) pudval |= PUD_TABLE_PXN; BUG_ON(!pgtable_alloc); - pmd_phys = pgtable_alloc(PMD_SHIFT); + pmd_phys = pgtable_alloc(PMD_SHIFT, arg); pmdp = pmd_set_fixmap(pmd_phys); init_clear_pgtable(pmdp); pmdp += pmd_index(addr); @@ -312,7 +317,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, (flags & NO_CONT_MAPPINGS) == 0) __prot = __pgprot(pgprot_val(prot) | PTE_CONT); - init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags); + init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, arg, flags); pmdp += pmd_index(next) - pmd_index(addr); phys += next - addr; @@ -323,7 +328,8 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, int flags) { unsigned long next; @@ -337,7 +343,7 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, if (flags & NO_EXEC_MAPPINGS) p4dval |= P4D_TABLE_PXN; BUG_ON(!pgtable_alloc); - pud_phys = pgtable_alloc(PUD_SHIFT); + pud_phys = pgtable_alloc(PUD_SHIFT, arg); pudp = pud_set_fixmap(pud_phys); init_clear_pgtable(pudp); pudp += pud_index(addr); @@ -368,7 +374,7 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, READ_ONCE(pud_val(*pudp)))); } else { alloc_init_cont_pmd(pudp, addr, next, phys, prot, - pgtable_alloc, flags); + pgtable_alloc, arg, flags); BUG_ON(pud_val(old_pud) != 0 && pud_val(old_pud) != READ_ONCE(pud_val(*pudp))); @@ -381,7 +387,8 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, phys_addr_t phys, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, int flags) { unsigned long next; @@ -395,7 +402,7 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, if (flags & NO_EXEC_MAPPINGS) pgdval |= PGD_TABLE_PXN; BUG_ON(!pgtable_alloc); - p4d_phys = pgtable_alloc(P4D_SHIFT); + p4d_phys = pgtable_alloc(P4D_SHIFT, arg); p4dp = p4d_set_fixmap(p4d_phys); init_clear_pgtable(p4dp); p4dp += p4d_index(addr); @@ -411,7 +418,7 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, next = p4d_addr_end(addr, end); alloc_init_pud(p4dp, addr, next, phys, prot, - pgtable_alloc, flags); + pgtable_alloc, arg, flags); BUG_ON(p4d_val(old_p4d) != 0 && p4d_val(old_p4d) != READ_ONCE(p4d_val(*p4dp))); @@ -422,10 +429,11 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, p4d_clear_fixmap(); } -static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, +void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, int flags) { unsigned long addr, end, next; @@ -445,7 +453,7 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, do { next = pgd_addr_end(addr, end); alloc_init_p4d(pgdp, addr, next, phys, prot, pgtable_alloc, - flags); + arg, flags); phys += next - addr; } while (pgdp++, addr = next, addr != end); } @@ -453,12 +461,13 @@ static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys, static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), + phys_addr_t (*pgtable_alloc)(int, void *), + void *arg, int flags) { mutex_lock(&fixmap_lock); __create_pgd_mapping_locked(pgdir, phys, virt, size, prot, - pgtable_alloc, flags); + pgtable_alloc, arg, flags); mutex_unlock(&fixmap_lock); } @@ -466,10 +475,10 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys, extern __alias(__create_pgd_mapping_locked) void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot, - phys_addr_t (*pgtable_alloc)(int), int flags); + phys_addr_t (*pgtable_alloc)(int, void *), void *arg, int flags); #endif -static phys_addr_t __pgd_pgtable_alloc(int shift) +static phys_addr_t __pgd_pgtable_alloc(int shift, void *unused) { /* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */ void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL & ~__GFP_ZERO); @@ -478,9 +487,9 @@ static phys_addr_t __pgd_pgtable_alloc(int shift) return __pa(ptr); } -static phys_addr_t pgd_pgtable_alloc(int shift) +static phys_addr_t pgd_pgtable_alloc(int shift, void *unused) { - phys_addr_t pa = __pgd_pgtable_alloc(shift); + phys_addr_t pa = __pgd_pgtable_alloc(shift, unused); struct ptdesc *ptdesc = page_ptdesc(phys_to_page(pa)); /* @@ -512,7 +521,7 @@ void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt, &phys, virt); return; } - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, + __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, NULL, NO_CONT_MAPPINGS); } @@ -528,7 +537,7 @@ void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; __create_pgd_mapping(mm->pgd, phys, virt, size, prot, - pgd_pgtable_alloc, flags); + pgd_pgtable_alloc, NULL, flags); } static void update_mapping_prot(phys_addr_t phys, unsigned long virt, @@ -540,7 +549,7 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt, return; } - __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, + __create_pgd_mapping(init_mm.pgd, phys, virt, size, prot, NULL, NULL, NO_CONT_MAPPINGS); /* flush the TLBs after updating live kernel mappings */ @@ -551,7 +560,7 @@ static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start, phys_addr_t end, pgprot_t prot, int flags) { __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start, - prot, early_pgtable_alloc, flags); + prot, early_pgtable_alloc, NULL, flags); } void __init mark_linear_text_alias_ro(void) @@ -742,7 +751,7 @@ static int __init map_entry_trampoline(void) memset(tramp_pg_dir, 0, PGD_SIZE); __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, entry_tramp_text_size(), prot, - __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS); + __pgd_pgtable_alloc, NULL, NO_BLOCK_MAPPINGS); /* Map both the text and data into the kernel page table */ for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++) @@ -1344,7 +1353,7 @@ int arch_add_memory(int nid, u64 start, u64 size, flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), - size, params->pgprot, __pgd_pgtable_alloc, + size, params->pgprot, __pgd_pgtable_alloc, NULL, flags); memblock_clear_nomap(start, size); From patchwork Thu Jul 18 08:57:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pingfan Liu X-Patchwork-Id: 813464 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 742E17A715 for ; Thu, 18 Jul 2024 08:59:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293160; cv=none; b=arYRFyEeyTTOTtN2HbACIA8Xhky3NZtXvAXXho5/m2j2x2foKqVbnmucXEvgSuasnXs5VtsjSevEyM6VyGmMVr0L7ytCppVVbj5Ouv1IBBfDpamNU7pTqURgcgpcHMnTMb86kVYPtYfZKWHmtFJHlHiANQRrXK+1AzX23oV9zEc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721293160; c=relaxed/simple; bh=Rwc+Z9bYlpYjE73SsPLbEFcVwo5dDaEVDQguWUeVBVk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=akApZln12so9odAy+qUm8n275sSRfeSg97MbQnzgUsTPpmUpEjQ0fiLJVtv/uRTgrkqXub/3FODtyV4Kd3rukvbOiWxMyR/Y6xiT+ikXukOvE3548JqdEYlCLVRgoFDLfQ3E7QUFlQzo98vO0UZrP8j636a7kmkfuKdZwaP2fdg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=cljem0p2; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="cljem0p2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1721293157; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=3hNfYZDiuxS1NyyJIIF1E+E75SCF0d1XgAjWnjU5K1g=; b=cljem0p2JoihKvvwHnEBe/rFQqFiK472qes0QC0+ETnkYUpHPGWBibKRw0Zd/fjywMu+ts SWXPinO1km5IWZoFbasRDIe+Dp7P/X89PJsLIaQLvXUTEK4sDbSRnSWdapHEH042M7hrDh KlwY/mZdm6y+WjLwR7ELbfpVYyB+Vrg= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-589-D31q2u5bOAauFQDGlbOiXQ-1; Thu, 18 Jul 2024 04:59:14 -0400 X-MC-Unique: D31q2u5bOAauFQDGlbOiXQ-1 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1EF131955D5C; Thu, 18 Jul 2024 08:59:11 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.125]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 13330300018A; Thu, 18 Jul 2024 08:59:02 +0000 (UTC) From: Pingfan Liu To: linux-arm-kernel@lists.infradead.org, kexec@lists.infradead.org, linux-efi@vger.kernel.org Cc: Pingfan Liu , Ard Biesheuvel , Jan Hendrik Farr , Philipp Rudo , Lennart Poettering , Jarkko Sakkinen , Baoquan He , Dave Young , Mark Rutland , Will Deacon , Catalin Marinas Subject: [RFC 6/7] arm64: kexec: Prepare page table for emulator Date: Thu, 18 Jul 2024 16:57:56 +0800 Message-ID: <20240718085759.13247-7-piliu@redhat.com> In-Reply-To: <20240718085759.13247-1-piliu@redhat.com> References: <20240718085759.13247-1-piliu@redhat.com> Precedence: bulk X-Mailing-List: linux-efi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 The emulator will run in identity mapping, and the first kernel prepares for it. The special allocator resorts to kimage_alloc_control_pages(), which can avoid the allocation on the spot of the destination and overwritten during copying the kernel. The identity mapping covers only all of the kexec segments, and this reduces the memory consumption of page table. Signed-off-by: Pingfan Liu Cc: Ard Biesheuvel Cc: Jan Hendrik Farr Cc: Philipp Rudo Cc: Lennart Poettering Cc: Jarkko Sakkinen Cc: Baoquan He Cc: Dave Young Cc: Mark Rutland Cc: Will Deacon Cc: Catalin Marinas To: linux-arm-kernel@lists.infradead.org To: kexec@lists.infradead.org To: linux-efi@vger.kernel.org --- arch/arm64/kernel/machine_kexec.c | 90 +++++++++++++++++++++++++++++-- include/linux/kexec.h | 5 +- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 82e2203d86a31..ae76874879188 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -86,8 +87,22 @@ static void kexec_segment_flush(const struct kimage *kimage) } } +/* todo: alloc page for the pgtable used by efi emulator in crashkernel range */ +static phys_addr_t crash_page_alloc(int unused, void *arg) +{ + struct kimage *kimage = (struct kimage *)arg; + int i; + + //skip kimage->segment[].mem + for (i = 0; i < kimage->nr_segments; i ++) { + //seg = &kimage->segment[i]; + } + //skip any range allocated + return -1; +} + /* Allocates pages for kexec page table */ -static void *kexec_page_alloc(void *arg) +static void *__kexec_page_alloc(void *arg) { struct kimage *kimage = arg; struct page *page = kimage_alloc_control_pages(kimage, 0); @@ -102,6 +117,69 @@ static void *kexec_page_alloc(void *arg) return vaddr; } +static phys_addr_t kexec_page_alloc(int unused, void *arg) +{ + void *vaddr; + + vaddr = __kexec_page_alloc(arg); + if (!vaddr) + return (phys_addr_t)-1; + return virt_to_phys(vaddr); +} + +/* + * This function should be called after all kimage segments have been profiled + * Return physical address of page table's root + */ +phys_addr_t arch_emulator_prepare_pgtable(struct kimage *kimage, + struct efi_emulator_param *param) +{ + struct kexec_segment *seg; + unsigned long paddr, sz; + pgd_t *pgd; + typedef phys_addr_t (* alloc_fn)(int, void *); + alloc_fn alloc; + phys_addr_t pgd_paddr; + int i; + + /* + * Set up pgtable of emulator, either for crash or for reboot. + * All of the segments have been profiled, and kimage_alloc_normal_control_pages() + * will allocate page in safe zone. + * On the other hand, these pages are not in any segment, which means they are + * left, not copied. Hence the radix tree laying out on them is not broken. + */ + if (kimage->head & IND_DONE) + alloc = crash_page_alloc; + else + alloc = kexec_page_alloc; + pgd_paddr = alloc(0, kimage); + pgd = (pgd_t *)phys_to_virt(pgd_paddr); + for (i = 0; i < kimage->nr_segments; i ++) { + seg = &kimage->segment[i]; + paddr = ALIGN_DOWN(seg->mem, PAGE_SIZE); + sz = ALIGN(seg->mem - paddr + seg->memsz, PAGE_SIZE); + kexec_dprintk("Set up mapping for phyaddr: 0x%lx, size:0x%lx", paddr, sz); + //todo: distinguish executable segment + __create_pgd_mapping_locked(pgd, paddr, paddr, sz, + PAGE_KERNEL_EXEC, alloc, kimage, 0); + } + + /* + * Per UEFI specification, SetVirtualAddressMap() is oneshot, which means + * efi stub should not call EFI runtime service without setting up mapping. + * As a result, emulator does not need to set up the mapping for + * EFI_RUNTIME_SERVICES_CODE etc. + */ + + if (param->print_enabled) + __create_pgd_mapping_locked(pgd, param->earlycon_reg_base, + param->earlycon_reg_base, param->earlycon_reg_sz, + pgprot_device(PAGE_KERNEL), alloc, kimage, 0); + + return pgd_paddr; +} + int machine_kexec_post_load(struct kimage *kimage) { int rc; @@ -109,7 +187,7 @@ int machine_kexec_post_load(struct kimage *kimage) void *reloc_code = page_to_virt(kimage->control_code_page); long reloc_size; struct trans_pgd_info info = { - .trans_alloc_page = kexec_page_alloc, + .trans_alloc_page = __kexec_page_alloc, .trans_alloc_arg = kimage, }; @@ -129,7 +207,7 @@ int machine_kexec_post_load(struct kimage *kimage) } /* Create a copy of the linear map */ - trans_pgd = kexec_page_alloc(kimage); + trans_pgd = __kexec_page_alloc(kimage); if (!trans_pgd) return -ENOMEM; rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END); @@ -145,6 +223,7 @@ int machine_kexec_post_load(struct kimage *kimage) &kimage->arch.t0sz, reloc_code); if (rc) return rc; + kimage->arch.phys_offset = virt_to_phys(kimage) - (long)kimage; /* Flush the reloc_code in preparation for its execution. */ @@ -175,7 +254,6 @@ void machine_kexec(struct kimage *kimage) "Some CPUs may be stale, kdump will be unreliable.\n"); pr_info("Bye!\n"); - local_daif_mask(); /* @@ -192,7 +270,8 @@ void machine_kexec(struct kimage *kimage) cpu_install_idmap(); restart = (void *)__pa_symbol(cpu_soft_restart); - restart(is_hyp_nvhe(), kimage->start, kimage->arch.dtb_mem, + /* kimage->start can be either the entry of kernel or efi emulator */ + restart(is_hyp_nvhe(), kimage->start, kimage->arch.param_mem, 0, 0); } else { void (*kernel_reloc)(struct kimage *kimage); @@ -201,6 +280,7 @@ void machine_kexec(struct kimage *kimage) __hyp_set_vectors(kimage->arch.el2_vectors); cpu_install_ttbr0(kimage->arch.ttbr0, kimage->arch.t0sz); kernel_reloc = (void *)kimage->arch.kern_reloc; + //tell between the emulator and normal kernel inside the relocate code kernel_reloc(kimage); } diff --git a/include/linux/kexec.h b/include/linux/kexec.h index cff6b6869498b..c68427f796d31 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -22,6 +22,7 @@ #include #include +#include extern note_buf_t __percpu *crash_notes; @@ -463,7 +464,9 @@ static inline int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, g static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { } #endif -extern phys_addr_t arch_emulator_prepare_pgtable(struct kimage *kimage); +extern phys_addr_t arch_emulator_prepare_pgtable(struct kimage *kimage, + struct efi_emulator_param *param); + extern bool kexec_file_dbg_print; #define kexec_dprintk(fmt, arg...) \