Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Bootstrap loader decompressor.  Starts at 0x10000 (where pbs puts it)
3
 * or 0x7c00 (where pxe puts it) and memmoves kernel (immediately following)
4
 * into standard kernel location.
5
 */
6
#include "mem.h"
7
#include "/sys/src/boot/pc/x16.h"
8
 
9
#undef BIOSCALL		/* we don't know what evil the bios gets up to */
10
#define BIOSCALL(b)	INT $(b); CLI
11
 
12
#define CMPL(r0, r1)	BYTE $0x66; CMP(r0, r1)
13
#define LLI(i, rX)	BYTE $0x66;		/* i -> rX */		\
14
			BYTE $(0xB8+rX);				\
15
			LONG $i;
16
#define CPUID		BYTE $0x0F; BYTE $0xA2	/* CPUID, argument in AX */
17
#define WBINVD		BYTE $0x0F; BYTE $0x09
18
 
19
TEXT origin(SB), $0
20
/*
21
 *	turn off interrupts
22
 */
23
	CLI
24
 
25
	/*
26
	 * This part of l.s is used only in the boot kernel.
27
	 * It assumes that we are in real address mode, i.e.,
28
	 * that we look like an 8086.
29
	 *
30
	 * Make sure the segments are reasonable.
31
	 * If we were started directly from the BIOS
32
	 * (i.e. no MS-DOS) then DS may not be
33
	 * right.
34
	 */
35
	MOVW	CS, AX
36
	MOVW	AX, DS
37
 
38
	LWI(0, rAX)			/* always put stack in first 64k */
39
	MTSR(rAX, rSS)
40
	LWI(origin(SB), rSP)		/* set the stack pointer */
41
 
42
	LWI(0x2401, rAX)		/* enable a20 line */
43
	BIOSCALL(0x15)
44
 
45
	XORL	AX, AX
46
	MOVB	$0x03, AL
47
//	LWI(3, rAX)
48
	INT	$0x10			/* set video mode in AL */
49
 
50
/*
51
 * Check for CGA mode.
52
 */
53
_cgastart:
54
	LWI(0x0F00, rAX)		/* get current video mode in AL */
55
	BIOSCALL(0x10)
56
	ANDI(0x007F, rAX)
57
	SUBI(0x0003, rAX)		/* is it mode 3? */
58
	JEQ	_cgamode3
59
 
60
	LWI(0x0003, rAX)		/* turn on text mode 3 */
61
	BIOSCALL(0x10)
62
_cgamode3:
63
	LWI(_hello(SB), rSI)
64
	CALL	_cgaputs(SB)
65
 
66
	LLI(BIOSTABLES, rAX)	/* tables in low memory, not after end */
67
	OPSIZE; ANDL $~(BY2PG-1), AX
68
	OPSIZE; SHRL $4, AX
69
	SW(rAX, _ES(SB))
70
	CLR(rDI)
71
	SW(rDI, _DI(SB))
72
 
73
	MTSR(rAX, rES)
74
 
75
/*
76
 * Check for APM1.2 BIOS support.
77
 */
78
	LWI(0x5304, rAX)		/* disconnect anyone else */
79
	CLR(rBX)
80
	BIOSCALL(0x15)
81
	JCS	_apmfail
82
 
83
	LWI(0x5303, rAX)		/* connect */
84
	CLR(rBX)
85
	CLC
86
	BIOSCALL(0x15)
87
	JCC	_apmpush
88
_apmfail:
89
	LW(_ES(SB), rAX)		/* no support */
90
	MTSR(rAX, rES)
91
	LW(_DI(SB), rDI)
92
	JCS	_apmend
93
 
94
_apmpush:
95
	OPSIZE; PUSHR(rSI)		/* save returned APM data on stack */
96
	OPSIZE; PUSHR(rBX)
97
	PUSHR(rDI)
98
	PUSHR(rDX)
99
	PUSHR(rCX)
100
	PUSHR(rAX)
101
 
102
	LW(_ES(SB), rAX)
103
	MTSR(rAX, rES)
104
	LW(_DI(SB), rDI)
105
 
106
	LWI(0x5041, rAX)		/* first 4 bytes are APM\0 */
107
	STOSW
108
	LWI(0x004D, rAX)
109
	STOSW
110
 
111
	LWI(8, rCX)			/* pop the saved APM data */
112
_apmpop:
113
	POPR(rAX)
114
	STOSW
115
	LOOP	_apmpop
116
_apmend:
117
 
118
/*
119
 * Try to retrieve the 0xE820 memory map.
120
 * This is weird because some BIOS do not seem to preserve
121
 * ES/DI on failure. Consequently they may not be valid
122
 * at _e820end:.
123
 */
124
	SW(rDI, _DI(SB))		/* save DI */
125
	CLR(rAX)			/* write terminator */
126
	STOSW
127
	STOSW
128
 
129
	CLR(rBX)
130
	PUSHR(rBX)			/* keep loop count on stack */
131
					/* BX is the continuation value */
132
_e820loop:
133
	POPR(rAX)
134
	INC(rAX)
135
	PUSHR(rAX)			/* doesn't affect FLAGS */
136
	CMPI(32, rAX)			/* mmap[32+1] in C code */
137
	JGT	_e820pop
138
 
139
	LLI(20, rCX)			/* buffer size */
140
	LLI(0x534D4150, rDX)		/* signature - ASCII "SMAP" */
141
	LLI(0x0000E820, rAX)		/* function code */
142
 
143
	BIOSCALL(0x15)			/* writes 20 bytes at (es,di) */
144
 
145
	JCS	_e820pop		/* some kind of error */
146
	LLI(0x534D4150, rDX)
147
	CMPL(rDX, rAX)			/* verify correct BIOS version */
148
	JNE	_e820pop
149
	LLI(20, rDX)
150
	CMPL(rDX, rCX)			/* verify correct count */
151
	JNE	_e820pop
152
 
153
	SUBI(4, rDI)			/* overwrite terminator */
154
	LWI(0x414D, rAX)		/* first 4 bytes are "MAP\0" */
155
	STOSW
156
	LWI(0x0050, rAX)
157
	STOSW
158
 
159
	ADDI(20, rDI)			/* bump to next entry */
160
 
161
	SW(rDI, _DI(SB))		/* save DI */
162
	CLR(rAX)			/* write terminator */
163
	STOSW
164
	STOSW
165
 
166
	OR(rBX, rBX)			/* zero if last entry */
167
	JNE	_e820loop
168
 
169
_e820pop:
170
	POPR(rAX)			/* loop count */
171
	LW(_DI(SB), rDI)
172
	CLR(rAX)
173
	MTSR(rAX, rES)
174
_e820end:
175
 
176
/*
177
 * 	goto protected mode
178
 */
179
/*	MOVL	loadgdtptr(SB),GDTR /**/
180
	 BYTE	$0x0f
181
	 BYTE	$0x01
182
	 BYTE	$0x16
183
	 WORD	$loadgdtptr(SB)
184
 
185
	DELAY
186
	LWI(1, rAX)
187
	/* MOV AX,MSW */
188
	BYTE $0x0F; BYTE $0x01; BYTE $0xF0
189
 
190
/*
191
 *	clear prefetch queue (weird code to avoid optimizations)
192
 */
193
	DELAY
194
 
195
/*
196
 *	set all segs
197
 */
198
/*	MOVW	$KDSEL,AX	/**/
199
	 BYTE	$0xc7
200
	 BYTE	$0xc0
201
	 WORD	$KDSEL
202
	MOVW	AX,DS
203
	MOVW	AX,SS
204
	MOVW	AX,ES
205
	MOVW	AX,FS
206
	MOVW	AX,GS
207
 
208
	MOVW	$(20*1024*1024-4), SP		/* new stack pointer */
209
	DELAY
210
 
211
	/* god only knows what the damned bios has been up to... */
212
	CLI
213
 
214
	/* jump to C (main) */
215
/*	JMPFAR	KESEL:$main(SB) /**/
216
	 BYTE	$0x66
217
	 BYTE	$0xEA
218
	 LONG	$_main(SB)
219
	 WORD	$KESEL
220
 
221
/* output a cheery wee message (rSI) */
222
TEXT _cgaputs(SB), $0
223
//_cgaputs:
224
	CLR(rBX)
225
_cgaputsloop:
226
	LODSB
227
	ORB(rAL, rAL)
228
	JEQ	_cgaend
229
 
230
	LBI(0x0E,rAH)
231
	BIOSCALL(0x10)
232
	JMP	_cgaputsloop
233
_cgaend:
234
	RET
235
 
236
TEXT _hello(SB), $0
237
	BYTE $'\r'; BYTE $'\n'
238
	BYTE $'9'; BYTE $'b'; BYTE $'o'; BYTE $'o'
239
	BYTE $'t'; BYTE $' '
240
	BYTE $'\z'
241
 
242
/* offset into bios tables using segment ES.  stos? use (es,di) */
243
TEXT _DI(SB), $0
244
	LONG	$0
245
 
246
/* segment address of bios tables (BIOSTABLES >> 4) */
247
TEXT _ES(SB), $0
248
	LONG	$0
249
 
250
/*
251
 *  pointer to initial gdt
252
 */
253
TEXT	loadgdtptr(SB),$0
254
	WORD	$(4*8)
255
	LONG	$loadgdt(SB)
256
 
257
/*
258
 *  gdt to get us to 32-bit/segmented/unpaged mode
259
 */
260
TEXT	loadgdt(SB),$0
261
 
262
	/* null descriptor */
263
	LONG	$0
264
	LONG	$0
265
 
266
	/* data segment descriptor for 4 gigabytes (PL 0) */
267
	LONG	$(0xFFFF)
268
	LONG	$(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
269
 
270
	/* exec segment descriptor for 4 gigabytes (PL 0) */
271
	LONG	$(0xFFFF)
272
	LONG	$(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
273
 
274
	/* exec segment descriptor for 4 gigabytes (PL 0) 16-bit */
275
	LONG	$(0xFFFF)
276
	LONG	$(SEGG|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
277
 
278
/*
279
 *  output a byte
280
 */
281
TEXT	outb(SB),$0
282
	MOVL	p+0(FP),DX
283
	MOVL	b+4(FP),AX
284
	OUTB
285
	RET
286
 
287
/*
288
 *  input a byte
289
 */
290
TEXT	inb(SB),$0
291
	MOVL	p+0(FP),DX
292
	XORL	AX,AX
293
	INB
294
	RET
295
 
296
TEXT mb586(SB), $0
297
	XORL	AX, AX
298
	CPUID
299
	RET
300
 
301
TEXT wbinvd(SB), $0
302
	WBINVD
303
	RET
304
 
305
TEXT	splhi(SB),$0
306
	PUSHFL
307
	POPL	AX
308
	CLI
309
	RET