xref: /inferno-os/os/port/devboot.c (revision 556f8a312ed1b20f8ff25c104928646828e8b05c)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 enum{
9 	Qdir,
10 	Qboot,
11 	Qmem,
12 	Qkexec,
13 
14 	Maxkexec = 1536*1024,
15 };
16 
17 static
18 Dirtab bootdir[]={
19 	".",			{Qdir, 0, QTDIR},	0,	0555,
20 	"boot",		{Qboot},	0,	0220,
21 	"mem",		{Qmem},		0,	0660,
22 	"kexec",		{Qkexec},		0,	0220,
23 };
24 
25 static Chan*
26 bootattach(char *spec)
27 {
28 	return devattach('B', spec);
29 }
30 
31 static Walkqid*
32 bootwalk(Chan *c, Chan *nc, char **name, int nname)
33 {
34 	return devwalk(c, nc, name, nname, bootdir, nelem(bootdir), devgen);
35 }
36 
37 static int
38 bootstat(Chan *c, uchar *dp, int n)
39 {
40 	return devstat(c, dp, n, bootdir, nelem(bootdir), devgen);
41 }
42 
43 static Chan*
44 bootopen(Chan *c, int omode)
45 {
46 	if (c->qid.path == Qkexec) {
47 		c->aux = malloc(Maxkexec);
48 		print("kexec buffer: %lux\n", c->aux);
49 	}
50 	return devopen(c, omode, bootdir, nelem(bootdir), devgen);
51 }
52 
53 static void
54 bootclose(Chan *c)
55 {
56 	if(c->qid.path == Qkexec && c->aux != nil){
57 		print("exec new kernel @%lux\n", (ulong)c->aux);
58 		splhi();
59 		segflush(c->aux, 64*1024);
60 		gotopc((ulong)c->aux);
61 	}
62 }
63 
64 static long
65 bootread(Chan *c, void *buf, long n, vlong offset)
66 {
67 	switch((ulong)c->qid.path){
68 
69 	case Qdir:
70 		return devdirread(c, buf, n, bootdir, nelem(bootdir), devgen);
71 
72 	case Qmem:
73 		/* kernel memory */
74 		if(offset>=KZERO && offset<KZERO+conf.npage*BY2PG){
75 			if(offset+n > KZERO+conf.npage*BY2PG)
76 				n = KZERO+conf.npage*BY2PG - offset;
77 			memmove(buf, (char*)offset, n);
78 			return n;
79 		}
80 		error(Ebadarg);
81 	}
82 
83 	error(Egreg);
84 	return 0;	/* not reached */
85 }
86 
87 static long
88 bootwrite(Chan *c, void *buf, long n, vlong offset)
89 {
90 	ulong pc;
91 	uchar *p;
92 
93 	switch((ulong)c->qid.path){
94 	case Qmem:
95 		/* kernel memory */
96 		if(offset>=KZERO && offset<KZERO+conf.npage*BY2PG){
97 			if(offset+n > KZERO+conf.npage*BY2PG)
98 				n = KZERO+conf.npage*BY2PG - offset;
99 			memmove((char*)offset, buf, n);
100 			segflush((void*)offset, n);
101 			return n;
102 		}
103 		error(Ebadarg);
104 
105 	case Qboot:
106 		p = (uchar*)buf;
107 		pc = (((((p[0]<<8)|p[1])<<8)|p[2])<<8)|p[3];
108 		if(pc < KZERO || pc >= KZERO+conf.npage*BY2PG)
109 			error(Ebadarg);
110 		splhi();
111 		segflush((void*)pc, 64*1024);
112 		gotopc(pc);
113 
114 	case Qkexec:
115 		print(".");
116 		if(c->aux != nil && offset <= Maxkexec){
117 			if(offset+n > Maxkexec)
118 				n = Maxkexec - offset;
119 			memmove((char*)c->aux+offset, buf, n);
120 			segflush((char*)c->aux+offset, n);
121 			return n;
122 		}
123 		free(c->aux);
124 		c->aux = nil;
125 		error(Ebadarg);
126 	}
127 	error(Ebadarg);
128 	return 0;	/* not reached */
129 }
130 
131 Dev bootdevtab = {
132 	'B',
133 	"boot",
134 
135 	devreset,
136 	devinit,
137 	devshutdown,
138 	bootattach,
139 	bootwalk,
140 	bootstat,
141 	bootopen,
142 	devcreate,
143 	bootclose,
144 	bootread,
145 	devbread,
146 	bootwrite,
147 	devbwrite,
148 	devremove,
149 	devwstat,
150 };
151