From: Andrew Cooper Date: Sun, 12 Apr 2015 17:39:41 +0000 (+0100) Subject: Provide 64bit division in 32bit environments X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=d75062b1fc6123e287e337b19ae9b1e0975b37db;p=people%2Froyger%2Fxen-test-framework.git Provide 64bit division in 32bit environments Signed-off-by: Andrew Cooper --- diff --git a/include/arch/x86/div.h b/include/arch/x86/div.h new file mode 100644 index 0000000..1985b2d --- /dev/null +++ b/include/arch/x86/div.h @@ -0,0 +1,64 @@ +#ifndef XTF_X86_DIV_H +#define XTF_X86_DIV_H + +#include + +/* + * Divide a 64bit number by 32bit divisor without software support. + * + * The dividend is modified in place, and the modulus is returned. + */ +static inline uint32_t divmod64(uint64_t *dividend, uint32_t divisor) +{ + uint32_t mod; + +#ifdef __x86_64__ + + /* + * On 64bit, issue a straight 'div' instruction. + */ + + mod = *dividend % divisor; + *dividend /= divisor; +#else + { + /* + * On 32bit, this is harder. + * + * In x86, 'divl' can take a 64bit dividend, but the resulting + * quotient must fit in %eax or a #DE will occur. + * + * To avoid this, we split the division in two. The remainder from + * the higher divide can safely be used in the upper 32bits of the + * lower divide, as it will not cause an overflow. + */ + uint32_t high = *dividend >> 32, low = *dividend, umod = 0; + + if ( high ) + { + umod = high % divisor; + high /= divisor; + } + + asm ("divl %2" + : "=a" (low), "=d" (mod) + : "rm" (divisor), "0" (low), "1" (umod)); + + *dividend = (((uint64_t)high) << 32) | low; + } +#endif + + return mod; +} + +#endif /* XTF_X86_DIV_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */