I saw a line in xen's kernel code (file: xen/include/asm-x86/x86_64/page.h), but cannot understand why they are doing this:
/* Extract flags into 24-bit integer, or turn 24-bit flags into a pte mask. */
#define get_pte_flags(x) (((int)((x) >> 40) & ~0xFFF) | ((int)(x) & 0xFFF))
#define put_pte_flags(x) (((intpte_t)((x) & ~0xFFF) << 40) | ((x) & 0xFFF))
As to
#define get_pte_flags(x) (((int)((x) >> 40) & ~0xFFF) | ((int)(x) & 0xFFF))
I understand ((int)(x) & 0xFFF) will extract the last 24 bits of x, but why they need the first part ((int)((x) >> 40) & ~0xFFF) ?
As to
#define put_pte_flags(x) (((intpte_t)((x) & ~0xFFF) << 40) | ((x) & 0xFFF))
I'm lost at the purpose of ((intpte_t)((x) & ~0xFFF) << 40). It should be 0 in my opinion. Then why do we need it?
Thanks,
I had to look twice at their code. Because it took me a minute to realize that 0xFFF is not 24 bits, it's only 12 bits. So take an example 64 bit input: 0xAABBCCDDEEFF1122. Shift it right by 40, and you get 0x0000000000AABBCC. ~0xFFF is shorthand in this case for 0xFFFFFFFFFFFFF000. And them together, and you get 0x0000000000AAB000. So basically, they grabbed the top 12 bits and moved them down. Then they or that with the bottom 12 bits. So they end up with 0x0000000000AAB122.
The other half does the opposite, takes 24 bits at the bottom, cuts them in half and puts 12 at the top and 12 at the bottom.
0xFFF is not 24 one-bits, it's only 12.
Knowing this, you'll see that the purpose of get_pte_flags is to move the top 12 bits into position 12-24, like so:
xxxxxxxx xxxx0000 00000000 00000000 00000000 00000000 0000yyyy yyyyyyyy
becomes
00000000 00000000 00000000 00000000 00000000 xxxxxxxx xxxxyyyy yyyyyyyy
Of course, put_pte_flags does the inverse, moving the bits back to the most significant position.
Think 64 bit.
On a 32 bit system the result would be 0, of course.
But, when you shift 24 bit 40 bits left, you have
xxxxxxxx yyyyyyyy zzzzzzzz 00000000 00000000 00000000 00000000 00000000
which is a valid 64 bit value.
Related
I am learning about bit wise operators and ran into this problem:
In computer graphics, colors are often stores as three numbers,
representing red, green and blue intensities. Suppose that each number requires eight bits, and we'd like to store all three values in a single long integer.
Write a macro named MK_COLOR with three parameters (the red, green and blue intensities). MK_COLOR should return a long in which
the last three bytes contain the red, green and blue intensities, with the red value as the last byte and the green value as the next-to-last byte.
The solution is:
#define MK_COLOR(r,g,b) ((long) (b) << 16 | (g) << 8 | (r))
I don't fully understand how the solution works, so I will try to break down my understanding, lets say r = 20 (10100), g = 30 (11110) and b = 40 (101000).
b is shifted left by 16 bits so we get 00010100 00000000 00000000
g is shifted by 8 bits so we get 11110000
there is a | OR operator which looks like this:
00010100 00000000 00000000
| 11110000 00000000 00000000
---------------------------
11110100 00000000 00000000
the last step does OR on this result we got but with r which looks like this:
11110100 00000000 00000000
| 10100000 00000000 00000000
---------------------------
11110100 00000000 00000000 // result
The result is 11110100 00000000 00000000 which is 15990784 in decimal. This result however is incorrect according to when I run the program and get 2629140 as the answer.
Why is it wrong? Could you please explain what I did wrong and how I can better my understanding of this?
You have mistake in your shift results. Let's break it up:
r = 20 = 0b00010100
g = 30 = 0b00011110
b = 40 = 0b00101000
(long)(b) << 16 = 0b 00101000 00000000 00000000
(long)(g) << 8 = 0b 00000000 00011110 00000000
(long)(r) = 0b 00000000 00000000 00010100
-------------------------------------------
Ored Result = 0b 00101000 00011110 00010100 = 2629140
You're unintentionally doing some extra shifts.
You start with:
r = 00010100
g = 00011110
b = 00101000
Then:
b << 16 = 00101000 00000000 00000000
g << 8 = 00011110 00000000 (you had initially shifted left by only 3)
Then you OR them all together:
00101000 00000000 00000000
00000000 00011110 00000000
| 00000000 00000000 00010100
----------------------------
00101000 00011110 00010100
The mistake you made was you added zeros on the left, essentially performing an additional shift an changing the values.
if((x & 1) == 0)
printf("EVEN!\n");
else
printf("ODD!\n");
why X&1 will always gives 1 when number is odd.. I mean what is happening in memory during this operation can any one explain it ?
Every odd number in binary has the lowest order bit set. And X & 1 is always testing that bit. Hence that check is always true.
If you don't see why the first statement is true then just convert a few decimal numbers to binary and it should be clear.
1 == 00000001b
3 == 00000011b
5 == 00000101b
7 == 00000111b
etc
Then just to be sure, do the same for a few even numbers to verify that the lowest order bit is always 0:
2 == 00000010b
4 == 00000100b
6 == 00000110b
8 == 00001000b
etc
It is because of binary number. Every binary number is the set of the 2 to the power of some number. If you are looking for the 4 bit number, then only odd number is 1(2 to the power of 0). If you are looking for number for example 12 it is on binary representation 1100. When you put the mask of 1 it looks like this
1100
&0001
0000
if you pick a odd number for example 3, you have
0011
&0001
0001
As you can see only last digit of binary number is odd and 1 is 00000001.
No matter what sizeof(int) on a platform, the number 1 represented by all the bits set to 0 except the least significant bit, which is set to 1. Let's the take the most common representation -- a 32 bit number. On such a platform, 1 is:
00000000 00000000 00000000 00000001
If you perform a bitwise AND operation of any other number with 1, all the bits except the least significant bit will always be 0. The only time the least significant bit of the result will be 1 is when the least significant bit of the other number is also 1.
Those numbers are:
00000000 00000000 00000000 00000001, which is 1
00000000 00000000 00000000 00000011, which is 3
00000000 00000000 00000000 00000101, which is 5
00000000 00000000 00000000 00000111, which is 7
and so on. As you can see from the pattern, the least significant bits of all the odd numbers are 1. The least significant bit of all the even numbers are 0. Hence,
x & 1 is 1 for all odd values of x
x & 1 is 0 for all even values of x
in ruby.h, I find it difficult to understand this macro:
#define SYMBOL_P(x) (((VALUE)(x)&0xff)==SYMBOL_FLAG)
I have no idea why this & operation is executed with 0xff. Doesn't every number & 0xff equal itself?
& is a bitwize operator (AND), (remember logic table?)
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
so what it does here?
0xff is the hexa of 255
in binary (DWORD): 00000000 00000000 00000000 11111111
so assuming a number x= any_value
the representation of x can be like this
???????? ???????? ???????? ????????
each ? can be either 1 or 0
so applying bitwize operator & (AND) with the mask 0xff gives
???????? ???????? ???????? ????????
&
00000000 00000000 00000000 11111111
=
00000000 00000000 00000000 ????????
for example
00000000 00000000 00000011 00000011
&
00000000 00000000 00000000 11111111
=
00000000 00000000 00000000 00000011
^________________________^ ^______^
zeroed kept
The VALUE type in the Ruby source code is usually 32-bit or 64-bit, so the & 0xFF sets all the bits except the lowest 8 to 0.
I'm reading the Multiboot2 specification. You can find it here. Compared to the previous version, it names all of its structures "tags". They're defined like this:
3.1.3 General tag structure
Tags constitutes a buffer of structures following each other padded on u_virt size. Every structure has
following format:
+-------------------+
u16 | type |
u16 | flags |
u32 | size |
+-------------------+
type is divided into 2 parts. Lower contains an identifier of
contents of the rest of the tag. size contains the size of tag
including header fields. If bit 0 of flags (also known as
optional) is set if bootloader may ignore this tag if it lacks
relevant support. Tags are terminated by a tag of type 0 and size
8.
Then later in example code:
for (tag = (struct multiboot_tag *) (addr + 8);
tag->type != MULTIBOOT_TAG_TYPE_END;
tag = (struct multiboot_tag *) ((multiboot_uint8_t *) tag
+ ((tag->size + 7) & ~7)))
The last part confuses me. In Multiboot 1, the code was substantially simpler, you could just do multiboot_some_structure * mss = (multiboot_some_structure *) mbi->some_addr and get the members directly, without confusing code like this.
Can somebody explain what ((tag->size + 7) & ~7) means?
As mentioned by chux in his comment, this rounds tag->size up to the nearest multiple of 8.
Let's take a closer look at how that works.
Suppose size is 16:
00010000 // 16 in binary
+00000111 // add 7
--------
00010111 // results in 23
The expression ~7 takes the value 7 and inverts all bits. So:
00010111 // 23 (from pervious step)
&11111000 // bitwise-AND ~7
--------
00010000 // results in 16
Now suppose size is 17:
00010001 // 17 in binary
+00000111 // add 7
--------
00011000 // results in 24
Then:
00011000 // 24 (from pervious step)
&11111000 // bitwise-AND ~7
--------
00011000 // results in 24
So if the lower 3 bits of size are all zero, i.e. a multiple of 8, (size+7)&~7 sets those bits and then clears them, so no net effect. But if any one of those bits is 1, the bit corresponding to 8 gets incremented, then the lower bits are cleared, i.e. the number is rounded up to the nearest multiple of 8.
~ is a bitwise not. & is a bitwise AND
assuming 16 bits are used:
7 is 0000 0000 0000 0111
~7 is 1111 1111 1111 1000
Anything and'd with a 0 is 0. Anything and'd with 1 is itself. Thus
N & 0 = 0
N & 1 = N
So when you AND with ~7, you essentially clear the lowest three bits and all of the other bits remain unchanged.
Thanks for #chux for the answer. According to him, it rounds the size up to a multiple of 8, if needed. This is very similar to a technique done in 15bpp drawing code:
//+7/8 will cause this to round up...
uint32_t vbe_bytes_per_pixel = (vbe_bits_per_pixel + 7) / 8;
Here's the reasoning:
Things were pretty simple up to now but some confusion is introduced
by the 16bpp format. It's actually 15bpp since the default format is
actually RGB 5:5:5 with the top bit of each u_int16 being unused. In
this format, each of the red, green and blue colour components is
represented by a 5 bit number giving 32 different levels of each and
32786 possible different colours in total (true 16bpp would be RGB
5:6:5 where there are 65536 possible colours). No palette is used for
16bpp RGB images - the red, green and blue values in the pixel are
used to define the colours directly.
& ~7 sets the last three bits to 0
I found the following in some old and bad documented C code:
#define addr (((((147 << 8) | 87) << 8) | 117) << 8) | 107
What is it? Well I know it's an IP address - and shifting 8 bits to the left makes some sense too. But can anyone explain this to me as a whole? What is happening there?
Thank you!
The code
(((((147 << 8) | 87) << 8) | 117) << 8) | 107
generates 4 bytes containing the IP 147.87.117.107.
The first step is the innermost bracket:
147<<8
147 = 1001 0011
1001 0011 << 8 = 1001 0011 0000 0000
The second byte 87 is inserted by bitwise-or operation on (147<<8). As you can see, the 8 bits on the right are all 0 (due to <<8), so the bitwise-or operation just inserts the 8 bits from 87:
1001 0011 0000 0000 (147<<8)
0000 0000 0101 0111 (87)
------------------- bitwise-or
1001 0011 0101 0111 (147<<8)|87
The same is done with rest so you have 4 bytes at the end saved into a single 32-bit integer.
An IPv4 address consists of four bytes, which means it can be stored in a 32-bit integer. This is taking the four parts of the IP address (147.87.117.107) and using bit-shifting and the bit-wise OR operator to "encode" the address in a single 4-byte quantity.
(Note: the address might be 107.117.87.147 - I can't remember offhand what order the bytes are stored in.)
The (hex) bytes of the resulting quantity look like:
aabb ccdd
Where aa is the hex representation of 147 (0x93), bb is 87 (0x57), cc is 117 (0x75), and dd is 107 (0x6b), so the resulting value is 9357756b.
Update: None of this applies to IPv6, since an IPv6 address is 128 bits instead of 32.