wok-current view memtest/stuff/bootloader.S @ rev 15205
hg merge
author | Aleksej Bobylev <al.bobylev@gmail.com> |
---|---|
date | Mon Sep 09 03:32:26 2013 +0300 (2013-09-09) |
parents | |
children | d9dd83ccc85f |
line source
1 SYSSEG = 0x1000
2 INITSEG = 0x9000
3 SETUPSEG = 0x9020
5 setup_sects = 497
6 syssize = 500
8 .text
9 .code16
10 .org 0
11 .globl _start
12 _start:
14 #define CODESZ 512
16 /* some extra features */
17 #define EXE_SUPPORT real mode dos .exe file support
18 #define CMDLINE 0x9E00
19 #define HELP store help message for /? argument
20 #define CHECK_REALMODE does not support vm86
22 /* some contraints to reduce the size */
23 //#define FLOPPY_1440K_ONLY 1.44M floppies support only
24 #define NO_CURSOR_DEFINITION
26 #ifdef EXE_SUPPORT
27 #define EXEADRS(x) x+0xE0
28 stacktop = 0x9E00 # in 0x8000 .. 0xA000
29 decw %bp // Magic number: MZ
30 popw %dx
31 jmp start // Bytes on last page of file
32 .word (CODESZ+511)/512 // Pages in file
33 .word 0 // Relocations
34 .word (end_header-_start)/16 // Size of header in paragraphs
35 .word 4096 // Minimum extra paragraphs needed
36 .word -1 // Maximum extra paragraphs needed
37 .word (CODESZ+15)/16 // Initial (relative) SS value
38 .word stacktop // Initial SP value
39 .word 0 // Checksum
40 .word EXEADRS(comstart) // Initial IP value
41 .word 0xFFF0 // Initial (relative) CS value
42 // .word 0x001C // File address of relocation table
43 // .word 0,0,0 // Overlay number
44 .ascii "(SliTaz)"
45 end_header:
46 comstart:
47 #ifdef CMDLINE
48 .word 0xA33A // CMP AH,[BP+DI+stacktop]
49 .word stacktop
50 #else
51 #undef HELP
52 #endif
53 cld # assume nothing
54 pushw $INITSEG
55 popw %es
56 #ifdef CMDLINE
57 movw %sp, %di
58 movw $0x80, %si
59 lodsb
60 cbw
61 xchgw %ax, %cx
62 jcxz nocmdline
63 movb $0x3F, 0x7F(%si)
64 skipspace:
65 lodsb
66 cmpb $0x20, %al
67 je skipspace
68 decw %si
69 rep
70 movsb
71 # ifdef HELP
72 # define PUTS
73 movw $EXEADRS(helpmsg), %si
74 cmpb $'/', %al
75 je puts
76 # endif
77 nocmdline:
78 #endif
79 #ifdef CHECK_REALMODE
80 #define PUTS
81 movw $EXEADRS(realmode_expected), %si
82 pushfw // save flags
83 // bits 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
84 // flags 0 NT IOPL OF DF IF TF SF ZF 0 AF 0 PF 1 CF
85 movb $0x10, %ah // DF = IF = TF = 0
86 pushw %ax
87 popfw // < 286 : flags[12..15] are forced 1
88 pushfw // = 286 : flags[12..15] are forced 0
89 popw %cx // > 286 : only flags[15] is forced 0
90 popfw // restore flags
91 addb %ah, %ch // test F0 and 00 cases
92 cmpb %ah, %ch
93 jbe puts // C=8086/80186, Z=80286
94 smsww %ax
95 andb $1, %al
96 jne puts
97 #endif
98 movw $0x100, %si
99 movw $end_header, %di
100 movb EXEADRS(setup_sects), %ch
101 movb $(512-(end_header-_start))/2, %cl
102 rep
103 movsw
104 ljmp $INITSEG, $movesys
105 start:
106 pushw %dx
107 xorw %dx, %dx
108 #else
109 #undef HELP
110 #undef CMDLINE
111 #undef CHECK_REALMODE
112 #endif
113 cld # assume nothing
114 stacktop = 0x9E00 # in 0x8000 .. 0xA000
115 zeroed = 12 # zeroed registers
116 movw $stacktop-12-zeroed, %di # stacktop is an arbitrary value >=
117 # length of bootsect + length of
118 # setup + room for stack;
119 # 12 is disk parm size.
120 pushw $INITSEG
121 popw %ss # %ss contain INITSEG
122 movw %di, %sp # put stack at INITSEG:stacktop-...
124 # Many BIOS's default disk parameter tables will not recognize
125 # multi-sector reads beyond the maximum sector number specified
126 # in the default diskette parameter tables - this may mean 7
127 # sectors in some cases.
128 #
129 # Since single sector reads are slow and out of the question,
130 # we must take care of this by creating new parameter tables
131 # (for the first disk) in RAM. We can set the maximum sector
132 # count to 36 - the most we will encounter on an ED 2.88.
133 #
134 # High doesn't hurt. Low does. Let's use the max: 63
136 pushw %ss
137 popw %es # %es = %ss = INITSEG
138 xorw %ax, %ax # %ax = 0
139 movw $zeroed/2, %cx # clear gdt + offset, %ds, limits
140 rep # don't worry about cld
141 stosw # already done above
142 popw %bx # offset = 0
143 popw %ds # %ds = 0
144 popw %fs # %fs = 0
146 movb setup_sects+0x7C00, %al # read bootsector + setup (%ds = 0)
147 incw %ax
149 ldsw 0x78(%bx), %si # %ds:%bx+0x78 is parameter table address
150 pushw %es
151 pushw %di
152 movb $6, %cl # copy 12 bytes
153 rep # don't worry about cld
154 movsw # already done above
155 pushw %ss
156 popw %ds # now %ds = %es = %ss = INITSEG
157 popl %fs:0x78(%bx) # update parameter table address
158 movb $63, 0x4-12(%di) # patch sector count, %di = stacktop
159 cli
161 xchg %ax, %di # sector count
162 popw %ax # limits = 0
163 incw %cx # cylinder 0, sector 1, clear Z
164 call read_first_sectors # read setup
166 # This routine loads the system at address LOADSEG, making sure
167 # no 64kB boundaries are crossed. We try to load it as fast as
168 # possible, loading whole tracks whenever we can.
170 popw %bx # clear %bx
171 movw syssize, %di
172 addw $(512/16)-1, %di
173 shrw $9-4, %di
174 movw $SYSSEG, %cx
175 call read_sectorsCX
177 # This procedure turns off the floppy drive motor, so
178 # that we enter the kernel in a known state, and
179 # don't have to worry about it later.
181 kill_motor:
182 xchgw %ax, %di # reset FDC (%di < 128)
183 int $0x13
185 # After that (everything loaded), we jump to the setup-routine
186 # loaded directly after the bootblock:
187 # Segments are as follows: %ds = %ss = INITSEG
189 jmp_setup:
190 ljmp $SETUPSEG, $0
192 #ifdef PUTS
193 #define PUTC
194 puts:
195 lodsb
196 orb %al, %al
197 je exit
198 call putc
199 jmp puts
200 #endif
201 #ifdef EXE_SUPPORT
202 movesys:
203 pushw %es
204 popw %ss
205 movw EXEADRS(syssize), %bp // %ds untouched
206 movw $SYSSEG, %ax
207 movw %ds, %bx
208 cwd
209 incw %dx
210 cmpw %ax, %bx
211 jnc forward
212 negw %dx
213 addw %bp, %ax
214 addw %bp, %bx
215 forward:
216 movw %ax, %es
217 movw %bx, %ds
218 xorw %di, %di
219 movb $8, %cl
220 rep
221 movsw
222 subw $16, %si
223 addw %dx, %ax
224 addw %dx, %bx
225 decw %bp
226 jns forward
227 #ifndef NO_CURSOR_DEFINITION
228 movb $1, %ah
229 movb $0, %bh
230 movb $0x20, %ch // 0x2000
231 int $0x10
232 #endif
233 pushw %ss
234 popw %ds
235 jmp jmp_setup
236 #endif
237 putcdot:
238 #ifdef PUTC
239 movb $0x2E, %al
240 putc:
241 movb $0xE, %ah
242 movw $7, %bx
243 int $0x10
244 #endif
245 exit:
246 ret
249 # read_sectors reads %di sectors into %es:0 buffer.
250 # %es:0 is updated to the next memory location.
251 # First, sectors are read sector by sector until
252 # sector per track count is known. Then they are
253 # read track by track.
254 # Assume no error on first track.
256 #ifdef FLOPPY_1440K_ONLY
257 #define FLOPPY_HEADS 2 /* 2 heads */
258 #define FLOPPY_SECTORS 18 /* 18 sectors */
259 #else
260 #define FLOPPY_HEADS 2 /* 2 heads minimum */
261 #define FLOPPY_SECTORS 9 /* 9 sectors minimum */
262 #endif
264 check_limits:
265 #ifndef FLOPPY_1440K_ONLY
266 popw %dx
267 #ifdef FLOPPY_SECTORS
268 cmpb $FLOPPY_SECTORS+1, %cl # minimum sector count
269 jb check_head
270 #endif
271 cmpb %al, %cl # max sector known ?
272 ja next_head # no -> store it
273 check_head:
274 #ifdef FLOPPY_HEADS
275 cmpb $FLOPPY_HEADS, %dh # 2 heads minimum
276 jb check_cylinder
277 #endif
278 cmpb %ah, %dh # max head known ?
279 ja next_cylinder # no -> store it
280 check_cylinder:
281 #endif
282 pushaw
283 #ifndef FLOPPY_1440K_ONLY
284 cbw # %ah = 0
285 #endif
286 int $0x13 # reset controler
287 popaw
288 movb $1, %al # sector by sector...
289 read_sectorslp:
290 pushw %dx # some bios break dx...
291 #ifndef FLOPPY_1440K_ONLY
292 pushw %ax # limits
293 subb %cl, %al # sectors remaining in track
294 ja tolastsect
295 movb $1, %al # 1 sector mini
296 tolastsect:
297 #else
298 mov $FLOPPY_SECTORS+1, %al
299 subb %cl, %al # sectors remaining in track
300 #endif
301 cbw
302 cmpw %di, %ax
303 jb more1trk
304 movw %di, %ax # sectors to read
305 more1trk:
306 pushw %ax # save context
307 movb $2, %ah # cmd: read chs
308 int $0x13
309 #ifndef FLOPPY_1440K_ONLY
310 popw %dx # save %ax
311 popw %ax # limits
312 #else
313 popw %ax # restore context
314 popw %dx
315 #endif
316 jc check_limits
317 #ifndef FLOPPY_1440K_ONLY
318 xchgw %ax, %bp
319 addw %dx,%cx # next sector
320 movw %cx, %gs
321 movw %es, %cx
322 pushw %dx
323 shlw $5, %dx
324 addw %dx, %cx
325 popw %dx
326 subw %dx,%di # update sector counter
327 popw %dx
328 read_sectorsCX:
329 movw %cx, %es # next location
330 jz putcdot
331 #else
332 addw %ax,%cx # next sector
333 movw %cx, %gs
334 movw %es, %cx
335 pushw %ax
336 shlw $5, %ax
337 addw %ax, %cx
338 popw %ax
339 subw %ax,%di # update sector counter
340 read_sectorsCX:
341 movw %cx, %es # next location
342 jz putcdot
343 #endif
344 read_sectors:
345 movw %gs, %cx
346 #ifndef FLOPPY_1440K_ONLY
347 # al is last sector+1
348 # ah is last cylinder+1
349 xchgw %ax, %bp
350 #endif
351 #ifndef FLOPPY_1440K_ONLY
352 cmpb %al,%cl # reach sector limit ?
353 jne bdendlp
354 next_head:
355 movb %cl,%al
356 #else
357 cmpb $FLOPPY_SECTORS+1,%cl # reach sector limit ?
358 jne bdendlp
359 #endif
360 incb %dh # next head
361 movb $1,%cl # first sector
362 #ifndef FLOPPY_1440K_ONLY
363 cmpb %ah, %dh # reach head limit ?
364 jne bdendlp
365 next_cylinder:
366 movb %dh,%ah
367 #else
368 cmpb %cl,%dh # reach head limit ?
369 je bdendlp
370 #endif
371 # NOTE : support 256 cylinders max
372 incb %ch # next cylinder
373 read_first_sectors:
374 movb $0,%dh # first head
375 bdendlp:
376 jmp read_sectorslp
378 #ifdef CHECK_REALMODE
379 realmode_expected:
380 .ascii "386 real mode only."
381 .byte 13,10,0
382 #endif
383 #ifdef HELP
384 helpmsg:
385 .ascii "No help available."
386 .byte 13,10
387 .byte 0
388 #endif
389 .org 497