|
|
1.1 root 1: .unixorder
2: .llen 132
3: .include as.inc
4:
5: IODELAY .macro
6: jmp .+2 / DELAY
7: jmp .+2 / DELAY
8: .endm
9:
10: / Most places where %cr3 is refreshed, it can be done through a Ring 0 gate.
11: MMUUPD .macro
12: pushfl
13: cli
14: lcall $SEG_MMUUPD,$0 / gate to mmuupdfR0
15: popfl
16: .endm
17:
18: /
19: / USTART and ESP_START map kernel stack and u area within top 4k page
20: / of virtual space.
21: / NDP context starts 0x100 bytes below u area.
22: / See also U_OFFSET, NDP_OFFSET in uproc.h
23: /
24: .set USTART,0xFFFFFB00
25: .set ESP0_START,0xFFFFF300
26: .set ESP1_START,USTART
27:
28: .set u,USTART
29: .set PSW_VAL,0x1200 / set system IOPL to 1, enable IRQ
30: / .set PSW_VAL,0x3200 / set system IOPL to 3, enable IRQ
31:
32: / (lgl-
33: / The information contained herein is a trade secret of Mark Williams
34: / Company, and is confidential information. It is provided under a
35: / license agreement, and may be copied or disclosed only under the
36: / terms of that agreement. Any reproduction or disclosure of this
37: / material without the express written authorization of Mark Williams
38: / Company or persuant to the license agreement is unlawful.
39:
40: / Copyright (c) 1982, 1992.
41: / An unpublished work by Mark Williams Company, Chicago.
42: / All rights reserved.
43:
44: / Intel 386 port and extensions
45: / Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
46: / -lgl)
47: /
48: / $Log: as.s,v $
49: / Revision 2.3 93/07/26 13:55:44 nigel
50: / Nigel's R80
51: /
52: / Revision 1.17 92/12/08 16:43:10 root
53: / ker 70
54: /
55: / Revision 1.16 92/11/12 10:04:31 root
56: / Ker #68
57: /
58: / Revision 1.15 92/11/09 17:08:28 root
59: / Just before adding vio segs.
60: /
61: / Revision 1.13 92/10/06 23:47:48 root
62: / Ker #64
63: /
64: / Revision 1.12 92/10/06 20:45:40 root
65: / Ker #63d
66: /
67: / Revision 1.10 92/07/27 18:15:43 hal
68: / Kernel #59
69: /
70: / Revision 1.9 92/07/16 16:38:14 hal
71: / Kernel #58
72: /
73: / Revision 1.8 92/07/15 13:50:55 root
74: / COH 4.0.0
75: /
76: / Revision 1.6 92/04/03 11:05:28 hal
77: / Fix missed IRQ bug.
78: / Add read_t0(), read_psw(), getusd(), putusd().
79: /
80:
81: ///////
82: / Machine language assist for
83: / Intel 80386/80486 Coherent. This contains the parts
84: / that are common to all machines as well as the machine-specific code
85: / for the IBM PC-386
86:
87:
88: ///////
89:
90: / System entry point.
91:
92: / When this code is entered, the boot program has done the following:
93: / Relocate itself above where the kernel will be (e.g., 0x20600).
94: / Load as.s binary; text at 0x02000, data at next paragraph (16-byte)
95: / boundary at or beyond end of kernel text.
96: / CS = 0x02000 <- start of kernel text ("physical" stext)
97: / ES = 0x02xxx <- start of kernel data
98: / SS,DS = 0x20xxx <- ....some address in boot data space....
99:
100: / Due to the way the kernel has been linked (see ld.master), symbol "stext"
101: / has a value of 0xFFC0_0000, which is the start of the last 4 meg segment.
102: / This value is the address in linear space once we have entered paging mode,
103: / but until that time relocation arithmetic is necessary:
104: /
105: / Before segmentation is turned on, symbols in kernel text or data space
106: / must be relocated by -SBASE<<BPCSHIFT for memory reference instructions
107: / to work.
108:
109: ///////
110:
111: stext: / kernel code starts at stext+0x100
112: .org .+0x100 / reserve stack space
113: cli / No interrupts, please.
114:
115: / put up a debugging "!" on the screen. We can still use the BIOS.
116: push %si / Save registers.
117: push %di
118:
119: movb $'!', %al
120:
121: movw $0x0007, %bx / Page 0, white on black
122: movb $0x0E, %ah / Write TTY.
123: int $VIDEO / Call video I/O in ROM.
124: pop %di
125: pop %si
126:
127: / equipment status word to AX
128: int $0x11 / Obtain int 11 value before printf().
129: movl %eax,%ecx / esw -> cx
130:
131: / val11 is a long, initially zero, in the CS.
132: / copy (long)esw to val11
133: .byte PX_ADDR / 32-bit address
134: .byte PX_OPND / 32-bit operand
135: movl %ecx,%cs:[[-SBASE]<<BPCSHIFT]+val11
136:
137: / last use of boot block's stack
138: .byte PX_ADDR / 32-bit address
139: .byte PX_OPND / 32-bit operand
140: lgdtl %cs:[[-SBASE]<<BPCSHIFT]+gdtinit
141:
142: / turn on lsbit of cr0 - Protection Enable
143: mov %cr0,%eax
144: orb $1,%al
145: mov %eax,%cr0
146:
147: / intersegment jump (48-bit address)
148: / jumping flushes the cache...
149: /
150: .byte PX_OPND
151: ljmp $SEG_386_II, $next
152:
153: next:
154: movw $SEG_386_ID, %ax
155: movw %ax, %ds
156: movw %ax, %es
157: movw %ax, %ss
158: movw $SEG_386_UD|R_USR, %ax
159: movw %ax, %fs
160: mov $stext+0x100,%eax / 256 byte stack for initialization
161: mov %eax,%esp
162:
163: / Enable the A20 address line, which is normally disabled by the ROM BIOS.
164: / This line is under the control of the 8042 keyboard interface controller.
165:
166: sub %ecx, %ecx
167: loc0: inb $KBCTRL / Wait for 8042 input buffer to empty.
168: testb $2,%al
169: loopne loc0
170: IODELAY
171:
172: movb $0xD1, %al / Request next output byte to be
173: outb $KBCTRL / sent to the 8042 output port.
174: IODELAY
175:
176: sub %ecx, %ecx
177: loc1: inb $KBCTRL / Wait for 8042 input buffer to empty.
178: testb $2, %al
179: loopne loc1
180: IODELAY
181:
182: movb $0xDF,%al / Enable A20 address line.
183: outb $KBDATA / See Page 1-44, IBM-AT Tech Ref.
184: IODELAY
185:
186: sub %ecx, %ecx
187: loc2: inb $KBCTRL / Wait for 8042 input buffer to empty.
188: testb $2,%al / NOTE: A20 not enabled for up to 20 us.
189: loopne loc2
190:
191:
192: / Reprogram the 8253 timer so that channel 0,
193: / which is used as the clock, interrupts at exactly
194: / 100 HZ, instead of 18.2 HZ.
195:
196: movb $0x36,%al / Timer 0, LSB, MSB, mode 3
197: outb $PIT+3
198: IODELAY
199: movb $0x9C,%al / Lsb of 59659/5 = 11932
200: outb $PIT
201: IODELAY
202: movb $0x2E,%al / Msb of 59659/5 = 11932
203: outb $PIT
204: IODELAY
205:
206: / Reprogram the 1st programmable interrupt controller.
207: / Its default vector table collides with iAPX 286 protection vectors.
208: movb $0x11,%al / ICW1 - edge, ICW4
209: outb $PIC
210: IODELAY
211: movb $0x20,%al / ICW2 - Reserve 1st 32 vectors for 286
212: outb $PICM
213: IODELAY
214: movb $0x04,%al / ICW3 - master level 2
215: outb $PICM
216: IODELAY
217: movb $0x01,%al / ICW4 - 8086 mode, master.
218: outb $PICM
219: IODELAY
220:
221: / NIGEL: The original code here (and related code in "i386/md.c") turned off
222: / the chain bit in the first PIC by default (and at every subsequent
223: / opportunity) even though all the mask bits in the slave PIC are set to off.
224: / In order to support an enhanced interrupt architecture for the STREAMS and
225: / DDI/DDK subsystems I want to remove the state knowledge from the code in
226: / "i386/md.c" so that the chain bit is always left on.
227: / In order to do this, I have modified the startup code below so that the
228: / system by default allows the slave PIC to interrupt (of course, it still
229: / won't interrupt unless it is enabled to; the masking I have removed was
230: / totally redundant).
231:
232: movb $0xFA,%al / Disable interrupts from master PIC.
233: outb $PICM / (except for clock and slave PIC interrupt).
234:
235: movb $0x11,%al / ICW1 - edge, ICW4
236: outb $SPIC
237: IODELAY
238: movb $0x70,%al / ICW2 - slave starts at 0x70th interrupt
239: outb $SPICM
240: IODELAY
241: movb $0x02,%al / ICW3 - master level 2
242: outb $SPICM
243: IODELAY
244: movb $0x01,%al / ICW4 - 8086 mode.
245: outb $SPICM
246: IODELAY
247: movb $0xFF,%al
248: outb $SPICM / Disable interrupts from slave PIC.
249: /DEBUG
250: xor %ebp, %ebp / Halt stack backtraces
251: cli
252: call __cinit
253: call mchinit / C initialization
254: mov %cr0,%eax / Turn on paging
255: / use 80000001 to allow FP
256: / or $0x80000001,%eax
257: / use 80000005 to disallow FP
258: or $0x80000005,%eax
259: mov %eax,%cr0
260: ljmp $SEG_RNG0_TXT,$loc3 / clear pipeline; jump far, direct
261:
262: /
263: / Ring 0 startup code
264: /
265: loc3:
266: movw $SEG_386_KD, %ax
267: movw %ax, %ds
268: movw $SEG_RNG0_STK, %ax
269: movw %ax, %ss
270: movl $ESP0_START,%esp / Stack pointer for init
271: clts / Clear task switched flag.
272:
273: / Call the machine setup code.
274: / Call Coherent main.
275: / On return, send control off to the user
276: / at its entry point.
277:
278: sub %eax, %eax / Load local descriptor table register.
279: lldt %ax
280:
281: / movw $tss,%ax / Fix low 16 bits of tss base in gdt
282: / movw %ax,gdt+SEG_TSS+2
283:
284: / Fix tss base in gdt
285: movl $tss,%eax
286: movw %ax,gdt+SEG_TSS+2 / Fix bits 0..15
287: rorl $16,%eax / Get tss bits 16..31
288: movb %al,gdt+SEG_TSS+4 / Fix bits 16..23
289: movb %ah,gdt+SEG_TSS+7 / Fix bits 24..31
290:
291: movw $SEG_TSS,%ax / Load task state segment register.
292: ltr %ax
293: lidt idtmap / Load interrupt descriptor table
294: lgdt gdtmap
295:
296: / movw $ldt,%ax / Relocate ldt in gdt
297: / movw %ax,gdt+SEG_LDT+2
298:
299: / Fix ldt base in gdt
300: movl $ldt,%eax
301: movw %ax,gdt+SEG_LDT+2 / Fix bits 0..15
302: rorl $16,%eax / Get ldt bits 16..31
303: movb %al,gdt+SEG_LDT+4 / Fix bits 16..23
304: movb %ah,gdt+SEG_LDT+7 / Fix bits 24..31
305:
306: movw $SEG_LDT,%ax
307: lldt %ax
308:
309: call i8086 / i8086() does fixup of tss_sp0
310:
311: /
312: / Enter Ring 1 kernel from Ring 0
313: /
314: push $SEG_RNG1_STK / SS
315: push $ESP1_START / ESP
316: push $PSW_VAL / PSW
317: push $SEG_RNG1_TXT / CS
318: push $__xmain__ / IP
319: movw $SEG_386_KD, %ax / DS, ES
320: movw %ax, %ds / Map data segment
321: movw %ax, %es / Map extra segment
322: iret / Go to ring 1
323:
324: /
325: / Start of Ring 1 kernel.
326: / Need Ring 1 because interrupts are about to turn on, and all irpt gates
327: / have DPL (descriptor privilege level) 1.
328: /
329: __xmain__:
330: sti / Interrupts on, and
331: call main / call Coherent mainline.
332: cli / Interrupts off.
333:
334: /
335: / Enter User mode from Ring 1 kernel
336: /
337: push $SEG_386_UD|R_USR / SS
338: push $NBPC / ESP
339: push $PSW_VAL / PSW
340: push $SEG_386_UI|R_USR / CS
341: push $0 / IP
342: movw $SEG_386_UD|R_USR, %ax / DS, ES
343: movw %ax, %ds / Map data segment
344: movw %ax, %es / Map extra segment
345: iret / Go to user state.
346:
347: ///////
348: /
349: / Trap and interrupt save.
350: /
351: / This version of tsave runs from Ring 1 trap/irpt gates.
352: /
353: ///////
354: .globl disflag
355:
356: tsave: / What level of interrupt ?
357: pusha
358: push %ds / Save current state
359: push %es
360: push %fs
361: push %gs
362:
363: xor %ebp, %ebp / Halt backtraces
364:
365: movw $SEG_386_KD, %ax / Map ds
366: movw %ax, %ds
367: movw %ax, %es
368: movw $SEG_386_UD|R_USR, %ax / Map es
369: movw %ax, %fs
370:
371: sti
372: icall X_TRAPNO(%esp) / and call the caller
373: cli
374:
375: / if got here from user mode or from idle process, call stand()
376: / else just do cleanup and return
377:
378: movb X_ERR+8(%esp),%al / trapped CS: user RPL?
379: andb $3,%al
380: cmpb $R_USR,%al
381: je tsave1a / jmp if user mode
382: cmpl $__idle__,X_ERR+4(%esp) / trapped EIP == idle process?
383: jnz tsave1b / Call stand() only if idle
384: movl $1,disflag
385:
386: tsave1a:
387: sti
388: call stand
389: tsave1b:
390: cli / No more interrupts
391: pop %gs / Restore
392: pop %fs
393: pop %es
394: pop %ds
395: popa
396: add $8,%esp / forget err, trapno
397: iret / Done.
398:
399: /
400: / Here is another version of tsave, called only from the GP vector (RING 0)
401: /
402:
403: BYPASS .macro addr
404: cmpl $addr,X_ERR+4(%esp) / trapped EIP
405: jz tsave0b
406: .endm
407:
408: tsave0: / What level of interrupt ?
409: pusha
410: push %ds / Save current state
411: push %es
412: push %fs
413: push %gs
414:
415: movw $SEG_386_KD, %ax / Map ds
416: movw %ax, %ds
417: movw %ax, %es
418: movw $SEG_386_UD|R_USR, %ax / Map es
419: movw %ax, %fs
420:
421: jmp tsave0b
422:
423: //The following lines help find traps during startup.
424: BYPASS read_cr0
425: BYPASS read_cr2
426: BYPASS read_cr3
427: tsave0q:
428: mov 52(%esp),%eax / Print fault code.
429: cmpb $0x40,%al
430: je tsave0b / Skip over hardware interrupts.
431: push %eax
432: call print32
433: pop %ecx
434:
435: push $' '
436: call mchirp
437: pop %ecx
438:
439: mov 56(%esp),%eax / Print eip.
440: push %eax
441: call print32
442: pop %ecx
443:
444: push $' '
445: call mchirp
446: pop %ecx
447:
448: push %esp / Print esp.
449: call print32
450: pop %ecx
451:
452: tsave0a: jmp tsave0a
453: tsave0b:
454: //
455:
456: icall X_TRAPNO(%esp) / and call the caller
457:
458: pop %gs / Restore
459: pop %fs
460: pop %es
461: pop %ds
462: popa
463: add $8,%esp / forget err, trapno
464: iret / Done.
465:
466: ///////
467:
468: / Save the environment of a process
469: / envsave(p)
470: / MENV *p;
471:
472: / Save the context of a process
473: / consave(p)
474: / MCON *p;
475:
476: ///////
477:
478: envsave:
479: consave:
480: mov %edi, %ecx / Hide di.
481: mov 4(%esp), %edi / di at the MCON block.
482:
483: cld / Ensure increment.
484: mov %ecx, %eax / Save di
485: stosl
486: mov %esi, %eax / Save si
487: stosl
488: mov %ebx, %eax / Save bx
489: stosl
490: mov %ebp, %eax / Save bp
491: stosl
492: mov %esp, %eax / Save sp
493: stosl
494: mov (%esp), %eax / Save ra as pc
495: stosl
496: pushfl / Save fw
497: pop %eax
498: stosl
499: xorl %eax, %eax
500: movw %fs, %ax / save space pointer
501: stosl
502: mov %ecx, %edi / Put di back,
503: sub %eax, %eax / indicate a state save and
504: ret / return to caller.
505:
506: ///////
507:
508: / Restore the environment of a process.
509: / envrest(p)
510: / MENV *p;
511:
512: ///////
513:
514: envrest:
515: cli
516: cld
517: mov 4(%esp),%esi / Pointer to context
518: lodsl / Restore di
519: mov %eax, %edi
520: lodsl / Restore si
521: mov %eax, %ecx / Save for later
522: lodsl / Restore bx
523: mov %eax, %ebx
524: lodsl / Restore bp
525: mov %eax, %ebp
526: lodsl / Restore sp
527: mov %eax, %esp
528: push %cs / Push current CS
529: lodsl / Restore pc
530: push %eax
531: lodsl / Restore flags
532: mov %eax, 8(%esp) / Stack now in form PSW,CS,IP.
533: lodsl
534: movw %ax, %fs / Restore space
535: mov %ecx, %esi / Restore si
536: mov $1,%eax / We are restoring
537: iret / Return through PSW,CS,IP.
538:
539: ///////
540:
541: / Restore the context of a process.
542: / Called with interrupts disabled from dispatch.
543: / conrest(u, o)
544: / saddr_t u;
545:
546: ///////
547:
548: conrest:
549: mov 8(%esp), %esi / Fetch syscon offset
550:
551: cli / Interrupts on hold
552: cld
553:
554: / Map new u area into linear space and update paging hardware
555:
556: mov 4(%esp),%eax / Fetch new u area saddr_t
557: orb $SEG_SRW,%al
558: mov %eax,[PTABLE1_V<<BPCSHIFT]+UADDR
559:
560: lcall $SEG_MMUUPD,$0 / strobe CR3
561:
562: / Restore context
563:
564: lodsl / Restore di
565: mov %eax,%edi
566: lodsl / Restore si
567: mov %eax,%ecx / Save for later
568: lodsl / Restore bx
569: mov %eax,%ebx
570: lodsl / Restore bp
571: mov %eax,%ebp
572: lodsl / Restore sp
573: mov %eax,%esp
574: push %cs / Push current CS
575: lodsl / Restore pc
576: push %eax
577:
578: lodsl / Restore flags
579: mov %eax,8(%esp) / Stack now in form PSW,CS,IP.
580:
581: lodsl
582: movw %ax, %fs / Restore space
583:
584: mov %ecx,%esi / Restore si
585: mov $1,%eax / We are restoring
586: iret / Return through PSW,CS,IP.
587:
588: / Save useful registers.
589:
590: / msysgen(p)
591: / MGEN *p;
592:
593: msysgen:
594: ret / Nothing useful to save
595:
596: / Disable interrupts. Previous value is returned.
597:
598: sphi:
599: pushf / Save flags
600: pop %eax / Return current value
601: cli / Disable interrupts
602: ret / And return
603:
604: / Enable interrupts. Previous value is returned.
605:
606: splo:
607: pushf
608: pop %eax
609: sti
610: ret
611:
612: / Change interrupt flag, with no return value. Since we want to test bit 10
613: / of the flags word, we test bit 2 of the second byte with a byte test.
614: / (An earlier version of this routine used IRET, which is a bad idea beacuse
615: / it is a) very slow, and b) dangerous).
616:
617: spl:
618: pushf / Transfer previous flags to
619: pop %eax / %eax by way of the stack
620: testb $0x2,5(%esp) / Test argument interrupt flag
621: je ?cleari / Branch if flag was clear
622: sti
623: ret
624: ?cleari:
625: cli
626: ret
627:
628: ///////
629:
630: / Idle routine.
631: / Enable interupts, and wait for something to
632: / happen. Does not do anything to the 8259, bacause
633: / this will be set up correctly.
634:
635: ///////
636: .globl idle
637: idle:
638: sti / Interupts on.
639: __idle__:
640: jmp __idle__ / Wait for an interrupt
641: ret / and return.
642:
643: ///////
644:
645: / The world is indeed grim.
646: / Hang. Keep the interrupts on so that the
647: / keyboard can get int.
648:
649: ///////
650:
651: halt: sti / Be safe,
652: __halt__
653: jmp __halt__ / And hang.
654:
655: ///////
656:
657: / Basic port level I/O.
658:
659: / Byte I/O (8 bits)
660: / int inb(port);
661: / int outb(port, data);
662:
663: / Word I/O (16 bits)
664: / int inw(port);
665: / int outw(port, data);
666:
667: / Long I/O (32 bits)
668: / int inl(port);
669: / int outl(port, data);
670:
671: ///////
672:
673: inb: mov 4(%esp),%edx
674: sub %eax,%eax
675: inb (%dx)
676: ret
677:
678: outb: movl 4(%esp),%edx
679: movl 8(%esp),%eax
680: outb (%dx)
681: ret
682:
683: inw: mov 4(%esp),%edx
684: sub %eax,%eax
685: inw (%dx)
686: ret
687:
688: outw: movl 4(%esp),%edx
689: movl 8(%esp),%eax
690: outw (%dx)
691: ret
692:
693: inl: mov 4(%esp),%edx
694: sub %eax,%eax
695: inl (%dx)
696: ret
697:
698: outl: movl 4(%esp),%edx
699: movl 8(%esp),%eax
700: outl (%dx)
701: ret
702:
703: ///////
704:
705: / AT Hard Disk Assembler Support
706:
707: / atsend( va ) - send 512 bytes from virtual address to hard disk
708: / atrecv( va ) - receive 512 bytes from hard disk into virtual address
709: / DRQ is not checked. DRQ must be true before atsend/atrecv are called.
710:
711: / va is a system global address
712: ///////
713:
714: .globl atsend
715:
716: va = 8 / va offset from %ebp
717: work0 = -4 / work0 offset from %ebp
718: atsend:
719: enter $0,$4 / reserve 4 bytes (1 int) of local storage
720: push %esi
721: call workAlloc / get a temp virt page
722: movl %eax, work0(%ebp) / this is "work0" - a click number
723:
724: cld
725: mov va(%ebp), %eax / fetch argument va
726: shr $BPCSHIFT,%eax / get page table index from va
727: mov sysmem,%edx
728: leal (%edx,%eax,4),%esi / base = sysmem.u.pbase + btocrd(va)
729:
730: / Since the requested transfer may span a click boundary, have two clicks
731: / ready in the page table - the one containing the virtual address of the
732: / start of the user area, and the click which follows in virtual memory.
733:
734: lodsl / ptable1_V[WORK0] = *base++ | SEG_SRW
735: or $SEG_SRW,%eax
736: movl work0(%ebp), %edx / work0
737: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
738:
739: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
740: or $SEG_SRW,%eax
741: inc %edx / work1
742: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
743:
744: / Now that page boundaries are set, work on the offsets.
745:
746: mov va(%ebp), %esi / va = ctob(WORK0) + (va & (NBPC-1))
747: and $NBPC-1,%esi / get click offset part of va
748: movl work0(%ebp), %edx / work0
749: shl $BPCSHIFT,%edx / ctob(work0)
750: add %edx,%esi
751:
752: mov $256, %ecx / copy one disk block
753: mov $0x1F0, %edx
754:
755: / Do the block transfer.
756:
757: rep
758: outsw
759:
760: push work0(%ebp) / workFree(work0)
761: call workFree
762: pop %edx
763: pop %esi
764: leave
765: ret
766:
767: .globl atrecv
768: atrecv:
769: enter $0,$4 / reserve 4 bytes (1 int) of local storage
770: push %esi
771: call workAlloc / get a temp virt page
772: movl %eax, work0(%ebp) / this is "work0" - a click number
773:
774: cld
775: mov va(%ebp), %eax
776: shr $BPCSHIFT,%eax
777: mov sysmem,%edx
778: leal (%edx,%eax,4),%esi / base = sysmem.u.pbase + btocrd(va)
779:
780: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
781: or $SEG_SRW,%eax
782: movl work0(%ebp), %edx / work0
783: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
784:
785: lodsl / ptable1_V[WORK1] = *base++ | SEG_SRW
786: or $SEG_SRW,%eax
787: inc %edx / work1
788: movl %eax,[PTABLE1_V<<BPCSHIFT](%edx,4)
789:
790: mov va(%ebp), %esi / va = ctob(WORK0) + (va & (NBPC-1))
791: and $NBPC-1,%esi
792: movl work0(%ebp), %edx / work0
793: shl $BPCSHIFT,%edx / ctob(work0)
794: add %edx,%esi
795:
796: mov $256, %ecx / copy one disk block
797: mov $0x1F0, %edx
798:
799: xchg %esi,%edi
800: rep / Value of the ECX register is not
801: insw
802: xchg %esi,%edi
803:
804: push work0(%ebp) / workFree(work0)
805: call workFree
806: pop %edx
807: pop %esi
808: leave
809: ret
810:
811: ///////
812:
813: / This dummy routine is put in vector
814: / table slots that are unused. All it does is
815: / return to the caller.
816:
817: ///////
818:
819: vret: ret
820:
821: / mmuupd() uses a call gate.
822: mmuupd:
823: pushf
824: cli
825: lcall $SEG_MMUUPD,$0 / gates to mmuupdfR0
826: popf
827: ret
828:
829: / Ring 0 far mmu update. Called via a gate. Uses %eax.
830: / Want interrupts off when we arrive since the interrupt gates
831: / lead into Ring 1.
832: mmuupdfR0:
833: mov $PTABLE0_P<<BPCSHIFT,%eax
834: mov %eax,%cr3
835: lret
836:
837: / Ring 0 near mmu update. Called from ring 0 startup. Uses %eax.
838: mmuupdnR0:
839: mov $PTABLE0_P<<BPCSHIFT,%eax
840: mov %eax,%cr3
841: ret
842:
843: ///////
844: / Get cs selector - return 0 if in kernel, CS if not in kernel.
845: / This version is for resident drivers.
846: / There is a different version (cs_self.s) for loadable drivers.
847: / int cs_sel();
848: ///////
849:
850: cs_sel:
851: sub %eax, %eax
852: ret
853:
854: / load the 'alternate address space register' (fs)
855: / with the segment reference passed as an argument.
856:
857: / The value returned is the old value of the 'fs' register
858:
859: setspace:
860: xorl %eax, %eax
861: movw %fs, %ax
862: movw 4(%esp), %fs
863: ret
864:
865: /////////////////////////
866: /
867: / From __xtrap_on__ to __xtrap_off__, GP fault and page fault will not
868: / cause panic. Normally, these two traps coming from kernel text result
869: / in panic.
870: /
871: /////////////////////////
872: .globl __xtrap_on__
873: .globl __xtrap_break__
874: .globl __xtrap_off__
875: __xtrap_on__:
876:
877: ///////
878:
879: start_copy .macro
880: movl %esp, %edx / Frame pointer for copy code
881: .endm
882:
883: end_copy .macro
884: ret
885: .endm
886:
887: copy_frame .define %edx
888:
889: ///////
890: / Fetch a byte from the user's data space.
891: / getubd(u)
892: / char *u;
893: ///////
894:
895: getubd:
896: start_copy
897: movl %ss:4(copy_frame), %ecx
898: movzxb %fs:(%ecx), %eax
899: end_copy
900:
901: / Fetch a short from the user's data space.
902: / Coherent 386 fetches a 16 bit short
903: / getusd(u)
904: / char *u;
905: ///////
906:
907: getusd:
908: start_copy
909: movl %ss:4(copy_frame), %ecx
910: movzxw %fs:(%ecx), %eax
911: end_copy
912:
913: ///////
914: / Fetch a word from the user's data space.
915: / Coherent 386 fetches a 32 bit word
916: / getuwd(u)
917: / char *u;
918: ///////
919:
920: getuwd:
921: getupd:
922: start_copy
923: movl %ss:4(copy_frame), %ecx
924: movl %fs:(%ecx), %eax
925: end_copy
926:
927: ///////
928: / Store a byte into the user's data space.
929: / putubd(u, w)
930: / char *u;
931: / int w;
932: ///////
933:
934: putubd:
935: start_copy
936: movl %ss:4(copy_frame), %ecx
937: movb %ss:8(copy_frame), %al
938: movb %al, %fs:(%ecx)
939: end_copy
940:
941: ///////
942: / Store a short into the user's data space.
943: / Coherent 386 stores a 16 bit short
944: / putusd(u, w)
945: / char *u;
946: / int w;
947: ///////
948:
949: putusd:
950: start_copy
951: movl %ss:4(copy_frame), %ecx
952: movw %ss:8(copy_frame), %ax
953: movw %ax, %fs:(%ecx)
954: end_copy
955:
956: ///////
957: / Store a word into the user's data space.
958: / Coherent 386 stores a 32 bit word
959: / putuwd(u, w)
960: / char *u;
961: / int w;
962: ///////
963:
964: putuwi:
965: putuwd:
966: start_copy
967: movl %ss:4(copy_frame), %ecx
968: movl %ss:8(copy_frame), %eax
969: movl %eax, %fs:(%ecx)
970: end_copy
971:
972: ///////
973: / Perform a block-clear of user-space memory
974: / size_t umemclear (caddr_t * dest, size_t size)
975: //////
976: .globl umemclear
977: umemclear:
978: start_copy
979:
980: push %ds / Preserve %ds
981: push %es / Preserve %es (?)
982: pushl %esi / Preserve %esi
983: pushl %edi / Preserve %esi
984:
985: movw %fs, %ax
986: movw %ax, %es / Dest segment
987:
988: movl %ss:4(copy_frame), %edi / Dest
989:
990: movl %ss:8(copy_frame), %ecx / Length
991: sarl $2, %ecx / in longwords.
992:
993: xorl %eax, %eax / Zero-fill target
994: rep stosl / If %ecx > 0, clear longwords
995:
996: movl %ss:8(copy_frame), %ecx / Length
997: andl $3, %ecx / residual byte count
998: rep stosb / If %ecx > 0, clear bytes
999:
1000: movl %ss:8(copy_frame), %eax / Return value
1001:
1002: popl %edi / Restore registers
1003: popl %esi
1004: pop %es
1005: pop %ds
1006: end_copy
1007:
1008: ////////
1009: / Block transfer "n" bytes from location
1010: / "k" in the system map to location "u" in the
1011: / user's data space. Return the number of bytes
1012: / transferred.
1013: / kucopy(k, u, n)
1014: / char *k;
1015: / char *u;
1016: / int n;
1017: ///////
1018:
1019: kucopy:
1020: start_copy
1021:
1022: push %ds / Preserve %ds
1023: push %es / Preserve %es (?)
1024: pushl %esi / Preserve %esi
1025: pushl %edi / Preserve %esi
1026:
1027: movw %fs, %ax
1028: movw %ax, %es / Dest segment
1029:
1030: movl %ss:4(copy_frame), %esi / Source
1031: movl %ss:8(copy_frame), %edi / Dest
1032:
1033: movl %ss:12(copy_frame), %eax / Return value
1034: movl %eax, %ecx / Length
1035: sarl $2, %ecx / in longwords.
1036: rep movsl / If %ecx > 0, move longwords
1037:
1038: movl %eax, %ecx / Length
1039: andl $3, %ecx / residual byte count
1040: rep movsb / If %ecx > 0, move bytes
1041:
1042: popl %edi / Restore registers
1043: popl %esi
1044: pop %es
1045: pop %ds
1046: end_copy
1047:
1048:
1049: ///////
1050: / Block copy "n" bytes from location "u" in
1051: / the user data space to location "k" in the system
1052: / data space. Return the actual number of bytes
1053: / moved.
1054: / ukcopy(u, k, n)
1055: / char *u;
1056: / char *k;
1057: / int n;
1058: ///////
1059:
1060: ukcopy:
1061: start_copy
1062:
1063: push %ds / Preserve %ds
1064: push %es / Preserve %es (assume == %ds)
1065: pushl %esi / Preserve %si
1066: pushl %edi / Preserve %di
1067:
1068: movw %fs, %ax
1069: movw %ax, %ds / Source segment
1070:
1071: mov %ss:4(copy_frame), %esi / Source
1072: mov %ss:8(copy_frame), %edi / Dest
1073:
1074: movl %ss:12(copy_frame), %eax / Return value
1075: movl %eax, %ecx / Length
1076: sarl $2, %ecx / in longwords
1077: rep movsl / If %ecx > 0, move longwords
1078:
1079: movl %eax, %ecx / Length
1080: andl $3, %ecx / residual byte count
1081: rep movsb / if %ecx > 0, move bytes
1082:
1083: popl %edi / Restore registers
1084: popl %esi
1085: pop %es
1086: pop %ds
1087: end_copy / Return
1088:
1089: ////////
1090: / Block copy "n" bytes from far location "src" in
1091: / an arbitrary (but valid) to location "dst" in
1092: / data space. Return the actual number of bytes
1093: / moved.
1094: /
1095: / ffcopy(src, dst, n)
1096: / char far *src;
1097: / char far *dst;
1098: / int n;
1099: ////////
1100: .globl ffcopy
1101: ffcopy:
1102: start_copy
1103:
1104: push %ds / Preserve %ds
1105: push %es / Preserve %es
1106: pushl %esi / Preserve %esi
1107: pushl %edi / Preserve %edi
1108:
1109: les %ss:12(copy_frame), %edi / Dest segment, length
1110: lds %ss:4(copy_frame), %esi / Source segment, length
1111:
1112: movl %ss:20(copy_frame), %eax / Return value
1113: movl %eax, %ecx / Length
1114: sarl $2, %ecx / in longwords
1115: rep movsl / if %ecx > 0, move longwords
1116:
1117: movl %eax, %ecx / Length
1118: andl $3, %ecx / residual byte count
1119: rep movsb / if %ecx > 0, move bytes
1120:
1121: popl %edi
1122: popl %esi
1123: pop %es
1124: pop %ds
1125: end_copy / Return
1126:
1127: ////////
1128: / Read a byte from a selector and offset.
1129: /
1130: / ffbyte(off, sel)
1131: / unsigned long sel;
1132: / unsigned long off;
1133: ////////
1134: .globl ffbyte
1135: ffbyte:
1136: start_copy
1137: lgs %ss:4(copy_frame), %ecx / Source seg:offset
1138: movzxb %gs:(%ecx), %eax / Move with zero-fill
1139: end_copy
1140:
1141: ////////
1142: / Read a (short) word from a selector and offset.
1143: /
1144: / ffword(off, sel)
1145: / unsigned long sel;
1146: / unsigned long off;
1147: ////////
1148: .globl ffword
1149: ffword:
1150: start_copy
1151: lgs %ss:4(copy_frame), %ecx / Source seg:offset
1152: movzxw %gs:(%ecx), %eax / Move with zero-fill
1153: end_copy
1154:
1155: ////////
1156: / write a byte using a selector and offset.
1157: /
1158: / sfbyte(off, sel, byte)
1159: / unsigned long sel;
1160: / unsigned long off;
1161: / int byte;
1162: ////////
1163: .globl sfbyte
1164: sfbyte:
1165: start_copy
1166: lgs %ss:4(copy_frame), %ecx / Dest seg:offset
1167: movb %ss:12(copy_frame), %al
1168: movb %al, %gs:(%ecx)
1169: end_copy
1170:
1171: ////////
1172: / write a (short) word using a selector and offset.
1173: /
1174: / sfword(off, sel, word)
1175: / unsigned long sel;
1176: / unsigned long off;
1177: / int word;
1178: ////////
1179: .globl sfword
1180: sfword:
1181: start_copy
1182: lgs %ss:4(copy_frame), %ecx / Dest seg:offset
1183: movw %ss:12(copy_frame), %ax
1184: movw %ax, %gs:(%ecx)
1185: end_copy
1186:
1187: ///////
1188: / The n-element copy routines jump here with the stack untouched if they
1189: / detect a bounds error or page fault on a user address. The only routines
1190: / above that use the stack at all do so with a standard format, so we detect
1191: / what is on the stack and restore appropriately.
1192: / [ For simplicity, just assume that the pushed values will either all be
1193: / there or not be there at all, which is a very good assumption. ]
1194: ///////
1195:
1196: __xtrap_break__:
1197: subl %eax, %eax / Return 0 to indicate error
1198: / condition.
1199: cmpl %esp, %edx / Anything on stack?
1200: je ?no_stack
1201:
1202: popl %edi / Restore registers
1203: popl %esi
1204: pop %es
1205: pop %ds
1206: ?no_stack:
1207: end_copy / Return
1208:
1209: __xtrap_off__: / See __xtrap_on__ above.
1210:
1211: / seg2io(long nbytes, vaddr_t p, long port)
1212:
1213: / nbytes must be a short word multiple
1214:
1215: seg2io:
1216: movl %esp,%edx
1217: push %esi
1218:
1219: mov 4(%edx),%ecx
1220: mov 8(%edx),%esi
1221: mov 12(%edx),%edx / mov edx,2(dx)
1222: sar $1,%ecx / char to short
1223:
1224: cld
1225: rep
1226: outsw
1227:
1228: pop %esi
1229: ret
1230:
1231:
1232:
1233: / io2seg(long nbytes, vaddr_t p, long port)
1234:
1235: / nbytes must be a short word multiple
1236:
1237: io2seg:
1238: mov %esp,%edx
1239: push %edi
1240:
1241: mov 4(%edx),%ecx
1242: mov 8(%edx),%edi
1243: mov 12(%edx),%edx / mov edx,2(dx)
1244: sar $1,%ecx / char to short
1245:
1246: cld
1247: rep / Value of the ECX register is not
1248: insw
1249:
1250: pop %edi
1251: ret
1252:
1253:
1254: ///////
1255: /
1256: / Profile scaling - special multiply routine is used for speed.
1257: /
1258: / pscale(a,b) is product a*b shifted right 16 bits
1259: /
1260: ///////
1261:
1262: .globl pscale
1263: pscale:
1264: mov 4(%esp),%eax / fetch first argument
1265: mull 8(%esp) / unsigned multiply by second argument
1266: shrd $16,%edx,%eax / shift 64-bit product right 16 bits
1267: ret
1268:
1269: ///////
1270:
1271: / Trap an interrupt linkage.
1272: / Each of the machine traps has a special little
1273: / linkage, that sets up the type code and sends
1274: / control off to the common trap processor. Device
1275: / interrupts, other than the clock (IR0), are
1276: / done here.
1277:
1278: ///////
1279:
1280: trap0:
1281: push $0x00 / Divide error.
1282: call tsave
1283: jmp trap
1284:
1285: / The debug vector is tricky.
1286: /
1287: / If single stepping user code, the vector must point into Ring 1 code
1288: / so that a ptraced child can be synchronized with its parent.
1289: / use trap1_usr for this
1290: /
1291: / If single stepping the kernel, the vector must point into Ring 0 code
1292: / so context switches switch out the debug stack frame.
1293: / use trap1_ker for this
1294:
1295: .globl __debug_usr__
1296: trap1_usr:
1297: push $0x01 / Single step.
1298: call tsave
1299: jmp __debug_usr__
1300:
1301: .globl __debug_ker__
1302: trap1_ker:
1303: push $0x01 / Single step.
1304: call tsave0
1305: jmp __debug_ker__
1306:
1307: trap2:
1308: push $0x02 / Non-maskable interrupt.
1309: call tsave
1310: jmp trap
1311:
1312: trap3:
1313: push $0x03 / INT 3 (breakpoint).
1314: call tsave
1315: jmp trap
1316:
1317: trap4:
1318: push $0x04 / Overflow.
1319: call tsave
1320: jmp trap
1321:
1322: trap5:
1323: push $0x05 / Bound check.
1324: call tsave
1325: jmp trap
1326:
1327: trap6:
1328: push $0x06 / Invalid opcode.
1329: call tsave
1330: jmp trap
1331:
1332: trap7:
1333: push $0x07 / Processor Extension not available.
1334: call tsave
1335: jmp emtrap
1336:
1337: trap8:
1338: / pop %ss:trapcode / Get error code from stack [always 0]
1339: add $4,%esp
1340: push $0x08 / Double Exception detected
1341: call tsave
1342: jmp trap
1343:
1344: trap9:
1345: push $0x09 / Processor extension segment overrun
1346: call tsave
1347: jmp trap
1348:
1349: trap10:
1350: / pop %ss:trapcode / Get error code from stack
1351: add $4,%esp
1352: push $0x0A / Invalid task state segment
1353: call tsave
1354: jmp trap
1355:
1356: trap11:
1357: / pop %ss:trapcode / Get error code from stack
1358: add $4,%esp
1359: push $0x0B / Segment not present
1360: call tsave
1361: jmp trap
1362:
1363: trap12:
1364: / pop %ss:trapcode / Get error code from stack
1365: add $4,%esp
1366: push $0x0C / Stack segment overrun or not present
1367: call tsave
1368: jmp trap
1369:
1370: trap13:
1371: / pop %ss:trapcode / Get error code from stack
1372: / add $4,%esp
1373: / push $0x0D / General protection
1374: call tsave0
1375: jmp gpfault
1376:
1377: trap14:
1378: / pop %ss:trapcode / Get error code from stack
1379: / add $4,%esp
1380: / push $0x0E / Page Fault
1381: call tsave
1382: jmp pagefault
1383:
1384: trap16:
1385: push $0x10 / Floating point error
1386: call tsave
1387: jmp fptrap
1388:
1389: syc:
1390: push $0x22 / Old format system calls.
1391: call tsave
1392: jmp trap
1393:
1394: .set FAKE_EFL,12
1395: syc32:
1396: push %eax / save %eax
1397: pushf / modify current flags
1398: pop %eax
1399: orw $PSW_VAL,%ax / set IF=1, IOPL=1 (user) on iret
1400: mov %eax,FAKE_EFL(%esp)
1401: pop %eax / restore %eax
1402: push $0x20 / New format system calls.
1403: call tsave
1404: jmp trap
1405:
1406: sig32:
1407: push %eax
1408: pushf
1409: pop %eax
1410: orw $PSW_VAL,%ax
1411: mov %eax,FAKE_EFL(%esp)
1412: pop %eax
1413: push $0x20 / New format signal return.
1414: call tsave
1415: jmp msigend
1416:
1417: ran:
1418: push $0x21 / Random trap.
1419: call tsave
1420: jmp trap
1421:
1422: dev1:
1423: push $0x0140 / Device 1: keyboard
1424: call tsave
1425: icall [1<<2]+vecs
1426: jmp eoi / Dismiss interrupt
1427:
1428: / Device 2: mapped into device 9
1429: dev3:
1430: push $0x0340 / Device 3: al1
1431: call tsave
1432: icall [3<<2]+vecs
1433: jmp eoi / Dismiss interrupt
1434:
1435: dev4:
1436: push $0x0440 / Device 4: al0
1437: call tsave
1438: icall [4<<2]+vecs
1439: jmp eoi / Dismiss interrupt
1440:
1441: dev5:
1442: push $0x0540 / Device 5: hard disk
1443: call tsave
1444: icall [5<<2]+vecs
1445: jmp eoi / Dismiss interrupt
1446:
1447: dev6:
1448: push $0x0640 / Device 6: floppy
1449: call tsave
1450: icall [6<<2]+vecs
1451: jmp eoi / Dismiss interrupt
1452:
1453: dev7:
1454: push $0x0740 / Device 7: lp
1455: call tsave
1456: icall [7<<2]+vecs
1457: jmp eoi / Dismiss interrupt
1458:
1459: dev8:
1460: push $0x0840 / Device 8:
1461: call tsave
1462: icall [8<<2]+vecs
1463: jmp eoi2 / Dismiss interrupt
1464:
1465: dev9:
1466: push $0x0940 / Device 9:
1467: call tsave
1468: icall [9<<2]+vecs
1469: jmp eoi2 / Dismiss interrupt
1470:
1471: dev10:
1472: push $0x0A40 / Device 10:
1473: call tsave
1474: icall [10<<2]+vecs
1475: jmp eoi2 / Dismiss interrupt
1476:
1477: dev11:
1478: push $0x0B40 / Device 11:
1479: call tsave
1480: icall [11<<2]+vecs
1481: jmp eoi2 / Dismiss interrupt
1482:
1483: dev12:
1484: push $0x0C40 / Device 12:
1485: call tsave
1486: icall [12<<2]+vecs
1487: jmp eoi2 / Dismiss interrupt
1488:
1489: .align 4
1490: dev13:
1491: / Used to be coprocessor exception interrupt
1492: / Coprocessor err had to be cleared by writing a 0 byte to port 0xF0
1493: /
1494: push $0x0D40 / Device 13:
1495: call tsave
1496: icall [13<<2]+vecs
1497: jmp eoi2 / Dismiss interrupt
1498:
1499: dev14:
1500: push $0x0E40 / Device 14:
1501: call tsave
1502: icall [14<<2]+vecs
1503: jmp eoi2 / Dismiss interrupt
1504:
1505: dev15:
1506: push $0x0F40 / Device 15:
1507: call tsave
1508: icall [15<<2]+vecs
1509: jmp eoi2 / Dismiss interrupt
1510:
1511: ///////
1512:
1513: / Clock interrupt.
1514:
1515: ///////
1516:
1517: clk:
1518: push $0x0040
1519: call tsave / Perform trap save.
1520: mov X_ERR+12(%esp),%eax / ECS at tick time
1521: and $3,%eax / This will be R_USR iff user mode
1522: push %eax
1523: mov X_ERR+12(%esp),%eax / EIP at tick time
1524: push %eax
1525: call clock / clock(eip, umode)
1526: add $8,%esp / pop arguments.
1527: jmp eoi / Dismiss interrupt
1528:
1529: ///////
1530:
1531: / This co-routine is called to dismiss an interrupt.
1532: / The interrupt code is in X_ERR(%esp)
1533:
1534: / Control returns to "tsave"
1535:
1536: ///////
1537:
1538: .globl eoi2
1539: eoi2:
1540: cli
1541: movb $0x20,%al / Send a non specific EOI
1542: outb $SPIC / to the slave PIC.
1543: IODELAY
1544: movb $0x0B,%al / OCW3 - read isr
1545: outb $SPIC
1546: IODELAY
1547: / inb $SPIC / in-service register to %eax:8..15
1548: / testb %al,%al
1549: / jnz eoi2x / no EOI to master if slave isr nonzero
1550: eoi:
1551: cli
1552: movb $0x20,%al / Send a non specific EOI
1553: outb $PIC / to the master PIC.
1554: IODELAY
1555: eoi2x: ret / Done.
1556:
1557: ///////
1558:
1559: / Read the equipment description. Use
1560: / the "int 11" interface, so that the IBM
1561: / ROM will do all the details.
1562:
1563: ///////
1564:
1565: int11: mov %cs:val11,%eax / Ask the ROM
1566: ret / to put stuff in AX
1567:
1568: ///////
1569:
1570: / Bootstrap.
1571: / Called by the keyboard driver on control-alt-del.
1572: / Requests the 8042 controller to initiate a processor reset,
1573: / which is the only way to terminate protected mode operation.
1574:
1575: / Reference: IBM-AT Technical Reference Manual,
1576: / Real-time Clock/CMOS RAM [Page 1-45]
1577: / Keyboard controller [Page 1-40]
1578: / Test 3, Page 5-68.
1579:
1580: ///////
1581: boot:
1582: cli / Disable interrupts.
1583:
1584: subl %ecx,%ecx
1585: loc12: inb $KBCTRL / Wait for 8042 input buffer to empty.
1586: testb $2, %al
1587: loopne loc12
1588: IODELAY
1589:
1590: movb $0xFE,%al / Issue a shutdown command
1591: outb $KBCTRL / to the 8042 control port.
1592:
1593: loc13: hlt / Halt until processor reset occurs.
1594: jmp loc13
1595:
1596: .globl putchar
1597:
1598: / Comment in the line below if debugging output is to go to the
1599: / printer
1600:
1601: /putchar:
1602:
1603: movb 4(%esp),%al
1604: cmpb $0xa,%al
1605: jne loc18
1606: push $0xd
1607: call putchar
1608: add $4,%esp
1609: loc18: mov $LPSTAT,%edx
1610: inb (%dx)
1611: testb $IBMNBSY,%al
1612: je loc18
1613:
1614: mov $LPCSR,%edx
1615: movb $SEL+NINIT, %al
1616: outb (%dx)
1617:
1618: mov $LPDATA, %edx
1619: movb 4(%esp),%al
1620: outb (%dx)
1621:
1622: mov $LPCSR,%edx
1623: movb $SEL+NINIT+STROBE,%al
1624: outb (%dx)
1625: movb $8, %cl
1626: l_1: decb %cl
1627: jne l_1
1628: movb $SEL+NINIT, %al
1629: outb (%dx)
1630: ret
1631:
1632: / long _canl(l) long l;
1633: / This is called by the routines that
1634: / transform longs to and from the
1635: / canonical formats.
1636:
1637: _canl:
1638: mov 4(%esp),%eax
1639: rol $16,%eax
1640: ret
1641:
1642: regcr2: mov %cr2,%eax
1643: ret
1644:
1645: regfp: mov %ebp,%eax
1646: ret
1647:
1648: / .align 4 / CPU resets if val11 isn't aligned.
1649: .byte 0
1650: val11: .long 0 / Value obtained from int11 [in code].
1651:
1652: aicodep:
1653: sub %ebx,%ebx
1654: sub $aicodep,%ebx
1655: lea fn(%ebx),%eax
1656: mov %eax,argl(%ebx)
1657: lea a1(%ebx),%eax
1658: mov %eax,argl+4(%ebx)
1659: lea argl+8(%ebx),%eax / No environment
1660: push %eax
1661: lea argl(%ebx),%eax / Argument list
1662: push %eax
1663: lea fn(%ebx),%eax / File name
1664: push %eax
1665: sub $4,%esp / Dummy word for exec
1666: movl $59, %eax
1667: lcall $0x7,$0
1668: jmp . / Instant page fault if exec failed!
1669: .alignoff
1670: .align 2
1671: argl: .long 0 / argv[0] = "/etc/init";
1672: .long 0 / argv[1] = "";
1673: .long 0 / argv[2] = NULL;
1674:
1675: fn: .byte "/etc/init",0
1676: a1: .byte 0
1677: sb:
1678: .set aicodes, .-aicodep
1679:
1680: ///////
1681:
1682: / Task State Segment - Coherent runs as a single protected mode 386 task.
1683:
1684: ///////
1685: .alignon
1686: .align 4
1687: .globl tss_sp0 / Use run-time fixup for tss_sp0
1688: .globl tssIoMap
1689: .globl tssIoEnd
1690: tss: / Task State Segment.
1691: tss_lnk:.long 0 / 0: Back link selector to TSS.
1692: tss_sp0:.long ESP0_START / 4: SP for CPL 0.
1693: tss_ss0:.long SEG_RNG0_STK / 8: SS for CPL 0.
1694: tss_sp1:.long ESP1_START / C: SP for CPL 1.
1695: tss_ss1:.long SEG_RNG1_STK / 10: SS for CPL 1.
1696: tss_sp2:.long u+NBPC / 14: SP for CPL 2.
1697: tss_ss2:.long SEG_386_KD / 18: SS for CPL 2.
1698: tss_cr3:.long PTABLE0_P<<BPCSHIFT / 1C: CR3 (PDBR)
1699: tss_ip: .long 0 / 20: EIP (Entry point).
1700: tss_psw:.long 0 / 24: Flag word.
1701: tss_ax: .long 0 / 28: Register AX.
1702: tss_cx: .long 0 / 2C: Register CX.
1703: tss_dx: .long 0 / 30: Register DX.
1704: tss_bx: .long 0 / 34: Register BX.
1705: tss_bp: .long 0 / 38: Register BP.
1706: tss_sp: .long 0 / 3C: Register SP.
1707: tss_si: .long 0 / 40: Register SI.
1708: tss_di: .long 0 / 44: Register DI.
1709: tss_es: .long 0 / 48: Register ES.
1710: tss_cs: .long 0 / 4C: Register CS.
1711: tss_ss: .long 0 / 50: Register SS.
1712: tss_ds: .long 0 / 54: Register DS.
1713: tss_fs: .long 0 / 58: Register FS.
1714: tss_gs: .long 0 / 5C: Register GS.
1715: tss_ldt:.long SEG_LDT / 60: Task LDT Selector.
1716: .long TSS_IOMAP_OFF / 64: T bit & I/O map base
1717: / I/O map is part of tss.
1718: / Bitmap up to port address TSS_IOMAP_LEN.
1719: / Initialize to all 1's, meaning no I/O allowed.
1720: / tss + 0x68 = tssIoMap
1721: tssIoMap:
1722: .long [[TSS_IOMAP_LEN + 31] .div 32] # -1
1723: tssIoEnd:
1724: .long [[0x1000 - TSS_IOMAP_LEN] .div 32] # -1
1725: .long -1
1726: ///////
1727:
1728: / Data.
1729:
1730: ///////
1731: .data
1732: sdata:
1733:
1734: vecs: .long 16 # vret / Interrupt vector table
1735:
1736: trapcode:.long 0
1737:
1738: .text
1739: ///////
1740:
1741: / Read a byte from the CMOS. Takes one argument--the
1742: / CMOS address to read from as an int; returns the
1743: / value read as a char.
1744: /
1745: / int read_cmos(int addr);
1746:
1747: read_cmos:
1748: push %esi
1749: push %edi
1750: movb 12(%esp), %al / Fetch address from stack.
1751: outb $CMOSA / Send address to CMOS.
1752: IODELAY
1753: sub %eax, %eax / Zero out everything we don't want.
1754: inb $CMOSD / Get Value from CMOS into al.
1755: pop %edi
1756: pop %esi
1757: ret / Return from read_cmos().
1758:
1759: / Write a byte to the CMOS.
1760: /
1761: / void write_cmos(int addr, int data)
1762:
1763: write_cmos:
1764: push %esi
1765: push %edi
1766: movb 12(%esp), %al / Fetch address from stack.
1767: outb $CMOSA / Send address to CMOS.
1768: IODELAY
1769: movb 16(%esp), %al / Fetch address from stack.
1770: outb $CMOSD / Get Value from CMOS into al.
1771: IODELAY
1772: pop %edi
1773: pop %esi
1774: ret / Return from read_cmos().
1775:
1776: / Read timer channel 0 into int value.
1777: / Clock counts down from 11932 to 0 with each clock tick.
1778: .globl read_t0
1779: read_t0:
1780: pushfl
1781: cli
1782: xorl %eax,%eax / Counter latch timer 0 and clear return val
1783: outb $PIT+3
1784: IODELAY
1785: inb $PIT / low byte of counter latch
1786: IODELAY
1787: movb %al,%ah
1788: inb $PIT / high byte of counter latch
1789: IODELAY
1790: xchgb %al,%ah
1791: popfl
1792: ret
1793:
1794: / return current contents of psw
1795: .globl read_psw
1796: read_psw:
1797: pushfl
1798: popl %eax
1799: ret
1800:
1801:
1802: / return current contents of cr0
1803: .globl read_cr0
1804: read_cr0:
1805: movl %cr0,%eax
1806: ret
1807:
1808: / return current contents of cr2
1809: .globl read_cr2
1810: read_cr2:
1811: movl %cr2,%eax
1812: ret
1813:
1814: / return current contents of cr3
1815: .globl read_cr3
1816: read_cr3:
1817: movl %cr3,%eax
1818: ret
1819:
1820: /////////
1821: /
1822: / Debugging support.
1823: /
1824: /////////
1825: .globl write_dr0
1826: .globl write_dr1
1827: .globl write_dr2
1828: .globl write_dr3
1829: .globl write_dr6
1830: .globl write_dr7
1831:
1832: .globl read_dr0
1833: .globl read_dr1
1834: .globl read_dr2
1835: .globl read_dr3
1836: .globl read_dr6
1837: .globl read_dr7
1838:
1839: / write arg to dr0
1840: write_dr0:
1841: movl 4(%esp),%eax
1842: movl %eax,%dr0
1843: ret
1844:
1845: / write arg to dr1
1846: write_dr1:
1847: movl 4(%esp),%eax
1848: movl %eax,%dr1
1849: ret
1850:
1851: / write arg to dr2
1852: write_dr2:
1853: movl 4(%esp),%eax
1854: movl %eax,%dr2
1855: ret
1856:
1857: / write arg to dr3
1858: write_dr3:
1859: movl 4(%esp),%eax
1860: movl %eax,%dr3
1861: ret
1862:
1863: / write arg to dr6
1864: write_dr6:
1865: movl 4(%esp),%eax
1866: movl %eax,%dr6
1867: ret
1868:
1869: / write arg to dr7
1870: write_dr7:
1871: movl 4(%esp),%eax
1872: movl %eax,%dr7
1873: ret
1874:
1875: read_dr0:
1876: movl %dr0,%eax
1877: ret
1878:
1879: read_dr1:
1880: movl %dr1,%eax
1881: ret
1882:
1883: read_dr2:
1884: movl %dr2,%eax
1885: ret
1886:
1887: read_dr3:
1888: movl %dr3,%eax
1889: ret
1890:
1891: read_dr6:
1892: movl %dr6,%eax
1893: ret
1894:
1895: read_dr7:
1896: movl %dr7,%eax
1897: ret
1898:
1899: / write to the EM bit of CR0
1900: / this routine is a stub for the ring 0 code
1901: / argument is 0 or 1
1902: /
1903: / void setEm(int bit)
1904: .globl setEm
1905: setEm:
1906: movl 4(%esp),%eax / fetch argument
1907: pushf
1908: cli
1909: pushl %eax
1910: lcall $SEG_SET_EM,$0 / gate to setEmfR0
1911: / setEmfR0 will delete 4 bytes worth of args
1912: popf
1913: ret
1914:
1915: / Ring 0 write to CR0 EM bit. Called via a gate.
1916: / Want interrupts off when we arrive since the interrupt gates
1917: / lead into Ring 1.
1918: setEmfR0:
1919: movb 8(%esp),%cl / fetch argument
1920:
1921: cmpb $0,%cl
1922: movl %cr0,%eax
1923: jz se00
1924: orb $4,%al / set EM bit
1925: andb $0xDF,%al / clear NE bit
1926: jmp se01
1927: se00:
1928: andb $0xFB,%al / clear EM bit
1929: orb $0x20,%al / set NE bit
1930: se01:
1931: mov %eax,%cr0
1932: / make 4-byte arg list disappear
1933: lret $4
1934:
1935: / return nonzero if paging is turned on
1936: .globl paging
1937: paging:
1938: movl (%esp),%eax / fetch return address
1939: cmpl $[SBASE<<BPCSHIFT],%eax / is it >= unsigned FFC0_0000?
1940: jae pagingMaybe
1941: xorl %eax,%eax / if not, no paging
1942: ret
1943: pagingMaybe:
1944: movw %cs,%ax / if return addr high, cs is a selector
1945: cmpw $0x58,%ax / selectors 58-6F are nonpaging
1946: jb pagingYes
1947: cmpw $0x6F,%ax / selectors 58-6F are nonpaging
1948: ja pagingYes
1949: xorl %eax,%eax / no paging
1950: ret
1951: pagingYes:
1952: movl $1,%eax
1953: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.