Message ID | 0c80dc19-8f01-3561-aa05-9b34001faeb4@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Julien, > The patch belows solve my problem: > > diff --git a/xen/arch/arm/guest_walk.c b/xen/arch/arm/guest_walk.c > index b258248322..6ca994e438 100644 > --- a/xen/arch/arm/guest_walk.c > +++ b/xen/arch/arm/guest_walk.c > @@ -112,7 +112,7 @@ static int guest_walk_sd(const struct vcpu *v, > * level translation table does not need to be page aligned. > */ > mask = GENMASK(19, 12); > - paddr = (pte.walk.base << 10) | ((gva & mask) >> 10); > + paddr = ((paddr_t)pte.walk.base << 10) | ((gva & mask) >> 10); > > /* Access the guest's memory to read only one PTE. */ > ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false); > > This is because pte.walk.base is encoded on unsigned int:22 bits. A shift by 10 will not > fit an integer, and my compiler seems to promote it to "signed long long". Hence the bogus > address. > Thats quite an interesting phenomenon :) I have just played around with this and it does indeed appear that the value is casted to a signed result! What I don't yet understand is the following: An unsigned int with the length of 22 bit should actually exactly fit an integer after a left shift of 10 (or do I miss s.th.?). Anyway, thanks for the patch! V8 containing this change will follow soon. Thanks, ~Sergej
On 08/08/17 15:47, Sergej Proskurin wrote: > Hi Julien, > >> The patch belows solve my problem: >> >> diff --git a/xen/arch/arm/guest_walk.c b/xen/arch/arm/guest_walk.c >> index b258248322..6ca994e438 100644 >> --- a/xen/arch/arm/guest_walk.c >> +++ b/xen/arch/arm/guest_walk.c >> @@ -112,7 +112,7 @@ static int guest_walk_sd(const struct vcpu *v, >> * level translation table does not need to be page aligned. >> */ >> mask = GENMASK(19, 12); >> - paddr = (pte.walk.base << 10) | ((gva & mask) >> 10); >> + paddr = ((paddr_t)pte.walk.base << 10) | ((gva & mask) >> 10); >> >> /* Access the guest's memory to read only one PTE. */ >> ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false); >> >> This is because pte.walk.base is encoded on unsigned int:22 bits. A shift by 10 will not >> fit an integer, and my compiler seems to promote it to "signed long long". Hence the bogus >> address. >> > > Thats quite an interesting phenomenon :) I have just played around with > this and it does indeed appear that the value is casted to a signed > result! What I don't yet understand is the following: An unsigned int > with the length of 22 bit should actually exactly fit an integer after a > left shift of 10 (or do I miss s.th.?). C type promotion ftw! All integral types smaller than int are promoted to int before any operations on them. This includes things like unsigned char/short etc. Then, the type is promoted to match that of the other operand, which might be a wider type (e.g. long) or an unsigned version of the same type. ~Andrew
On 08/08/2017 04:58 PM, Andrew Cooper wrote: > On 08/08/17 15:47, Sergej Proskurin wrote: >> Hi Julien, >> >>> The patch belows solve my problem: >>> >>> diff --git a/xen/arch/arm/guest_walk.c b/xen/arch/arm/guest_walk.c >>> index b258248322..6ca994e438 100644 >>> --- a/xen/arch/arm/guest_walk.c >>> +++ b/xen/arch/arm/guest_walk.c >>> @@ -112,7 +112,7 @@ static int guest_walk_sd(const struct vcpu *v, >>> * level translation table does not need to be page aligned. >>> */ >>> mask = GENMASK(19, 12); >>> - paddr = (pte.walk.base << 10) | ((gva & mask) >> 10); >>> + paddr = ((paddr_t)pte.walk.base << 10) | ((gva & mask) >> 10); >>> >>> /* Access the guest's memory to read only one PTE. */ >>> ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false); >>> >>> This is because pte.walk.base is encoded on unsigned int:22 bits. A shift by 10 will not >>> fit an integer, and my compiler seems to promote it to "signed long long". Hence the bogus >>> address. >>> >> Thats quite an interesting phenomenon :) I have just played around with >> this and it does indeed appear that the value is casted to a signed >> result! What I don't yet understand is the following: An unsigned int >> with the length of 22 bit should actually exactly fit an integer after a >> left shift of 10 (or do I miss s.th.?). > C type promotion ftw! > > All integral types smaller than int are promoted to int before any > operations on them. This includes things like unsigned char/short etc. > > Then, the type is promoted to match that of the other operand, which > might be a wider type (e.g. long) or an unsigned version of the same type. Thanks Andrew, I did not know that! Cheers, ~Sergej
diff --git a/xen/arch/arm/guest_walk.c b/xen/arch/arm/guest_walk.c index b258248322..6ca994e438 100644 --- a/xen/arch/arm/guest_walk.c +++ b/xen/arch/arm/guest_walk.c @@ -112,7 +112,7 @@ static int guest_walk_sd(const struct vcpu *v, * level translation table does not need to be page aligned. */ mask = GENMASK(19, 12); - paddr = (pte.walk.base << 10) | ((gva & mask) >> 10); + paddr = ((paddr_t)pte.walk.base << 10) | ((gva & mask) >> 10); /* Access the guest's memory to read only one PTE. */ ret = access_guest_memory_by_ipa(d, paddr, &pte, sizeof(short_desc_t), false);