Re: [GRUB PATCH RFC 15/18] i386/txt: Add Intel TXT core implementation

2020-06-01 Thread Ross Philipson
On 5/22/20 9:24 AM, Krystian Hebel wrote:
> 
> On 05.05.2020 01:21, Daniel Kiper wrote:
>> +static grub_err_t
>> +init_txt_heap (struct grub_slaunch_params *slparams, struct
>> grub_txt_acm_header *sinit)
>> +{
>> +  grub_uint8_t *txt_heap;
>> +  grub_uint32_t os_sinit_data_ver, sinit_caps;
>> +  grub_uint64_t *size;
>> +  struct grub_txt_os_mle_data *os_mle_data;
>> +  struct grub_txt_os_sinit_data *os_sinit_data;
>> +  struct grub_txt_heap_end_element *heap_end_element;
>> +  struct grub_txt_heap_event_log_pointer2_1_element
>> *heap_event_log_pointer2_1_element;
>> +#ifdef GRUB_MACHINE_EFI
>> +  struct grub_acpi_rsdp_v20 *rsdp;
>> +#endif
>> +
>> +  /* BIOS data already verified in grub_txt_verify_platform(). */
>> +
>> +  txt_heap = grub_txt_get_heap ();
>> +
>> +  /* OS/loader to MLE data. */
>> +
>> +  os_mle_data = grub_txt_os_mle_data_start (txt_heap);
>> +  size = (grub_uint64_t *) ((grub_addr_t) os_mle_data - sizeof
>> (grub_uint64_t));
> There is 'grub_txt_os_mle_data_size()' in previous patch, it would look
> better.
>> +  *size = sizeof (*os_mle_data) + sizeof (grub_uint64_t);
>> +
>> +  grub_memset (os_mle_data, 0, sizeof (*os_mle_data));
>> +
>> +  os_mle_data->version = GRUB_SL_OS_MLE_STRUCT_VERSION;
>> +  os_mle_data->zero_page_addr = (grub_uint32_t)(grub_addr_t)
>> slparams->params;
>> +  os_mle_data->saved_misc_enable_msr = grub_rdmsr
>> (GRUB_MSR_X86_MISC_ENABLE);
>> +
>> +  os_mle_data->ap_wake_block = slparams->ap_wake_block;
>> +
>> +  save_mtrrs (os_mle_data);
>> +
>> +  /* OS/loader to SINIT data. */
>> +
>> +  os_sinit_data_ver = grub_txt_supported_os_sinit_data_ver (sinit);
>> +
>> +  if (os_sinit_data_ver < OS_SINIT_DATA_MIN_VER)
>> +    return grub_error (GRUB_ERR_BAD_DEVICE,
>> +   N_("unsupported OS to SINIT data version in SINIT ACM:
>> %d"
>> +   " expected >= %d"), os_sinit_data_ver,
>> OS_SINIT_DATA_MIN_VER);
>> +
>> +  os_sinit_data = grub_txt_os_sinit_data_start (txt_heap);
>> +  size = (grub_uint64_t *) ((grub_addr_t) os_sinit_data - sizeof
>> (grub_uint64_t));
> Ditto
>> +
>> +  *size = sizeof(grub_uint64_t) + sizeof (struct
>> grub_txt_os_sinit_data) +
>> +  sizeof (struct grub_txt_heap_end_element);
>> +
>> +  if (grub_get_tpm_ver () == GRUB_TPM_12)
>> +    *size += sizeof (struct grub_txt_heap_tpm_event_log_element);
>> +  else if (grub_get_tpm_ver () == GRUB_TPM_20)
>> +    *size += sizeof (struct grub_txt_heap_event_log_pointer2_1_element);
>> +  else
>> +    return grub_error (GRUB_ERR_BAD_DEVICE, N_("unsupported TPM
>> version"));
>> +
>> +  grub_memset (os_sinit_data, 0, *size);
>> +
>> +#ifdef GRUB_MACHINE_EFI
>> +  rsdp = grub_acpi_get_rsdpv2 ();
>> +
>> +  if (rsdp == NULL)
>> +    return grub_printf ("WARNING: ACPI RSDP 2.0 missing\n");
>> +
>> +  os_sinit_data->efi_rsdt_ptr = (grub_uint64_t)(grub_addr_t) rsdp;
>> +#endif
>> +
>> +  os_sinit_data->mle_ptab = slparams->mle_ptab_target;
>> +  os_sinit_data->mle_size = slparams->mle_size;
>> +
>> +  os_sinit_data->mle_hdr_base = slparams->mle_header_offset;
>> +
>> +  /* TODO: Check low PMR with RMRR. Look at relevant tboot code too. */
>> +  /* TODO: Kernel should not allocate any memory outside of PMRs
>> regions!!! */
>> +  os_sinit_data->vtd_pmr_lo_base = 0;
>> +  os_sinit_data->vtd_pmr_lo_size = ALIGN_DOWN (grub_mmap_get_highest
>> (0x1),
>> +   GRUB_TXT_PMR_ALIGN);
>> +
>> +  os_sinit_data->vtd_pmr_hi_base = ALIGN_UP (grub_mmap_get_lowest
>> (0x1),
>> + GRUB_TXT_PMR_ALIGN);
>> +  os_sinit_data->vtd_pmr_hi_size = ALIGN_DOWN (grub_mmap_get_highest
>> (0x),
>> +   GRUB_TXT_PMR_ALIGN);
>> +  os_sinit_data->vtd_pmr_hi_size -= os_sinit_data->vtd_pmr_hi_base;
> Could it be done with just one PMR, from 0 to top of memory, or would

No because there could be these legacy reserved regions in somewhere
below 4G that might cause hangs if you block DMA to them. So the idea is
the high PMR covers everything > 4G and the low PMR needs special logic
to not block these reserved regions. We are working on better logic for
this now.

> TXT complain?
>> +
>> +  grub_dprintf ("slaunch",
>> +    "vtd_pmr_lo_base: 0x%" PRIxGRUB_UINT64_T " vtd_pmr_lo_size: 0x%"
>> +    PRIxGRUB_UINT64_T " vtd_pmr_hi_base: 0x%" PRIxGRUB_UINT64_T
>> +    " vtd_pmr_hi_size: 0x%" PRIxGRUB_UINT64_T "\n",
>> +    os_sinit_data->vtd_pmr_lo_base, os_sinit_data->vtd_pmr_lo_size,
>> +    os_sinit_data->vtd_pmr_hi_base, os_sinit_data->vtd_pmr_hi_size);
>> +
>>
>> 
>>
>> +/*
>> + * The MLE page tables have to be below the MLE and have no special
>> regions in
>> + * between them and the MLE (this is a bit of an unwritten rule).
>> + * 20 pages are carved out of memory below the MLE. That leave 18
>> page table
>> + * pages that can cover up to 36M .
>> + * can only contain 4k pages
>> + *
>> + * TODO: TXT Spec p.32; List section name and number with PT MLE
>> requirments here.
>> + *
>> + * TODO: This 

Re: [GRUB PATCH RFC 15/18] i386/txt: Add Intel TXT core implementation

2020-05-22 Thread Krystian Hebel


On 05.05.2020 01:21, Daniel Kiper wrote:

+static grub_err_t
+init_txt_heap (struct grub_slaunch_params *slparams, struct 
grub_txt_acm_header *sinit)
+{
+  grub_uint8_t *txt_heap;
+  grub_uint32_t os_sinit_data_ver, sinit_caps;
+  grub_uint64_t *size;
+  struct grub_txt_os_mle_data *os_mle_data;
+  struct grub_txt_os_sinit_data *os_sinit_data;
+  struct grub_txt_heap_end_element *heap_end_element;
+  struct grub_txt_heap_event_log_pointer2_1_element 
*heap_event_log_pointer2_1_element;
+#ifdef GRUB_MACHINE_EFI
+  struct grub_acpi_rsdp_v20 *rsdp;
+#endif
+
+  /* BIOS data already verified in grub_txt_verify_platform(). */
+
+  txt_heap = grub_txt_get_heap ();
+
+  /* OS/loader to MLE data. */
+
+  os_mle_data = grub_txt_os_mle_data_start (txt_heap);
+  size = (grub_uint64_t *) ((grub_addr_t) os_mle_data - sizeof 
(grub_uint64_t));
There is 'grub_txt_os_mle_data_size()' in previous patch, it would look 
better.

+  *size = sizeof (*os_mle_data) + sizeof (grub_uint64_t);
+
+  grub_memset (os_mle_data, 0, sizeof (*os_mle_data));
+
+  os_mle_data->version = GRUB_SL_OS_MLE_STRUCT_VERSION;
+  os_mle_data->zero_page_addr = (grub_uint32_t)(grub_addr_t) slparams->params;
+  os_mle_data->saved_misc_enable_msr = grub_rdmsr (GRUB_MSR_X86_MISC_ENABLE);
+
+  os_mle_data->ap_wake_block = slparams->ap_wake_block;
+
+  save_mtrrs (os_mle_data);
+
+  /* OS/loader to SINIT data. */
+
+  os_sinit_data_ver = grub_txt_supported_os_sinit_data_ver (sinit);
+
+  if (os_sinit_data_ver < OS_SINIT_DATA_MIN_VER)
+return grub_error (GRUB_ERR_BAD_DEVICE,
+  N_("unsupported OS to SINIT data version in SINIT ACM: 
%d"
+  " expected >= %d"), os_sinit_data_ver, 
OS_SINIT_DATA_MIN_VER);
+
+  os_sinit_data = grub_txt_os_sinit_data_start (txt_heap);
+  size = (grub_uint64_t *) ((grub_addr_t) os_sinit_data - sizeof 
(grub_uint64_t));

Ditto

+
+  *size = sizeof(grub_uint64_t) + sizeof (struct grub_txt_os_sinit_data) +
+ sizeof (struct grub_txt_heap_end_element);
+
+  if (grub_get_tpm_ver () == GRUB_TPM_12)
+*size += sizeof (struct grub_txt_heap_tpm_event_log_element);
+  else if (grub_get_tpm_ver () == GRUB_TPM_20)
+*size += sizeof (struct grub_txt_heap_event_log_pointer2_1_element);
+  else
+return grub_error (GRUB_ERR_BAD_DEVICE, N_("unsupported TPM version"));
+
+  grub_memset (os_sinit_data, 0, *size);
+
+#ifdef GRUB_MACHINE_EFI
+  rsdp = grub_acpi_get_rsdpv2 ();
+
+  if (rsdp == NULL)
+return grub_printf ("WARNING: ACPI RSDP 2.0 missing\n");
+
+  os_sinit_data->efi_rsdt_ptr = (grub_uint64_t)(grub_addr_t) rsdp;
+#endif
+
+  os_sinit_data->mle_ptab = slparams->mle_ptab_target;
+  os_sinit_data->mle_size = slparams->mle_size;
+
+  os_sinit_data->mle_hdr_base = slparams->mle_header_offset;
+
+  /* TODO: Check low PMR with RMRR. Look at relevant tboot code too. */
+  /* TODO: Kernel should not allocate any memory outside of PMRs regions!!! */
+  os_sinit_data->vtd_pmr_lo_base = 0;
+  os_sinit_data->vtd_pmr_lo_size = ALIGN_DOWN (grub_mmap_get_highest 
(0x1),
+  GRUB_TXT_PMR_ALIGN);
+
+  os_sinit_data->vtd_pmr_hi_base = ALIGN_UP (grub_mmap_get_lowest 
(0x1),
+GRUB_TXT_PMR_ALIGN);
+  os_sinit_data->vtd_pmr_hi_size = ALIGN_DOWN (grub_mmap_get_highest 
(0x),
+  GRUB_TXT_PMR_ALIGN);
+  os_sinit_data->vtd_pmr_hi_size -= os_sinit_data->vtd_pmr_hi_base;
Could it be done with just one PMR, from 0 to top of memory, or would 
TXT complain?

+
+  grub_dprintf ("slaunch",
+   "vtd_pmr_lo_base: 0x%" PRIxGRUB_UINT64_T " vtd_pmr_lo_size: 0x%"
+   PRIxGRUB_UINT64_T " vtd_pmr_hi_base: 0x%" PRIxGRUB_UINT64_T
+   " vtd_pmr_hi_size: 0x%" PRIxGRUB_UINT64_T "\n",
+   os_sinit_data->vtd_pmr_lo_base, os_sinit_data->vtd_pmr_lo_size,
+   os_sinit_data->vtd_pmr_hi_base, os_sinit_data->vtd_pmr_hi_size);
+



+/*
+ * The MLE page tables have to be below the MLE and have no special regions in
+ * between them and the MLE (this is a bit of an unwritten rule).
+ * 20 pages are carved out of memory below the MLE. That leave 18 page table
+ * pages that can cover up to 36M .
+ * can only contain 4k pages
+ *
+ * TODO: TXT Spec p.32; List section name and number with PT MLE requirments 
here.
+ *
+ * TODO: This function is not able to cover MLEs larger than 1 GiB. Fix it!!!
+ * After fixing inrease GRUB_TXT_MLE_MAX_SIZE too.
+ */


What do you mean by "special regions"? In TXT spec it is written that 
there may be no holes

in the virtual address space:

"There may not be any invalid (not-present) page table entries after the 
first valid

entry (i.e. there may not be any gaps in the MLE’s linear address space)."

Also that spec:
"A breadth-first search of page tables must produce increasing physical 
addresses."


Maybe I misunderstood, but does it mean that the paging structures 

[GRUB PATCH RFC 15/18] i386/txt: Add Intel TXT core implementation

2020-05-04 Thread Daniel Kiper
From: Ross Philipson 

Signed-off-by: Ross Philipson 
Signed-off-by: Daniel Kiper 
---
 grub-core/loader/i386/txt/txt.c | 887 
 include/grub/i386/memory.h  |   5 +
 2 files changed, 892 insertions(+)
 create mode 100644 grub-core/loader/i386/txt/txt.c

diff --git a/grub-core/loader/i386/txt/txt.c b/grub-core/loader/i386/txt/txt.c
new file mode 100644
index 0..3e25890c3
--- /dev/null
+++ b/grub-core/loader/i386/txt/txt.c
@@ -0,0 +1,887 @@
+/*
+ * txt.c: Intel(r) TXT support functions, including initiating measured
+ *launch, post-launch, AP wakeup, etc.
+ *
+ * Copyright (c) 2003-2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *   * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020  Oracle and/or its affiliates.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see .
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define OS_SINIT_DATA_TPM_12_VER   6
+#define OS_SINIT_DATA_TPM_20_VER   7
+
+#define OS_SINIT_DATA_MIN_VER  OS_SINIT_DATA_TPM_12_VER
+
+static grub_err_t
+enable_smx_mode (void)
+{
+  grub_uint32_t caps;
+
+  /* Enable SMX mode. */
+  grub_write_cr4 (grub_read_cr4 () | GRUB_CR4_X86_SMXE);
+
+  caps = grub_txt_getsec_capabilities (0);
+
+  if (!(caps & GRUB_SMX_CAPABILITY_CHIPSET_PRESENT))
+{
+  grub_error (GRUB_ERR_BAD_DEVICE, N_("TXT-capable chipset is not 
present"));
+  goto fail;
+}
+
+  if (!(caps & GRUB_SMX_CAPABILITY_SENTER))
+{
+  grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[SENTER] is not available"));
+  goto fail;
+}
+
+  if (!(caps & GRUB_SMX_CAPABILITY_PARAMETERS))
+{
+  grub_error (GRUB_ERR_BAD_DEVICE, N_("GETSEC[PARAMETERS] is not 
available"));
+  goto fail;
+}
+
+  return GRUB_ERR_NONE;
+
+ fail:
+  /* Disable SMX mode on failure. */
+  grub_write_cr4 (grub_read_cr4 () & ~GRUB_CR4_X86_SMXE);
+
+  return grub_errno;
+}
+
+static void
+grub_txt_smx_parameters (struct grub_smx_parameters *params)
+{
+  grub_uint32_t index = 0, eax, ebx, ecx, param_type;
+
+  grub_memset (params, 0, sizeof(struct grub_smx_supported_versions));
+
+  params->max_acm_size = GRUB_SMX_DEFAULT_MAX_ACM_SIZE;
+  params->acm_memory_types = GRUB_SMX_DEFAULT_ACM_MEMORY_TYPE;
+  params->senter_controls = GRUB_SMX_DEFAULT_SENTER_CONTROLS;
+
+  do
+{
+  grub_txt_getsec_parameters (index, , , );
+  param_type = eax & GRUB_SMX_PARAMETER_TYPE_MASK;
+
+  switch (param_type)
+{
+case GRUB_SMX_PARAMETER_NULL:
+  break; /* This means done. */
+
+case GRUB_SMX_PARAMETER_ACM_VERSIONS:
+  if (params->version_count == GRUB_SMX_PARAMETER_MAX_VERSIONS)
+{
+