1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #if 1 30*7c478bd9Sstevel@tonic-gate #undef DEBUG 31*7c478bd9Sstevel@tonic-gate #endif 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* #define DEBUG ON */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* 36*7c478bd9Sstevel@tonic-gate * Conditions on use: 37*7c478bd9Sstevel@tonic-gate * kmem_alloc and kmem_free must not be called from interrupt level, 38*7c478bd9Sstevel@tonic-gate * except from software interrupt level. This is because they are 39*7c478bd9Sstevel@tonic-gate * not reentrant, and only block out software interrupts. They take 40*7c478bd9Sstevel@tonic-gate * too long to block any real devices. There is a routine 41*7c478bd9Sstevel@tonic-gate * kmem_free_intr that can be used to free blocks at interrupt level, 42*7c478bd9Sstevel@tonic-gate * but only up to splimp, not higher. This is because kmem_free_intr 43*7c478bd9Sstevel@tonic-gate * only spl's to splimp. 44*7c478bd9Sstevel@tonic-gate * 45*7c478bd9Sstevel@tonic-gate * Also, these routines are not that fast, so they should not be used 46*7c478bd9Sstevel@tonic-gate * in very frequent operations (e.g. operations that happen more often 47*7c478bd9Sstevel@tonic-gate * than, say, once every few seconds). 48*7c478bd9Sstevel@tonic-gate */ 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * description: 52*7c478bd9Sstevel@tonic-gate * Yet another memory allocator, this one based on a method 53*7c478bd9Sstevel@tonic-gate * described in C.J. Stephenson, "Fast Fits", IBM Sys. Journal 54*7c478bd9Sstevel@tonic-gate * 55*7c478bd9Sstevel@tonic-gate * The basic data structure is a "Cartesian" binary tree, in which 56*7c478bd9Sstevel@tonic-gate * nodes are ordered by ascending addresses (thus minimizing free 57*7c478bd9Sstevel@tonic-gate * list insertion time) and block sizes decrease with depth in the 58*7c478bd9Sstevel@tonic-gate * tree (thus minimizing search time for a block of a given size). 59*7c478bd9Sstevel@tonic-gate * 60*7c478bd9Sstevel@tonic-gate * In other words, for any node s, letting D(s) denote 61*7c478bd9Sstevel@tonic-gate * the set of descendents of s, we have: 62*7c478bd9Sstevel@tonic-gate * 63*7c478bd9Sstevel@tonic-gate * a. addr(D(left(s))) < addr(s) < addr(D(right(s))) 64*7c478bd9Sstevel@tonic-gate * b. len(D(left(s))) <= len(s) >= len(D(right(s))) 65*7c478bd9Sstevel@tonic-gate */ 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 68*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 69*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 70*7c478bd9Sstevel@tonic-gate #include <sys/saio.h> 71*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * The node header structure. 75*7c478bd9Sstevel@tonic-gate * 76*7c478bd9Sstevel@tonic-gate * To reduce storage consumption, a header block is associated with 77*7c478bd9Sstevel@tonic-gate * free blocks only, not allocated blocks. 78*7c478bd9Sstevel@tonic-gate * When a free block is allocated, its header block is put on 79*7c478bd9Sstevel@tonic-gate * a free header block list. 80*7c478bd9Sstevel@tonic-gate * 81*7c478bd9Sstevel@tonic-gate * This creates a header space and a free block space. 82*7c478bd9Sstevel@tonic-gate * The left pointer of a header blocks is used to chain free header 83*7c478bd9Sstevel@tonic-gate * blocks together. 84*7c478bd9Sstevel@tonic-gate */ 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate typedef enum {false, true} bool; 87*7c478bd9Sstevel@tonic-gate typedef struct freehdr *Freehdr; 88*7c478bd9Sstevel@tonic-gate typedef struct dblk *Dblk; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* 91*7c478bd9Sstevel@tonic-gate * Description of a header for a free block 92*7c478bd9Sstevel@tonic-gate * Only free blocks have such headers. 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate struct freehdr { 95*7c478bd9Sstevel@tonic-gate Freehdr left; /* Left tree pointer */ 96*7c478bd9Sstevel@tonic-gate Freehdr right; /* Right tree pointer */ 97*7c478bd9Sstevel@tonic-gate Dblk block; /* Ptr to the data block */ 98*7c478bd9Sstevel@tonic-gate size_t size; /* Size of the data block */ 99*7c478bd9Sstevel@tonic-gate }; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate #define NIL ((Freehdr) 0) 102*7c478bd9Sstevel@tonic-gate #define WORDSIZE sizeof (int) 103*7c478bd9Sstevel@tonic-gate #define SMALLEST_BLK 1 /* Size of smallest block */ 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate /* 106*7c478bd9Sstevel@tonic-gate * Description of a data block. 107*7c478bd9Sstevel@tonic-gate */ 108*7c478bd9Sstevel@tonic-gate struct dblk { 109*7c478bd9Sstevel@tonic-gate char data[1]; /* Addr returned to the caller */ 110*7c478bd9Sstevel@tonic-gate }; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * weight(x) is the size of a block, in bytes; or 0 if and only if x 114*7c478bd9Sstevel@tonic-gate * is a null pointer. It is the responsibility of kmem_alloc() and 115*7c478bd9Sstevel@tonic-gate * kmem_free() to keep zero-length blocks out of the arena. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate #define weight(x) ((x) == NIL? 0: (x->size)) 119*7c478bd9Sstevel@tonic-gate #define nextblk(p, size) ((Dblk) ((char *)(p) + (size))) 120*7c478bd9Sstevel@tonic-gate #define max(a, b) ((a) < (b)? (b): (a)) 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate void *kmem_alloc(size_t, int); 123*7c478bd9Sstevel@tonic-gate void kmem_free(void *ptr, size_t nbytes); 124*7c478bd9Sstevel@tonic-gate Freehdr getfreehdr(void); 125*7c478bd9Sstevel@tonic-gate static bool morecore(size_t); 126*7c478bd9Sstevel@tonic-gate void insert(Dblk p, size_t len, Freehdr *tree); 127*7c478bd9Sstevel@tonic-gate void freehdr(Freehdr p); 128*7c478bd9Sstevel@tonic-gate void delete(Freehdr *p); 129*7c478bd9Sstevel@tonic-gate static void check_need_to_free(void); 130*7c478bd9Sstevel@tonic-gate extern caddr_t resalloc(enum RESOURCES, size_t, caddr_t, int); 131*7c478bd9Sstevel@tonic-gate #ifdef __sparc 132*7c478bd9Sstevel@tonic-gate extern void resalloc_init(void); 133*7c478bd9Sstevel@tonic-gate #endif 134*7c478bd9Sstevel@tonic-gate extern int splnet(void); 135*7c478bd9Sstevel@tonic-gate extern int splimp(void); 136*7c478bd9Sstevel@tonic-gate extern void splx(int); 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate /* 139*7c478bd9Sstevel@tonic-gate * Structure containing various info about allocated memory. 140*7c478bd9Sstevel@tonic-gate */ 141*7c478bd9Sstevel@tonic-gate #define NEED_TO_FREE_SIZE 5 142*7c478bd9Sstevel@tonic-gate struct kmem_info { 143*7c478bd9Sstevel@tonic-gate Freehdr free_root; 144*7c478bd9Sstevel@tonic-gate Freehdr free_hdr_list; 145*7c478bd9Sstevel@tonic-gate struct map *map; 146*7c478bd9Sstevel@tonic-gate struct pte *pte; 147*7c478bd9Sstevel@tonic-gate caddr_t vaddr; 148*7c478bd9Sstevel@tonic-gate struct need_to_free { 149*7c478bd9Sstevel@tonic-gate caddr_t addr; 150*7c478bd9Sstevel@tonic-gate size_t nbytes; 151*7c478bd9Sstevel@tonic-gate } need_to_free_list, need_to_free[NEED_TO_FREE_SIZE]; 152*7c478bd9Sstevel@tonic-gate } kmem_info; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate struct map *kernelmap; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 158*7c478bd9Sstevel@tonic-gate static void prtree(Freehdr, char *); 159*7c478bd9Sstevel@tonic-gate #endif 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate /* 162*7c478bd9Sstevel@tonic-gate * Initialize kernel memory allocator 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate void 166*7c478bd9Sstevel@tonic-gate kmem_init(void) 167*7c478bd9Sstevel@tonic-gate { 168*7c478bd9Sstevel@tonic-gate int i; 169*7c478bd9Sstevel@tonic-gate struct need_to_free *ntf; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 172*7c478bd9Sstevel@tonic-gate printf("kmem_init entered\n"); 173*7c478bd9Sstevel@tonic-gate #endif 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate #ifdef __sparc 176*7c478bd9Sstevel@tonic-gate resalloc_init(); 177*7c478bd9Sstevel@tonic-gate #endif 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate kmem_info.free_root = NIL; 180*7c478bd9Sstevel@tonic-gate kmem_info.free_hdr_list = NULL; 181*7c478bd9Sstevel@tonic-gate kmem_info.map = kernelmap; 182*7c478bd9Sstevel@tonic-gate kmem_info.need_to_free_list.addr = 0; 183*7c478bd9Sstevel@tonic-gate ntf = kmem_info.need_to_free; 184*7c478bd9Sstevel@tonic-gate for (i = 0; i < NEED_TO_FREE_SIZE; i++) { 185*7c478bd9Sstevel@tonic-gate ntf[i].addr = 0; 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 188*7c478bd9Sstevel@tonic-gate printf("kmem_init returning\n"); 189*7c478bd9Sstevel@tonic-gate prtree(kmem_info.free_root, "kmem_init"); 190*7c478bd9Sstevel@tonic-gate #endif 191*7c478bd9Sstevel@tonic-gate } 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * Insert a new node in a cartesian tree or subtree, placing it 195*7c478bd9Sstevel@tonic-gate * in the correct position with respect to the existing nodes. 196*7c478bd9Sstevel@tonic-gate * 197*7c478bd9Sstevel@tonic-gate * algorithm: 198*7c478bd9Sstevel@tonic-gate * Starting from the root, a binary search is made for the new 199*7c478bd9Sstevel@tonic-gate * node. If this search were allowed to continue, it would 200*7c478bd9Sstevel@tonic-gate * eventually fail (since there cannot already be a node at the 201*7c478bd9Sstevel@tonic-gate * given address); but in fact it stops when it reaches a node in 202*7c478bd9Sstevel@tonic-gate * the tree which has a length less than that of the new node (or 203*7c478bd9Sstevel@tonic-gate * when it reaches a null tree pointer). The new node is then 204*7c478bd9Sstevel@tonic-gate * inserted at the root of the subtree for which the shorter node 205*7c478bd9Sstevel@tonic-gate * forms the old root (or in place of the null pointer). 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate void 210*7c478bd9Sstevel@tonic-gate insert(Dblk p, /* Ptr to the block to insert */ 211*7c478bd9Sstevel@tonic-gate size_t len, /* Length of new node */ 212*7c478bd9Sstevel@tonic-gate Freehdr *tree) /* Address of ptr to root */ 213*7c478bd9Sstevel@tonic-gate { 214*7c478bd9Sstevel@tonic-gate Freehdr x; 215*7c478bd9Sstevel@tonic-gate Freehdr *left_hook; /* Temp for insertion */ 216*7c478bd9Sstevel@tonic-gate Freehdr *right_hook; /* Temp for insertion */ 217*7c478bd9Sstevel@tonic-gate Freehdr newhdr; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate x = *tree; 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * Search for the first node which has a weight less 222*7c478bd9Sstevel@tonic-gate * than that of the new node; this will be the 223*7c478bd9Sstevel@tonic-gate * point at which we insert the new node. 224*7c478bd9Sstevel@tonic-gate */ 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate while (weight(x) >= len) { 227*7c478bd9Sstevel@tonic-gate if (p < x->block) 228*7c478bd9Sstevel@tonic-gate tree = &x->left; 229*7c478bd9Sstevel@tonic-gate else 230*7c478bd9Sstevel@tonic-gate tree = &x->right; 231*7c478bd9Sstevel@tonic-gate x = *tree; 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * Perform root insertion. The variable x traces a path through 236*7c478bd9Sstevel@tonic-gate * the tree, and with the help of left_hook and right_hook, 237*7c478bd9Sstevel@tonic-gate * rewrites all links that cross the territory occupied 238*7c478bd9Sstevel@tonic-gate * by p. Note that this improves performance under 239*7c478bd9Sstevel@tonic-gate * paging. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate newhdr = getfreehdr(); 243*7c478bd9Sstevel@tonic-gate *tree = newhdr; 244*7c478bd9Sstevel@tonic-gate left_hook = &newhdr->left; 245*7c478bd9Sstevel@tonic-gate right_hook = &newhdr->right; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate newhdr->left = NIL; 248*7c478bd9Sstevel@tonic-gate newhdr->right = NIL; 249*7c478bd9Sstevel@tonic-gate newhdr->block = p; 250*7c478bd9Sstevel@tonic-gate newhdr->size = len; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate while (x != NIL) { 253*7c478bd9Sstevel@tonic-gate /* 254*7c478bd9Sstevel@tonic-gate * Remark: 255*7c478bd9Sstevel@tonic-gate * The name 'left_hook' is somewhat confusing, since 256*7c478bd9Sstevel@tonic-gate * it is always set to the address of a .right link 257*7c478bd9Sstevel@tonic-gate * field. However, its value is always an address 258*7c478bd9Sstevel@tonic-gate * below (i.e., to the left of) p. Similarly 259*7c478bd9Sstevel@tonic-gate * for right_hook. The values of left_hook and 260*7c478bd9Sstevel@tonic-gate * right_hook converge toward the value of p, 261*7c478bd9Sstevel@tonic-gate * as in a classical binary search. 262*7c478bd9Sstevel@tonic-gate */ 263*7c478bd9Sstevel@tonic-gate if (x->block < p) { 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * rewrite link crossing from the left 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate *left_hook = x; 268*7c478bd9Sstevel@tonic-gate left_hook = &x->right; 269*7c478bd9Sstevel@tonic-gate x = x->right; 270*7c478bd9Sstevel@tonic-gate } else { 271*7c478bd9Sstevel@tonic-gate /* 272*7c478bd9Sstevel@tonic-gate * rewrite link crossing from the right 273*7c478bd9Sstevel@tonic-gate */ 274*7c478bd9Sstevel@tonic-gate *right_hook = x; 275*7c478bd9Sstevel@tonic-gate right_hook = &x->left; 276*7c478bd9Sstevel@tonic-gate x = x->left; 277*7c478bd9Sstevel@tonic-gate } /* else */ 278*7c478bd9Sstevel@tonic-gate } /* while */ 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate *left_hook = *right_hook = NIL; /* clear remaining hooks */ 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate } /* insert */ 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate /* 286*7c478bd9Sstevel@tonic-gate * Delete a node from a cartesian tree. p is the address of 287*7c478bd9Sstevel@tonic-gate * a pointer to the node which is to be deleted. 288*7c478bd9Sstevel@tonic-gate * 289*7c478bd9Sstevel@tonic-gate * algorithm: 290*7c478bd9Sstevel@tonic-gate * The left and right sons of the node to be deleted define two 291*7c478bd9Sstevel@tonic-gate * subtrees which are to be merged and attached in place of the 292*7c478bd9Sstevel@tonic-gate * deleted node. Each node on the inside edges of these two 293*7c478bd9Sstevel@tonic-gate * subtrees is examined and longer nodes are placed above the 294*7c478bd9Sstevel@tonic-gate * shorter ones. 295*7c478bd9Sstevel@tonic-gate * 296*7c478bd9Sstevel@tonic-gate * On entry: 297*7c478bd9Sstevel@tonic-gate * *p is assumed to be non-null. 298*7c478bd9Sstevel@tonic-gate */ 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate void 301*7c478bd9Sstevel@tonic-gate delete(Freehdr *p) 302*7c478bd9Sstevel@tonic-gate { 303*7c478bd9Sstevel@tonic-gate Freehdr x; 304*7c478bd9Sstevel@tonic-gate Freehdr left_branch; /* left subtree of deleted node */ 305*7c478bd9Sstevel@tonic-gate Freehdr right_branch; /* right subtree of deleted node */ 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate x = *p; 308*7c478bd9Sstevel@tonic-gate left_branch = x->left; 309*7c478bd9Sstevel@tonic-gate right_branch = x->right; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate while (left_branch != right_branch) { 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * iterate until left branch and right branch are 314*7c478bd9Sstevel@tonic-gate * both NIL. 315*7c478bd9Sstevel@tonic-gate */ 316*7c478bd9Sstevel@tonic-gate if (weight(left_branch) >= weight(right_branch)) { 317*7c478bd9Sstevel@tonic-gate /* 318*7c478bd9Sstevel@tonic-gate * promote the left branch 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate *p = left_branch; 321*7c478bd9Sstevel@tonic-gate p = &left_branch->right; 322*7c478bd9Sstevel@tonic-gate left_branch = left_branch->right; 323*7c478bd9Sstevel@tonic-gate } else { 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * promote the right branch 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate *p = right_branch; 328*7c478bd9Sstevel@tonic-gate p = &right_branch->left; 329*7c478bd9Sstevel@tonic-gate right_branch = right_branch->left; 330*7c478bd9Sstevel@tonic-gate } /* else */ 331*7c478bd9Sstevel@tonic-gate } /* while */ 332*7c478bd9Sstevel@tonic-gate *p = NIL; 333*7c478bd9Sstevel@tonic-gate freehdr(x); 334*7c478bd9Sstevel@tonic-gate } /* delete */ 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * Demote a node in a cartesian tree, if necessary, to establish 339*7c478bd9Sstevel@tonic-gate * the required vertical ordering. 340*7c478bd9Sstevel@tonic-gate * 341*7c478bd9Sstevel@tonic-gate * algorithm: 342*7c478bd9Sstevel@tonic-gate * The left and right subtrees of the node to be demoted are to 343*7c478bd9Sstevel@tonic-gate * be partially merged and attached in place of the demoted node. 344*7c478bd9Sstevel@tonic-gate * The nodes on the inside edges of these two subtrees are 345*7c478bd9Sstevel@tonic-gate * examined and the longer nodes are placed above the shorter 346*7c478bd9Sstevel@tonic-gate * ones, until a node is reached which has a length no greater 347*7c478bd9Sstevel@tonic-gate * than that of the node being demoted (or until a null pointer 348*7c478bd9Sstevel@tonic-gate * is reached). The node is then attached at this point, and 349*7c478bd9Sstevel@tonic-gate * the remaining subtrees (if any) become its descendants. 350*7c478bd9Sstevel@tonic-gate * 351*7c478bd9Sstevel@tonic-gate * on entry: 352*7c478bd9Sstevel@tonic-gate * a. All the nodes in the tree, including the one to be demoted, 353*7c478bd9Sstevel@tonic-gate * must be correctly ordered horizontally; 354*7c478bd9Sstevel@tonic-gate * b. All the nodes except the one to be demoted must also be 355*7c478bd9Sstevel@tonic-gate * correctly positioned vertically. The node to be demoted 356*7c478bd9Sstevel@tonic-gate * may be already correctly positioned vertically, or it may 357*7c478bd9Sstevel@tonic-gate * have a length which is less than that of one or both of 358*7c478bd9Sstevel@tonic-gate * its progeny. 359*7c478bd9Sstevel@tonic-gate * c. *p is non-null 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate static void 364*7c478bd9Sstevel@tonic-gate demote(Freehdr *p) 365*7c478bd9Sstevel@tonic-gate { 366*7c478bd9Sstevel@tonic-gate Freehdr x; /* addr of node to be demoted */ 367*7c478bd9Sstevel@tonic-gate Freehdr left_branch; 368*7c478bd9Sstevel@tonic-gate Freehdr right_branch; 369*7c478bd9Sstevel@tonic-gate size_t wx; 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate x = *p; 372*7c478bd9Sstevel@tonic-gate left_branch = x->left; 373*7c478bd9Sstevel@tonic-gate right_branch = x->right; 374*7c478bd9Sstevel@tonic-gate wx = weight(x); 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate while (weight(left_branch) > wx || weight(right_branch) > wx) { 377*7c478bd9Sstevel@tonic-gate /* 378*7c478bd9Sstevel@tonic-gate * select a descendant branch for promotion 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate if (weight(left_branch) >= weight(right_branch)) { 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * promote the left branch 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate *p = left_branch; 385*7c478bd9Sstevel@tonic-gate p = &left_branch->right; 386*7c478bd9Sstevel@tonic-gate left_branch = *p; 387*7c478bd9Sstevel@tonic-gate } else { 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * promote the right branch 390*7c478bd9Sstevel@tonic-gate */ 391*7c478bd9Sstevel@tonic-gate *p = right_branch; 392*7c478bd9Sstevel@tonic-gate p = &right_branch->left; 393*7c478bd9Sstevel@tonic-gate right_branch = *p; 394*7c478bd9Sstevel@tonic-gate } /* else */ 395*7c478bd9Sstevel@tonic-gate } /* while */ 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate *p = x; /* attach demoted node here */ 398*7c478bd9Sstevel@tonic-gate x->left = left_branch; 399*7c478bd9Sstevel@tonic-gate x->right = right_branch; 400*7c478bd9Sstevel@tonic-gate } /* demote */ 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * Allocate a block of storage 404*7c478bd9Sstevel@tonic-gate * 405*7c478bd9Sstevel@tonic-gate * algorithm: 406*7c478bd9Sstevel@tonic-gate * The freelist is searched by descending the tree from the root 407*7c478bd9Sstevel@tonic-gate * so that at each decision point the "better fitting" child node 408*7c478bd9Sstevel@tonic-gate * is chosen (i.e., the shorter one, if it is long enough, or 409*7c478bd9Sstevel@tonic-gate * the longer one, otherwise). The descent stops when both 410*7c478bd9Sstevel@tonic-gate * child nodes are too short. 411*7c478bd9Sstevel@tonic-gate * 412*7c478bd9Sstevel@tonic-gate * function result: 413*7c478bd9Sstevel@tonic-gate * kmem_alloc returns a pointer to the allocated block; a null 414*7c478bd9Sstevel@tonic-gate * pointer indicates storage could not be allocated. 415*7c478bd9Sstevel@tonic-gate */ 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * We need to return blocks that are on word boundaries so that callers 418*7c478bd9Sstevel@tonic-gate * that are putting int's into the area will work. Since we allow 419*7c478bd9Sstevel@tonic-gate * arbitrary free'ing, we need a weight function that considers 420*7c478bd9Sstevel@tonic-gate * free blocks starting on an odd boundary special. Allocation is 421*7c478bd9Sstevel@tonic-gate * aligned to 8 byte boundaries (ALIGN). 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate #define ALIGN 8 /* doubleword aligned .. */ 424*7c478bd9Sstevel@tonic-gate #define ALIGNMASK (ALIGN-1) 425*7c478bd9Sstevel@tonic-gate #define ALIGNMORE(addr) (ALIGN - ((uintptr_t)(addr) & ALIGNMASK)) 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * If it is empty then weight == 0 429*7c478bd9Sstevel@tonic-gate * If it is aligned then weight == size 430*7c478bd9Sstevel@tonic-gate * If it is unaligned 431*7c478bd9Sstevel@tonic-gate * if not enough room to align then weight == 0 432*7c478bd9Sstevel@tonic-gate * else weight == aligned size 433*7c478bd9Sstevel@tonic-gate */ 434*7c478bd9Sstevel@tonic-gate #define mweight(x) ((x) == NIL ? 0 : \ 435*7c478bd9Sstevel@tonic-gate ((((uintptr_t)(x)->block) & ALIGNMASK) == 0 ? (x)->size : \ 436*7c478bd9Sstevel@tonic-gate (((x)->size <= ALIGNMORE((x)->block)) ? 0 : \ 437*7c478bd9Sstevel@tonic-gate (x)->size - ALIGNMORE((x)->block)))) 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/ 440*7c478bd9Sstevel@tonic-gate void * 441*7c478bd9Sstevel@tonic-gate kmem_alloc(size_t nbytes, int kmflag) 442*7c478bd9Sstevel@tonic-gate { 443*7c478bd9Sstevel@tonic-gate Freehdr a; /* ptr to node to be allocated */ 444*7c478bd9Sstevel@tonic-gate Freehdr *p; /* address of ptr to node */ 445*7c478bd9Sstevel@tonic-gate size_t left_weight; 446*7c478bd9Sstevel@tonic-gate size_t right_weight; 447*7c478bd9Sstevel@tonic-gate Freehdr left_son; 448*7c478bd9Sstevel@tonic-gate Freehdr right_son; 449*7c478bd9Sstevel@tonic-gate char *retblock; /* Address returned to the user */ 450*7c478bd9Sstevel@tonic-gate int s; 451*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 452*7c478bd9Sstevel@tonic-gate printf("kmem_alloc(nbytes 0x%lx)\n", nbytes); 453*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate if (nbytes == 0) { 456*7c478bd9Sstevel@tonic-gate return (NULL); 457*7c478bd9Sstevel@tonic-gate } 458*7c478bd9Sstevel@tonic-gate s = splnet(); 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate if (nbytes < SMALLEST_BLK) { 461*7c478bd9Sstevel@tonic-gate printf("illegal kmem_alloc call for %lx bytes\n", nbytes); 462*7c478bd9Sstevel@tonic-gate prom_panic("kmem_alloc"); 463*7c478bd9Sstevel@tonic-gate } 464*7c478bd9Sstevel@tonic-gate check_need_to_free(); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate /* 467*7c478bd9Sstevel@tonic-gate * ensure that at least one block is big enough to satisfy 468*7c478bd9Sstevel@tonic-gate * the request. 469*7c478bd9Sstevel@tonic-gate */ 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (mweight(kmem_info.free_root) <= nbytes) { 472*7c478bd9Sstevel@tonic-gate /* 473*7c478bd9Sstevel@tonic-gate * the largest block is not enough. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate if (!morecore(nbytes)) { 476*7c478bd9Sstevel@tonic-gate printf("kmem_alloc failed, nbytes %lx\n", nbytes); 477*7c478bd9Sstevel@tonic-gate prom_panic("kmem_alloc"); 478*7c478bd9Sstevel@tonic-gate } 479*7c478bd9Sstevel@tonic-gate } 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate /* 482*7c478bd9Sstevel@tonic-gate * search down through the tree until a suitable block is 483*7c478bd9Sstevel@tonic-gate * found. At each decision point, select the better 484*7c478bd9Sstevel@tonic-gate * fitting node. 485*7c478bd9Sstevel@tonic-gate */ 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate p = (Freehdr *) &kmem_info.free_root; 488*7c478bd9Sstevel@tonic-gate a = *p; 489*7c478bd9Sstevel@tonic-gate left_son = a->left; 490*7c478bd9Sstevel@tonic-gate right_son = a->right; 491*7c478bd9Sstevel@tonic-gate left_weight = mweight(left_son); 492*7c478bd9Sstevel@tonic-gate right_weight = mweight(right_son); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate while (left_weight >= nbytes || right_weight >= nbytes) { 495*7c478bd9Sstevel@tonic-gate if (left_weight <= right_weight) { 496*7c478bd9Sstevel@tonic-gate if (left_weight >= nbytes) { 497*7c478bd9Sstevel@tonic-gate p = &a->left; 498*7c478bd9Sstevel@tonic-gate a = left_son; 499*7c478bd9Sstevel@tonic-gate } else { 500*7c478bd9Sstevel@tonic-gate p = &a->right; 501*7c478bd9Sstevel@tonic-gate a = right_son; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate } else { 504*7c478bd9Sstevel@tonic-gate if (right_weight >= nbytes) { 505*7c478bd9Sstevel@tonic-gate p = &a->right; 506*7c478bd9Sstevel@tonic-gate a = right_son; 507*7c478bd9Sstevel@tonic-gate } else { 508*7c478bd9Sstevel@tonic-gate p = &a->left; 509*7c478bd9Sstevel@tonic-gate a = left_son; 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate } 512*7c478bd9Sstevel@tonic-gate left_son = a->left; 513*7c478bd9Sstevel@tonic-gate right_son = a->right; 514*7c478bd9Sstevel@tonic-gate left_weight = mweight(left_son); 515*7c478bd9Sstevel@tonic-gate right_weight = mweight(right_son); 516*7c478bd9Sstevel@tonic-gate } /* while */ 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate /* 519*7c478bd9Sstevel@tonic-gate * allocate storage from the selected node. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate if (a->size - nbytes < SMALLEST_BLK) { 523*7c478bd9Sstevel@tonic-gate /* 524*7c478bd9Sstevel@tonic-gate * not big enough to split; must leave at least 525*7c478bd9Sstevel@tonic-gate * a dblk's worth of space. 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate retblock = a->block->data; 528*7c478bd9Sstevel@tonic-gate delete(p); 529*7c478bd9Sstevel@tonic-gate } else { 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* 532*7c478bd9Sstevel@tonic-gate * split the node, allocating nbytes from the top. 533*7c478bd9Sstevel@tonic-gate * Remember we've already accounted for the 534*7c478bd9Sstevel@tonic-gate * allocated node's header space. 535*7c478bd9Sstevel@tonic-gate */ 536*7c478bd9Sstevel@tonic-gate Freehdr x; 537*7c478bd9Sstevel@tonic-gate x = getfreehdr(); 538*7c478bd9Sstevel@tonic-gate if ((uintptr_t)a->block->data & ALIGNMASK) { 539*7c478bd9Sstevel@tonic-gate size_t size; 540*7c478bd9Sstevel@tonic-gate if (a->size <= ALIGNMORE(a->block->data)) 541*7c478bd9Sstevel@tonic-gate prom_panic("kmem_alloc: short block allocated"); 542*7c478bd9Sstevel@tonic-gate size = nbytes + ALIGNMORE(a->block->data); 543*7c478bd9Sstevel@tonic-gate x->block = a->block; 544*7c478bd9Sstevel@tonic-gate x->size = ALIGNMORE(a->block->data); 545*7c478bd9Sstevel@tonic-gate x->left = a->left; 546*7c478bd9Sstevel@tonic-gate x->right = a->right; 547*7c478bd9Sstevel@tonic-gate /* 548*7c478bd9Sstevel@tonic-gate * the node pointed to by *p has become smaller; 549*7c478bd9Sstevel@tonic-gate * move it down to its appropriate place in 550*7c478bd9Sstevel@tonic-gate * the tree. 551*7c478bd9Sstevel@tonic-gate */ 552*7c478bd9Sstevel@tonic-gate *p = x; 553*7c478bd9Sstevel@tonic-gate demote(p); 554*7c478bd9Sstevel@tonic-gate retblock = a->block->data + ALIGNMORE(a->block->data); 555*7c478bd9Sstevel@tonic-gate if (a->size > size) { 556*7c478bd9Sstevel@tonic-gate kmem_free((caddr_t)nextblk(a->block, size), 557*7c478bd9Sstevel@tonic-gate (size_t)(a->size - size)); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate freehdr(a); 560*7c478bd9Sstevel@tonic-gate } else { 561*7c478bd9Sstevel@tonic-gate x->block = nextblk(a->block, nbytes); 562*7c478bd9Sstevel@tonic-gate x->size = a->size - nbytes; 563*7c478bd9Sstevel@tonic-gate x->left = a->left; 564*7c478bd9Sstevel@tonic-gate x->right = a->right; 565*7c478bd9Sstevel@tonic-gate /* 566*7c478bd9Sstevel@tonic-gate * the node pointed to by *p has become smaller; 567*7c478bd9Sstevel@tonic-gate * move it down to its appropriate place in 568*7c478bd9Sstevel@tonic-gate * the tree. 569*7c478bd9Sstevel@tonic-gate */ 570*7c478bd9Sstevel@tonic-gate *p = x; 571*7c478bd9Sstevel@tonic-gate demote(p); 572*7c478bd9Sstevel@tonic-gate retblock = a->block->data; 573*7c478bd9Sstevel@tonic-gate freehdr(a); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 577*7c478bd9Sstevel@tonic-gate prtree(kmem_info.free_root, "kmem_alloc"); 578*7c478bd9Sstevel@tonic-gate #endif 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate splx(s); 581*7c478bd9Sstevel@tonic-gate bzero(retblock, nbytes); 582*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 583*7c478bd9Sstevel@tonic-gate printf("kmem_alloc bzero complete - returning %p\n", retblock); 584*7c478bd9Sstevel@tonic-gate #endif 585*7c478bd9Sstevel@tonic-gate return (retblock); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate } /* kmem_alloc */ 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * Return a block to the free space tree. 591*7c478bd9Sstevel@tonic-gate * 592*7c478bd9Sstevel@tonic-gate * algorithm: 593*7c478bd9Sstevel@tonic-gate * Starting at the root, search for and coalesce free blocks 594*7c478bd9Sstevel@tonic-gate * adjacent to one given. When the appropriate place in the 595*7c478bd9Sstevel@tonic-gate * tree is found, insert the given block. 596*7c478bd9Sstevel@tonic-gate * 597*7c478bd9Sstevel@tonic-gate * Do some sanity checks to avoid total confusion in the tree. 598*7c478bd9Sstevel@tonic-gate * If the block has already been freed, prom_panic. 599*7c478bd9Sstevel@tonic-gate * If the ptr is not from the arena, prom_panic. 600*7c478bd9Sstevel@tonic-gate */ 601*7c478bd9Sstevel@tonic-gate void 602*7c478bd9Sstevel@tonic-gate kmem_free(void *ptr, size_t nbytes) 603*7c478bd9Sstevel@tonic-gate { 604*7c478bd9Sstevel@tonic-gate Freehdr *np; /* For deletion from free list */ 605*7c478bd9Sstevel@tonic-gate Freehdr neighbor; /* Node to be coalesced */ 606*7c478bd9Sstevel@tonic-gate char *neigh_block; /* Ptr to potential neighbor */ 607*7c478bd9Sstevel@tonic-gate size_t neigh_size; /* Size of potential neighbor */ 608*7c478bd9Sstevel@tonic-gate int s; 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 611*7c478bd9Sstevel@tonic-gate printf("kmem_free (ptr %p nbytes %lx)\n", ptr, nbytes); 612*7c478bd9Sstevel@tonic-gate prtree(kmem_info.free_root, "kmem_free"); 613*7c478bd9Sstevel@tonic-gate #endif 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate #ifdef lint 616*7c478bd9Sstevel@tonic-gate neigh_block = bkmem_zalloc(nbytes); 617*7c478bd9Sstevel@tonic-gate neigh_block = neigh_block; 618*7c478bd9Sstevel@tonic-gate #endif 619*7c478bd9Sstevel@tonic-gate if (nbytes == 0) { 620*7c478bd9Sstevel@tonic-gate return; 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate if (ptr == 0) { 624*7c478bd9Sstevel@tonic-gate prom_panic("kmem_free of 0"); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate s = splnet(); 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate /* 629*7c478bd9Sstevel@tonic-gate * Search the tree for the correct insertion point for this 630*7c478bd9Sstevel@tonic-gate * node, coalescing adjacent free blocks along the way. 631*7c478bd9Sstevel@tonic-gate */ 632*7c478bd9Sstevel@tonic-gate np = &kmem_info.free_root; 633*7c478bd9Sstevel@tonic-gate neighbor = *np; 634*7c478bd9Sstevel@tonic-gate while (neighbor != NIL) { 635*7c478bd9Sstevel@tonic-gate neigh_block = (char *)neighbor->block; 636*7c478bd9Sstevel@tonic-gate neigh_size = neighbor->size; 637*7c478bd9Sstevel@tonic-gate if ((char *)ptr < neigh_block) { 638*7c478bd9Sstevel@tonic-gate if ((char *)ptr + nbytes == neigh_block) { 639*7c478bd9Sstevel@tonic-gate /* 640*7c478bd9Sstevel@tonic-gate * Absorb and delete right neighbor 641*7c478bd9Sstevel@tonic-gate */ 642*7c478bd9Sstevel@tonic-gate nbytes += neigh_size; 643*7c478bd9Sstevel@tonic-gate delete(np); 644*7c478bd9Sstevel@tonic-gate } else if ((char *)ptr + nbytes > neigh_block) { 645*7c478bd9Sstevel@tonic-gate /* 646*7c478bd9Sstevel@tonic-gate * The block being freed overlaps 647*7c478bd9Sstevel@tonic-gate * another block in the tree. This 648*7c478bd9Sstevel@tonic-gate * is bad news. 649*7c478bd9Sstevel@tonic-gate */ 650*7c478bd9Sstevel@tonic-gate printf("kmem_free: free block overlap %p+%lx" 651*7c478bd9Sstevel@tonic-gate " over %p\n", (void *)ptr, nbytes, 652*7c478bd9Sstevel@tonic-gate (void *)neigh_block); 653*7c478bd9Sstevel@tonic-gate prom_panic("kmem_free: free block overlap"); 654*7c478bd9Sstevel@tonic-gate } else { 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * Search to the left 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate np = &neighbor->left; 659*7c478bd9Sstevel@tonic-gate } 660*7c478bd9Sstevel@tonic-gate } else if ((char *)ptr > neigh_block) { 661*7c478bd9Sstevel@tonic-gate if (neigh_block + neigh_size == ptr) { 662*7c478bd9Sstevel@tonic-gate /* 663*7c478bd9Sstevel@tonic-gate * Absorb and delete left neighbor 664*7c478bd9Sstevel@tonic-gate */ 665*7c478bd9Sstevel@tonic-gate ptr = neigh_block; 666*7c478bd9Sstevel@tonic-gate nbytes += neigh_size; 667*7c478bd9Sstevel@tonic-gate delete(np); 668*7c478bd9Sstevel@tonic-gate } else if (neigh_block + neigh_size > (char *)ptr) { 669*7c478bd9Sstevel@tonic-gate /* 670*7c478bd9Sstevel@tonic-gate * This block has already been freed 671*7c478bd9Sstevel@tonic-gate */ 672*7c478bd9Sstevel@tonic-gate prom_panic("kmem_free block already free"); 673*7c478bd9Sstevel@tonic-gate } else { 674*7c478bd9Sstevel@tonic-gate /* 675*7c478bd9Sstevel@tonic-gate * search to the right 676*7c478bd9Sstevel@tonic-gate */ 677*7c478bd9Sstevel@tonic-gate np = &neighbor->right; 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate } else { 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * This block has already been freed 682*7c478bd9Sstevel@tonic-gate * as "ptr == neigh_block" 683*7c478bd9Sstevel@tonic-gate */ 684*7c478bd9Sstevel@tonic-gate prom_panic("kmem_free: block already free as neighbor"); 685*7c478bd9Sstevel@tonic-gate return; 686*7c478bd9Sstevel@tonic-gate } /* else */ 687*7c478bd9Sstevel@tonic-gate neighbor = *np; 688*7c478bd9Sstevel@tonic-gate } /* while */ 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate /* 691*7c478bd9Sstevel@tonic-gate * Insert the new node into the free space tree 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate insert((Dblk) ptr, nbytes, &kmem_info.free_root); 694*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 695*7c478bd9Sstevel@tonic-gate printf("exiting kmem_free\n"); 696*7c478bd9Sstevel@tonic-gate prtree(kmem_info.free_root, "kmem_free"); 697*7c478bd9Sstevel@tonic-gate #endif 698*7c478bd9Sstevel@tonic-gate splx(s); 699*7c478bd9Sstevel@tonic-gate } /* kmem_free */ 700*7c478bd9Sstevel@tonic-gate 701*7c478bd9Sstevel@tonic-gate /* 702*7c478bd9Sstevel@tonic-gate * Sigh. We include a header file which the kernel 703*7c478bd9Sstevel@tonic-gate * uses to declare (one of its many) kmem_free prototypes. 704*7c478bd9Sstevel@tonic-gate * In order not to use the kernel's namespace, then, we must 705*7c478bd9Sstevel@tonic-gate * define another name here for use by boot. 706*7c478bd9Sstevel@tonic-gate */ 707*7c478bd9Sstevel@tonic-gate void * 708*7c478bd9Sstevel@tonic-gate bkmem_alloc(size_t size) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate return (kmem_alloc(size, 0)); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate /* 714*7c478bd9Sstevel@tonic-gate * Boot's kmem_alloc is really kmem_zalloc(). 715*7c478bd9Sstevel@tonic-gate */ 716*7c478bd9Sstevel@tonic-gate void * 717*7c478bd9Sstevel@tonic-gate bkmem_zalloc(size_t size) 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate return (kmem_alloc(size, 0)); 720*7c478bd9Sstevel@tonic-gate } 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate void 723*7c478bd9Sstevel@tonic-gate bkmem_free(void *p, size_t bytes) 724*7c478bd9Sstevel@tonic-gate { 725*7c478bd9Sstevel@tonic-gate kmem_free(p, bytes); 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate static void 729*7c478bd9Sstevel@tonic-gate check_need_to_free(void) 730*7c478bd9Sstevel@tonic-gate { 731*7c478bd9Sstevel@tonic-gate int i; 732*7c478bd9Sstevel@tonic-gate struct need_to_free *ntf; 733*7c478bd9Sstevel@tonic-gate caddr_t addr; 734*7c478bd9Sstevel@tonic-gate size_t nbytes; 735*7c478bd9Sstevel@tonic-gate int s; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate again: 738*7c478bd9Sstevel@tonic-gate s = splimp(); 739*7c478bd9Sstevel@tonic-gate ntf = &kmem_info.need_to_free_list; 740*7c478bd9Sstevel@tonic-gate if (ntf->addr) { 741*7c478bd9Sstevel@tonic-gate addr = ntf->addr; 742*7c478bd9Sstevel@tonic-gate nbytes = ntf->nbytes; 743*7c478bd9Sstevel@tonic-gate *ntf = *(struct need_to_free *)ntf->addr; 744*7c478bd9Sstevel@tonic-gate splx(s); 745*7c478bd9Sstevel@tonic-gate kmem_free(addr, nbytes); 746*7c478bd9Sstevel@tonic-gate goto again; 747*7c478bd9Sstevel@tonic-gate } 748*7c478bd9Sstevel@tonic-gate ntf = kmem_info.need_to_free; 749*7c478bd9Sstevel@tonic-gate for (i = 0; i < NEED_TO_FREE_SIZE; i++) { 750*7c478bd9Sstevel@tonic-gate if (ntf[i].addr) { 751*7c478bd9Sstevel@tonic-gate addr = ntf[i].addr; 752*7c478bd9Sstevel@tonic-gate nbytes = ntf[i].nbytes; 753*7c478bd9Sstevel@tonic-gate ntf[i].addr = 0; 754*7c478bd9Sstevel@tonic-gate splx(s); 755*7c478bd9Sstevel@tonic-gate kmem_free(addr, nbytes); 756*7c478bd9Sstevel@tonic-gate goto again; 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate splx(s); 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate 762*7c478bd9Sstevel@tonic-gate /* 763*7c478bd9Sstevel@tonic-gate * Add a block of at least nbytes to the free space tree. 764*7c478bd9Sstevel@tonic-gate * 765*7c478bd9Sstevel@tonic-gate * return value: 766*7c478bd9Sstevel@tonic-gate * true if at least nbytes can be allocated 767*7c478bd9Sstevel@tonic-gate * false otherwise 768*7c478bd9Sstevel@tonic-gate * 769*7c478bd9Sstevel@tonic-gate * remark: 770*7c478bd9Sstevel@tonic-gate * free space (delimited by the static variable ubound) is 771*7c478bd9Sstevel@tonic-gate * extended by an amount determined by rounding nbytes up to 772*7c478bd9Sstevel@tonic-gate * a multiple of the system page size. 773*7c478bd9Sstevel@tonic-gate */ 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate static bool 776*7c478bd9Sstevel@tonic-gate morecore(size_t nbytes) 777*7c478bd9Sstevel@tonic-gate { 778*7c478bd9Sstevel@tonic-gate #ifdef __sparc 779*7c478bd9Sstevel@tonic-gate enum RESOURCES type = RES_BOOTSCRATCH_NOFAIL; 780*7c478bd9Sstevel@tonic-gate #else 781*7c478bd9Sstevel@tonic-gate enum RESOURCES type = RES_BOOTSCRATCH; 782*7c478bd9Sstevel@tonic-gate #endif 783*7c478bd9Sstevel@tonic-gate Dblk p; 784*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 785*7c478bd9Sstevel@tonic-gate printf("morecore(nbytes 0x%lx)\n", nbytes); 786*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate 789*7c478bd9Sstevel@tonic-gate nbytes = roundup(nbytes, PAGESIZE); 790*7c478bd9Sstevel@tonic-gate p = (Dblk) resalloc(type, nbytes, (caddr_t)0, 0); 791*7c478bd9Sstevel@tonic-gate if (p == 0) { 792*7c478bd9Sstevel@tonic-gate return (false); 793*7c478bd9Sstevel@tonic-gate } 794*7c478bd9Sstevel@tonic-gate kmem_free((caddr_t)p, nbytes); 795*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 796*7c478bd9Sstevel@tonic-gate printf("morecore() returing, p = %p\n", p); 797*7c478bd9Sstevel@tonic-gate #endif 798*7c478bd9Sstevel@tonic-gate return (true); 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate } /* morecore */ 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * Get a free block header 804*7c478bd9Sstevel@tonic-gate * There is a list of available free block headers. 805*7c478bd9Sstevel@tonic-gate * When the list is empty, allocate another pagefull. 806*7c478bd9Sstevel@tonic-gate */ 807*7c478bd9Sstevel@tonic-gate Freehdr 808*7c478bd9Sstevel@tonic-gate getfreehdr(void) 809*7c478bd9Sstevel@tonic-gate { 810*7c478bd9Sstevel@tonic-gate Freehdr r; 811*7c478bd9Sstevel@tonic-gate int n = 0; 812*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 813*7c478bd9Sstevel@tonic-gate printf("getfreehdr()\n"); 814*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate if (kmem_info.free_hdr_list != NIL) { 817*7c478bd9Sstevel@tonic-gate r = kmem_info.free_hdr_list; 818*7c478bd9Sstevel@tonic-gate kmem_info.free_hdr_list = kmem_info.free_hdr_list->left; 819*7c478bd9Sstevel@tonic-gate } else { 820*7c478bd9Sstevel@tonic-gate r = (Freehdr)resalloc(RES_BOOTSCRATCH, PAGESIZE, (caddr_t)0, 0); 821*7c478bd9Sstevel@tonic-gate if (r == 0) { 822*7c478bd9Sstevel@tonic-gate prom_panic("getfreehdr"); 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate for (n = 1; n < PAGESIZE / sizeof (*r); n++) { 825*7c478bd9Sstevel@tonic-gate freehdr(&r[n]); 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate } 828*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 829*7c478bd9Sstevel@tonic-gate printf("getfreehdr: freed %x headers\n", n); 830*7c478bd9Sstevel@tonic-gate printf("getfreehdr: returning %p\n", r); 831*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 832*7c478bd9Sstevel@tonic-gate return (r); 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate /* 836*7c478bd9Sstevel@tonic-gate * Free a free block header 837*7c478bd9Sstevel@tonic-gate * Add it to the list of available headers. 838*7c478bd9Sstevel@tonic-gate */ 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate void 841*7c478bd9Sstevel@tonic-gate freehdr(Freehdr p) 842*7c478bd9Sstevel@tonic-gate { 843*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 844*7c478bd9Sstevel@tonic-gate printf("freehdr(%p)\n", p); 845*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 846*7c478bd9Sstevel@tonic-gate p->left = kmem_info.free_hdr_list; 847*7c478bd9Sstevel@tonic-gate p->right = NIL; 848*7c478bd9Sstevel@tonic-gate p->block = NULL; 849*7c478bd9Sstevel@tonic-gate kmem_info.free_hdr_list = p; 850*7c478bd9Sstevel@tonic-gate } 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 853*7c478bd9Sstevel@tonic-gate /* 854*7c478bd9Sstevel@tonic-gate * Diagnostic routines 855*7c478bd9Sstevel@tonic-gate */ 856*7c478bd9Sstevel@tonic-gate static int depth = 0; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate static void 859*7c478bd9Sstevel@tonic-gate prtree(Freehdr p, char *cp) 860*7c478bd9Sstevel@tonic-gate { 861*7c478bd9Sstevel@tonic-gate int n; 862*7c478bd9Sstevel@tonic-gate if (depth == 0) { 863*7c478bd9Sstevel@tonic-gate printf("prtree(p %p cp %s)\n", p, cp); 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate if (p != NIL) { 866*7c478bd9Sstevel@tonic-gate depth++; 867*7c478bd9Sstevel@tonic-gate prtree(p->left, (char *)NULL); 868*7c478bd9Sstevel@tonic-gate depth--; 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate for (n = 0; n < depth; n++) { 871*7c478bd9Sstevel@tonic-gate printf(" "); 872*7c478bd9Sstevel@tonic-gate } 873*7c478bd9Sstevel@tonic-gate printf( 874*7c478bd9Sstevel@tonic-gate "(%p): (left = %p, right = %p, block = %p, size = %lx)\n", 875*7c478bd9Sstevel@tonic-gate p, p->left, p->right, p->block, p->size); 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate depth++; 878*7c478bd9Sstevel@tonic-gate prtree(p->right, (char *)NULL); 879*7c478bd9Sstevel@tonic-gate depth--; 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 883