1/* $NetBSD: src/sys/arch/acorn26/stand/boot26/boot26.c,v 1.5 2007-03-04 05:59:04 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 1999, 2000, 2001 Ben Harris 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include <lib/libkern/libkern.h> 31#include <lib/libsa/stand.h> 32#include <lib/libsa/loadfile.h> 33#include <riscoscalls.h> 34#include <sys/boot_flag.h> 35#include <machine/boot.h> 36#include <machine/memcreg.h> 37 38extern const char bootprog_rev[]; 39extern const char bootprog_name[]; 40 41int debug = 1; 42 43enum pgstatus { FREE, USED_RISCOS, USED_KERNEL, USED_BOOT }; 44 45int nbpp; 46struct os_mem_map_request *pginfo; 47enum pgstatus *pgstatus; 48 49u_long marks[MARK_MAX]; 50 51char fbuf[80]; 52 53void get_mem_map(struct os_mem_map_request *, enum pgstatus *, int); 54int vdu_var(int); 55 56extern void start_kernel(struct bootconfig *, u_int, u_int); 57 58int 59main(int argc, char **argv) 60{ 61 int npages, howto; 62 int i, j; 63 char *file; 64 struct bootconfig bootconfig; 65 int crow; 66 int ret; 67 68 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 69 70 os_read_mem_map_info(&nbpp, &npages); 71 if (debug) 72 printf("Machine has %d pages of %d KB each. " 73 "Total RAM: %d MB\n", npages, nbpp >> 10, 74 (npages * nbpp) >> 20); 75 76 /* Need one extra for teminator in OS_ReadMemMapEntries. */ 77 pginfo = alloc((npages + 1) * sizeof(*pginfo)); 78 if (pginfo == NULL) 79 panic("cannot alloc pginfo array"); 80 memset(pginfo, 0, npages * sizeof(*pginfo)); 81 pgstatus = alloc(npages * sizeof(*pgstatus)); 82 if (pgstatus == NULL) 83 panic("cannot alloc pgstatus array"); 84 memset(pgstatus, 0, npages * sizeof(*pgstatus)); 85 86 get_mem_map(pginfo, pgstatus, npages); 87 88 howto = 0; 89 file = NULL; 90 for (i = 1; i < argc; i++) 91 if (argv[i][0] == '-') 92 for (j = 1; argv[i][j]; j++) 93 BOOT_FLAG(argv[i][j], howto); 94 else 95 if (file) 96 panic("Too many files!"); 97 else 98 file = argv[i]; 99 if (file == NULL) { 100 if (howto & RB_ASKNAME) { 101 printf("boot: "); 102 gets(fbuf); 103 file = fbuf; 104 } else 105 file = "netbsd"; 106 } 107 printf("Booting %s (howto = 0x%x)\n", file, howto); 108 109 ret = loadfile(file, marks, LOAD_KERNEL); 110 if (ret == -1) 111 panic("Kernel load failed"); 112 close(ret); 113 114 printf("Starting at 0x%lx\n", marks[MARK_ENTRY]); 115 116 memset(&bootconfig, 0, sizeof(bootconfig)); 117 bootconfig.magic = BOOT_MAGIC; 118 bootconfig.version = 0; 119 bootconfig.boothowto = howto; 120 bootconfig.bootdev = -1; 121 bootconfig.ssym = (void *)marks[MARK_SYM] - MEMC_PHYS_BASE; 122 bootconfig.esym = (void *)marks[MARK_END] - MEMC_PHYS_BASE; 123 bootconfig.nbpp = nbpp; 124 bootconfig.npages = npages; 125 bootconfig.freebase = (void *)marks[MARK_END] - MEMC_PHYS_BASE; 126 bootconfig.xpixels = vdu_var(os_MODEVAR_XWIND_LIMIT) + 1; 127 bootconfig.ypixels = vdu_var(os_MODEVAR_YWIND_LIMIT) + 1; 128 bootconfig.bpp = 1 << vdu_var(os_MODEVAR_LOG2_BPP); 129 bootconfig.screenbase = (void *)vdu_var(os_VDUVAR_DISPLAY_START) + 130 vdu_var(os_VDUVAR_TOTAL_SCREEN_SIZE) - MEMC_PHYS_BASE; 131 bootconfig.screensize = vdu_var(os_VDUVAR_TOTAL_SCREEN_SIZE); 132 os_byte(osbyte_OUTPUT_CURSOR_POSITION, 0, 0, NULL, &crow); 133 bootconfig.cpixelrow = crow * vdu_var(os_VDUVAR_TCHAR_SPACEY); 134 135 if (bootconfig.bpp < 8) 136 printf("WARNING: Current screen mode has fewer than eight " 137 "bits per pixel.\n" 138 " Console display may not work correctly " 139 "(or at all).\n"); 140 /* Tear down RISC OS... */ 141 142 /* NetBSD will want the cache off initially. */ 143 xcache_control(0, 0, NULL); 144 145 /* Dismount all filesystems. */ 146 xosfscontrol_shutdown(); 147 148 /* Ask device drivers to reset devices. */ 149 service_pre_reset(); 150 151 /* Disable interrupts. */ 152 os_int_off(); 153 154 start_kernel(&bootconfig, marks[MARK_ENTRY], 0x02090000); 155 156 return 0; 157} 158 159void 160get_mem_map(struct os_mem_map_request *pginfo, enum pgstatus *pgstatus, 161 int npages) 162{ 163 int i; 164 165 for (i = 0; i < npages; i++) 166 pginfo[i].page_no = i; 167 pginfo[npages].page_no = -1; 168 os_read_mem_map_entries(pginfo); 169 170 if (debug) 171 printf("--------/-------/-------/-------\n"); 172 for (i = 0; i < npages; i++) { 173 pgstatus[i] = USED_RISCOS; 174 if (pginfo[i].access == os_AREA_ACCESS_NONE) { 175 if (debug) printf("."); 176 } else { 177 if (pginfo[i].map < (void *)0x0008000) { 178 if (debug) printf("0"); 179 } else if (pginfo[i].map < (void *)HIMEM) { 180 pgstatus[i] = USED_BOOT; 181 if (debug) printf("+"); 182 } else if (pginfo[i].map < (void *)0x1000000) { 183 if (pginfo[i].access == 184 os_AREA_ACCESS_READ_WRITE) { 185 pgstatus[i] = FREE; 186 if (debug) printf("*"); 187 } else { 188 if (debug) printf("a"); 189 } 190 } else if (pginfo[i].map < (void *)0x1400000) { 191 if (debug) printf("d"); 192 } else if (pginfo[i].map < (void *)0x1800000) { 193 if (debug) printf("s"); 194 } else if (pginfo[i].map < (void *)0x1c00000) { 195 if (debug) printf("m"); 196 } else if (pginfo[i].map < (void *)0x1e00000) { 197 if (debug) printf("h"); 198 } else if (pginfo[i].map < (void *)0x1f00000) { 199 if (debug) printf("f"); 200 } else if (pginfo[i].map < (void *)0x2000000) { 201 if (debug) printf("S"); 202 } 203 } 204 if (i % 32 == 31 && debug) 205 printf("\n"); 206 } 207} 208 209/* 210 * Return the address of a page that will end up corresponding to the 211 * target address when the kernel boots. "target" is expected to be 212 * in the MEMC physical RAM area (0x02000000--0x02ffffff). It need 213 * not be page-aligned. The return value is in the logical RAM area, 214 * and either points to a mapping of the requested page or to a 215 * mapping of another page which will be copied to the requested page 216 * after RISC OS is shut down. 217 * 218 * At present, there's no relocation mechanism, so we panic if its use 219 * is required. 220 */ 221static void * 222get_page(void *target) 223{ 224 int ppn; 225 226 ppn = ((void *)target - MEMC_PHYS_BASE) / nbpp; 227 if (pgstatus[ppn] != FREE) 228 panic("Page %d not free", ppn); 229 return pginfo[ppn].map; 230} 231 232ssize_t 233boot26_read(int f, void *addr, size_t size) 234{ 235 void *fragaddr; 236 size_t fragsize; 237 ssize_t retval, total; 238 239 total = 0; 240 while (size > 0) { 241 fragaddr = get_page(addr) + ((u_int)addr % nbpp); 242 fragsize = nbpp - ((u_int)addr % nbpp); 243 if (fragsize > size) 244 fragsize = size; 245 retval = read(f, fragaddr, fragsize); 246 if (retval < 0) 247 return retval; 248 total += retval; 249 if (retval < fragsize) 250 return total; 251 addr += fragsize; 252 size -= fragsize; 253 } 254 return total; 255} 256 257void * 258boot26_memcpy(void *dst, const void *src, size_t size) 259{ 260 void *fragaddr; 261 size_t fragsize; 262 void *addr = dst; 263 264 while (size > 0) { 265 fragaddr = get_page(addr) + ((u_int)addr % nbpp); 266 fragsize = nbpp - ((u_int)addr % nbpp); 267 if (fragsize > size) 268 fragsize = size; 269 memcpy(fragaddr, src, fragsize); 270 addr += fragsize; 271 src += fragsize; 272 size -= fragsize; 273 } 274 return dst; 275} 276 277void * 278boot26_memset(void *dst, int c, size_t size) 279{ 280 void *fragaddr; 281 size_t fragsize; 282 void *addr = dst; 283 284 while (size > 0) { 285 fragaddr = get_page(addr) + ((u_int)addr % nbpp); 286 fragsize = nbpp - ((u_int)addr % nbpp); 287 if (fragsize > size) 288 fragsize = size; 289 memset(fragaddr, c, fragsize); 290 addr += fragsize; 291 size -= fragsize; 292 } 293 return dst; 294} 295 296int 297vdu_var(int var) 298{ 299 int varlist[2], vallist[2]; 300 301 varlist[0] = var; 302 varlist[1] = -1; 303 os_read_vdu_variables(varlist, vallist); 304 return vallist[0]; 305} 306