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