Skip to content

Commit

Permalink
Add PTE mask page table translation parameter
Browse files Browse the repository at this point in the history
AMD EPYC processors introduce an optional SME bit in the page
tables to indicate encryption. The location of this bit is stored
in bits 0:5 of CPUID Fn8000_001F[EBX], i.e. it is not known at
build time and must be configurable through a parameter.

There might be other good use cases for this mask, because the API
is quite generic...

Signed-off-by: Petr Tesarik <ptesarik@suse.com>
  • Loading branch information
ptesarik committed Oct 2, 2020
1 parent 613192c commit 25cfbe2
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 59 deletions.
6 changes: 6 additions & 0 deletions include/libkdumpfile/addrxlat.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,12 @@ typedef struct _addrxlat_paging_form {
/** Parameters of page table translation. */
typedef struct _addrxlat_param_pgt {
addrxlat_fulladdr_t root; /**< Root page table address. */

/** Page table entry mask.
* Bits to be masked off the raw value. Zero means no masking.
*/
addrxlat_pte_t pte_mask;

addrxlat_paging_form_t pf; /**< Paging form. */
} addrxlat_param_pgt_t;

Expand Down
9 changes: 5 additions & 4 deletions src/addrxlat/aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,20 @@ pte_invalid(addrxlat_step_t *step)
addrxlat_status
pgt_aarch64(addrxlat_step_t *step)
{
addrxlat_pte_t pte;
addrxlat_status status;

status = read_pte64(step);
status = read_pte64(step, &pte);
if (status != ADDRXLAT_OK)
return status;

if (!PTE_VALID(step->raw.pte))
if (!PTE_VALID(pte))
return pte_not_present(step);

step->base.addr = step->raw.pte & PA_MASK;
step->base.addr = pte & PA_MASK;
step->base.as = step->meth->target_as;

if (PTE_TYPE(step->raw.pte) == PTE_TYPE_BLOCK) {
if (PTE_TYPE(pte) == PTE_TYPE_BLOCK) {
addrxlat_addr_t mask = pf_table_mask(
&step->meth->param.pgt.pf, step->remain);
if (mask > PAGE_MASK_1G)
Expand Down
14 changes: 10 additions & 4 deletions src/addrxlat/addrxlat-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,37 +251,43 @@ struct _addrxlat_sys {

/** Read raw 32-bit PTE value.
* @param step Current step state.
* @param pte Set to the (masked) PTE value on success.
* @returns Error status.
*
* On successful return, @c step->raw.pte contains the raw
* PTE value for the current translation step.
*/
static inline addrxlat_status
read_pte32(addrxlat_step_t *step)
read_pte32(addrxlat_step_t *step, addrxlat_pte_t *pte)
{
uint32_t pte32;
addrxlat_status status;
status = read32(step, &step->base, &pte32, "PTE");
if (status == ADDRXLAT_OK)
if (status == ADDRXLAT_OK) {
step->raw.pte = pte32;
*pte = pte32 & ~step->meth->param.pgt.pte_mask;
}
return status;
}

/** Read raw 64-bit PTE value.
* @param step Current step state.
* @param pte Set to the (masked) PTE value on success.
* @returns Error status.
*
* On successful return, @c step->raw.pte contains the raw
* PTE value for the current translation step.
*/
static inline addrxlat_status
read_pte64(addrxlat_step_t *step)
read_pte64(addrxlat_step_t *step, addrxlat_pte_t *pte)
{
uint64_t pte64;
addrxlat_status status;
status = read64(step, &step->base, &pte64, "PTE");
if (status == ADDRXLAT_OK)
if (status == ADDRXLAT_OK) {
step->raw.pte = pte64;
*pte = pte64 & ~step->meth->param.pgt.pte_mask;
}
return status;
}

Expand Down
23 changes: 14 additions & 9 deletions src/addrxlat/ia32.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,14 @@ pgt_ia32(addrxlat_step_t *step)
"pte",
"pgd",
};
addrxlat_pte_t pte;
addrxlat_status status;

status = read_pte32(step);
status = read_pte32(step, &pte);
if (status != ADDRXLAT_OK)
return status;

if (!(step->raw.pte & _PAGE_PRESENT))
if (!(pte & _PAGE_PRESENT))
return !step->ctx->noerr.notpresent
? set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"%s not present: %s[%u] = 0x%" ADDRXLAT_PRIxPTE,
Expand All @@ -106,12 +107,12 @@ pgt_ia32(addrxlat_step_t *step)
step->raw.pte)
: ADDRXLAT_ERR_NOTPRESENT;

step->base.addr = step->raw.pte;
step->base.addr = pte;
step->base.as = step->meth->target_as;

if (step->remain == 2 && (step->raw.pte & _PAGE_PSE)) {
if (step->remain == 2 && (pte & _PAGE_PSE)) {
step->base.addr &= ~PAGE_MASK_4M;
step->base.addr |= pgd_pse_high(step->raw.pte);
step->base.addr |= pgd_pse_high(pte);
return pgt_huge_page(step);
}

Expand Down Expand Up @@ -139,13 +140,14 @@ pgt_ia32_pae(addrxlat_step_t *step)
"pmd",
"pgd",
};
addrxlat_pte_t pte;
addrxlat_status status;

status = read_pte64(step);
status = read_pte64(step, &pte);
if (status != ADDRXLAT_OK)
return status;

if (!(step->raw.pte & _PAGE_PRESENT))
if (!(pte & _PAGE_PRESENT))
return !step->ctx->noerr.notpresent
? set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"%s not present: %s[%u] = 0x%" ADDRXLAT_PRIxPTE,
Expand All @@ -155,10 +157,10 @@ pgt_ia32_pae(addrxlat_step_t *step)
step->raw.pte)
: ADDRXLAT_ERR_NOTPRESENT;

step->base.addr = step->raw.pte & PHYSADDR_MASK_PAE;
step->base.addr = pte & PHYSADDR_MASK_PAE;
step->base.as = step->meth->target_as;

if (step->remain == 2 && (step->raw.pte & _PAGE_PSE)) {
if (step->remain == 2 && (pte & _PAGE_PSE)) {
step->base.addr &= ~PAGE_MASK_2M;
return pgt_huge_page(step);
}
Expand Down Expand Up @@ -212,6 +214,7 @@ check_pae(struct os_init_data *ctl, const addrxlat_fulladdr_t *root,
if (status != ADDRXLAT_OK)
return set_error(ctl->ctx, status,
"Cannot set up physical mappings");
meth.param.pgt.pte_mask = 0;
meth.param.pgt.pf = ia32_pf_pae;
step.ctx = ctl->ctx;
step.sys = ctl->sys;
Expand Down Expand Up @@ -294,6 +297,7 @@ sys_ia32_nonpae(struct os_init_data *ctl)
meth->param.pgt.root = ctl->popt.val[OPT_rootpgt].fulladdr;
else
meth->param.pgt.root.as = ADDRXLAT_NOADDR;
meth->param.pgt.pte_mask = 0;
meth->param.pgt.pf = ia32_pf;
return ADDRXLAT_OK;
}
Expand All @@ -319,6 +323,7 @@ sys_ia32_pae(struct os_init_data *ctl)
meth->param.pgt.root = ctl->popt.val[OPT_rootpgt].fulladdr;
else
meth->param.pgt.root.as = ADDRXLAT_NOADDR;
meth->param.pgt.pte_mask = 0;
meth->param.pgt.pf = ia32_pf_pae;
return ADDRXLAT_OK;
}
Expand Down
34 changes: 18 additions & 16 deletions src/addrxlat/ppc64.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,22 +113,23 @@ hugepd_shift(addrxlat_pte_t hpde)

/** Translate a Linux huge page using its directory entry.
* @param step Current step state.
* @param pte Page table entry value (possibly masked).
* @returns Error status.
*/
static addrxlat_status
huge_pd_linux(addrxlat_step_t *step)
huge_pd_linux(addrxlat_step_t *step, addrxlat_pte_t pte)
{
const addrxlat_paging_form_t *pf = &step->meth->param.pgt.pf;
addrxlat_addr_t off;
unsigned pdshift;
unsigned short i;

pdshift = hugepd_shift(step->raw.pte);
pdshift = hugepd_shift(pte);
if (!pdshift)
return set_error(step->ctx, ADDRXLAT_ERR_INVALID,
"Invalid hugepd shift");

step->base.addr = (step->raw.pte & ~HUGEPD_SHIFT_MASK) | PD_HUGE;
step->base.addr = (pte & ~HUGEPD_SHIFT_MASK) | PD_HUGE;
step->base.as = ADDRXLAT_KVADDR;

/* Calculate the total byte offset below current table. */
Expand All @@ -151,7 +152,7 @@ huge_pd_linux(addrxlat_step_t *step)
}

/** Check whether a Linux page table entry is huge.
* @param pte Page table entry (value).
* @param pte Page table entry value (possibly masked).
* @returns Non-zero if this is a huge page entry.
*/
static inline int
Expand All @@ -161,7 +162,8 @@ is_hugepte_linux(addrxlat_pte_t pte)
}

/** Update current step state for Linux huge page.
* @param state Current step state.
* @param step Current step state.
* @param pte Page table entry value (possibly masked).
* @param rpn_shift RPN shift.
* @returns Always @c ADDRXLAT_OK.
*
Expand All @@ -170,11 +172,11 @@ is_hugepte_linux(addrxlat_pte_t pte)
* offset and terminates.
*/
static addrxlat_status
huge_page_linux(addrxlat_step_t *step, unsigned rpn_shift)
huge_page_linux(addrxlat_step_t *step, addrxlat_pte_t pte, unsigned rpn_shift)
{
const addrxlat_paging_form_t *pf = &step->meth->param.pgt.pf;

step->base.addr = (step->raw.pte >> rpn_shift) << pf->fieldsz[0];
step->base.addr = (pte >> rpn_shift) << pf->fieldsz[0];
step->base.as = step->meth->target_as;
return pgt_huge_page(step);
}
Expand All @@ -194,13 +196,14 @@ pgt_ppc64_linux(addrxlat_step_t *step, unsigned rpn_shift)
"pgd",
};
const addrxlat_paging_form_t *pf = &step->meth->param.pgt.pf;
addrxlat_pte_t pte;
addrxlat_status status;

status = read_pte64(step);
status = read_pte64(step, &pte);
if (status != ADDRXLAT_OK)
return status;

if (!step->raw.pte)
if (!pte)
return !step->ctx->noerr.notpresent
? set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"%s[%u] is none",
Expand All @@ -211,19 +214,18 @@ pgt_ppc64_linux(addrxlat_step_t *step, unsigned rpn_shift)
if (step->remain > 1) {
addrxlat_addr_t table_size;

if (is_hugepte_linux(step->raw.pte))
return huge_page_linux(step, rpn_shift);
if (is_hugepte_linux(pte))
return huge_page_linux(step, pte, rpn_shift);

if (is_hugepd_linux(step->raw.pte))
return huge_pd_linux(step);
if (is_hugepd_linux(pte))
return huge_pd_linux(step, pte);

table_size = ((addrxlat_addr_t)1 << PTE_SHIFT <<
pf->fieldsz[step->remain - 1]);
step->base.addr = step->raw.pte & ~(table_size - 1);
step->base.addr = pte & ~(table_size - 1);
step->base.as = ADDRXLAT_KVADDR;
} else {
step->base.addr =
(step->raw.pte >> rpn_shift) << pf->fieldsz[0];
step->base.addr = (pte >> rpn_shift) << pf->fieldsz[0];
step->base.as = step->meth->target_as;
step->elemsz = 1;
}
Expand Down
22 changes: 11 additions & 11 deletions src/addrxlat/s390x.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ pgt_s390x(addrxlat_step_t *step)
"rg1", /* Invented; does not exist in the wild. */
};
const addrxlat_paging_form_t *pf = &step->meth->param.pgt.pf;
addrxlat_pte_t pte;
addrxlat_status status;

status = read_pte64(step);
status = read_pte64(step, &pte);
if (status != ADDRXLAT_OK)
return status;

if (PTE_I(step->raw.pte))
if (PTE_I(pte))
return !step->ctx->noerr.notpresent
? set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"%s not present: %s[%u] = 0x%" ADDRXLAT_PRIxPTE,
Expand All @@ -97,37 +98,36 @@ pgt_s390x(addrxlat_step_t *step)
step->raw.pte)
: ADDRXLAT_ERR_NOTPRESENT;

if (step->remain >= 2 && PTE_TT(step->raw.pte) != step->remain - 2)
if (step->remain >= 2 && PTE_TT(pte) != step->remain - 2)
return set_error(step->ctx, ADDRXLAT_ERR_INVALID,
"Table type field %u in %s",
(unsigned) PTE_TT(step->raw.pte),
(unsigned) PTE_TT(pte),
pgt_full_name[step->remain]);

step->base.addr = step->raw.pte;
step->base.addr = pte;
step->base.as = step->meth->target_as;

if (step->remain == 3 && PTE_FC(step->raw.pte)) {
if (step->remain == 3 && PTE_FC(pte)) {
step->base.addr &= ~RFAA_MASK;
return pgt_huge_page(step);
}

if (step->remain == 2 && PTE_FC(step->raw.pte)) {
if (step->remain == 2 && PTE_FC(pte)) {
step->base.addr &= ~SFAA_MASK;
return pgt_huge_page(step);
}

if (step->remain >= 3) {
unsigned pgidx = step->idx[step->remain - 1] >>
(pf->fieldsz[step->remain - 1] - pf->fieldsz[0]);
if (pgidx < PTE_TF(step->raw.pte) ||
pgidx > PTE_TL(step->raw.pte))
if (pgidx < PTE_TF(pte) || pgidx > PTE_TL(pte))
return !step->ctx->noerr.notpresent
? set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"%s index %u not within %u and %u",
pgt_full_name[step->remain-1],
(unsigned) step->idx[step->remain-1],
(unsigned) PTE_TF(step->raw.pte),
(unsigned) PTE_TL(step->raw.pte))
(unsigned) PTE_TF(pte),
(unsigned) PTE_TL(pte))
: ADDRXLAT_ERR_NOTPRESENT;
}

Expand Down
20 changes: 11 additions & 9 deletions src/addrxlat/step.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,22 +139,22 @@ first_step_pgt_generic(addrxlat_step_t *step, addrxlat_addr_t addr)

/** Common next step helper for page frame number.
* @param step Current step state.
* @param pte Page table entry value (possibly masked).
* @returns Error status.
*
* This function contains the common processing for 32-bit and
* 64-bit PFNs after the PTE was read into @c step->raw.pte.
* 64-bit PFNs after the PTE was read.
*/
static addrxlat_status
next_step_pfn_common(addrxlat_step_t *step)
next_step_pfn_common(addrxlat_step_t *step, addrxlat_pte_t pte)
{
const addrxlat_meth_t *meth;
if (!step->raw.pte)
if (!pte)
return set_error(step->ctx, ADDRXLAT_ERR_NOTPRESENT,
"Level-%u PFN not present",
step->remain);
meth = step->meth;
step->base.addr =
step->raw.pte << meth->param.pgt.pf.fieldsz[0];
step->base.addr = pte << meth->param.pgt.pf.fieldsz[0];
step->base.as = meth->target_as;
if (step->remain == 1)
step->elemsz = 1;
Expand All @@ -170,10 +170,11 @@ next_step_pfn_common(addrxlat_step_t *step)
static addrxlat_status
next_step_pfn32(addrxlat_step_t *step)
{
addrxlat_status status = read_pte32(step);
addrxlat_pte_t pte;
addrxlat_status status = read_pte32(step, &pte);
if (status != ADDRXLAT_OK)
return status;
return next_step_pfn_common(step);
return next_step_pfn_common(step, pte);
}

/** Next step function for a 64-bit page frame number.
Expand All @@ -185,10 +186,11 @@ next_step_pfn32(addrxlat_step_t *step)
static addrxlat_status
next_step_pfn64(addrxlat_step_t *step)
{
addrxlat_status status = read_pte64(step);
addrxlat_pte_t pte;
addrxlat_status status = read_pte64(step, &pte);
if (status != ADDRXLAT_OK)
return status;
return next_step_pfn_common(step);
return next_step_pfn_common(step, pte);
}

/** Check unsigned address overflow.
Expand Down
Loading

0 comments on commit 25cfbe2

Please sign in to comment.