/* * This file is part of the coreboot project. * * Copyright (C) 2014 Google Inc. * Copyright (C) 2015-2016 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include size_t mmap_region_granularity(void) { if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) /* Align to TSEG size when SMM is in use */ if (CONFIG_SMM_TSEG_SIZE != 0) return CONFIG_SMM_TSEG_SIZE; /* Make it 8MiB by default. */ return 8*MiB; } void smm_region(void **start, size_t *size) { *start = (void *)sa_get_tseg_base(); *size = sa_get_tseg_size(); } /* * Subregions within SMM * +-------------------------+ BGSM * | IED | IED_REGION_SIZE * +-------------------------+ * | External Stage Cache | SMM_RESERVED_SIZE * +-------------------------+ * | code and data | * | (TSEG) | * +-------------------------+ TSEG */ int smm_subregion(int sub, void **start, size_t *size) { uintptr_t sub_base; size_t sub_size; void *smm_base; const size_t ied_size = CONFIG_IED_REGION_SIZE; const size_t cache_size = CONFIG_SMM_RESERVED_SIZE; smm_region(&smm_base, &sub_size); sub_base = (uintptr_t)smm_base; switch (sub) { case SMM_SUBREGION_HANDLER: /* Handler starts at the base of TSEG. */ sub_size -= ied_size; sub_size -= cache_size; break; case SMM_SUBREGION_CACHE: /* External cache is in the middle of TSEG. */ sub_base += sub_size - (ied_size + cache_size); sub_size = cache_size; break; case SMM_SUBREGION_CHIPSET: /* IED is at the top. */ sub_base += sub_size - ied_size; sub_size = ied_size; break; default: return -1; } *start = (void *)sub_base; *size = sub_size; return 0; } static bool is_ptt_enable(void) { if ((read32((void *)PTT_TXT_BASE_ADDRESS) & PTT_PRESENT) == PTT_PRESENT) return true; return false; } /* * Host Memory Map: * * +--------------------------+ TOUUD * | | * +--------------------------+ 4GiB * | PCI Address Space | * +--------------------------+ TOLUD (also maps into MC address space) * | iGD | * +--------------------------+ BDSM * | GTT | * +--------------------------+ BGSM * | TSEG | * +--------------------------+ TSEGMB * | DMA Protected Region | * +--------------------------+ DPR * | PRM (C6DRAM/SGX) | * +--------------------------+ PRMRR * | Trace Memory | * +--------------------------+ Probless Trace * | PTT | * +--------------------------+ top_of_ram * | Reserved - FSP/CBMEM | * +--------------------------+ TOLUM * | Usage DRAM | * +--------------------------+ 0 * * Some of the base registers above can be equal making the size of those * regions 0. The reason is because the memory controller internally subtracts * the base registers from each other to determine sizes of the regions. In * other words, the memory map is in a fixed order no matter what. */ static u32 calculate_dram_base(void) { const struct soc_intel_skylake_config *config; const struct device *dev; uint32_t dram_base; uint32_t prmrr_base; size_t prmrr_size; dev = dev_find_slot(0, PCI_DEVFN(SA_DEV_SLOT_IGD, 0)); if (!dev) die("ERROR - device not found!"); /* Read TOLUD from Host Bridge offset */ dram_base = sa_get_tolud_base(); if (dev->enabled) { /* Read BDSM from Host Bridge */ dram_base -= sa_get_dsm_size(); /* Read BGSM from Host Bridge */ dram_base -= sa_get_gsm_size(); } /* Get TSEG size */ dram_base -= sa_get_tseg_size(); /* Get DPR size */ if (IS_ENABLED(CONFIG_SA_ENABLE_DPR)) dram_base -= sa_get_dpr_size(); config = dev->chip_info; if (IS_ENABLED(CONFIG_PLATFORM_USES_FSP1_1)) prmrr_size = 1*MiB; else prmrr_size = config->PrmrrSize; if (prmrr_size > 0) { /* * PRMRR Sizes that are > 1MB and < 32MB are * not supported and will fail out. */ if ((prmrr_size > 1*MiB) && (prmrr_size < 32*MiB)) die("PRMRR Sizes that are > 1MB and < 32MB are not" "supported!\n"); prmrr_base = dram_base - prmrr_size; if (prmrr_size >= 32*MiB) prmrr_base = ALIGN_DOWN(prmrr_base, 128*MiB); dram_base = prmrr_base; } if (config->ProbelessTrace) { /* GDXC MOT */ dram_base -= GDXC_MOT_MEMORY_SIZE; /* Round down to natual boundary accroding to PSMI size */ dram_base = ALIGN_DOWN(dram_base, PSMI_BUFFER_AREA_SIZE); /* GDXC IOT */ dram_base -= GDXC_IOT_MEMORY_SIZE; /* PSMI buffer area */ dram_base -= PSMI_BUFFER_AREA_SIZE; } if (is_ptt_enable()) dram_base -= 4*KiB; /* Allocate 4KB for PTT if enable */ return dram_base; } /* Get usable system memory start address */ static u32 top_of_32bit_ram(void) { /* * Check if Tseg has been initialized, we will use this as a flag * to check if the MRC is done, and only then continue to read the * PRMMR_BASE MSR. The system hangs if PRMRR_BASE MSR is read before * PRMRR_MASK MSR lock bit is set. */ if (sa_get_tseg_base() == 0) return 0; return calculate_dram_base(); } void *cbmem_top(void) { /* * +-------------------------+ Top of RAM (aligned) * | System Management Mode | * | code and data | Length: CONFIG_TSEG_SIZE * | (TSEG) | * +-------------------------+ SMM base (aligned) * | | * | Chipset Reserved Memory | * | | * +-------------------------+ top_of_ram (aligned) * | | * | CBMEM Root | * | | * +-------------------------+ * | | * | FSP Reserved Memory | * | | * +-------------------------+ * | | * | Various CBMEM Entries | * | | * +-------------------------+ top_of_stack (8 byte aligned) * | | * | stack (CBMEM Entry) | * | | * +-------------------------+ */ return (void *)top_of_32bit_ram(); }