newbie newbie - 1 year ago 103
C Question

Understanding Linux module code snippet

I am interpreting a generated intermediate code of a linux kernel module. But i am unable to understand the following line of code of

pci_set_dma_mask


if ((err = pci_set_dma_mask(pdev, (((32) == 64) ? ~0ULL : ((1ULL<<(32))-1))))) {

(void)((NETIF_MSG_PROBE & nic->msg_enable) && printk("<3>" "e100" ": " "%s: %s: "
"No usable DMA configuration, aborting.\n", nic->netdev->name, func));
}


My understanding is that, since 32 != 64,
((1ULL<<(32))-1)
will execute. But what kind of value is
1ULL
? What is happening internally when we left shift
1ULL
32 times?. And can someone provide some code samples to understand this? Thanks in advance

Recommended for you: Get network issues from WhatsUp Gold. Not end users.
Answer Source

The redundant parentheses and the trivial condition (32) == 64 show that this is generated code, possibly the result of running the preprocessor. That condition tests whether something is 32-bit or 64-bit and the code has been generated for a system where that thing is 32-bit.

On a 64-bit system, the value ~0ULL is used. With the ULL suffix, the constant is of type unsigned long long, which is a 64-bit type on all platforms that the Linux kernel supports (standard C specifies that unsigned long long is 64-bit or larger but almost all systems have it as exactly 64 bits). The ~ operator takes the bitwise complement, so the result is the number 264-1, i.e. a 64-bit constant whose binary representation is all-bits-one. In hexadecimal, that's 0xffffffffffffffff.

The reason the code uses ~0ULL and not ~0 is that in ~0, the constant 0 is an int, which is a 32-bit type on all platforms that the Linux kernel support. The ~ operator applies to this would yield a 32-bit value with all-bits-one, i.e. 0xffffffff in hexadecimal, i.e. the number number 232-1. When converted to a 64-bit value, the numerical value remains the same — not an all-64-bits-one constant.

On a 32-bit system, the code uses 1ULL<<(32))-1. First 1ULL is a 64-bit value; 1ULL << 32 shifts it left by 32, which means multiplying the numerical value by 232, which yields the number 232, or in hexadecimal 0x100000000. Subtracting 1 yields 232, i.e. 0xffffffff (an all-32-bits-one constant).

Doing the operations on an unsigned long long is necessary here too, because a left shift by 32 is not defined for 32-bit values. Standard C says that x << 32 is undefined behavior if the type of x is a 32-bit type or less. In practice, on many systems, the processor instruction for shifting on a 32-bit type takes a shift amount in the range 0…31, and 1 << 32 would be compiled to the same code as 1 << 0 (wrapping modulo 32), yielding 1 instead of 232.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download