1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/promif.h> 32 #include <sys/memlist.h> 33 #include <sys/bootconf.h> 34 #include <sys/salib.h> 35 36 /* 37 * This file defines the interface from the prom and platform-dependent 38 * form of the memory lists, to boot's more generic form of the memory 39 * list. For sun4u, the memory list properties are {hi, lo, size_hi, size_lo}, 40 * which is similar to boot's format, except boot's format is a linked 41 * list, and the prom's is an array of these structures. Note that the 42 * native property on sparc machines is identical to the property encoded 43 * format, so no property decoding is required. 44 * 45 * Note that the format of the memory lists is really 4 encoded integers, 46 * but the encoding is the same as that given in the following structure 47 * on SPARC systems ... 48 */ 49 50 struct sun4u_prom_memlist { 51 u_longlong_t addr; 52 u_longlong_t size; 53 }; 54 55 struct sun4u_prom_memlist scratch_memlist[200]; 56 57 struct memlist *fill_memlists(char *name, char *prop, struct memlist *); 58 extern struct memlist *pfreelistp, *vfreelistp, *pinstalledp; 59 60 static struct memlist *reg_to_list(struct sun4u_prom_memlist *a, size_t size, 61 struct memlist *old); 62 static void sort_reglist(struct sun4u_prom_memlist *ar, size_t size); 63 extern void kmem_init(void); 64 65 void 66 init_memlists(void) 67 { 68 /* this list is a map of pmem actually installed */ 69 pinstalledp = fill_memlists("memory", "reg", pinstalledp); 70 71 vfreelistp = fill_memlists("virtual-memory", "available", vfreelistp); 72 pfreelistp = fill_memlists("memory", "available", pfreelistp); 73 74 kmem_init(); 75 } 76 77 struct memlist * 78 fill_memlists(char *name, char *prop, struct memlist *old) 79 { 80 static pnode_t pmem = 0; 81 static pnode_t pmmu = 0; 82 pnode_t node; 83 size_t links; 84 struct memlist *al; 85 struct sun4u_prom_memlist *pm = scratch_memlist; 86 87 if (pmem == (pnode_t)0) { 88 89 /* 90 * Figure out the interesting phandles, one time 91 * only. 92 */ 93 94 ihandle_t ih; 95 96 if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1) 97 prom_panic("Can't get mmu ihandle"); 98 pmmu = prom_getphandle(ih); 99 100 if ((ih = prom_memory_ihandle()) == (ihandle_t)-1) 101 prom_panic("Can't get memory ihandle"); 102 pmem = prom_getphandle(ih); 103 } 104 105 if (strcmp(name, "memory") == 0) 106 node = pmem; 107 else 108 node = pmmu; 109 110 /* 111 * Read memory node and calculate the number of entries 112 */ 113 if ((links = prom_getproplen(node, prop)) == -1) 114 prom_panic("Cannot get list.\n"); 115 if (links > sizeof (scratch_memlist)) { 116 prom_printf("%s list <%s> exceeds boot capabilities\n", 117 name, prop); 118 prom_panic("fill_memlists - memlist size"); 119 } 120 links = links / sizeof (struct sun4u_prom_memlist); 121 122 123 (void) prom_getprop(node, prop, (caddr_t)pm); 124 sort_reglist(pm, links); 125 al = reg_to_list(pm, links, old); 126 return (al); 127 } 128 129 /* 130 * Simple selection sort routine. 131 * Sorts platform dependent memory lists into ascending order 132 */ 133 134 static void 135 sort_reglist(struct sun4u_prom_memlist *ar, size_t n) 136 { 137 int i, j, min; 138 struct sun4u_prom_memlist temp; 139 140 for (i = 0; i < n; i++) { 141 min = i; 142 143 for (j = i+1; j < n; j++) { 144 if (ar[j].addr < ar[min].addr) 145 min = j; 146 } 147 148 if (i != min) { 149 /* Swap ar[i] and ar[min] */ 150 temp = ar[min]; 151 ar[min] = ar[i]; 152 ar[i] = temp; 153 } 154 } 155 } 156 157 /* 158 * This routine will convert our platform dependent memory list into 159 * struct memlists's. And it will also coalesce adjacent nodes if 160 * possible. 161 */ 162 static struct memlist * 163 reg_to_list(struct sun4u_prom_memlist *ar, size_t n, struct memlist *old) 164 { 165 struct memlist *ptr, *head, *last; 166 int i; 167 u_longlong_t size = 0; 168 u_longlong_t addr = 0; 169 u_longlong_t start1, start2; 170 int flag = 0; 171 172 if (n == 0) 173 return ((struct memlist *)0); 174 175 /* 176 * if there was a memory list allocated before, free it first. 177 */ 178 if (old) 179 (void) add_to_freelist(old); 180 181 head = NULL; 182 last = NULL; 183 184 for (i = 0; i < n; i++) { 185 start1 = ar[i].addr; 186 start2 = ar[i+1].addr; 187 if (i < n-1 && (start1 + ar[i].size == start2)) { 188 size += ar[i].size; 189 if (!flag) { 190 addr = start1; 191 flag++; 192 } 193 continue; 194 } else if (flag) { 195 /* 196 * catch the last one on the way out of 197 * this iteration 198 */ 199 size += ar[i].size; 200 } 201 202 ptr = (struct memlist *)get_memlist_struct(); 203 if (!head) 204 head = ptr; 205 if (last) 206 last->next = ptr; 207 ptr->address = flag ? addr : start1; 208 ptr->size = size ? size : ar[i].size; 209 ptr->prev = last; 210 last = ptr; 211 212 size = 0; 213 flag = 0; 214 addr = 0; 215 } 216 217 last->next = NULL; 218 return (head); 219 } 220