summaryrefslogtreecommitdiff
path: root/sys/arch/alpha/stand/bootxx.c
blob: 48c21f3c7faa260b41122a62e4c938a38b297034 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <sys/param.h>
#include <machine/prom.h>

#include "bbinfo.h"

extern _end, start;

struct bbinfoloc desc = {
	0xbabefacedeadbeef,
	(u_int64_t)&start,
	(u_int64_t)&_end,
	0xdeadbeeffacebabe
};

int
open_dev(fd)
	int *fd;
{
	prom_return_t ret;
	char devname[64];
	int devlen;

	/*
	 * XXX
         * We don't know what device names look like yet,
         * so we can't change them.
         */
        ret.bits = prom_getenv(PROM_E_BOOTED_DEV, devname, sizeof(devname));
        devlen = ret.u.retval;

        ret.bits = prom_open(devname, devlen);
        if (ret.u.status)
                return 0;

	*fd = ret.u.retval;

	return 1;
}

int
load_file(bbinfop, loadaddr)
	struct bbinfo *bbinfop;
	char *loadaddr;
{
	prom_return_t ret;
	int32_t cksum, *int32p;
	int i, n, fd, rv;
	char *cp;

	if (bbinfop->nblocks <= 0) {
		puts("invalid number of blocks in boot program description\n");
		return 0;
	}
	if (bbinfop->bsize < 4096 || bbinfop->bsize > MAXBSIZE) {
		puts("invalid block size in boot program description\n");
		return 0;
	}

	int32p = (int32_t *)&_end;
	n = bbinfop->nblocks +
	    (sizeof(*bbinfop) / sizeof(bbinfop->blocks[0])) - 1;
	if ((long)&_end - (long)&start + sizeof(bbinfop->blocks[0]) * n >
	    15 * 512) {
		puts("way too many blocks\n");
		return 0;
	}

	for (i = 0, cksum = 0; i < n; i++)
		cksum += *int32p++;
	if (cksum != 0) {
		puts("invalid checksum in boot program description\n");
		return 0;
	}

	if (!open_dev(&fd)) {
		puts("couldn't open disk device\n");
		return 0;
	}

	cp = loadaddr;
	rv = 1;
	for (i = 0; i < bbinfop->nblocks; i++) {
puts(".");
		ret.bits = prom_read(fd, bbinfop->bsize, cp,
		    bbinfop->blocks[i]);
puts("\b");
		if (ret.u.status) {
			rv = 0;
			puts("BLOCK READ ERROR!\n");
			break;
		}
		cp += bbinfop->bsize;
	}
	prom_close(fd);

	return (rv);
}

void
main()
{
	struct bbinfo *bbinfop;
	char *loadaddr;
	void (*entry) __P((void));

	/* Init prom callback vector. */
	init_prom_calls();

	puts("\nNetBSD/Alpha primary boot...\n");

	bbinfop = (struct bbinfo *)&_end;
	loadaddr = (char *)SECONDARY_LOAD_ADDRESS;
	if (!load_file(bbinfop, loadaddr)) {
		puts("\nLOAD FAILED!\n\n");
		return;
	}

	puts("Jumping to entry point...\n");
	entry = (void (*)())loadaddr;
	(*entry)();
	puts("SECONDARY BOOT BLOCK RETURNED!\n");
}