Ejemplo n.º 1
0
uint64_t buddy_alloc(buddy_t *bd, unsigned sz) {

  /** Firstly we find the smallest power of 2 that will hold the allocation request, and take the log base 2 of it. { */
  unsigned log_sz = log2_roundup(sz);
  if (log_sz > MAX_BUDDY_SZ_LOG2)
    panic("buddy_alloc had request that was too large to handle!");

  unsigned orig_log_sz = log_sz;

  /** Then we try and find a free block of this size. This involves searching in the right bitmap for an set bit. If there are no set bits, we increase the size of the block we're searching for. { */

  /* Search for a free block - we may have to increase the size of the
     block to find a free one. */
  int64_t idx;
  while (log_sz <= MAX_BUDDY_SZ_LOG2) {
    idx = bitmap_first_set(&bd->orders[log_sz - MIN_BUDDY_SZ_LOG2]);
    if (idx != -1)
      /* Block found! */
      break;
    ++log_sz;
  }

  if (idx == -1)
    /* No free blocks :( */
    return ~0ULL;

  /** Now, if we couldn't get a block of the size we wanted, we'll have to
      split it down to the right size. { */

  /* We may have to split blocks to get back to a block of
     the minimum size. */
  for (; log_sz != orig_log_sz; --log_sz) {
    int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;

    /* We're splitting a block, so deallocate it first... */
    bitmap_clear(&bd->orders[order_idx], idx);

    /* Then set both its children as free in the next order. */
    idx = INC_ORDER(idx);
    bitmap_set(&bd->orders[order_idx-1], idx);
    bitmap_set(&bd->orders[order_idx-1], idx+1);
  }

  /** By this point we have a block that is free. We should now mark it as allocated then calculate the address that actually equates to. { */

  /* Mark the block as not free. */
  int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
  bitmap_clear(&bd->orders[order_idx], idx);

  uint64_t addr = bd->start + ((uint64_t)idx << log_sz);
  return addr;  
}
Ejemplo n.º 2
0
uint64_t buddy_alloc(buddy_t *bd, unsigned sz)
{
    unsigned log_sz = log2_roundup(sz);
    if(log_sz > MAX_BUDDY_SZ_LOG2) {
        panic("buddy_alloc had request that was too large to handle");
    }
    unsigned orig_log_sz = log_sz;
    // Search for a free block -- we may need to increase the size of the block
    // to find a free one
    int64_t idx;
    while (log_sz <= MAX_BUDDY_SZ_LOG2) {
        idx = bitmap_first_set(&bd->orders[log_sz - MIN_BUDDY_SZ_LOG2]);
        if(idx != -1) {
            // we found a block
            break;
        }
        log_sz++;
    }

    if (idx == -1) {
        // No free blocks
        return ~0ULL;
    }
    // Split blocks to get a block of minimum size
    for(; log_sz != orig_log_sz; log_sz--) {
        int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
        // splitting a block, so deallocate it first.
        bitmap_clear(&bd->orders[order_idx], idx);

        // Set both children as free.
        idx = INC_ORDER(idx);
        bitmap_set(&bd->orders[order_idx - 1], idx);
        bitmap_set(&bd->orders[order_idx - 1], idx + 1);
    }
    int order_idx = log_sz - MIN_BUDDY_SZ_LOG2;
    bitmap_clear(&bd->orders[order_idx], idx);

    uint64_t addr = bd->start + ((uint64_t)idx << log_sz);
    return addr;
}