achoora
achoora

Reputation: 1350

Whats the purpose served by the strange bitwise operator combo?

I was going through the following code and came across the following snippet.

https://www.virtualbox.org/svn/vbox/trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Core/Pei/Hob/Hob.c

EFI_STATUS  
EFIAPI  
PeiCreateHob (  
  IN CONST EFI_PEI_SERVICES  **PeiServices,  
  IN UINT16            Type,  
  IN UINT16            Length,  
  IN OUT VOID          **Hob  
  )  
{  
  EFI_STATUS                           Status;  
  EFI_HOB_HANDOFF_INFO_TABLE           *HandOffHob;  
  EFI_HOB_GENERIC_HEADER               *HobEnd;  
  EFI_PHYSICAL_ADDRESS                 FreeMemory;  


  Status = PeiGetHobList (PeiServices, Hob);  
  if (EFI_ERROR(Status)) {  
    return Status;  
  }

  HandOffHob = *Hob;  

  //
  // Check Length to avoid data overflow.
  //
  if (0x10000 - Length <= 0x7) {  
    return EFI_INVALID_PARAMETER;  
  }
  Length     = (UINT16)((Length + 0x7) & (~0x7));  
  ...

I don't get what we are achieving with the following operation:

Length     = (UINT16)((Length + 0x7) & (~0x7));

I know that the length would be 16 bit aligned. But why are we ANDing with all zeros? We would be losing the LSB 3 bits in the operation as I understand. What's the use of this operation?

Upvotes: 0

Views: 174

Answers (1)

WhozCraig
WhozCraig

Reputation: 66194

Length = (UINT16)((Length + 0x7) & (~0x7));

The operation performs two significant steps:

  • Performs a round-up by carry to bits above the lower three bits of Length
  • Ensures the lower three bits are then empty, thereby making the result the closest multiple of 8 equal to, or greater than, the original Length value.

Part 1: Rounding Up

If the lower three bits of Length are in anyway lit (anything besides 000), an increment by 0x7 (111 in binary) will propagate via carry to the bits above the lower three. For 000 in the lower three bits, the lower three bits simply become 111 and there is no carry. For example:

 5 - 00000101
 7 - 00000111
=============
12 - 00001100
         ^-------note carry

Another example:

250 -  11111010
  7 -  00000111
===============
257 - 100000001

And finally, an example that is already clear on the lower three bits (and therefore a multiple of 8):

24 - 00011000
 7 - 00000111
=============
31 - 00011111

Part 2: Culling Lower Bits

Once the value is rounded up, the lower three bits are culled to ensure the final result is a multiple of 8. Using the examples we had before

   5 - 00000101
+  7 - 00000111
===============
  12 - 00001100
& ~7 - 11111000
===============
   8   00001000

Next example

 250 -  11111010
+  7 -  00000111
================
 257 - 100000001
& ~7 - 111111000
================
 256 - 100000000

And our final example:

  24 - 00011000
+  7 - 00000111
===============
  31 - 00011111
& ~7 - 11111000
===============
  24 - 00011000

In summary, this simply sets Length to be the closest value equal-to or above the current value that is a multiple of 8. That's it.

Upvotes: 3

Related Questions