1/*-
2 * Copyright (c) 2013-2014 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/linker.h>
36#include <sys/reboot.h>
37
38#include <machine/bootinfo.h>
39#include <machine/elf.h>
40
41#include <stand.h>
42#include <bootstrap.h>
43#include <loader.h>
44#include <mips.h>
45
46#ifdef LOADER_USB_SUPPORT
47#include <storage/umass_common.h>
48#endif
49
50static int	__elfN(exec)(struct preloaded_file *);
51static void	extract_currdev(struct bootinfo *);
52
53struct devsw *devsw[] = {
54	&beri_cfi_disk,
55	&beri_sdcard_disk,
56#ifdef LOADER_USB_SUPPORT
57	&umass_disk,
58#endif
59	NULL
60};
61
62struct file_format *file_formats[] = {
63	&beri_elf,
64	NULL
65};
66
67struct fs_ops *file_system[] = {
68#ifdef LOADER_UFS_SUPPORT
69	&ufs_fsops,
70#endif
71	NULL
72};
73
74struct console *consoles[] = {
75	&altera_jtag_uart_console,
76	NULL
77};
78
79extern uint8_t	__bss_start, __bss_end;
80extern uint8_t	__heap_start, __heap_end;
81
82static int
83__elfN(exec)(struct preloaded_file *fp)
84{
85
86	return (EFTYPE);
87}
88
89/*
90 * Capture arguments from boot2 for later reuse when launching the kernel.
91 * Note that we choose not to maintain a pointer to boo2_bootinfop after
92 * initial argument processing: this is because we might load the kernel over
93 * the spot where boot2 was running, so we can't pass that pointer on to the
94 * kernel.  To be on the safe side, never reference it outside of the body of
95 * main(), instead preserving a copy.
96 */
97int		 boot2_argc;
98char		**boot2_argv;
99char		**boot2_envv;
100
101struct bootinfo	boot2_bootinfo;
102
103int
104main(int argc, char *argv[], char *envv[], struct bootinfo *bootinfop)
105{
106	struct devsw **dp;
107
108	/* NB: Must be sure to bzero() before using any globals. */
109	bzero(&__bss_start, &__bss_end - &__bss_start);
110
111	boot2_argc = argc;
112	boot2_argv = argv;
113	boot2_envv = envv;
114	boot2_bootinfo = *bootinfop;	/* Copy rather than by reference. */
115
116	setheap(&__heap_start, &__heap_end);
117
118	/*
119	 * Pick up console settings from boot2; probe console.
120	 */
121	if (bootinfop->bi_boot2opts & RB_MULTIPLE) {
122		if (bootinfop->bi_boot2opts & RB_SERIAL)
123			setenv("console", "comconsole vidconsole", 1);
124		else
125			setenv("console", "vidconsole comconsole", 1);
126	} else if (bootinfop->bi_boot2opts & RB_SERIAL)
127		setenv("console", "comconsole", 1);
128	else if (bootinfop->bi_boot2opts & RB_MUTE)
129		setenv("console", "nullconsole", 1);
130	cons_probe();
131	setenv("LINES", "24", 1);
132
133	printf("%s(%d, %p, %p, %p (%p))\n", __func__, argc, argv, envv,
134	    bootinfop, (void *)bootinfop->bi_memsize);
135
136	/*
137	 * Initialise devices.
138	 */
139	for (dp = devsw; *dp != NULL; dp++) {
140		if ((*dp)->dv_init != NULL)
141			(*dp)->dv_init();
142	}
143	extract_currdev(bootinfop);
144
145	printf("\n%s", bootprog_info);
146#if 0
147	printf("bootpath=\"%s\"\n", bootpath);
148#endif
149
150	interact();
151	return (0);
152}
153
154static void
155extract_currdev(struct bootinfo *bootinfop)
156{
157	const char *bootdev;
158
159	/*
160	 * Pick up boot device information from boot2.
161	 *
162	 * XXXRW: Someday: device units.
163	 */
164	switch(bootinfop->bi_boot_dev_type) {
165	case BOOTINFO_DEV_TYPE_DRAM:
166		bootdev = "dram0";
167		break;
168
169	case BOOTINFO_DEV_TYPE_CFI:
170		bootdev = "cfi0";
171		break;
172
173	case BOOTINFO_DEV_TYPE_SDCARD:
174		bootdev = "sdcard0";
175		break;
176
177	default:
178		bootdev = NULL;
179	}
180
181	if (bootdev != NULL) {
182		env_setenv("currdev", EV_VOLATILE, bootdev, NULL, env_nounset);
183		env_setenv("loaddev", EV_VOLATILE, bootdev, env_noset,
184		    env_nounset);
185	}
186}
187
188void
189abort(void)
190{
191
192	printf("error: loader abort\n");
193	while (1);
194	__unreachable();
195}
196
197void
198exit(int code)
199{
200
201	printf("error: loader exit\n");
202	while (1);
203	__unreachable();
204}
205
206void
207longjmperror(void)
208{
209
210	printf("error: loader longjmp error\n");
211	while (1);
212	__unreachable();
213}
214
215time_t
216time(time_t *tloc)
217{
218
219	/* We can't provide time since UTC, so just provide time since boot. */
220	return (cp0_count_get() / 100000000);
221}
222
223/*
224 * Delay - in usecs
225 *
226 * NOTE: We are assuming that the CPU is running at 100MHz.
227 */
228void
229delay(int usecs)
230{
231	uint32_t delta;
232	uint32_t curr;
233	uint32_t last;
234
235	last = cp0_count_get();
236	while (usecs > 0) {
237		curr = cp0_count_get();
238		delta = curr - last;
239		while (usecs > 0 && delta >= 100) {
240			usecs--;
241			last += 100;
242			delta -= 100;
243		}
244	}
245}
246