rev |
line source |
pascal@955
|
1 --- gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
|
pascal@955
|
2 +++ gpxe-0.9.3/src/arch/i386/prefix/lkrnprefix.S
|
pascal@960
|
3 @@ -3,6 +3,7 @@
|
pascal@960
|
4
|
pascal@960
|
5 Authors: Gary Byers (gb@thinguin.org)
|
pascal@960
|
6 Marty Connor (mdc@thinguin.org)
|
pascal@960
|
7 + Pascal Bellard (pascal.bellard@slitaz.org)
|
pascal@960
|
8
|
pascal@960
|
9 This software may be used and distributed according to the terms
|
pascal@960
|
10 of the GNU Public License (GPL), incorporated herein by reference.
|
pascal@960
|
11 @@ -50,40 +51,351 @@
|
pascal@955
|
12 .arch i386
|
pascal@955
|
13 .org 0
|
pascal@955
|
14 .section ".prefix", "ax", @progbits
|
pascal@955
|
15 -/*
|
pascal@955
|
16 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
|
pascal@955
|
17 - a .lilo file is dd'ed to a floppy), print an error message.
|
pascal@955
|
18 -*/
|
pascal@955
|
19
|
pascal@955
|
20 -bootsector:
|
pascal@955
|
21 - jmp $BOOTSEG, $1f /* reload cs:ip to match relocation addr */
|
pascal@955
|
22 -1:
|
pascal@955
|
23 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
|
pascal@955
|
24 - of bootsect + room for stack */
|
pascal@955
|
25 + call here
|
pascal@955
|
26 +here:
|
pascal@955
|
27 + pop %ax
|
pascal@955
|
28 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
|
pascal@955
|
29 + jne bootsector
|
pascal@955
|
30 +
|
pascal@955
|
31 +/* We need a real mode stack that won't be stomped on by Etherboot
|
pascal@955
|
32 + which starts at 0x20000. Choose something that's sufficiently high,
|
pascal@955
|
33 + but not in DOC territory. Note that we couldn't do this in a real
|
pascal@955
|
34 + .com program since stack variables are in the same segment as the
|
pascal@955
|
35 + code and data, but this isn't really a .com program, it just looks
|
pascal@955
|
36 + like one to make DOS load it into memory. It still has the 64kB
|
pascal@955
|
37 + limitation of .com files though. */
|
pascal@955
|
38 +#define STACK_SEG 0x7000
|
pascal@955
|
39 +#define STACK_SIZE 0x4000
|
pascal@955
|
40 + /* Set up temporary stack */
|
pascal@955
|
41 + movw $STACK_SEG, %ax
|
pascal@955
|
42 + movw %ax, %ss
|
pascal@955
|
43 + movw $STACK_SIZE, %sp
|
pascal@955
|
44 +
|
pascal@955
|
45 + /* Calculate segment address of image start */
|
pascal@955
|
46 + pushw %cs
|
pascal@955
|
47 + popw %ax
|
pascal@960
|
48 + addw $(0x100/16), %ax /* Adjust cs */
|
pascal@960
|
49 + pushw %ax
|
pascal@955
|
50 + jmp go_setup_code
|
pascal@955
|
51 +
|
pascal@955
|
52 +bootsector:
|
pascal@955
|
53 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
|
pascal@955
|
54 +go:
|
pascal@955
|
55 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
|
pascal@955
|
56 + /* of bootsect + room for stack + 12 for */
|
pascal@955
|
57 + /* saved disk parm block */
|
pascal@955
|
58
|
pascal@955
|
59 movw $BOOTSEG, %ax
|
pascal@955
|
60 movw %ax,%ds
|
pascal@955
|
61 movw %ax,%es
|
pascal@955
|
62 -
|
pascal@955
|
63 - cli
|
pascal@955
|
64 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
|
pascal@955
|
65 + movw %ax,%ss /* put stack at initial position */
|
pascal@955
|
66 movw %di,%sp
|
pascal@955
|
67 - sti
|
pascal@955
|
68
|
pascal@955
|
69 - movw $why_end-why, %cx
|
pascal@955
|
70 - movw $why, %si
|
pascal@955
|
71 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
|
pascal@955
|
72 + * reads beyond the maximum sector number specified in the default diskette
|
pascal@955
|
73 + * parameter tables - this may mean 7 sectors in some cases.
|
pascal@955
|
74 + *
|
pascal@955
|
75 + * Since single sector reads are slow and out of the question, we must take care
|
pascal@955
|
76 + * of this by creating new parameter tables (for the first disk) in RAM. We
|
pascal@955
|
77 + * will set the maximum sector count to 36 - the most we will encounter on an
|
pascal@955
|
78 + * ED 2.88. High doesn't hurt. Low does.
|
pascal@955
|
79 + *
|
pascal@955
|
80 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
|
pascal@955
|
81 + */
|
pascal@960
|
82 +
|
pascal@955
|
83 + xorw %cx,%cx
|
pascal@955
|
84 + movw %cx,%es /* access segment 0 */
|
pascal@955
|
85 + movw $0x78, %bx /* 0:bx is parameter table address */
|
pascal@955
|
86 + pushw %ds /* save ds */
|
pascal@955
|
87 +/* 0:bx is parameter table address */
|
pascal@955
|
88 + ldsw %es:(%bx),%si /* loads ds and si */
|
pascal@955
|
89 +
|
pascal@955
|
90 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
|
pascal@955
|
91 + movb $6, %cl /* copy 12 bytes */
|
pascal@955
|
92 + cld
|
pascal@955
|
93 + pushw %di /* keep a copy for later */
|
pascal@955
|
94 + rep
|
pascal@955
|
95 + movsw /* ds:si is source, es:di is dest */
|
pascal@955
|
96 + popw %di
|
pascal@955
|
97 +
|
pascal@955
|
98 + movb $36,%es:4(%di)
|
pascal@955
|
99 +
|
pascal@955
|
100 + movw %cx,%ds /* access segment 0 */
|
pascal@955
|
101 + xchgw %di,(%bx)
|
pascal@955
|
102 + movw %es,%si
|
pascal@955
|
103 + xchgw %si,2(%bx)
|
pascal@955
|
104 + popw %ds /* restore ds */
|
pascal@955
|
105 + movw %di, dpoff /* save old parameters */
|
pascal@955
|
106 + movw %si, dpseg /* to restore just before finishing */
|
pascal@955
|
107 + pushw %ds
|
pascal@955
|
108 + popw %es /* reload es */
|
pascal@955
|
109 +
|
pascal@955
|
110 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
|
pascal@955
|
111 +
|
pascal@955
|
112 + xorb %ah,%ah /* reset FDC */
|
pascal@955
|
113 + xorb %dl,%dl
|
pascal@955
|
114 + int $0x13
|
pascal@955
|
115 +
|
pascal@955
|
116 +/* Get disk drive parameters, specifically number of sectors/track.
|
pascal@955
|
117 + *
|
pascal@955
|
118 + * It seems that there is no BIOS call to get the number of sectors. Guess
|
pascal@955
|
119 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
|
pascal@955
|
120 + * 15 if sector 15 can be read. Otherwise guess 9.
|
pascal@955
|
121 + */
|
pascal@960
|
122
|
pascal@960
|
123 - movw $0x0007, %bx /* page 0, attribute 7 (normal) */
|
pascal@960
|
124 - movb $0x0e, %ah /* write char, tty mode */
|
pascal@960
|
125 -prloop:
|
pascal@955
|
126 + movw $disksizes, %si /* table of sizes to try */
|
pascal@955
|
127 +
|
pascal@955
|
128 +probe_loop:
|
pascal@955
|
129 lodsb
|
pascal@955
|
130 + orb %al, %al
|
pascal@955
|
131 + je got_sectors /* if all else fails, try 9 */
|
pascal@955
|
132 + cbtw /* extend to word */
|
pascal@955
|
133 + movw %ax, sectors
|
pascal@955
|
134 + xchgw %cx,%ax /* cx = track and sector */
|
pascal@955
|
135 + xorw %dx,%dx /* drive 0, head 0 */
|
pascal@955
|
136 + movw $0x0200, %bx /* address after boot sector */
|
pascal@955
|
137 + /* (512 bytes from origin, es = cs) */
|
pascal@955
|
138 + movw $0x0201, %ax /* service 2, 1 sector */
|
pascal@955
|
139 + int $0x13
|
pascal@955
|
140 + jc probe_loop /* try next value */
|
pascal@955
|
141 +
|
pascal@955
|
142 +got_sectors:
|
pascal@955
|
143 + movw $msg1end-msg1, %cx
|
pascal@955
|
144 + movw $msg1, %si
|
pascal@955
|
145 + call print_str
|
pascal@955
|
146 +
|
pascal@955
|
147 +/* ok, we've written the Loading... message, now we want to load the system */
|
pascal@955
|
148 +
|
pascal@955
|
149 + movw $SYSSEG, %ax
|
pascal@955
|
150 + movw %ax,%es /* segment of SYSSEG<<4 */
|
pascal@955
|
151 + pushw %es
|
pascal@955
|
152 + call read_it
|
pascal@955
|
153 +
|
pascal@955
|
154 +/* This turns off the floppy drive motor, so that we enter the kernel in a
|
pascal@955
|
155 + * known state, and don't have to worry about it later.
|
pascal@955
|
156 + */
|
pascal@955
|
157 + movw $0x3f2, %dx
|
pascal@955
|
158 + xorb %al,%al
|
pascal@955
|
159 + outb %al,%dx
|
pascal@955
|
160 +
|
pascal@955
|
161 + call print_nl
|
pascal@955
|
162 + pop %es /* = SYSSEG */
|
pascal@955
|
163 +sigok:
|
pascal@955
|
164 +
|
pascal@955
|
165 +/* Restore original disk parameters */
|
pascal@955
|
166 + movw $0x78, %bx
|
pascal@955
|
167 + movw dpoff, %di
|
pascal@955
|
168 + movw dpseg, %si
|
pascal@955
|
169 + xorw %ax,%ax
|
pascal@955
|
170 + movw %ax,%ds
|
pascal@955
|
171 + movw %di,(%bx)
|
pascal@955
|
172 + movw %si,2(%bx)
|
pascal@955
|
173 +
|
pascal@960
|
174 + /* Everything now loaded. %es = SYSSEG, so %es:0000 points to
|
pascal@960
|
175 + * start of loaded image.
|
pascal@960
|
176 + */
|
pascal@955
|
177 +
|
pascal@960
|
178 + /* Jump to loaded copy */
|
pascal@960
|
179 + ljmp $SYSSEG, $run_etherboot
|
pascal@955
|
180 +
|
pascal@960
|
181 +endseg: .word SYSSEG + _load_size_pgh
|
pascal@960
|
182 + .section ".zinfo.fixup", "a" /* Compressor fixup information */
|
pascal@960
|
183 + .ascii "SUBW"
|
pascal@960
|
184 + .long endseg
|
pascal@960
|
185 + .long 16
|
pascal@960
|
186 + .long 0
|
pascal@960
|
187 + .previous
|
pascal@960
|
188 +
|
pascal@955
|
189 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
|
pascal@955
|
190 + * boundaries are crossed. We try to load it as fast as possible, loading whole
|
pascal@955
|
191 + * tracks whenever we can.
|
pascal@955
|
192 + *
|
pascal@955
|
193 + * in: es - starting address segment (normally SYSSEG)
|
pascal@955
|
194 + */
|
pascal@955
|
195 +read_it:
|
pascal@955
|
196 + movw $0,sread /* read whole image incl boot sector */
|
pascal@955
|
197 + movw %es,%ax
|
pascal@955
|
198 + testw $0x0fff, %ax
|
pascal@955
|
199 +die: jne die /* es must be at 64kB boundary */
|
pascal@955
|
200 + xorw %bx,%bx /* bx is starting address within segment */
|
pascal@955
|
201 +rp_read:
|
pascal@955
|
202 + movw %es,%ax
|
pascal@955
|
203 + movw %bx,%dx
|
pascal@955
|
204 + movb $4, %cl
|
pascal@955
|
205 + shrw %cl,%dx /* bx is always divisible by 16 */
|
pascal@955
|
206 + addw %dx,%ax
|
pascal@960
|
207 + cmpw syssize, %ax /* have we loaded all yet? */
|
pascal@955
|
208 + jb ok1_read
|
pascal@955
|
209 + ret
|
pascal@955
|
210 +ok1_read:
|
pascal@955
|
211 + movw sectors, %ax
|
pascal@955
|
212 + subw sread, %ax
|
pascal@955
|
213 + movw %ax,%cx
|
pascal@955
|
214 + shlw $9, %cx /* 80186 opcode */
|
pascal@955
|
215 + addw %bx,%cx
|
pascal@955
|
216 + jnc ok2_read
|
pascal@955
|
217 + je ok2_read
|
pascal@955
|
218 + xorw %ax,%ax
|
pascal@955
|
219 + subw %bx,%ax
|
pascal@955
|
220 + shrw $9, %ax /* 80186 opcode */
|
pascal@955
|
221 +ok2_read:
|
pascal@955
|
222 + call read_track
|
pascal@955
|
223 + movw %ax,%cx
|
pascal@955
|
224 + addw sread, %ax
|
pascal@955
|
225 + cmpw sectors, %ax
|
pascal@955
|
226 + jne ok3_read
|
pascal@955
|
227 + movw $1, %ax
|
pascal@955
|
228 + subw head, %ax
|
pascal@955
|
229 + jne ok4_read
|
pascal@955
|
230 + incw track
|
pascal@955
|
231 +ok4_read:
|
pascal@955
|
232 + movw %ax, head
|
pascal@955
|
233 + xorw %ax,%ax
|
pascal@955
|
234 +ok3_read:
|
pascal@955
|
235 + movw %ax, sread
|
pascal@955
|
236 + shlw $9, %cx /* 80186 opcode */
|
pascal@955
|
237 + addw %cx,%bx
|
pascal@955
|
238 + jnc rp_read
|
pascal@955
|
239 + movw %es,%ax
|
pascal@955
|
240 + addb $0x10, %ah
|
pascal@955
|
241 + movw %ax,%es
|
pascal@955
|
242 + xorw %bx,%bx
|
pascal@955
|
243 + jmp rp_read
|
pascal@955
|
244 +
|
pascal@955
|
245 +read_track:
|
pascal@955
|
246 + pusha /* 80186 opcode */
|
pascal@955
|
247 + pushw %ax
|
pascal@955
|
248 + pushw %bx
|
pascal@955
|
249 + pushw %bp /* just in case the BIOS is buggy */
|
pascal@955
|
250 + movb $0x2e, %al /* 0x2e = . */
|
pascal@955
|
251 + call print_char
|
pascal@955
|
252 + popw %bp
|
pascal@955
|
253 + popw %bx
|
pascal@955
|
254 + popw %ax
|
pascal@955
|
255 +
|
pascal@955
|
256 + movw sread, %cx
|
pascal@955
|
257 + incw %cx
|
pascal@955
|
258 + movb track, %ch
|
pascal@955
|
259 + movw $0x0100, %dx
|
pascal@955
|
260 + andb head, %dh
|
pascal@955
|
261 + movb $2, %ah
|
pascal@955
|
262 +
|
pascal@955
|
263 + pushw %dx /* save for error dump */
|
pascal@955
|
264 + pushw %cx
|
pascal@955
|
265 + pushw %bx
|
pascal@955
|
266 + pushw %ax
|
pascal@955
|
267 +
|
pascal@955
|
268 + int $0x13
|
pascal@955
|
269 + jc bad_rt
|
pascal@955
|
270 + addw $8, %sp
|
pascal@955
|
271 + popa /* 80186 opcode */
|
pascal@955
|
272 + ret
|
pascal@955
|
273 +
|
pascal@955
|
274 +bad_rt: pushw %ax /* save error code */
|
pascal@955
|
275 + call print_all /* ah = error, al = read */
|
pascal@955
|
276 +
|
pascal@955
|
277 + xorb %ah,%ah
|
pascal@955
|
278 + xorb %dl,%dl
|
pascal@955
|
279 + int $0x13
|
pascal@955
|
280 +
|
pascal@955
|
281 + addw $10, %sp
|
pascal@955
|
282 + popa /* 80186 opcode */
|
pascal@955
|
283 + jmp read_track
|
pascal@955
|
284 +
|
pascal@955
|
285 +/* print_all is for debugging purposes. It will print out all of the registers.
|
pascal@955
|
286 + * The assumption is that this is called from a routine, with a stack frame like
|
pascal@955
|
287 + * dx
|
pascal@955
|
288 + * cx
|
pascal@955
|
289 + * bx
|
pascal@955
|
290 + * ax
|
pascal@955
|
291 + * error
|
pascal@955
|
292 + * ret <- sp
|
pascal@955
|
293 + */
|
pascal@955
|
294 +
|
pascal@955
|
295 +print_all:
|
pascal@955
|
296 + call print_nl /* nl for readability */
|
pascal@955
|
297 + /* print_nl update ah and bx */
|
pascal@955
|
298 + movw $5, %cx /* error code + 4 registers */
|
pascal@955
|
299 + movw %sp,%bp
|
pascal@955
|
300 +
|
pascal@955
|
301 +print_loop:
|
pascal@955
|
302 + pushw %cx /* save count left */
|
pascal@955
|
303 +
|
pascal@955
|
304 + cmpb $5, %cl
|
pascal@955
|
305 + jae no_reg /* see if register name is needed */
|
pascal@955
|
306 +
|
pascal@955
|
307 + movb $0x5+0x41-1, %al
|
pascal@955
|
308 + subb %cl,%al
|
pascal@955
|
309 + int $0x10
|
pascal@955
|
310 +
|
pascal@955
|
311 + movb $0x58, %al /* 'X' */
|
pascal@955
|
312 int $0x10
|
pascal@955
|
313 +
|
pascal@955
|
314 + movb $0x3A, %al /* ':' */
|
pascal@955
|
315 + int $0x10
|
pascal@955
|
316 +
|
pascal@955
|
317 +no_reg:
|
pascal@955
|
318 + addw $2, %bp /* next register */
|
pascal@955
|
319 + call print_hex /* print it */
|
pascal@955
|
320 + movb $0x20, %al /* print a space */
|
pascal@955
|
321 + int $0x10
|
pascal@955
|
322 + popw %cx
|
pascal@955
|
323 + loop print_loop
|
pascal@955
|
324 + /* nl for readability */
|
pascal@955
|
325 +print_nl:
|
pascal@955
|
326 + movb $0xd, %al /* CR */
|
pascal@955
|
327 + call print_char
|
pascal@955
|
328 + movb $0xa, %al /* LF */
|
pascal@955
|
329 + jmp print_char
|
pascal@955
|
330 +
|
pascal@955
|
331 +
|
pascal@955
|
332 +print_str:
|
pascal@955
|
333 +prloop:
|
pascal@955
|
334 + lodsb
|
pascal@955
|
335 + call print_char
|
pascal@955
|
336 loop prloop
|
pascal@955
|
337 -freeze: jmp freeze
|
pascal@955
|
338 + ret
|
pascal@960
|
339
|
pascal@960
|
340 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
|
pascal@960
|
341 -why_end:
|
pascal@955
|
342 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
|
pascal@960
|
343
|
pascal@955
|
344 +print_hex:
|
pascal@955
|
345 + movw (%bp),%dx /* load word into dx */
|
pascal@955
|
346 + movb $4, %cl
|
pascal@955
|
347 + call print_2digits
|
pascal@955
|
348 +print_2digits:
|
pascal@955
|
349 + call print_digit
|
pascal@955
|
350 +/* fall through */
|
pascal@955
|
351 +print_digit:
|
pascal@955
|
352 + rol %cl,%dx /* rotate to use lowest 4 bits */
|
pascal@955
|
353 + movb $0x0f, %al /* mask for nybble */
|
pascal@955
|
354 + andb %dl,%al
|
pascal@955
|
355 + addb $0x90, %al /* convert al to ascii hex */
|
pascal@955
|
356 + daa /* (four instructions) */
|
pascal@955
|
357 + adcb $0x40, %al
|
pascal@955
|
358 + daa
|
pascal@955
|
359 +print_char:
|
pascal@955
|
360 + movb $0x0e, %ah /* write char, tty mode */
|
pascal@955
|
361 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
|
pascal@955
|
362 + int $0x10
|
pascal@955
|
363 + ret
|
pascal@955
|
364 +
|
pascal@955
|
365 +sread: .word 0 /* sectors read of current track */
|
pascal@955
|
366 +head: .word 0 /* current head */
|
pascal@955
|
367 +track: .word 0 /* current track */
|
pascal@955
|
368 +
|
pascal@955
|
369 +sectors:
|
pascal@955
|
370 + .word 0
|
pascal@960
|
371 +
|
pascal@955
|
372 +dpseg: .word 0
|
pascal@955
|
373 +dpoff: .word 0
|
pascal@960
|
374 +
|
pascal@955
|
375 +disksizes:
|
pascal@955
|
376 + .byte 36,18,15,9,0
|
pascal@955
|
377 +
|
pascal@955
|
378 +msg1:
|
pascal@955
|
379 + .ascii "Loading ROM image"
|
pascal@955
|
380 +msg1end:
|
pascal@955
|
381
|
pascal@955
|
382 .org 497
|
pascal@955
|
383 setup_sects:
|
pascal@960
|
384 @@ -106,13 +418,6 @@
|
pascal@960
|
385
|
pascal@960
|
386 .org 512
|
pascal@960
|
387
|
pascal@960
|
388 - .section ".zinfo.fixup", "a" /* Compressor fixup information */
|
pascal@960
|
389 - .ascii "SUBW"
|
pascal@960
|
390 - .long syssize
|
pascal@960
|
391 - .long 16
|
pascal@960
|
392 - .long 0
|
pascal@960
|
393 - .previous
|
pascal@960
|
394 -
|
pascal@960
|
395 /*
|
pascal@960
|
396 We're now at the beginning of the second sector of the image -
|
pascal@960
|
397 where the setup code goes.
|
pascal@960
|
398 @@ -123,14 +428,18 @@
|
pascal@955
|
399 executing the Etherboot image that's loaded at SYSSEG:0 and
|
pascal@955
|
400 whose entry point is SYSSEG:0.
|
pascal@955
|
401 */
|
pascal@955
|
402 -setup_code:
|
pascal@955
|
403 +setup_code:
|
pascal@960
|
404 + pushw $(SYSSEG-(PREFIXSIZE/16))
|
pascal@955
|
405 /* Etherboot expects to be contiguous in memory once loaded.
|
pascal@955
|
406 * LILO doesn't do this, but since we don't need any
|
pascal@955
|
407 * information that's left in the prefix, it doesn't matter:
|
pascal@955
|
408 * we just have to ensure that %cs:0000 is where the start of
|
pascal@955
|
409 * the Etherboot image *would* be.
|
pascal@955
|
410 */
|
pascal@955
|
411 - ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_etherboot
|
pascal@955
|
412 +go_setup_code:
|
pascal@955
|
413 + pushw $run_etherboot
|
pascal@955
|
414 + /* Calculated lcall to _start with %cs:0000 = image start */
|
pascal@955
|
415 + lret
|
pascal@955
|
416
|
pascal@955
|
417
|
pascal@955
|
418 .org PREFIXSIZE
|
pascal@960
|
419 @@ -140,6 +449,10 @@
|
pascal@960
|
420 run_etherboot:
|
pascal@960
|
421 call install
|
pascal@960
|
422
|
pascal@960
|
423 + /* Set up real-mode stack */
|
pascal@960
|
424 + movw %bx, %ss
|
pascal@960
|
425 + movw $_estack16, %sp
|
pascal@960
|
426 +
|
pascal@960
|
427 /* Jump to .text16 segment */
|
pascal@960
|
428 pushw %ax
|
pascal@960
|
429 pushw $1f
|