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