summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1993-06-12 14:58:17 +0000
committerrgrimes <rgrimes@FreeBSD.org>1993-06-12 14:58:17 +0000
commit25062ba061871945759b3baa833fe64969383e40 (patch)
tree2d1c31051ed0dbaad984013c9fe695b1a01e1c39
parentf078b88a160c467761b3f3641f05dfd0aa3f7753 (diff)
downloadFreeBSD-src-25062ba061871945759b3baa833fe64969383e40.zip
FreeBSD-src-25062ba061871945759b3baa833fe64969383e40.tar.gz
Initial import, 0.1 + pk 0.2.4-B1
-rw-r--r--bin/expr/Makefile20
-rw-r--r--bin/expr/expr.y594
-rw-r--r--libexec/makekey/Makefile6
-rw-r--r--libexec/makekey/makekey.859
-rw-r--r--libexec/makekey/makekey.c85
-rw-r--r--sys/alpha/include/pc/display.h43
-rw-r--r--sys/alpha/include/pc/msdos.h63
-rw-r--r--sys/amd64/Makefile24
-rw-r--r--sys/amd64/amd64/autoconf.c213
-rw-r--r--sys/amd64/amd64/db_disasm.c1397
-rw-r--r--sys/amd64/amd64/db_interface.c255
-rw-r--r--sys/amd64/amd64/db_trace.c292
-rw-r--r--sys/amd64/amd64/fpu.c564
-rw-r--r--sys/amd64/amd64/genassym.c174
-rw-r--r--sys/amd64/amd64/locore.S1830
-rw-r--r--sys/amd64/amd64/locore.s1830
-rw-r--r--sys/amd64/amd64/machdep.c1131
-rw-r--r--sys/amd64/amd64/mem.c191
-rw-r--r--sys/amd64/amd64/pmap.c1728
-rw-r--r--sys/amd64/amd64/sys_machdep.c105
-rw-r--r--sys/amd64/amd64/trap.c547
-rw-r--r--sys/amd64/amd64/tsc.c271
-rw-r--r--sys/amd64/amd64/vm_machdep.c410
-rw-r--r--sys/amd64/include/cpu.h108
-rw-r--r--sys/amd64/include/cpufunc.h82
-rw-r--r--sys/amd64/include/db_machdep.h154
-rw-r--r--sys/amd64/include/float.h74
-rw-r--r--sys/amd64/include/fpu.h146
-rw-r--r--sys/amd64/include/frame.h116
-rw-r--r--sys/amd64/include/npx.h146
-rw-r--r--sys/amd64/include/pc/display.h43
-rw-r--r--sys/amd64/include/pcb.h87
-rw-r--r--sys/amd64/include/pmap.h234
-rw-r--r--sys/amd64/include/proc.h47
-rw-r--r--sys/amd64/include/psl.h60
-rw-r--r--sys/amd64/include/reg.h93
-rw-r--r--sys/amd64/include/segments.h196
-rw-r--r--sys/amd64/include/specialreg.h67
-rw-r--r--sys/amd64/include/trap.h96
-rw-r--r--sys/amd64/include/tss.h78
-rw-r--r--sys/amd64/include/vmparam.h256
-rw-r--r--sys/amd64/isa/clock.c271
-rw-r--r--sys/amd64/isa/icu.h109
-rw-r--r--sys/amd64/isa/isa.c766
-rw-r--r--sys/amd64/isa/isa.h188
-rw-r--r--sys/amd64/isa/npx.c564
-rw-r--r--sys/amd64/isa/timerreg.h89
-rw-r--r--sys/amd64/isa/vector.S376
-rw-r--r--sys/amd64/isa/vector.s376
-rw-r--r--sys/conf/Makefile.i386164
-rw-r--r--sys/conf/Makefile.powerpc164
-rw-r--r--sys/conf/files.i38671
-rw-r--r--sys/ddb/db_access.c116
-rw-r--r--sys/ddb/db_access.h55
-rw-r--r--sys/ddb/db_aout.c309
-rw-r--r--sys/ddb/db_break.c387
-rw-r--r--sys/ddb/db_break.h84
-rw-r--r--sys/ddb/db_command.c526
-rw-r--r--sys/ddb/db_command.h67
-rw-r--r--sys/ddb/db_examine.c364
-rw-r--r--sys/ddb/db_expr.c248
-rw-r--r--sys/ddb/db_input.c268
-rw-r--r--sys/ddb/db_lex.c295
-rw-r--r--sys/ddb/db_lex.h89
-rw-r--r--sys/ddb/db_output.c389
-rw-r--r--sys/ddb/db_output.h53
-rw-r--r--sys/ddb/db_print.c104
-rw-r--r--sys/ddb/db_run.c426
-rw-r--r--sys/ddb/db_sym.c360
-rw-r--r--sys/ddb/db_sym.h114
-rw-r--r--sys/ddb/db_trap.c106
-rw-r--r--sys/ddb/db_variables.c186
-rw-r--r--sys/ddb/db_variables.h72
-rw-r--r--sys/ddb/db_watch.c294
-rw-r--r--sys/ddb/db_watch.h74
-rw-r--r--sys/ddb/db_write_cmd.c120
-rw-r--r--sys/dev/fdc/fdc.c903
-rw-r--r--sys/dev/fdc/fdcreg.h72
-rw-r--r--sys/dev/ic/i8237.h9
-rw-r--r--sys/dev/ic/nec765.h71
-rw-r--r--sys/dev/ic/ns16550.h50
-rw-r--r--sys/dev/sio/sio.c1721
-rw-r--r--sys/dev/sio/sioreg.h113
-rw-r--r--sys/dev/speaker/spkr.c520
-rw-r--r--sys/i386/Makefile24
-rw-r--r--sys/i386/boot/Makefile131
-rw-r--r--sys/i386/boot/biosboot/Makefile131
-rw-r--r--sys/i386/boot/biosboot/README.386BSD149
-rw-r--r--sys/i386/boot/biosboot/README.MACH218
-rw-r--r--sys/i386/boot/biosboot/asm.h192
-rw-r--r--sys/i386/boot/biosboot/boot.c323
-rw-r--r--sys/i386/boot/biosboot/boot.h48
-rw-r--r--sys/i386/boot/biosboot/disk.c238
-rw-r--r--sys/i386/boot/biosboot/io.c189
-rw-r--r--sys/i386/boot/biosboot/sys.c240
-rw-r--r--sys/i386/boot/biosboot/table.c112
-rw-r--r--sys/i386/conf/GENERICAH95
-rw-r--r--sys/i386/conf/Makefile.i386164
-rw-r--r--sys/i386/conf/devices.i38618
-rw-r--r--sys/i386/conf/files.i38671
-rw-r--r--sys/i386/eisa/aha1742.c1420
-rw-r--r--sys/i386/i386/autoconf.c213
-rw-r--r--sys/i386/i386/cons.c213
-rw-r--r--sys/i386/i386/cons.h65
-rw-r--r--sys/i386/i386/db_disasm.c1397
-rw-r--r--sys/i386/i386/db_interface.c255
-rw-r--r--sys/i386/i386/db_trace.c292
-rw-r--r--sys/i386/i386/genassym.c174
-rw-r--r--sys/i386/i386/in_cksum.c181
-rw-r--r--sys/i386/i386/locore.s1830
-rw-r--r--sys/i386/i386/machdep.c1131
-rw-r--r--sys/i386/i386/math_emu.h154
-rw-r--r--sys/i386/i386/math_emulate.c1487
-rw-r--r--sys/i386/i386/mem.c191
-rw-r--r--sys/i386/i386/microtime.s135
-rw-r--r--sys/i386/i386/pmap.c1728
-rw-r--r--sys/i386/i386/swapgeneric.c166
-rw-r--r--sys/i386/i386/symbols.raw89
-rw-r--r--sys/i386/i386/sys_machdep.c105
-rw-r--r--sys/i386/i386/trap.c547
-rw-r--r--sys/i386/i386/tsc.c271
-rw-r--r--sys/i386/i386/vm_machdep.c410
-rw-r--r--sys/i386/include/_limits.h57
-rw-r--r--sys/i386/include/ansi.h57
-rw-r--r--sys/i386/include/cpu.h108
-rw-r--r--sys/i386/include/cpufunc.h82
-rw-r--r--sys/i386/include/db_machdep.h154
-rw-r--r--sys/i386/include/endian.h117
-rw-r--r--sys/i386/include/float.h74
-rw-r--r--sys/i386/include/frame.h116
-rw-r--r--sys/i386/include/limits.h57
-rw-r--r--sys/i386/include/mtpr.h0
-rw-r--r--sys/i386/include/npx.h146
-rw-r--r--sys/i386/include/param.h164
-rw-r--r--sys/i386/include/pc/display.h43
-rw-r--r--sys/i386/include/pc/msdos.h63
-rw-r--r--sys/i386/include/pcb.h87
-rw-r--r--sys/i386/include/pmap.h234
-rw-r--r--sys/i386/include/proc.h47
-rw-r--r--sys/i386/include/psl.h60
-rw-r--r--sys/i386/include/reg.h93
-rw-r--r--sys/i386/include/segments.h196
-rw-r--r--sys/i386/include/specialreg.h67
-rw-r--r--sys/i386/include/stdarg.h53
-rw-r--r--sys/i386/include/trap.h96
-rw-r--r--sys/i386/include/tss.h78
-rw-r--r--sys/i386/include/types.h50
-rw-r--r--sys/i386/include/vmparam.h256
-rw-r--r--sys/i386/isa/aha1542.c1644
-rw-r--r--sys/i386/isa/clock.c271
-rw-r--r--sys/i386/isa/fd.c903
-rw-r--r--sys/i386/isa/fdreg.h72
-rw-r--r--sys/i386/isa/ic/i8042.h23
-rw-r--r--sys/i386/isa/ic/i8237.h9
-rw-r--r--sys/i386/isa/ic/nec765.h71
-rw-r--r--sys/i386/isa/ic/ns16450.h49
-rw-r--r--sys/i386/isa/ic/ns16550.h50
-rw-r--r--sys/i386/isa/icu.h109
-rw-r--r--sys/i386/isa/icu.s376
-rw-r--r--sys/i386/isa/isa.c766
-rw-r--r--sys/i386/isa/isa.h188
-rw-r--r--sys/i386/isa/isa_device.h85
-rw-r--r--sys/i386/isa/kbd.h58
-rw-r--r--sys/i386/isa/lpt.c455
-rw-r--r--sys/i386/isa/lptreg.h34
-rw-r--r--sys/i386/isa/npx.c564
-rw-r--r--sys/i386/isa/rtc.h85
-rw-r--r--sys/i386/isa/sio.c1721
-rw-r--r--sys/i386/isa/sioreg.h113
-rw-r--r--sys/i386/isa/spkr.c520
-rw-r--r--sys/i386/isa/timerreg.h89
-rw-r--r--sys/i386/isa/ultra14f.c1308
-rw-r--r--sys/i386/isa/vector.s376
-rw-r--r--sys/i386/isa/wd.c1352
-rw-r--r--sys/i386/isa/wdreg.h143
-rw-r--r--sys/i386/isa/wt.c1162
-rw-r--r--sys/i386/isa/wtreg.h95
-rw-r--r--sys/isa/atrtc.c271
-rw-r--r--sys/isa/fd.c903
-rw-r--r--sys/isa/fdreg.h72
-rw-r--r--sys/isa/ic/nec765.h71
-rw-r--r--sys/isa/ic/ns16550.h50
-rw-r--r--sys/isa/rtc.h85
-rw-r--r--sys/isa/sio.c1721
-rw-r--r--sys/isa/sioreg.h113
-rw-r--r--sys/isa/timerreg.h89
-rw-r--r--sys/kern/subr_rlist.c191
-rw-r--r--sys/kern/subr_trap.c547
-rw-r--r--sys/kern/tty_cons.c213
-rw-r--r--sys/powerpc/include/_limits.h57
-rw-r--r--sys/powerpc/include/limits.h57
-rw-r--r--sys/scsi/README182
-rw-r--r--sys/scsi/cd.c1722
-rw-r--r--sys/scsi/scsi_all.h373
-rw-r--r--sys/scsi/scsi_cd.h295
-rw-r--r--sys/scsi/scsi_disk.h249
-rw-r--r--sys/scsi/scsi_tape.h169
-rw-r--r--sys/scsi/scsiconf.c761
-rw-r--r--sys/scsi/scsiconf.h113
-rw-r--r--sys/scsi/sd.c1466
-rw-r--r--sys/scsi/st.c1774
-rw-r--r--sys/sys/cdio.h149
-rw-r--r--sys/sys/cons.h65
-rw-r--r--sys/sys/rlist.h34
204 files changed, 67453 insertions, 0 deletions
diff --git a/bin/expr/Makefile b/bin/expr/Makefile
new file mode 100644
index 0000000..4c9ac6a
--- /dev/null
+++ b/bin/expr/Makefile
@@ -0,0 +1,20 @@
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 1 00092
+# -------------------- ----- ----------------------
+#
+# 15 Mar 93 Patchkit Coordinator Corrected SRCS, missing .c
+#
+PROG=expr
+SRCS=expr.c
+CFLAGS+=-I. -I${.CURDIR}
+NOMAN=noman
+CLEANFILES+=expr.c y.tab.h
+
+expr.c:
+ ${YACC} -d ${.IMPSRC}
+ mv y.tab.c expr.c
+
+.include <bsd.prog.mk>
+
diff --git a/bin/expr/expr.y b/bin/expr/expr.y
new file mode 100644
index 0000000..f8c389c
--- /dev/null
+++ b/bin/expr/expr.y
@@ -0,0 +1,594 @@
+%{
+/* Written by Pace Willisson (pace@blitz.com)
+ * and placed in the public domain
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00148
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 J. T. Conklin Many fixes for () and other such things
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+enum valtype {
+ integer, string
+} ;
+
+struct val {
+ enum valtype type;
+ union {
+ char *s;
+ int i;
+ } u;
+};
+
+struct val *result;
+struct val *op_or ();
+struct val *op_and ();
+struct val *op_eq ();
+struct val *op_gt ();
+struct val *op_lt ();
+struct val *op_ge ();
+struct val *op_le ();
+struct val *op_ne ();
+struct val *op_plus ();
+struct val *op_minus ();
+struct val *op_times ();
+struct val *op_div ();
+struct val *op_rem ();
+struct val *op_colon ();
+
+char **av;
+%}
+
+%union
+{
+ struct val *val;
+}
+
+%left <val> '|'
+%left <val> '&'
+%left <val> '=' '>' '<' GE LE NE
+%left <val> '+' '-'
+%left <val> '*' '/' '%'
+%left <val> ':'
+%left UNARY
+
+%token <val> TOKEN
+%type <val> start expr
+
+%%
+
+start: expr { result = $$; }
+
+expr: TOKEN
+ | '(' expr ')' { $$ = $2; }
+ | expr '|' expr { $$ = op_or ($1, $3); }
+ | expr '&' expr { $$ = op_and ($1, $3); }
+ | expr '=' expr { $$ = op_eq ($1, $3); }
+ | expr '>' expr { $$ = op_gt ($1, $3); }
+ | expr '<' expr { $$ = op_lt ($1, $3); }
+ | expr GE expr { $$ = op_ge ($1, $3); }
+ | expr LE expr { $$ = op_le ($1, $3); }
+ | expr NE expr { $$ = op_ne ($1, $3); }
+ | expr '+' expr { $$ = op_plus ($1, $3); }
+ | expr '-' expr { $$ = op_minus ($1, $3); }
+ | expr '*' expr { $$ = op_times ($1, $3); }
+ | expr '/' expr { $$ = op_div ($1, $3); }
+ | expr '%' expr { $$ = op_rem ($1, $3); }
+ | expr ':' expr { $$ = op_colon ($1, $3); }
+ | '-' expr %prec UNARY { $$ = op_minus (NULL, $2); }
+ ;
+
+
+%%
+
+struct val *
+make_integer (i)
+int i;
+{
+ struct val *vp;
+
+ vp = (struct val *) malloc (sizeof (*vp));
+ if (vp == NULL) {
+ fprintf (stderr, "expr: out of memory\n");
+ exit (2);
+ }
+
+ vp->type = integer;
+ vp->u.i = i;
+ return vp;
+}
+
+struct val *
+make_str (s)
+char *s;
+{
+ struct val *vp;
+
+ vp = (struct val *) malloc (sizeof (*vp));
+ if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
+ fprintf (stderr, "expr: out of memory\n");
+ exit (2);
+ }
+
+ vp->type = string;
+ return vp;
+}
+
+
+void
+free_value (vp)
+struct val *vp;
+{
+ if (vp->type == string)
+ free (vp->u.s);
+}
+
+
+int
+to_integer (vp)
+struct val *vp;
+{
+ char *s;
+ int neg;
+ int i;
+
+ if (vp->type == integer)
+ return 1;
+
+ s = vp->u.s;
+ i = 0;
+
+ neg = (*s == '-');
+ if (neg)
+ s++;
+
+ for (;*s; s++) {
+ if (!isdigit (*s))
+ return 0;
+
+ i *= 10;
+ i += *s - '0';
+ }
+
+ free (vp->u.s);
+ if (neg)
+ i *= -1;
+
+ vp->type = integer;
+ vp->u.i = i;
+ return 1;
+}
+
+void
+to_string (vp)
+struct val *vp;
+{
+ char *tmp;
+
+ if (vp->type == string)
+ return;
+
+ tmp = malloc (25);
+ if (tmp == NULL) {
+ fprintf (stderr, "expr: out of memory\n");
+ exit (2);
+ }
+
+ sprintf (tmp, "%d", vp->u.i);
+ vp->type = string;
+ vp->u.s = tmp;
+}
+
+
+int
+isstring (vp)
+struct val *vp;
+{
+ return (vp->type == string);
+}
+
+
+int
+yylex ()
+{
+ struct val *vp;
+ char *p;
+
+ if (*av == NULL)
+ return (0);
+
+ p = *av++;
+
+ if (strlen (p) == 1) {
+ if (strchr ("|&=<>+-*/%:()", *p))
+ return (*p);
+ } else if (strlen (p) == 2 && p[1] == '=') {
+ switch (*p) {
+ case '>': return (GE);
+ case '<': return (LE);
+ case '!': return (NE);
+ }
+ }
+
+ yylval.val = make_str (p);
+ return (TOKEN);
+}
+
+int
+is_zero_or_null (vp)
+struct val *vp;
+{
+ /* Like most other versions of expr, this version will return
+ false for a string value of multiple zeros.*/
+
+ if (vp->type == integer) {
+ return (vp->u.i == 0);
+ } else {
+ return (*vp->u.s == 0 || strcmp (vp->u.s, "0") == 0);
+ }
+ /* NOTREACHED */
+}
+
+void
+main (argc, argv)
+int argc;
+char **argv;
+{
+ av = argv + 1;
+
+ yyparse ();
+
+ if (result->type == integer)
+ printf ("%d\n", result->u.i);
+ else
+ printf ("%s\n", result->u.s);
+
+ if (is_zero_or_null (result))
+ exit (1);
+ else
+ exit (0);
+}
+
+int
+yyerror (s)
+char *s;
+{
+ fprintf (stderr, "expr: syntax error\n");
+ exit (2);
+}
+
+
+struct val *
+op_or (a, b)
+struct val *a, *b;
+{
+ if (is_zero_or_null (a)) {
+ free_value (a);
+ return (b);
+ } else {
+ free_value (b);
+ return (a);
+ }
+}
+
+struct val *
+op_and (a, b)
+struct val *a, *b;
+{
+ if (is_zero_or_null (a) || is_zero_or_null (b)) {
+ free_value (a);
+ free_value (b);
+ return (make_integer (0));
+ } else {
+ free_value (b);
+ return (a);
+ }
+}
+
+struct val *
+op_eq (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) == 0);
+ } else {
+ r = make_integer (a->u.i == b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_gt (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) > 0);
+ } else {
+ r= make_integer (a->u.i > b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_lt (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) < 0);
+ } else {
+ r = make_integer (a->u.i < b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_ge (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) >= 0);
+ } else {
+ r = make_integer (a->u.i >= b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_le (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) <= 0);
+ } else {
+ r = make_integer (a->u.i <= b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_ne (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ /* attempt to coerce both arguments to integers */
+ (void) to_integer (a);
+ (void) to_integer (b);
+
+ /* But if either one of them really is a string, do
+ a string comparison */
+ if (isstring (a) || isstring (b)) {
+ to_string (a);
+ to_string (b);
+ r = make_integer (strcmp (a->u.s, b->u.s) != 0);
+ } else {
+ r = make_integer (a->u.i != b->u.i);
+ }
+
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_plus (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ if (!to_integer (a) || !to_integer (b)) {
+ fprintf (stderr, "expr: non-numeric argument\n");
+ exit (2);
+ }
+
+ r = make_integer (a->u.i + b->u.i);
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_minus (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ if (!to_integer (a) || !to_integer (b)) {
+ fprintf (stderr, "expr: non-numeric argument\n");
+ exit (2);
+ }
+
+ r = make_integer (a->u.i - b->u.i);
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_times (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ if (!to_integer (a) || !to_integer (b)) {
+ fprintf (stderr, "expr: non-numeric argument\n");
+ exit (2);
+ }
+
+ r = make_integer (a->u.i * b->u.i);
+ free_value (a);
+ free_value (b);
+ return (r);
+}
+
+struct val *
+op_div (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ if (!to_integer (a) || !to_integer (b)) {
+ fprintf (stderr, "expr: non-numeric argument\n");
+ exit (2);
+ }
+
+ if (b->u.i == 0) {
+ fprintf (stderr, "expr: division by zero\n");
+ exit (2);
+ }
+
+ r = make_integer (a->u.i / b->u.i);
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+struct val *
+op_rem (a, b)
+struct val *a, *b;
+{
+ struct val *r;
+
+ if (!to_integer (a) || !to_integer (b)) {
+ fprintf (stderr, "expr: non-numeric argument\n");
+ exit (2);
+ }
+
+ if (b->u.i == 0) {
+ fprintf (stderr, "expr: division by zero\n");
+ exit (2);
+ }
+
+ r = make_integer (a->u.i % b->u.i);
+ free_value (a);
+ free_value (b);
+ return r;
+}
+
+#include <regexp.h>
+
+struct val *
+op_colon (a, b)
+struct val *a, *b;
+{
+ regexp *rp;
+ char *newexp;
+ char *p;
+ char *q;
+
+ newexp = malloc (3 * strlen (b->u.s));
+ p = b->u.s;
+ q = newexp;
+
+ *q++ = '^';
+ while (*p) {
+ if (*p == '\\') {
+ p++;
+ if (*p == '(' || *p == ')') {
+ *q++ = *p++;
+ } else {
+ *q++ = '\\';
+ *q++ = *p++;
+ }
+ } else if (*p == '(' || *p == ')') {
+ *q++ = '\\';
+ *q++ = *p++;
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = 0;
+
+ if ((rp = regcomp (newexp)) == NULL)
+ yyerror ("invalid regular expression");
+
+ if (regexec (rp, a->u.s)) {
+ if (rp->startp[1]) {
+ rp->endp[1][0] = 0;
+ return (make_str (rp->startp[1]));
+ } else {
+ return (make_integer (rp->endp[0] - rp->startp[0]));
+ }
+ } else {
+ return (make_integer (0));
+ }
+}
+
+void
+regerror (s)
+const char *s;
+{
+ fprintf (stderr, "expr: %s\n", s);
+ exit (2);
+}
diff --git a/libexec/makekey/Makefile b/libexec/makekey/Makefile
new file mode 100644
index 0000000..b982bee
--- /dev/null
+++ b/libexec/makekey/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 5.3 (Berkeley) 5/11/90
+
+PROG= makekey
+MAN8= makekey.0
+
+.include <bsd.prog.mk>
diff --git a/libexec/makekey/makekey.8 b/libexec/makekey/makekey.8
new file mode 100644
index 0000000..ec9f979
--- /dev/null
+++ b/libexec/makekey/makekey.8
@@ -0,0 +1,59 @@
+.\" Copyright (c) 1990, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)makekey.8 6.5 (Berkeley) 7/1/91
+.\"
+.Dd July 1, 1991
+.Dt MAKEKEY 8
+.Os
+.Sh NAME
+.Nm makekey
+.Nd make encrypted keys or passwords
+.Sh SYNOPSIS
+.Nm makekey
+.Sh DESCRIPTION
+.Nm Makekey
+encypts a key and salt which it reads from the standard input
+and writes the result to the standard output.
+The key is expected to be
+ten bytes; the salt is expected to be two bytes.
+See
+.Xr crypt 3
+for more information on what characters the key and salt can contain
+and how the encrypted value is calculated.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr crypt 1 ,
+.Xr crypt 3
+.Sh HISTORY
+A
+.Nm
+command appeared in Version 7 AT&T UNIX.
diff --git a/libexec/makekey/makekey.c b/libexec/makekey/makekey.c
new file mode 100644
index 0000000..1a2e149
--- /dev/null
+++ b/libexec/makekey/makekey.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)makekey.c 5.3 (Berkeley) 2/25/91";
+#endif /* not lint */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void error(), get();
+
+main()
+{
+ int len;
+ char *r, key[9], salt[3];
+
+ get(key, sizeof(key) - 1);
+ get(salt, sizeof(salt) - 1);
+ len = strlen(r = crypt(key, salt));
+ if (write(STDOUT_FILENO, r, len) != len)
+ error();
+ exit(0);
+}
+
+static void
+get(bp, len)
+ char *bp;
+ register int len;
+{
+ register int nr;
+
+ bp[len] = '\0';
+ if ((nr = read(STDIN_FILENO, bp, len)) == len)
+ return;
+ if (nr >= 0)
+ errno = EFTYPE;
+ error();
+}
+
+static void
+error()
+{
+ (void)fprintf(stderr, "makekey: %s\n", strerror(errno));
+ exit(1);
+}
diff --git a/sys/alpha/include/pc/display.h b/sys/alpha/include/pc/display.h
new file mode 100644
index 0000000..cab46e4
--- /dev/null
+++ b/sys/alpha/include/pc/display.h
@@ -0,0 +1,43 @@
+/*
+ * IBM PC display definitions
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/alpha/include/pc/msdos.h b/sys/alpha/include/pc/msdos.h
new file mode 100644
index 0000000..8d1eb7b
--- /dev/null
+++ b/sys/alpha/include/pc/msdos.h
@@ -0,0 +1,63 @@
+/*
+ * msdos common header file
+ * [obtained from mtools -wfj]
+ * how to decipher DOS disk structures in coexisting with DOS
+ */
+
+#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */
+#define MDIR_SIZE 32 /* MSDOS directory size in bytes */
+#define MAX_CLUSTER 8192 /* largest cluster size */
+#define MAX_PATH 128 /* largest MSDOS path length */
+#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
+
+#define NEW 1
+#define OLD 0
+
+struct directory {
+ unsigned char name[8]; /* file name */
+ unsigned char ext[3]; /* file extension */
+ unsigned char attr; /* attribute byte */
+ unsigned char reserved[10]; /* ?? */
+ unsigned char time[2]; /* time stamp */
+ unsigned char date[2]; /* date stamp */
+ unsigned char start[2]; /* starting cluster number */
+ unsigned char size[4]; /* size of the file */
+};
+
+struct bootsector {
+ unsigned char jump[3]; /* Jump to boot code */
+ unsigned char banner[8]; /* OEM name & version */
+ unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */
+ unsigned char clsiz; /* Cluster size in sectors */
+ unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */
+ unsigned char nfat; /* Number of FAT tables hopefully 2 */
+ unsigned char dirents[2]; /* Number of directory slots */
+ unsigned char psect[2]; /* Total sectors on disk */
+ unsigned char descr; /* Media descriptor=first byte of FAT */
+ unsigned char fatlen[2]; /* Sectors in FAT */
+ unsigned char nsect[2]; /* Sectors/track */
+ unsigned char nheads[2]; /* Heads */
+ unsigned char nhs[4]; /* number of hidden sectors */
+ unsigned char bigsect[4]; /* big total sectors */
+ unsigned char junk[476]; /* who cares? */
+};
+
+/* DOS partition table -- located in boot block */
+
+#define DOSBBSECTOR 0 /* DOS boot block relative sector number */
+#define DOSPARTOFF 446
+#define NDOSPART 4
+
+struct dos_partition {
+ unsigned char dp_flag; /* bootstrap flags */
+ unsigned char dp_shd; /* starting head */
+ unsigned char dp_ssect; /* starting sector */
+ unsigned char dp_scyl; /* starting cylinder */
+ unsigned char dp_typ; /* partition type */
+#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
+ unsigned char dp_ehd; /* end head */
+ unsigned char dp_esect; /* end sector */
+ unsigned char dp_ecyl; /* end cylinder */
+ unsigned long dp_start; /* absolute starting sector number */
+ unsigned long dp_size; /* partition size in sectors */
+} dos_partitions[NDOSPART];
diff --git a/sys/amd64/Makefile b/sys/amd64/Makefile
new file mode 100644
index 0000000..0662e28
--- /dev/null
+++ b/sys/amd64/Makefile
@@ -0,0 +1,24 @@
+# @(#)Makefile 7.3 (Berkeley) 6/9/91
+
+# Makefile for i386 tags file
+
+all:
+ @echo "make tags or links only"
+
+TI386= ../i386/tags
+SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch]
+AI386= ../i386/i386/*.s
+
+# Directories in which to place i386 tags links
+DI386= eisa isa mca include
+
+tags:
+ -ctags -dtf ${TI386} ${COMM} ${SI386}
+ egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \
+ sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \
+ >> ${TI386}
+ sort -o ${TI386} ${TI386}
+
+links:
+ -for i in ${DI386}; do \
+ cd $$i && rm -f tags; ln -s ../tags tags; done
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c
new file mode 100644
index 0000000..7eee991
--- /dev/null
+++ b/sys/amd64/amd64/autoconf.c
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)autoconf.c 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00117
+ * -------------------- ----- ----------------------
+ *
+ * 09 Apr 93 ???(From sun-lamp) Fix to report sd when Julians
+ * scsi code is used, allow you to swap
+ * root floppies during a boot
+ */
+static char rcsid[] = "$Header: /b/source/CVS/src/sys.386bsd/i386/i386/autoconf.c,v 1.3 1993/04/10 21:58:52 cgd Exp $";
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the vba
+ * device tables and the memory controller monitoring. Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "dkstat.h"
+#include "conf.h"
+#include "dmap.h"
+#include "reboot.h"
+
+#include "machine/pte.h"
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int dkn; /* number of iostat dk numbers assigned so far */
+extern int cold; /* cold start flag initialized in locore.s */
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+configure()
+{
+
+#include "isa.h"
+#if NISA > 0
+ isa_configure();
+#endif
+
+#if GENERICxxx
+ if ((boothowto & RB_ASKNAME) == 0)
+ setroot();
+ setconf();
+#else
+ setroot();
+#endif
+ /*
+ * Configure swap area and related system
+ * parameter based on device(s) used.
+ */
+ swapconf();
+ cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+swapconf()
+{
+ register struct swdevt *swp;
+ register int nblks;
+extern int Maxmem;
+
+ for (swp = swdevt; swp->sw_dev > 0; swp++)
+ {
+ unsigned d = major(swp->sw_dev);
+
+ if (d > nblkdev) break;
+ if (bdevsw[d].d_psize) {
+ nblks = (*bdevsw[d].d_psize)(swp->sw_dev);
+ if (nblks > 0 &&
+ (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ swp->sw_nblks = nblks;
+ else
+ swp->sw_nblks = 0;
+ }
+ swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ }
+ if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
+ /*dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;*/
+ dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) -
+ Maxmem*NBPG/512;
+ if (dumplo < 0)
+ dumplo = 0;
+}
+
+#define DOSWAP /* change swdevt and dumpdev */
+u_long bootdev = 0; /* should be dev_t, but not until 32 bits */
+
+#include "sd.h"
+static char devname[][2] = {
+ 'w','d', /* 0 = wd */
+ 's','w', /* 1 = sw */
+ 'f','d', /* 2 = fd */
+ 'w','t', /* 3 = wt */
+#if NSD < 1
+ 'a','s', /* 4 = as */
+#else
+ 's','d', /* 4 = sd -- new SCSI system */
+#endif
+};
+
+#define PARTITIONMASK 0x7
+#define PARTITIONSHIFT 3
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+setroot()
+{
+ int majdev, mindev, unit, part, adaptor;
+ dev_t temp, orootdev;
+ struct swdevt *swp;
+
+/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
+ if (boothowto & RB_DFLTROOT ||
+ (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
+ return;
+ majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
+ if (majdev > sizeof(devname) / sizeof(devname[0]))
+ return;
+ adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
+ part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
+ unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
+ mindev = (unit << PARTITIONSHIFT) + part;
+ orootdev = rootdev;
+ rootdev = makedev(majdev, mindev);
+ /*
+ * If the original rootdev is the same as the one
+ * just calculated, don't need to adjust the swap configuration.
+ */
+ if (rootdev == orootdev)
+ return;
+ if (devname[majdev][0] == 'f' && devname[majdev][1] == 'd') {
+ printf("");
+ printf("* insert the floppy you want to have mounted as\n");
+ printf("* root, and hit any key to continue booting:\n");
+ cngetc();
+ printf("");
+ }
+ printf("changing root device to %c%c%d%c\n",
+ devname[majdev][0], devname[majdev][1],
+ mindev >> PARTITIONSHIFT, part + 'a');
+#ifdef DOSWAP
+ mindev &= ~PARTITIONMASK;
+ for (swp = swdevt; swp->sw_dev; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev == 0)
+ return;
+ /*
+ * If dumpdev was the same as the old primary swap
+ * device, move it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+#endif
+}
diff --git a/sys/amd64/amd64/db_disasm.c b/sys/amd64/amd64/db_disasm.c
new file mode 100644
index 0000000..20430b6
--- /dev/null
+++ b/sys/amd64/amd64/db_disasm.c
@@ -0,0 +1,1397 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_disasm.c,v $
+ * Revision 1.1 1992/03/25 21:42:01 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:11:03 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:03 mrt]
+ *
+ * Revision 2.2 90/08/27 21:55:56 dbg
+ * Fix register operand for move to/from control/test/debug
+ * register instructions. Add i486 instructions.
+ * [90/08/27 dbg]
+ *
+ * Import db_sym.h. Print instruction displacements in
+ * current radix (signed). Change calling sequence of
+ * db_disasm.
+ * [90/08/21 dbg]
+ * Fix includes.
+ * [90/08/08 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+
+/*
+ * Instruction disassembler.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Size attributes
+ */
+#define BYTE 0
+#define WORD 1
+#define LONG 2
+#define QUAD 3
+#define SNGL 4
+#define DBLR 5
+#define EXTR 6
+#define SDEP 7
+#define NONE 8
+
+/*
+ * Addressing modes
+ */
+#define E 1 /* general effective address */
+#define Eind 2 /* indirect address (jump, call) */
+#define Ew 3 /* address, word size */
+#define Eb 4 /* address, byte size */
+#define R 5 /* register, in 'reg' field */
+#define Rw 6 /* word register, in 'reg' field */
+#define Ri 7 /* register in instruction */
+#define S 8 /* segment reg, in 'reg' field */
+#define Si 9 /* segment reg, in instruction */
+#define A 10 /* accumulator */
+#define BX 11 /* (bx) */
+#define CL 12 /* cl, for shifts */
+#define DX 13 /* dx, for IO */
+#define SI 14 /* si */
+#define DI 15 /* di */
+#define CR 16 /* control register */
+#define DR 17 /* debug register */
+#define TR 18 /* test register */
+#define I 19 /* immediate, unsigned */
+#define Is 20 /* immediate, signed */
+#define Ib 21 /* byte immediate, unsigned */
+#define Ibs 22 /* byte immediate, signed */
+#define Iw 23 /* word immediate, unsigned */
+#define Il 24 /* long immediate */
+#define O 25 /* direct address */
+#define Db 26 /* byte displacement from EIP */
+#define Dl 27 /* long displacement from EIP */
+#define o1 28 /* constant 1 */
+#define o3 29 /* constant 3 */
+#define OS 30 /* immediate offset/segment */
+#define ST 31 /* FP stack top */
+#define STI 32 /* FP stack */
+#define X 33 /* extended FP op */
+#define XA 34 /* for 'fstcw %ax' */
+
+struct inst {
+ char * i_name; /* name */
+ short i_has_modrm; /* has regmodrm byte */
+ short i_size; /* operand size */
+ int i_mode; /* addressing modes */
+ char * i_extra; /* pointer to extra opcode table */
+};
+
+#define op1(x) (x)
+#define op2(x,y) ((x)|((y)<<8))
+#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16))
+
+struct finst {
+ char * f_name; /* name for memory instruction */
+ int f_size; /* size for memory instruction */
+ int f_rrmode; /* mode for rr instruction */
+ char * f_rrname; /* name for rr instruction
+ (or pointer to table) */
+};
+
+char * db_Grp6[] = {
+ "sldt",
+ "str",
+ "lldt",
+ "ltr",
+ "verr",
+ "verw",
+ "",
+ ""
+};
+
+char * db_Grp7[] = {
+ "sgdt",
+ "sidt",
+ "lgdt",
+ "lidt",
+ "smsw",
+ "",
+ "lmsw",
+ "invlpg"
+};
+
+char * db_Grp8[] = {
+ "",
+ "",
+ "",
+ "",
+ "bt",
+ "bts",
+ "btr",
+ "btc"
+};
+
+struct inst db_inst_0f0x[] = {
+/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 },
+/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 },
+/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
+/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
+/*04*/ { "", FALSE, NONE, 0, 0 },
+/*05*/ { "", FALSE, NONE, 0, 0 },
+/*06*/ { "clts", FALSE, NONE, 0, 0 },
+/*07*/ { "", FALSE, NONE, 0, 0 },
+
+/*08*/ { "invd", FALSE, NONE, 0, 0 },
+/*09*/ { "wbinvd",FALSE, NONE, 0, 0 },
+/*0a*/ { "", FALSE, NONE, 0, 0 },
+/*0b*/ { "", FALSE, NONE, 0, 0 },
+/*0c*/ { "", FALSE, NONE, 0, 0 },
+/*0d*/ { "", FALSE, NONE, 0, 0 },
+/*0e*/ { "", FALSE, NONE, 0, 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f2x[] = {
+/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */
+/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */
+/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 },
+/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 },
+/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 },
+/*25*/ { "", FALSE, NONE, 0, 0 },
+/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 },
+/*27*/ { "", FALSE, NONE, 0, 0 },
+
+/*28*/ { "", FALSE, NONE, 0, 0 },
+/*29*/ { "", FALSE, NONE, 0, 0 },
+/*2a*/ { "", FALSE, NONE, 0, 0 },
+/*2b*/ { "", FALSE, NONE, 0, 0 },
+/*2c*/ { "", FALSE, NONE, 0, 0 },
+/*2d*/ { "", FALSE, NONE, 0, 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f8x[] = {
+/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
+/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
+/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 },
+/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 },
+/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 },
+/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 },
+/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 },
+/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 },
+
+/*88*/ { "js", FALSE, NONE, op1(Dl), 0 },
+/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 },
+/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 },
+/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 },
+/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 },
+/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 },
+/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 },
+/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 },
+};
+
+struct inst db_inst_0f9x[] = {
+/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 },
+/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 },
+/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 },
+/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 },
+/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 },
+/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 },
+/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 },
+/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 },
+
+/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 },
+/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 },
+/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 },
+/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 },
+/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 },
+/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 },
+/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 },
+/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 },
+};
+
+struct inst db_inst_0fax[] = {
+/*a0*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*a2*/ { "", FALSE, NONE, 0, 0 },
+/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 },
+/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 },
+/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "", FALSE, NONE, 0, 0 },
+
+/*a8*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*aa*/ { "", FALSE, NONE, 0, 0 },
+/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 },
+/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 },
+/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 },
+};
+
+struct inst db_inst_0fbx[] = {
+/*b0*/ { "", FALSE, NONE, 0, 0 },
+/*b1*/ { "", FALSE, NONE, 0, 0 },
+/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 },
+/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 },
+/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 },
+/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 },
+/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 },
+/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 },
+
+/*b8*/ { "", FALSE, NONE, 0, 0 },
+/*b9*/ { "", FALSE, NONE, 0, 0 },
+/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 },
+/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
+/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
+/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
+/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 },
+/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 },
+};
+
+struct inst db_inst_0fcx[] = {
+/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+};
+
+struct inst db_inst_0fdx[] = {
+/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "", FALSE, NONE, 0, 0 },
+/*c9*/ { "", FALSE, NONE, 0, 0 },
+/*ca*/ { "", FALSE, NONE, 0, 0 },
+/*cb*/ { "", FALSE, NONE, 0, 0 },
+/*cc*/ { "", FALSE, NONE, 0, 0 },
+/*cd*/ { "", FALSE, NONE, 0, 0 },
+/*ce*/ { "", FALSE, NONE, 0, 0 },
+/*cf*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst *db_inst_0f[] = {
+ db_inst_0f0x,
+ 0,
+ db_inst_0f2x,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ db_inst_0f8x,
+ db_inst_0f9x,
+ db_inst_0fax,
+ db_inst_0fbx,
+ db_inst_0fcx,
+ db_inst_0fdx,
+ 0,
+ 0
+};
+
+char * db_Esc92[] = {
+ "fnop", "", "", "", "", "", "", ""
+};
+char * db_Esc93[] = {
+ "", "", "", "", "", "", "", ""
+};
+char * db_Esc94[] = {
+ "fchs", "fabs", "", "", "ftst", "fxam", "", ""
+};
+char * db_Esc95[] = {
+ "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz",""
+};
+char * db_Esc96[] = {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp",
+ "fincstp"
+};
+char * db_Esc97[] = {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"
+};
+
+char * db_Esca4[] = {
+ "", "fucompp","", "", "", "", "", ""
+};
+
+char * db_Escb4[] = {
+ "", "", "fnclex","fninit","", "", "", ""
+};
+
+char * db_Esce3[] = {
+ "", "fcompp","", "", "", "", "", ""
+};
+
+char * db_Escf4[] = {
+ "fnstsw","", "", "", "", "", "", ""
+};
+
+struct finst db_Esc8[] = {
+/*0*/ { "fadd", SNGL, op2(STI,ST), 0 },
+/*1*/ { "fmul", SNGL, op2(STI,ST), 0 },
+/*2*/ { "fcom", SNGL, op2(STI,ST), 0 },
+/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 },
+/*4*/ { "fsub", SNGL, op2(STI,ST), 0 },
+/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 },
+/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 },
+/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 },
+};
+
+struct finst db_Esc9[] = {
+/*0*/ { "fld", SNGL, op1(STI), 0 },
+/*1*/ { "", NONE, op1(STI), "fxch" },
+/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 },
+/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 },
+/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 },
+/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 },
+/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 },
+/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 },
+};
+
+struct finst db_Esca[] = {
+/*0*/ { "fiadd", WORD, 0, 0 },
+/*1*/ { "fimul", WORD, 0, 0 },
+/*2*/ { "ficom", WORD, 0, 0 },
+/*3*/ { "ficomp", WORD, 0, 0 },
+/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 },
+/*5*/ { "fisubr", WORD, 0, 0 },
+/*6*/ { "fidiv", WORD, 0, 0 },
+/*7*/ { "fidivr", WORD, 0, 0 }
+};
+
+struct finst db_Escb[] = {
+/*0*/ { "fild", WORD, 0, 0 },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fist", WORD, 0, 0 },
+/*3*/ { "fistp", WORD, 0, 0 },
+/*4*/ { "", WORD, op1(X), (char *)db_Escb4 },
+/*5*/ { "fld", EXTR, 0, 0 },
+/*6*/ { "", WORD, 0, 0 },
+/*7*/ { "fstp", EXTR, 0, 0 },
+};
+
+struct finst db_Escc[] = {
+/*0*/ { "fadd", DBLR, op2(ST,STI), 0 },
+/*1*/ { "fmul", DBLR, op2(ST,STI), 0 },
+/*2*/ { "fcom", DBLR, op2(ST,STI), 0 },
+/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 },
+/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" },
+/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" },
+/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" },
+/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" },
+};
+
+struct finst db_Escd[] = {
+/*0*/ { "fld", DBLR, op1(STI), "ffree" },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fst", DBLR, op1(STI), 0 },
+/*3*/ { "fstp", DBLR, op1(STI), 0 },
+/*4*/ { "frstor", NONE, op1(STI), "fucom" },
+/*5*/ { "", NONE, op1(STI), "fucomp" },
+/*6*/ { "fnsave", NONE, 0, 0 },
+/*7*/ { "fnstsw", NONE, 0, 0 },
+};
+
+struct finst db_Esce[] = {
+/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" },
+/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" },
+/*2*/ { "ficom", LONG, 0, 0 },
+/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 },
+/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" },
+/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" },
+/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" },
+/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" },
+};
+
+struct finst db_Escf[] = {
+/*0*/ { "fild", LONG, 0, 0 },
+/*1*/ { "", LONG, 0, 0 },
+/*2*/ { "fist", LONG, 0, 0 },
+/*3*/ { "fistp", LONG, 0, 0 },
+/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 },
+/*5*/ { "fld", QUAD, 0, 0 },
+/*6*/ { "fbstp", NONE, 0, 0 },
+/*7*/ { "fstp", QUAD, 0, 0 },
+};
+
+struct finst *db_Esc_inst[] = {
+ db_Esc8, db_Esc9, db_Esca, db_Escb,
+ db_Escc, db_Escd, db_Esce, db_Escf
+};
+
+char * db_Grp1[] = {
+ "add",
+ "or",
+ "adc",
+ "sbb",
+ "and",
+ "sub",
+ "xor",
+ "cmp"
+};
+
+char * db_Grp2[] = {
+ "rol",
+ "ror",
+ "rcl",
+ "rcr",
+ "shl",
+ "shr",
+ "shl",
+ "sar"
+};
+
+struct inst db_Grp3[] = {
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "not", TRUE, NONE, op1(E), 0 },
+ { "neg", TRUE, NONE, op1(E), 0 },
+ { "mul", TRUE, NONE, op2(E,A), 0 },
+ { "imul", TRUE, NONE, op2(E,A), 0 },
+ { "div", TRUE, NONE, op2(E,A), 0 },
+ { "idiv", TRUE, NONE, op2(E,A), 0 },
+};
+
+struct inst db_Grp4[] = {
+ { "inc", TRUE, BYTE, op1(E), 0 },
+ { "dec", TRUE, BYTE, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_Grp5[] = {
+ { "inc", TRUE, LONG, op1(E), 0 },
+ { "dec", TRUE, LONG, op1(E), 0 },
+ { "call", TRUE, NONE, op1(Eind),0 },
+ { "lcall", TRUE, NONE, op1(Eind),0 },
+ { "jmp", TRUE, NONE, op1(Eind),0 },
+ { "ljmp", TRUE, NONE, op1(Eind),0 },
+ { "push", TRUE, LONG, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_inst_table[256] = {
+/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 },
+/*01*/ { "add", TRUE, LONG, op2(R, E), 0 },
+/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 },
+/*03*/ { "add", TRUE, LONG, op2(E, R), 0 },
+/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 },
+/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 },
+/*06*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*07*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 },
+/*09*/ { "or", TRUE, LONG, op2(R, E), 0 },
+/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 },
+/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 },
+/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
+/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
+/*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+
+/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
+/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
+/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 },
+/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 },
+/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 },
+/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 },
+/*16*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*17*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 },
+/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 },
+/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 },
+/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 },
+/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 },
+/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 },
+/*1e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 },
+/*21*/ { "and", TRUE, LONG, op2(R, E), 0 },
+/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 },
+/*23*/ { "and", TRUE, LONG, op2(E, R), 0 },
+/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 },
+/*25*/ { "and", FALSE, LONG, op2(I, A), 0 },
+/*26*/ { "", FALSE, NONE, 0, 0 },
+/*27*/ { "aaa", FALSE, NONE, 0, 0 },
+
+/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 },
+/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 },
+/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 },
+/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 },
+/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 },
+/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "das", FALSE, NONE, 0, 0 },
+
+/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 },
+/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 },
+/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 },
+/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 },
+/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 },
+/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 },
+/*36*/ { "", FALSE, NONE, 0, 0 },
+/*37*/ { "daa", FALSE, NONE, 0, 0 },
+
+/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 },
+/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 },
+/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 },
+/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 },
+/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 },
+/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 },
+/*3e*/ { "", FALSE, NONE, 0, 0 },
+/*3f*/ { "aas", FALSE, NONE, 0, 0 },
+
+/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+
+/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+
+/*50*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*51*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*52*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*53*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*54*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*55*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*56*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*57*/ { "push", FALSE, LONG, op1(Ri), 0 },
+
+/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+
+/*60*/ { "pusha", FALSE, LONG, 0, 0 },
+/*61*/ { "popa", FALSE, LONG, 0, 0 },
+/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 },
+/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 },
+
+/*64*/ { "", FALSE, NONE, 0, 0 },
+/*65*/ { "", FALSE, NONE, 0, 0 },
+/*66*/ { "", FALSE, NONE, 0, 0 },
+/*67*/ { "", FALSE, NONE, 0, 0 },
+
+/*68*/ { "push", FALSE, LONG, op1(I), 0 },
+/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 },
+/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 },
+/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 },
+/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 },
+/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 },
+/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 },
+/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 },
+
+/*70*/ { "jo", FALSE, NONE, op1(Db), 0 },
+/*71*/ { "jno", FALSE, NONE, op1(Db), 0 },
+/*72*/ { "jb", FALSE, NONE, op1(Db), 0 },
+/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 },
+/*74*/ { "jz", FALSE, NONE, op1(Db), 0 },
+/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 },
+/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 },
+/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 },
+
+/*78*/ { "js", FALSE, NONE, op1(Db), 0 },
+/*79*/ { "jns", FALSE, NONE, op1(Db), 0 },
+/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 },
+/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 },
+/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 },
+/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 },
+/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
+/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
+
+/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 },
+/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 },
+/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 },
+/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 },
+/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
+/*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
+/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
+/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 },
+
+/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 },
+/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 },
+/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 },
+/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 },
+/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 },
+/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 },
+/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 },
+/*8f*/ { "pop", TRUE, LONG, op1(E), 0 },
+
+/*90*/ { "nop", FALSE, NONE, 0, 0 },
+/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+
+/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
+/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
+/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
+/*9b*/ { "wait", FALSE, NONE, 0, 0 },
+/*9c*/ { "pushf", FALSE, LONG, 0, 0 },
+/*9d*/ { "popf", FALSE, LONG, 0, 0 },
+/*9e*/ { "sahf", FALSE, NONE, 0, 0 },
+/*9f*/ { "lahf", FALSE, NONE, 0, 0 },
+
+/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 },
+/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 },
+/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 },
+/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 },
+/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 },
+/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 },
+/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 },
+/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 },
+
+/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 },
+/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 },
+/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 },
+/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 },
+/*ac*/ { "ldos", FALSE, BYTE, op1(SI), 0 },
+/*ad*/ { "ldos", FALSE, LONG, op1(SI), 0 },
+/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 },
+/*af*/ { "scas", FALSE, LONG, op1(SI), 0 },
+
+/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+
+/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+
+/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 },
+/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 },
+/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
+/*c3*/ { "ret", FALSE, NONE, 0, 0 },
+/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
+/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 },
+/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 },
+/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 },
+
+/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 },
+/*c9*/ { "leave", FALSE, NONE, 0, 0 },
+/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 },
+/*cb*/ { "lret", FALSE, NONE, 0, 0 },
+/*cc*/ { "int", FALSE, NONE, op1(o3), 0 },
+/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 },
+/*ce*/ { "into", FALSE, NONE, 0, 0 },
+/*cf*/ { "iret", FALSE, NONE, 0, 0 },
+
+/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 },
+/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 },
+/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 },
+/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 },
+/*d4*/ { "aam", TRUE, NONE, 0, 0 },
+/*d5*/ { "aad", TRUE, NONE, 0, 0 },
+/*d6*/ { "", FALSE, NONE, 0, 0 },
+/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
+
+/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 },
+/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 },
+/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca },
+/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb },
+/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc },
+/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd },
+/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce },
+/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf },
+
+/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
+/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
+/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
+/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
+/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
+/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
+/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
+/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 },
+
+/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 },
+/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 },
+/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 },
+/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 },
+/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 },
+/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 },
+/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 },
+/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 },
+
+/*f0*/ { "", FALSE, NONE, 0, 0 },
+/*f1*/ { "", FALSE, NONE, 0, 0 },
+/*f2*/ { "", FALSE, NONE, 0, 0 },
+/*f3*/ { "", FALSE, NONE, 0, 0 },
+/*f4*/ { "hlt", FALSE, NONE, 0, 0 },
+/*f5*/ { "cmc", FALSE, NONE, 0, 0 },
+/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 },
+/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 },
+
+/*f8*/ { "clc", FALSE, NONE, 0, 0 },
+/*f9*/ { "stc", FALSE, NONE, 0, 0 },
+/*fa*/ { "cli", FALSE, NONE, 0, 0 },
+/*fb*/ { "sti", FALSE, NONE, 0, 0 },
+/*fc*/ { "cld", FALSE, NONE, 0, 0 },
+/*fd*/ { "std", FALSE, NONE, 0, 0 },
+/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 },
+/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 },
+};
+
+struct inst db_bad_inst =
+ { "???", FALSE, NONE, 0, 0 }
+;
+
+#define f_mod(byte) ((byte)>>6)
+#define f_reg(byte) (((byte)>>3)&0x7)
+#define f_rm(byte) ((byte)&0x7)
+
+#define sib_ss(byte) ((byte)>>6)
+#define sib_index(byte) (((byte)>>3)&0x7)
+#define sib_base(byte) ((byte)&0x7)
+
+struct i_addr {
+ int is_reg; /* if reg, reg number is in 'disp' */
+ int disp;
+ char * base;
+ char * index;
+ int ss;
+};
+
+char * db_index_reg_16[8] = {
+ "%bx,%si",
+ "%bx,%di",
+ "%bp,%si",
+ "%bp,%di",
+ "%si",
+ "%di",
+ "%bp",
+ "%bx"
+};
+
+char * db_reg[3][8] = {
+ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
+ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"
+};
+
+char * db_seg_reg[8] = {
+ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", ""
+};
+
+/*
+ * lengths for size attributes
+ */
+int db_lengths[] = {
+ 1, /* BYTE */
+ 2, /* WORD */
+ 4, /* LONG */
+ 8, /* QUAD */
+ 4, /* SNGL */
+ 8, /* DBLR */
+ 10, /* EXTR */
+};
+
+#define get_value_inc(result, loc, size, is_signed) \
+ result = db_get_value((loc), (size), (is_signed)); \
+ (loc) += (size);
+
+/*
+ * Read address at location and return updated location.
+ */
+db_addr_t
+db_read_address(loc, short_addr, regmodrm, addrp)
+ db_addr_t loc;
+ int short_addr;
+ int regmodrm;
+ struct i_addr *addrp; /* out */
+{
+ int mod, rm, sib, index, ss, disp;
+
+ mod = f_mod(regmodrm);
+ rm = f_rm(regmodrm);
+
+ if (mod == 3) {
+ addrp->is_reg = TRUE;
+ addrp->disp = rm;
+ return (loc);
+ }
+ addrp->is_reg = FALSE;
+ addrp->index = 0;
+
+ if (short_addr) {
+ addrp->index = 0;
+ addrp->ss = 0;
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_index_reg_16[rm];
+ }
+ break;
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ case 2:
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ }
+ }
+ else {
+ if (mod != 3 && rm == 4) {
+ get_value_inc(sib, loc, 1, FALSE);
+ rm = sib_base(sib);
+ index = sib_index(sib);
+ if (index != 4)
+ addrp->index = db_reg[LONG][index];
+ addrp->ss = sib_ss(sib);
+ }
+
+ switch (mod) {
+ case 0:
+ if (rm == 5) {
+ get_value_inc(addrp->disp, loc, 4, FALSE);
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_reg[LONG][rm];
+ }
+ break;
+
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+
+ case 2:
+ get_value_inc(disp, loc, 4, FALSE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+ }
+ }
+ return (loc);
+}
+
+void
+db_print_address(seg, size, addrp)
+ char * seg;
+ int size;
+ struct i_addr *addrp;
+{
+ if (addrp->is_reg) {
+ db_printf("%s", db_reg[size][addrp->disp]);
+ return;
+ }
+
+ if (seg) {
+ db_printf("%s:", seg);
+ }
+
+ db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY);
+ if (addrp->base != 0 || addrp->index != 0) {
+ db_printf("(");
+ if (addrp->base)
+ db_printf("%s", addrp->base);
+ if (addrp->index)
+ db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
+ db_printf(")");
+ }
+}
+
+/*
+ * Disassemble floating-point ("escape") instruction
+ * and return updated location.
+ */
+db_addr_t
+db_disasm_esc(loc, inst, short_addr, size, seg)
+ db_addr_t loc;
+ int inst;
+ int short_addr;
+ int size;
+ char * seg;
+{
+ int regmodrm;
+ struct finst *fp;
+ int mod;
+ struct i_addr address;
+ char * name;
+
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)];
+ mod = f_mod(regmodrm);
+ if (mod != 3) {
+ /*
+ * Normal address modes.
+ */
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ db_printf(fp->f_name);
+ switch(fp->f_size) {
+ case SNGL:
+ db_printf("s");
+ break;
+ case DBLR:
+ db_printf("l");
+ break;
+ case EXTR:
+ db_printf("t");
+ break;
+ case WORD:
+ db_printf("s");
+ break;
+ case LONG:
+ db_printf("l");
+ break;
+ case QUAD:
+ db_printf("q");
+ break;
+ default:
+ break;
+ }
+ db_printf("\t");
+ db_print_address(seg, BYTE, &address);
+ }
+ else {
+ /*
+ * 'reg-reg' - special formats
+ */
+ switch (fp->f_rrmode) {
+ case op2(ST,STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
+ break;
+ case op2(STI,ST):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
+ break;
+ case op1(STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d)",name, f_rm(regmodrm));
+ break;
+ case op1(X):
+ db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ case op1(XA):
+ db_printf("%s\t%%ax",
+ ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ default:
+ db_printf("<bad instruction>");
+ break;
+ }
+ }
+
+ return (loc);
+}
+
+/*
+ * Disassemble instruction at 'loc'. 'altfmt' specifies an
+ * (optional) alternate format. Return address of start of
+ * next instruction.
+ */
+db_addr_t
+db_disasm(loc, altfmt)
+ db_addr_t loc;
+ boolean_t altfmt;
+{
+ int inst;
+ int size;
+ int short_addr;
+ char * seg;
+ struct inst * ip;
+ char * i_name;
+ int i_size;
+ int i_mode;
+ int regmodrm;
+ boolean_t first;
+ int displ;
+ int prefix;
+ int imm;
+ int imm2;
+ int len;
+ struct i_addr address;
+
+ get_value_inc(inst, loc, 1, FALSE);
+ short_addr = FALSE;
+ size = LONG;
+ seg = 0;
+
+ /*
+ * Get prefixes
+ */
+ prefix = TRUE;
+ do {
+ switch (inst) {
+ case 0x66: /* data16 */
+ size = WORD;
+ break;
+ case 0x67:
+ short_addr = TRUE;
+ break;
+ case 0x26:
+ seg = "%es";
+ break;
+ case 0x36:
+ seg = "%ss";
+ break;
+ case 0x2e:
+ seg = "%cs";
+ break;
+ case 0x3e:
+ seg = "%ds";
+ break;
+ case 0x64:
+ seg = "%fs";
+ break;
+ case 0x65:
+ seg = "%gs";
+ break;
+ case 0xf0:
+ db_printf("lock ");
+ break;
+ case 0xf2:
+ db_printf("repne ");
+ break;
+ case 0xf3:
+ db_printf("repe "); /* XXX repe VS rep */
+ break;
+ default:
+ prefix = FALSE;
+ break;
+ }
+ if (prefix) {
+ get_value_inc(inst, loc, 1, FALSE);
+ }
+ } while (prefix);
+
+ if (inst >= 0xd8 && inst <= 0xdf) {
+ loc = db_disasm_esc(loc, inst, short_addr, size, seg);
+ db_printf("\n");
+ return (loc);
+ }
+
+ if (inst == 0x0f) {
+ get_value_inc(inst, loc, 1, FALSE);
+ ip = db_inst_0f[inst>>4];
+ if (ip == 0) {
+ ip = &db_bad_inst;
+ }
+ else {
+ ip = &ip[inst&0xf];
+ }
+ }
+ else
+ ip = &db_inst_table[inst];
+
+ if (ip->i_has_modrm) {
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ }
+
+ i_name = ip->i_name;
+ i_size = ip->i_size;
+ i_mode = ip->i_mode;
+
+ if (ip->i_extra == (char *)db_Grp1 ||
+ ip->i_extra == (char *)db_Grp2 ||
+ ip->i_extra == (char *)db_Grp6 ||
+ ip->i_extra == (char *)db_Grp7 ||
+ ip->i_extra == (char *)db_Grp8) {
+ i_name = ((char **)ip->i_extra)[f_reg(regmodrm)];
+ }
+ else if (ip->i_extra == (char *)db_Grp3) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ }
+ else if (ip->i_extra == (char *)db_Grp4 ||
+ ip->i_extra == (char *)db_Grp5) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ i_size = ip->i_size;
+ }
+
+ if (i_size == SDEP) {
+ if (size == WORD)
+ db_printf(i_name);
+ else
+ db_printf(ip->i_extra);
+ }
+ else {
+ db_printf(i_name);
+ if (i_size != NONE) {
+ if (i_size == BYTE) {
+ db_printf("b");
+ size = BYTE;
+ }
+ else if (i_size == WORD) {
+ db_printf("w");
+ size = WORD;
+ }
+ else if (size == WORD)
+ db_printf("w");
+ else
+ db_printf("l");
+ }
+ }
+ db_printf("\t");
+ for (first = TRUE;
+ i_mode != 0;
+ i_mode >>= 8, first = FALSE)
+ {
+ if (!first)
+ db_printf(",");
+
+ switch (i_mode & 0xFF) {
+
+ case E:
+ db_print_address(seg, size, &address);
+ break;
+
+ case Eind:
+ db_printf("*");
+ db_print_address(seg, size, &address);
+ break;
+
+ case Ew:
+ db_print_address(seg, WORD, &address);
+ break;
+
+ case Eb:
+ db_print_address(seg, BYTE, &address);
+ break;
+
+ case R:
+ db_printf("%s", db_reg[size][f_reg(regmodrm)]);
+ break;
+
+ case Rw:
+ db_printf("%s", db_reg[WORD][f_reg(regmodrm)]);
+ break;
+
+ case Ri:
+ db_printf("%s", db_reg[size][f_rm(inst)]);
+ break;
+
+ case S:
+ db_printf("%s", db_seg_reg[f_reg(regmodrm)]);
+ break;
+
+ case Si:
+ db_printf("%s", db_seg_reg[f_reg(inst)]);
+ break;
+
+ case A:
+ db_printf("%s", db_reg[size][0]); /* acc */
+ break;
+
+ case BX:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%bx" : "%ebx");
+ break;
+
+ case CL:
+ db_printf("%%cl");
+ break;
+
+ case DX:
+ db_printf("%%dx");
+ break;
+
+ case SI:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%si" : "%esi");
+ break;
+
+ case DI:
+ db_printf("%%es:(%s)", short_addr ? "%di" : "%edi");
+ break;
+
+ case CR:
+ db_printf("%%cr%d", f_reg(regmodrm));
+ break;
+
+ case DR:
+ db_printf("%%dr%d", f_reg(regmodrm));
+ break;
+
+ case TR:
+ db_printf("%%tr%d", f_reg(regmodrm));
+ break;
+
+ case I:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, FALSE);/* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Is:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Ib:
+ get_value_inc(imm, loc, 1, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Ibs:
+ get_value_inc(imm, loc, 1, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Iw:
+ get_value_inc(imm, loc, 2, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Il:
+ get_value_inc(imm, loc, 4, FALSE);
+ db_printf("$%#n", imm);
+ break;
+
+ case O:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE);
+ }
+ if (seg)
+ db_printf("%s:%#r",seg, displ);
+ else
+ db_printsym((db_addr_t)displ, DB_STGY_ANY);
+ break;
+
+ case Db:
+ get_value_inc(displ, loc, 1, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case Dl:
+ get_value_inc(displ, loc, 4, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case o1:
+ db_printf("$1");
+ break;
+
+ case o3:
+ db_printf("$3");
+ break;
+
+ case OS:
+ get_value_inc(imm, loc, 4, FALSE); /* offset */
+ get_value_inc(imm2, loc, 2, FALSE); /* segment */
+ db_printf("$%#n,%#n", imm2, imm);
+ break;
+ }
+ }
+
+ if (altfmt == 0) {
+ if (inst == 0xe9 || inst == 0xeb) {
+ /*
+ * GAS pads to longword boundary after unconditional jumps.
+ */
+ loc = (loc + (4-1)) & ~(4-1);
+ }
+ }
+ db_printf("\n");
+ return (loc);
+}
+
diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c
new file mode 100644
index 0000000..31e7849
--- /dev/null
+++ b/sys/amd64/amd64/db_interface.c
@@ -0,0 +1,255 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_interface.c,v $
+ * Revision 1.1 1992/03/25 21:42:03 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/05 17:11:13 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:17 mrt]
+ *
+ * Revision 2.3 90/12/04 14:45:55 jsb
+ * Changes for merged intel/pmap.{c,h}.
+ * [90/12/04 11:14:41 jsb]
+ *
+ * Revision 2.2 90/10/25 14:44:43 rwd
+ * Added watchpoint support.
+ * [90/10/18 rpd]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ *
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <sys/reboot.h>
+#include <vm/vm_statistics.h>
+#include <vm/pmap.h>
+
+#include <setjmp.h>
+#include <sys/systm.h> /* just for boothowto --eichin */
+int db_active = 0;
+
+/*
+ * Received keyboard interrupt sequence.
+ */
+kdb_kbd_trap(regs)
+ struct i386_saved_state *regs;
+{
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ kdb_trap(-1, 0, regs);
+ }
+}
+
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+
+static jmp_buf *db_nofault = 0;
+
+kdb_trap(type, code, regs)
+ int type, code;
+ register struct i386_saved_state *regs;
+{
+#if 0
+ if ((boothowto&RB_KDB) == 0)
+ return(0);
+#endif
+
+ switch (type) {
+ case T_BPTFLT /* T_INT3 */: /* breakpoint */
+ case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */
+ case T_PRIVINFLT /* T_DEBUG */: /* single_step */
+
+ case -1: /* keyboard interrupt */
+ break;
+
+ default:
+ kdbprinttrap(type, code);
+
+ if (db_nofault) {
+ jmp_buf *no_fault = db_nofault;
+ db_nofault = 0;
+ longjmp(*no_fault, 1);
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ if ((regs->tf_cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ ddb_regs.tf_esp = (int)&regs->tf_esp; /* kernel stack pointer */
+#if 0
+ ddb_regs.ss = KERNEL_DS;
+#endif
+ asm(" movw %%ss,%%ax; movl %%eax,%0 "
+ : "=g" (ddb_regs.tf_ss)
+ :
+ : "ax");
+ }
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, code);
+ cnpollc(FALSE);
+ db_active--;
+
+ regs->tf_eip = ddb_regs.tf_eip;
+ regs->tf_eflags = ddb_regs.tf_eflags;
+ regs->tf_eax = ddb_regs.tf_eax;
+ regs->tf_ecx = ddb_regs.tf_ecx;
+ regs->tf_edx = ddb_regs.tf_edx;
+ regs->tf_ebx = ddb_regs.tf_ebx;
+ if (regs->tf_cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */
+ regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */
+ }
+ regs->tf_ebp = ddb_regs.tf_ebp;
+ regs->tf_esi = ddb_regs.tf_esi;
+ regs->tf_edi = ddb_regs.tf_edi;
+ regs->tf_es = ddb_regs.tf_es & 0xffff;
+ regs->tf_cs = ddb_regs.tf_cs & 0xffff;
+ regs->tf_ds = ddb_regs.tf_ds & 0xffff;
+#if 0
+ regs->tf_fs = ddb_regs.tf_fs & 0xffff;
+ regs->tf_gs = ddb_regs.tf_gs & 0xffff;
+#endif
+
+ return (1);
+}
+
+/*
+ * Print trap reason.
+ */
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ printf("type %d", type);
+ printf(" trap, code=%x\n", code);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+
+extern jmp_buf db_jmpbuf;
+
+void
+db_read_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *src;
+
+ db_nofault = &db_jmpbuf;
+
+ src = (char *)addr;
+ while (--size >= 0)
+ *data++ = *src++;
+
+ db_nofault = 0;
+}
+
+struct pte *pmap_pte(pmap_t, vm_offset_t);
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *dst;
+
+ register pt_entry_t *ptep0 = 0;
+ pt_entry_t oldmap0 = { 0 };
+ vm_offset_t addr1;
+ register pt_entry_t *ptep1 = 0;
+ pt_entry_t oldmap1 = { 0 };
+ extern char etext;
+
+ db_nofault = &db_jmpbuf;
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS &&
+ addr <= (vm_offset_t)&etext)
+ {
+ ptep0 = pmap_pte(kernel_pmap, addr);
+ oldmap0 = *ptep0;
+ *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW;
+
+ addr1 = i386_trunc_page(addr + size - 1);
+ if (i386_trunc_page(addr) != addr1) {
+ /* data crosses a page boundary */
+
+ ptep1 = pmap_pte(kernel_pmap, addr1);
+ oldmap1 = *ptep1;
+ *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW;
+ }
+ tlbflush();
+ }
+
+ dst = (char *)addr;
+
+ while (--size >= 0)
+ *dst++ = *data++;
+
+ db_nofault = 0;
+
+ if (ptep0) {
+ *ptep0 = oldmap0;
+ if (ptep1) {
+ *ptep1 = oldmap1;
+ }
+ tlbflush();
+ }
+}
+
+Debugger (msg)
+char *msg;
+{
+ asm ("int $3");
+}
diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c
new file mode 100644
index 0000000..cbffbbc
--- /dev/null
+++ b/sys/amd64/amd64/db_trace.c
@@ -0,0 +1,292 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_trace.c,v $
+ * Revision 1.1 1992/03/25 21:42:05 pace
+ * Initial revision
+ *
+ * Revision 2.6 91/02/05 17:11:21 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:32 mrt]
+ *
+ * Revision 2.5 91/01/09 19:55:27 rpd
+ * Fixed stack tracing for threads without kernel stacks.
+ * [91/01/09 rpd]
+ *
+ * Revision 2.4 91/01/08 15:10:22 rpd
+ * Reorganized the pcb.
+ * [90/12/11 rpd]
+ *
+ * Revision 2.3 90/11/05 14:27:07 rpd
+ * If we can not guess the number of args to a function, use 5 vs 0.
+ * [90/11/02 rvb]
+ *
+ * Revision 2.2 90/08/27 21:56:20 dbg
+ * Import db_sym.h.
+ * [90/08/21 dbg]
+ * Fix includes.
+ * [90/08/08 dbg]
+ * Created from rvb's code for new debugger.
+ * [90/07/11 dbg]
+ *
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+ "cs", (int *)&ddb_regs.tf_cs, FCN_NULL,
+ "ds", (int *)&ddb_regs.tf_ds, FCN_NULL,
+ "es", (int *)&ddb_regs.tf_es, FCN_NULL,
+#if 0
+ "fs", (int *)&ddb_regs.tf_fs, FCN_NULL,
+ "gs", (int *)&ddb_regs.tf_gs, FCN_NULL,
+#endif
+ "ss", (int *)&ddb_regs.tf_ss, FCN_NULL,
+ "eax", (int *)&ddb_regs.tf_eax, FCN_NULL,
+ "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL,
+ "edx", (int *)&ddb_regs.tf_edx, FCN_NULL,
+ "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL,
+ "esp", (int *)&ddb_regs.tf_esp,FCN_NULL,
+ "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL,
+ "esi", (int *)&ddb_regs.tf_esi, FCN_NULL,
+ "edi", (int *)&ddb_regs.tf_edi, FCN_NULL,
+ "eip", (int *)&ddb_regs.tf_eip, FCN_NULL,
+ "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL,
+};
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Stack trace.
+ */
+#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+struct i386_frame {
+ struct i386_frame *f_frame;
+ int f_retaddr;
+ int f_arg0;
+};
+
+#define TRAP 1
+#define INTERRUPT 2
+
+db_addr_t db_trap_symbol_value = 0;
+db_addr_t db_kdintr_symbol_value = 0;
+boolean_t db_trace_symbols_found = FALSE;
+
+void
+db_find_trace_symbols()
+{
+ db_expr_t value;
+ if (db_value_of_name("_trap", &value))
+ db_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_kdintr", &value))
+ db_kdintr_symbol_value = (db_addr_t) value;
+ db_trace_symbols_found = TRUE;
+}
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+int
+db_numargs(fp)
+ struct i386_frame *fp;
+{
+ int *argp;
+ int inst;
+ int args;
+ extern char etext[];
+
+ argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
+ if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
+ args = 5;
+ else {
+ inst = db_get_value((int)argp, 4, FALSE);
+ if ((inst & 0xff) == 0x59) /* popl %ecx */
+ args = 1;
+ else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
+ args = ((inst >> 16) & 0xff) / 4;
+ else
+ args = 5;
+ }
+ return (args);
+}
+
+/*
+ * Figure out the next frame up in the call stack.
+ * For trap(), we print the address of the faulting instruction and
+ * proceed with the calling frame. We return the ip that faulted.
+ * If the trap was caused by jumping through a bogus pointer, then
+ * the next line in the backtrace will list some random function as
+ * being called. It should get the argument list correct, though.
+ * It might be possible to dig out from the next frame up the name
+ * of the function that faulted, but that could get hairy.
+ */
+void
+db_nextframe(fp, ip, argp, is_trap)
+ struct i386_frame **fp; /* in/out */
+ db_addr_t *ip; /* out */
+ int *argp; /* in */
+ int is_trap; /* in */
+{
+ struct i386_saved_state *saved_regs;
+
+ if (is_trap == 0) {
+ *ip = (db_addr_t)
+ db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
+ *fp = (struct i386_frame *)
+ db_get_value((int) &(*fp)->f_frame, 4, FALSE);
+ } else {
+ /*
+ * We know that trap() has 1 argument and we know that
+ * it is an (int *).
+ */
+ saved_regs = (struct i386_saved_state *)
+ db_get_value((int)argp, 4, FALSE);
+ db_printf("--- trap (number %d) ---\n",
+ saved_regs->tf_trapno & 0xffff);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ }
+
+}
+
+void
+db_stack_trace_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct i386_frame *frame, *lastframe;
+ int *argp;
+ db_addr_t callpc;
+ int is_trap;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+
+ if (!db_trace_symbols_found)
+ db_find_trace_symbols();
+
+ {
+ register char *cp = modif;
+ register char c;
+
+ while ((c = *cp++) != 0) {
+ if (c == 't')
+ trace_thread = TRUE;
+ if (c == 'u')
+ kernel_only = FALSE;
+ }
+ }
+
+ if (count == -1)
+ count = 65535;
+
+ if (!have_addr) {
+ frame = (struct i386_frame *)ddb_regs.tf_ebp;
+ callpc = (db_addr_t)ddb_regs.tf_eip;
+ }
+ else if (trace_thread) {
+ printf ("db_trace.c: can't trace thread\n");
+ }
+ else {
+ frame = (struct i386_frame *)addr;
+ callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
+ }
+
+ lastframe = 0;
+ while (count-- && frame != 0) {
+ register int narg;
+ char * name;
+ db_expr_t offset;
+
+ if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) {
+ narg = 1;
+ is_trap = TRAP;
+ }
+ else
+ if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) {
+ is_trap = INTERRUPT;
+ narg = 0;
+ }
+ else {
+ is_trap = 0;
+ narg = db_numargs(frame);
+ }
+
+ db_find_sym_and_offset(callpc, &name, &offset);
+ db_printf("%s(", name);
+
+ argp = &frame->f_arg0;
+ while (narg) {
+ db_printf("%x", db_get_value((int)argp, 4, FALSE));
+ argp++;
+ if (--narg != 0)
+ db_printf(",");
+ }
+ db_printf(") at ");
+ db_printsym(callpc, DB_STGY_XTRN);
+ db_printf("\n");
+
+ lastframe = frame;
+ db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
+
+ if (frame == 0) {
+ /* end of chain */
+ break;
+ }
+ if (INKERNEL((int)frame)) {
+ /* staying in kernel */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ else if (INKERNEL((int)lastframe)) {
+ /* switch from user to kernel */
+ if (kernel_only)
+ break; /* kernel stack only */
+ }
+ else {
+ /* in user */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
new file mode 100644
index 0000000..73392fa
--- /dev/null
+++ b/sys/amd64/amd64/fpu.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 23 May 93 Rodney W. Grimes Return a special value of -1 from
+ * the probe code to keep isa_config from
+ * printing out the I/O address when we
+ * are using trap 16 handling.
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $";
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0mask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al /* EOI (asm in strings loses cpp features) */
+ outb %al,$0xa0 /* IO_ICU2 */
+ outb %al,$0x20 /* IO_ICU1 */
+ movb $0,%al
+ outb %al,$0xf0 /* clear BUSY# latch */
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0mask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ return (IO_NPXSIZE);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (npx_ex16)
+ printf(" <Errors reported via Exception 16>");
+ else if (npx_irq13)
+ printf(" <Errors reported via IRQ 13>");
+ else if (npx_exists)
+ printf(" <Error reporting broken, using 387 emulator>");
+ else
+ printf(" <387 Emulator>");
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ curpcb->pcb_flags &= ~FM_TRAP;
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0mask >> 8))
+ | (old_icu2_mask & (npx0mask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
new file mode 100644
index 0000000..18ec37b
--- /dev/null
+++ b/sys/amd64/amd64/genassym.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)genassym.c 5.11 (Berkeley) 5/10/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 24 Apr 93 Bruce Evans/Dave Rivers Npx-0.5 support
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/genassym.c,v 1.2 92/01/21 14:22:02 william Exp $";
+
+#ifndef lint
+static char sccsid[] = "@(#)genassym.c 5.11 (Berkeley) 5/10/91";
+#endif /* not lint */
+
+#include "sys/param.h"
+#include "sys/buf.h"
+#include "sys/vmmeter.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/mbuf.h"
+#include "sys/msgbuf.h"
+#include "sys/resourcevar.h"
+#include "machine/cpu.h"
+#include "machine/trap.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "sys/syscall.h"
+#include "vm/vm_param.h"
+#include "vm/vm_map.h"
+#include "machine/pmap.h"
+
+main()
+{
+ struct proc *p = (struct proc *)0;
+ struct vmmeter *vm = (struct vmmeter *)0;
+ struct user *up = (struct user *)0;
+ struct rusage *rup = (struct rusage *)0;
+ struct uprof *uprof = (struct uprof *)0;
+ struct vmspace *vms = (struct vmspace *)0;
+ vm_map_t map = (vm_map_t)0;
+ pmap_t pmap = (pmap_t)0;
+ struct pcb *pcb = (struct pcb *)0;
+ register unsigned i;
+
+ printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT);
+ printf("#define\tUDOT_SZ %d\n", sizeof(struct user));
+ printf("#define\tP_LINK %d\n", &p->p_link);
+ printf("#define\tP_RLINK %d\n", &p->p_rlink);
+ printf("#define\tP_VMSPACE %d\n", &p->p_vmspace);
+ printf("#define\tVM_PMAP %d\n", &vms->vm_pmap);
+ printf("#define\tP_ADDR %d\n", &p->p_addr);
+ printf("#define\tP_PRI %d\n", &p->p_pri);
+ printf("#define\tP_STAT %d\n", &p->p_stat);
+ printf("#define\tP_WCHAN %d\n", &p->p_wchan);
+ printf("#define\tP_FLAG %d\n", &p->p_flag);
+ printf("#define\tP_PID %d\n", &p->p_pid);
+ printf("#define\tSSLEEP %d\n", SSLEEP);
+ printf("#define\tSRUN %d\n", SRUN);
+ printf("#define\tV_SWTCH %d\n", &vm->v_swtch);
+ printf("#define\tV_TRAP %d\n", &vm->v_trap);
+ printf("#define\tV_SYSCALL %d\n", &vm->v_syscall);
+ printf("#define\tV_INTR %d\n", &vm->v_intr);
+ printf("#define\tV_SOFT %d\n", &vm->v_soft);
+ printf("#define\tV_PDMA %d\n", &vm->v_pdma);
+ printf("#define\tV_FAULTS %d\n", &vm->v_faults);
+ printf("#define\tV_PGREC %d\n", &vm->v_pgrec);
+ printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec);
+ printf("#define\tUPAGES %d\n", UPAGES);
+ printf("#define\tHIGHPAGES %d\n", HIGHPAGES);
+ printf("#define\tCLSIZE %d\n", CLSIZE);
+ printf("#define\tNBPG %d\n", NBPG);
+ printf("#define\tNPTEPG %d\n", NPTEPG);
+ printf("#define\tPGSHIFT %d\n", PGSHIFT);
+ printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE);
+ printf("#define\tUSRPTSIZE %d\n", USRPTSIZE);
+ printf("#define\tUSRIOSIZE %d\n", USRIOSIZE);
+#ifdef SYSVSHM
+ printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS);
+#endif
+ printf("#define\tUSRSTACK %d\n", USRSTACK);
+ printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf)));
+ printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS);
+ printf("#define\tMCLBYTES %d\n", MCLBYTES);
+ printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link);
+ printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0);
+ printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0);
+ printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1);
+ printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1);
+ printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2);
+ printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2);
+ printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3);
+ printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip);
+ printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags);
+ printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax);
+ printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx);
+ printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx);
+ printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx);
+ printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp);
+ printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp);
+ printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi);
+ printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi);
+ printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es);
+ printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs);
+ printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss);
+ printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds);
+ printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs);
+ printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs);
+ printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt);
+ printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt);
+ printf("#define\tNKMEMCLUSTERS %d\n", NKMEMCLUSTERS);
+ printf("#define\tU_PROF %d\n", &up->u_stats.p_prof);
+ printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale);
+ printf("#define\tPR_BASE %d\n", &uprof->pr_base);
+ printf("#define\tPR_SIZE %d\n", &uprof->pr_size);
+ printf("#define\tPR_OFF %d\n", &uprof->pr_off);
+ printf("#define\tPR_SCALE %d\n", &uprof->pr_scale);
+ printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt);
+ printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags);
+ printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu);
+#ifdef notused
+ printf("#define\tFP_WASUSED %d\n", FP_WASUSED);
+ printf("#define\tFP_NEEDSSAVE %d\n", FP_NEEDSSAVE);
+ printf("#define\tFP_NEEDSRESTORE %d\n", FP_NEEDSRESTORE);
+#endif
+ printf("#define\tFP_USESEMC %d\n", FP_USESEMC);
+ printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc);
+ printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2);
+ printf("#define\tPCB_SIGC %d\n", pcb->pcb_sigc);
+ printf("#define\tPCB_IML %d\n", &pcb->pcb_iml);
+ printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault);
+
+ printf("#define\tB_READ %d\n", B_READ);
+ printf("#define\tENOENT %d\n", ENOENT);
+ printf("#define\tEFAULT %d\n", EFAULT);
+ printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG);
+ exit(0);
+}
diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S
new file mode 100644
index 0000000..d558dba
--- /dev/null
+++ b/sys/amd64/amd64/locore.S
@@ -0,0 +1,1830 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)locore.s 7.3 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped
+ * 28 Nov 92 Frank MacLachlan Aligned addresses and data
+ * on 32bit boundaries.
+ * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1)
+ */
+
+
+/*
+ * locore.s: 4BSD machine support for the Intel 386
+ * Preliminary version
+ * Written by William F. Jolitz, 386BSD Project
+ */
+
+#include "assym.s"
+#include "machine/psl.h"
+#include "machine/pte.h"
+
+#include "errno.h"
+
+#include "machine/trap.h"
+
+#include "machine/specialreg.h"
+#include "i386/isa/debug.h"
+
+#define KDSEL 0x10
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+/*
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+ .set IDXSHIFT,10
+ .set SYSTEM,0xFE000000 # virtual address of system start
+ /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */
+ .set SYSPDROFF,0x3F8 # Page dir index of System Base
+
+#define ALIGN_DATA .align 2
+#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */
+#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */
+
+/* NB: NOP now preserves registers so NOPs can be inserted anywhere */
+/* XXX: NOP and FASTER_NOP are misleadingly named */
+#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */
+#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax
+#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax
+#else
+#define FASTER_NOP
+#define NOP
+#endif
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .set PDRPDROFF,0x3F7 # Page dir index of Page dir
+ .globl _PTmap, _PTD, _PTDpde, _Sysmap
+ .set _PTmap,0xFDC00000
+ .set _PTD,0xFDFF7000
+ .set _Sysmap,0xFDFF8000
+ .set _PTDpde,0xFDFF7000+4*PDRPDROFF
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .set APDRPDROFF,0x3FE # Page dir index of Page dir
+ .globl _APTmap, _APTD, _APTDpde
+ .set _APTmap,0xFF800000
+ .set _APTD,0xFFBFE000
+ .set _APTDpde,0xFDFF7000+4*APDRPDROFF
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack, USRSTACK
+ .globl _kstack
+ .set PPDROFF,0x3F6
+ .set PPTEOFF,0x400-UPAGES # 0x3FE
+
+#define ENTRY(name) \
+ .globl _/**/name; ALIGN_TEXT; _/**/name:
+#define ALTENTRY(name) ENTRY(name)
+
+/*
+ * Initialization
+ */
+ .data
+ .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys
+_cpu: .long 0 # are we 386, 386sx, or 486
+_cold: .long 1 # cold till we are not
+_atdevbase: .long 0 # location of start of iomem in virtual
+_atdevphys: .long 0 # location of device mapping ptes (phys)
+
+ .globl _IdlePTD, _KPTphys
+_IdlePTD: .long 0
+_KPTphys: .long 0
+
+ .space 512
+tmpstk:
+ .text
+ .globl start
+start: movw $0x1234,%ax
+ movw %ax,0x472 # warm boot
+ jmp 1f
+ .space 0x500 # skip over warm boot shit
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-SYSTEM
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-SYSTEM
+ movl 12(%esp),%eax
+ movl %eax, _cyloffset-SYSTEM
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location
+
+#ifdef garbage
+ /* count up memory */
+
+ xorl %eax,%eax # start with base memory at 0x0
+ #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K
+ movl $ 0xA0,%ecx # look every 4K up to 640K
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+
+ movl $0x100000,%eax # next, talley remaining memory
+ #movl $((0xFFF000-0x100000)/NBPG),%ecx
+ movl $(0xFFF-0x100),%ecx
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+#endif
+
+/* find end of kernel image */
+ movl $_end-SYSTEM,%ecx
+ addl $ NBPG-1,%ecx
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi
+
+/* clear bss and memory for bootstrap pagetables. */
+ movl $_edata-SYSTEM,%edi
+ subl %edi,%ecx
+ addl $(UPAGES+5)*NBPG,%ecx
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * 0 1 2 3 4
+ */
+ xorl %eax,%eax # pattern
+ cld
+ rep
+ stosb
+
+ movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */
+
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $ NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ * N.B. don't bother with making kernel text RO, as 386
+ * ignores R/W AND U/S bits on kernel access (only v works) !
+ *
+ * First step - build page tables
+ */
+ movl %esi,%ecx # this much memory,
+ shrl $ PGSHIFT,%ecx # for this many pte s
+ addl $ UPAGES+4,%ecx # including our early context
+ movl $0xa0,%ecx # XXX - cover debugger pages
+ movl $PG_V|PG_KW,%eax # having these bits set,
+ lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0,
+ movl %ebx,_KPTphys-SYSTEM # in the kernel page table,
+ fillkpt
+
+/* map I/O memory map */
+
+ movl $0x100-0xa0,%ecx # for this many pte s,
+ movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92
+ movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $ UPAGES,%ecx # for this many pte s,
+ lea (1*NBPG)(%esi),%eax # physical address in proc 0
+ lea (SYSTEM)(%eax),%edx
+ movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init
+ orl $PG_V|PG_KW,%eax # having these bits set,
+ lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0
+ addl $(PPTEOFF*4),%ebx
+ fillkpt
+
+/*
+ * Construct a page table directory
+ * (of page directory elements - pde's)
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ lea (4*NBPG)(%esi),%eax # physical address of kernel page table
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax,(%esi) # which is where temp maps!
+
+ /* kernel pde's */
+ movl $ 3,%ecx # for this many pde s,
+ lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps!
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0
+ orl $PG_V|PG_KW,%eax # pde entry is valid
+ movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps!
+
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 # XXX - debugger signature
+ jne 1f
+ movb $1,_bdb_exists-SYSTEM
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi # base address of current gdt
+ movl $_gdt-SYSTEM,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep # copy gdt
+ movsl
+ movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi # base address of current idt
+ movl 8+4(%esi),%eax # convert dbg descriptor to ...
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ...
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp
+ movl 24+4(%esi),%eax # same for bpt descriptor
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-SYSTEM
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-SYSTEM
+
+ movl $_idt-SYSTEM,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep # copy idt
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+
+ /* load base of page directory, and enable mapping */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3 # load ptd addr into mmu
+ movl %cr0,%eax # get control word
+#ifdef USE_486_WRITE_PROTECT
+ orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page!
+#else
+ orl $CR0_PE|CR0_PG,%eax # and let s page!
+#endif
+ movl %eax,%cr0 # NOW!
+
+ pushl $begin # jump to high mem!
+ ret
+
+begin: /* now running relocated at SYSTEM where the system is linked to run */
+
+ .globl _Crtat
+ movl _Crtat,%eax
+ subl $0xfe0a0000,%eax
+ movl _atdevphys,%edx # get pte PA
+ subl _KPTphys,%edx # remove base of ptes, now have phys offset
+ shll $ PGSHIFT-2,%edx # corresponding to virt offset
+ addl $ SYSTEM,%edx # add virtual base
+ movl %edx, _atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack */
+ movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location
+ xorl %eax,%eax # mark end of frames
+ movl %eax,%ebp
+ movl _proc0paddr, %eax
+ movl %esi, PCB_CR3(%eax)
+
+ lea 7*NBPG(%esi),%esi # skip past stack.
+ pushl %esi
+
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax # adjust slots 9-17
+ movl $9,%ecx
+reloc_gdt:
+ movb $0xfe,7(%eax) # top byte of base addresses, was 0,
+ addl $8,%eax # now SYSTEM>>24
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+
+ call _init386 # wire 386 chip for unix operation
+
+ movl $0,_PTD
+ call _main
+ popl %esi
+
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ # build outer stack frame
+ pushl %ecx # user ss
+ pushl $ USRSTACK # user esp
+ pushl %eax # user cs
+ pushl $0 # user ip
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs # double map cs to fs
+ movl %cx,%gs # and ds to gs
+ lret # goto user!
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+ .set exec,59
+ .set exit,1
+
+#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+/*
+ * Icode is copied out to process 1 to exec /etc/init.
+ * If the exec fails, process 1 exits.
+ */
+ENTRY(icode)
+ # pushl $argv-_icode # gas fucks up again
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax
+
+ # pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax
+ pushl %eax # dummy out rta
+
+ movl %esp,%ebp
+ movl $exec,%eax
+ LCALL(0x7,0x0)
+ pushl %eax
+ movl $exit,%eax
+ pushl %eax # dummy out rta
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6)
+ .long eicode-_icode # argv[1] follows icode after copyout
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+ENTRY(sigcode)
+ call 12(%esp)
+ lea 28(%esp),%eax # scp (the call may have clobbered the
+ # copy at 8(%esp))
+ # XXX - use genassym
+ pushl %eax
+ pushl %eax # junk to fake return address
+ movl $103,%eax # sigreturn()
+ LCALL(0x7,0) # enter kernel with args on stack
+ hlt # never gets here
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
+
+ /*
+ * Support routines for GCC
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inb %dx,%al
+ ret
+
+
+ENTRY(inw)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inw %dx,%ax
+ ret
+
+
+ENTRY(rtcin)
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ subl %eax,%eax # clr eax
+ inb $0x71,%al
+ ret
+
+ENTRY(outb)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ /*
+ * void bzero(void *base, u_int cnt)
+ */
+
+ENTRY(bzero)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+
+ /*
+ * fillw (pat,base,cnt)
+ */
+
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je _bcopyw
+ cmpl $4,%eax
+ jne _bcopyb
+ /*
+ * Fall through to bcopy. ENTRY() provides harmless fill bytes.
+ */
+
+ /*
+ * (ov)bcopy (src,dst,cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ * Changed by bde to not bother returning %eax = 0.
+ */
+
+ENTRY(ovbcopy)
+ENTRY(bcopy)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+#ifdef notdef
+ENTRY(copyout)
+ movl _curpcb, %eax
+ movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp), %esi
+ movl 20(%esp), %edi
+ movl 24(%esp), %ebx
+
+ /* first, check to see if "write fault" */
+1: movl %edi, %eax
+#ifdef notyet
+ shrl $IDXSHIFT, %eax /* fetch pte associated with address */
+ andb $0xfc, %al
+ movl _PTmap(%eax), %eax
+
+ andb $7, %al /* if we are the one case that won't trap... */
+ cmpb $5, %al
+ jne 2f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+
+ cmpl $0, %eax /* if not ok, return */
+ jne cpyflt
+ /* otherwise, continue with reference */
+2:
+ movl %edi, %eax /* calculate remainder this pass */
+ andl $0xfffff000, %eax
+ movl $NBPG, %ecx
+ subl %eax, %ecx
+ cmpl %ecx, %ebx
+ jle 3f
+ movl %ebx, %ecx
+3: subl %ecx, %ebx
+ movl %ecx, %edx
+#else
+ movl %ebx, %ecx
+ movl %ebx, %edx
+#endif
+
+ shrl $2,%ecx /* movem */
+ cld
+ rep
+ movsl
+ movl %edx, %ecx /* don't depend on ecx here! */
+ andl $3, %ecx
+ rep
+ movsb
+
+#ifdef notyet
+ cmpl $0, %ebx
+ jl 1b
+#endif
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx # XXX - not used, but affects stack offsets
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+#else
+ENTRY(copyout)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt: popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+
+#endif
+
+ # insb(port,addr,cnt)
+ENTRY(insb)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # insw(port,addr,cnt)
+ENTRY(insw)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6d # rep insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # outsw(port,addr,cnt)
+ENTRY(outsw)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6f # rep outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ # outsb(port,addr,cnt)
+ENTRY(outsb)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ /*
+ * void lgdt(struct region_descriptor *rdp);
+ */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+ # movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+ /*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+ /*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+ /*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+ /*
+ * void lcr3(caddr_t cr3)
+ */
+ ALIGN_TEXT
+ENTRY(load_cr3)
+ALTENTRY(lcr3)
+ movl 4(%esp),%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # tlbflush()
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # lcr0(cr0)
+ENTRY(lcr0)
+ALTENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+ # rcr0()
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+ # rcr2()
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+ # rcr3()
+ENTRY(_cr3)
+ALTENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+ # ssdtosd(*ssdp,*sdp)
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+/*
+ * {fu,su},{byte,word}
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ decl %eax
+ ret
+
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+
+#ifdef notdef
+ shrl $IDXSHIFT, %edx /* fetch pte associated with address */
+ andb $0xfc, %dl
+ movl _PTmap(%edx), %edx
+
+ andb $7, %dl /* if we are the one case that won't trap... */
+ cmpb $5 , %edx
+ jne 1f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ cmpl $0, %eax /* if not ok, return */
+ jne fusufault
+ movl 8(%esp),%eax /* otherwise, continue with reference */
+1:
+ movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movb %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx, (%eax) # save ebx
+ movl %esp, 4(%eax) # save esp
+ movl %ebp, 8(%eax) # save ebp
+ movl %esi,12(%eax) # save esi
+ movl %edi,16(%eax) # save edi
+ movl (%esp),%edx # get rta
+ movl %edx,20(%eax) # save eip
+ xorl %eax,%eax # return (0);
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx # restore ebx
+ movl 4(%eax),%esp # restore esp
+ movl 8(%eax),%ebp # restore ebp
+ movl 12(%eax),%esi # restore esi
+ movl 16(%eax),%edi # restore edi
+ movl 20(%eax),%edx # get rta
+ movl %edx,(%esp) # put in return frame
+ xorl %eax,%eax # return (1);
+ incl %eax
+ ret
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+
+ .globl _whichqs,_qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) # should not be on q already
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs # set q full bit
+ shll $3,%edx
+ addl $_qs,%edx # locate q hdr
+ movl %edx,P_LINK(%eax) # link process on tail of q
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs # clear full bit, panic if clear already
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx # unlink process
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx # q still has something?
+ je rem2
+ shrl $3,%edx # yes, set bit as still full
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) # zap reverse link to indicate off list
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, Swtch branches to idle
+ * to wait for something to come ready.
+ */
+ .globl Idle
+ ALIGN_TEXT
+Idle:
+sti_for_idle:
+ sti
+ SHOW_STI
+ ALIGN_TEXT
+idle:
+ call _spl0
+ cmpl $0,_whichqs
+ jne sw1
+ hlt # wait for interrupt
+ jmp idle
+
+ SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax # Hardware registers
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2,%eax # save temporary map PTE
+ movl %eax,PCB_CMAP2(%ecx) # in our context
+ movl $0,_curproc # out of process
+
+ # movw _cpl, %ax
+ # movw %ax, PCB_IML(%ecx) # save ipl
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+ SHOW_CLI
+ movl _whichqs,%edi
+2:
+ # XXX - bsf is sloow
+ bsfl %edi,%eax # find a full q
+ je sti_for_idle # if none, idle
+ # XX update whichqs?
+swfnd:
+ btrl %eax,%edi # clear q full status
+ jnb 2b # if it was clear, look for another
+ movl %eax,%ebx # save which one we are using
+
+ shll $3,%eax
+ addl $_qs,%eax # select q
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list)
+ je badsw # not possible
+#endif
+
+ movl P_LINK(%eax),%ecx # unlink from front of process q
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi # q empty
+ je 3f
+ btsl %ebx,%edi # nope, set to indicate full
+3:
+ movl %edi,_whichqs # update q status
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $ SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx), %ebx
+ movl PCB_ESP(%edx), %esp
+ movl PCB_EBP(%edx), %ebp
+ movl PCB_ESI(%edx), %esi
+ movl PCB_EDI(%edx), %edi
+ movl PCB_EIP(%edx), %eax
+ movl %eax, (%esp)
+
+ movl PCB_CMAP2(%edx),%eax # get temporary map
+ movl %eax,_CMAP2 # reload temporary map PTE
+
+ movl %ecx,_curproc # into next process
+ movl %edx,_curpcb
+
+ pushl %edx # save p to return
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+ SHOW_STI
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax # return (p);
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(p) ; struct proc *p;
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx # old pc
+ popl %eax # arg, our return value
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 # good bye address space
+ #write buffer?
+ movl $tmpstk-4,%esp # temporary stack, compensated for call
+ jmp %edx # return, execute remainder of cleanup
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp), %ecx
+ movw _cpl, %ax
+ movw %ax, PCB_IML(%ecx)
+ movl (%esp), %eax
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2, %edx # save temporary map PTE
+ movl %edx, PCB_CMAP2(%ecx) # in our context
+
+ cmpl $0, 8(%esp)
+ je 1f
+ movl %esp, %edx # relocate current sp relative to pcb
+ subl $_kstack, %edx # (sp is relative to kstack):
+ addl %edx, %ecx # pcb += sp - kstack;
+ movl %eax, (%ecx) # write return pc at (relocated) sp@
+ # this mess deals with replicating register state gcc hides
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax, %eax # return 0
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jl L1 /* if (pc < 0) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
+
+ # To be done:
+ ENTRY(astoff)
+ ret
+
+ .data
+ ALIGN_DATA
+ .globl _cyloffset, _curpcb
+_cyloffset: .long 0
+ .globl _proc0paddr
+_proc0paddr: .long 0
+LF: .asciz "swtch %x"
+ ALIGN_DATA
+
+#if 0
+#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
+ call _panic; MSG(msg)
+#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \
+ popl %eax ; popal
+#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text
+#endif /* 0 */
+
+/*
+ * Trap and fault vector routines
+ *
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp alltraps
+#ifdef KGDB
+#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps
+#else
+#define BPTTRAP(a) sti; TRAP(a)
+#endif
+
+ .text
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+#ifdef BDBTRAP
+ BDBTRAP(dbg)
+#endif
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+#ifdef BDBTRAP
+ BDBTRAP(bpt)
+#endif
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+ /*PANIC("Double Fault");*/
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+ /*PANIC("TSS not valid");*/
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#ifdef NPX
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop /* silly, the bug is for popal and it only
+ * bites when the next instruction has a
+ * complicated address mode */
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ pushl _cpl
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ call _npxintr
+ jmp doreti
+#else
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+alltraps:
+ pushal
+ nop
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+calltrap:
+ incl _cnt+V_TRAP
+ call _trap
+ /*
+ * Return through doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */
+ pushl _cpl
+ pushl $0 /* dummy unit */
+ jmp doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ ALIGN_TEXT
+bpttraps:
+ pushal
+ nop
+ pushl %es
+ pushl %ds
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ # non-kernel mode?
+ jne calltrap # yes
+ call _kgdb_trap_glue
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl # only for stupid carry bit and more stupid wait3 cc kludge
+ # XXX - also for direction flag (bzero, etc. clear it)
+ pushal # only need eax,ecx,edx - trap resaves others
+ nop
+ movl $KDSEL,%eax # switch to kernel segments
+ movl %ax,%ds
+ movl %ax,%es
+ incl _cnt+V_SYSCALL # kml 3/25/93
+ call _syscall
+ /*
+ * Return through doreti to handle ASTs. Have to change syscall frame
+ * to interrupt frame.
+ *
+ * XXX - we should have set up the frame earlier to avoid the
+ * following popal/pushal (not much can be done to avoid shuffling
+ * the flags). Consistent frames would simplify things all over.
+ */
+ movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */
+ movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */
+ movl 32+8(%esp),%ecx
+ movl %ebx,32+0(%esp)
+ movl %ecx,32+4(%esp)
+ movl %eax,32+8(%esp)
+ popal
+ nop
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop
+ movl __udatasel,%eax /* switch back to user segments */
+ push %eax /* XXX - better to preserve originals? */
+ push %eax
+ pushl _cpl
+ pushl $0
+ jmp doreti
+
+ENTRY(htonl)
+ENTRY(ntohl)
+ movl 4(%esp),%eax
+#ifdef i486
+ /* XXX */
+ /* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ENTRY(htons)
+ENTRY(ntohs)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+#ifdef SHOW_A_LOT
+
+/*
+ * 'show_bits' was too big when defined as a macro. The line length for some
+ * enclosing macro was too big for gas. Perhaps the code would have blown
+ * the cache anyway.
+ */
+
+ ALIGN_TEXT
+show_bits:
+ pushl %eax
+ SHOW_BIT(0)
+ SHOW_BIT(1)
+ SHOW_BIT(2)
+ SHOW_BIT(3)
+ SHOW_BIT(4)
+ SHOW_BIT(5)
+ SHOW_BIT(6)
+ SHOW_BIT(7)
+ SHOW_BIT(8)
+ SHOW_BIT(9)
+ SHOW_BIT(10)
+ SHOW_BIT(11)
+ SHOW_BIT(12)
+ SHOW_BIT(13)
+ SHOW_BIT(14)
+ SHOW_BIT(15)
+ popl %eax
+ ret
+
+ .data
+bit_colors:
+ .byte GREEN,RED,0,0
+ .text
+
+#endif /* SHOW_A_LOT */
+
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s
new file mode 100644
index 0000000..d558dba
--- /dev/null
+++ b/sys/amd64/amd64/locore.s
@@ -0,0 +1,1830 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)locore.s 7.3 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped
+ * 28 Nov 92 Frank MacLachlan Aligned addresses and data
+ * on 32bit boundaries.
+ * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1)
+ */
+
+
+/*
+ * locore.s: 4BSD machine support for the Intel 386
+ * Preliminary version
+ * Written by William F. Jolitz, 386BSD Project
+ */
+
+#include "assym.s"
+#include "machine/psl.h"
+#include "machine/pte.h"
+
+#include "errno.h"
+
+#include "machine/trap.h"
+
+#include "machine/specialreg.h"
+#include "i386/isa/debug.h"
+
+#define KDSEL 0x10
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+/*
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+ .set IDXSHIFT,10
+ .set SYSTEM,0xFE000000 # virtual address of system start
+ /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */
+ .set SYSPDROFF,0x3F8 # Page dir index of System Base
+
+#define ALIGN_DATA .align 2
+#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */
+#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */
+
+/* NB: NOP now preserves registers so NOPs can be inserted anywhere */
+/* XXX: NOP and FASTER_NOP are misleadingly named */
+#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */
+#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax
+#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax
+#else
+#define FASTER_NOP
+#define NOP
+#endif
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .set PDRPDROFF,0x3F7 # Page dir index of Page dir
+ .globl _PTmap, _PTD, _PTDpde, _Sysmap
+ .set _PTmap,0xFDC00000
+ .set _PTD,0xFDFF7000
+ .set _Sysmap,0xFDFF8000
+ .set _PTDpde,0xFDFF7000+4*PDRPDROFF
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .set APDRPDROFF,0x3FE # Page dir index of Page dir
+ .globl _APTmap, _APTD, _APTDpde
+ .set _APTmap,0xFF800000
+ .set _APTD,0xFFBFE000
+ .set _APTDpde,0xFDFF7000+4*APDRPDROFF
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack, USRSTACK
+ .globl _kstack
+ .set PPDROFF,0x3F6
+ .set PPTEOFF,0x400-UPAGES # 0x3FE
+
+#define ENTRY(name) \
+ .globl _/**/name; ALIGN_TEXT; _/**/name:
+#define ALTENTRY(name) ENTRY(name)
+
+/*
+ * Initialization
+ */
+ .data
+ .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys
+_cpu: .long 0 # are we 386, 386sx, or 486
+_cold: .long 1 # cold till we are not
+_atdevbase: .long 0 # location of start of iomem in virtual
+_atdevphys: .long 0 # location of device mapping ptes (phys)
+
+ .globl _IdlePTD, _KPTphys
+_IdlePTD: .long 0
+_KPTphys: .long 0
+
+ .space 512
+tmpstk:
+ .text
+ .globl start
+start: movw $0x1234,%ax
+ movw %ax,0x472 # warm boot
+ jmp 1f
+ .space 0x500 # skip over warm boot shit
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-SYSTEM
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-SYSTEM
+ movl 12(%esp),%eax
+ movl %eax, _cyloffset-SYSTEM
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location
+
+#ifdef garbage
+ /* count up memory */
+
+ xorl %eax,%eax # start with base memory at 0x0
+ #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K
+ movl $ 0xA0,%ecx # look every 4K up to 640K
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+
+ movl $0x100000,%eax # next, talley remaining memory
+ #movl $((0xFFF000-0x100000)/NBPG),%ecx
+ movl $(0xFFF-0x100),%ecx
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+#endif
+
+/* find end of kernel image */
+ movl $_end-SYSTEM,%ecx
+ addl $ NBPG-1,%ecx
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi
+
+/* clear bss and memory for bootstrap pagetables. */
+ movl $_edata-SYSTEM,%edi
+ subl %edi,%ecx
+ addl $(UPAGES+5)*NBPG,%ecx
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * 0 1 2 3 4
+ */
+ xorl %eax,%eax # pattern
+ cld
+ rep
+ stosb
+
+ movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */
+
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $ NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ * N.B. don't bother with making kernel text RO, as 386
+ * ignores R/W AND U/S bits on kernel access (only v works) !
+ *
+ * First step - build page tables
+ */
+ movl %esi,%ecx # this much memory,
+ shrl $ PGSHIFT,%ecx # for this many pte s
+ addl $ UPAGES+4,%ecx # including our early context
+ movl $0xa0,%ecx # XXX - cover debugger pages
+ movl $PG_V|PG_KW,%eax # having these bits set,
+ lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0,
+ movl %ebx,_KPTphys-SYSTEM # in the kernel page table,
+ fillkpt
+
+/* map I/O memory map */
+
+ movl $0x100-0xa0,%ecx # for this many pte s,
+ movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92
+ movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $ UPAGES,%ecx # for this many pte s,
+ lea (1*NBPG)(%esi),%eax # physical address in proc 0
+ lea (SYSTEM)(%eax),%edx
+ movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init
+ orl $PG_V|PG_KW,%eax # having these bits set,
+ lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0
+ addl $(PPTEOFF*4),%ebx
+ fillkpt
+
+/*
+ * Construct a page table directory
+ * (of page directory elements - pde's)
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ lea (4*NBPG)(%esi),%eax # physical address of kernel page table
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax,(%esi) # which is where temp maps!
+
+ /* kernel pde's */
+ movl $ 3,%ecx # for this many pde s,
+ lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps!
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0
+ orl $PG_V|PG_KW,%eax # pde entry is valid
+ movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps!
+
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 # XXX - debugger signature
+ jne 1f
+ movb $1,_bdb_exists-SYSTEM
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi # base address of current gdt
+ movl $_gdt-SYSTEM,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep # copy gdt
+ movsl
+ movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi # base address of current idt
+ movl 8+4(%esi),%eax # convert dbg descriptor to ...
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ...
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp
+ movl 24+4(%esi),%eax # same for bpt descriptor
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-SYSTEM
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-SYSTEM
+
+ movl $_idt-SYSTEM,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep # copy idt
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+
+ /* load base of page directory, and enable mapping */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3 # load ptd addr into mmu
+ movl %cr0,%eax # get control word
+#ifdef USE_486_WRITE_PROTECT
+ orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page!
+#else
+ orl $CR0_PE|CR0_PG,%eax # and let s page!
+#endif
+ movl %eax,%cr0 # NOW!
+
+ pushl $begin # jump to high mem!
+ ret
+
+begin: /* now running relocated at SYSTEM where the system is linked to run */
+
+ .globl _Crtat
+ movl _Crtat,%eax
+ subl $0xfe0a0000,%eax
+ movl _atdevphys,%edx # get pte PA
+ subl _KPTphys,%edx # remove base of ptes, now have phys offset
+ shll $ PGSHIFT-2,%edx # corresponding to virt offset
+ addl $ SYSTEM,%edx # add virtual base
+ movl %edx, _atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack */
+ movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location
+ xorl %eax,%eax # mark end of frames
+ movl %eax,%ebp
+ movl _proc0paddr, %eax
+ movl %esi, PCB_CR3(%eax)
+
+ lea 7*NBPG(%esi),%esi # skip past stack.
+ pushl %esi
+
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax # adjust slots 9-17
+ movl $9,%ecx
+reloc_gdt:
+ movb $0xfe,7(%eax) # top byte of base addresses, was 0,
+ addl $8,%eax # now SYSTEM>>24
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+
+ call _init386 # wire 386 chip for unix operation
+
+ movl $0,_PTD
+ call _main
+ popl %esi
+
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ # build outer stack frame
+ pushl %ecx # user ss
+ pushl $ USRSTACK # user esp
+ pushl %eax # user cs
+ pushl $0 # user ip
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs # double map cs to fs
+ movl %cx,%gs # and ds to gs
+ lret # goto user!
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+ .set exec,59
+ .set exit,1
+
+#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+/*
+ * Icode is copied out to process 1 to exec /etc/init.
+ * If the exec fails, process 1 exits.
+ */
+ENTRY(icode)
+ # pushl $argv-_icode # gas fucks up again
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax
+
+ # pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax
+ pushl %eax # dummy out rta
+
+ movl %esp,%ebp
+ movl $exec,%eax
+ LCALL(0x7,0x0)
+ pushl %eax
+ movl $exit,%eax
+ pushl %eax # dummy out rta
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6)
+ .long eicode-_icode # argv[1] follows icode after copyout
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+ENTRY(sigcode)
+ call 12(%esp)
+ lea 28(%esp),%eax # scp (the call may have clobbered the
+ # copy at 8(%esp))
+ # XXX - use genassym
+ pushl %eax
+ pushl %eax # junk to fake return address
+ movl $103,%eax # sigreturn()
+ LCALL(0x7,0) # enter kernel with args on stack
+ hlt # never gets here
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
+
+ /*
+ * Support routines for GCC
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inb %dx,%al
+ ret
+
+
+ENTRY(inw)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inw %dx,%ax
+ ret
+
+
+ENTRY(rtcin)
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ subl %eax,%eax # clr eax
+ inb $0x71,%al
+ ret
+
+ENTRY(outb)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ /*
+ * void bzero(void *base, u_int cnt)
+ */
+
+ENTRY(bzero)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+
+ /*
+ * fillw (pat,base,cnt)
+ */
+
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je _bcopyw
+ cmpl $4,%eax
+ jne _bcopyb
+ /*
+ * Fall through to bcopy. ENTRY() provides harmless fill bytes.
+ */
+
+ /*
+ * (ov)bcopy (src,dst,cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ * Changed by bde to not bother returning %eax = 0.
+ */
+
+ENTRY(ovbcopy)
+ENTRY(bcopy)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+#ifdef notdef
+ENTRY(copyout)
+ movl _curpcb, %eax
+ movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp), %esi
+ movl 20(%esp), %edi
+ movl 24(%esp), %ebx
+
+ /* first, check to see if "write fault" */
+1: movl %edi, %eax
+#ifdef notyet
+ shrl $IDXSHIFT, %eax /* fetch pte associated with address */
+ andb $0xfc, %al
+ movl _PTmap(%eax), %eax
+
+ andb $7, %al /* if we are the one case that won't trap... */
+ cmpb $5, %al
+ jne 2f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+
+ cmpl $0, %eax /* if not ok, return */
+ jne cpyflt
+ /* otherwise, continue with reference */
+2:
+ movl %edi, %eax /* calculate remainder this pass */
+ andl $0xfffff000, %eax
+ movl $NBPG, %ecx
+ subl %eax, %ecx
+ cmpl %ecx, %ebx
+ jle 3f
+ movl %ebx, %ecx
+3: subl %ecx, %ebx
+ movl %ecx, %edx
+#else
+ movl %ebx, %ecx
+ movl %ebx, %edx
+#endif
+
+ shrl $2,%ecx /* movem */
+ cld
+ rep
+ movsl
+ movl %edx, %ecx /* don't depend on ecx here! */
+ andl $3, %ecx
+ rep
+ movsb
+
+#ifdef notyet
+ cmpl $0, %ebx
+ jl 1b
+#endif
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx # XXX - not used, but affects stack offsets
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+#else
+ENTRY(copyout)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt: popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+
+#endif
+
+ # insb(port,addr,cnt)
+ENTRY(insb)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # insw(port,addr,cnt)
+ENTRY(insw)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6d # rep insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # outsw(port,addr,cnt)
+ENTRY(outsw)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6f # rep outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ # outsb(port,addr,cnt)
+ENTRY(outsb)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ /*
+ * void lgdt(struct region_descriptor *rdp);
+ */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+ # movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+ /*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+ /*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+ /*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+ /*
+ * void lcr3(caddr_t cr3)
+ */
+ ALIGN_TEXT
+ENTRY(load_cr3)
+ALTENTRY(lcr3)
+ movl 4(%esp),%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # tlbflush()
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # lcr0(cr0)
+ENTRY(lcr0)
+ALTENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+ # rcr0()
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+ # rcr2()
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+ # rcr3()
+ENTRY(_cr3)
+ALTENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+ # ssdtosd(*ssdp,*sdp)
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+/*
+ * {fu,su},{byte,word}
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ decl %eax
+ ret
+
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+
+#ifdef notdef
+ shrl $IDXSHIFT, %edx /* fetch pte associated with address */
+ andb $0xfc, %dl
+ movl _PTmap(%edx), %edx
+
+ andb $7, %dl /* if we are the one case that won't trap... */
+ cmpb $5 , %edx
+ jne 1f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ cmpl $0, %eax /* if not ok, return */
+ jne fusufault
+ movl 8(%esp),%eax /* otherwise, continue with reference */
+1:
+ movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movb %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx, (%eax) # save ebx
+ movl %esp, 4(%eax) # save esp
+ movl %ebp, 8(%eax) # save ebp
+ movl %esi,12(%eax) # save esi
+ movl %edi,16(%eax) # save edi
+ movl (%esp),%edx # get rta
+ movl %edx,20(%eax) # save eip
+ xorl %eax,%eax # return (0);
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx # restore ebx
+ movl 4(%eax),%esp # restore esp
+ movl 8(%eax),%ebp # restore ebp
+ movl 12(%eax),%esi # restore esi
+ movl 16(%eax),%edi # restore edi
+ movl 20(%eax),%edx # get rta
+ movl %edx,(%esp) # put in return frame
+ xorl %eax,%eax # return (1);
+ incl %eax
+ ret
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+
+ .globl _whichqs,_qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) # should not be on q already
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs # set q full bit
+ shll $3,%edx
+ addl $_qs,%edx # locate q hdr
+ movl %edx,P_LINK(%eax) # link process on tail of q
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs # clear full bit, panic if clear already
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx # unlink process
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx # q still has something?
+ je rem2
+ shrl $3,%edx # yes, set bit as still full
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) # zap reverse link to indicate off list
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, Swtch branches to idle
+ * to wait for something to come ready.
+ */
+ .globl Idle
+ ALIGN_TEXT
+Idle:
+sti_for_idle:
+ sti
+ SHOW_STI
+ ALIGN_TEXT
+idle:
+ call _spl0
+ cmpl $0,_whichqs
+ jne sw1
+ hlt # wait for interrupt
+ jmp idle
+
+ SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax # Hardware registers
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2,%eax # save temporary map PTE
+ movl %eax,PCB_CMAP2(%ecx) # in our context
+ movl $0,_curproc # out of process
+
+ # movw _cpl, %ax
+ # movw %ax, PCB_IML(%ecx) # save ipl
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+ SHOW_CLI
+ movl _whichqs,%edi
+2:
+ # XXX - bsf is sloow
+ bsfl %edi,%eax # find a full q
+ je sti_for_idle # if none, idle
+ # XX update whichqs?
+swfnd:
+ btrl %eax,%edi # clear q full status
+ jnb 2b # if it was clear, look for another
+ movl %eax,%ebx # save which one we are using
+
+ shll $3,%eax
+ addl $_qs,%eax # select q
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list)
+ je badsw # not possible
+#endif
+
+ movl P_LINK(%eax),%ecx # unlink from front of process q
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi # q empty
+ je 3f
+ btsl %ebx,%edi # nope, set to indicate full
+3:
+ movl %edi,_whichqs # update q status
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $ SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx), %ebx
+ movl PCB_ESP(%edx), %esp
+ movl PCB_EBP(%edx), %ebp
+ movl PCB_ESI(%edx), %esi
+ movl PCB_EDI(%edx), %edi
+ movl PCB_EIP(%edx), %eax
+ movl %eax, (%esp)
+
+ movl PCB_CMAP2(%edx),%eax # get temporary map
+ movl %eax,_CMAP2 # reload temporary map PTE
+
+ movl %ecx,_curproc # into next process
+ movl %edx,_curpcb
+
+ pushl %edx # save p to return
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+ SHOW_STI
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax # return (p);
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(p) ; struct proc *p;
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx # old pc
+ popl %eax # arg, our return value
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 # good bye address space
+ #write buffer?
+ movl $tmpstk-4,%esp # temporary stack, compensated for call
+ jmp %edx # return, execute remainder of cleanup
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp), %ecx
+ movw _cpl, %ax
+ movw %ax, PCB_IML(%ecx)
+ movl (%esp), %eax
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2, %edx # save temporary map PTE
+ movl %edx, PCB_CMAP2(%ecx) # in our context
+
+ cmpl $0, 8(%esp)
+ je 1f
+ movl %esp, %edx # relocate current sp relative to pcb
+ subl $_kstack, %edx # (sp is relative to kstack):
+ addl %edx, %ecx # pcb += sp - kstack;
+ movl %eax, (%ecx) # write return pc at (relocated) sp@
+ # this mess deals with replicating register state gcc hides
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax, %eax # return 0
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jl L1 /* if (pc < 0) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
+
+ # To be done:
+ ENTRY(astoff)
+ ret
+
+ .data
+ ALIGN_DATA
+ .globl _cyloffset, _curpcb
+_cyloffset: .long 0
+ .globl _proc0paddr
+_proc0paddr: .long 0
+LF: .asciz "swtch %x"
+ ALIGN_DATA
+
+#if 0
+#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
+ call _panic; MSG(msg)
+#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \
+ popl %eax ; popal
+#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text
+#endif /* 0 */
+
+/*
+ * Trap and fault vector routines
+ *
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp alltraps
+#ifdef KGDB
+#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps
+#else
+#define BPTTRAP(a) sti; TRAP(a)
+#endif
+
+ .text
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+#ifdef BDBTRAP
+ BDBTRAP(dbg)
+#endif
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+#ifdef BDBTRAP
+ BDBTRAP(bpt)
+#endif
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+ /*PANIC("Double Fault");*/
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+ /*PANIC("TSS not valid");*/
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#ifdef NPX
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop /* silly, the bug is for popal and it only
+ * bites when the next instruction has a
+ * complicated address mode */
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ pushl _cpl
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ call _npxintr
+ jmp doreti
+#else
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+alltraps:
+ pushal
+ nop
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+calltrap:
+ incl _cnt+V_TRAP
+ call _trap
+ /*
+ * Return through doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */
+ pushl _cpl
+ pushl $0 /* dummy unit */
+ jmp doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ ALIGN_TEXT
+bpttraps:
+ pushal
+ nop
+ pushl %es
+ pushl %ds
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ # non-kernel mode?
+ jne calltrap # yes
+ call _kgdb_trap_glue
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl # only for stupid carry bit and more stupid wait3 cc kludge
+ # XXX - also for direction flag (bzero, etc. clear it)
+ pushal # only need eax,ecx,edx - trap resaves others
+ nop
+ movl $KDSEL,%eax # switch to kernel segments
+ movl %ax,%ds
+ movl %ax,%es
+ incl _cnt+V_SYSCALL # kml 3/25/93
+ call _syscall
+ /*
+ * Return through doreti to handle ASTs. Have to change syscall frame
+ * to interrupt frame.
+ *
+ * XXX - we should have set up the frame earlier to avoid the
+ * following popal/pushal (not much can be done to avoid shuffling
+ * the flags). Consistent frames would simplify things all over.
+ */
+ movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */
+ movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */
+ movl 32+8(%esp),%ecx
+ movl %ebx,32+0(%esp)
+ movl %ecx,32+4(%esp)
+ movl %eax,32+8(%esp)
+ popal
+ nop
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop
+ movl __udatasel,%eax /* switch back to user segments */
+ push %eax /* XXX - better to preserve originals? */
+ push %eax
+ pushl _cpl
+ pushl $0
+ jmp doreti
+
+ENTRY(htonl)
+ENTRY(ntohl)
+ movl 4(%esp),%eax
+#ifdef i486
+ /* XXX */
+ /* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ENTRY(htons)
+ENTRY(ntohs)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+#ifdef SHOW_A_LOT
+
+/*
+ * 'show_bits' was too big when defined as a macro. The line length for some
+ * enclosing macro was too big for gas. Perhaps the code would have blown
+ * the cache anyway.
+ */
+
+ ALIGN_TEXT
+show_bits:
+ pushl %eax
+ SHOW_BIT(0)
+ SHOW_BIT(1)
+ SHOW_BIT(2)
+ SHOW_BIT(3)
+ SHOW_BIT(4)
+ SHOW_BIT(5)
+ SHOW_BIT(6)
+ SHOW_BIT(7)
+ SHOW_BIT(8)
+ SHOW_BIT(9)
+ SHOW_BIT(10)
+ SHOW_BIT(11)
+ SHOW_BIT(12)
+ SHOW_BIT(13)
+ SHOW_BIT(14)
+ SHOW_BIT(15)
+ popl %eax
+ ret
+
+ .data
+bit_colors:
+ .byte GREEN,RED,0,0
+ .text
+
+#endif /* SHOW_A_LOT */
+
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
new file mode 100644
index 0000000..f0351a7
--- /dev/null
+++ b/sys/amd64/amd64/machdep.c
@@ -0,0 +1,1131 @@
+/*-
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 15 Aug 92 William Jolitz Large memory bug
+ * 15 Aug 92 Terry Lambert Fixed CMOS RAM size bug
+ * 25 Mar 93 Sean Eric Fagan Added #ifdef HZ around microtime for
+ * the new microtime.s routine
+ * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans New intr-0.1 code
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/machdep.c,v 1.2 92/01/21 14:22:09 william Exp Locker: root $";
+
+
+#include <stddef.h>
+#include "param.h"
+#include "systm.h"
+#include "signalvar.h"
+#include "kernel.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "reboot.h"
+#include "conf.h"
+#include "file.h"
+#include "callout.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "msgbuf.h"
+#include "net/netisr.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+extern vm_offset_t avail_end;
+
+#include "machine/cpu.h"
+#include "machine/reg.h"
+#include "machine/psl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/rtc.h"
+
+
+#define EXPECT_BASEMEM 640 /* The expected base memory*/
+#define INFORM_WAIT 1 /* Set to pause berfore crash in weird cases*/
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+int nswbuf = 0;
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+int msgbufmapped; /* set when safe to use msgbuf */
+extern int freebufspace;
+
+/*
+ * Machine-dependent startup code
+ */
+int boothowto = 0, Maxmem = 0;
+long dumplo;
+int physmem, maxmem;
+extern int bootdev;
+#ifdef SMALL
+extern int forcemaxmem;
+#endif
+int biosmem;
+
+extern cyloffset;
+
+cpu_startup()
+{
+ register int unixsize;
+ register unsigned i;
+ register struct pte *pte;
+ int mapaddr, j;
+ register caddr_t v;
+ int maxbufs, base, residual;
+ extern long Usrptsize;
+ vm_offset_t minaddr, maxaddr;
+ vm_size_t size;
+ int firstaddr;
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* avail_end was pre-decremented in pmap_bootstrap to compensate */
+ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
+ pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG,
+ VM_PROT_ALL, TRUE);
+ msgbufmapped = 1;
+
+#ifdef KDB
+ kdb_init(); /* startup kernel debugger */
+#endif
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ /*printf(version);
+ printf("real mem = %d\n", ctob(physmem));*/
+
+ /*
+ * Allocate space for system data structures.
+ * The first available kernel virtual address is in "v".
+ * As pages of kernel virtual memory are allocated, "v" is incremented.
+ * As pages of memory are allocated and cleared,
+ * "firstaddr" is incremented.
+ * An index into the kernel page table corresponding to the
+ * virtual memory address maintained in "v" is kept in "mapaddr".
+ */
+
+ /*
+ * Make two passes. The first pass calculates how much memory is
+ * needed and allocates it. The second pass assigns virtual
+ * addresses to the various data structures.
+ */
+ firstaddr = 0;
+again:
+ v = (caddr_t)firstaddr;
+
+#define valloc(name, type, num) \
+ (name) = (type *)v; v = (caddr_t)((name)+(num))
+#define valloclim(name, type, num, lim) \
+ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
+ valloc(callout, struct callout, ncallout);
+#ifdef SYSVSHM
+ valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
+#endif
+ /*
+ * Determine how many buffers to allocate.
+ * Use 10% of memory for the first 2 Meg, 5% of the remaining
+ * memory. Insure a minimum of 16 buffers.
+ * We allocate 1/2 as many swap buffer headers as file i/o buffers.
+ */
+ if (bufpages == 0)
+ if (physmem < (2 * 1024 * 1024))
+ bufpages = physmem / 10 / CLSIZE;
+ else
+ bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE;
+ /*
+ * 15 Aug 92 William Jolitz bufpages fix for too large
+ */
+ bufpages = min( NKMEMCLUSTERS*2/5, bufpages);
+
+ if (nbuf == 0) {
+ nbuf = bufpages / 2;
+ if (nbuf < 16)
+ nbuf = 16;
+ }
+ freebufspace = bufpages * NBPG;
+ if (nswbuf == 0) {
+ nswbuf = (nbuf / 2) &~ 1; /* force even */
+ if (nswbuf > 256)
+ nswbuf = 256; /* sanity */
+ }
+ valloc(swbuf, struct buf, nswbuf);
+ valloc(buf, struct buf, nbuf);
+
+ /*
+ * End of first pass, size has been calculated so allocate memory
+ */
+ if (firstaddr == 0) {
+ size = (vm_size_t)(v - firstaddr);
+ firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
+ if (firstaddr == 0)
+ panic("startup: no room for tables");
+ goto again;
+ }
+ /*
+ * End of second pass, addresses have been assigned
+ */
+ if ((vm_size_t)(v - firstaddr) != size)
+ panic("startup: table size inconsistency");
+ /*
+ * Allocate a submap for buffer space allocations.
+ */
+ buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ bufpages*NBPG, TRUE);
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, TRUE);
+
+ /*
+ * Finally, allocate mbuf pool. Since mclrefcnt is an off-size
+ * we use the more space efficient malloc in place of kmem_alloc.
+ */
+ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
+ M_MBUF, M_NOWAIT);
+ bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
+ mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
+ VM_MBUF_SIZE, FALSE);
+ /*
+ * Initialize callouts
+ */
+ callfree = callout;
+ for (i = 1; i < ncallout; i++)
+ callout[i-1].c_next = &callout[i];
+
+ /*printf("avail mem = %d\n", ptoa(vm_page_free_count));*/
+
+ /*
+ * Set up CPU-specific registers, cache, etc.
+ */
+ initcpu();
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ /*
+ * Configure the system.
+ */
+ configure();
+}
+
+#ifdef PGINPROF
+/*
+ * Return the difference (in microseconds)
+ * between the current time and a previous
+ * time as represented by the arguments.
+ * If there is a pending clock interrupt
+ * which has not been serviced due to high
+ * ipl, return error code.
+ */
+/*ARGSUSED*/
+vmtime(otime, olbolt, oicr)
+ register int otime, olbolt, oicr;
+{
+
+ return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
+}
+#endif
+
+struct sigframe {
+ int sf_signum;
+ int sf_code;
+ struct sigcontext *sf_scp;
+ sig_t sf_handler;
+ int sf_eax;
+ int sf_edx;
+ int sf_ecx;
+ struct sigcontext sf_sc;
+} ;
+
+extern int kstack[];
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig, mask;
+ unsigned code;
+{
+ register struct proc *p = curproc;
+ register int *regs;
+ register struct sigframe *fp;
+ struct sigacts *ps = p->p_sigacts;
+ int oonstack, frmtrap;
+
+ regs = p->p_regs;
+ oonstack = ps->ps_onstack;
+ frmtrap = curpcb->pcb_flags & FM_TRAP;
+ /*
+ * Allocate and validate space for the signal handler
+ * context. Note that if the stack is in P0 space, the
+ * call to grow() is a nop, and the useracc() check
+ * will fail if the process has not already allocated
+ * the space with a `brk'.
+ */
+ if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
+ fp = (struct sigframe *)(ps->ps_sigsp
+ - sizeof(struct sigframe));
+ ps->ps_onstack = 1;
+ } else {
+ if (frmtrap)
+ fp = (struct sigframe *)(regs[tESP]
+ - sizeof(struct sigframe));
+ else
+ fp = (struct sigframe *)(regs[sESP]
+ - sizeof(struct sigframe));
+ }
+
+ if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize))
+ (void)grow(p, (unsigned)fp);
+
+ if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ SIGACTION(p, SIGILL) = SIG_DFL;
+ sig = sigmask(SIGILL);
+ p->p_sigignore &= ~sig;
+ p->p_sigcatch &= ~sig;
+ p->p_sigmask &= ~sig;
+ psignal(p, SIGILL);
+ return;
+ }
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+ fp->sf_signum = sig;
+ fp->sf_code = code;
+ fp->sf_scp = &fp->sf_sc;
+ fp->sf_handler = catcher;
+
+ /* save scratch registers */
+ if(frmtrap) {
+ fp->sf_eax = regs[tEAX];
+ fp->sf_edx = regs[tEDX];
+ fp->sf_ecx = regs[tECX];
+ } else {
+ fp->sf_eax = regs[sEAX];
+ fp->sf_edx = regs[sEDX];
+ fp->sf_ecx = regs[sECX];
+ }
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ fp->sf_sc.sc_onstack = oonstack;
+ fp->sf_sc.sc_mask = mask;
+ if(frmtrap) {
+ fp->sf_sc.sc_sp = regs[tESP];
+ fp->sf_sc.sc_fp = regs[tEBP];
+ fp->sf_sc.sc_pc = regs[tEIP];
+ fp->sf_sc.sc_ps = regs[tEFLAGS];
+ regs[tESP] = (int)fp;
+ regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ } else {
+ fp->sf_sc.sc_sp = regs[sESP];
+ fp->sf_sc.sc_fp = regs[sEBP];
+ fp->sf_sc.sc_pc = regs[sEIP];
+ fp->sf_sc.sc_ps = regs[sEFLAGS];
+ regs[sESP] = (int)fp;
+ regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ }
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper priviledges or to cause
+ * a machine fault.
+ */
+sigreturn(p, uap, retval)
+ struct proc *p;
+ struct args {
+ struct sigcontext *sigcntxp;
+ } *uap;
+ int *retval;
+{
+ register struct sigcontext *scp;
+ register struct sigframe *fp;
+ register int *regs = p->p_regs;
+
+
+ /*
+ * (XXX old comment) regs[sESP] points to the return address.
+ * The user scp pointer is above that.
+ * The return address is faked in the signal trampoline code
+ * for consistency.
+ */
+ scp = uap->sigcntxp;
+ fp = (struct sigframe *)
+ ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
+
+ if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
+ return(EINVAL);
+
+ /* restore scratch registers */
+ regs[sEAX] = fp->sf_eax ;
+ regs[sEDX] = fp->sf_edx ;
+ regs[sECX] = fp->sf_ecx ;
+
+ if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
+ return(EINVAL);
+#ifdef notyet
+ if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
+ return(EINVAL);
+ }
+#endif
+ p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
+ p->p_sigmask = scp->sc_mask &~
+ (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
+ regs[sEBP] = scp->sc_fp;
+ regs[sESP] = scp->sc_sp;
+ regs[sEIP] = scp->sc_pc;
+ regs[sEFLAGS] = scp->sc_ps;
+ return(EJUSTRETURN);
+}
+
+int waittime = -1;
+struct pcb dumppcb;
+
+boot(arghowto)
+ int arghowto;
+{
+ register long dummy; /* r12 is reserved */
+ register int howto; /* r11 == how to boot */
+ register int devtype; /* r10 == major of root dev */
+ extern char *panicstr;
+ extern int cold;
+ int nomsg = 1;
+
+ if(cold) {
+ printf("hit reset please");
+ for(;;);
+ }
+ howto = arghowto;
+ if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
+ register struct buf *bp;
+ int iter, nbusy;
+
+ waittime = 0;
+ (void) splnet();
+ /*
+ * Release inodes held by texts before update.
+ */
+ if (panicstr == 0)
+ vnode_pager_umount(NULL);
+ sync((struct sigcontext *)0);
+
+ for (iter = 0; iter < 20; iter++) {
+ nbusy = 0;
+ for (bp = &buf[nbuf]; --bp >= buf; )
+ if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
+ nbusy++;
+ if (nbusy == 0)
+ break;
+ if (nomsg) {
+ printf("updating disks before rebooting... ");
+ nomsg = 0;
+ }
+ /* printf("%d ", nbusy); */
+ DELAY(40000 * iter);
+ }
+ if (nbusy)
+ printf(" failed!\n");
+ else if (nomsg == 0)
+ printf("succeded.\n");
+ DELAY(10000); /* wait for printf to finish */
+ }
+ splhigh();
+ devtype = major(rootdev);
+ if (howto&RB_HALT) {
+ pg("\nThe operating system has halted. Please press any key to reboot.\n\n");
+ } else {
+ if (howto & RB_DUMP) {
+ savectx(&dumppcb, 0);
+ dumppcb.pcb_ptd = rcr3();
+ dumpsys();
+ /*NOTREACHED*/
+ }
+ }
+#ifdef lint
+ dummy = 0; dummy = dummy;
+ printf("howto %d, devtype %d\n", arghowto, devtype);
+#endif
+ cpu_reset();
+ for(;;) ;
+ /*NOTREACHED*/
+}
+
+int dumpmag = 0x8fca0101; /* magic number for savecore */
+int dumpsize = 0; /* also for savecore */
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+dumpsys()
+{
+
+ if (dumpdev == NODEV)
+ return;
+ if ((minor(dumpdev)&07) != 1)
+ return;
+ printf("\nThe operating system is saving a copy of RAM memory to device %x, offset %d\n\
+(hit any key to abort): [ amount left to save (MB) ] ", dumpdev, dumplo);
+ dumpsize = physmem;
+ switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
+
+ case ENXIO:
+ printf("-- device bad\n");
+ break;
+
+ case EFAULT:
+ printf("-- device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("-- area improper\n");
+ break;
+
+ case EIO:
+ printf("-- i/o error\n");
+ break;
+
+ case EINTR:
+ printf("-- aborted from console\n");
+ break;
+
+ default:
+ printf(" succeeded\n");
+ break;
+ }
+ printf("system rebooting.\n\n");
+ DELAY(10000);
+}
+
+#ifdef HZ
+/*
+ * If HZ is defined we use this code, otherwise the code in
+ * /sys/i386/i386/microtime.s is used. The othercode only works
+ * for HZ=100.
+ */
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+
+ *tvp = time;
+ tvp->tv_usec += tick;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ splx(s);
+}
+#endif /* HZ */
+
+physstrat(bp, strat, prio)
+ struct buf *bp;
+ int (*strat)(), prio;
+{
+ register int s;
+ caddr_t baddr;
+
+ /*
+ * vmapbuf clobbers b_addr so we must remember it so that it
+ * can be restored after vunmapbuf. This is truely rude, we
+ * should really be storing this in a field in the buf struct
+ * but none are available and I didn't want to add one at
+ * this time. Note that b_addr for dirty page pushes is
+ * restored in vunmapbuf. (ugh!)
+ */
+ baddr = bp->b_un.b_addr;
+ vmapbuf(bp);
+ (*strat)(bp);
+ /* pageout daemon doesn't wait for pushed pages */
+ if (bp->b_flags & B_DIRTY)
+ return;
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0)
+ sleep((caddr_t)bp, prio);
+ splx(s);
+ vunmapbuf(bp);
+ bp->b_un.b_addr = baddr;
+}
+
+initcpu()
+{
+}
+
+/*
+ * Clear registers on exec
+ */
+setregs(p, entry)
+ struct proc *p;
+ u_long entry;
+{
+
+ p->p_regs[sEBP] = 0; /* bottom of the fp chain */
+ p->p_regs[sEIP] = entry;
+
+ p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */
+ load_cr0(rcr0() | CR0_TS); /* start emulating */
+#ifdef NPX
+ npxinit(__INITIAL_NPXCW__);
+#endif
+}
+
+/*
+ * Initialize 386 and configure to run kernel
+ */
+
+/*
+ * Initialize segments & interrupt table
+ */
+
+
+#define GNULL_SEL 0 /* Null Descriptor */
+#define GCODE_SEL 1 /* Kernel Code Descriptor */
+#define GDATA_SEL 2 /* Kernel Data Descriptor */
+#define GLDT_SEL 3 /* LDT - eventually one per process */
+#define GTGATE_SEL 4 /* Process task switch gate */
+#define GPANIC_SEL 5 /* Task state to consider panic from */
+#define GPROC0_SEL 6 /* Task state process slot zero and up */
+#define NGDT GPROC0_SEL+1
+
+union descriptor gdt[GPROC0_SEL+1];
+
+/* interrupt descriptor table */
+struct gate_descriptor idt[NIDT];
+
+/* local descriptor table */
+union descriptor ldt[5];
+#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
+#define LSYS5SIGR_SEL 1
+
+#define L43BSDCALLS_SEL 2 /* notyet */
+#define LUCODE_SEL 3
+#define LUDATA_SEL 4
+/* seperate stack, es,fs,gs sels ? */
+/* #define LPOSIXCALLS_SEL 5 /* notyet */
+
+struct i386tss tss, panic_tss;
+
+extern struct user *proc0paddr;
+
+/* software prototypes -- in more palitable form */
+struct soft_segment_descriptor gdt_segs[] = {
+ /* Null Descriptor */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* LDT Descriptor */
+{ (int) ldt, /* segment base address */
+ sizeof(ldt)-1, /* length - all address space */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - Placeholder */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Panic Tss Descriptor */
+{ (int) &panic_tss, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Proc 0 Tss Descriptor */
+{ (int) kstack, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ }};
+
+struct soft_segment_descriptor ldt_segs[] = {
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ } };
+
+setidt(idx, func, typ, dpl) char *func; {
+ struct gate_descriptor *ip = idt + idx;
+
+ ip->gd_looffset = (int)func;
+ ip->gd_selector = 8;
+ ip->gd_stkcpy = 0;
+ ip->gd_xx = 0;
+ ip->gd_type = typ;
+ ip->gd_dpl = dpl;
+ ip->gd_p = 1;
+ ip->gd_hioffset = ((int)func)>>16 ;
+}
+
+#define IDTVEC(name) __CONCAT(X, name)
+extern IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
+ IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
+ IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
+ IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
+ IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
+ IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
+ IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
+ IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
+
+int lcr0(), lcr3(), rcr0(), rcr2();
+int _udatasel, _ucodesel, _gsel_tss;
+
+init386(first)
+{
+ extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
+ int x, *pi;
+ unsigned biosbasemem, biosextmem;
+ struct gate_descriptor *gdp;
+ extern int sigcode,szsigcode;
+ /* table descriptors - used to load tables by microp */
+ struct region_descriptor r_gdt, r_idt;
+ int pagesinbase, pagesinext;
+
+
+ proc0.p_addr = proc0paddr;
+
+ /*
+ * Initialize the console before we print anything out.
+ */
+
+ cninit (KERNBASE+0xa0000);
+
+ /* make gdt memory segments */
+ gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
+ for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
+ /* make ldt memory segments */
+ ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
+ ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
+ /* Note. eventually want private ldts per process */
+ for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
+
+ /* exceptions */
+ setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL);
+ setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL);
+ setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL);
+ setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL);
+ setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_KPL);
+ setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL);
+ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL);
+ setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL);
+ setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL);
+ setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL);
+ setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL);
+ setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL);
+ setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL);
+ setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL);
+ setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL);
+ setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL);
+ setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL);
+ setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL);
+ setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL);
+ setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL);
+ setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL);
+ setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL);
+ setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL);
+ setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL);
+ setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL);
+ setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL);
+ setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL);
+ setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL);
+ setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL);
+ setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL);
+ setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL);
+ setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL);
+
+#include "isa.h"
+#if NISA >0
+ isa_defaultirq();
+#endif
+
+ r_gdt.rd_limit = sizeof(gdt)-1;
+ r_gdt.rd_base = (int) gdt;
+ lgdt(&r_gdt);
+ r_idt.rd_limit = sizeof(idt)-1;
+ r_idt.rd_base = (int) idt;
+ lidt(&r_idt);
+ lldt(GSEL(GLDT_SEL, SEL_KPL));
+
+#include "ddb.h"
+#if NDDB > 0
+ kdb_init();
+ if (boothowto & RB_KDB)
+ Debugger();
+#endif
+
+ /* Use BIOS values stored in RTC CMOS RAM, since probing
+ * breaks certain 386 AT relics.
+ */
+ biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
+ biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+/*printf("bios base %d ext %d ", biosbasemem, biosextmem);*/
+
+ /*
+ * 15 Aug 92 Terry Lambert The real fix for the CMOS bug
+ */
+ if( biosbasemem != EXPECT_BASEMEM) {
+ printf( "Warning: Base memory %dK, assuming %dK\n", biosbasemem, EXPECT_BASEMEM);
+ biosbasemem = EXPECT_BASEMEM; /* assume base*/
+ }
+
+ if( biosextmem > 65536) {
+ printf( "Warning: Extended memory %dK(>64M), assuming 0K\n", biosextmem);
+ biosextmem = 0; /* assume none*/
+ }
+
+ /*
+ * Go into normal calculation; Note that we try to run in 640K, and
+ * that invalid CMOS values of non 0xffff are no longer a cause of
+ * ptdi problems. I have found a gutted kernel can run in 640K.
+ */
+ pagesinbase = 640/4 - first/NBPG;
+ pagesinext = biosextmem/4;
+ /* use greater of either base or extended memory. do this
+ * until I reinstitue discontiguous allocation of vm_page
+ * array.
+ */
+ if (pagesinbase > pagesinext)
+ Maxmem = 640/4;
+ else {
+ Maxmem = pagesinext + 0x100000/NBPG;
+ first = 0x100000; /* skip hole */
+ }
+
+ /* This used to explode, since Maxmem used to be 0 for bas CMOS*/
+ maxmem = Maxmem - 1; /* highest page of usable memory */
+ physmem = maxmem; /* number of pages of physmem addr space */
+/*printf("using first 0x%x to 0x%x\n ", first, maxmem*NBPG);*/
+ if (maxmem < 2048/4) {
+ printf("Too little RAM memory. Warning, running in degraded mode.\n");
+#ifdef INFORM_WAIT
+ /*
+ * People with less than 2 Meg have to hit return; this way
+ * we see the messages and can tell them why they blow up later.
+ * If they get working well enough to recompile, they can unset
+ * the flag; otherwise, it's a toy and they have to lump it.
+ */
+ getchar(); /* kernel getchar in /sys/i386/isa/pccons.c*/
+#endif /* !INFORM_WAIT*/
+ }
+ /*
+ * End of CMOS bux fix
+ */
+
+ /* call pmap initialization to make new kernel address space */
+ pmap_bootstrap (first, 0);
+ /* now running on new page tables, configured,and u/iom is accessible */
+
+ /* make a initial tss so microp can get interrupt stack on syscall! */
+ proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
+ proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+ ltr(_gsel_tss);
+
+ /* make a call gate to reenter kernel with */
+ gdp = &ldt[LSYS5CALLS_SEL].gd;
+
+ x = (int) &IDTVEC(syscall);
+ gdp->gd_looffset = x++;
+ gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
+ gdp->gd_stkcpy = 0;
+ gdp->gd_type = SDT_SYS386CGT;
+ gdp->gd_dpl = SEL_UPL;
+ gdp->gd_p = 1;
+ gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
+
+ /* transfer to user mode */
+
+ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
+ _udatasel = LSEL(LUDATA_SEL, SEL_UPL);
+
+ /* setup proc 0's pcb */
+ bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
+ proc0.p_addr->u_pcb.pcb_flags = 0;
+ proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
+}
+
+extern struct pte *CMAP1, *CMAP2;
+extern caddr_t CADDR1, CADDR2;
+/*
+ * zero out physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+clearseg(n) {
+
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(n);
+ load_cr3(rcr3());
+ bzero(CADDR2,NBPG);
+ *(int *) CADDR2 = 0;
+}
+
+/*
+ * copy a page of physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+copyseg(frm, n) {
+
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(n);
+ load_cr3(rcr3());
+ bcopy((void *)frm, (void *)CADDR2, NBPG);
+}
+
+/*
+ * copy a page of physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+physcopyseg(frm, to) {
+
+ *(int *)CMAP1 = PG_V | PG_KW | ctob(frm);
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(to);
+ load_cr3(rcr3());
+ bcopy(CADDR1, CADDR2, NBPG);
+}
+
+/*aston() {
+ schednetisr(NETISR_AST);
+}*/
+
+setsoftclock() {
+ schednetisr(NETISR_SCLK);
+}
+
+/*
+ * insert an element into a queue
+ */
+#undef insque
+_insque(element, head)
+ register struct prochd *element, *head;
+{
+ element->ph_link = head->ph_link;
+ head->ph_link = (struct proc *)element;
+ element->ph_rlink = (struct proc *)head;
+ ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+#undef remque
+_remque(element)
+ register struct prochd *element;
+{
+ ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
+ ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
+ element->ph_rlink = (struct proc *)0;
+}
+
+vmunaccess() {}
+
+/*
+ * Below written in C to allow access to debugging code
+ */
+copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *toaddr, *fromaddr; {
+ int c,tally;
+
+ tally = 0;
+ while (maxlength--) {
+ c = fubyte(fromaddr++);
+ if (c == -1) {
+ if(lencopied) *lencopied = tally;
+ return(EFAULT);
+ }
+ tally++;
+ *(char *)toaddr++ = (char) c;
+ if (c == 0){
+ if(lencopied) *lencopied = (u_int)tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = (u_int)tally;
+ return(ENAMETOOLONG);
+}
+
+copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *fromaddr, *toaddr; {
+ int c;
+ int tally;
+
+ tally = 0;
+ while (maxlength--) {
+ c = subyte(toaddr++, *(char *)fromaddr);
+ if (c == -1) return(EFAULT);
+ tally++;
+ if (*(char *)fromaddr++ == 0){
+ if(lencopied) *lencopied = tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = tally;
+ return(ENAMETOOLONG);
+}
+
+copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *fromaddr, *toaddr; {
+ u_int tally;
+
+ tally = 0;
+ while (maxlength--) {
+ *(u_char *)toaddr = *(u_char *)fromaddr++;
+ tally++;
+ if (*(u_char *)toaddr++ == 0) {
+ if(lencopied) *lencopied = tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = tally;
+ return(ENAMETOOLONG);
+}
diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c
new file mode 100644
index 0000000..650e21e
--- /dev/null
+++ b/sys/amd64/amd64/mem.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and code derived from software contributed to
+ * Berkeley by William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: mem.c 1.13 89/10/08$
+ * @(#)mem.c 7.2 (Berkeley) 5/9/91
+ */
+
+/*
+ * Memory special file
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "uio.h"
+#include "malloc.h"
+
+#include "machine/cpu.h"
+
+#include "vm/vm_param.h"
+#include "vm/lock.h"
+#include "vm/vm_statistics.h"
+#include "vm/pmap.h"
+#include "vm/vm_prot.h"
+
+extern char *vmmap; /* poor name! */
+/*ARGSUSED*/
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register int o;
+ register u_int c, v;
+ register struct iovec *iov;
+ int error = 0;
+ caddr_t zbuf = NULL;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+ case 0:
+ v = uio->uio_offset;
+ pmap_enter(pmap_kernel(), vmmap, v,
+ uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
+ TRUE);
+ o = (int)uio->uio_offset & PGOFSET;
+ c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
+ c = MIN(c, (u_int)(NBPG - o));
+ c = MIN(c, (u_int)iov->iov_len);
+ error = uiomove((caddr_t)&vmmap[o], (int)c, uio);
+ pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]);
+ continue;
+
+/* minor device 1 is kernel memory */
+ case 1:
+ c = iov->iov_len;
+ if (!kernacc((caddr_t)uio->uio_offset, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return(EFAULT);
+ error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
+ continue;
+
+/* minor device 2 is EOF/RATHOLE */
+ case 2:
+ if (uio->uio_rw == UIO_READ)
+ return (0);
+ c = iov->iov_len;
+ break;
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+ case 12:
+ if (uio->uio_rw == UIO_WRITE) {
+ c = iov->iov_len;
+ break;
+ }
+ if (zbuf == NULL) {
+ zbuf = (caddr_t)
+ malloc(CLBYTES, M_TEMP, M_WAITOK);
+ bzero(zbuf, CLBYTES);
+ }
+ c = MIN(iov->iov_len, CLBYTES);
+ error = uiomove(zbuf, (int)c, uio);
+ continue;
+
+#ifdef notyet
+/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
+ i/o device address bus, different than memory bus. Semantics here are
+ very different than ordinary read/write, as if iov_len is a multiple
+ an implied string move from a single port will be done. Note that lseek
+ must be used to set the port number reliably. */
+ case 14:
+ if (iov->iov_len == 1) {
+ u_char tmp;
+ tmp = inb(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insb(uio->uio_offset, iov->iov_base,
+ iov->iov_len);
+ }
+ break;
+ case 15:
+ if (iov->iov_len == sizeof (short)) {
+ u_short tmp;
+ tmp = inw(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insw(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (short));
+ }
+ break;
+ case 16:
+ if (iov->iov_len == sizeof (long)) {
+ u_long tmp;
+ tmp = inl(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insl(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (long));
+ }
+ break;
+#endif
+
+ default:
+ return (ENXIO);
+ }
+ if (error)
+ break;
+ iov->iov_base += c;
+ iov->iov_len -= c;
+ uio->uio_offset += c;
+ uio->uio_resid -= c;
+ }
+ if (zbuf)
+ free(zbuf, M_TEMP);
+ return (error);
+}
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
new file mode 100644
index 0000000..66c7fec
--- /dev/null
+++ b/sys/amd64/amd64/pmap.c
@@ -0,0 +1,1728 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pmap.c 7.7 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00063
+ * -------------------- ----- ----------------------
+ *
+ * 28 Nov 1991 Poul-Henning Kamp Speedup processing.
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $";
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90
+ */
+
+/*
+ * Reno i386 version, from Mike Hibler's hp300 version.
+ */
+
+/*
+ * Manages physical address maps.
+ *
+ * In addition to hardware address maps, this
+ * module is called upon to provide software-use-only
+ * maps which may or may not be stored in the same
+ * form as hardware maps. These pseudo-maps are
+ * used to store intermediate results from copy
+ * operations to and from address spaces.
+ *
+ * Since the information managed by this module is
+ * also stored by the logical address mapping module,
+ * this module may throw away valid virtual-to-physical
+ * mappings at almost any time. However, invalidations
+ * of virtual-to-physical mappings must be done as
+ * requested.
+ *
+ * In order to cope with hardware architectures which
+ * make virtual-to-physical map invalidates expensive,
+ * this module may delay invalidate or reduced protection
+ * operations until such time as they are actually
+ * necessary. This module is given full information as
+ * to which processors are currently using which maps,
+ * and to when physical maps must be made correct.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "malloc.h"
+#include "user.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+/*#include "vm/vm_pageout.h"*/
+
+#include "i386/isa/isa.h"
+
+/*
+ * Allocate various and sundry SYSMAPs used in the days of old VM
+ * and not yet converted. XXX.
+ */
+#define BSDVM_COMPAT 1
+
+#ifdef DEBUG
+struct {
+ int kernel; /* entering kernel mapping */
+ int user; /* entering user mapping */
+ int ptpneeded; /* needed to allocate a PT page */
+ int pwchange; /* no mapping change, just wiring or protection */
+ int wchange; /* no mapping change, just wiring */
+ int mchange; /* was mapped but mapping to different page */
+ int managed; /* a managed page */
+ int firstpv; /* first mapping for this PA */
+ int secondpv; /* second mapping for this PA */
+ int ci; /* cache inhibited */
+ int unmanaged; /* not a managed page */
+ int flushes; /* cache flushes */
+} enter_stats;
+struct {
+ int calls;
+ int removes;
+ int pvfirst;
+ int pvsearch;
+ int ptinvalid;
+ int uflushes;
+ int sflushes;
+} remove_stats;
+
+int debugmap = 0;
+int pmapdebug = 0 /* 0xffff */;
+#define PDB_FOLLOW 0x0001
+#define PDB_INIT 0x0002
+#define PDB_ENTER 0x0004
+#define PDB_REMOVE 0x0008
+#define PDB_CREATE 0x0010
+#define PDB_PTPAGE 0x0020
+#define PDB_CACHE 0x0040
+#define PDB_BITS 0x0080
+#define PDB_COLLECT 0x0100
+#define PDB_PROTECT 0x0200
+#define PDB_PDRTAB 0x0400
+#define PDB_PARANOIA 0x2000
+#define PDB_WIRING 0x4000
+#define PDB_PVDUMP 0x8000
+
+int pmapvacflush = 0;
+#define PVF_ENTER 0x01
+#define PVF_REMOVE 0x02
+#define PVF_PROTECT 0x04
+#define PVF_TOTAL 0x80
+#endif
+
+/*
+ * Get PDEs and PTEs for user/kernel address space
+ */
+#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
+
+#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
+
+#define pmap_pde_v(pte) ((pte)->pd_v)
+#define pmap_pte_w(pte) ((pte)->pg_w)
+/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */
+#define pmap_pte_m(pte) ((pte)->pg_m)
+#define pmap_pte_u(pte) ((pte)->pg_u)
+#define pmap_pte_v(pte) ((pte)->pg_v)
+#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v))
+#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v))
+
+/*
+ * Given a map and a machine independent protection code,
+ * convert to a vax protection code.
+ */
+#define pte_prot(m, p) (protection_codes[p])
+int protection_codes[8];
+
+struct pmap kernel_pmap_store;
+pmap_t kernel_pmap;
+
+vm_offset_t avail_start; /* PA of first available physical page */
+vm_offset_t avail_end; /* PA of last available physical page */
+vm_size_t mem_size; /* memory size in bytes */
+vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/
+vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
+vm_offset_t vm_first_phys; /* PA of first managed page */
+vm_offset_t vm_last_phys; /* PA just past last managed page */
+int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
+boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
+char *pmap_attributes; /* reference and modify bits */
+
+boolean_t pmap_testbit();
+void pmap_clear_modify();
+
+#if BSDVM_COMPAT
+#include "msgbuf.h"
+
+/*
+ * All those kernel PT submaps that BSD is so fond of
+ */
+struct pte *CMAP1, *CMAP2, *mmap;
+caddr_t CADDR1, CADDR2, vmmap;
+struct pte *msgbufmap;
+struct msgbuf *msgbufp;
+#endif
+
+/*
+ * Bootstrap the system enough to run with virtual memory.
+ * Map the kernel's code and data, and allocate the system page table.
+ *
+ * On the I386 this is called after mapping has already been enabled
+ * and just syncs the pmap module with what has already been done.
+ * [We can't call it easily with mapping off since the kernel is not
+ * mapped with PA == VA, hence we would have to relocate every address
+ * from the linked base (virtual) address 0xFE000000 to the actual
+ * (physical) address starting relative to 0]
+ */
+struct pte *pmap_pte();
+
+void
+pmap_bootstrap(firstaddr, loadaddr)
+ vm_offset_t firstaddr;
+ vm_offset_t loadaddr;
+{
+#if BSDVM_COMPAT
+ vm_offset_t va;
+ struct pte *pte;
+#endif
+ extern vm_offset_t maxmem, physmem;
+extern int IdlePTD;
+
+ avail_start = firstaddr;
+ avail_end = maxmem << PG_SHIFT;
+
+ /* XXX: allow for msgbuf */
+ avail_end -= i386_round_page(sizeof(struct msgbuf));
+
+ mem_size = physmem << PG_SHIFT;
+ virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG;
+ virtual_end = VM_MAX_KERNEL_ADDRESS;
+ i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE;
+
+ /*
+ * Initialize protection array.
+ */
+ i386_protection_init();
+
+ /*
+ * The kernel's pmap is statically allocated so we don't
+ * have to use pmap_create, which is unlikely to work
+ * correctly at this part of the boot sequence.
+ */
+ kernel_pmap = &kernel_pmap_store;
+
+#ifdef notdef
+ /*
+ * Create Kernel page directory table and page maps.
+ * [ currently done in locore. i have wild and crazy ideas -wfj ]
+ */
+ bzero(firstaddr, 4*NBPG);
+ kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS;
+ kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG;
+
+ firstaddr += NBPG;
+ for (x = i386_btod(VM_MIN_KERNEL_ADDRESS);
+ x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) {
+ struct pde *pde;
+ pde = kernel_pmap->pm_pdir + x;
+ *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW;
+ }
+#else
+ kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD);
+#endif
+
+
+ simple_lock_init(&kernel_pmap->pm_lock);
+ kernel_pmap->pm_count = 1;
+
+#if BSDVM_COMPAT
+ /*
+ * Allocate all the submaps we need
+ */
+#define SYSMAP(c, p, v, n) \
+ v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n);
+
+ va = virtual_avail;
+ pte = pmap_pte(kernel_pmap, va);
+
+ SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 )
+ SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 )
+ SYSMAP(caddr_t ,mmap ,vmmap ,1 )
+ SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 )
+ virtual_avail = va;
+#endif
+ /*
+ * reserve special hunk of memory for use by bus dma as a bounce
+ * buffer (contiguous virtual *and* physical memory). for now,
+ * assume vm does not use memory beneath hole, and we know that
+ * the bootstrap uses top 32k of base memory. -wfj
+ */
+ {
+ extern vm_offset_t isaphysmem;
+ isaphysmem = va;
+
+ virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL);
+ }
+
+ *(int *)PTD = 0;
+ load_cr3(rcr3());
+
+}
+
+/*
+ * Initialize the pmap module.
+ * Called by vm_init, to initialize any structures that the pmap
+ * system needs to map virtual memory.
+ */
+void
+pmap_init(phys_start, phys_end)
+ vm_offset_t phys_start, phys_end;
+{
+ vm_offset_t addr, addr2;
+ vm_size_t npg, s;
+ int rv;
+ extern int KPTphys;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_init(%x, %x)\n", phys_start, phys_end);
+#endif
+ /*
+ * Now that kernel map has been allocated, we can mark as
+ * unavailable regions which we have mapped in locore.
+ */
+ addr = atdevbase;
+ (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
+ &addr, (0x100000-0xa0000), FALSE);
+
+ addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */;
+ vm_object_reference(kernel_object);
+ (void) vm_map_find(kernel_map, kernel_object, addr,
+ &addr, 2*NBPG, FALSE);
+
+ /*
+ * Allocate memory for random pmap data structures. Includes the
+ * pv_head_table and pmap_attributes.
+ */
+ npg = atop(phys_end - phys_start);
+ s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg);
+ s = round_page(s);
+ addr = (vm_offset_t) kmem_alloc(kernel_map, s);
+ pv_table = (pv_entry_t) addr;
+ addr += sizeof(struct pv_entry) * npg;
+ pmap_attributes = (char *) addr;
+#ifdef DEBUG
+ if (pmapdebug & PDB_INIT)
+ printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n",
+ s, npg, pv_table, pmap_attributes);
+#endif
+
+ /*
+ * Now it is safe to enable pv_table recording.
+ */
+ vm_first_phys = phys_start;
+ vm_last_phys = phys_end;
+ pmap_initialized = TRUE;
+}
+
+/*
+ * Used to map a range of physical addresses into kernel
+ * virtual address space.
+ *
+ * For now, VM is already on, we only need to map the
+ * specified memory.
+ */
+vm_offset_t
+pmap_map(virt, start, end, prot)
+ vm_offset_t virt;
+ vm_offset_t start;
+ vm_offset_t end;
+ int prot;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot);
+#endif
+ while (start < end) {
+ pmap_enter(kernel_pmap, virt, start, prot, FALSE);
+ virt += PAGE_SIZE;
+ start += PAGE_SIZE;
+ }
+ return(virt);
+}
+
+/*
+ * Create and return a physical map.
+ *
+ * If the size specified for the map
+ * is zero, the map is an actual physical
+ * map, and may be referenced by the
+ * hardware.
+ *
+ * If the size specified is non-zero,
+ * the map will be used in software only, and
+ * is bounded by that size.
+ *
+ * [ just allocate a ptd and mark it uninitialize -- should we track
+ * with a table which process has which ptd? -wfj ]
+ */
+
+pmap_t
+pmap_create(size)
+ vm_size_t size;
+{
+ register pmap_t pmap;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+ printf("pmap_create(%x)\n", size);
+#endif
+ /*
+ * Software use map does not need a pmap
+ */
+ if (size)
+ return(NULL);
+
+ /* XXX: is it ok to wait here? */
+ pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
+#ifdef notifwewait
+ if (pmap == NULL)
+ panic("pmap_create: cannot allocate a pmap");
+#endif
+ bzero(pmap, sizeof(*pmap));
+ pmap_pinit(pmap);
+ return (pmap);
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+void
+pmap_pinit(pmap)
+ register struct pmap *pmap;
+{
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+ pg("pmap_pinit(%x)\n", pmap);
+#endif
+
+ /*
+ * No need to allocate page table space yet but we do need a
+ * valid page directory table.
+ */
+ pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG);
+
+ /* wire in kernel global address entries */
+ bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST,
+ (KPTDI_LAST-KPTDI_FIRST+1)*4);
+
+ /* install self-referential address mapping entry */
+ *(int *)(pmap->pm_pdir+PTDPTDI) =
+ (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW;
+
+ pmap->pm_count = 1;
+ simple_lock_init(&pmap->pm_lock);
+}
+
+/*
+ * Retire the given physical map from service.
+ * Should only be called if the map contains
+ * no valid mappings.
+ */
+void
+pmap_destroy(pmap)
+ register pmap_t pmap;
+{
+ int count;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_destroy(%x)\n", pmap);
+#endif
+ if (pmap == NULL)
+ return;
+
+ simple_lock(&pmap->pm_lock);
+ count = --pmap->pm_count;
+ simple_unlock(&pmap->pm_lock);
+ if (count == 0) {
+ pmap_release(pmap);
+ free((caddr_t)pmap, M_VMPMAP);
+ }
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap)
+ register struct pmap *pmap;
+{
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ pg("pmap_release(%x)\n", pmap);
+#endif
+#ifdef notdef /* DIAGNOSTIC */
+ /* count would be 0 from pmap_destroy... */
+ simple_lock(&pmap->pm_lock);
+ if (pmap->pm_count != 1)
+ panic("pmap_release count");
+#endif
+ kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG);
+}
+
+/*
+ * Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap)
+ pmap_t pmap;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_reference(%x)", pmap);
+#endif
+ if (pmap != NULL) {
+ simple_lock(&pmap->pm_lock);
+ pmap->pm_count++;
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+/*
+ * Remove the given range of addresses from the specified map.
+ *
+ * It is assumed that the start and end are properly
+ * rounded to the page size.
+ */
+void
+pmap_remove(pmap, sva, eva)
+ struct pmap *pmap;
+ register vm_offset_t sva;
+ register vm_offset_t eva;
+{
+ register pt_entry_t *ptp,*ptq;
+ vm_offset_t va;
+ vm_offset_t pa;
+ pt_entry_t *pte;
+ pv_entry_t pv, npv;
+ int ix;
+ int s, bits;
+#ifdef DEBUG
+ pt_entry_t opte;
+
+ if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
+ pg("pmap_remove(%x, %x, %x)", pmap, sva, eva);
+#endif
+
+ if (pmap == NULL)
+ return;
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ ptp=PTmap;
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+#ifdef DEBUG
+ remove_stats.calls++;
+#endif
+
+ /* this is essential since we must check the PDE(sva) for precense */
+ while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva)))
+ sva = (sva & PD_MASK) + (1<<PD_SHIFT);
+ sva = i386_btop(sva);
+ eva = i386_btop(eva);
+
+ for (; sva < eva; sva++) {
+ /*
+ * Weed out invalid mappings.
+ * Note: we assume that the page directory table is
+ * always allocated, and in kernel virtual.
+ */
+ ptq=ptp+sva;
+ while((sva & 0x3ff) && !pmap_pte_pa(ptq))
+ {
+ if(++sva >= eva)
+ return;
+ ptq++;
+ }
+
+
+ if(!(sva & 0x3ff)) /* Only check once in a while */
+ {
+ if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva))))
+ {
+ /* We can race ahead here, straight to next pde.. */
+ sva = (sva & 0xffc00) + (1<<10) -1 ;
+ continue;
+ }
+ }
+ if(!pmap_pte_pa(ptp+sva))
+ continue;
+
+ pte = ptp + sva;
+ pa = pmap_pte_pa(pte);
+ va = i386_ptob(sva);
+#ifdef DEBUG
+ opte = *pte;
+ remove_stats.removes++;
+#endif
+ /*
+ * Update statistics
+ */
+ if (pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * Invalidate the PTEs.
+ * XXX: should cluster them up and invalidate as many
+ * as possible at once.
+ */
+#ifdef DEBUG
+ if (pmapdebug & PDB_REMOVE)
+ printf("remove: inv %x ptes at %x(%x) ",
+ i386pagesperpage, pte, *(int *)pte);
+#endif
+ bits = ix = 0;
+ do {
+ bits |= *(int *)pte & (PG_U|PG_M);
+ *(int *)pte++ = 0;
+ /*TBIS(va + ix * I386_PAGE_SIZE);*/
+ } while (++ix != i386pagesperpage);
+ if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pmap, (struct pcb *)curproc->p_addr);
+ /* are we current address space or kernel? */
+ /*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ load_cr3(curpcb->pcb_ptd);*/
+ tlbflush();
+
+#ifdef needednotdone
+reduce wiring count on page table pages as references drop
+#endif
+
+ /*
+ * Remove from the PV table (raise IPL since we
+ * may be called at interrupt time).
+ */
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ continue;
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * If it is the first entry on the list, it is actually
+ * in the header and we must copy the following entry up
+ * to the header. Otherwise we must search the list for
+ * the entry. In either case we free the now unused entry.
+ */
+ if (pmap == pv->pv_pmap && va == pv->pv_va) {
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free((caddr_t)npv, M_VMPVENT);
+ } else
+ pv->pv_pmap = NULL;
+#ifdef DEBUG
+ remove_stats.pvfirst++;
+#endif
+ } else {
+ for (npv = pv->pv_next; npv; npv = npv->pv_next) {
+#ifdef DEBUG
+ remove_stats.pvsearch++;
+#endif
+ if (pmap == npv->pv_pmap && va == npv->pv_va)
+ break;
+ pv = npv;
+ }
+#ifdef DEBUG
+ if (npv == NULL)
+ panic("pmap_remove: PA not in pv_tab");
+#endif
+ pv->pv_next = npv->pv_next;
+ free((caddr_t)npv, M_VMPVENT);
+ pv = pa_to_pvh(pa);
+ }
+
+#ifdef notdef
+[tally number of pagetable pages, if sharing of ptpages adjust here]
+#endif
+ /*
+ * Update saved attributes for managed page
+ */
+ pmap_attributes[pa_index(pa)] |= bits;
+ splx(s);
+ }
+#ifdef notdef
+[cache and tlb flushing, if needed]
+#endif
+}
+
+/*
+ * Routine: pmap_remove_all
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ */
+void
+pmap_remove_all(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+ int s;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
+ printf("pmap_remove_all(%x)", pa);
+ /*pmap_pvdump(pa);*/
+#endif
+ /*
+ * Not one of ours
+ */
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Do it the easy way for now
+ */
+ while (pv->pv_pmap != NULL) {
+#ifdef DEBUG
+ if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) ||
+ pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa)
+ panic("pmap_remove_all: bad mapping");
+#endif
+ pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE);
+ }
+ splx(s);
+}
+
+/*
+ * Routine: pmap_copy_on_write
+ * Function:
+ * Remove write privileges from all
+ * physical maps for this physical page.
+ */
+void
+pmap_copy_on_write(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
+ printf("pmap_copy_on_write(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_RO, TRUE);
+}
+
+/*
+ * Set the physical protection on the
+ * specified range of this map as requested.
+ */
+void
+pmap_protect(pmap, sva, eva, prot)
+ register pmap_t pmap;
+ vm_offset_t sva, eva;
+ vm_prot_t prot;
+{
+ register pt_entry_t *pte;
+ register vm_offset_t va;
+ register int ix;
+ int i386prot;
+ boolean_t firstpage = TRUE;
+ register pt_entry_t *ptp;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
+ printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot);
+#endif
+ if (pmap == NULL)
+ return;
+
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+ pmap_remove(pmap, sva, eva);
+ return;
+ }
+ if (prot & VM_PROT_WRITE)
+ return;
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ ptp=PTmap;
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+ for (va = sva; va < eva; va += PAGE_SIZE) {
+ /*
+ * Page table page is not allocated.
+ * Skip it, we don't want to force allocation
+ * of unnecessary PTE pages just to set the protection.
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ /* XXX: avoid address wrap around */
+ if (va >= i386_trunc_pdr((vm_offset_t)-1))
+ break;
+ va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE;
+ continue;
+ }
+
+ pte = ptp + i386_btop(va);
+
+ /*
+ * Page not valid. Again, skip it.
+ * Should we do this? Or set protection anyway?
+ */
+ if (!pmap_pte_v(pte))
+ continue;
+
+ ix = 0;
+ i386prot = pte_prot(pmap, prot);
+ if(va < UPT_MAX_ADDRESS)
+ i386prot |= 2 /*PG_u*/;
+ do {
+ /* clear VAC here if PG_RO? */
+ pmap_pte_set_prot(pte++, i386prot);
+ /*TBIS(va + ix * I386_PAGE_SIZE);*/
+ } while (++ix != i386pagesperpage);
+ }
+ if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pmap, (struct pcb *)curproc->p_addr);
+}
+
+/*
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * If specified, the page will be wired down, meaning
+ * that the related pte can not be reclaimed.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+void
+pmap_enter(pmap, va, pa, prot, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+ vm_prot_t prot;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register int npte, ix;
+ vm_offset_t opa;
+ boolean_t cacheable = TRUE;
+ boolean_t checkpv = TRUE;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))
+ printf("pmap_enter(%x, %x, %x, %x, %x)",
+ pmap, va, pa, prot, wired);
+#endif
+ if (pmap == NULL)
+ return;
+
+ if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig");
+ /* also, should not muck with PTD va! */
+
+#ifdef DEBUG
+ if (pmap == kernel_pmap)
+ enter_stats.kernel++;
+ else
+ enter_stats.user++;
+#endif
+
+ /*
+ * Page Directory table entry not valid, we need a new PT page
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ pg("ptdi %x", pmap->pm_pdir[PTDPTDI]);
+ }
+
+ pte = pmap_pte(pmap, va);
+ opa = pmap_pte_pa(pte);
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: pte %x, *pte %x ", pte, *(int *)pte);
+#endif
+
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+#ifdef DEBUG
+ enter_stats.pwchange++;
+#endif
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ pg("enter: wiring change -> %x ", wired);
+#endif
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+#ifdef DEBUG
+ enter_stats.wchange++;
+#endif
+ }
+ goto validate;
+ }
+
+ /*
+ * Mapping has changed, invalidate old range and fall through to
+ * handle validating new mapping.
+ */
+ if (opa) {
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: removing old mapping %x pa %x ", va, opa);
+#endif
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+#ifdef DEBUG
+ enter_stats.mchange++;
+#endif
+ }
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+ if (pa >= vm_first_phys && pa < vm_last_phys) {
+ register pv_entry_t pv, npv;
+ int s;
+
+#ifdef DEBUG
+ enter_stats.managed++;
+#endif
+ pv = pa_to_pvh(pa);
+ s = splimp();
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: pv at %x: %x/%x/%x ",
+ pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
+#endif
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+#ifdef DEBUG
+ enter_stats.firstpv++;
+#endif
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ pv->pv_flags = 0;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ /*printf("second time: ");*/
+#ifdef DEBUG
+ for (npv = pv; npv; npv = npv->pv_next)
+ if (pmap == npv->pv_pmap && va == npv->pv_va)
+ panic("pmap_enter: already in pv_tab");
+#endif
+ npv = (pv_entry_t)
+ malloc(sizeof *npv, M_VMPVENT, M_NOWAIT);
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+#ifdef DEBUG
+ if (!npv->pv_next)
+ enter_stats.secondpv++;
+#endif
+ }
+ splx(s);
+ }
+ /*
+ * Assumption: if it is not part of our managed memory
+ * then it must be device memory which may be volitile.
+ */
+ if (pmap_initialized) {
+ checkpv = cacheable = FALSE;
+#ifdef DEBUG
+ enter_stats.unmanaged++;
+#endif
+ }
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+ if (wired)
+ pmap->pm_stats.wired_count++;
+
+validate:
+ /*
+ * Now validate mapping with desired protection/wiring.
+ * Assume uniform modified and referenced status for all
+ * I386 pages in a MACH page.
+ */
+ npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V;
+ npte |= (*(int *)pte & (PG_M|PG_U));
+ if (wired)
+ npte |= PG_W;
+ if(va < UPT_MIN_ADDRESS)
+ npte |= PG_u;
+ else if(va < UPT_MAX_ADDRESS)
+ npte |= PG_u | PG_RW;
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: new pte value %x ", npte);
+#endif
+ ix = 0;
+ do {
+ *(int *)pte++ = npte;
+ /*TBIS(va);*/
+ npte += I386_PAGE_SIZE;
+ va += I386_PAGE_SIZE;
+ } while (++ix != i386pagesperpage);
+ pte--;
+#ifdef DEBUGx
+cache, tlb flushes
+#endif
+/*pads(pmap);*/
+ /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/
+ tlbflush();
+}
+
+/*
+ * pmap_page_protect:
+ *
+ * Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(phys, prot)
+ vm_offset_t phys;
+ vm_prot_t prot;
+{
+ switch (prot) {
+ case VM_PROT_READ:
+ case VM_PROT_READ|VM_PROT_EXECUTE:
+ pmap_copy_on_write(phys);
+ break;
+ case VM_PROT_ALL:
+ break;
+ default:
+ pmap_remove_all(phys);
+ break;
+ }
+}
+
+/*
+ * Routine: pmap_change_wiring
+ * Function: Change the wiring attribute for a map/virtual-address
+ * pair.
+ * In/out conditions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap, va, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired);
+#endif
+ if (pmap == NULL)
+ return;
+
+ pte = pmap_pte(pmap, va);
+#ifdef DEBUG
+ /*
+ * Page table page is not allocated.
+ * Should this ever happen? Ignore it for now,
+ * we don't want to force allocation of unnecessary PTE pages.
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ if (pmapdebug & PDB_PARANOIA)
+ pg("pmap_change_wiring: invalid PDE for %x ", va);
+ return;
+ }
+ /*
+ * Page not valid. Should this ever happen?
+ * Just continue and change wiring anyway.
+ */
+ if (!pmap_pte_v(pte)) {
+ if (pmapdebug & PDB_PARANOIA)
+ pg("pmap_change_wiring: invalid PTE for %x ", va);
+ }
+#endif
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ /*
+ * Wiring is not a hardware characteristic so there is no need
+ * to invalidate TLB.
+ */
+ ix = 0;
+ do {
+ pmap_pte_set_w(pte++, wired);
+ } while (++ix != i386pagesperpage);
+}
+
+/*
+ * Routine: pmap_pte
+ * Function:
+ * Extract the page table entry associated
+ * with the given map/virtual_address pair.
+ * [ what about induced faults -wfj]
+ */
+
+struct pte *pmap_pte(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_pte(%x, %x) ->\n", pmap, va);
+#endif
+ if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ return ((struct pte *) vtopte(va));
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ return((struct pte *) avtopte(va));
+ }
+ }
+ return(0);
+}
+
+/*
+ * Routine: pmap_extract
+ * Function:
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ */
+
+vm_offset_t
+pmap_extract(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+ register vm_offset_t pa;
+
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ pg("pmap_extract(%x, %x) -> ", pmap, va);
+#endif
+ pa = 0;
+ if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+ pa = *(int *) pmap_pte(pmap, va);
+ }
+ if (pa)
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ printf("%x\n", pa);
+#endif
+ return(pa);
+}
+
+/*
+ * Copy the range specified by src_addr/len
+ * from the source map to the range dst_addr/len
+ * in the destination map.
+ *
+ * This routine is only advisory and need not do anything.
+ */
+void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
+ pmap_t dst_pmap;
+ pmap_t src_pmap;
+ vm_offset_t dst_addr;
+ vm_size_t len;
+ vm_offset_t src_addr;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_copy(%x, %x, %x, %x, %x)",
+ dst_pmap, src_pmap, dst_addr, len, src_addr);
+#endif
+}
+
+/*
+ * Require that all active physical maps contain no
+ * incorrect entries NOW. [This update includes
+ * forcing updates of any address map caching.]
+ *
+ * Generally used to insure that a thread about
+ * to run will see a semantically correct world.
+ */
+void pmap_update()
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_update()");
+#endif
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_collect
+ * Function:
+ * Garbage collects the physical map system for
+ * pages which are no longer used.
+ * Success need not be guaranteed -- that is, there
+ * may well be pages which are not referenced, but
+ * others may be collected.
+ * Usage:
+ * Called by the pageout daemon when pages are scarce.
+ * [ needs to be written -wfj ]
+ */
+void
+pmap_collect(pmap)
+ pmap_t pmap;
+{
+ register vm_offset_t pa;
+ register pv_entry_t pv;
+ register int *pte;
+ vm_offset_t kpa;
+ int s;
+
+#ifdef DEBUG
+ int *pde;
+ int opmapdebug;
+ printf("pmap_collect(%x) ", pmap);
+#endif
+ if (pmap != kernel_pmap)
+ return;
+
+}
+
+/* [ macro again?, should I force kstack into user map here? -wfj ] */
+void
+pmap_activate(pmap, pcbp)
+ register pmap_t pmap;
+ struct pcb *pcbp;
+{
+int x;
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB))
+ pg("pmap_activate(%x, %x) ", pmap, pcbp);
+#endif
+ PMAP_ACTIVATE(pmap, pcbp);
+/*printf("pde ");
+for(x=0x3f6; x < 0x3fA; x++)
+ printf("%x ", pmap->pm_pdir[x]);*/
+/*pads(pmap);*/
+/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/
+}
+
+/*
+ * Routine: pmap_kernel
+ * Function:
+ * Returns the physical map handle for the kernel.
+ */
+pmap_t
+pmap_kernel()
+{
+ return (kernel_pmap);
+}
+
+/*
+ * pmap_zero_page zeros the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bzero to clear its contents, one machine dependent page
+ * at a time.
+ */
+pmap_zero_page(phys)
+ register vm_offset_t phys;
+{
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_zero_page(%x)", phys);
+#endif
+ phys >>= PG_SHIFT;
+ ix = 0;
+ do {
+ clearseg(phys++);
+ } while (++ix != i386pagesperpage);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bcopy to copy the page, one machine dependent page at a
+ * time.
+ */
+pmap_copy_page(src, dst)
+ register vm_offset_t src, dst;
+{
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_copy_page(%x, %x)", src, dst);
+#endif
+ src >>= PG_SHIFT;
+ dst >>= PG_SHIFT;
+ ix = 0;
+ do {
+ physcopyseg(src++, dst++);
+ } while (++ix != i386pagesperpage);
+}
+
+
+/*
+ * Routine: pmap_pageable
+ * Function:
+ * Make the specified pages (by pmap, offset)
+ * pageable (or not) as requested.
+ *
+ * A page which is not pageable may not take
+ * a fault; therefore, its page table entry
+ * must remain valid for the duration.
+ *
+ * This routine is merely advisory; pmap_enter
+ * will specify that these pages are to be wired
+ * down (or not) as appropriate.
+ */
+pmap_pageable(pmap, sva, eva, pageable)
+ pmap_t pmap;
+ vm_offset_t sva, eva;
+ boolean_t pageable;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_pageable(%x, %x, %x, %x)",
+ pmap, sva, eva, pageable);
+#endif
+ /*
+ * If we are making a PT page pageable then all valid
+ * mappings must be gone from that page. Hence it should
+ * be all zeros and there is no need to clean it.
+ * Assumptions:
+ * - we are called with only one page at a time
+ * - PT pages have only one pv_table entry
+ */
+ if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) {
+ register pv_entry_t pv;
+ register vm_offset_t pa;
+
+#ifdef DEBUG
+ if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE)
+ printf("pmap_pageable(%x, %x, %x, %x)",
+ pmap, sva, eva, pageable);
+#endif
+ /*if (!pmap_pde_v(pmap_pde(pmap, sva)))
+ return;*/
+ if(pmap_pte(pmap, sva) == 0)
+ return;
+ pa = pmap_pte_pa(pmap_pte(pmap, sva));
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+ pv = pa_to_pvh(pa);
+ /*if (!ispt(pv->pv_va))
+ return;*/
+#ifdef DEBUG
+ if (pv->pv_va != sva || pv->pv_next) {
+ pg("pmap_pageable: bad PT page va %x next %x\n",
+ pv->pv_va, pv->pv_next);
+ return;
+ }
+#endif
+ /*
+ * Mark it unmodified to avoid pageout
+ */
+ pmap_clear_modify(pa);
+#ifdef needsomethinglikethis
+ if (pmapdebug & PDB_PTPAGE)
+ pg("pmap_pageable: PT page %x(%x) unmodified\n",
+ sva, *(int *)pmap_pte(pmap, sva));
+ if (pmapdebug & PDB_WIRING)
+ pmap_check_wiring("pageable", sva);
+#endif
+ }
+}
+
+/*
+ * Clear the modify bits on the specified physical page.
+ */
+
+void
+pmap_clear_modify(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_clear_modify(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_M, FALSE);
+}
+
+/*
+ * pmap_clear_reference:
+ *
+ * Clear the reference bit on the specified physical page.
+ */
+
+void pmap_clear_reference(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_clear_reference(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_U, FALSE);
+}
+
+/*
+ * pmap_is_referenced:
+ *
+ * Return whether or not the specified physical page is referenced
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_referenced(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW) {
+ boolean_t rv = pmap_testbit(pa, PG_U);
+ printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]);
+ return(rv);
+ }
+#endif
+ return(pmap_testbit(pa, PG_U));
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Return whether or not the specified physical page is modified
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_modified(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW) {
+ boolean_t rv = pmap_testbit(pa, PG_M);
+ printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]);
+ return(rv);
+ }
+#endif
+ return(pmap_testbit(pa, PG_M));
+}
+
+vm_offset_t
+pmap_phys_address(ppn)
+ int ppn;
+{
+ return(i386_ptob(ppn));
+}
+
+/*
+ * Miscellaneous support routines follow
+ */
+
+i386_protection_init()
+{
+ register int *kp, prot;
+
+ kp = protection_codes;
+ for (prot = 0; prot < 8; prot++) {
+ switch (prot) {
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
+ *kp++ = 0;
+ break;
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
+ *kp++ = PG_RO;
+ break;
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ *kp++ = PG_RW;
+ break;
+ }
+ }
+}
+
+boolean_t
+pmap_testbit(pa, bit)
+ register vm_offset_t pa;
+ int bit;
+{
+ register pv_entry_t pv;
+ register int *pte, ix;
+ int s;
+
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return(FALSE);
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Check saved info first
+ */
+ if (pmap_attributes[pa_index(pa)] & bit) {
+ splx(s);
+ return(TRUE);
+ }
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va);
+ ix = 0;
+ do {
+ if (*pte++ & bit) {
+ splx(s);
+ return(TRUE);
+ }
+ } while (++ix != i386pagesperpage);
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+pmap_changebit(pa, bit, setem)
+ register vm_offset_t pa;
+ int bit;
+ boolean_t setem;
+{
+ register pv_entry_t pv;
+ register int *pte, npte, ix;
+ vm_offset_t va;
+ int s;
+ boolean_t firstpage = TRUE;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_BITS)
+ printf("pmap_changebit(%x, %x, %s)",
+ pa, bit, setem ? "set" : "clear");
+#endif
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Clear saved attributes (modify, reference)
+ */
+ if (!setem)
+ pmap_attributes[pa_index(pa)] &= ~bit;
+ /*
+ * Loop over all current mappings setting/clearing as appropos
+ * If setting RO do we need to clear the VAC?
+ */
+ if (pv->pv_pmap != NULL) {
+#ifdef DEBUG
+ int toflush = 0;
+#endif
+ for (; pv; pv = pv->pv_next) {
+#ifdef DEBUG
+ toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1;
+#endif
+ va = pv->pv_va;
+
+ /*
+ * XXX don't write protect pager mappings
+ */
+ if (bit == PG_RO) {
+ extern vm_offset_t pager_sva, pager_eva;
+
+ if (va >= pager_sva && va < pager_eva)
+ continue;
+ }
+
+ pte = (int *) pmap_pte(pv->pv_pmap, va);
+ ix = 0;
+ do {
+ if (setem)
+ npte = *pte | bit;
+ else
+ npte = *pte & ~bit;
+ if (*pte != npte) {
+ *pte = npte;
+ /*TBIS(va);*/
+ }
+ va += I386_PAGE_SIZE;
+ pte++;
+ } while (++ix != i386pagesperpage);
+
+ if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr);
+ }
+#ifdef somethinglikethis
+ if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) {
+ if ((pmapvacflush & PVF_TOTAL) || toflush == 3)
+ DCIA();
+ else if (toflush == 2)
+ DCIS();
+ else
+ DCIU();
+ }
+#endif
+ }
+ splx(s);
+}
+
+#ifdef DEBUG
+pmap_pvdump(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+
+ printf("pa %x", pa);
+ for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
+ printf(" -> pmap %x, va %x, flags %x",
+ pv->pv_pmap, pv->pv_va, pv->pv_flags);
+ pads(pv->pv_pmap);
+ }
+ printf(" ");
+}
+
+#ifdef notyet
+pmap_check_wiring(str, va)
+ char *str;
+ vm_offset_t va;
+{
+ vm_map_entry_t entry;
+ register int count, *pte;
+
+ va = trunc_page(va);
+ if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) ||
+ !pmap_pte_v(pmap_pte(kernel_pmap, va)))
+ return;
+
+ if (!vm_map_lookup_entry(pt_map, va, &entry)) {
+ pg("wired_check: entry for %x not found\n", va);
+ return;
+ }
+ count = 0;
+ for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++)
+ if (*pte)
+ count++;
+ if (entry->wired_count != count)
+ pg("*%s*: %x: w%d/a%d\n",
+ str, va, entry->wired_count, count);
+}
+#endif
+
+/* print address space of pmap*/
+pads(pm) pmap_t pm; {
+ unsigned va, i, j;
+ struct pte *ptep;
+
+ if(pm == kernel_pmap) return;
+ for (i = 0; i < 1024; i++)
+ if(pm->pm_pdir[i].pd_v)
+ for (j = 0; j < 1024 ; j++) {
+ va = (i<<22)+(j<<12);
+ if (pm == kernel_pmap && va < 0xfe000000)
+ continue;
+ if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
+ continue;
+ ptep = pmap_pte(pm, va);
+ if(pmap_pte_v(ptep))
+ printf("%x:%x ", va, *(int *)ptep);
+ } ;
+
+}
+#endif
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
new file mode 100644
index 0000000..10b9ac2
--- /dev/null
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -0,0 +1,105 @@
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "file.h"
+#include "time.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "mtio.h"
+#include "buf.h"
+#include "trace.h"
+
+#ifdef TRACE
+int nvualarm;
+
+vtrace(p, uap, retval)
+ struct proc *p;
+ register struct args {
+ int request;
+ int value;
+ } *uap;
+ int *retval;
+{
+ int vdoualarm();
+
+ switch (uap->request) {
+
+ case VTR_DISABLE: /* disable a trace point */
+ case VTR_ENABLE: /* enable a trace point */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ traceflags[uap->value] = uap->request;
+ break;
+
+ case VTR_VALUE: /* return a trace point setting */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ break;
+
+ case VTR_UALARM: /* set a real-time ualarm, less than 1 min */
+ if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+ return (EINVAL);
+ nvualarm++;
+ timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+ break;
+
+ case VTR_STAMP:
+ trace(TR_STAMP, uap->value, p->p_pid);
+ break;
+ }
+ return (0);
+}
+
+vdoualarm(arg)
+ int arg;
+{
+ register struct proc *p;
+
+ p = pfind(arg);
+ if (p)
+ psignal(p, 16);
+ nvualarm--;
+}
+#endif
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
new file mode 100644
index 0000000..57195f3
--- /dev/null
+++ b/sys/amd64/amd64/trap.c
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.c 7.4 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00137
+ * -------------------- ----- ----------------------
+ *
+ * 08 Apr 93 Bruce Evans Several VM system fixes
+ * Paul Kranenburg Add counter for vmstat
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $";
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+
+struct sysent sysent[];
+int nsysent;
+int dostacklimits;
+unsigned rcr2();
+extern short cpl;
+
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#include "ddb.h"
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, rcr2(), frame.tf_esp);*/
+if(curpcb == 0 || curproc == 0) goto we_re_toast;
+ if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) {
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+ }
+
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+ switch (type) {
+
+ default:
+ we_re_toast:
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+
+ printf("trap type %d code = %x eip = %x cs = %x eflags = %x ",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, frame.tf_eflags);
+ eva = rcr2();
+ printf("cr2 %x cpl %x\n", eva, cpl);
+ /* type &= ~T_USER; */ /* XXX what the hell is this */
+ panic("trap");
+ /*NOTREACHED*/
+
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#ifdef NPX
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif
+ i = math_emulate(&frame);
+ if (i == 0) return;
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+#if 0
+ /* XXX - check only applies to 386's and 486's with WP off */
+ if (code & PGEX_P) goto we_re_toast;
+#endif
+
+ /* fall into */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ register vm_offset_t va;
+ register struct vmspace *vm = p->p_vmspace;
+ register vm_map_t map;
+ int rv;
+ vm_prot_t ftype;
+ extern vm_map_t kernel_map;
+ unsigned nss,v;
+
+ va = trunc_page((vm_offset_t)eva);
+ /*
+ * Avoid even looking at pde_v(va) for high va's. va's
+ * above VM_MAX_KERNEL_ADDRESS don't correspond to normal
+ * PDE's (half of them correspond to APDEpde and half to
+ * an unmapped kernel PDE). va's betweeen 0xFEC00000 and
+ * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's
+ * (XXX - why are only 3 initialized when 6 are required to
+ * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped
+ * kernel page table would give inconsistent PTD's.
+ *
+ * XXX - faulting in unmapped page tables wastes a page if
+ * va turns out to be invalid.
+ *
+ * XXX - should "kernel address space" cover the kernel page
+ * tables? Might have same problem with PDEpde as with
+ * APDEpde (or there may be no problem with APDEpde).
+ */
+ if (va > 0xFEBFF000) {
+ rv = KERN_FAILURE; /* becomes SIGBUS */
+ goto nogo;
+ }
+ /*
+ * It is only a kernel address space fault iff:
+ * 1. (type & T_USER) == 0 and
+ * 2. pcb_onfault not set or
+ * 3. pcb_onfault set but supervisor space fault
+ * The last can occur during an exec() copyin where the
+ * argument space is lazy-allocated.
+ */
+ if (type == T_PAGEFLT && va >= KERNBASE)
+ map = kernel_map;
+ else
+ map = &vm->vm_map;
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+#ifdef DEBUG
+ if (map == kernel_map && va == 0) {
+ printf("trap: bad kernel access at %x\n", va);
+ goto we_re_toast;
+ }
+#endif
+
+ /*
+ * XXX: rude hack to make stack limits "work"
+ */
+ nss = 0;
+ if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map
+ && dostacklimits) {
+ nss = clrnd(btoc((unsigned)vm->vm_maxsaddr
+ + MAXSSIZ - (unsigned)va));
+ if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
+/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/
+ rv = KERN_FAILURE;
+ goto nogo;
+ }
+ }
+
+ /* check if page table is mapped, if not, fault it first */
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+ if (!pde_v(va)) {
+ v = trunc_page(vtopte(va));
+ rv = vm_fault(map, v, ftype, FALSE);
+ if (rv != KERN_SUCCESS) goto nogo;
+ /* check if page table fault, increment wiring */
+ vm_map_pageable(map, v, round_page(v+1), FALSE);
+ } else v=0;
+ rv = vm_fault(map, va, ftype, FALSE);
+ if (rv == KERN_SUCCESS) {
+ /*
+ * XXX: continuation of rude stack hack
+ */
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ va = trunc_page(vtopte(va));
+ /* for page table, increment wiring
+ as long as not a page table fault as well */
+ if (!v && type != T_PAGEFLT)
+ vm_map_pageable(map, va, round_page(va+1), FALSE);
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+ printf("vm_fault(%x, %x, %x, 0) -> %x\n",
+ map, va, ftype, rv);
+ printf(" type %x, code %x\n",
+ type, code);
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#include "isa.h"
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if(isa_nmi(code) == 0) return;
+ else goto we_re_toast;
+#endif
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR)
+ */
+int trapwrite(unsigned addr) {
+ int rv;
+ vm_offset_t va;
+
+ va = trunc_page((vm_offset_t)addr);
+ if (va > VM_MAXUSER_ADDRESS) return(1);
+ rv = vm_fault(&curproc->p_vmspace->vm_map, va,
+ VM_PROT_READ | VM_PROT_WRITE, FALSE);
+ if (rv == KERN_SUCCESS) return(0);
+ else return(1);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+syscall(frame)
+ volatile struct syscframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.sf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.sf_eax;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.sf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.sf_eip - 7;
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ if (callp == sysent) {
+ i = fuword(params);
+ params += sizeof (int);
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ }
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.sf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.sf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.sf_eax = rval[0];
+ frame.sf_edx = rval[1];
+ frame.sf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.sf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.sf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.sf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.sf_ss, code);
+ if ((frame.sf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.sf_cs, code);
+ if (frame.sf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.sf_eip, code);
+ frame.sf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c
new file mode 100644
index 0000000..0fb7701
--- /dev/null
+++ b/sys/amd64/amd64/tsc.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 14 Aug 92 Arne Henrik Juul Added code in the kernel to
+ * allow for DST in the BIOS.
+ * 17 Jan 93 Bruce Evans Fixed leap year and second
+ * calculations
+ * 01 Feb 93 Julian Elischer Added code to for the cpu
+ * speed independent spinwait()
+ * function, (used by scsi and others)
+ * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1
+ * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock
+ * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait
+ * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I
+ * still kept the other fixes... Had to
+ * add back in findcpuspeed that Bruce
+ * had removed.
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+#define DAYST 119
+#define DAYEN 303
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+
+startrtclock() {
+ int s;
+
+ findcpuspeed(); /* use the clock (while it's free)
+ to find the cpu speed */
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
+ outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+ outb (IO_RTC, RTC_DIAG);
+ outb (IO_RTC+1, 0);
+}
+
+unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
+
+#define FIRST_GUESS 0x2000
+findcpuspeed()
+{
+ unsigned char low;
+ unsigned int remainder;
+
+ /* Put counter in count down mode */
+ outb(IO_TIMER1+3, 0x34);
+ outb(IO_TIMER1, 0xff);
+ outb(IO_TIMER1, 0xff);
+ delaycount = FIRST_GUESS;
+ spinwait(1);
+ /* Read the value left in the counter */
+ low = inb(IO_TIMER1); /* least siginifcant */
+ remainder = inb(IO_TIMER1); /* most significant */
+ remainder = (remainder<<8) + low ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ */
+ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
+}
+
+
+/* convert 2 digit BCD number */
+bcd(i)
+int i;
+{
+ return ((i/16)*10 + (i%16));
+}
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(y)
+int y;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+/* convert months to seconds */
+unsigned long
+mtos(m,leap)
+int m,leap;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1;i<m;i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+inittodr(base)
+ time_t base;
+{
+ unsigned long sec;
+ int leap,day_week,t,yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+
+ /* XXX off by one? Need to calculate DST on SUNDAY */
+ /* Perhaps we should have the RTC hold GMT time to save */
+ /* us the bother of converting. */
+ yd = yd / (24*60*60);
+ if ((yd >= DAYST) && ( yd <= DAYEN)) {
+ sec -= 60*60;
+ }
+ sec += tz.tz_minuteswest * 60;
+
+ time.tv_sec = sec;
+}
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(base)
+ time_t base;
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Restart the clock.
+ */
+resettodr()
+{
+}
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern V(clk)();
+enablertclock() {
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(millisecs)
+ int millisecs;
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
new file mode 100644
index 0000000..27ef912
--- /dev/null
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -0,0 +1,410 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/vm_machdep.c,v 1.2 92/01/21 14:22:17 william Exp $";
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "user.h"
+
+#include "../include/cpu.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+cpu_fork(p1, p2)
+ register struct proc *p1, *p2;
+{
+ register struct user *up = p2->p_addr;
+ int foo, offset, addr, i;
+ extern char kstack[];
+ extern int mvesp();
+
+ /*
+ * Copy pcb and stack from proc p1 to p2.
+ * We do this as cheaply as possible, copying only the active
+ * part of the stack. The stack and pcb need to agree;
+ * this is tricky, as the final pcb is constructed by savectx,
+ * but its frame isn't yet on the stack when the stack is copied.
+ * swtch compensates for this when the child eventually runs.
+ * This should be done differently, with a single call
+ * that copies and updates the pcb+stack,
+ * replacing the bcopy and savectx.
+ */
+ p2->p_addr->u_pcb = p1->p_addr->u_pcb;
+ offset = mvesp() - (int)kstack;
+ bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
+ (unsigned) ctob(UPAGES) - offset);
+ p2->p_regs = p1->p_regs;
+
+ /*
+ * Wire top of address space of child to it's kstack.
+ * First, fault in a page of pte's to map it.
+ */
+ addr = trunc_page((u_int)vtopte(kstack));
+ vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
+ for (i=0; i < UPAGES; i++)
+ pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
+ pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG), VM_PROT_READ, 1);
+
+ pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
+
+ /*
+ *
+ * Arrange for a non-local goto when the new process
+ * is started, to resume here, returning nonzero from setjmp.
+ */
+ if (savectx(up, 1)) {
+ /*
+ * Return 1 in child.
+ */
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef notyet
+/*
+ * cpu_exit is called as the last action during exit.
+ *
+ * We change to an inactive address space and a "safe" stack,
+ * passing thru an argument to the new stack. Now, safely isolated
+ * from the resources we're shedding, we release the address space
+ * and any remaining machine-dependent resources, including the
+ * memory for the user structure and kernel stack.
+ *
+ * Next, we assign a dummy context to be written over by swtch,
+ * calling it to send this process off to oblivion.
+ * [The nullpcb allows us to minimize cost in swtch() by not having
+ * a special case].
+ */
+struct proc *swtch_to_inactive();
+cpu_exit(p)
+ register struct proc *p;
+{
+ static struct pcb nullpcb; /* pcb to overwrite on last swtch */
+
+#ifdef NPX
+ npxexit(p);
+#endif
+
+ /* move to inactive space and stack, passing arg accross */
+ p = swtch_to_inactive(p);
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+
+ p->p_addr = (struct user *) &nullpcb;
+ splclock();
+ swtch();
+ /* NOTREACHED */
+}
+#else
+cpu_exit(p)
+ register struct proc *p;
+{
+
+#ifdef NPX
+ npxexit(p);
+#endif
+ splclock();
+ swtch();
+}
+
+cpu_wait(p) struct proc *p; {
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+}
+#endif
+
+/*
+ * Set a red zone in the kernel stack after the u. area.
+ */
+setredzone(pte, vaddr)
+ u_short *pte;
+ caddr_t vaddr;
+{
+/* eventually do this by setting up an expand-down stack segment
+ for ss0: selector, allowing stack access down to top of u.
+ this means though that protection violations need to be handled
+ thru a double fault exception that must do an integral task
+ switch to a known good context, within which a dump can be
+ taken. a sensible scheme might be to save the initial context
+ used by sched (that has physical memory mapped 1:1 at bottom)
+ and take the dump while still in mapped mode */
+}
+
+/*
+ * Move pages from one kernel virtual address to another.
+ * Both addresses are assumed to reside in the Sysmap,
+ * and size must be a multiple of CLSIZE.
+ */
+pagemove(from, to, size)
+ register caddr_t from, to;
+ int size;
+{
+ register struct pte *fpte, *tpte;
+
+ if (size % CLBYTES)
+ panic("pagemove");
+ fpte = kvtopte(from);
+ tpte = kvtopte(to);
+ while (size > 0) {
+ *tpte++ = *fpte;
+ *(int *)fpte++ = 0;
+ from += NBPG;
+ to += NBPG;
+ size -= NBPG;
+ }
+ tlbflush();
+}
+
+/*
+ * Convert kernel VA to physical address
+ */
+kvtop(addr)
+ register caddr_t addr;
+{
+ vm_offset_t va;
+
+ va = pmap_extract(kernel_pmap, (vm_offset_t)addr);
+ if (va == 0)
+ panic("kvtop: zero page frame");
+ return((int)va);
+}
+
+#ifdef notdef
+/*
+ * The probe[rw] routines should probably be redone in assembler
+ * for efficiency.
+ */
+prober(addr)
+ register u_int addr;
+{
+ register int page;
+ register struct proc *p;
+
+ if (addr >= USRSTACK)
+ return(0);
+ p = u.u_procp;
+ page = btop(addr);
+ if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
+ return(1);
+ return(0);
+}
+
+probew(addr)
+ register u_int addr;
+{
+ register int page;
+ register struct proc *p;
+
+ if (addr >= USRSTACK)
+ return(0);
+ p = u.u_procp;
+ page = btop(addr);
+ if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
+ return((*(int *)vtopte(p, page) & PG_PROT) == PG_UW);
+ return(0);
+}
+
+/*
+ * NB: assumes a physically contiguous kernel page table
+ * (makes life a LOT simpler).
+ */
+kernacc(addr, count, rw)
+ register u_int addr;
+ int count, rw;
+{
+ register struct pde *pde;
+ register struct pte *pte;
+ register int ix, cnt;
+ extern long Syssize;
+
+ if (count <= 0)
+ return(0);
+ pde = (struct pde *)((u_int)u.u_procp->p_p0br + u.u_procp->p_szpt * NBPG);
+ ix = (addr & PD_MASK) >> PD_SHIFT;
+ cnt = ((addr + count + (1 << PD_SHIFT) - 1) & PD_MASK) >> PD_SHIFT;
+ cnt -= ix;
+ for (pde += ix; cnt; cnt--, pde++)
+ if (pde->pd_v == 0)
+ return(0);
+ ix = btop(addr-0xfe000000);
+ cnt = btop(addr-0xfe000000+count+NBPG-1);
+ if (cnt > (int)&Syssize)
+ return(0);
+ cnt -= ix;
+ for (pte = &Sysmap[ix]; cnt; cnt--, pte++)
+ if (pte->pg_v == 0 /*|| (rw == B_WRITE && pte->pg_prot == 1)*/)
+ return(0);
+ return(1);
+}
+
+useracc(addr, count, rw)
+ register u_int addr;
+ int count, rw;
+{
+ register int (*func)();
+ register u_int addr2;
+ extern int prober(), probew();
+
+ if (count <= 0)
+ return(0);
+ addr2 = addr;
+ addr += count;
+ func = (rw == B_READ) ? prober : probew;
+ do {
+ if ((*func)(addr2) == 0)
+ return(0);
+ addr2 = (addr2 + NBPG) & ~PGOFSET;
+ } while (addr2 < addr);
+ return(1);
+}
+#endif
+
+extern vm_map_t phys_map;
+
+/*
+ * Map an IO request into kernel virtual address space. Requests fall into
+ * one of five catagories:
+ *
+ * B_PHYS|B_UAREA: User u-area swap.
+ * Address is relative to start of u-area (p_addr).
+ * B_PHYS|B_PAGET: User page table swap.
+ * Address is a kernel VA in usrpt (Usrptmap).
+ * B_PHYS|B_DIRTY: Dirty page push.
+ * Address is a VA in proc2's address space.
+ * B_PHYS|B_PGIN: Kernel pagein of user pages.
+ * Address is VA in user's address space.
+ * B_PHYS: User "raw" IO request.
+ * Address is VA in user's address space.
+ *
+ * All requests are (re)mapped into kernel VA space via the useriomap
+ * (a name with only slightly more meaning than "kernelmap")
+ */
+vmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr;
+ register long flags = bp->b_flags;
+ struct proc *p;
+ int off;
+ vm_offset_t kva;
+ register vm_offset_t pa;
+
+ if ((flags & B_PHYS) == 0)
+ panic("vmapbuf");
+ addr = bp->b_saveaddr = bp->b_un.b_addr;
+ off = (int)addr & PGOFSET;
+ p = bp->b_proc;
+ npf = btoc(round_page(bp->b_bcount + off));
+ kva = kmem_alloc_wait(phys_map, ctob(npf));
+ bp->b_un.b_addr = (caddr_t) (kva + off);
+ while (npf--) {
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
+ if (pa == 0)
+ panic("vmapbuf: null page frame");
+ pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
+ VM_PROT_READ|VM_PROT_WRITE, TRUE);
+ addr += PAGE_SIZE;
+ kva += PAGE_SIZE;
+ }
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also invalidate the TLB entries and restore the original b_addr.
+ */
+vunmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr = bp->b_un.b_addr;
+ vm_offset_t kva;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+ npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
+ kva = (vm_offset_t)((int)addr & ~PGOFSET);
+ kmem_free_wakeup(phys_map, kva, ctob(npf));
+ bp->b_un.b_addr = bp->b_saveaddr;
+ bp->b_saveaddr = NULL;
+}
+
+/*
+ * Force reset the processor by invalidating the entire address space!
+ */
+cpu_reset() {
+
+ /* force a shutdown by unmapping entire address space ! */
+ bzero((caddr_t) PTD, NBPG);
+
+ /* "good night, sweet prince .... <THUNK!>" */
+ tlbflush();
+ /* NOTREACHED */
+}
diff --git a/sys/amd64/include/cpu.h b/sys/amd64/include/cpu.h
new file mode 100644
index 0000000..583d76c
--- /dev/null
+++ b/sys/amd64/include/cpu.h
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cpu.h 5.4 (Berkeley) 5/9/91
+ */
+
+/*
+ * Definitions unique to i386 cpu support.
+ */
+#include "machine/frame.h"
+#include "machine/segments.h"
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */
+
+/*
+ * function vs. inline configuration;
+ * these are defined to get generic functions
+ * rather than inline or machine-dependent implementations
+ */
+#define NEED_MINMAX /* need {,i,l,ul}{min,max} functions */
+#define NEED_FFS /* need ffs function */
+#define NEED_BCMP /* need bcmp function */
+#define NEED_STRLEN /* need strlen function */
+
+#define cpu_exec(p) /* nothing */
+
+/*
+ * Arguments to hardclock, softclock and gatherstats
+ * encapsulate the previous machine state in an opaque
+ * clockframe; for now, use generic intrframe.
+ */
+typedef struct intrframe clockframe;
+
+#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL)
+#define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0)
+#define CLKF_PC(framep) ((framep)->if_eip)
+
+#define resettodr() /* no todr to set */
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+#define need_resched() { want_resched++; aston(); }
+
+/*
+ * Give a profiling tick to the current process from the softclock
+ * interrupt. On tahoe, request an ast to send us through trap(),
+ * marking the proc as needing a profiling tick.
+ */
+#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); }
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+#define signotify(p) aston()
+
+#define aston() (astpending++)
+
+int astpending; /* need to trap before returning to user mode */
+int want_resched; /* resched() was called */
+
+/*
+ * Kinds of processor
+ */
+
+#define CPU_386SX 0
+#define CPU_386 1
+#define CPU_486SX 2
+#define CPU_486 3
+#define CPU_586 4
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
new file mode 100644
index 0000000..e3b4a8c
--- /dev/null
+++ b/sys/amd64/include/cpufunc.h
@@ -0,0 +1,82 @@
+/*
+ * Functions to provide access to special i386 instructions.
+ * XXX - bezillions more are defined in locore.s but are not declared anywhere.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#ifdef __GNUC__
+
+static __inline int bdb(void)
+{
+ extern int bdb_exists;
+
+ if (!bdb_exists)
+ return (0);
+ __asm("int $3");
+ return (1);
+}
+
+static __inline void
+disable_intr(void)
+{
+ __asm __volatile("cli");
+}
+
+static __inline void
+enable_intr(void)
+{
+ __asm __volatile("sti");
+}
+
+/*
+ * This roundabout method of returning a u_char helps stop gcc-1.40 from
+ * generating unnecessary movzbl's.
+ */
+#define inb(port) ((u_char) u_int_inb(port))
+
+static __inline u_int
+u_int_inb(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static __inline void
+outb(u_int port, u_char data)
+{
+ register u_char al asm("ax");
+
+ al = data; /* help gcc-1.40's register allocator */
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
+
+#else /* not __GNUC__ */
+
+int bdb __P((void));
+void disable_intr __P((void));
+void enable_intr __P((void));
+u_char inb __P((u_int port));
+void outb __P((u_int port, u_int data)); /* XXX - incompat */
+
+#endif /* __GNUC__ */
+
+#define really_u_int int /* XXX */
+#define really_void int /* XXX */
+
+void load_cr0 __P((u_int cr0));
+really_u_int rcr0 __P((void));
+
+#ifdef notyet
+really_void setidt __P((int idx, /*XXX*/caddr_t func, int typ, int dpl));
+#endif
+
+#undef really_u_int
+#undef really_void
diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h
new file mode 100644
index 0000000..8e37eec
--- /dev/null
+++ b/sys/amd64/include/db_machdep.h
@@ -0,0 +1,154 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_machdep.h,v $
+ * Revision 2.8 92/02/19 15:07:56 elf
+ * Added db_thread_fp_used.
+ * [92/02/19 rpd]
+ *
+ * Revision 2.7 91/10/09 16:06:28 af
+ * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh
+ * Added access and task name macros.
+ * [91/08/29 tak]
+ *
+ * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh
+ * Added access and task name macros.
+ * [91/08/29 tak]
+ *
+ * Revision 2.6 91/05/14 16:05:58 mrt
+ * Correcting copyright
+ *
+ * Revision 2.5 91/02/05 17:11:17 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:24 mrt]
+ *
+ * Revision 2.4 91/01/08 15:10:16 rpd
+ * Added dummy inst_load/inst_store macros.
+ * [90/12/11 rpd]
+ *
+ * Revision 2.3 90/10/25 14:44:49 rwd
+ * Added watchpoint support.
+ * [90/10/18 rpd]
+ *
+ * Revision 2.2 90/08/27 21:56:15 dbg
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+
+#ifndef _I386_DB_MACHDEP_H_
+#define _I386_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+
+/* #include <mach/i386/vm_types.h> */
+/* #include <mach/i386/vm_param.h> */
+#include <vm/vm_prot.h>
+#include <vm/vm_param.h>
+#include <vm/vm_inherit.h>
+#include <vm/lock.h>
+/* #include <i386/thread.h> */ /* for thread_status */
+#include <machine/frame.h> /* for struct trapframe */
+/* #include <i386/eflags.h> */
+#include <machine/eflags.h> /* from Mach... */
+/* #include <i386/trap.h> */
+#include <machine/trap.h>
+
+#define i386_saved_state trapframe
+/* end of mangling */
+
+typedef vm_offset_t db_addr_t; /* address - unsigned */
+typedef int db_expr_t; /* expression - signed */
+
+typedef struct i386_saved_state db_regs_t;
+db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip)
+
+#define BKPT_INST 0xcc /* breakpoint instruction */
+#define BKPT_SIZE (1) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1;
+
+#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF)
+#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF)
+
+/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */
+/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */
+/* using the 386bsd values, rather than the Mach ones: */
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
+#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP)
+
+#define I_CALL 0xe8
+#define I_CALLI 0xff
+#define I_RET 0xc3
+#define I_IRET 0xcf
+
+#define inst_trap_return(ins) (((ins)&0xff) == I_IRET)
+#define inst_return(ins) (((ins)&0xff) == I_RET)
+#define inst_call(ins) (((ins)&0xff) == I_CALL || \
+ (((ins)&0xff) == I_CALLI && \
+ ((ins)&0x3800) == 0x1000))
+#define inst_load(ins) 0
+#define inst_store(ins) 0
+
+/* access capability and access macros */
+
+#define DB_ACCESS_LEVEL 2 /* access any space */
+#define DB_CHECK_ACCESS(addr,size,task) \
+ db_check_access(addr,size,task)
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) \
+ db_phys_eq(task1,addr1,task2,addr2)
+#define DB_VALID_KERN_ADDR(addr) \
+ ((addr) >= VM_MIN_KERNEL_ADDRESS && \
+ (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) \
+ ((!(user) && DB_VALID_KERN_ADDR(addr)) || \
+ ((user) && (addr) < VM_MIN_KERNEL_ADDRESS))
+
+boolean_t db_check_access(/* vm_offset_t, int, task_t */);
+boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */);
+
+/* macros for printing OS server dependent task name */
+
+#define DB_TASK_NAME(task) db_task_name(task)
+#define DB_TASK_NAME_TITLE "COMMAND "
+#define DB_TASK_NAME_LEN 23
+#define DB_NULL_TASK_NAME "? "
+
+void db_task_name(/* task_t */);
+
+/* macro for checking if a thread has used floating-point */
+
+#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0)
+
+#endif /* _I386_DB_MACHDEP_H_ */
diff --git a/sys/amd64/include/float.h b/sys/amd64/include/float.h
new file mode 100644
index 0000000..edfe0d9
--- /dev/null
+++ b/sys/amd64/include/float.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)float.h 7.1 (Berkeley) 5/8/90
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00086
+ * -------------------- ----- ----------------------
+ *
+ * 27 Feb 93 Handel/da Silva/Poirot Adjust value for MAX_DOUBLE
+ */
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS 1 /* FP addition rounds to nearest */
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP -125 /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP -37 /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP -1021
+#define DBL_MIN 2.225073858507201E-308
+#define DBL_MIN_10_EXP -307
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.797693134862315E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
diff --git a/sys/amd64/include/fpu.h b/sys/amd64/include/fpu.h
new file mode 100644
index 0000000..134e0c1
--- /dev/null
+++ b/sys/amd64/include/fpu.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.h 5.3 (Berkeley) 1/18/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+#ifndef dontdef
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h
new file mode 100644
index 0000000..4dbabd1
--- /dev/null
+++ b/sys/amd64/include/frame.h
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)frame.h 5.2 (Berkeley) 1/18/91
+ */
+
+/*
+ * System stack frames.
+ */
+
+/*
+ * Exception/Trap Stack Frame
+ */
+
+struct trapframe {
+ int tf_es;
+ int tf_ds;
+ int tf_edi;
+ int tf_esi;
+ int tf_ebp;
+ int tf_isp;
+ int tf_ebx;
+ int tf_edx;
+ int tf_ecx;
+ int tf_eax;
+ int tf_trapno;
+ /* below portion defined in 386 hardware */
+ int tf_err;
+ int tf_eip;
+ int tf_cs;
+ int tf_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int tf_esp;
+ int tf_ss;
+};
+
+/* Interrupt stack frame */
+
+struct intrframe {
+ int if_vec;
+ int if_ppl;
+ int if_es;
+ int if_ds;
+ int if_edi;
+ int if_esi;
+ int if_ebp;
+ int :32;
+ int if_ebx;
+ int if_edx;
+ int if_ecx;
+ int if_eax;
+ int :32; /* for compat with trap frame - trapno */
+ int :32; /* for compat with trap frame - err */
+ /* below portion defined in 386 hardware */
+ int if_eip;
+ int if_cs;
+ int if_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int if_esp;
+ int if_ss;
+};
+
+/*
+ * Call Gate/System Call Stack Frame
+ */
+
+struct syscframe {
+ int sf_edi;
+ int sf_esi;
+ int sf_ebp;
+ int :32; /* redundant save of isp */
+ int sf_ebx;
+ int sf_edx;
+ int sf_ecx;
+ int sf_eax;
+ int sf_eflags;
+ /* below portion defined in 386 hardware */
+/* int sf_args[N]; /* if call gate copy args enabled!*/
+ int sf_eip;
+ int sf_cs;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int sf_esp;
+ int sf_ss;
+};
diff --git a/sys/amd64/include/npx.h b/sys/amd64/include/npx.h
new file mode 100644
index 0000000..134e0c1
--- /dev/null
+++ b/sys/amd64/include/npx.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.h 5.3 (Berkeley) 1/18/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+#ifndef dontdef
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/amd64/include/pc/display.h b/sys/amd64/include/pc/display.h
new file mode 100644
index 0000000..cab46e4
--- /dev/null
+++ b/sys/amd64/include/pc/display.h
@@ -0,0 +1,43 @@
+/*
+ * IBM PC display definitions
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
new file mode 100644
index 0000000..92bd810
--- /dev/null
+++ b/sys/amd64/include/pcb.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pcb.h 5.10 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Intel 386 process control block
+ */
+#include "machine/tss.h"
+#include "machine/npx.h"
+
+struct pcb {
+ struct i386tss pcb_tss;
+#define pcb_ksp pcb_tss.tss_esp0
+#define pcb_ptd pcb_tss.tss_cr3
+#define pcb_cr3 pcb_ptd
+#define pcb_pc pcb_tss.tss_eip
+#define pcb_psl pcb_tss.tss_eflags
+#define pcb_usp pcb_tss.tss_esp
+#define pcb_fp pcb_tss.tss_ebp
+#ifdef notyet
+ u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */
+#endif
+ struct save87 pcb_savefpu; /* floating point state for 287/387 */
+ struct emcsts pcb_saveemc; /* Cyrix EMC state */
+/*
+ * Software pcb (extension)
+ */
+ int pcb_flags;
+#ifdef notused
+#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */
+#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */
+#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */
+#endif
+#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */
+#define FM_TRAP 0x10 /* process entered kernel on a trap frame */
+#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */
+ short pcb_iml; /* interrupt mask level */
+ caddr_t pcb_onfault; /* copyin/out fault recovery */
+ long pcb_sigc[8]; /* XXX signal code trampoline */
+ int pcb_cmap2; /* XXX temporary PTE - will prefault instead */
+};
+
+#ifdef KERNEL
+struct pcb *curpcb; /* our current running pcb */
+#endif
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
new file mode 100644
index 0000000..2eff22f
--- /dev/null
+++ b/sys/amd64/include/pmap.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pmap.h 7.4 (Berkeley) 5/12/91
+ */
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * from hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90
+ */
+
+#ifndef _PMAP_MACHINE_
+#define _PMAP_MACHINE_ 1
+
+/*
+ * 386 page table entry and page table directory
+ * W.Jolitz, 8/89
+ */
+
+struct pde
+{
+unsigned int
+ pd_v:1, /* valid bit */
+ pd_prot:2, /* access control */
+ pd_mbz1:2, /* reserved, must be zero */
+ pd_u:1, /* hardware maintained 'used' bit */
+ :1, /* not used */
+ pd_mbz2:2, /* reserved, must be zero */
+ :3, /* reserved for software */
+ pd_pfnum:20; /* physical page frame number of pte's*/
+};
+
+#define PD_MASK 0xffc00000 /* page directory address bits */
+#define PT_MASK 0x003ff000 /* page table address bits */
+#define PD_SHIFT 22 /* page directory address shift */
+#define PG_SHIFT 12 /* page table address shift */
+
+struct pte
+{
+unsigned int
+ pg_v:1, /* valid bit */
+ pg_prot:2, /* access control */
+ pg_mbz1:2, /* reserved, must be zero */
+ pg_u:1, /* hardware maintained 'used' bit */
+ pg_m:1, /* hardware maintained modified bit */
+ pg_mbz2:2, /* reserved, must be zero */
+ pg_w:1, /* software, wired down page */
+ :1, /* software (unused) */
+ pg_nc:1, /* 'uncacheable page' bit */
+ pg_pfnum:20; /* physical page frame number */
+};
+
+#define PG_V 0x00000001
+#define PG_RO 0x00000000
+#define PG_RW 0x00000002
+#define PG_u 0x00000004
+#define PG_PROT 0x00000006 /* all protection bits . */
+#define PG_W 0x00000200
+#define PG_N 0x00000800 /* Non-cacheable */
+#define PG_M 0x00000040
+#define PG_U 0x00000020
+#define PG_FRAME 0xfffff000
+
+#define PG_NOACC 0
+#define PG_KR 0x00000000
+#define PG_KW 0x00000002
+#define PG_URKR 0x00000004
+#define PG_URKW 0x00000004
+#define PG_UW 0x00000006
+
+/* Garbage for current bastardized pager that assumes a hp300 */
+#define PG_NV 0
+#define PG_CI 0
+/*
+ * Page Protection Exception bits
+ */
+
+#define PGEX_P 0x01 /* Protection violation vs. not present */
+#define PGEX_W 0x02 /* during a Write cycle */
+#define PGEX_U 0x04 /* access from User mode (UPL) */
+
+typedef struct pde pd_entry_t; /* page directory entry */
+typedef struct pte pt_entry_t; /* Mach page table entry */
+
+/*
+ * One page directory, shared between
+ * kernel and user modes.
+ */
+#define I386_PAGE_SIZE NBPG
+#define I386_PDR_SIZE NBPDR
+
+#define I386_KPDES 8 /* KPT page directory size */
+#define I386_UPDES NBPDR/sizeof(struct pde)-8 /* UPT page directory size */
+
+#define UPTDI 0x3f6 /* ptd entry for u./kernel&user stack */
+#define PTDPTDI 0x3f7 /* ptd entry that points to ptd! */
+#define KPTDI_FIRST 0x3f8 /* start of kernel virtual pde's */
+#define KPTDI_LAST 0x3fA /* last of kernel virtual pde's */
+
+/*
+ * Address of current and alternate address space page table maps
+ * and directories.
+ */
+#ifdef KERNEL
+extern struct pte PTmap[], APTmap[], Upte;
+extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde;
+extern pt_entry_t *Sysmap;
+
+extern int IdlePTD; /* physical address of "Idle" state directory */
+#endif
+
+/*
+ * virtual address to page table entry and
+ * to physical address. Likewise for alternate address space.
+ * Note: these work recursively, thus vtopte of a pte will give
+ * the corresponding pde that in turn maps it.
+ */
+#define vtopte(va) (PTmap + i386_btop(va))
+#define kvtopte(va) vtopte(va)
+#define ptetov(pt) (i386_ptob(pt - PTmap))
+#define vtophys(va) (i386_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS)
+
+#define avtopte(va) (APTmap + i386_btop(va))
+#define ptetoav(pt) (i386_ptob(pt - APTmap))
+#define avtophys(va) (i386_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+
+/*
+ * macros to generate page directory/table indicies
+ */
+
+#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT)
+#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT)
+
+/*
+ * Pmap stuff
+ */
+
+struct pmap {
+ pd_entry_t *pm_pdir; /* KVA of page directory */
+ boolean_t pm_pdchanged; /* pdir changed */
+ short pm_dref; /* page directory ref count */
+ short pm_count; /* pmap reference count */
+ simple_lock_data_t pm_lock; /* lock on pmap */
+ struct pmap_statistics pm_stats; /* pmap statistics */
+ long pm_ptpages; /* more stats: PT pages */
+};
+
+typedef struct pmap *pmap_t;
+
+#ifdef KERNEL
+extern pmap_t kernel_pmap;
+#endif
+
+/*
+ * Macros for speed
+ */
+#define PMAP_ACTIVATE(pmapp, pcbp) \
+ if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \
+ (pcbp)->pcb_cr3 = \
+ pmap_extract(kernel_pmap, (pmapp)->pm_pdir); \
+ if ((pmapp) == &curproc->p_vmspace->vm_pmap) \
+ load_cr3((pcbp)->pcb_cr3); \
+ (pmapp)->pm_pdchanged = FALSE; \
+ }
+
+#define PMAP_DEACTIVATE(pmapp, pcbp)
+
+/*
+ * For each vm_page_t, there is a list of all currently valid virtual
+ * mappings of that page. An entry is a pv_entry_t, the list is pv_table.
+ */
+typedef struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ pmap_t pv_pmap; /* pmap where mapping lies */
+ vm_offset_t pv_va; /* virtual address for mapping */
+ int pv_flags; /* flags */
+} *pv_entry_t;
+
+#define PV_ENTRY_NULL ((pv_entry_t) 0)
+
+#define PV_CI 0x01 /* all entries must be cache inhibited */
+#define PV_PTPAGE 0x02 /* entry maps a page table page */
+
+#ifdef KERNEL
+
+pv_entry_t pv_table; /* array of entries, one per page */
+
+#define pa_index(pa) atop(pa - vm_first_phys)
+#define pa_to_pvh(pa) (&pv_table[pa_index(pa)])
+
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+
+#endif KERNEL
+
+#endif _PMAP_MACHINE_
diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h
new file mode 100644
index 0000000..02f3c01
--- /dev/null
+++ b/sys/amd64/include/proc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)proc.h 7.1 (Berkeley) 5/15/91
+ */
+
+/*
+ * Machine-dependent part of the proc structure for hp300.
+ */
+struct mdproc {
+ int md_flags; /* machine-dependent flags */
+#ifdef notyet
+ int *p_regs; /* registers on current frame */
+#endif
+};
+
+/* md_flags */
+#define MDP_AST 0x0001 /* async trap pending */
diff --git a/sys/amd64/include/psl.h b/sys/amd64/include/psl.h
new file mode 100644
index 0000000..aee73ed
--- /dev/null
+++ b/sys/amd64/include/psl.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)psl.h 5.2 (Berkeley) 1/18/91
+ */
+
+/*
+ * 386 processor status longword.
+ */
+#define PSL_C 0x00000001 /* carry bit */
+#define PSL_PF 0x00000004 /* parity bit */
+#define PSL_AF 0x00000010 /* bcd carry bit */
+#define PSL_Z 0x00000040 /* zero bit */
+#define PSL_N 0x00000080 /* negative bit */
+#define PSL_T 0x00000100 /* trace enable bit */
+#define PSL_I 0x00000200 /* interrupt enable bit */
+#define PSL_D 0x00000400 /* string instruction direction bit */
+#define PSL_V 0x00000800 /* overflow bit */
+#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */
+#define PSL_NT 0x00004000 /* nested task bit */
+#define PSL_RF 0x00010000 /* restart flag bit */
+#define PSL_VM 0x00020000 /* virtual 8086 mode bit */
+
+#define PSL_MBZ 0xfffc7fb7 /* must be zero bits */
+#define PSL_MBO 0x00000002 /* must be one bits */
+
+#define PSL_USERSET (PSL_IOPL)
+#define PSL_USERCLR (PSL_I|PSL_NT)
diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h
new file mode 100644
index 0000000..bc2f05c
--- /dev/null
+++ b/sys/amd64/include/reg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)reg.h 5.5 (Berkeley) 1/18/91
+ */
+
+/*
+ * Location of the users' stored
+ * registers within appropriate frame of 'trap' and 'syscall', relative to
+ * base of stack frame.
+ * Normal usage is u.u_ar0[XX] in kernel.
+ */
+
+/* When referenced during a trap/exception, registers are at these offsets */
+
+#define tES (0)
+#define tDS (1)
+#define tEDI (2)
+#define tESI (3)
+#define tEBP (4)
+
+#define tEBX (6)
+#define tEDX (7)
+#define tECX (8)
+#define tEAX (9)
+
+#define tEIP (12)
+#define tCS (13)
+#define tEFLAGS (14)
+#define tESP (15)
+#define tSS (16)
+
+/* During a system call, registers are at these offsets instead of above. */
+
+#define sEDI (0)
+#define sESI (1)
+#define sEBP (2)
+
+#define sEBX (4)
+#define sEDX (5)
+#define sECX (6)
+#define sEAX (7)
+#define sEFLAGS (8)
+#define sEIP (9)
+#define sCS (10)
+#define sESP (11)
+#define sSS (12)
+
+#define PC sEIP
+#define SP sESP
+#define PS sEFLAGS
+#define R0 sEDX
+#define R1 sECX
+/*
+ * Registers accessible to ptrace(2) syscall for debugger
+ */
+#ifdef IPCREG
+#define NIPCREG 14
+int ipcreg[NIPCREG] =
+ { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS };
+#endif
diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h
new file mode 100644
index 0000000..0456e59
--- /dev/null
+++ b/sys/amd64/include/segments.h
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)segments.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * 386 Segmentation Data Structures and definitions
+ * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989
+ */
+
+/*
+ * Selectors
+ */
+
+#define ISPL(s) ((s)&3) /* what is the priority level of a selector */
+#define SEL_KPL 0 /* kernel priority level */
+#define SEL_UPL 3 /* user priority level */
+#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
+#define SEL_LDT 4 /* local descriptor table */
+#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */
+#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
+#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
+
+/*
+ * Memory and System segment descriptors
+ */
+struct segment_descriptor {
+ unsigned sd_lolimit:16 ; /* segment extent (lsb) */
+ unsigned sd_lobase:24 ; /* segment base address (lsb) */
+ unsigned sd_type:5 ; /* segment type */
+ unsigned sd_dpl:2 ; /* segment descriptor priority level */
+ unsigned sd_p:1 ; /* segment descriptor present */
+ unsigned sd_hilimit:4 ; /* segment extent (msb) */
+ unsigned sd_xx:2 ; /* unused */
+ unsigned sd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/
+ unsigned sd_hibase:8 ; /* segment base address (msb) */
+} ;
+
+/*
+ * Gate descriptors (e.g. indirect descriptors)
+ */
+struct gate_descriptor {
+ unsigned gd_looffset:16 ; /* gate offset (lsb) */
+ unsigned gd_selector:16 ; /* gate segment selector */
+ unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
+ unsigned gd_xx:3 ; /* unused */
+ unsigned gd_type:5 ; /* segment type */
+ unsigned gd_dpl:2 ; /* segment descriptor priority level */
+ unsigned gd_p:1 ; /* segment descriptor present */
+ unsigned gd_hioffset:16 ; /* gate offset (msb) */
+} ;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+ struct segment_descriptor sd;
+ struct gate_descriptor gd;
+};
+
+ /* system segments and gate types */
+#define SDT_SYSNULL 0 /* system null */
+#define SDT_SYS286TSS 1 /* system 286 TSS available */
+#define SDT_SYSLDT 2 /* system local descriptor table */
+#define SDT_SYS286BSY 3 /* system 286 TSS busy */
+#define SDT_SYS286CGT 4 /* system 286 call gate */
+#define SDT_SYSTASKGT 5 /* system task gate */
+#define SDT_SYS286IGT 6 /* system 286 interrupt gate */
+#define SDT_SYS286TGT 7 /* system 286 trap gate */
+#define SDT_SYSNULL2 8 /* system null again */
+#define SDT_SYS386TSS 9 /* system 386 TSS available */
+#define SDT_SYSNULL3 10 /* system null again */
+#define SDT_SYS386BSY 11 /* system 386 TSS busy */
+#define SDT_SYS386CGT 12 /* system 386 call gate */
+#define SDT_SYSNULL4 13 /* system null again */
+#define SDT_SYS386IGT 14 /* system 386 interrupt gate */
+#define SDT_SYS386TGT 15 /* system 386 trap gate */
+
+ /* memory segment types */
+#define SDT_MEMRO 16 /* memory read only */
+#define SDT_MEMROA 17 /* memory read only accessed */
+#define SDT_MEMRW 18 /* memory read write */
+#define SDT_MEMRWA 19 /* memory read write accessed */
+#define SDT_MEMROD 20 /* memory read only expand dwn limit */
+#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
+#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
+#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */
+#define SDT_MEME 24 /* memory execute only */
+#define SDT_MEMEA 25 /* memory execute only accessed */
+#define SDT_MEMER 26 /* memory execute read */
+#define SDT_MEMERA 27 /* memory execute read accessed */
+#define SDT_MEMEC 28 /* memory execute only conforming */
+#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
+#define SDT_MEMERC 30 /* memory execute read conforming */
+#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
+
+/* is memory segment descriptor pointer ? */
+#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC)
+
+/* is 286 gate descriptor pointer ? */
+#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \
+ && (s->d_type) < SDT_SYS286TGT))
+
+/* is 386 gate descriptor pointer ? */
+#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \
+ && (s->d_type) < SDT_SYS386TGT))
+
+/* is gate descriptor pointer ? */
+#define ISGDP(s) (IS286GDP(s) || IS386GDP(s))
+
+/* is segment descriptor pointer ? */
+#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s))
+
+/* is system segment descriptor pointer ? */
+#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s))
+
+/*
+ * Software definitions are in this convenient format,
+ * which are translated into inconvenient segment descriptors
+ * when needed to be used by the 386 hardware
+ */
+
+struct soft_segment_descriptor {
+ unsigned ssd_base ; /* segment base address */
+ unsigned ssd_limit ; /* segment extent */
+ unsigned ssd_type:5 ; /* segment type */
+ unsigned ssd_dpl:2 ; /* segment descriptor priority level */
+ unsigned ssd_p:1 ; /* segment descriptor present */
+ unsigned ssd_xx:4 ; /* unused */
+ unsigned ssd_xx1:2 ; /* unused */
+ unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/
+};
+
+extern ssdtosd() ; /* to decode a ssd */
+extern sdtossd() ; /* to encode a sd */
+
+/*
+ * region descriptors, used to load gdt/idt tables before segments yet exist.
+ */
+struct region_descriptor {
+ unsigned rd_limit:16; /* segment extent */
+ unsigned rd_base:32; /* base address */
+};
+
+/*
+ * Segment Protection Exception code bits
+ */
+
+#define SEGEX_EXT 0x01 /* recursive or externally induced */
+#define SEGEX_IDT 0x02 /* interrupt descriptor table */
+#define SEGEX_TI 0x04 /* local descriptor table */
+ /* other bits are affected descriptor index */
+#define SEGEX_IDX(s) ((s)>>3)&0x1fff)
+
+/*
+ * Size of IDT table
+ */
+
+#define NIDT 256
+#define NRSVIDT 32 /* reserved entries for cpu exceptions */
diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h
new file mode 100644
index 0000000..d1908c9
--- /dev/null
+++ b/sys/amd64/include/specialreg.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Bits in 386 special registers:
+ */
+
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
+#ifdef notused
+#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
+#endif
+#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
+#ifdef notused
+#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */
+#endif
+#define CR0_PG 0x80000000 /* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */
+#ifdef notyet
+#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */
+#endif
diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h
new file mode 100644
index 0000000..6015605
--- /dev/null
+++ b/sys/amd64/include/trap.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.h 5.4 (Berkeley) 5/9/91
+ */
+
+/*
+ * Trap type values
+ * also known in trap.c for name strings
+ */
+
+#define T_RESADFLT 0 /* reserved addressing */
+#define T_PRIVINFLT 1 /* privileged instruction */
+#define T_RESOPFLT 2 /* reserved operand */
+#define T_BPTFLT 3 /* breakpoint instruction */
+#define T_SYSCALL 5 /* system call (kcall) */
+#define T_ARITHTRAP 6 /* arithmetic trap */
+#define T_ASTFLT 7 /* system forced exception */
+#define T_SEGFLT 8 /* segmentation (limit) fault */
+#define T_PROTFLT 9 /* protection fault */
+#define T_TRCTRAP 10 /* trace trap */
+#define T_PAGEFLT 12 /* page fault */
+#define T_TABLEFLT 13 /* page table fault */
+#define T_ALIGNFLT 14 /* alignment fault */
+#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */
+#define T_BUSERR 16 /* bus error */
+#define T_KDBTRAP 17 /* kernel debugger trap */
+
+#define T_DIVIDE 18 /* integer divide fault */
+#define T_NMI 19 /* non-maskable trap */
+#define T_OFLOW 20 /* overflow trap */
+#define T_BOUND 21 /* bound instruction fault */
+#define T_DNA 22 /* device not available fault */
+#define T_DOUBLEFLT 23 /* double fault */
+#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */
+#define T_TSSFLT 25 /* invalid tss fault */
+#define T_SEGNPFLT 26 /* segment not present fault */
+#define T_STKFLT 27 /* stack fault */
+#define T_RESERVED 28 /* reserved fault base */
+
+/* definitions for <sys/signal.h> */
+#define ILL_RESAD_FAULT T_RESADFLT
+#define ILL_PRIVIN_FAULT T_PRIVINFLT
+#define ILL_RESOP_FAULT T_RESOPFLT
+#define ILL_ALIGN_FAULT T_ALIGNFLT
+#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */
+
+/* codes for SIGFPE/ARITHTRAP */
+#define FPE_INTOVF_TRAP 0x1 /* integer overflow */
+#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */
+#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */
+#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */
+#define FPE_FLTUND_TRAP 0x5 /* floating underflow */
+#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */
+#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */
+
+/* codes for SIGBUS */
+#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */
+#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */
+#define BUS_STK_FAULT T_STKFLT /* stack segment */
+#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */
+
+/* Trap's coming from user mode */
+#define T_USER 0x100
diff --git a/sys/amd64/include/tss.h b/sys/amd64/include/tss.h
new file mode 100644
index 0000000..8ba140d
--- /dev/null
+++ b/sys/amd64/include/tss.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tss.h 5.4 (Berkeley) 1/18/91
+ */
+
+/*
+ * Intel 386 Context Data Type
+ */
+
+struct i386tss {
+ int tss_link; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp0; /* kernel stack pointer priviledge level 0 */
+#define tss_ksp tss_esp0
+ int tss_ss0; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp1; /* kernel stack pointer priviledge level 1 */
+ int tss_ss1; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp2; /* kernel stack pointer priviledge level 2 */
+ int tss_ss2; /* actually 16 bits: top 16 bits must be zero */
+ /* struct ptd *tss_cr3; /* page table directory */
+ int tss_cr3; /* page table directory */
+#define tss_ptd tss_cr3
+ int tss_eip; /* program counter */
+#define tss_pc tss_eip
+ int tss_eflags; /* program status longword */
+#define tss_psl tss_eflags
+ int tss_eax;
+ int tss_ecx;
+ int tss_edx;
+ int tss_ebx;
+ int tss_esp; /* user stack pointer */
+#define tss_usp tss_esp
+ int tss_ebp; /* user frame pointer */
+#define tss_fp tss_ebp
+ int tss_esi;
+ int tss_edi;
+ int tss_es; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ss; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ds; /* actually 16 bits: top 16 bits must be zero */
+ int tss_fs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_gs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ldt; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ioopt; /* options & io offset bitmap: currently zero */
+ /* XXX unimplemented .. i/o permission bitmap */
+};
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
new file mode 100644
index 0000000..39403d6
--- /dev/null
+++ b/sys/amd64/include/vmparam.h
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vmparam.h 5.9 (Berkeley) 5/12/91
+ */
+
+
+/*
+ * Machine dependent constants for 386.
+ */
+
+/*
+ * Virtual address space arrangement. On 386, both user and kernel
+ * share the address space, not unlike the vax.
+ * USRTEXT is the start of the user text/data space, while USRSTACK
+ * is the top (end) of the user stack. Immediately above the user stack
+ * resides the user structure, which is UPAGES long and contains the
+ * kernel stack.
+ *
+ * Immediately after the user structure is the page table map, and then
+ * kernal address space.
+ */
+#define USRTEXT 0
+#define USRSTACK 0xFDBFE000
+#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */
+#define LOWPAGES 0
+#define HIGHPAGES UPAGES
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#define MAXTSIZ (6*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ (6*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (32*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (512*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ MAXDSIZ /* max stack size */
+#endif
+
+/*
+ * Default sizes of swap allocation chunks (see dmap.h).
+ * The actual values may be changed in vminit() based on MAXDSIZ.
+ * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024.
+ */
+#define DMMIN 32 /* smallest swap allocation */
+#define DMMAX 4096 /* largest potential swap allocation */
+#define DMTEXT 1024 /* swap allocation for text */
+
+/*
+ * Sizes of the system and user portions of the system page table.
+ */
+#define SYSPTSIZE (2*NPTEPG)
+#define USRPTSIZE (2*NPTEPG)
+
+/*
+ * Size of User Raw I/O map
+ */
+#define USRIOSIZE 300
+
+/*
+ * The size of the clock loop.
+ */
+#define LOOPPAGES (maxfree - firstfree)
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+/*
+ * A swapped in process is given a small amount of core without being bothered
+ * by the page replacement algorithm. Basically this says that if you are
+ * swapped in you deserve some resources. We protect the last SAFERSS
+ * pages against paging and will just swap you out rather than paging you.
+ * Note that each process has at least UPAGES+CLSIZE pages which are not
+ * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this
+ * number just means a swapped in process is given around 25k bytes.
+ * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81),
+ * so we loan each swapped in process memory worth 100$, or just admit
+ * that we don't consider it worthwhile and swap it out to disk which costs
+ * $30/mb or about $0.75.
+ * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17
+ * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) }
+ */
+#define SAFERSS 8 /* nominal ``small'' resident set size
+ protected against replacement */
+
+/*
+ * DISKRPM is used to estimate the number of paging i/o operations
+ * which one can expect from a single disk controller.
+ */
+#define DISKRPM 60
+
+/*
+ * Klustering constants. Klustering is the gathering
+ * of pages together for pagein/pageout, while clustering
+ * is the treatment of hardware page size as though it were
+ * larger than it really is.
+ *
+ * KLMAX gives maximum cluster size in CLSIZE page (cluster-page)
+ * units. Note that KLMAX*CLSIZE must be <= DMMIN in dmap.h.
+ */
+
+#define KLMAX (4/CLSIZE)
+#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */
+#define KLIN (4/CLSIZE) /* default data/stack in klust */
+#define KLTXT (4/CLSIZE) /* default text in klust */
+#define KLOUT (4/CLSIZE)
+
+/*
+ * KLSDIST is the advance or retard of the fifo reclaim for sequential
+ * processes data space.
+ */
+#define KLSDIST 3 /* klusters advance/retard for seq. fifo */
+
+/*
+ * Paging thresholds (see vm_sched.c).
+ * Strategy of 1/19/85:
+ * lotsfree is 512k bytes, but at most 1/4 of memory
+ * desfree is 200k bytes, but at most 1/8 of memory
+ * minfree is 64k bytes, but at most 1/2 of desfree
+ */
+#define LOTSFREE (512 * 1024)
+#define LOTSFREEFRACT 4
+#define DESFREE (200 * 1024)
+#define DESFREEFRACT 8
+#define MINFREE (64 * 1024)
+#define MINFREEFRACT 2
+
+/*
+ * There are two clock hands, initially separated by HANDSPREAD bytes
+ * (but at most all of user memory). The amount of time to reclaim
+ * a page once the pageout process examines it increases with this
+ * distance and decreases as the scan rate rises.
+ */
+#define HANDSPREAD (2 * 1024 * 1024)
+
+/*
+ * The number of times per second to recompute the desired paging rate
+ * and poke the pagedaemon.
+ */
+#define RATETOSCHEDPAGING 4
+
+/*
+ * Believed threshold (in megabytes) for which interleaved
+ * swapping area is desirable.
+ */
+#define LOTSOFMEM 2
+
+#define mapin(pte, v, pfnum, prot) \
+ {(*(int *)(pte) = ((pfnum)<<PGSHIFT) | (prot)) ; }
+
+/*
+ * Mach derived constants
+ */
+
+/* user/kernel map constants */
+#define VM_MIN_ADDRESS ((vm_offset_t)0)
+#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFDBFE000)
+#define UPT_MIN_ADDRESS ((vm_offset_t)0xFDC00000)
+#define UPT_MAX_ADDRESS ((vm_offset_t)0xFDFF7000)
+#define VM_MAX_ADDRESS UPT_MAX_ADDRESS
+#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xFDFF7000)
+#define UPDT VM_MIN_KERNEL_ADDRESS
+#define KPT_MIN_ADDRESS ((vm_offset_t)0xFDFF8000)
+#define KPT_MAX_ADDRESS ((vm_offset_t)0xFDFFF000)
+#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFF7FF000)
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES)
+#define VM_KMEM_SIZE (NKMEMCLUSTERS*CLBYTES)
+#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES)
+
+/* # of kernel PT pages (initial only, can grow dynamically) */
+#define VM_KERNEL_PT_PAGES ((vm_size_t)2) /* XXX: SYSPTSIZE */
+
+/* pcb base */
+#define pcbb(p) ((u_int)(p)->p_addr)
+
+/*
+ * Flush MMU TLB
+ */
+
+#ifndef I386_CR3PAT
+#define I386_CR3PAT 0x0
+#endif
+
+#ifdef notyet
+#define _cr3() ({u_long rtn; \
+ asm (" movl %%cr3,%%eax; movl %%eax,%0 " \
+ : "=g" (rtn) \
+ : \
+ : "ax"); \
+ rtn; \
+})
+
+#define load_cr3(s) ({ u_long val; \
+ val = (s) | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+
+#define tlbflush() ({ u_long val; \
+ val = u.u_pcb.pcb_ptd | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+#endif
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
new file mode 100644
index 0000000..0fb7701
--- /dev/null
+++ b/sys/amd64/isa/clock.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 14 Aug 92 Arne Henrik Juul Added code in the kernel to
+ * allow for DST in the BIOS.
+ * 17 Jan 93 Bruce Evans Fixed leap year and second
+ * calculations
+ * 01 Feb 93 Julian Elischer Added code to for the cpu
+ * speed independent spinwait()
+ * function, (used by scsi and others)
+ * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1
+ * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock
+ * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait
+ * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I
+ * still kept the other fixes... Had to
+ * add back in findcpuspeed that Bruce
+ * had removed.
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+#define DAYST 119
+#define DAYEN 303
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+
+startrtclock() {
+ int s;
+
+ findcpuspeed(); /* use the clock (while it's free)
+ to find the cpu speed */
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
+ outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+ outb (IO_RTC, RTC_DIAG);
+ outb (IO_RTC+1, 0);
+}
+
+unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
+
+#define FIRST_GUESS 0x2000
+findcpuspeed()
+{
+ unsigned char low;
+ unsigned int remainder;
+
+ /* Put counter in count down mode */
+ outb(IO_TIMER1+3, 0x34);
+ outb(IO_TIMER1, 0xff);
+ outb(IO_TIMER1, 0xff);
+ delaycount = FIRST_GUESS;
+ spinwait(1);
+ /* Read the value left in the counter */
+ low = inb(IO_TIMER1); /* least siginifcant */
+ remainder = inb(IO_TIMER1); /* most significant */
+ remainder = (remainder<<8) + low ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ */
+ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
+}
+
+
+/* convert 2 digit BCD number */
+bcd(i)
+int i;
+{
+ return ((i/16)*10 + (i%16));
+}
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(y)
+int y;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+/* convert months to seconds */
+unsigned long
+mtos(m,leap)
+int m,leap;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1;i<m;i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+inittodr(base)
+ time_t base;
+{
+ unsigned long sec;
+ int leap,day_week,t,yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+
+ /* XXX off by one? Need to calculate DST on SUNDAY */
+ /* Perhaps we should have the RTC hold GMT time to save */
+ /* us the bother of converting. */
+ yd = yd / (24*60*60);
+ if ((yd >= DAYST) && ( yd <= DAYEN)) {
+ sec -= 60*60;
+ }
+ sec += tz.tz_minuteswest * 60;
+
+ time.tv_sec = sec;
+}
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(base)
+ time_t base;
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Restart the clock.
+ */
+resettodr()
+{
+}
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern V(clk)();
+enablertclock() {
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(millisecs)
+ int millisecs;
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h
new file mode 100644
index 0000000..4866d8d
--- /dev/null
+++ b/sys/amd64/isa/icu.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)icu.h 5.6 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00158
+ * -------------------- ----- ----------------------
+ *
+ * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1)
+ */
+
+/*
+ * AT/386 Interrupt Control constants
+ * W. Jolitz 8/89
+ */
+
+#ifndef __ICU__
+#define __ICU__
+
+#ifndef LOCORE
+
+/*
+ * Interrupt "level" mechanism variables, masks, and macros
+ */
+extern unsigned imen; /* interrupt mask enable */
+extern unsigned cpl; /* current priority level mask */
+
+extern unsigned highmask; /* group of interrupts masked with splhigh() */
+extern unsigned ttymask; /* group of interrupts masked with spltty() */
+extern unsigned biomask; /* group of interrupts masked with splbio() */
+extern unsigned netmask; /* group of interrupts masked with splimp() */
+
+#define INTREN(s) (imen &= ~(s), SET_ICUS())
+#define INTRDIS(s) (imen |= (s), SET_ICUS())
+#define INTRMASK(msk,s) (msk |= (s))
+#if 0
+#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8))
+#else
+/*
+ * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to
+ * include isa.h, while too many things include icu.h.
+ */
+#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8))
+#endif
+
+#endif
+
+/*
+ * Interrupt enable bits -- in order of priority
+ */
+#define IRQ0 0x0001 /* highest priority - timer */
+#define IRQ1 0x0002
+#define IRQ_SLAVE 0x0004
+#define IRQ8 0x0100
+#define IRQ9 0x0200
+#define IRQ2 IRQ9
+#define IRQ10 0x0400
+#define IRQ11 0x0800
+#define IRQ12 0x1000
+#define IRQ13 0x2000
+#define IRQ14 0x4000
+#define IRQ15 0x8000
+#define IRQ3 0x0008
+#define IRQ4 0x0010
+#define IRQ5 0x0020
+#define IRQ6 0x0040
+#define IRQ7 0x0080 /* lowest - parallel printer */
+
+/*
+ * Interrupt Control offset into Interrupt descriptor table (IDT)
+ */
+#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
+#define ICU_LEN 16 /* 32-47 are ISA interrupts */
+
+#endif __ICU__
diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c
new file mode 100644
index 0000000..8707b43
--- /dev/null
+++ b/sys/amd64/isa/isa.c
@@ -0,0 +1,766 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa.c 7.2 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 4 00163
+ * -------------------- ----- ----------------------
+ *
+ * 18 Aug 92 Frank Maclachlan *See comments below
+ * 25 Mar 93 Rodney W. Grimes Added counter for stray interrupt,
+ * turned on logging of stray interrupts,
+ * Now prints maddr, msize, and flags
+ * after finding a device.
+ * 26 Apr 93 Bruce Evans New intr-0.1 code
+ * Rodney W. Grimes Only print io address if id_alive != -1
+ * 17 May 93 Rodney W. Grimes renamed stray interrupt counters to
+ * work with new intr-0.1 code.
+ * Enabled printf for interrupt masks to
+ * aid in bug reports.
+ * 27 May 93 Guido van Rooij New routine add find_isa_dev
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/RCS/isa.c,v 1.2 92/01/21 14:34:23 william Exp Locker: root $";
+
+/*
+ * code to manage AT bus
+ *
+ * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
+ * Fixed uninitialized variable problem and added code to deal
+ * with DMA page boundaries in isa_dmarangecheck(). Fixed word
+ * mode DMA count compution and reorganized DMA setup code in
+ * isa_dmastart()
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "uio.h"
+#include "syslog.h"
+#include "malloc.h"
+#include "rlist.h"
+#include "machine/segments.h"
+#include "vm/vm.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/ic/i8237.h"
+#include "i386/isa/ic/i8042.h"
+
+/*
+** Register definitions for DMA controller 1 (channels 0..3):
+*/
+#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
+#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
+#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
+#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
+
+/*
+** Register definitions for DMA controller 2 (channels 4..7):
+*/
+#define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */
+#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
+#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
+#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
+
+int config_isadev __P((struct isa_device *, u_int *));
+
+#ifdef notyet
+struct rlist *isa_iomem;
+
+/*
+ * Configure all ISA devices
+ */
+isa_configure() {
+ struct isa_device *dvp;
+ struct isa_driver *dp;
+
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/
+ for (dvp = isa_devtab_tty; dvp; dvp++)
+ (void) config_isadev(dvp, &ttymask);
+ for (dvp = isa_devtab_bio; dvp; dvp++)
+ (void) config_isadev(dvp, &biomask);
+ for (dvp = isa_devtab_net; dvp; dvp++)
+ (void) config_isadev(dvp, &netmask);
+ for (dvp = isa_devtab_null; dvp; dvp++)
+ (void) config_isadev(dvp, (u_int *) NULL);
+#include "sl.h"
+#if NSL > 0
+ netmask |= ttymask;
+ ttymask |= netmask;
+#endif
+/* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp;
+ static short drqseen, irqseen;
+
+ if (dp = isdp->id_driver) {
+ /* if a device with i/o memory, convert to virtual address */
+ if (isdp->id_maddr) {
+ extern unsigned int atdevbase;
+
+ isdp->id_maddr -= IOM_BEGIN;
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+
+ printf("%s%d at port 0x%x ", dp->name,
+ isdp->id_unit, isdp->id_iobase);
+
+ /* check for conflicts */
+ if (irqseen & isdp->id_irq) {
+ printf("INTERRUPT CONFLICT - irq%d\n",
+ ffs(isdp->id_irq) - 1);
+ return (0);
+ }
+ if (isdp->id_drq != -1
+ && (drqseen & (1<<isdp->id_drq))) {
+ printf("DMA CONFLICT - drq%d\n", isdp->id_drq);
+ return (0);
+ }
+ /* NEED TO CHECK IOMEM CONFLICT HERE */
+
+ /* allocate and wire in device */
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ printf("irq %d ", intrno);
+ INTREN(isdp->id_irq);
+ if(mp)INTRMASK(*mp,isdp->id_irq);
+ setidt(NRSVIDT + intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ irqseen |= isdp->id_irq;
+ }
+ if (isdp->id_drq != -1) {
+ printf("drq %d ", isdp->id_drq);
+ drqseen |= 1 << isdp->id_drq;
+ }
+
+ (*dp->attach)(isdp);
+
+ printf("on isa\n");
+ }
+ return (1);
+ } else return(0);
+}
+#else /* notyet */
+/*
+ * Configure all ISA devices
+ */
+isa_configure() {
+ struct isa_device *dvp;
+ struct isa_driver *dp;
+
+ enable_intr();
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++);
+ for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++);
+ for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++);
+ for (dvp = isa_devtab_null; config_isadev(dvp,(u_int *) NULL); dvp++);
+#include "sl.h"
+#if NSL > 0
+ netmask |= ttymask;
+ ttymask |= netmask;
+#endif
+ /* biomask |= ttymask ; can some tty devices use buffers? */
+ printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp;
+
+ if (dp = isdp->id_driver) {
+ if (isdp->id_maddr) {
+ extern u_int atdevbase;
+
+ isdp->id_maddr -= 0xa0000; /* XXX should be a define */
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+ printf("%s%d", dp->name, isdp->id_unit);
+ /*
+ * The attach should really be after all the printf's
+ * but until all the drivers are fixed do it here.
+ * There is a comment below that shows where this
+ * really belongs. Rod Grimes 04/10/93
+ */
+ (*dp->attach)(isdp);
+ /*
+ * Only print the I/O address range if id_alive != -1
+ * Right now this is a temporary fix just for the new
+ * NPX code so that if it finds a 486 that can use trap
+ * 16 it will not report I/O addresses.
+ * Rod Grimes 04/26/94
+ */
+ if (isdp->id_alive != -1) {
+ printf(" at 0x%x", isdp->id_iobase);
+ if ((isdp->id_iobase + isdp->id_alive - 1) !=
+ isdp->id_iobase)
+ printf("-0x%x",
+ isdp->id_iobase +
+ isdp->id_alive - 1);
+ }
+ if(isdp->id_irq)
+ printf(" irq %d", ffs(isdp->id_irq)-1);
+ if (isdp->id_drq != -1)
+ printf(" drq %d", isdp->id_drq);
+ if (isdp->id_maddr != 0)
+ printf(" maddr 0x%x", kvtop(isdp->id_maddr));
+ if (isdp->id_msize != 0)
+ printf(" msize %d", isdp->id_msize);
+ if (isdp->id_flags != 0)
+ printf(" flags 0x%x", isdp->id_flags);
+ printf(" on isa\n");
+
+ /* This is the place the attach should be done! */
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ setidt(ICU_OFFSET+intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ if(mp)
+ INTRMASK(*mp,isdp->id_irq);
+ INTREN(isdp->id_irq);
+ }
+ }
+ return (1);
+ } else return(0);
+}
+#endif /* (!) notyet */
+
+#define IDTVEC(name) __CONCAT(X,name)
+/* default interrupt vector table entries */
+extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
+ IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
+ IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
+ IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
+
+static *defvec[16] = {
+ &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
+ &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
+ &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
+ &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
+
+/* out of range default interrupt vector gate entry */
+extern IDTVEC(intrdefault);
+
+/*
+ * Fill in default interrupt table (in case of spuruious interrupt
+ * during configuration of kernel, setup interrupt control unit
+ */
+isa_defaultirq() {
+ int i;
+
+ /* icu vectors */
+ for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
+ setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
+
+ /* out of range vectors */
+ for (i = NRSVIDT; i < NIDT; i++)
+ setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
+
+ /* initialize 8259's */
+ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
+ outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
+#ifdef AUTO_EOI_1
+ outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU1+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU1, 0x0a); /* default to IRR on read */
+ outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
+
+ outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
+ outb(IO_ICU2+1,2); /* my slave id is 2 */
+#ifdef AUTO_EOI_2
+ outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU2+1,1); /* 8086 mode */
+#endif
+ outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU2, 0x0a); /* default to IRR on read */
+}
+
+/* region of physical memory known to be contiguous */
+vm_offset_t isaphysmem;
+static caddr_t dma_bounce[8]; /* XXX */
+static char bounced[8]; /* XXX */
+#define MAXDMASZ 512 /* XXX */
+
+/* high byte of address is stored in this port for i-th dma channel */
+static short dmapageport[8] =
+ { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
+
+/*
+ * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * external dma control by a board.
+ */
+void isa_dmacascade(unsigned chan)
+{
+ if (chan > 7)
+ panic("isa_dmacascade: impossible request");
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0) {
+ outb(DMA1_MODE, DMA37MD_CASCADE | chan);
+ outb(DMA1_SMSK, chan);
+ } else {
+ outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+/*
+ * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * problems by using a bounce buffer.
+ */
+void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
+{ vm_offset_t phys;
+ int waport;
+ caddr_t newaddr;
+
+ if ( chan > 7
+ || (chan < 4 && nbytes > (1<<16))
+ || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
+ panic("isa_dmastart: impossible request");
+
+ if (isa_dmarangecheck(addr, nbytes, chan)) {
+ if (dma_bounce[chan] == 0)
+ dma_bounce[chan] =
+ /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
+ (caddr_t) isaphysmem + NBPG*chan;
+ bounced[chan] = 1;
+ newaddr = dma_bounce[chan];
+ *(int *) newaddr = 0; /* XXX */
+
+ /* copy bounce buffer on write */
+ if (!(flags & B_READ))
+ bcopy(addr, newaddr, nbytes);
+ addr = newaddr;
+ }
+
+ /* translate to physical */
+ phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+
+ if ((chan & 4) == 0) {
+ /*
+ * Program one of DMA channels 0..3. These are
+ * byte mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
+ else
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
+ outb(DMA1_FFC, 0);
+
+ /* send start address */
+ waport = DMA1_CHN(chan);
+ outb(waport, phys);
+ outb(waport, phys>>8);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ outb(waport + 1, --nbytes);
+ outb(waport + 1, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA1_SMSK, chan);
+ } else {
+ /*
+ * Program one of DMA channels 4..7. These are
+ * word mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
+ else
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
+ outb(DMA2_FFC, 0);
+
+ /* send start address */
+ waport = DMA2_CHN(chan - 4);
+ outb(waport, phys>>1);
+ outb(waport, phys>>9);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ nbytes >>= 1;
+ outb(waport + 2, --nbytes);
+ outb(waport + 2, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
+{
+
+ /* copy bounce buffer on read */
+ /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
+ if (bounced[chan]) {
+ bcopy(dma_bounce[chan], addr, nbytes);
+ bounced[chan] = 0;
+ }
+}
+
+/*
+ * Check for problems with the address range of a DMA transfer
+ * (non-contiguous physical pages, outside of bus address space,
+ * crossing DMA page boundaries).
+ * Return true if special handling needed.
+ */
+
+isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
+ vm_offset_t phys, priorpage = 0, endva;
+ u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
+
+ endva = (vm_offset_t)round_page(va + length);
+ for (; va < (caddr_t) endva ; va += NBPG) {
+ phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
+#define ISARAM_END RAM_END
+ if (phys == 0)
+ panic("isa_dmacheck: no physical page present");
+ if (phys > ISARAM_END)
+ return (1);
+ if (priorpage) {
+ if (priorpage + NBPG != phys)
+ return (1);
+ /* check if crossing a DMA page boundary */
+ if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
+ return (1);
+ }
+ priorpage = phys;
+ }
+ return (0);
+}
+
+/* head of queue waiting for physmem to become available */
+struct buf isa_physmemq;
+
+/* blocked waiting for resource to become free for exclusive use */
+static isaphysmemflag;
+/* if waited for and call requested when free (B_CALL) */
+static void (*isaphysmemunblock)(); /* needs to be a list */
+
+/*
+ * Allocate contiguous physical memory for transfer, returning
+ * a *virtual* address to region. May block waiting for resource.
+ * (assumed to be called at splbio())
+ */
+caddr_t
+isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
+
+ isaphysmemunblock = func;
+ while (isaphysmemflag & B_BUSY) {
+ isaphysmemflag |= B_WANTED;
+ sleep(&isaphysmemflag, PRIBIO);
+ }
+ isaphysmemflag |= B_BUSY;
+
+ return((caddr_t)isaphysmem);
+}
+
+/*
+ * Free contiguous physical memory used for transfer.
+ * (assumed to be called at splbio())
+ */
+void
+isa_freephysmem(caddr_t va, unsigned length) {
+
+ isaphysmemflag &= ~B_BUSY;
+ if (isaphysmemflag & B_WANTED) {
+ isaphysmemflag &= B_WANTED;
+ wakeup(&isaphysmemflag);
+ if (isaphysmemunblock)
+ (*isaphysmemunblock)();
+ }
+}
+
+/*
+ * Handle a NMI, possibly a machine check.
+ * return true to panic system, false to ignore.
+ */
+isa_nmi(cd) {
+
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ return(0);
+}
+
+/*
+ * Caught a stray interrupt, notify
+ */
+isa_strayintr(d) {
+
+ /* DON'T BOTHER FOR NOW! */
+ /* for some reason, we get bursts of intr #7, even if not enabled! */
+ /*
+ * Well the reason you got bursts of intr #7 is because someone
+ * raised an interrupt line and dropped it before the 8259 could
+ * prioritize it. This is documented in the intel data book. This
+ * means you have BAD hardware! I have changed this so that only
+ * the first 5 get logged, then it quits logging them, and puts
+ * out a special message. rgrimes 3/25/1993
+ */
+ extern u_long intrcnt_stray;
+
+ intrcnt_stray++;
+ if (intrcnt_stray <= 5)
+ log(LOG_ERR,"ISA strayintr %x\n", d);
+ if (intrcnt_stray == 5)
+ log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
+}
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
+ * (2 * TIMER_FREQ) Hz.
+ * Note: timer had better have been programmed before this is first used!
+ * (The standard programming causes the timer to generate a square wave and
+ * the counter is decremented twice every cycle.)
+ */
+#define CF (2 * TIMER_FREQ)
+#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
+
+extern int hz; /* XXX - should be elsewhere */
+
+int DELAY(n)
+ int n;
+{
+ int counter_limit;
+ int prev_tick;
+ int tick;
+ int ticks_left;
+ int sec;
+ int usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+
+ /*
+ * Calculate (n * (CF / 1e6)) without using floating point and without
+ * any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * CF
+ + usec * (CF / 1000000)
+ + usec * ((CF % 1000000) / 1000) / 1000
+ + usec * (CF % 1000) / 1000000;
+
+ counter_limit = TIMER_FREQ / hz;
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - counter_limit);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+getit(unit, timer) {
+ int high;
+ int low;
+
+ /*
+ * XXX - isa.h defines bogus timers. There's no such timer as
+ * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
+ * its interface is quite different. Neither timer is an 8252.
+ * We actually only call this with unit = 0 and timer = 0. It
+ * could be static...
+ */
+ /*
+ * Protect ourself against interrupts.
+ * XXX - sysbeep() and sysbeepstop() need protection.
+ */
+ disable_intr();
+ /*
+ * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
+ */
+ outb(IO_TIMER1 + 3, timer << 6);
+
+ low = inb(IO_TIMER1 + timer);
+ high = inb(IO_TIMER1 + timer);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+static beeping;
+static
+sysbeepstop(f)
+{
+ /* disable counter 2 */
+ outb(0x61, inb(0x61) & 0xFC);
+ if (f)
+ timeout(sysbeepstop, 0, f);
+ else
+ beeping = 0;
+}
+
+void sysbeep(int pitch, int period)
+{
+
+ outb(0x61, inb(0x61) | 3); /* enable counter 2 */
+ /*
+ * XXX - move timer stuff to clock.c.
+ * Program counter 2:
+ * ccaammmb, c counter, a = access, m = mode, b = BCD
+ * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
+ */
+ outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
+
+ outb(0x42, pitch);
+ outb(0x42, (pitch>>8));
+
+ if (!beeping) {
+ beeping = period;
+ timeout(sysbeepstop, period/2, period);
+ }
+}
+
+/*
+ * Pass command to keyboard controller (8042)
+ */
+unsigned kbc_8042cmd(val) {
+
+ while (inb(KBSTATP)&KBS_IBF);
+ if (val) outb(KBCMDP, val);
+ while (inb(KBSTATP)&KBS_IBF);
+ return (inb(KBDATAP));
+}
+
+/*
+ * find an ISA device in a given isa_devtab_* table, given
+ * the table to search, the expected id_driver entry, and the unit number.
+ *
+ * this function is defined in isa_device.h, and this location is debatable;
+ * i put it there because it's useless w/o, and directly operates on
+ * the other stuff in that file.
+ *
+ */
+
+struct isa_device *find_isadev(table, driverp, unit)
+ struct isa_device *table;
+ struct isa_driver *driverp;
+ int unit;
+{
+ if (driverp == NULL) /* sanity check */
+ return NULL;
+
+ while ((table->id_driver != driverp) || (table->id_unit != unit)) {
+ if (table->id_driver == 0)
+ return NULL;
+
+ table++;
+ }
+
+ return table;
+}
+
+/*
+ * Return nonzero if a (masked) irq is pending for a given device.
+ */
+int
+isa_irq_pending(dvp)
+ struct isa_device *dvp;
+{
+ unsigned id_irq;
+
+ id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
+ if (id_irq & 0xff)
+ return (inb(IO_ICU1) & id_irq);
+ return (inb(IO_ICU2) & (id_irq >> 8));
+}
diff --git a/sys/amd64/isa/isa.h b/sys/amd64/isa/isa.h
new file mode 100644
index 0000000..a9c042d
--- /dev/null
+++ b/sys/amd64/isa/isa.h
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa.h 5.7 (Berkeley) 5/9/91
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 3 00158
+ * -------------------- ----- ----------------------
+ *
+ * 15 Feb 93 Julian Elischer Added entries for some scsi adapters
+ * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES
+ * section
+ * 26 Apr 93 Bruce Evans Support for intr-0.1
+ */
+
+/*
+ * ISA Bus conventions
+ */
+
+#ifndef LOCORE
+#include <sys/cdefs.h>
+
+unsigned char rtcin __P((int));
+extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
+void sysbeep __P((int, int));
+unsigned kbd_8042cmd __P((int));
+struct isa_device;
+int isa_irq_pending __P((struct isa_device *dvp));
+#endif
+
+
+/*
+ * Input / Output Port Assignments
+ */
+
+#ifndef IO_BEGIN
+#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
+
+ /* CPU Board */
+#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */
+#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
+#define IO_TIMER1 0x040 /* 8252 Timer #1 */
+#define IO_TIMER2 0x048 /* 8252 Timer #2 */
+#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_RTC 0x070 /* RTC */
+#define IO_NMI IO_RTC /* NMI Control */
+#define IO_DMAPG 0x080 /* DMA Page Registers */
+#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
+#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */
+#define IO_NPX 0x0F0 /* Numeric Coprocessor */
+
+ /* Cards */
+ /* 0x100 - 0x16F Open */
+
+#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */
+
+ /* 0x178 - 0x1EF Open */
+
+#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */
+#define IO_GAME 0x200 /* Game Controller */
+
+ /* 0x208 - 0x277 Open */
+
+#define IO_LPT2 0x278 /* Parallel Port #2 */
+
+ /* 0x280 - 0x2E7 Open */
+
+#define IO_COM4 0x2e8 /* COM4 i/o address */
+
+ /* 0x2F0 - 0x2F7 Open */
+
+#define IO_COM2 0x2f8 /* COM2 i/o address */
+ /* 0x300 - 0x32F Open */
+
+#define IO_BT0 0x330 /* bustek 742a default addr. */
+#define IO_AHA0 0x330 /* adaptec 1542 default addr. */
+#define IO_UHA0 0x330 /* ultrastore 14f default addr. */
+#define IO_BT1 0x334 /* bustek 742a default addr. */
+#define IO_AHA1 0x334 /* adaptec 1542 default addr. */
+ /* 0x338 - 0x36F Open */
+
+#define IO_FD2 0x370 /* secondary base i/o address */
+#define IO_LPT1 0x378 /* Parallel Port #1 */
+
+ /* 0x380 - 0x3AF Open */
+
+#define IO_MDA 0x3B0 /* Monochome Adapter */
+#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */
+#define IO_VGA 0x3C0 /* E/VGA Ports */
+#define IO_CGA 0x3D0 /* CGA Ports */
+
+ /* 0x3E0 - 0x3E7 Open */
+
+#define IO_COM3 0x3e8 /* COM3 i/o address */
+#define IO_FD1 0x3f0 /* primary base i/o address */
+#define IO_COM1 0x3f8 /* COM1 i/o address */
+
+#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */
+#endif IO_ISABEGIN
+
+/*
+ * Input / Output Port Sizes - these are from several sources, and tend
+ * to be the larger of what was found, ie COM ports can be 4, but some
+ * boards do not fully decode the address, thus 8 ports are used.
+ */
+
+#ifndef IO_ISASIZES
+#define IO_ISASIZES
+
+#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */
+#define IO_CGASIZE 16 /* CGA controllers */
+#define IO_DMASIZE 16 /* 8237 DMA controllers */
+#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */
+#define IO_FDCSIZE 8 /* Nec765 floppy controllers */
+#define IO_WDCSIZE 8 /* WD compatible disk controllers */
+#define IO_GAMSIZE 16 /* AT compatible game controllers */
+#define IO_ICUSIZE 16 /* 8259A interrupt controllers */
+#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */
+#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */
+#define IO_MDASIZE 16 /* Monochrome display controllers */
+#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */
+#define IO_TMRSIZE 16 /* 8253 programmable timers */
+#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */
+#define IO_VGASIZE 16 /* VGA controllers */
+
+#endif /* IO_ISASIZES */
+
+/*
+ * Input / Output Memory Physical Addresses
+ */
+
+#ifndef IOM_BEGIN
+#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */
+#define IOM_END 0x100000 /* End of I/O Memory "hole" */
+#define IOM_SIZE (IOM_END - IOM_BEGIN)
+#endif IOM_BEGIN
+
+/*
+ * RAM Physical Address Space (ignoring the above mentioned "hole")
+ */
+
+#ifndef RAM_BEGIN
+#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */
+#define RAM_END 0x1000000 /* End of RAM Memory */
+#define RAM_SIZE (RAM_END - RAM_BEGIN)
+#endif RAM_BEGIN
+
+/*
+ * Oddball Physical Memory Addresses
+ */
+#ifndef COMPAQ_RAMRELOC
+#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */
+#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */
+#define WEITEK_FPU 0xC0000000 /* WTL 2167 */
+#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */
+#endif COMPAQ_RAMRELOC
diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c
new file mode 100644
index 0000000..73392fa
--- /dev/null
+++ b/sys/amd64/isa/npx.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 23 May 93 Rodney W. Grimes Return a special value of -1 from
+ * the probe code to keep isa_config from
+ * printing out the I/O address when we
+ * are using trap 16 handling.
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $";
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0mask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al /* EOI (asm in strings loses cpp features) */
+ outb %al,$0xa0 /* IO_ICU2 */
+ outb %al,$0x20 /* IO_ICU1 */
+ movb $0,%al
+ outb %al,$0xf0 /* clear BUSY# latch */
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0mask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ return (IO_NPXSIZE);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (npx_ex16)
+ printf(" <Errors reported via Exception 16>");
+ else if (npx_irq13)
+ printf(" <Errors reported via IRQ 13>");
+ else if (npx_exists)
+ printf(" <Error reporting broken, using 387 emulator>");
+ else
+ printf(" <387 Emulator>");
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ curpcb->pcb_flags &= ~FM_TRAP;
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0mask >> 8))
+ | (old_icu2_mask & (npx0mask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/amd64/isa/timerreg.h b/sys/amd64/isa/timerreg.h
new file mode 100644
index 0000000..72c7022
--- /dev/null
+++ b/sys/amd64/isa/timerreg.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/amd64/isa/vector.S b/sys/amd64/isa/vector.S
new file mode 100644
index 0000000..38ac79c
--- /dev/null
+++ b/sys/amd64/isa/vector.S
@@ -0,0 +1,376 @@
+/* vector.s */
+/*
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00167
+ * -------------------- ----- ----------------------
+ *
+ * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple
+ * devices configed on the same irq with
+ * respect to ipending.
+ *
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#ifdef AUTO_EOI_1
+#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */
+#define ENABLE_ICU1
+#endif
+
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#ifdef AUTO_EOI_2
+#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */
+#define ENABLE_ICU1_AND_2 /* ... but it works */
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ /* pushl %es ; know compiler doesn't do string insns */ \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ /* movl %ax,%es ; */ \
+ SHOW_CLI ; /* although it interferes with "ASAP" */ \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ SHOW_STI ; \
+ /* popl %es ; */ \
+ popl %ds ; \
+ popl %edx; \
+ popl %ecx; \
+ popl %eax; \
+ iret
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dummy error code */ \
+ pushl $T_ASTFLT ; \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \
+ movl %ax,%es ; \
+ SHOW_CLI ; /* interrupt did an implicit cli */ \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ SHOW_CPL ; \
+ SHOW_STI ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ jmp doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ COUNT_EVENT(_intrcnt_pend, id_num) ; \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,Vresume + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ SHOW_IPENDING ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+IDTVEC(intrdefault)
+ STRAYINTR(7,1,1, al) /* XXX */
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+Vresume: .space 16 * 4 /* where to resume intr handler after unpend */
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _intrcnt_pend
+_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */
+ .globl _intrcnt_spl
+_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */
+ .globl _intrcnt_show
+_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .asciz "name pend"
+
+ BUILD_VECTORS
+
+/*
+ * now the spl names
+ */
+ .asciz "unpend_v"
+ .asciz "doreti"
+ .asciz "p0!ni"
+ .asciz "!p0!ni"
+ .asciz "p0ni"
+ .asciz "netisr_raw"
+ .asciz "netisr_ip"
+ .asciz "netisr_imp"
+ .asciz "netisr_ns"
+ .asciz "softclock"
+ .asciz "trap"
+ .asciz "doreti_exit2"
+ .asciz "splbio"
+ .asciz "splclock"
+ .asciz "splhigh"
+ .asciz "splimp"
+ .asciz "splnet"
+ .asciz "splsoftclock"
+ .asciz "spltty"
+ .asciz "spl0"
+ .asciz "netisr_raw2"
+ .asciz "netisr_ip2"
+ .asciz "splx"
+ .asciz "splx!0"
+ .asciz "unpend_V"
+ .asciz "spl25" /* spl25-spl31 are spares */
+ .asciz "spl26"
+ .asciz "spl27"
+ .asciz "spl28"
+ .asciz "spl29"
+ .asciz "spl30"
+ .asciz "spl31"
+/*
+ * now the mask names
+ */
+ .asciz "cli"
+ .asciz "cpl"
+ .asciz "imen"
+ .asciz "ipending"
+ .asciz "sti"
+ .asciz "mask5" /* mask5-mask7 are spares */
+ .asciz "mask6"
+ .asciz "mask7"
+
+_eintrnames:
diff --git a/sys/amd64/isa/vector.s b/sys/amd64/isa/vector.s
new file mode 100644
index 0000000..38ac79c
--- /dev/null
+++ b/sys/amd64/isa/vector.s
@@ -0,0 +1,376 @@
+/* vector.s */
+/*
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00167
+ * -------------------- ----- ----------------------
+ *
+ * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple
+ * devices configed on the same irq with
+ * respect to ipending.
+ *
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#ifdef AUTO_EOI_1
+#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */
+#define ENABLE_ICU1
+#endif
+
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#ifdef AUTO_EOI_2
+#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */
+#define ENABLE_ICU1_AND_2 /* ... but it works */
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ /* pushl %es ; know compiler doesn't do string insns */ \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ /* movl %ax,%es ; */ \
+ SHOW_CLI ; /* although it interferes with "ASAP" */ \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ SHOW_STI ; \
+ /* popl %es ; */ \
+ popl %ds ; \
+ popl %edx; \
+ popl %ecx; \
+ popl %eax; \
+ iret
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dummy error code */ \
+ pushl $T_ASTFLT ; \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \
+ movl %ax,%es ; \
+ SHOW_CLI ; /* interrupt did an implicit cli */ \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ SHOW_CPL ; \
+ SHOW_STI ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ jmp doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ COUNT_EVENT(_intrcnt_pend, id_num) ; \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,Vresume + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ SHOW_IPENDING ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+IDTVEC(intrdefault)
+ STRAYINTR(7,1,1, al) /* XXX */
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+Vresume: .space 16 * 4 /* where to resume intr handler after unpend */
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _intrcnt_pend
+_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */
+ .globl _intrcnt_spl
+_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */
+ .globl _intrcnt_show
+_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .asciz "name pend"
+
+ BUILD_VECTORS
+
+/*
+ * now the spl names
+ */
+ .asciz "unpend_v"
+ .asciz "doreti"
+ .asciz "p0!ni"
+ .asciz "!p0!ni"
+ .asciz "p0ni"
+ .asciz "netisr_raw"
+ .asciz "netisr_ip"
+ .asciz "netisr_imp"
+ .asciz "netisr_ns"
+ .asciz "softclock"
+ .asciz "trap"
+ .asciz "doreti_exit2"
+ .asciz "splbio"
+ .asciz "splclock"
+ .asciz "splhigh"
+ .asciz "splimp"
+ .asciz "splnet"
+ .asciz "splsoftclock"
+ .asciz "spltty"
+ .asciz "spl0"
+ .asciz "netisr_raw2"
+ .asciz "netisr_ip2"
+ .asciz "splx"
+ .asciz "splx!0"
+ .asciz "unpend_V"
+ .asciz "spl25" /* spl25-spl31 are spares */
+ .asciz "spl26"
+ .asciz "spl27"
+ .asciz "spl28"
+ .asciz "spl29"
+ .asciz "spl30"
+ .asciz "spl31"
+/*
+ * now the mask names
+ */
+ .asciz "cli"
+ .asciz "cpl"
+ .asciz "imen"
+ .asciz "ipending"
+ .asciz "sti"
+ .asciz "mask5" /* mask5-mask7 are spares */
+ .asciz "mask6"
+ .asciz "mask7"
+
+_eintrnames:
diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386
new file mode 100644
index 0000000..7eedfb8
--- /dev/null
+++ b/sys/conf/Makefile.i386
@@ -0,0 +1,164 @@
+# Copyright 1990 W. Jolitz
+# @(#)Makefile.i386 7.1 5/10/91
+# Makefile for 4.3 BSD-Reno
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00158
+# -------------------- ----- ----------------------
+#
+# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and
+# plain old link
+# 25 Mar 93 Sean Eric Fagan Add support for assembler source
+# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes
+# Rodney W. Grimes Added depedencies for conf.o due to
+# all the new drivers. And to param.c
+# because there were missing.
+# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL
+# Redirect stderr from dbsym to null,
+# this is bad, but atleast I won't get
+# 100's of bug reports about the silly
+# warning from dbsym.
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+
+S= ../..
+I386= ../../i386
+
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= -O ${COPTS}
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS}
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@
+
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ex - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym
+
+lint: /tmp param.c
+ @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+ ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+ grep -v 'struct/union .* never defined' | \
+ grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depend on maxusers
+assym.s machdep.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ $S/sys/vmmeter.h \
+ $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h
+
+assym.s: genassym
+ ./genassym >assym.s
+
+genassym:
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \
+ $S/sys/tty.h $S/sys/conf.h \
+ as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \
+ lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \
+ ${I386}/i386/conf.c
+ ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c \
+ $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \
+ $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \
+ $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \
+ $S/sys/shm.h
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+newvers:
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc
new file mode 100644
index 0000000..7eedfb8
--- /dev/null
+++ b/sys/conf/Makefile.powerpc
@@ -0,0 +1,164 @@
+# Copyright 1990 W. Jolitz
+# @(#)Makefile.i386 7.1 5/10/91
+# Makefile for 4.3 BSD-Reno
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00158
+# -------------------- ----- ----------------------
+#
+# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and
+# plain old link
+# 25 Mar 93 Sean Eric Fagan Add support for assembler source
+# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes
+# Rodney W. Grimes Added depedencies for conf.o due to
+# all the new drivers. And to param.c
+# because there were missing.
+# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL
+# Redirect stderr from dbsym to null,
+# this is bad, but atleast I won't get
+# 100's of bug reports about the silly
+# warning from dbsym.
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+
+S= ../..
+I386= ../../i386
+
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= -O ${COPTS}
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS}
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@
+
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ex - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym
+
+lint: /tmp param.c
+ @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+ ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+ grep -v 'struct/union .* never defined' | \
+ grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depend on maxusers
+assym.s machdep.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ $S/sys/vmmeter.h \
+ $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h
+
+assym.s: genassym
+ ./genassym >assym.s
+
+genassym:
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \
+ $S/sys/tty.h $S/sys/conf.h \
+ as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \
+ lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \
+ ${I386}/i386/conf.c
+ ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c \
+ $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \
+ $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \
+ $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \
+ $S/sys/shm.h
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+newvers:
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
new file mode 100644
index 0000000..578472c
--- /dev/null
+++ b/sys/conf/files.i386
@@ -0,0 +1,71 @@
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00160
+# -------------------- ----- ----------------------
+#
+# 17 Feb 93 Julian Elischer Added files for scsi
+# 10 Mar 93 Rodney W. Grimes Added files for lpt and lpa
+# 25 Mar 93 Sean Eric Fagan Added microtime.s routine
+# 08 Apr 93 Rodney W. Grimes Cleaned up the tabs, sorted file names
+# Added ix, speaker, dcfclock
+# 23 Apr 93 Holger Veit Added codrv
+# 26 May 93 Rodney W. Grimes Rename of Bruce Evans com driver to sio
+# Gene Stark Add xten power controler driver (tw)
+# David Greenman Add ethernet driver (SMC/WD/3COM) (ed)
+# Rick Macklem Add bus mouse driver (mse)
+#
+i386/i386/autoconf.c standard device-driver
+i386/i386/cons.c standard
+i386/i386/db_disasm.c optional ddb
+i386/i386/db_interface.c optional ddb
+i386/i386/db_trace.c optional ddb
+i386/i386/in_cksum.c optional inet
+i386/i386/machdep.c standard config-dependent
+i386/i386/math_emulate.c standard
+i386/i386/mem.c standard
+i386/i386/microtime.s standard
+i386/i386/ns_cksum.c optional ns
+i386/i386/pmap.c standard
+i386/i386/sys_machdep.c standard
+i386/i386/trap.c standard
+i386/i386/vm_machdep.c standard
+i386/isa/aha1542.c optional aha device-driver
+i386/isa/aha1742.c optional ahb device-driver
+i386/isa/as.c optional as device-driver
+i386/isa/bt742a.c optional bt device-driver
+i386/isa/clock.c standard
+i386/isa/codrv/co_cons.c optional co device-driver
+i386/isa/codrv/co_kbd.c optional co device-driver
+i386/isa/codrv/co_vga.c optional co device-driver
+i386/isa/codrv/co_codrv1.c optional co device-driver
+i386/isa/codrv/co_vty.c optional vty
+i386/isa/codrv/co_pc3.c optional vtemul
+i386/isa/codrv/co_mini.c optional vtemul
+i386/isa/com.c optional com device-driver
+i386/isa/dcfclk.c optional dcfclk device-driver
+i386/isa/fd.c optional fd device-driver
+i386/isa/if_ec.c optional ec device-driver
+i386/isa/if_ed.c optional ed device-driver
+i386/isa/if_is.c optional is device-driver
+i386/isa/if_ix.c optional ix device-driver
+i386/isa/if_ne.c optional ne device-driver
+i386/isa/if_we.c optional we device-driver
+i386/isa/isa.c optional isa device-driver
+i386/isa/lpa.c optional lpa device-driver
+i386/isa/lpt.c optional lpt device-driver
+i386/isa/mse.c optional mse device-driver
+i386/isa/npx.c optional npx device-driver
+i386/isa/pccons.c optional pc device-driver
+i386/isa/sio.c optional sio device-driver
+i386/isa/spkr.c optional speaker
+i386/isa/tw.c optional tw device-driver
+i386/isa/ultra14f.c optional uha device-driver
+i386/isa/wd.c optional wd device-driver
+i386/isa/wt.c optional wt device-driver
+scsi/cd.c optional cd
+scsi/ch.c optional ch
+scsi/scsiconf.c optional scbus
+scsi/sd.c optional sd
+scsi/st.c optional st
+
diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c
new file mode 100644
index 0000000..63368c0
--- /dev/null
+++ b/sys/ddb/db_access.c
@@ -0,0 +1,116 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_access.c,v $
+ * Revision 1.1 1992/03/25 21:44:50 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:05:44 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:16:22 mrt]
+ *
+ * Revision 2.2 90/08/27 21:48:20 dbg
+ * Fix type declarations.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h> /* type definitions */
+
+/*
+ * Access unaligned data items on aligned (longword)
+ * boundaries.
+ */
+
+extern void db_read_bytes(); /* machine-dependent */
+extern void db_write_bytes(); /* machine-dependent */
+
+int db_extend[] = { /* table for sign-extending */
+ 0,
+ 0xFFFFFF80,
+ 0xFFFF8000,
+ 0xFF800000
+};
+
+db_expr_t
+db_get_value(addr, size, is_signed)
+ db_addr_t addr;
+ register int size;
+ boolean_t is_signed;
+{
+ char data[sizeof(int)];
+ register db_expr_t value;
+ register int i;
+
+ db_read_bytes(addr, size, data);
+
+ value = 0;
+#if BYTE_MSF
+ for (i = 0; i < size; i++)
+#else /* BYTE_LSF */
+ for (i = size - 1; i >= 0; i--)
+#endif
+ {
+ value = (value << 8) + (data[i] & 0xFF);
+ }
+
+ if (size < 4) {
+ if (is_signed && (value & db_extend[size]) != 0)
+ value |= db_extend[size];
+ }
+ return (value);
+}
+
+void
+db_put_value(addr, size, value)
+ db_addr_t addr;
+ register int size;
+ register db_expr_t value;
+{
+ char data[sizeof(int)];
+ register int i;
+
+#if BYTE_MSF
+ for (i = size - 1; i >= 0; i--)
+#else /* BYTE_LSF */
+ for (i = 0; i < size; i++)
+#endif
+ {
+ data[i] = value & 0xFF;
+ value >>= 8;
+ }
+
+ db_write_bytes(addr, size, data);
+}
+
diff --git a/sys/ddb/db_access.h b/sys/ddb/db_access.h
new file mode 100644
index 0000000..ddc5349
--- /dev/null
+++ b/sys/ddb/db_access.h
@@ -0,0 +1,55 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_access.h,v $
+ * Revision 1.1 1992/03/25 21:44:53 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:05:49 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:16:37 mrt]
+ *
+ * Revision 2.2 90/08/27 21:48:27 dbg
+ * Created.
+ * [90/08/07 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Data access functions for debugger.
+ */
+#include <machine/db_machdep.h> /* expression types */
+
+extern db_expr_t db_get_value(/* db_addr_t addr,
+ int size,
+ boolean_t is_signed */);
+extern void db_put_value(/* db_addr_t addr,
+ int size,
+ db_expr_t value */);
diff --git a/sys/ddb/db_aout.c b/sys/ddb/db_aout.c
new file mode 100644
index 0000000..88f4b03
--- /dev/null
+++ b/sys/ddb/db_aout.c
@@ -0,0 +1,309 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_aout.c,v $
+ * Revision 1.1 1992/03/25 21:44:55 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:05:55 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:16:44 mrt]
+ *
+ * Revision 2.2 90/08/27 21:48:35 dbg
+ * Created.
+ * [90/08/17 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Symbol table routines for a.out format files.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h> /* data types */
+#include <ddb/db_sym.h>
+
+#ifndef DB_NO_AOUT
+
+#define _AOUT_INCLUDE_
+#include "nlist.h"
+
+/*
+ * An a.out symbol table as loaded into the kernel debugger:
+ *
+ * symtab -> size of symbol entries, in bytes
+ * sp -> first symbol entry
+ * ...
+ * ep -> last symbol entry + 1
+ * strtab == start of string table
+ * size of string table in bytes,
+ * including this word
+ * -> strings
+ */
+
+/*
+ * Find pointers to the start and end of the symbol entries,
+ * given a pointer to the start of the symbol table.
+ */
+#define db_get_aout_symtab(symtab, sp, ep) \
+ (sp = (struct nlist *)((symtab) + 1), \
+ ep = (struct nlist *)((char *)sp + *(symtab)))
+
+#define SYMTAB_SPACE 63000
+int db_symtabsize = SYMTAB_SPACE;
+char db_symtab[SYMTAB_SPACE] = { 1 };
+
+X_db_sym_init(symtab, esymtab, name)
+ int * symtab; /* pointer to start of symbol table */
+ char * esymtab; /* pointer to end of string table,
+ for checking - rounded up to integer
+ boundary */
+ char * name;
+{
+ register struct nlist *sym_start, *sym_end;
+ register struct nlist *sp;
+ register char * strtab;
+ register int strlen;
+
+ if (*symtab < 4) {
+ printf ("DDB: no symbols\n");
+ return;
+ }
+
+ db_get_aout_symtab(symtab, sym_start, sym_end);
+
+ strtab = (char *)sym_end;
+ strlen = *(int *)strtab;
+
+#if 0
+ if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1))
+ != esymtab)
+ {
+ db_printf("[ %s symbol table not valid ]\n", name);
+ return;
+ }
+
+ db_printf("[ preserving %#x bytes of %s symbol table ]\n",
+ esymtab - (char *)symtab, name);
+#endif
+
+ for (sp = sym_start; sp < sym_end; sp++) {
+ register int strx;
+ strx = sp->n_un.n_strx;
+ if (strx != 0) {
+ if (strx > strlen) {
+ db_printf("Bad string table index (%#x)\n", strx);
+ sp->n_un.n_name = 0;
+ continue;
+ }
+ sp->n_un.n_name = strtab + strx;
+ }
+ }
+
+ db_add_symbol_table(sym_start, sym_end, name, (char *)symtab);
+}
+
+db_sym_t
+X_db_lookup(stab, symstr)
+ db_symtab_t *stab;
+ char * symstr;
+{
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)stab->start;
+ ep = (struct nlist *)stab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) == 0 &&
+ sp->n_un.n_name != 0 &&
+ db_eqname(sp->n_un.n_name, symstr, '_'))
+ {
+ return ((db_sym_t)sp);
+ }
+ }
+ return ((db_sym_t)0);
+}
+
+db_sym_t
+X_db_search_symbol(symtab, off, strategy, diffp)
+ db_symtab_t * symtab;
+ register
+ db_addr_t off;
+ db_strategy_t strategy;
+ db_expr_t *diffp; /* in/out */
+{
+ register unsigned int diff = *diffp;
+ register struct nlist *symp = 0;
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) != 0)
+ continue;
+ if (off >= sp->n_value) {
+ if (off - sp->n_value < diff) {
+ diff = off - sp->n_value;
+ symp = sp;
+ if (diff == 0)
+ break;
+ }
+ else if (off - sp->n_value == diff) {
+ if (symp == 0)
+ symp = sp;
+ else if ((symp->n_type & N_EXT) == 0 &&
+ (sp->n_type & N_EXT) != 0)
+ symp = sp; /* pick the external symbol */
+ }
+ }
+ }
+ if (symp == 0) {
+ *diffp = off;
+ }
+ else {
+ *diffp = diff;
+ }
+ return ((db_sym_t)symp);
+}
+
+/*
+ * Return the name and value for a symbol.
+ */
+void
+X_db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ register struct nlist *sp;
+
+ sp = (struct nlist *)sym;
+ if (namep)
+ *namep = sp->n_un.n_name;
+ if (valuep)
+ *valuep = sp->n_value;
+}
+
+boolean_t
+X_db_line_at_pc()
+{
+ return (FALSE);
+}
+
+/*
+ * Initialization routine for a.out files.
+ */
+kdb_init()
+{
+#if 0
+ extern char *esym;
+ extern int end;
+
+ if (esym > (char *)&end) {
+ X_db_sym_init((int *)&end, esym, "mach");
+ }
+#endif
+
+ X_db_sym_init (db_symtab, 0, "mach");
+}
+
+#if 0
+/*
+ * Read symbol table from file.
+ * (should be somewhere else)
+ */
+#include <boot_ufs/file_io.h>
+#include <vm/vm_kern.h>
+
+read_symtab_from_file(fp, symtab_name)
+ struct file *fp;
+ char * symtab_name;
+{
+ vm_size_t resid;
+ kern_return_t result;
+ vm_offset_t symoff;
+ vm_size_t symsize;
+ vm_offset_t stroff;
+ vm_size_t strsize;
+ vm_size_t table_size;
+ vm_offset_t symtab;
+
+ if (!get_symtab(fp, &symoff, &symsize)) {
+ boot_printf("[ error %d reading %s file header ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ stroff = symoff + symsize;
+ result = read_file(fp, (vm_offset_t)stroff,
+ (vm_offset_t)&strsize, sizeof(strsize), &resid);
+ if (result || resid) {
+ boot_printf("[ no valid symbol table present for %s ]\n",
+ symtab_name);
+ return;
+ }
+
+ table_size = sizeof(int) + symsize + strsize;
+ table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1);
+
+ symtab = kmem_alloc_wired(kernel_map, table_size);
+
+ *(int *)symtab = symsize;
+
+ result = read_file(fp, symoff,
+ symtab + sizeof(int), symsize, &resid);
+ if (result || resid) {
+ boot_printf("[ error %d reading %s symbol table ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ result = read_file(fp, stroff,
+ symtab + sizeof(int) + symsize, strsize, &resid);
+ if (result || resid) {
+ boot_printf("[ error %d reading %s string table ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ X_db_sym_init((int *)symtab,
+ (char *)(symtab + table_size),
+ symtab_name);
+
+}
+#endif
+
+#endif /* DB_NO_AOUT */
diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c
new file mode 100644
index 0000000..9db7a04
--- /dev/null
+++ b/sys/ddb/db_break.c
@@ -0,0 +1,387 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_break.c,v $
+ * Revision 1.1 1992/03/25 21:44:57 pace
+ * Initial revision
+ *
+ * Revision 2.7 91/02/05 17:06:00 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:01 mrt]
+ *
+ * Revision 2.6 91/01/08 15:09:03 rpd
+ * Added db_map_equal, db_map_current, db_map_addr.
+ * [90/11/10 rpd]
+ *
+ * Revision 2.5 90/11/05 14:26:32 rpd
+ * Initialize db_breakpoints_inserted to TRUE.
+ * [90/11/04 rpd]
+ *
+ * Revision 2.4 90/10/25 14:43:33 rwd
+ * Added map field to breakpoints.
+ * Added map argument to db_set_breakpoint, db_delete_breakpoint,
+ * db_find_breakpoint. Added db_find_breakpoint_here.
+ * [90/10/18 rpd]
+ *
+ * Revision 2.3 90/09/28 16:57:07 jsb
+ * Fixed db_breakpoint_free.
+ * [90/09/18 rpd]
+ *
+ * Revision 2.2 90/08/27 21:49:53 dbg
+ * Reflected changes in db_printsym()'s calling seq.
+ * [90/08/20 af]
+ * Clear breakpoints only if inserted.
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Breakpoints.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_break.h>
+
+extern boolean_t db_map_equal();
+extern boolean_t db_map_current();
+extern vm_map_t db_map_addr();
+
+#define NBREAKPOINTS 100
+struct db_breakpoint db_break_table[NBREAKPOINTS];
+db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
+db_breakpoint_t db_free_breakpoints = 0;
+db_breakpoint_t db_breakpoint_list = 0;
+
+db_breakpoint_t
+db_breakpoint_alloc()
+{
+ register db_breakpoint_t bkpt;
+
+ if ((bkpt = db_free_breakpoints) != 0) {
+ db_free_breakpoints = bkpt->link;
+ return (bkpt);
+ }
+ if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
+ db_printf("All breakpoints used.\n");
+ return (0);
+ }
+ bkpt = db_next_free_breakpoint;
+ db_next_free_breakpoint++;
+
+ return (bkpt);
+}
+
+void
+db_breakpoint_free(bkpt)
+ register db_breakpoint_t bkpt;
+{
+ bkpt->link = db_free_breakpoints;
+ db_free_breakpoints = bkpt;
+}
+
+void
+db_set_breakpoint(map, addr, count)
+ vm_map_t map;
+ db_addr_t addr;
+ int count;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_find_breakpoint(map, addr)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return;
+ }
+
+ bkpt->map = map;
+ bkpt->address = addr;
+ bkpt->flags = 0;
+ bkpt->init_count = count;
+ bkpt->count = count;
+
+ bkpt->link = db_breakpoint_list;
+ db_breakpoint_list = bkpt;
+}
+
+void
+db_delete_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+ register db_breakpoint_t *prev;
+
+ for (prev = &db_breakpoint_list;
+ (bkpt = *prev) != 0;
+ prev = &bkpt->link) {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr)) {
+ *prev = bkpt->link;
+ break;
+ }
+ }
+ if (bkpt == 0) {
+ db_printf("Not set.\n");
+ return;
+ }
+
+ db_breakpoint_free(bkpt);
+}
+
+db_breakpoint_t
+db_find_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr))
+ return (bkpt);
+ }
+ return (0);
+}
+
+db_breakpoint_t
+db_find_breakpoint_here(addr)
+ db_addr_t addr;
+{
+ return db_find_breakpoint(db_map_addr(addr), addr);
+}
+
+boolean_t db_breakpoints_inserted = TRUE;
+
+void
+db_set_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (!db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ bkpt->bkpt_inst = db_get_value(bkpt->address,
+ BKPT_SIZE,
+ FALSE);
+ db_put_value(bkpt->address,
+ BKPT_SIZE,
+ BKPT_SET(bkpt->bkpt_inst));
+ }
+ db_breakpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ }
+ db_breakpoints_inserted = FALSE;
+ }
+}
+
+/*
+ * Set a temporary breakpoint.
+ * The instruction is changed immediately,
+ * so the breakpoint does not have to be on the breakpoint list.
+ */
+db_breakpoint_t
+db_set_temp_breakpoint(addr)
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return 0;
+ }
+
+ bkpt->map = NULL;
+ bkpt->address = addr;
+ bkpt->flags = BKPT_TEMP;
+ bkpt->init_count = 1;
+ bkpt->count = 1;
+
+ bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
+ db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
+ return bkpt;
+}
+
+void
+db_delete_temp_breakpoint(bkpt)
+ db_breakpoint_t bkpt;
+{
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ db_breakpoint_free(bkpt);
+}
+
+/*
+ * List breakpoints.
+ */
+void
+db_list_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoint_list == 0) {
+ db_printf("No breakpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Count Address\n");
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ db_printf("%s%8x %5d ",
+ db_map_current(bkpt->map) ? "*" : " ",
+ bkpt->map, bkpt->init_count);
+ db_printsym(bkpt->address, DB_STGY_PROC);
+ db_printf("\n");
+ }
+}
+
+/* Delete breakpoint */
+/*ARGSUSED*/
+void
+db_delete_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
+}
+
+/* Set breakpoint with skip count */
+/*ARGSUSED*/
+void
+db_breakpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (count == -1)
+ count = 1;
+
+ db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
+}
+
+/* list breakpoints */
+void
+db_listbreak_cmd()
+{
+ db_list_breakpoints();
+}
+
+#include <vm/vm_kern.h>
+
+/*
+ * We want ddb to be usable before most of the kernel has been
+ * initialized. In particular, current_thread() or kernel_map
+ * (or both) may be null.
+ */
+
+boolean_t
+db_map_equal(map1, map2)
+ vm_map_t map1, map2;
+{
+ return ((map1 == map2) ||
+ ((map1 == NULL) && (map2 == kernel_map)) ||
+ ((map1 == kernel_map) && (map2 == NULL)));
+}
+
+boolean_t
+db_map_current(map)
+ vm_map_t map;
+{
+#if 0
+ thread_t thread;
+
+ return ((map == NULL) ||
+ (map == kernel_map) ||
+ (((thread = current_thread()) != NULL) &&
+ (map == thread->task->map)));
+#else
+ return (1);
+#endif
+}
+
+vm_map_t
+db_map_addr(addr)
+ vm_offset_t addr;
+{
+#if 0
+ thread_t thread;
+
+ /*
+ * We want to return kernel_map for all
+ * non-user addresses, even when debugging
+ * kernel tasks with their own maps.
+ */
+
+ if ((VM_MIN_ADDRESS <= addr) &&
+ (addr < VM_MAX_ADDRESS) &&
+ ((thread = current_thread()) != NULL))
+ return thread->task->map;
+ else
+#endif
+ return kernel_map;
+}
diff --git a/sys/ddb/db_break.h b/sys/ddb/db_break.h
new file mode 100644
index 0000000..874cbcb
--- /dev/null
+++ b/sys/ddb/db_break.h
@@ -0,0 +1,84 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_break.h,v $
+ * Revision 1.1 1992/03/25 21:44:59 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/05 17:06:06 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:10 mrt]
+ *
+ * Revision 2.3 90/10/25 14:43:40 rwd
+ * Added map field to breakpoints.
+ * [90/10/18 rpd]
+ *
+ * Revision 2.2 90/08/27 21:50:00 dbg
+ * Modularized typedef names.
+ * [90/08/20 af]
+ * Add external defintions.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#ifndef _DDB_DB_BREAK_H_
+#define _DDB_DB_BREAK_H_
+
+#include <vm/vm_map.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Breakpoint.
+ */
+
+struct db_breakpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t address; /* set here */
+ int init_count; /* number of times to skip bkpt */
+ int count; /* current count */
+ int flags; /* flags: */
+#define BKPT_SINGLE_STEP 0x2 /* to simulate single step */
+#define BKPT_TEMP 0x4 /* temporary */
+ int bkpt_inst; /* saved instruction at bkpt */
+ struct db_breakpoint *link; /* link in in-use or free chain */
+};
+typedef struct db_breakpoint *db_breakpoint_t;
+
+extern db_breakpoint_t db_find_breakpoint();
+extern db_breakpoint_t db_find_breakpoint_here();
+extern void db_set_breakpoints();
+extern void db_clear_breakpoints();
+
+extern db_breakpoint_t db_set_temp_breakpoint(/* db_addr_t addr */);
+extern void db_delete_temp_breakpoint(/* db_breakpoint_t bkpt */);
+
+#endif _DDB_DB_BREAK_H_
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
new file mode 100644
index 0000000..e660e18
--- /dev/null
+++ b/sys/ddb/db_command.c
@@ -0,0 +1,526 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_command.c,v $
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00081
+ * -------------------- ----- ----------------------
+ *
+ * 01 Feb 93 Julian Elischer move strcmp to a more general
+ * part of the kernel.
+ *
+ * Revision 1.1 1992/03/25 21:45:02 pace
+ * Initial revision
+ *
+ * Revision 2.6 91/02/05 17:06:10 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:18 mrt]
+ *
+ * Revision 2.5 91/01/08 17:31:54 rpd
+ * Forward reference for db_fncall();
+ * [91/01/04 12:35:17 rvb]
+ *
+ * Add call as a synonym for ! and match for next
+ * [91/01/04 12:14:48 rvb]
+ *
+ * Revision 2.4 90/11/07 16:49:15 rpd
+ * Added search.
+ * [90/11/06 rpd]
+ *
+ * Revision 2.3 90/10/25 14:43:45 rwd
+ * Changed db_fncall to print the result unsigned.
+ * [90/10/19 rpd]
+ *
+ * Added CS_MORE to db_watchpoint_cmd.
+ * [90/10/17 rpd]
+ * Added watchpoint commands: watch, dwatch, show watches.
+ * [90/10/16 rpd]
+ *
+ * Revision 2.2 90/08/27 21:50:10 dbg
+ * Remove 'listbreaks' - use 'show breaks' instead. Change 'show
+ * threads' to 'show all threads' to avoid clash with 'show thread'.
+ * Set 'dot' here from db_prev or db_next, depending on 'db_ed_style'
+ * flag and syntax table.
+ * [90/08/22 dbg]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Command dispatcher.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+
+#include <setjmp.h>
+
+/*
+ * Exported global variables
+ */
+boolean_t db_cmd_loop_done;
+jmp_buf db_jmpbuf;
+db_addr_t db_dot;
+db_addr_t db_last_addr;
+db_addr_t db_prev;
+db_addr_t db_next;
+
+/*
+ * if 'ed' style: 'dot' is set at start of last item printed,
+ * and '+' points to next line.
+ * Otherwise: 'dot' points to next item, '..' points to last.
+ */
+boolean_t db_ed_style = TRUE;
+
+
+/*
+ * Utility routine - discard tokens through end-of-line.
+ */
+void
+db_skip_to_eol()
+{
+ int t;
+ do {
+ t = db_read_token();
+ } while (t != tEOL);
+}
+
+/*
+ * Command table
+ */
+struct command {
+ char * name; /* command name */
+ void (*fcn)(); /* function to call */
+ int flag; /* extra info: */
+#define CS_OWN 0x1 /* non-standard syntax */
+#define CS_MORE 0x2 /* standard syntax, but may have other
+ words at end */
+#define CS_SET_DOT 0x100 /* set dot after command */
+ struct command *more; /* another level of command */
+};
+
+/*
+ * Results of command search.
+ */
+#define CMD_UNIQUE 0
+#define CMD_FOUND 1
+#define CMD_NONE 2
+#define CMD_AMBIGUOUS 3
+#define CMD_HELP 4
+
+/*
+ * Search for command prefix.
+ */
+int
+db_cmd_search(name, table, cmdp)
+ char * name;
+ struct command *table;
+ struct command **cmdp; /* out */
+{
+ struct command *cmd;
+ int result = CMD_NONE;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ register char *lp;
+ register char *rp;
+ register int c;
+
+ lp = name;
+ rp = cmd->name;
+ while ((c = *lp) == *rp) {
+ if (c == 0) {
+ /* complete match */
+ *cmdp = cmd;
+ return (CMD_UNIQUE);
+ }
+ lp++;
+ rp++;
+ }
+ if (c == 0) {
+ /* end of name, not end of command -
+ partial match */
+ if (result == CMD_FOUND) {
+ result = CMD_AMBIGUOUS;
+ /* but keep looking for a full match -
+ this lets us match single letters */
+ }
+ else {
+ *cmdp = cmd;
+ result = CMD_FOUND;
+ }
+ }
+ }
+ if (result == CMD_NONE) {
+ /* check for 'help' */
+ if (name[0] == 'h' && name[1] == 'e'
+ && name[2] == 'l' && name[3] == 'p')
+ result = CMD_HELP;
+ }
+ return (result);
+}
+
+void
+db_cmd_list(table)
+ struct command *table;
+{
+ register struct command *cmd;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ }
+}
+
+void
+db_command(last_cmdp, cmd_table)
+ struct command **last_cmdp; /* IN_OUT */
+ struct command *cmd_table;
+{
+ struct command *cmd;
+ int t;
+ char modif[TOK_STRING_SIZE];
+ db_expr_t addr, count;
+ boolean_t have_addr;
+ int result;
+
+ t = db_read_token();
+ if (t == tEOL) {
+ /* empty line repeats last command, at 'next' */
+ cmd = *last_cmdp;
+ addr = (db_expr_t)db_next;
+ have_addr = FALSE;
+ count = 1;
+ modif[0] = '\0';
+ }
+ else if (t == tEXCL) {
+ void db_fncall();
+ db_fncall();
+ return;
+ }
+ else if (t != tIDENT) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ else {
+ /*
+ * Search for command
+ */
+ while (cmd_table) {
+ result = db_cmd_search(db_tok_string,
+ cmd_table,
+ &cmd);
+ switch (result) {
+ case CMD_NONE:
+ db_printf("No such command\n");
+ db_flush_lex();
+ return;
+ case CMD_AMBIGUOUS:
+ db_printf("Ambiguous\n");
+ db_flush_lex();
+ return;
+ case CMD_HELP:
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ default:
+ break;
+ }
+ if ((cmd_table = cmd->more) != 0) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ }
+ }
+ }
+
+ if ((cmd->flag & CS_OWN) == 0) {
+ /*
+ * Standard syntax:
+ * command [/modifier] [addr] [,count]
+ */
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+ db_strcpy(modif, db_tok_string);
+ }
+ else {
+ db_unread_token(t);
+ modif[0] = '\0';
+ }
+
+ if (db_expression(&addr)) {
+ db_dot = (db_addr_t) addr;
+ db_last_addr = db_dot;
+ have_addr = TRUE;
+ }
+ else {
+ addr = (db_expr_t) db_dot;
+ have_addr = FALSE;
+ }
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ else {
+ db_unread_token(t);
+ count = -1;
+ }
+ if ((cmd->flag & CS_MORE) == 0) {
+ db_skip_to_eol();
+ }
+ }
+ }
+ *last_cmdp = cmd;
+ if (cmd != 0) {
+ /*
+ * Execute the command.
+ */
+ (*cmd->fcn)(addr, have_addr, count, modif);
+
+ if (cmd->flag & CS_SET_DOT) {
+ /*
+ * If command changes dot, set dot to
+ * previous address displayed (if 'ed' style).
+ */
+ if (db_ed_style) {
+ db_dot = db_prev;
+ }
+ else {
+ db_dot = db_next;
+ }
+ }
+ else {
+ /*
+ * If command does not change dot,
+ * set 'next' location to be the same.
+ */
+ db_next = db_dot;
+ }
+ }
+}
+
+/*
+ * 'show' commands
+ */
+extern void db_listbreak_cmd();
+extern void db_listwatch_cmd();
+extern void db_show_regs(), db_show_one_thread(), db_show_all_threads();
+extern void vm_map_print(), vm_object_print(), vm_page_print();
+extern void ipc_port_print();
+void db_show_help();
+
+struct command db_show_all_cmds[] = {
+#if 0
+ { "threads", db_show_all_threads,0, 0 },
+#endif
+ { (char *)0 }
+};
+
+struct command db_show_cmds[] = {
+ { "all", 0, 0, db_show_all_cmds },
+ { "registers", db_show_regs, 0, 0 },
+ { "breaks", db_listbreak_cmd, 0, 0 },
+ { "watches", db_listwatch_cmd, 0, 0 },
+#if 0
+ { "thread", db_show_one_thread, 0, 0 },
+#endif
+ { "map", vm_map_print, 0, 0 },
+ { "object", vm_object_print, 0, 0 },
+#if 0
+ { "page", vm_page_print, 0, 0 },
+#endif
+#if 0
+ { "port", ipc_port_print, 0, 0 },
+#endif
+ { (char *)0, }
+};
+
+extern void db_print_cmd(), db_examine_cmd(), db_set_cmd();
+extern void db_search_cmd();
+extern void db_write_cmd();
+extern void db_delete_cmd(), db_breakpoint_cmd();
+extern void db_deletewatch_cmd(), db_watchpoint_cmd();
+extern void db_single_step_cmd(), db_trace_until_call_cmd(),
+ db_trace_until_matching_cmd(), db_continue_cmd();
+extern void db_stack_trace_cmd();
+void db_help_cmd();
+void db_fncall();
+
+struct command db_command_table[] = {
+ { "print", db_print_cmd, 0, 0 },
+ { "examine", db_examine_cmd, CS_SET_DOT, 0 },
+ { "x", db_examine_cmd, CS_SET_DOT, 0 },
+ { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 },
+ { "set", db_set_cmd, CS_OWN, 0 },
+ { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "delete", db_delete_cmd, 0, 0 },
+ { "d", db_delete_cmd, 0, 0 },
+ { "break", db_breakpoint_cmd, 0, 0 },
+ { "dwatch", db_deletewatch_cmd, 0, 0 },
+ { "watch", db_watchpoint_cmd, CS_MORE,0 },
+ { "step", db_single_step_cmd, 0, 0 },
+ { "s", db_single_step_cmd, 0, 0 },
+ { "continue", db_continue_cmd, 0, 0 },
+ { "c", db_continue_cmd, 0, 0 },
+ { "until", db_trace_until_call_cmd,0, 0 },
+ { "next", db_trace_until_matching_cmd,0, 0 },
+ { "match", db_trace_until_matching_cmd,0, 0 },
+ { "trace", db_stack_trace_cmd, 0, 0 },
+ { "call", db_fncall, CS_OWN, 0 },
+ { "show", 0, 0, db_show_cmds },
+ { (char *)0, }
+};
+
+struct command *db_last_command = 0;
+
+void
+db_help_cmd()
+{
+ struct command *cmd = db_command_table;
+
+ while (cmd->name != 0) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ cmd++;
+ }
+}
+
+void
+db_command_loop()
+{
+ /*
+ * Initialize 'prev' and 'next' to dot.
+ */
+ db_prev = db_dot;
+ db_next = db_dot;
+
+ db_cmd_loop_done = 0;
+ while (!db_cmd_loop_done) {
+
+ (void) setjmp(db_jmpbuf);
+ if (db_print_position() != 0)
+ db_printf("\n");
+
+ db_printf("db> ");
+ (void) db_read_line();
+
+ db_command(&db_last_command, db_command_table);
+ }
+}
+
+void
+db_error(s)
+ char *s;
+{
+ if (s)
+ db_printf(s);
+ db_flush_lex();
+ longjmp(db_jmpbuf, 1);
+}
+
+
+/*
+ * Call random function:
+ * !expr(arg,arg,arg)
+ */
+void
+db_fncall()
+{
+ db_expr_t fn_addr;
+#define MAXARGS 11
+ db_expr_t args[MAXARGS];
+ int nargs = 0;
+ db_expr_t retval;
+ db_expr_t (*func)();
+ int t;
+
+ if (!db_expression(&fn_addr)) {
+ db_printf("Bad function\n");
+ db_flush_lex();
+ return;
+ }
+ func = (db_expr_t (*) ()) fn_addr;
+
+ t = db_read_token();
+ if (t == tLPAREN) {
+ if (db_expression(&args[0])) {
+ nargs++;
+ while ((t = db_read_token()) == tCOMMA) {
+ if (nargs == MAXARGS) {
+ db_printf("Too many arguments\n");
+ db_flush_lex();
+ return;
+ }
+ if (!db_expression(&args[nargs])) {
+ db_printf("Argument missing\n");
+ db_flush_lex();
+ return;
+ }
+ nargs++;
+ }
+ db_unread_token(t);
+ }
+ if (db_read_token() != tRPAREN) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ db_skip_to_eol();
+
+ while (nargs < MAXARGS) {
+ args[nargs++] = 0;
+ }
+
+ retval = (*func)(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8], args[9] );
+ db_printf("%#n\n", retval);
+}
diff --git a/sys/ddb/db_command.h b/sys/ddb/db_command.h
new file mode 100644
index 0000000..938a3d6
--- /dev/null
+++ b/sys/ddb/db_command.h
@@ -0,0 +1,67 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_command.h,v $
+ * Revision 1.1 1992/03/25 21:45:05 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:15 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:28 mrt]
+ *
+ * Revision 2.2 90/08/27 21:50:19 dbg
+ * Replace db_last_address_examined with db_prev, db_next.
+ * [90/08/22 dbg]
+ * Created.
+ * [90/08/07 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Command loop declarations.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+extern void db_command_loop();
+extern void db_skip_to_eol();
+
+extern void db_error(/* char * */); /* report error */
+
+extern db_addr_t db_dot; /* current location */
+extern db_addr_t db_last_addr; /* last explicit address typed */
+extern db_addr_t db_prev; /* last address examined
+ or written */
+extern db_addr_t db_next; /* next address to be examined
+ or written */
+
+
diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c
new file mode 100644
index 0000000..66f5f68
--- /dev/null
+++ b/sys/ddb/db_examine.c
@@ -0,0 +1,364 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_examine.c,v $
+ * Revision 1.1 1992/03/25 21:45:07 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/05 17:06:20 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:37 mrt]
+ *
+ * Revision 2.3 90/11/07 16:49:23 rpd
+ * Added db_search_cmd, db_search.
+ * [90/11/06 rpd]
+ *
+ * Revision 2.2 90/08/27 21:50:38 dbg
+ * Add 'r', 'z' to print and examine formats.
+ * Change calling sequence of db_disasm.
+ * db_examine sets db_prev and db_next instead of explicitly
+ * advancing dot.
+ * [90/08/20 dbg]
+ * Reflected changes in db_printsym()'s calling seq.
+ * [90/08/20 af]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h> /* type definitions */
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+char db_examine_format[TOK_STRING_SIZE] = "x";
+
+extern db_addr_t db_disasm(/* db_addr_t, boolean_t */);
+ /* instruction disassembler */
+
+/*
+ * Examine (print) data.
+ */
+/*ARGSUSED*/
+void
+db_examine_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] != '\0')
+ db_strcpy(db_examine_format, modif);
+
+ if (count == -1)
+ count = 1;
+
+ db_examine((db_addr_t) addr, db_examine_format, count);
+}
+
+db_examine(addr, fmt, count)
+ register
+ db_addr_t addr;
+ char * fmt; /* format string */
+ int count; /* repeat count */
+{
+ int c;
+ db_expr_t value;
+ int size;
+ int width;
+ char * fp;
+
+ while (--count >= 0) {
+ fp = fmt;
+ size = 4;
+ width = 16;
+ while ((c = *fp++) != 0) {
+ switch (c) {
+ case 'b':
+ size = 1;
+ width = 4;
+ break;
+ case 'h':
+ size = 2;
+ width = 8;
+ break;
+ case 'l':
+ size = 4;
+ width = 16;
+ break;
+ case 'a': /* address */
+ /* always forces a new line */
+ if (db_print_position() != 0)
+ db_printf("\n");
+ db_prev = addr;
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf(":\t");
+ break;
+ default:
+ if (db_print_position() == 0) {
+ /* If we hit a new symbol, print it */
+ char * name;
+ db_expr_t off;
+
+ db_find_sym_and_offset(addr, &name, &off);
+ if (off == 0)
+ db_printf("%s:\t", name);
+ else
+ db_printf("\t\t");
+
+ db_prev = addr;
+ }
+
+ switch (c) {
+ case 'r': /* signed, current radix */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*r", width, value);
+ break;
+ case 'x': /* unsigned hex */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*x", width, value);
+ break;
+ case 'z': /* signed hex */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*z", width, value);
+ break;
+ case 'd': /* signed decimal */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*d", width, value);
+ break;
+ case 'u': /* unsigned decimal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*u", width, value);
+ break;
+ case 'o': /* unsigned octal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*o", width, value);
+ break;
+ case 'c': /* character */
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ case 's': /* null-terminated string */
+ for (;;) {
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value == 0)
+ break;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ }
+ break;
+ case 'i': /* instruction */
+ addr = db_disasm(addr, FALSE);
+ break;
+ case 'I': /* instruction, alternate form */
+ addr = db_disasm(addr, TRUE);
+ break;
+ default:
+ break;
+ }
+ if (db_print_position() != 0)
+ db_end_line();
+ break;
+ }
+ }
+ }
+ db_next = addr;
+}
+
+/*
+ * Print value.
+ */
+char db_print_format = 'x';
+
+/*ARGSUSED*/
+void
+db_print_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_expr_t value;
+
+ if (modif[0] != '\0')
+ db_print_format = modif[0];
+
+ switch (db_print_format) {
+ case 'a':
+ db_printsym((db_addr_t)addr, DB_STGY_ANY);
+ break;
+ case 'r':
+ db_printf("%11r", addr);
+ break;
+ case 'x':
+ db_printf("%8x", addr);
+ break;
+ case 'z':
+ db_printf("%8z", addr);
+ break;
+ case 'd':
+ db_printf("%11d", addr);
+ break;
+ case 'u':
+ db_printf("%11u", addr);
+ break;
+ case 'o':
+ db_printf("%16o", addr);
+ break;
+ case 'c':
+ value = addr & 0xFF;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ }
+ db_printf("\n");
+}
+
+db_print_loc_and_inst(loc)
+ db_addr_t loc;
+{
+ db_printsym(loc, DB_STGY_PROC);
+ db_printf(":\t");
+ (void) db_disasm(loc, TRUE);
+}
+
+db_strcpy(dst, src)
+ register char *dst;
+ register char *src;
+{
+ while (*dst++ = *src++)
+ ;
+}
+
+/*
+ * Search for a value in memory.
+ * Syntax: search [/bhl] addr value [mask] [,count]
+ */
+void
+db_search_cmd()
+{
+ int t;
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ bad_modifier:
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!strcmp(db_tok_string, "b"))
+ size = 1;
+ else if (!strcmp(db_tok_string, "h"))
+ size = 2;
+ else if (!strcmp(db_tok_string, "l"))
+ size = 4;
+ else
+ goto bad_modifier;
+ } else {
+ db_unread_token(t);
+ size = 4;
+ }
+
+ if (!db_expression(&addr)) {
+ db_printf("Address missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&value)) {
+ db_printf("Value missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&mask))
+ mask = 0xffffffff;
+
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ } else {
+ db_unread_token(t);
+ count = -1; /* effectively forever */
+ }
+ db_skip_to_eol();
+
+ db_search(addr, size, value, mask, count);
+}
+
+db_search(addr, size, value, mask, count)
+ register
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+{
+ while (count-- != 0) {
+ db_prev = addr;
+ if ((db_get_value(addr, size, FALSE) & mask) == value)
+ break;
+ addr += size;
+ }
+ db_next = addr;
+}
diff --git a/sys/ddb/db_expr.c b/sys/ddb/db_expr.c
new file mode 100644
index 0000000..062662c
--- /dev/null
+++ b/sys/ddb/db_expr.c
@@ -0,0 +1,248 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_expr.c,v $
+ * Revision 1.1 1992/03/25 21:45:09 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:25 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:17:46 mrt]
+ *
+ * Revision 2.2 90/08/27 21:50:57 dbg
+ * Use '..' instead of '$$' for db_prev.
+ * Use '+' for db_next.
+ * [90/08/22 dbg]
+ *
+ * Allow repeated unary operators.
+ * [90/08/20 dbg]
+ *
+ * Reflected back rename of db_symbol_value->db_value_of_name
+ * [90/08/20 af]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+
+boolean_t
+db_term(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ if (!db_value_of_name(db_tok_string, valuep)) {
+ db_error("Symbol not found\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ if (t == tNUMBER) {
+ *valuep = (db_expr_t)db_tok_number;
+ return (TRUE);
+ }
+ if (t == tDOT) {
+ *valuep = (db_expr_t)db_dot;
+ return (TRUE);
+ }
+ if (t == tDOTDOT) {
+ *valuep = (db_expr_t)db_prev;
+ return (TRUE);
+ }
+ if (t == tPLUS) {
+ *valuep = (db_expr_t) db_next;
+ return (TRUE);
+ }
+ if (t == tDITTO) {
+ *valuep = (db_expr_t)db_last_addr;
+ return (TRUE);
+ }
+ if (t == tDOLLAR) {
+ if (!db_get_variable(valuep))
+ return (FALSE);
+ return (TRUE);
+ }
+ if (t == tLPAREN) {
+ if (!db_expression(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ t = db_read_token();
+ if (t != tRPAREN) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (FALSE);
+}
+
+boolean_t
+db_unary(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tMINUS) {
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = -*valuep;
+ return (TRUE);
+ }
+ if (t == tSTAR) {
+ /* indirection */
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = db_get_value((db_addr_t)*valuep, sizeof(int), FALSE);
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (db_term(valuep));
+}
+
+boolean_t
+db_mult_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_unary(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH) {
+ if (!db_term(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSTAR)
+ lhs *= rhs;
+ else {
+ if (rhs == 0) {
+ db_error("Divide by 0\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSLASH)
+ lhs /= rhs;
+ else if (t == tPCT)
+ lhs %= rhs;
+ else
+ lhs = ((lhs+rhs-1)/rhs)*rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_add_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_mult_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tPLUS || t == tMINUS) {
+ if (!db_mult_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tPLUS)
+ lhs += rhs;
+ else
+ lhs -= rhs;
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_shift_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_add_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSHIFT_L || t == tSHIFT_R) {
+ if (!db_add_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (rhs < 0) {
+ db_error("Negative shift amount\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSHIFT_L)
+ lhs <<= rhs;
+ else {
+ /* Shift right is unsigned */
+ lhs = (unsigned) lhs >> rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+int
+db_expression(valuep)
+ db_expr_t *valuep;
+{
+ return (db_shift_expr(valuep));
+}
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c
new file mode 100644
index 0000000..5ec7824
--- /dev/null
+++ b/sys/ddb/db_input.c
@@ -0,0 +1,268 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_input.c,v $
+ * Revision 1.1 1992/03/25 21:45:10 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/14 14:41:53 mrt
+ * Add input line editing.
+ * [90/11/11 dbg]
+ *
+ * Revision 2.3 91/02/05 17:06:32 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:13 mrt]
+ *
+ * Revision 2.2 90/08/27 21:51:03 dbg
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <ddb/db_output.h>
+
+/*
+ * Character input and editing.
+ */
+
+/*
+ * We don't track output position while editing input,
+ * since input always ends with a new-line. We just
+ * reset the line position at the end.
+ */
+char * db_lbuf_start; /* start of input line buffer */
+char * db_lbuf_end; /* end of input line buffer */
+char * db_lc; /* current character */
+char * db_le; /* one past last character */
+
+#define CTRL(c) ((c) & 0x1f)
+#define isspace(c) ((c) == ' ' || (c) == '\t')
+#define BLANK ' '
+#define BACKUP '\b'
+
+void
+db_putstring(s, count)
+ char *s;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(*s++);
+}
+
+void
+db_putnchars(c, count)
+ int c;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(c);
+}
+
+/*
+ * Delete N characters, forward or backward
+ */
+#define DEL_FWD 0
+#define DEL_BWD 1
+void
+db_delete(n, bwd)
+ int n;
+ int bwd;
+{
+ register char *p;
+
+ if (bwd) {
+ db_lc -= n;
+ db_putnchars(BACKUP, n);
+ }
+ for (p = db_lc; p < db_le-n; p++) {
+ *p = *(p+n);
+ cnputc(*p);
+ }
+ db_putnchars(BLANK, n);
+ db_putnchars(BACKUP, db_le - db_lc);
+ db_le -= n;
+}
+
+/* returns TRUE at end-of-line */
+int
+db_inputchar(c)
+ int c;
+{
+ switch (c) {
+ case CTRL('b'):
+ /* back up one character */
+ if (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('f'):
+ /* forward one character */
+ if (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('a'):
+ /* beginning of line */
+ while (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('e'):
+ /* end of line */
+ while (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('h'):
+ case 0177:
+ /* erase previous character */
+ if (db_lc > db_lbuf_start)
+ db_delete(1, DEL_BWD);
+ break;
+ case CTRL('d'):
+ /* erase next character */
+ if (db_lc < db_le)
+ db_delete(1, DEL_FWD);
+ break;
+ case CTRL('k'):
+ /* delete to end of line */
+ if (db_lc < db_le)
+ db_delete(db_le - db_lc, DEL_FWD);
+ break;
+ case CTRL('t'):
+ /* twiddle last 2 characters */
+ if (db_lc >= db_lbuf_start + 2) {
+ c = db_lc[-2];
+ db_lc[-2] = db_lc[-1];
+ db_lc[-1] = c;
+ cnputc(BACKUP);
+ cnputc(BACKUP);
+ cnputc(db_lc[-2]);
+ cnputc(db_lc[-1]);
+ }
+ break;
+ case CTRL('r'):
+ db_putstring("^R\n", 3);
+ if (db_le > db_lbuf_start) {
+ db_putstring(db_lbuf_start, db_le - db_lbuf_start);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ case '\n':
+ case '\r':
+ *db_le++ = c;
+ return (1);
+ default:
+ if (db_le == db_lbuf_end) {
+ cnputc('\007');
+ }
+ else if (c >= ' ' && c <= '~') {
+ register char *p;
+
+ for (p = db_le; p > db_lc; p--)
+ *p = *(p-1);
+ *db_lc++ = c;
+ db_le++;
+ cnputc(c);
+ db_putstring(db_lc, db_le - db_lc);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ }
+ return (0);
+}
+
+int
+db_readline(lstart, lsize)
+ char * lstart;
+ int lsize;
+{
+ db_force_whitespace(); /* synch output position */
+
+ db_lbuf_start = lstart;
+ db_lbuf_end = lstart + lsize;
+ db_lc = lstart;
+ db_le = lstart;
+
+ while (!db_inputchar(cngetc()))
+ continue;
+
+ db_putchar('\n'); /* synch output position */
+
+ *db_le = 0;
+ return (db_le - db_lbuf_start);
+}
+
+void
+db_check_interrupt()
+{
+ register int c;
+
+ c = cnmaygetc();
+ switch (c) {
+ case -1: /* no character */
+ return;
+
+ case CTRL('c'):
+ db_error((char *)0);
+ /*NOTREACHED*/
+
+ case CTRL('s'):
+ do {
+ c = cnmaygetc();
+ if (c == CTRL('c'))
+ db_error((char *)0);
+ } while (c != CTRL('q'));
+ break;
+
+ default:
+ /* drop on floor */
+ break;
+ }
+}
+
+cnmaygetc ()
+{
+ return (-1);
+}
+
+/* called from kdb_trap in db_interface.c */
+cnpollc (flag)
+{
+}
diff --git a/sys/ddb/db_lex.c b/sys/ddb/db_lex.c
new file mode 100644
index 0000000..dcfd900
--- /dev/null
+++ b/sys/ddb/db_lex.c
@@ -0,0 +1,295 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_lex.c,v $
+ * Revision 1.1 1992/03/25 21:45:13 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:36 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:20 mrt]
+ *
+ * Revision 2.2 90/08/27 21:51:10 dbg
+ * Add 'dotdot' token.
+ * [90/08/22 dbg]
+ *
+ * Allow backslash to quote any character into an identifier.
+ * Allow colon in identifier for symbol table qualification.
+ * [90/08/16 dbg]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Lexical analyzer.
+ */
+#include <ddb/db_lex.h>
+
+char db_line[120];
+char * db_lp, *db_endlp;
+
+int
+db_read_line()
+{
+ int i;
+
+ i = db_readline(db_line, sizeof(db_line));
+ if (i == 0)
+ return (0); /* EOI */
+ db_lp = db_line;
+ db_endlp = db_lp + i;
+ return (i);
+}
+
+void
+db_flush_line()
+{
+ db_lp = db_line;
+ db_endlp = db_line;
+}
+
+int db_look_char = 0;
+
+int
+db_read_char()
+{
+ int c;
+
+ if (db_look_char != 0) {
+ c = db_look_char;
+ db_look_char = 0;
+ }
+ else if (db_lp >= db_endlp)
+ c = -1;
+ else
+ c = *db_lp++;
+ return (c);
+}
+
+void
+db_unread_char(c)
+{
+ db_look_char = c;
+}
+
+int db_look_token = 0;
+
+void
+db_unread_token(t)
+ int t;
+{
+ db_look_token = t;
+}
+
+int
+db_read_token()
+{
+ int t;
+
+ if (db_look_token) {
+ t = db_look_token;
+ db_look_token = 0;
+ }
+ else
+ t = db_lex();
+ return (t);
+}
+
+int db_tok_number;
+char db_tok_string[TOK_STRING_SIZE];
+
+int db_radix = 16;
+
+void
+db_flush_lex()
+{
+ db_flush_line();
+ db_look_char = 0;
+ db_look_token = 0;
+}
+
+int
+db_lex()
+{
+ int c;
+
+ c = db_read_char();
+ while (c <= ' ' || c > '~') {
+ if (c == '\n' || c == -1)
+ return (tEOL);
+ c = db_read_char();
+ }
+
+ if (c >= '0' && c <= '9') {
+ /* number */
+ int r, digit;
+
+ if (c > '0')
+ r = db_radix;
+ else {
+ c = db_read_char();
+ if (c == 'O' || c == 'o')
+ r = 8;
+ else if (c == 'T' || c == 't')
+ r = 10;
+ else if (c == 'X' || c == 'x')
+ r = 16;
+ else {
+ r = db_radix;
+ db_unread_char(c);
+ }
+ c = db_read_char();
+ }
+ db_tok_number = 0;
+ for (;;) {
+ if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
+ digit = c - '0';
+ else if (r == 16 && ((c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f'))) {
+ if (c >= 'a')
+ digit = c - 'a' + 10;
+ else if (c >= 'A')
+ digit = c - 'A' + 10;
+ }
+ else
+ break;
+ db_tok_number = db_tok_number * r + digit;
+ c = db_read_char();
+ }
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '_'))
+ {
+ db_error("Bad character in number\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ db_unread_char(c);
+ return (tNUMBER);
+ }
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c == '_' || c == '\\')
+ {
+ /* string */
+ char *cp;
+
+ cp = db_tok_string;
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad escape\n");
+ }
+ *cp++ = c;
+ while (1) {
+ c = db_read_char();
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '\\' || c == ':')
+ {
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad escape\n");
+ }
+ *cp++ = c;
+ if (cp == db_tok_string+sizeof(db_tok_string)) {
+ db_error("String too long\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ continue;
+ }
+ else {
+ *cp = '\0';
+ break;
+ }
+ }
+ db_unread_char(c);
+ return (tIDENT);
+ }
+
+ switch (c) {
+ case '+':
+ return (tPLUS);
+ case '-':
+ return (tMINUS);
+ case '.':
+ c = db_read_char();
+ if (c == '.')
+ return (tDOTDOT);
+ db_unread_char(c);
+ return (tDOT);
+ case '*':
+ return (tSTAR);
+ case '/':
+ return (tSLASH);
+ case '=':
+ return (tEQ);
+ case '%':
+ return (tPCT);
+ case '#':
+ return (tHASH);
+ case '(':
+ return (tLPAREN);
+ case ')':
+ return (tRPAREN);
+ case ',':
+ return (tCOMMA);
+ case '"':
+ return (tDITTO);
+ case '$':
+ return (tDOLLAR);
+ case '!':
+ return (tEXCL);
+ case '<':
+ c = db_read_char();
+ if (c == '<')
+ return (tSHIFT_L);
+ db_unread_char(c);
+ break;
+ case '>':
+ c = db_read_char();
+ if (c == '>')
+ return (tSHIFT_R);
+ db_unread_char(c);
+ break;
+ case -1:
+ return (tEOF);
+ }
+ db_printf("Bad character\n");
+ db_flush_lex();
+ return (tEOF);
+}
diff --git a/sys/ddb/db_lex.h b/sys/ddb/db_lex.h
new file mode 100644
index 0000000..56c5569
--- /dev/null
+++ b/sys/ddb/db_lex.h
@@ -0,0 +1,89 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_lex.h,v $
+ * Revision 1.1 1992/03/25 21:45:15 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:41 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:28 mrt]
+ *
+ * Revision 2.2 90/08/27 21:51:16 dbg
+ * Add 'dotdot' token.
+ * [90/08/22 dbg]
+ * Export db_flush_lex.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Lexical analyzer.
+ */
+extern int db_read_line();
+extern void db_flush_line();
+extern int db_read_char();
+extern void db_unread_char(/* char c */);
+extern int db_read_token();
+extern void db_unread_token(/* int t */);
+extern void db_flush_lex();
+
+extern int db_tok_number;
+#define TOK_STRING_SIZE 120
+extern char db_tok_string[TOK_STRING_SIZE];
+extern int db_radix;
+
+#define tEOF (-1)
+#define tEOL 1
+#define tNUMBER 2
+#define tIDENT 3
+#define tPLUS 4
+#define tMINUS 5
+#define tDOT 6
+#define tSTAR 7
+#define tSLASH 8
+#define tEQ 9
+#define tLPAREN 10
+#define tRPAREN 11
+#define tPCT 12
+#define tHASH 13
+#define tCOMMA 14
+#define tDITTO 15
+#define tDOLLAR 16
+#define tEXCL 17
+#define tSHIFT_L 18
+#define tSHIFT_R 19
+#define tDOTDOT 20
+
+
+
+
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
new file mode 100644
index 0000000..fc8fca7
--- /dev/null
+++ b/sys/ddb/db_output.c
@@ -0,0 +1,389 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 4 00083
+ * -------------------- ----- ----------------------
+ *
+ * 14 Mar 93 Chris G. Demetriou Fixed so that tab is not output,
+ * use spaces instead.
+ */
+/*
+ * HISTORY
+ * $Log: db_output.c,v $
+ * Revision 1.1 1992/03/25 21:45:18 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:45 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:41 mrt]
+ *
+ * Revision 2.2 90/08/27 21:51:25 dbg
+ * Put extra features of db_doprnt in _doprnt.
+ * [90/08/20 dbg]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Printf and character output for debugger.
+ */
+
+#include "param.h"
+#include <machine/stdarg.h>
+
+/*
+ * Character output - tracks position in line.
+ * To do this correctly, we should know how wide
+ * the output device is - then we could zero
+ * the line position when the output device wraps
+ * around to the start of the next line.
+ *
+ * Instead, we count the number of spaces printed
+ * since the last printing character so that we
+ * don't print trailing spaces. This avoids most
+ * of the wraparounds.
+ */
+int db_output_position = 0; /* output column */
+int db_last_non_space = 0; /* last non-space character */
+int db_tab_stop_width = 8; /* how wide are tab stops? */
+#define NEXT_TAB(i) \
+ ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
+int db_max_width = 80; /* output line width */
+
+extern void db_check_interrupt();
+
+/*
+ * Force pending whitespace.
+ */
+void
+db_force_whitespace()
+{
+ register int last_print, next_tab;
+
+ last_print = db_last_non_space;
+ while (last_print < db_output_position) {
+ next_tab = NEXT_TAB(last_print);
+ if (next_tab <= db_output_position) {
+ while (last_print < next_tab) { /* DON'T send a tab!!! */
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ else {
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ db_last_non_space = db_output_position;
+}
+
+/*
+ * Output character. Buffer whitespace.
+ */
+db_putchar(c)
+ int c; /* character to output */
+{
+ if (c > ' ' && c <= '~') {
+ /*
+ * Printing character.
+ * If we have spaces to print, print them first.
+ * Use tabs if possible.
+ */
+ db_force_whitespace();
+ cnputc(c);
+ db_output_position++;
+ db_last_non_space = db_output_position;
+ }
+ else if (c == '\n') {
+ /* Return */
+ cnputc(c);
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_check_interrupt();
+ }
+ else if (c == '\t') {
+ /* assume tabs every 8 positions */
+ db_output_position = NEXT_TAB(db_output_position);
+ }
+ else if (c == ' ') {
+ /* space */
+ db_output_position++;
+ }
+ else if (c == '\007') {
+ /* bell */
+ cnputc(c);
+ }
+ /* other characters are assumed non-printing */
+}
+
+/*
+ * Return output position
+ */
+int
+db_print_position()
+{
+ return (db_output_position);
+}
+
+/*
+ * End line if too long.
+ */
+void
+db_end_line()
+{
+ if (db_output_position >= db_max_width)
+ db_printf("\n");
+}
+
+/*
+ * Printing
+ */
+extern int db_radix;
+
+/*VARARGS1*/
+db_printf(char *fmt, ...)
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/* alternate name */
+
+/*VARARGS1*/
+kdbprintf(char *fmt, ...)
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/*
+ * Put a number (base <= 16) in a buffer in reverse order; return an
+ * optional length and a pointer to the NULL terminated (preceded?)
+ * buffer.
+ */
+static char *
+db_ksprintn(ul, base, lenp)
+ register u_long ul;
+ register int base, *lenp;
+{ /* A long in base 8, plus NULL. */
+ static char buf[sizeof(long) * NBBY / 3 + 2];
+ register char *p;
+
+ p = buf;
+ do {
+ *++p = "0123456789abcdef"[ul % base];
+ } while (ul /= base);
+ if (lenp)
+ *lenp = p - buf;
+ return (p);
+}
+
+db_printf_guts(fmt, ap)
+ register const char *fmt;
+ va_list ap;
+{
+ register char *p;
+ register int ch, n;
+ u_long ul;
+ int base, lflag, tmp, width;
+ char padc;
+ int ladjust;
+ int sharpflag;
+ int neg;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = *(u_char *)fmt++) != '%') {
+ if (ch == '\0')
+ return;
+ db_putchar(ch);
+ }
+ lflag = 0;
+ ladjust = 0;
+ sharpflag = 0;
+ neg = 0;
+reswitch: switch (ch = *(u_char *)fmt++) {
+ case '0':
+ padc = '0';
+ goto reswitch;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (width = 0;; ++fmt) {
+ width = width * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ goto reswitch;
+ case 'l':
+ lflag = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case 'b':
+ ul = va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
+ db_putchar(ch);
+
+ if (!ul)
+ break;
+
+ for (tmp = 0; n = *p++;) {
+ if (ul & (1 << (n - 1))) {
+ db_putchar(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ db_putchar(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p);
+ }
+ if (tmp)
+ db_putchar('>');
+ break;
+ case '*':
+ width = va_arg (ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ goto reswitch;
+ case 'c':
+ db_putchar(va_arg(ap, int));
+ break;
+ case 's':
+ p = va_arg(ap, char *);
+ width -= strlen (p);
+ if (!ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ while (ch = *p++)
+ db_putchar(ch);
+ if (ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ break;
+ case 'r':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'n':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'd':
+ ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 10;
+ goto number;
+ case 'o':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 8;
+ goto number;
+ case 'u':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 10;
+ goto number;
+ case 'z':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 16;
+ goto number;
+ case 'x':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 16;
+number: p = (char *)db_ksprintn(ul, base, &tmp);
+ if (sharpflag && ul != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+ if (neg)
+ db_putchar ('-');
+ if (sharpflag && ul != 0) {
+ if (base == 8) {
+ db_putchar ('0');
+ } else if (base == 16) {
+ db_putchar ('0');
+ db_putchar ('x');
+ }
+ }
+ if (ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+
+ while (ch = *p--)
+ db_putchar(ch);
+ break;
+ default:
+ db_putchar('%');
+ if (lflag)
+ db_putchar('l');
+ /* FALLTHROUGH */
+ case '%':
+ db_putchar(ch);
+ }
+ }
+}
+
diff --git a/sys/ddb/db_output.h b/sys/ddb/db_output.h
new file mode 100644
index 0000000..3ad599d
--- /dev/null
+++ b/sys/ddb/db_output.h
@@ -0,0 +1,53 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_output.h,v $
+ * Revision 1.1 1992/03/25 21:45:20 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:06:49 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:48 mrt]
+ *
+ * Revision 2.2 90/08/27 21:51:32 dbg
+ * Created.
+ * [90/08/07 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * Printing routines for kernel debugger.
+ */
+
+extern void db_force_whitespace();
+extern int db_print_position();
+extern void db_end_line();
+extern int db_printf();
diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c
new file mode 100644
index 0000000..48eef38
--- /dev/null
+++ b/sys/ddb/db_print.c
@@ -0,0 +1,104 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_print.c,v $
+ * Revision 1.1 1992/03/25 21:45:22 pace
+ * Initial revision
+ *
+ * Revision 2.5 91/02/05 17:06:53 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:18:56 mrt]
+ *
+ * Revision 2.4 90/10/25 14:43:54 rwd
+ * Changed db_show_regs to print unsigned.
+ * [90/10/19 rpd]
+ * Generalized the watchpoint support.
+ * [90/10/16 rwd]
+ *
+ * Revision 2.3 90/09/09 23:19:52 rpd
+ * Avoid totally incorrect guesses of symbol names for small values.
+ * [90/08/30 17:39:08 af]
+ *
+ * Revision 2.2 90/08/27 21:51:49 dbg
+ * Insist that 'show thread' be called with an explicit address.
+ * [90/08/22 dbg]
+ *
+ * Fix type for db_maxoff.
+ * [90/08/20 dbg]
+ *
+ * Do not dereference the "valuep" field of a variable directly,
+ * call the new db_read/write_variable functions instead.
+ * Reflected changes in symbol lookup functions.
+ * [90/08/20 af]
+ * Reduce lint.
+ * [90/08/10 14:33:44 dbg]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Miscellaneous printing.
+ */
+#include "param.h"
+#include "proc.h"
+
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+
+extern unsigned int db_maxoff;
+
+void
+db_show_regs()
+{
+ int (*func)();
+ register struct db_variable *regp;
+ db_expr_t value, offset;
+ char * name;
+
+ for (regp = db_regs; regp < db_eregs; regp++) {
+ db_read_variable(regp, &value);
+ db_printf("%-12s%#10n", regp->name, value);
+ db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
+ if (name != 0 && offset <= db_maxoff && offset != value) {
+ db_printf("\t%s", name);
+ if (offset != 0)
+ db_printf("+%#r", offset);
+ }
+ db_printf("\n");
+ }
+ db_print_loc_and_inst(PC_REGS(DDB_REGS));
+}
+
diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c
new file mode 100644
index 0000000..b8e33aa
--- /dev/null
+++ b/sys/ddb/db_run.c
@@ -0,0 +1,426 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_run.c,v $
+ * Revision 1.1 1992/03/25 21:45:24 pace
+ * Initial revision
+ *
+ * Revision 2.5 91/02/05 17:06:58 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:05 mrt]
+ *
+ * Revision 2.4 91/01/08 15:09:10 rpd
+ * Fixed bug in db_restart_at_pc.
+ * [90/12/07 rpd]
+ * Added STEP_COUNT and count option to db_continue_cmd.
+ * Changed db_stop_at_pc to return (modified) is_breakpoint.
+ * Fixed db_stop_at_pc to print newlines in the right places.
+ * [90/11/27 rpd]
+ *
+ * Revision 2.3 90/10/25 14:43:59 rwd
+ * Changed db_find_breakpoint to db_find_breakpoint_here.
+ * [90/10/18 rpd]
+ *
+ * Fixed db_set_single_step to pass regs to branch_taken.
+ * Added watchpoint argument to db_restart_at_pc.
+ * [90/10/17 rpd]
+ * Generalized the watchpoint support.
+ * [90/10/16 rwd]
+ * Added watchpoint support.
+ * [90/10/16 rpd]
+ *
+ * Revision 2.2 90/08/27 21:51:59 dbg
+ * Fixed names for single-step functions.
+ * [90/08/20 af]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Commands to run process.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+
+int db_run_mode;
+#define STEP_NONE 0
+#define STEP_ONCE 1
+#define STEP_RETURN 2
+#define STEP_CALLT 3
+#define STEP_CONTINUE 4
+#define STEP_INVISIBLE 5
+#define STEP_COUNT 6
+
+boolean_t db_sstep_print;
+int db_loop_count;
+int db_call_depth;
+
+int db_inst_count;
+int db_load_count;
+int db_store_count;
+
+#ifndef db_set_single_step
+void db_set_single_step(/* db_regs_t *regs */); /* forward */
+#endif
+#ifndef db_clear_single_step
+void db_clear_single_step(/* db_regs_t *regs */);
+#endif
+
+boolean_t
+db_stop_at_pc(is_breakpoint)
+ boolean_t *is_breakpoint;
+{
+ register db_addr_t pc;
+ register db_breakpoint_t bkpt;
+
+ db_clear_single_step(DDB_REGS);
+ db_clear_breakpoints();
+ db_clear_watchpoints();
+ pc = PC_REGS(DDB_REGS);
+
+#ifdef FIXUP_PC_AFTER_BREAK
+ if (*is_breakpoint) {
+ /*
+ * Breakpoint trap. Fix up the PC if the
+ * machine requires it.
+ */
+ FIXUP_PC_AFTER_BREAK
+ pc = PC_REGS(DDB_REGS);
+ }
+#endif
+
+ /*
+ * Now check for a breakpoint at this address.
+ */
+ bkpt = db_find_breakpoint_here(pc);
+ if (bkpt) {
+ if (--bkpt->count == 0) {
+ bkpt->count = bkpt->init_count;
+ *is_breakpoint = TRUE;
+ return (TRUE); /* stop here */
+ }
+ } else if (*is_breakpoint) {
+ ddb_regs.tf_eip += 1;
+ }
+
+ *is_breakpoint = FALSE;
+
+ if (db_run_mode == STEP_INVISIBLE) {
+ db_run_mode = STEP_CONTINUE;
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_COUNT) {
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_ONCE) {
+ if (--db_loop_count > 0) {
+ if (db_sstep_print) {
+ db_printf("\t\t");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_RETURN) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until matching return */
+
+ if (!inst_trap_return(ins) &&
+ (!inst_return(ins) || --db_call_depth != 0)) {
+ if (db_sstep_print) {
+ if (inst_call(ins) || inst_return(ins)) {
+ register int i;
+
+ db_printf("[after %6d] ", db_inst_count);
+ for (i = db_call_depth; --i > 0; )
+ db_printf(" ");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ }
+ if (inst_call(ins))
+ db_call_depth++;
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_CALLT) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until call or return */
+
+ if (!inst_call(ins) &&
+ !inst_return(ins) &&
+ !inst_trap_return(ins)) {
+ return (FALSE); /* continue */
+ }
+ }
+ db_run_mode = STEP_NONE;
+ return (TRUE);
+}
+
+void
+db_restart_at_pc(watchpt)
+ boolean_t watchpt;
+{
+ register db_addr_t pc = PC_REGS(DDB_REGS);
+
+ if ((db_run_mode == STEP_COUNT) ||
+ (db_run_mode == STEP_RETURN) ||
+ (db_run_mode == STEP_CALLT)) {
+ db_expr_t ins;
+
+ /*
+ * We are about to execute this instruction,
+ * so count it now.
+ */
+
+ ins = db_get_value(pc, sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+#ifdef SOFTWARE_SSTEP
+ /* XXX works on mips, but... */
+ if (inst_branch(ins) || inst_call(ins)) {
+ ins = db_get_value(next_instr_address(pc,1),
+ sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+ }
+#endif SOFTWARE_SSTEP
+ }
+
+ if (db_run_mode == STEP_CONTINUE) {
+ if (watchpt || db_find_breakpoint_here(pc)) {
+ /*
+ * Step over breakpoint/watchpoint.
+ */
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(DDB_REGS);
+ } else {
+ db_set_breakpoints();
+ db_set_watchpoints();
+ }
+ } else {
+ db_set_single_step(DDB_REGS);
+ }
+}
+
+void
+db_single_step(regs)
+ db_regs_t *regs;
+{
+ if (db_run_mode == STEP_CONTINUE) {
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(regs);
+ }
+}
+
+#ifdef SOFTWARE_SSTEP
+/*
+ * Software implementation of single-stepping.
+ * If your machine does not have a trace mode
+ * similar to the vax or sun ones you can use
+ * this implementation, done for the mips.
+ * Just define the above conditional and provide
+ * the functions/macros defined below.
+ *
+ * extern boolean_t
+ * inst_branch(), returns true if the instruction might branch
+ * extern unsigned
+ * branch_taken(), return the address the instruction might
+ * branch to
+ * db_getreg_val(); return the value of a user register,
+ * as indicated in the hardware instruction
+ * encoding, e.g. 8 for r8
+ *
+ * next_instr_address(pc,bd) returns the address of the first
+ * instruction following the one at "pc",
+ * which is either in the taken path of
+ * the branch (bd==1) or not. This is
+ * for machines (mips) with branch delays.
+ *
+ * A single-step may involve at most 2 breakpoints -
+ * one for branch-not-taken and one for branch taken.
+ * If one of these addresses does not already have a breakpoint,
+ * we allocate a breakpoint and save it here.
+ * These breakpoints are deleted on return.
+ */
+db_breakpoint_t db_not_taken_bkpt = 0;
+db_breakpoint_t db_taken_bkpt = 0;
+
+void
+db_set_single_step(regs)
+ register db_regs_t *regs;
+{
+ db_addr_t pc = PC_REGS(regs);
+ register unsigned inst, brpc;
+
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ */
+ inst = db_get_value(pc, sizeof(int), FALSE);
+ if (inst_branch(inst) || inst_call(inst)) {
+ extern unsigned getreg_val();
+
+ brpc = branch_taken(inst, pc, getreg_val, regs);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(brpc);
+ }
+ pc = next_instr_address(pc,1);
+ }
+ pc = next_instr_address(pc,0);
+ db_not_taken_bkpt = db_set_temp_breakpoint(pc);
+}
+
+void
+db_clear_single_step(regs)
+ db_regs_t *regs;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_taken_bkpt);
+ db_taken_bkpt = 0;
+ }
+ if (db_not_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
+ }
+}
+
+#endif SOFTWARE_SSTEP
+
+extern int db_cmd_loop_done;
+
+/* single-step */
+/*ARGSUSED*/
+void
+db_single_step_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (count == -1)
+ count = 1;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_ONCE;
+ db_loop_count = count;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* trace and print until call/return */
+/*ARGSUSED*/
+void
+db_trace_until_call_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_CALLT;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/*ARGSUSED*/
+void
+db_trace_until_matching_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_RETURN;
+ db_call_depth = 1;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* continue */
+/*ARGSUSED*/
+void
+db_continue_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] == 'c')
+ db_run_mode = STEP_COUNT;
+ else
+ db_run_mode = STEP_CONTINUE;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
diff --git a/sys/ddb/db_sym.c b/sys/ddb/db_sym.c
new file mode 100644
index 0000000..0517c68
--- /dev/null
+++ b/sys/ddb/db_sym.c
@@ -0,0 +1,360 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_sym.c,v $
+ * Revision 1.1 1992/03/25 21:45:27 pace
+ * Initial revision
+ *
+ * Revision 2.5 91/02/05 17:07:07 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:17 mrt]
+ *
+ * Revision 2.4 90/10/25 14:44:05 rwd
+ * Changed db_printsym to print unsigned.
+ * [90/10/19 rpd]
+ *
+ * Revision 2.3 90/09/09 23:19:56 rpd
+ * Avoid totally incorrect guesses of symbol names for small values.
+ * [90/08/30 17:39:48 af]
+ *
+ * Revision 2.2 90/08/27 21:52:18 dbg
+ * Removed nlist.h. Fixed some type declarations.
+ * Qualifier character is ':'.
+ * [90/08/20 dbg]
+ * Modularized symtab info into a new db_symtab_t type.
+ * Modified db_add_symbol_table and others accordingly.
+ * Defined db_sym_t, a new (opaque) type used to represent
+ * symbols. This should support all sort of future symtable
+ * formats. Functions like db_qualify take a db_sym_t now.
+ * New db_symbol_values() function to explode the content
+ * of a db_sym_t.
+ * db_search_symbol() replaces db_find_sym_and_offset(), which is
+ * now a macro defined in our (new) header file. This new
+ * function accepts more restrictive searches, which are
+ * entirely delegated to the symtab-specific code.
+ * Accordingly, db_printsym() accepts a strategy parameter.
+ * New db_line_at_pc() function.
+ * Renamed misleading db_eqsym into db_eqname.
+ * [90/08/20 10:47:06 af]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ * Revision 2.1 90/07/26 16:43:52 dbg
+ * Created.
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+
+/*
+ * We import from the symbol-table dependent routines:
+ */
+extern db_sym_t X_db_lookup();
+extern db_sym_t X_db_search_symbol();
+extern boolean_t X_db_line_at_pc();
+extern void X_db_symbol_values();
+
+/*
+ * Multiple symbol tables
+ */
+#define MAXNOSYMTABS 3 /* mach, ux, emulator */
+
+db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
+int db_nsymtab = 0;
+
+db_symtab_t *db_last_symtab;
+
+db_sym_t db_lookup(); /* forward */
+
+/*
+ * Add symbol table, with given name, to list of symbol tables.
+ */
+void
+db_add_symbol_table(start, end, name, ref)
+ char *start;
+ char *end;
+ char *name;
+ char *ref;
+{
+ if (db_nsymtab >= MAXNOSYMTABS) {
+ printf ("No slots left for %s symbol table", name);
+ panic ("db_sym.c: db_add_symbol_table");
+ }
+
+ db_symtabs[db_nsymtab].start = start;
+ db_symtabs[db_nsymtab].end = end;
+ db_symtabs[db_nsymtab].name = name;
+ db_symtabs[db_nsymtab].private = ref;
+ db_nsymtab++;
+}
+
+/*
+ * db_qualify("vm_map", "ux") returns "unix:vm_map".
+ *
+ * Note: return value points to static data whose content is
+ * overwritten by each call... but in practice this seems okay.
+ */
+static char *
+db_qualify(sym, symtabname)
+ db_sym_t sym;
+ register char *symtabname;
+{
+ char *symname;
+ static char tmp[256];
+ register char *s;
+
+ db_symbol_values(sym, &symname, 0);
+ s = tmp;
+ while (*s++ = *symtabname++) {
+ }
+ s[-1] = ':';
+ while (*s++ = *symname++) {
+ }
+ return tmp;
+}
+
+
+boolean_t
+db_eqname(src, dst, c)
+ char *src;
+ char *dst;
+ char c;
+{
+ if (!strcmp(src, dst))
+ return (TRUE);
+ if (src[0] == c)
+ return (!strcmp(src+1,dst));
+ return (FALSE);
+}
+
+boolean_t
+db_value_of_name(name, valuep)
+ char *name;
+ db_expr_t *valuep;
+{
+ db_sym_t sym;
+
+ sym = db_lookup(name);
+ if (sym == DB_SYM_NULL)
+ return (FALSE);
+ db_symbol_values(sym, &name, valuep);
+ return (TRUE);
+}
+
+
+/*
+ * Lookup a symbol.
+ * If the symbol has a qualifier (e.g., ux:vm_map),
+ * then only the specified symbol table will be searched;
+ * otherwise, all symbol tables will be searched.
+ */
+db_sym_t
+db_lookup(symstr)
+ char *symstr;
+{
+ db_sym_t sp;
+ register int i;
+ int symtab_start = 0;
+ int symtab_end = db_nsymtab;
+ register char *cp;
+
+ /*
+ * Look for, remove, and remember any symbol table specifier.
+ */
+ for (cp = symstr; *cp; cp++) {
+ if (*cp == ':') {
+ *cp = '\0';
+ for (i = 0; i < db_nsymtab; i++) {
+ if (! strcmp(symstr, db_symtabs[i].name)) {
+ symtab_start = i;
+ symtab_end = i + 1;
+ break;
+ }
+ }
+ *cp = ':';
+ if (i == db_nsymtab) {
+ db_error("invalid symbol table name");
+ }
+ symstr = cp+1;
+ }
+ }
+
+ /*
+ * Look in the specified set of symbol tables.
+ * Return on first match.
+ */
+ for (i = symtab_start; i < symtab_end; i++) {
+ if (sp = X_db_lookup(&db_symtabs[i], symstr)) {
+ db_last_symtab = &db_symtabs[i];
+ return sp;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Does this symbol name appear in more than one symbol table?
+ * Used by db_symbol_values to decide whether to qualify a symbol.
+ */
+boolean_t db_qualify_ambiguous_names = FALSE;
+
+boolean_t
+db_symbol_is_ambiguous(sym)
+ db_sym_t sym;
+{
+ char *sym_name;
+ register int i;
+ register
+ boolean_t found_once = FALSE;
+
+ if (!db_qualify_ambiguous_names)
+ return FALSE;
+
+ db_symbol_values(sym, &sym_name, 0);
+ for (i = 0; i < db_nsymtab; i++) {
+ if (X_db_lookup(&db_symtabs[i], sym_name)) {
+ if (found_once)
+ return TRUE;
+ found_once = TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Find the closest symbol to val, and return its name
+ * and the difference between val and the symbol found.
+ */
+db_sym_t
+db_search_symbol( val, strategy, offp)
+ register db_addr_t val;
+ db_strategy_t strategy;
+ db_expr_t *offp;
+{
+ register
+ unsigned int diff;
+ unsigned int newdiff;
+ register int i;
+ db_sym_t ret = DB_SYM_NULL, sym;
+
+ newdiff = diff = ~0;
+ db_last_symtab = 0;
+ for (i = 0; i < db_nsymtab; i++) {
+ sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
+ if (newdiff < diff) {
+ db_last_symtab = &db_symtabs[i];
+ diff = newdiff;
+ ret = sym;
+ }
+ }
+ *offp = diff;
+ return ret;
+}
+
+/*
+ * Return name and value of a symbol
+ */
+void
+db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ db_expr_t value;
+
+ if (sym == DB_SYM_NULL) {
+ *namep = 0;
+ return;
+ }
+
+ X_db_symbol_values(sym, namep, &value);
+
+ if (db_symbol_is_ambiguous(sym))
+ *namep = db_qualify(sym, db_last_symtab->name);
+ if (valuep)
+ *valuep = value;
+}
+
+
+/*
+ * Print a the closest symbol to value
+ *
+ * After matching the symbol according to the given strategy
+ * we print it in the name+offset format, provided the symbol's
+ * value is close enough (eg smaller than db_maxoff).
+ * We also attempt to print [filename:linenum] when applicable
+ * (eg for procedure names).
+ *
+ * If we could not find a reasonable name+offset representation,
+ * then we just print the value in hex. Small values might get
+ * bogus symbol associations, e.g. 3 might get some absolute
+ * value like _INCLUDE_VERSION or something, therefore we do
+ * not accept symbols whose value is zero (and use plain hex).
+ */
+
+unsigned int db_maxoff = 0x10000000;
+
+void
+db_printsym(off, strategy)
+ db_expr_t off;
+ db_strategy_t strategy;
+{
+ db_expr_t d;
+ char *filename;
+ char *name;
+ db_expr_t value;
+ int linenum;
+ db_sym_t cursym;
+
+ cursym = db_search_symbol(off, strategy, &d);
+ db_symbol_values(cursym, &name, &value);
+ if (name == 0 || d >= db_maxoff || value == 0) {
+ db_printf("%#n", off);
+ return;
+ }
+ db_printf("%s", name);
+ if (d)
+ db_printf("+%#r", d);
+ if (strategy == DB_STGY_PROC) {
+ if (db_line_at_pc(cursym, &filename, &linenum, off))
+ db_printf(" [%s:%d]", filename, linenum);
+ }
+}
+
+
+boolean_t
+db_line_at_pc( sym, filename, linenum, pc)
+{
+ return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
+}
diff --git a/sys/ddb/db_sym.h b/sys/ddb/db_sym.h
new file mode 100644
index 0000000..663f1cd
--- /dev/null
+++ b/sys/ddb/db_sym.h
@@ -0,0 +1,114 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_sym.h,v $
+ * Revision 1.1 1992/03/25 21:45:29 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:07:12 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:27 mrt]
+ *
+ * Revision 2.2 90/08/27 21:52:39 dbg
+ * Changed type of db_sym_t to char * - it's a better type for an
+ * opaque pointer.
+ * [90/08/22 dbg]
+ *
+ * Created.
+ * [90/08/19 af]
+ *
+ */
+/*
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * This module can handle multiple symbol tables
+ */
+typedef struct {
+ char *name; /* symtab name */
+ char *start; /* symtab location */
+ char *end;
+ char *private; /* optional machdep pointer */
+} db_symtab_t;
+
+extern db_symtab_t *db_last_symtab; /* where last symbol was found */
+
+/*
+ * Symbol representation is specific to the symtab style:
+ * BSD compilers use dbx' nlist, other compilers might use
+ * a different one
+ */
+typedef char * db_sym_t; /* opaque handle on symbols */
+#define DB_SYM_NULL ((db_sym_t)0)
+
+/*
+ * Non-stripped symbol tables will have duplicates, for instance
+ * the same string could match a parameter name, a local var, a
+ * global var, etc.
+ * We are most concern with the following matches.
+ */
+typedef int db_strategy_t; /* search strategy */
+
+#define DB_STGY_ANY 0 /* anything goes */
+#define DB_STGY_XTRN 1 /* only external symbols */
+#define DB_STGY_PROC 2 /* only procedures */
+
+extern boolean_t db_qualify_ambiguous_names;
+ /* if TRUE, check across symbol tables
+ * for multiple occurrences of a name.
+ * Might slow down quite a bit */
+
+/*
+ * Functions exported by the symtable module
+ */
+extern void db_add_symbol_table();
+ /* extend the list of symbol tables */
+
+extern int db_value_of_name(/* char*, db_expr_t* */);
+ /* find symbol value given name */
+
+extern db_sym_t db_search_symbol(/* db_expr_t, db_strategy_t, int* */);
+ /* find symbol given value */
+
+extern void db_symbol_values(/* db_sym_t, char**, db_expr_t* */);
+ /* return name and value of symbol */
+
+#define db_find_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_ANY,offp),namep,0)
+ /* find name&value given approx val */
+
+#define db_find_xtrn_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_XTRN,offp),namep,0)
+ /* ditto, but no locals */
+
+extern int db_eqname(/* char*, char*, char */);
+ /* strcmp, modulo leading char */
+
+extern void db_printsym(/* db_expr_t, db_strategy_t */);
+ /* print closest symbol to a value */
diff --git a/sys/ddb/db_trap.c b/sys/ddb/db_trap.c
new file mode 100644
index 0000000..099fab1
--- /dev/null
+++ b/sys/ddb/db_trap.c
@@ -0,0 +1,106 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_trap.c,v $
+ * Revision 1.1 1992/03/25 21:45:31 pace
+ * Initial revision
+ *
+ * Revision 2.5 91/02/05 17:07:16 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:35 mrt]
+ *
+ * Revision 2.4 91/01/08 15:09:17 rpd
+ * Changed db_stop_at_pc's arguments.
+ * Print db_inst_count, db_load_count, db_store_count.
+ * [90/11/27 rpd]
+ *
+ * Revision 2.3 90/10/25 14:44:11 rwd
+ * From rpd.
+ * [90/10/19 17:03:17 rwd]
+ *
+ * Generalized the watchpoint support.
+ * [90/10/16 rwd]
+ * Added watchpoint support.
+ * [90/10/16 rpd]
+ *
+ * Revision 2.2 90/08/27 21:52:52 dbg
+ * Assign to db_dot before calling the print function.
+ * [90/08/20 af]
+ * Reduce lint.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Trap entry point to kernel debugger.
+ */
+#include "param.h"
+#include "proc.h"
+#include <ddb/db_command.h>
+#include <ddb/db_break.h>
+
+extern void db_restart_at_pc();
+extern boolean_t db_stop_at_pc();
+
+extern int db_inst_count;
+extern int db_load_count;
+extern int db_store_count;
+
+db_trap(type, code)
+ int type, code;
+{
+ boolean_t bkpt;
+ boolean_t watchpt;
+
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+
+ if (db_stop_at_pc(&bkpt)) {
+ if (db_inst_count) {
+ db_printf("After %d instructions (%d loads, %d stores),\n",
+ db_inst_count, db_load_count, db_store_count);
+ }
+ if (bkpt)
+ db_printf("Breakpoint at\t");
+ else if (watchpt)
+ db_printf("Watchpoint at\t");
+ else
+ db_printf("Stopped at\t");
+ db_dot = PC_REGS(DDB_REGS);
+ db_print_loc_and_inst(db_dot);
+
+ db_command_loop();
+ }
+
+ db_restart_at_pc(watchpt);
+}
diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c
new file mode 100644
index 0000000..ed9512d
--- /dev/null
+++ b/sys/ddb/db_variables.c
@@ -0,0 +1,186 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_variables.c,v $
+ * Revision 1.1 1992/03/25 21:45:33 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:07:19 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:46 mrt]
+ *
+ * Revision 2.2 90/08/27 21:53:24 dbg
+ * New db_read/write_variable functions. Should be used instead
+ * of dereferencing valuep directly, which might not be a true
+ * pointer if there is an fcn() access function.
+ * [90/08/20 af]
+ *
+ * Fix declarations.
+ * Check for trailing garbage after last expression on command line.
+ * [90/08/10 14:34:54 dbg]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+
+extern unsigned int db_maxoff;
+
+extern int db_radix;
+extern int db_max_width;
+extern int db_tab_stop_width;
+
+struct db_variable db_vars[] = {
+ { "radix", &db_radix, FCN_NULL },
+ { "maxoff", (int *)&db_maxoff, FCN_NULL },
+ { "maxwidth", &db_max_width, FCN_NULL },
+ { "tabstops", &db_tab_stop_width, FCN_NULL },
+};
+struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
+
+int
+db_find_variable(varp)
+ struct db_variable **varp;
+{
+ int t;
+ struct db_variable *vp;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ for (vp = db_vars; vp < db_evars; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ for (vp = db_regs; vp < db_eregs; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ }
+ db_error("Unknown variable\n");
+ return (0);
+}
+
+int
+db_get_variable(valuep)
+ db_expr_t *valuep;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_read_variable(vp, valuep);
+
+ return (1);
+}
+
+int
+db_set_variable(value)
+ db_expr_t value;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_write_variable(vp, &value);
+
+ return (1);
+}
+
+
+db_read_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *valuep = *(vp->valuep);
+ else
+ (*func)(vp, valuep, DB_VAR_GET);
+}
+
+db_write_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *(vp->valuep) = *valuep;
+ else
+ (*func)(vp, valuep, DB_VAR_SET);
+}
+
+void
+db_set_cmd()
+{
+ db_expr_t value;
+ int (*func)();
+ struct db_variable *vp;
+ int t;
+
+ t = db_read_token();
+ if (t != tDOLLAR) {
+ db_error("Unknown variable\n");
+ return;
+ }
+ if (!db_find_variable(&vp)) {
+ db_error("Unknown variable\n");
+ return;
+ }
+
+ t = db_read_token();
+ if (t != tEQ)
+ db_unread_token(t);
+
+ if (!db_expression(&value)) {
+ db_error("No value\n");
+ return;
+ }
+ if (db_read_token() != tEOL) {
+ db_error("?\n");
+ }
+
+ db_write_variable(vp, &value);
+}
diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h
new file mode 100644
index 0000000..f958d2c
--- /dev/null
+++ b/sys/ddb/db_variables.h
@@ -0,0 +1,72 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_variables.h,v $
+ * Revision 1.1 1992/03/25 21:45:35 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:07:23 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:19:54 mrt]
+ *
+ * Revision 2.2 90/08/27 21:53:40 dbg
+ * Modularized typedef name. Documented the calling sequence of
+ * the (optional) access function of a variable. Now the valuep
+ * field can be made opaque, eg be an offset that fcn() resolves.
+ * [90/08/20 af]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DB_VARIABLES_H_
+#define _DB_VARIABLES_H_
+
+/*
+ * Debugger variables.
+ */
+struct db_variable {
+ char *name; /* Name of variable */
+ int *valuep; /* value of variable */
+ /* function to call when reading/writing */
+ int (*fcn)(/* db_variable *vp, db_expr_t *valuep, int op */);
+#define DB_VAR_GET 0
+#define DB_VAR_SET 1
+};
+#define FCN_NULL ((int (*)())0)
+
+extern struct db_variable db_vars[]; /* debugger variables */
+extern struct db_variable *db_evars;
+extern struct db_variable db_regs[]; /* machine registers */
+extern struct db_variable *db_eregs;
+
+#endif /* _DB_VARIABLES_H_ */
diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c
new file mode 100644
index 0000000..e69d906d9
--- /dev/null
+++ b/sys/ddb/db_watch.c
@@ -0,0 +1,294 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_watch.c,v $
+ * Revision 1.1 1992/03/25 21:45:37 pace
+ * Initial revision
+ *
+ * Revision 2.5 91/02/05 17:07:27 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:20:02 mrt]
+ *
+ * Revision 2.4 91/01/08 15:09:24 rpd
+ * Use db_map_equal, db_map_current, db_map_addr.
+ * [90/11/10 rpd]
+ *
+ * Revision 2.3 90/11/05 14:26:39 rpd
+ * Initialize db_watchpoints_inserted to TRUE.
+ * [90/11/04 rpd]
+ *
+ * Revision 2.2 90/10/25 14:44:16 rwd
+ * Made db_watchpoint_cmd parse a size argument.
+ * [90/10/17 rpd]
+ * Generalized the watchpoint support.
+ * [90/10/16 rwd]
+ * Created.
+ * [90/10/16 rpd]
+ *
+ */
+/*
+ * Author: Richard P. Draves, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <vm/vm_map.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Watchpoints.
+ */
+
+extern boolean_t db_map_equal();
+extern boolean_t db_map_current();
+extern vm_map_t db_map_addr();
+
+boolean_t db_watchpoints_inserted = TRUE;
+
+#define NWATCHPOINTS 100
+struct db_watchpoint db_watch_table[NWATCHPOINTS];
+db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
+db_watchpoint_t db_free_watchpoints = 0;
+db_watchpoint_t db_watchpoint_list = 0;
+
+db_watchpoint_t
+db_watchpoint_alloc()
+{
+ register db_watchpoint_t watch;
+
+ if ((watch = db_free_watchpoints) != 0) {
+ db_free_watchpoints = watch->link;
+ return (watch);
+ }
+ if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
+ db_printf("All watchpoints used.\n");
+ return (0);
+ }
+ watch = db_next_free_watchpoint;
+ db_next_free_watchpoint++;
+
+ return (watch);
+}
+
+void
+db_watchpoint_free(watch)
+ register db_watchpoint_t watch;
+{
+ watch->link = db_free_watchpoints;
+ db_free_watchpoints = watch;
+}
+
+void
+db_set_watchpoint(map, addr, size)
+ vm_map_t map;
+ db_addr_t addr;
+ vm_size_t size;
+{
+ register db_watchpoint_t watch;
+
+ if (map == NULL) {
+ db_printf("No map.\n");
+ return;
+ }
+
+ /*
+ * Should we do anything fancy with overlapping regions?
+ */
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr == addr) &&
+ (watch->hiaddr == addr+size)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ watch = db_watchpoint_alloc();
+ if (watch == 0) {
+ db_printf("Too many watchpoints.\n");
+ return;
+ }
+
+ watch->map = map;
+ watch->loaddr = addr;
+ watch->hiaddr = addr+size;
+
+ watch->link = db_watchpoint_list;
+ db_watchpoint_list = watch;
+
+ db_watchpoints_inserted = FALSE;
+}
+
+void
+db_delete_watchpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_watchpoint_t watch;
+ register db_watchpoint_t *prev;
+
+ for (prev = &db_watchpoint_list;
+ (watch = *prev) != 0;
+ prev = &watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr <= addr) &&
+ (addr < watch->hiaddr)) {
+ *prev = watch->link;
+ db_watchpoint_free(watch);
+ return;
+ }
+
+ db_printf("Not set.\n");
+}
+
+void
+db_list_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (db_watchpoint_list == 0) {
+ db_printf("No watchpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Address Size\n");
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ db_printf("%s%8x %8x %x\n",
+ db_map_current(watch->map) ? "*" : " ",
+ watch->map, watch->loaddr,
+ watch->hiaddr - watch->loaddr);
+}
+
+/* Delete watchpoint */
+/*ARGSUSED*/
+void
+db_deletewatch_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_watchpoint(db_map_addr(addr), addr);
+}
+
+/* Set watchpoint */
+/*ARGSUSED*/
+void
+db_watchpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ vm_size_t size;
+ db_expr_t value;
+
+ if (db_expression(&value))
+ size = (vm_size_t) value;
+ else
+ size = 4;
+ db_skip_to_eol();
+
+ db_set_watchpoint(db_map_addr(addr), addr, size);
+}
+
+/* list watchpoints */
+void
+db_listwatch_cmd()
+{
+ db_list_watchpoints();
+}
+
+void
+db_set_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (!db_watchpoints_inserted) {
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ pmap_protect(watch->map->pmap,
+ trunc_page(watch->loaddr),
+ round_page(watch->hiaddr),
+ VM_PROT_READ);
+
+ db_watchpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_watchpoints()
+{
+ db_watchpoints_inserted = FALSE;
+}
+
+boolean_t
+db_find_watchpoint(map, addr, regs)
+ vm_map_t map;
+ db_addr_t addr;
+ db_regs_t *regs;
+{
+ register db_watchpoint_t watch;
+ db_watchpoint_t found = 0;
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map)) {
+ if ((watch->loaddr <= addr) &&
+ (addr < watch->hiaddr))
+ return (TRUE);
+ else if ((trunc_page(watch->loaddr) <= addr) &&
+ (addr < round_page(watch->hiaddr)))
+ found = watch;
+ }
+
+ /*
+ * We didn't hit exactly on a watchpoint, but we are
+ * in a protected region. We want to single-step
+ * and then re-protect.
+ */
+
+ if (found) {
+ db_watchpoints_inserted = FALSE;
+ db_single_step(regs);
+ }
+
+ return (FALSE);
+}
diff --git a/sys/ddb/db_watch.h b/sys/ddb/db_watch.h
new file mode 100644
index 0000000..9795755
--- /dev/null
+++ b/sys/ddb/db_watch.h
@@ -0,0 +1,74 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_watch.h,v $
+ * Revision 1.1 1992/03/25 21:45:40 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:07:31 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:20:09 mrt]
+ *
+ * Revision 2.2 90/10/25 14:44:21 rwd
+ * Generalized the watchpoint support.
+ * [90/10/16 rwd]
+ * Created.
+ * [90/10/16 rpd]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#ifndef _DDB_DB_WATCH_
+#define _DDB_DB_WATCH_
+
+#include <vm/vm_map.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Watchpoint.
+ */
+
+typedef struct db_watchpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t loaddr; /* from this address */
+ db_addr_t hiaddr; /* to this address */
+ struct db_watchpoint *link; /* link in in-use or free chain */
+} *db_watchpoint_t;
+
+extern boolean_t db_find_watchpoint(/* vm_map_t map, db_addr_t addr,
+ db_regs_t *regs */);
+extern void db_set_watchpoints();
+extern void db_clear_watchpoints();
+
+extern void db_set_watchpoint(/* vm_map_t map, db_addr_t addr, vm_size_t size */);
+extern void db_delete_watchpoint(/* vm_map_t map, db_addr_t addr */);
+extern void db_list_watchpoints();
+
+#endif _DDB_DB_WATCH_
diff --git a/sys/ddb/db_write_cmd.c b/sys/ddb/db_write_cmd.c
new file mode 100644
index 0000000..dce22a9
--- /dev/null
+++ b/sys/ddb/db_write_cmd.c
@@ -0,0 +1,120 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_write_cmd.c,v $
+ * Revision 1.1 1992/03/25 21:45:42 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/05 17:07:35 mrt
+ * Changed to new Mach copyright
+ * [91/01/31 16:20:19 mrt]
+ *
+ * Revision 2.3 90/10/25 14:44:26 rwd
+ * Changed db_write_cmd to print unsigned.
+ * [90/10/19 rpd]
+ *
+ * Revision 2.2 90/08/27 21:53:54 dbg
+ * Set db_prev and db_next instead of explicitly advancing dot.
+ * [90/08/22 dbg]
+ * Reflected changes in db_printsym()'s calling seq.
+ * [90/08/20 af]
+ * Warn user if nothing was written.
+ * [90/08/07 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Write to file.
+ */
+/*ARGSUSED*/
+void
+db_write_cmd(address, have_addr, count, modif)
+ db_expr_t address;
+ boolean_t have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ register
+ db_addr_t addr;
+ register
+ db_expr_t old_value;
+ db_expr_t new_value;
+ register int size;
+ boolean_t wrote_one = FALSE;
+
+ addr = (db_addr_t) address;
+
+ switch (modif[0]) {
+ case 'b':
+ size = 1;
+ break;
+ case 'h':
+ size = 2;
+ break;
+ case 'l':
+ case '\0':
+ size = 4;
+ break;
+ default:
+ db_error("Unknown size\n");
+ return;
+ }
+
+ while (db_expression(&new_value)) {
+ old_value = db_get_value(addr, size, FALSE);
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf("\t\t%#8n\t=\t%#8n\n", old_value, new_value);
+ db_put_value(addr, size, new_value);
+ addr += size;
+
+ wrote_one = TRUE;
+ }
+
+ if (!wrote_one)
+ db_error("Nothing written.\n");
+
+ db_next = addr;
+ db_prev = addr - size;
+
+ db_skip_to_eol();
+}
+
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
new file mode 100644
index 0000000..a461e81
--- /dev/null
+++ b/sys/dev/fdc/fdc.c
@@ -0,0 +1,903 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fd.c 7.4 (Berkeley) 5/25/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ *
+ * Largely rewritten to handle multiple controllers and drives
+ * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993
+ */
+char rev[] = "$Revision: 1.10 $";
+/*
+ * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $
+ */
+/*
+ * $Log: fd.c,v $
+ * Revision 1.10 93/04/13 16:53:29 root
+ * make sure turning off a drive motor doesn't deselect another
+ * drive active at the time.
+ * Also added a pointer from the fd_data to it's fd_type.
+ *
+ * Revision 1.9 93/04/13 15:31:02 root
+ * make all seeks go through DOSEEK state so are sure of being done right.
+ *
+ * Revision 1.8 93/04/12 21:20:13 root
+ * only check if old fd is the one we are working on if there IS
+ * an old fd pointer. (in fdstate())
+ *
+ * Revision 1.7 93/04/11 17:05:35 root
+ * cleanup timeouts etc.
+ * also fix bug to select teh correct drive when running > 1 drive
+ * at a time.
+ *
+ * Revision 1.6 93/04/05 00:48:45 root
+ * change a timeout and add version to banner message
+ *
+ * Revision 1.5 93/04/04 16:39:08 root
+ * first working version.. some floppy controllers don't seem to
+ * like 2 int. status inquiries in a row.
+ *
+ */
+
+#include "fd.h"
+#if NFD > 0
+
+#include "param.h"
+#include "dkbad.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "ioctl.h"
+#include "buf.h"
+#include "uio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+#undef NFD
+#define NFD 2
+
+#define FDUNIT(s) ((s>>3)&1)
+#define FDTYPE(s) ((s)&7)
+
+#define b_cylin b_resid
+#define FDBLK 512
+#define NUMTYPES 4
+
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int gap; /* gap len between sectors */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int steptrac; /* steps per cylinder */
+ int trans; /* transfer speed code */
+ int heads; /* number of heads */
+};
+
+struct fd_type fd_types[NUMTYPES] =
+{
+ { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */
+ { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */
+ { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */
+ { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */
+};
+
+#define DRVS_PER_CTLR 2
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+}fdc_data[(NFD+1)/DRVS_PER_CTLR];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (presently 2) (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc;
+ int fdu; /* this unit number */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else DEBUG
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif DEBUG
+
+extern int hz;
+/* state needed for current transfer */
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+int fdprobe(), fdattach(), fd_turnoff();
+
+struct isa_driver fddriver = {
+ fdprobe, fdattach, "fd",
+};
+
+/*
+ * probe for existance of controller
+ */
+fdprobe(dev)
+struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+fdattach(dev)
+struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+
+ fdt = rtcin(RTC_FDISKETTE);
+ hdr = 0;
+
+ /* check for each floppy drive */
+ for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0;
+ ((fdu < NFD) && (fdsu < DRVS_PER_CTLR));
+ fdu++,fdsu++)
+ {
+ /* is there a unit? */
+ if ((fdt & 0xf0) == RTCFDT_NONE)
+ continue;
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd_data[fdu].track = -2;
+ fd_data[fdu].fdc = fdc;
+ fd_data[fdu].fdsu = fdsu;
+ /* yes, announce it */
+ if (!hdr)
+ printf(" drives ");
+ else
+ printf(", ");
+ printf("%d: ", fdu);
+
+
+ if ((fdt & 0xf0) == RTCFDT_12M) {
+ printf("1.2M");
+ fd_data[fdu].type = 1;
+ fd_data[fdu].ft = fd_types + 1;
+
+ }
+ if ((fdt & 0xf0) == RTCFDT_144M) {
+ printf("1.44M");
+ fd_data[fdu].type = 0;
+ fd_data[fdu].ft = fd_types + 0;
+ }
+
+ fdt <<= 4;
+ fd_turnoff(fdu);
+ hdr = 1;
+ }
+
+ printf(" %s ",rev);
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+}
+
+int
+fdsize(dev)
+dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+fdstrategy(bp)
+ register struct buf *bp; /* IO operation to perform */
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+ /*type = FDTYPE(minor(bp->b_dev));*/
+
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff,fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+set_motor(fdcu_t fdcu, fdu_t fdu, int reset)
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+fd_turnoff(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+fd_motor_on(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fd_pseudointr(fd->fdc->fdcu);
+ }
+}
+
+fd_turnon(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */
+ }
+}
+
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu_t fdcu)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+out_fdc(fdcu_t fdcu,int x)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i = 100000;
+
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1);
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+static fdopenf;
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ /*int type = FDTYPE(minor(dev));*/
+ int s;
+
+ /* check bounds */
+ if (fdu >= NFD) return(ENXIO);
+ /*if (type >= NUMTYPES) return(ENXIO);*/
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+fdclose(dev, flags)
+ dev_t dev;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+fdstart(fdcu_t fdcu)
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+fd_timeout(fdcu_t fdcu)
+{
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+
+ dp = &fdc_data[fdcu].head;
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fd_pseudointr(fdcu);
+}
+
+/* just ensure it has the right spl */
+fd_pseudointr(fdcu_t fdcu)
+{
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ while(fdstate(fdcu, fdc));
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int fdstate(fdcu_t fdcu, fdc_p fdc)
+{
+ int read,head,trac,sec,i,s,sectrac,cyl,st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, fdu);
+ timeout(fd_turnoff,fdu,4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ return(0); /* will return later */
+ case SEEKWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu,
+ descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout,fdcu,2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout,fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+retrier(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ printf("fd%d: hard error (ST0 %b ",
+ fdc->fdu, fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[4], fdc->status[5], fdc->status[6]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+#endif
+
diff --git a/sys/dev/fdc/fdcreg.h b/sys/dev/fdc/fdcreg.h
new file mode 100644
index 0000000..948f566
--- /dev/null
+++ b/sys/dev/fdc/fdcreg.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
+
diff --git a/sys/dev/ic/i8237.h b/sys/dev/ic/i8237.h
new file mode 100644
index 0000000..dc269f2
--- /dev/null
+++ b/sys/dev/ic/i8237.h
@@ -0,0 +1,9 @@
+/*
+ * Intel 8237 DMA Controller
+ */
+
+#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
+#define DMA37MD_READ 0x08 /* write the device, read memory operation */
+
diff --git a/sys/dev/ic/nec765.h b/sys/dev/ic/nec765.h
new file mode 100644
index 0000000..b84b46e
--- /dev/null
+++ b/sys/dev/ic/nec765.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h
new file mode 100644
index 0000000..e20e9aa
--- /dev/null
+++ b/sys/dev/ic/ns16550.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
new file mode 100644
index 0000000..38503fd
--- /dev/null
+++ b/sys/dev/sio/sio.c
@@ -0,0 +1,1721 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sio.c 7.5 (Berkeley) 5/16/91
+ *
+ * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt
+ * com port driver.
+ * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR
+ * code, add multiport support.
+ * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting
+ * into the patch kit. Added in sioselect
+ * from com.c. Added port 4 support.
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $";
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * COM driver, based on HP dca driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#undef CRTS_IFLOW
+#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TS_RTSBLOCK TS_TBLOCK /* XXX */
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+#ifndef COM_BIDIR
+#define UNIT(x) (minor(x)) /* XXX */
+#else /* COM_BIDIR */
+#define COM_UNITMASK 0x7f
+#define COM_CALLOUTMASK 0x80
+
+#define UNIT(x) (minor(x) & COM_UNITMASK)
+#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
+#endif /* COM_BIDIR */
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#endif /* COM_MULTIPORT */
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+#define schedsoftcom() (ipending |= 1 << 4) /* XXX */
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef int Bool_t; /* promoted boolean */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+ bool_t softDCD; /* nonzero for faked carrier detect */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+
+/*
+ * These functions in the com module ought to be declared (with a prototype)
+ * in a com-driver system header. The void ones may need to be int to match
+ * ancient devswitch declarations, but they don't actually return anything.
+ */
+#define Dev_t int /* promoted dev_t */
+struct consdev;
+
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+void siointr __P((int unit));
+#ifdef COM_MULTIPORT
+bool_t comintr1 __P((struct com_s *com));
+#endif /* COM_MULTIPORT */
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+int siocngetc __P((Dev_t dev));
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+/*
+ * sioopen gets compared to the d_open entry in struct cdevsw. d_open and
+ * other functions are declared in <sys/conf.h> with short types like dev_t
+ * in the prototype. Such declarations are broken because they vary with
+ * __P (significantly in theory - the compiler is allowed to push a short
+ * arg if it has seen the prototype; insignificantly in practice - gcc
+ * doesn't push short args and it would be slower on 386's to do so).
+ *
+ * Also, most of the device switch functions are still declared old-style
+ * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler
+ * and faster if dev_t's were always promoted (to ints or whatever) as
+ * early as possible.
+ *
+ * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type
+ * when comparing it to the d_open entry just to avoid compiler warnings.
+ */
+typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+void siostop __P((struct tty *tp, int rw));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+void softsio0 __P((void));
+void softsio1 __P((void));
+void softsio2 __P((void));
+void softsio3 __P((void));
+void softsio4 __P((void));
+void softsio5 __P((void));
+void softsio6 __P((void));
+void softsio7 __P((void));
+void softsio8 __P((void));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void cominit __P((int unit, int rate));
+static int commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void compoll __P((void));
+static int comstart __P((struct tty *tp));
+static void comwakeup __P((void));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static bool_t comconsinit;
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+struct tty sio_tty[NSIO];
+extern struct tty *constty;
+extern u_int ipending; /* XXX */
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = 1;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+ || !isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ enable_intr();
+
+ return (result);
+}
+
+static int /* XXX - should be void */
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ if (unit == comconsole)
+ DELAY(1000); /* XXX */
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit];
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+#if 0
+ com->softDCD = TRUE;
+#endif
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+ com->tp = &sio_tty[unit];
+#ifdef COM_BIDIR
+ /*
+ * if bidirectional ports possible, clear the bidir port info;
+ */
+ com->bidir = FALSE;
+ com->active = FALSE;
+ com->active_in = com->active_out = FALSE;
+#endif /* COM_BIDIR */
+
+ /* attempt to determine UART type */
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a)
+ printf(" <8250>");
+ else {
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" <16450>");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" <16450?>");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" <16550?>");
+ break;
+ case FIFO_TRIGGER_14:
+ com->hasfifo = TRUE;
+ printf(" <16550A>");
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+ }
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ struct isa_device *masterdev;
+
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(iobase + com_mcr, 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase+com_scr, 0x80);
+ }
+ else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ cominit(unit, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("com%d: ", unit);
+ kgdb_connect(1);
+ }
+ else
+ printf("com%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ /*
+ * Need to reset baud rate, etc. of next print so reset comconsinit.
+ * Also make sure console is always "hardwired"
+ */
+ if (unit == comconsole) {
+ comconsinit = FALSE;
+ com->softDCD = TRUE;
+ }
+
+ com_addr(unit) = com;
+
+ splx(s);
+
+ if (!comwakeup_started) {
+ comwakeup();
+ comwakeup_started = TRUE;
+ }
+
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error = 0;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit = UNIT(dev);
+#ifdef COM_BIDIR
+ bool_t callout = CALLOUT(dev);
+#endif /* COM_BIDIR */
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+ tp = com->tp;
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ com->softDCD = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep(&com->active_out,
+ TTIPRI|PCATCH,
+ "comoth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ } else if (com->last_modem_status & MSR_DCD) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* put DTR & RTS up */
+ /* NOTE: cgd'sdriver used the ier register
+ * to enable/disable interrupts. This one
+ * uses both ier and IENABLE in the mcr.
+ */
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+ /* wait for it... */
+ error = tsleep(&com->active_in,
+ TTIPRI|PCATCH,
+ "comdcd",
+ 0);
+
+ /* if not active, turn DTR & RTS off */
+ if (!com->active)
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We no longer use the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off. It's useful to have clocal on
+ * initially so that "stty changed-defaults </dev/comx"
+ * doesn't hang waiting for carrier.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8 | CLOCAL;
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ }
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ disable_intr();
+ if (com->hasfifo)
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ com->last_modem_status =
+ com->prev_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->softDCD || com->prev_modem_status & MSR_DCD)
+ tp->t_state |= TS_CARR_ON;
+ }
+ else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ splx(s);
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remainded hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+{
+ comhardclose(com);
+}
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ comhardclose(com);
+ ttyclose(tp);
+ return (0);
+}
+
+void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ s = spltty();
+ iobase = com->iobase;
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts if debugging */
+ if (kgdb_dev != makedev(commajor, com - &com_structs[0]))
+#endif
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+ || !(tp->t_state & TS_ISOPEN))
+ (void) commctl(com, 0, DMSET);
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+ com->softDCD = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+void
+siointr(unit)
+ int unit;
+{
+ struct com_s *com;
+#ifndef COM_MULTIPORT
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+ com = com_addr(unit);
+#else /* COM_MULTIPORT */
+ int i;
+ bool_t donesomething;
+
+ do {
+ donesomething = FALSE;
+ for(i=0;i<NSIO;i++) {
+ com=com_addr(i);
+ if(com != NULL) {
+ /* XXX When siointr is called
+ * to start output, maybe
+ * it should be changed to a
+ * call to comintr1. Doesn't
+ * seem a good idea: interrupts
+ * are disabled all the time.
+ */
+enable_intr();
+disable_intr();
+ donesomething = comintr1(com);
+ }
+ }
+ } while (donesomething);
+ return;
+}
+
+bool_t
+comintr1(struct com_s *com)
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+ bool_t donesomething;
+
+ donesomething = FALSE;
+#endif /* COM_MULTIPORT */
+
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ schedsoftcom();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ ioptr = com->optr;
+ outb(com->data_port, *ioptr);
+ ++com->bytes_out;
+ com->optr = ++ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ schedsoftcom(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#ifdef COM_MULTIPORT
+ return (donesomething);
+#else
+ return;
+#endif /* COM_MULTIPORT */
+ }
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS);
+ break;
+ case TIOCCDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+ break;
+ case TIOCMSET:
+ (void) commctl(com, *(int *)data, DMSET);
+ break;
+ case TIOCMBIS:
+ (void) commctl(com, *(int *)data, DMBIS);
+ break;
+ case TIOCMBIC:
+ (void) commctl(com, *(int *)data, DMBIC);
+ break;
+ case TIOCMGET:
+ *(int *)data = commctl(com, 0, DMGET);
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ if (p->p_ucred->cr_uid != 0)
+ return(EPERM);
+
+ /* if it's the console, can't do it */
+ if (UNIT(dev) == comconsole)
+ return(ENOTTY);
+
+ /* can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+
+ /* if the port is active, don't do it */
+ /* if (com->active)
+ return(EBUSY); */
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = &com->tp->t_out;
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+static void
+compoll()
+{
+ static bool_t awake = FALSE;
+ struct com_s *com;
+ int s;
+ int unit;
+
+ if (com_events == 0)
+ return;
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf))
+ incc = 0;
+ else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ if (!(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTSBLOCK))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD &&
+ unit != comconsole) {
+#ifdef COM_BIDIR
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ com->softDCD = FALSE;
+ wakeup((caddr_t) &com->active_in);
+ }
+#else
+ if (com->prev_modem_status & MSR_DCD)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#endif /* COM_BIDIR */
+ else if ((*linesw[tp->t_line].l_modem)(tp, 0)
+ == 0) {
+ disable_intr();
+ outb(com->modem_ctl_port,
+ com->mcr_image
+ &= ~(MCR_DTR | MCR_RTS));
+ enable_intr();
+ }
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ u_int delta_error_counts[CE_NTYPES];
+ int errnum;
+ u_long total;
+
+ disable_intr();
+ bcopy(com->delta_error_counts, delta_error_counts,
+ sizeof delta_error_counts);
+ bzero(com->delta_error_counts,
+ sizeof delta_error_counts);
+ enable_intr();
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ delta = delta_error_counts[errnum];
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "com%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTSBLOCK)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTSBLOCK;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(&tp->t_raw, (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ }
+ else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+ splx(s);
+ awake = FALSE;
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0) {
+ (void) commctl(com, 0, DMSET); /* hang up line */
+ splx(s);
+ return (0);
+ }
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ "comparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ * Note that DCD flow control stupidly uses the same state flag
+ * (TS_TTSTOP) as XON/XOFF flow control.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->prev_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ enable_intr();
+ siointr(unit); /* recover from fiddling with CS_TTGO */
+ splx(s);
+ return (0);
+}
+
+static int /* XXX - should be void */
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTSBLOCK) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ }
+ else {
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ else if (RB_LEN(&tp->t_out) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(&tp->t_out);
+ disable_intr();
+ com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr(unit); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+ return (1);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+static int
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits);
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | MCR_IENABLE);
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits));
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits & ~MCR_IENABLE));
+ break;
+ case DMGET:
+ bits = com->prev_modem_status;
+ break;
+ }
+ enable_intr();
+ return (bits);
+}
+
+static void
+comwakeup()
+{
+ struct com_s *com;
+ int unit;
+
+ timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1);
+ if (com_events != 0)
+ /* schedule compoll() to run when the cpl allows */
+ schedsoftcom();
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ }
+}
+
+void
+softsio0() { compoll(); }
+
+void
+softsio1() { compoll(); }
+
+void
+softsio2() { compoll(); }
+
+void
+softsio3() { compoll(); }
+
+void
+softsio4() { compoll(); }
+
+void
+softsio5() { compoll(); }
+
+void
+softsio6() { compoll(); }
+
+void
+softsio7() { compoll(); }
+
+void
+softsio8() { compoll(); }
+
+/*
+ * Following are all routines needed for COM to act as console
+ * XXX - not tested in this version
+ * XXX - check that the corresponding serial interrupts are never enabled
+ */
+#include "i386/i386/cons.h"
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == (bogus_open_t) sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = CONUNIT;
+ com_addr(unit) = &com_structs[unit];
+ com_addr(unit)->iobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+ cp->cn_tp = &sio_tty[unit];
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ unit = UNIT(cp->cn_dev);
+ cominit(unit, comdefaultrate);
+ comconsole = unit;
+ comconsinit = TRUE;
+}
+
+static void
+cominit(unit, rate)
+ int unit;
+ int rate;
+{
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(unit)->iobase;
+ s = splhigh();
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ rate = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_data, rate & 0xFF);
+ outb(iobase + com_ier, rate >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+
+ /*
+ * XXX - fishy to enable interrupts and then poll.
+ * It shouldn't be necessary to ready the iir.
+ */
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ (void) inb(iobase + com_iir);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ Port_t iobase;
+ int s;
+ int timo;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (!comconsinit) {
+ (void) cominit(UNIT(dev), comdefaultrate);
+ comconsinit = TRUE;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ outb(iobase + com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+/*
+ * 10 Feb 93 Jordan K. Hubbard Added select code
+ * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5
+ */
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct tty *tp = &sio_tty[UNIT(dev)];
+ int nread;
+ int s = spltty();
+ struct proc *selp;
+
+ switch (rw) {
+
+ case FREAD:
+ nread = ttnread(tp);
+ if (nread > 0 ||
+ ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+ goto win;
+ if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_RCOLL;
+ else
+ tp->t_rsel = p->p_pid;
+ break;
+
+ case FWRITE:
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+ goto win;
+ if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_WCOLL;
+ else
+ tp->t_wsel = p->p_pid;
+ break;
+ }
+ splx(s);
+ return (0);
+ win:
+ splx(s);
+ return (1);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/dev/sio/sioreg.h b/sys/dev/sio/sioreg.h
new file mode 100644
index 0000000..2a62683
--- /dev/null
+++ b/sys/dev/sio/sioreg.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/dev/speaker/spkr.c b/sys/dev/speaker/spkr.c
new file mode 100644
index 0000000..ffeec08
--- /dev/null
+++ b/sys/dev/speaker/spkr.c
@@ -0,0 +1,520 @@
+/*
+ * spkr.c -- device driver for console speaker on 80386
+ *
+ * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+ * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+ * 386bsd only clean version, all SYSV stuff removed
+ * use hz value from param.c
+ */
+
+#include "speaker.h"
+
+#if NSPEAKER > 0
+
+#include "param.h"
+#include "kernel.h"
+#include "errno.h"
+#include "buf.h"
+#include "uio.h"
+#include "spkr.h"
+
+/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+ *
+ * This section defines a function tone() which causes a tone of given
+ * frequency and duration from the 80x86's console speaker.
+ * Another function endtone() is defined to force sound off, and there is
+ * also a rest() entry point to do pauses.
+ *
+ * Audible sound is generated using the Programmable Interval Timer (PIT) and
+ * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+ * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+ * used to generate clicks (a square wave) of whatever frequency is desired.
+ */
+
+/*
+ * PIT and PPI port addresses and control values
+ *
+ * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+ * channel 2, frequency LSB first, square-wave mode and binary encoding.
+ * The encoding is as follows:
+ *
+ * +----------+----------+---------------+-----+
+ * | 1 0 | 1 1 | 0 1 1 | 0 |
+ * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD |
+ * +----------+----------+---------------+-----+
+ * Counter Write Mode 3 Binary
+ * Channel 2 LSB first, (Square Wave) Encoding
+ * MSB second
+ */
+#define PPI 0x61 /* port of Programmable Peripheral Interface */
+#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
+#define PIT_CTRL 0x43 /* PIT control address */
+#define PIT_COUNT 0x42 /* PIT count address */
+#define PIT_MODE 0xB6 /* set timer mode for sound generation */
+
+/*
+ * Magic numbers for timer control.
+ */
+#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */
+
+static int endtone()
+/* turn off the speaker, ending current tone */
+{
+ wakeup((caddr_t)endtone);
+ outb(PPI, inb(PPI) & ~PPI_SPKR);
+}
+
+static void tone(hz, ticks)
+/* emit tone of frequency hz for given number of ticks */
+unsigned int hz, ticks;
+{
+ unsigned int divisor = TIMER_CLK / hz;
+ int sps;
+
+#ifdef DEBUG
+ printf("tone: hz=%d ticks=%d\n", hz, ticks);
+#endif /* DEBUG */
+
+ /* set timer to generate clicks at given frequency in Hertz */
+ sps = spltty();
+ outb(PIT_CTRL, PIT_MODE); /* prepare timer */
+ outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */
+ outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */
+ splx(sps);
+
+ /* turn the speaker on */
+ outb(PPI, inb(PPI) | PPI_SPKR);
+
+ /*
+ * Set timeout to endtone function, then give up the timeslice.
+ * This is so other processes can execute while the tone is being
+ * emitted.
+ */
+ timeout((caddr_t)endtone, (caddr_t)NULL, ticks);
+ sleep((caddr_t)endtone, PZERO - 1);
+}
+
+static int endrest()
+/* end a rest */
+{
+ wakeup((caddr_t)endrest);
+}
+
+static void rest(ticks)
+/* rest for given number of ticks */
+int ticks;
+{
+ /*
+ * Set timeout to endrest function, then give up the timeslice.
+ * This is so other processes can execute while the rest is being
+ * waited out.
+ */
+#ifdef DEBUG
+ printf("rest: %d\n", ticks);
+#endif /* DEBUG */
+ timeout((caddr_t)endrest, (caddr_t)NULL, ticks);
+ sleep((caddr_t)endrest, PZERO - 1);
+}
+
+/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+ *
+ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+ * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
+ * Requires tone(), rest(), and endtone(). String play is not interruptible
+ * except possibly at physical block boundaries.
+ */
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define dtoi(c) ((c) - '0')
+
+static int octave; /* currently selected octave */
+static int whole; /* whole-note time at current tempo, in ticks */
+static int value; /* whole divisor for note time, quarter note = 1 */
+static int fill; /* controls spacing of notes */
+static bool octtrack; /* octave-tracking on? */
+static bool octprefix; /* override current octave-tracking state? */
+
+/*
+ * Magic number avoidance...
+ */
+#define SECS_PER_MIN 60 /* seconds per minute */
+#define WHOLE_NOTE 4 /* quarter notes per whole note */
+#define MIN_VALUE 64 /* the most we can divide a note by */
+#define DFLT_VALUE 4 /* default value (quarter-note) */
+#define FILLTIME 8 /* for articulation, break note in parts */
+#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
+#define NORMAL 7 /* 7/8ths of note interval is filled */
+#define LEGATO 8 /* all of note interval is filled */
+#define DFLT_OCTAVE 4 /* default octave */
+#define MIN_TEMPO 32 /* minimum tempo */
+#define DFLT_TEMPO 120 /* default tempo */
+#define MAX_TEMPO 255 /* max tempo */
+#define NUM_MULT 3 /* numerator of dot multiplier */
+#define DENOM_MULT 2 /* denominator of dot multiplier */
+
+/* letter to half-tone: A B C D E F G */
+static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+
+/*
+ * This is the American Standard A440 Equal-Tempered scale with frequencies
+ * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+ * our octave 0 is standard octave 2.
+ */
+#define OCTAVE_NOTES 12 /* semitones per octave */
+static int pitchtab[] =
+{
+/* C C# D D# E F F# G G# A A# B*/
+/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
+/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
+/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
+/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
+/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+};
+
+static void playinit()
+{
+ octave = DFLT_OCTAVE;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+ fill = NORMAL;
+ value = DFLT_VALUE;
+ octtrack = FALSE;
+ octprefix = TRUE; /* act as though there was an initial O(n) */
+}
+
+static void playtone(pitch, value, sustain)
+/* play tone of proper duration for current rhythm signature */
+int pitch, value, sustain;
+{
+ register int sound, silence, snum = 1, sdenom = 1;
+
+ /* this weirdness avoids floating-point arithmetic */
+ for (; sustain; sustain--)
+ {
+ snum *= NUM_MULT;
+ sdenom *= DENOM_MULT;
+ }
+
+ if (pitch == -1)
+ rest(whole * snum / (value * sdenom));
+ else
+ {
+ sound = (whole * snum) / (value * sdenom)
+ - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+ silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+
+#ifdef DEBUG
+ printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+ pitch, sound, silence);
+#endif /* DEBUG */
+
+ tone(pitchtab[pitch], sound);
+ if (fill != LEGATO)
+ rest(silence);
+ }
+}
+
+static int abs(n)
+int n;
+{
+ if (n < 0)
+ return(-n);
+ else
+ return(n);
+}
+
+static void playstring(cp, slen)
+/* interpret and play an item from a notation string */
+char *cp;
+size_t slen;
+{
+ int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+
+#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+ {v = v * 10 + (*++cp - '0'); slen--;}
+ for (; slen--; cp++)
+ {
+ int sustain, timeval, tempo;
+ register char c = toupper(*cp);
+
+#ifdef DEBUG
+ printf("playstring: %c (%x)\n", c, c);
+#endif /* DEBUG */
+
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+
+ /* compute pitch */
+ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+
+ /* this may be followed by an accidental sign */
+ if (cp[1] == '#' || cp[1] == '+')
+ {
+ ++pitch;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == '-')
+ {
+ --pitch;
+ ++cp;
+ slen--;
+ }
+
+ /*
+ * If octave-tracking mode is on, and there has been no octave-
+ * setting prefix, find the version of the current letter note
+ * closest to the last regardless of octave.
+ */
+ if (octtrack && !octprefix)
+ {
+ if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+ {
+ ++octave;
+ pitch += OCTAVE_NOTES;
+ }
+
+ if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+ {
+ --octave;
+ pitch -= OCTAVE_NOTES;
+ }
+ }
+ octprefix = FALSE;
+ lastpitch = pitch;
+
+ /* ...which may in turn be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+
+ /* ...and/or sustain dots */
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+
+ /* time to emit the actual tone */
+ playtone(pitch, timeval, sustain);
+ break;
+
+ case 'O':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ octprefix = octtrack = FALSE;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ octtrack = TRUE;
+ ++cp;
+ slen--;
+ }
+ else
+ {
+ GETNUM(cp, octave);
+ if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+ octave = DFLT_OCTAVE;
+ octprefix = TRUE;
+ }
+ break;
+
+ case '>':
+ if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+ octave++;
+ octprefix = TRUE;
+ break;
+
+ case '<':
+ if (octave > 0)
+ octave--;
+ octprefix = TRUE;
+ break;
+
+ case 'N':
+ GETNUM(cp, pitch);
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(pitch - 1, value, sustain);
+ break;
+
+ case 'L':
+ GETNUM(cp, value);
+ if (value <= 0 || value > MIN_VALUE)
+ value = DFLT_VALUE;
+ break;
+
+ case 'P':
+ case '~':
+ /* this may be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(-1, timeval, sustain);
+ break;
+
+ case 'T':
+ GETNUM(cp, tempo);
+ if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+ tempo = DFLT_TEMPO;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+ break;
+
+ case 'M':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ fill = NORMAL;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'S' || cp[1] == 's')
+ {
+ fill = STACCATO;
+ ++cp;
+ slen--;
+ }
+ break;
+ }
+ }
+}
+
+/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+ *
+ * This section implements driver hooks to run playstring() and the tone(),
+ * endtone(), and rest() functions defined above.
+ */
+
+static int spkr_active; /* exclusion flag */
+static struct buf *spkr_inbuf; /* incoming buf */
+
+int spkropen(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ printf("spkropen: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (spkr_active)
+ return(EBUSY);
+ else
+ {
+ playinit();
+ spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_active = 1;
+ }
+ return(0);
+}
+
+int spkrwrite(dev, uio)
+dev_t dev;
+struct uio *uio;
+{
+ register unsigned n;
+ char *cp;
+ int error;
+#ifdef DEBUG
+ printf("spkrwrite: entering with dev = %x, count = %d\n",
+ dev, uio->uio_resid);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ n = MIN(DEV_BSIZE, uio->uio_resid);
+ cp = spkr_inbuf->b_un.b_addr;
+ error = uiomove(cp, n, uio);
+ if (!error)
+ playstring(cp, n);
+ return(error);
+ }
+}
+
+int spkrclose(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ printf("spkrclose: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ endtone();
+ brelse(spkr_inbuf);
+ spkr_active = 0;
+ }
+ return(0);
+}
+
+int spkrioctl(dev, cmd, cmdarg)
+dev_t dev;
+int cmd;
+caddr_t cmdarg;
+{
+#ifdef DEBUG
+ printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (cmd == SPKRTONE)
+ {
+ tone_t *tp = (tone_t *)cmdarg;
+
+ if (tp->frequency == 0)
+ rest(tp->duration);
+ else
+ tone(tp->frequency, tp->duration);
+ }
+ else if (cmd == SPKRTUNE)
+ {
+ tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
+ tone_t ttp;
+ int error;
+
+ for (; ; tp++) {
+ error = copyin(tp, &ttp, sizeof(tone_t));
+ if (error)
+ return(error);
+ if (ttp.duration == 0)
+ break;
+ if (ttp.frequency == 0)
+ rest(ttp.duration);
+ else
+ tone(ttp.frequency, ttp.duration);
+ }
+ }
+ else
+ return(EINVAL);
+ return(0);
+}
+
+#endif /* NSPEAKER > 0 */
+/* spkr.c ends here */
diff --git a/sys/i386/Makefile b/sys/i386/Makefile
new file mode 100644
index 0000000..0662e28
--- /dev/null
+++ b/sys/i386/Makefile
@@ -0,0 +1,24 @@
+# @(#)Makefile 7.3 (Berkeley) 6/9/91
+
+# Makefile for i386 tags file
+
+all:
+ @echo "make tags or links only"
+
+TI386= ../i386/tags
+SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch]
+AI386= ../i386/i386/*.s
+
+# Directories in which to place i386 tags links
+DI386= eisa isa mca include
+
+tags:
+ -ctags -dtf ${TI386} ${COMM} ${SI386}
+ egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \
+ sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \
+ >> ${TI386}
+ sort -o ${TI386} ${TI386}
+
+links:
+ -for i in ${DI386}; do \
+ cd $$i && rm -f tags; ln -s ../tags tags; done
diff --git a/sys/i386/boot/Makefile b/sys/i386/boot/Makefile
new file mode 100644
index 0000000..bebd8bc
--- /dev/null
+++ b/sys/i386/boot/Makefile
@@ -0,0 +1,131 @@
+#
+# Ported to boot 386BSD by Julian Elischer (julian@tfs.com)
+# September 1992
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+#
+# HISTORY
+# $Log: Makefile,v $
+# Revision 2.2 92/04/04 11:33:46 rpd
+# Fabricated for MACH 3.0
+# [92/03/30 mg32]
+#
+# Thu Sep 10 22:40:23 PDT 1992
+# Ported to 386BSD by Julian Elischer
+# julian@tfs.com
+#
+
+CFLAGS = -O -DDO_BAD144
+LIBS= -lc
+INC= -I../..
+
+# start.o should be first, table.o should be second
+OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o
+
+.SUFFIXES: .s .c .o
+
+# These are wierd because we don't want separate code and data segments.. ok?
+.c.o:
+ @echo $(CC) -c $(CFLAGS) $(INC) $*.c
+ -@trap "/bin/rm -f $*.i $*.s; exit 0" 0 1 2 3 10 15; \
+ $(CC) $(CFLAGS) $(INC) -S $<; \
+ if [ $$? != 0 ]; then :; else \
+ sed -f boot.sed $*.s > $*.i; \
+ $(AS) $*.i -o $@; \
+ fi
+
+.s.o:
+ @echo $(AS) -o $*.o $<
+ -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \
+ /bin/rm -f X$*.c; \
+ ln $*.s X$*.c; \
+ $(CC) -E $(CFLAGS) X$*.c > $*.i; \
+ if [ $$? != 0 ]; then :; \
+ else \
+ $(AS) $*.i -o $@; \
+ fi
+
+
+boot: boot.sed $(OBJS)
+ $(LD) -N -T 0 -o boot $(OBJS) $(LIBS)
+ cp boot boot.sym
+ @strip boot
+ @./rmaouthdr boot boot.tmp
+ @mv -f boot.tmp boot
+ @ls -l boot
+
+biosboot: boot
+ dd if=boot of=biosboot count=1
+
+bootbios: boot
+ dd if=boot of=bootbios skip=1
+
+/usr/mdec/bootsd: bootbios
+ cp bootbios /usr/mdec/bootsd
+
+/usr/mdec/sdboot: biosboot
+ cp biosboot /usr/mdec/sdboot
+
+/usr/mdec/bootwd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootwd
+ ln /usr/mdec/bootsd /usr/mdec/bootwd
+
+/usr/mdec/wdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/wdboot
+ ln /usr/mdec/sdboot /usr/mdec/wdboot
+
+/usr/mdec/bootfd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootfd
+ ln /usr/mdec/bootsd /usr/mdec/bootfd
+
+/usr/mdec/fdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/fdboot
+ ln /usr/mdec/sdboot /usr/mdec/fdboot
+
+sd: /usr/mdec/bootsd /usr/mdec/sdboot
+wd: /usr/mdec/bootwd /usr/mdec/wdboot
+fd: /usr/mdec/bootfd /usr/mdec/fdboot
+
+#wd0: /usr/mdec/bootwd /usr/mdec/wdboot
+# disklabel -r -w wd0 julian julian5 /usr/mdec/wdboot /usr/mdec/bootwd
+#
+
+sd0: /usr/mdec/bootsd /usr/mdec/sdboot
+ disklabel -r -w sd0 XT-8760 scsitest /usr/mdec/sdboot /usr/mdec/bootsd
+
+
+#fd0: /usr/mdec/bootfd /usr/mdec/fdboot
+# disklabel -r -w fd0 floppy5 bootflpy /usr/mdec/fdboot /usr/mdec/bootfd
+#
+
+install: wd sd
+# you should use the old floppy booter, it's MUCH faster
+# This one works but it's too slow.
+# besides how many kernels can you fit on a floppy?
+# only use this one if you want to boot a kernel
+# from a hard disk 2 when you've trashed hard disk 1
+#install: wd sd fd
+
+clean:
+ /bin/rm -f *.o *.d boot bootbios biosboot boot.sym
+
+
diff --git a/sys/i386/boot/biosboot/Makefile b/sys/i386/boot/biosboot/Makefile
new file mode 100644
index 0000000..bebd8bc
--- /dev/null
+++ b/sys/i386/boot/biosboot/Makefile
@@ -0,0 +1,131 @@
+#
+# Ported to boot 386BSD by Julian Elischer (julian@tfs.com)
+# September 1992
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+#
+# HISTORY
+# $Log: Makefile,v $
+# Revision 2.2 92/04/04 11:33:46 rpd
+# Fabricated for MACH 3.0
+# [92/03/30 mg32]
+#
+# Thu Sep 10 22:40:23 PDT 1992
+# Ported to 386BSD by Julian Elischer
+# julian@tfs.com
+#
+
+CFLAGS = -O -DDO_BAD144
+LIBS= -lc
+INC= -I../..
+
+# start.o should be first, table.o should be second
+OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o
+
+.SUFFIXES: .s .c .o
+
+# These are wierd because we don't want separate code and data segments.. ok?
+.c.o:
+ @echo $(CC) -c $(CFLAGS) $(INC) $*.c
+ -@trap "/bin/rm -f $*.i $*.s; exit 0" 0 1 2 3 10 15; \
+ $(CC) $(CFLAGS) $(INC) -S $<; \
+ if [ $$? != 0 ]; then :; else \
+ sed -f boot.sed $*.s > $*.i; \
+ $(AS) $*.i -o $@; \
+ fi
+
+.s.o:
+ @echo $(AS) -o $*.o $<
+ -@trap "/bin/rm -f $*.i X$*.c; exit 0" 0 1 2 3 10 15; \
+ /bin/rm -f X$*.c; \
+ ln $*.s X$*.c; \
+ $(CC) -E $(CFLAGS) X$*.c > $*.i; \
+ if [ $$? != 0 ]; then :; \
+ else \
+ $(AS) $*.i -o $@; \
+ fi
+
+
+boot: boot.sed $(OBJS)
+ $(LD) -N -T 0 -o boot $(OBJS) $(LIBS)
+ cp boot boot.sym
+ @strip boot
+ @./rmaouthdr boot boot.tmp
+ @mv -f boot.tmp boot
+ @ls -l boot
+
+biosboot: boot
+ dd if=boot of=biosboot count=1
+
+bootbios: boot
+ dd if=boot of=bootbios skip=1
+
+/usr/mdec/bootsd: bootbios
+ cp bootbios /usr/mdec/bootsd
+
+/usr/mdec/sdboot: biosboot
+ cp biosboot /usr/mdec/sdboot
+
+/usr/mdec/bootwd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootwd
+ ln /usr/mdec/bootsd /usr/mdec/bootwd
+
+/usr/mdec/wdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/wdboot
+ ln /usr/mdec/sdboot /usr/mdec/wdboot
+
+/usr/mdec/bootfd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootfd
+ ln /usr/mdec/bootsd /usr/mdec/bootfd
+
+/usr/mdec/fdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/fdboot
+ ln /usr/mdec/sdboot /usr/mdec/fdboot
+
+sd: /usr/mdec/bootsd /usr/mdec/sdboot
+wd: /usr/mdec/bootwd /usr/mdec/wdboot
+fd: /usr/mdec/bootfd /usr/mdec/fdboot
+
+#wd0: /usr/mdec/bootwd /usr/mdec/wdboot
+# disklabel -r -w wd0 julian julian5 /usr/mdec/wdboot /usr/mdec/bootwd
+#
+
+sd0: /usr/mdec/bootsd /usr/mdec/sdboot
+ disklabel -r -w sd0 XT-8760 scsitest /usr/mdec/sdboot /usr/mdec/bootsd
+
+
+#fd0: /usr/mdec/bootfd /usr/mdec/fdboot
+# disklabel -r -w fd0 floppy5 bootflpy /usr/mdec/fdboot /usr/mdec/bootfd
+#
+
+install: wd sd
+# you should use the old floppy booter, it's MUCH faster
+# This one works but it's too slow.
+# besides how many kernels can you fit on a floppy?
+# only use this one if you want to boot a kernel
+# from a hard disk 2 when you've trashed hard disk 1
+#install: wd sd fd
+
+clean:
+ /bin/rm -f *.o *.d boot bootbios biosboot boot.sym
+
+
diff --git a/sys/i386/boot/biosboot/README.386BSD b/sys/i386/boot/biosboot/README.386BSD
new file mode 100644
index 0000000..ae61346
--- /dev/null
+++ b/sys/i386/boot/biosboot/README.386BSD
@@ -0,0 +1,149 @@
+This Boot code is different from the original boot code that came with
+386BSD in that it uses the BIOS to load the kernel and to provide all i/o
+services. The advantage ofthis is that the same boot code exactly, can run
+on any device that is supported by the BIOS. (That's most of them)
+This is important for the 'generic scsi' project because it means we can
+write drivers for new scsi adapters without having to develop an new
+set of boot blocks for each.
+
+At this point you should read the first part of README.MACH... come back here
+when you have done that:
+
+In normal operation, when co-existing with other operating systems, the
+following operations occur:
+
+1/ the BIOS loads the first block of the disk (called the Master Boot Record
+or MBR) and if it has the correct magic numbers, jumps into it:
+
+2/ The MBR code, looks at the Partition table that is embedded within it,
+to detirmine which is the partition to boot from. If you are using the os-bs
+bootblocks (highly recommended) then it will give you a menu to choose from.
+
+3/ The MBR will load the first record of the selected partition and
+if it has (the same) magic numbers, jumps into it. In 386bsd this is the
+first stage boot, (or boot1) it is represented in /usr/mdec by
+wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning
+then this block will be at block zero, and will have been loaded directly by
+the BIOS.
+
+4/ Boot1 will look at block0 (which might be itself if there are no DOS
+partitions) and will find the 386bsd partition, and using the information
+regarding the start position of that partition, will load the next 13 sectors
+or so, to around 90000 (640k - 64k). and will jump into it at the appropriate
+entry point. Since boot1 and boot2 were compiled together as one file
+and then split later, boot1 knows the exact position within boot2 of the
+entry point.
+
+Boot 1 also contains a compiled in DOS partition table
+(in case it is at block 0), which contains a 386bsd partition starting
+at 0. This ensures that the same code can work whether or not
+boot1 is at block 0.
+
+5/ Boot2 asks the user for a boot device, partition and filename, and then
+loads the MBR of the selected device. This may or may not be the device
+which was originally used to boot the first MBR. The partition table
+of the new MBR is searched for a 386bsd partition, and if one is found,
+that is then in turn searched for the disklabel. This could all be on the
+second disk at this point, if the user selected it.
+
+6/On finding the disklabel, boot2 can find the correct unix partition
+within the 386bsd partition, and using cutdown filesystem code,
+look for the file to boot (e.g. 386bsd).
+
+7/ Boot2 loads this file starting at the location specified by the a.out header,
+(see later) and leaps into it at the location specified in he header.
+
+if the file does not exist or cannot be loaded, boot2 goes back to step 5.
+
+386bsd is now running and will hopefully start vm etc. and get to multi-user
+mode.
+
+##########################################################################
+During all these steps, all i/o is performed using the BIOS. This has a number
+of side effects:
+
+1/ Since BIOS disk calls are specified in terms of cylinder,head and sector,
+and the BIOS read the disk information from either the CMOS or from some other
+location which is un-available to us, we must use the cyl,head,sec information
+that is given in the MBR, rather than the start address in the MBR, because
+we cannot guarentee that we can corectly calculate C,H,S from the start address.
+
+Therefore, the C,H,S information in the MBR must be as correct for this boot
+to work as it would be for DOS to boot. For example, adaptec BIOS routines
+assume a layout of 64 heads and 32 sectors giving 1MB per ficticious cylinder.
+You must use these figures to calculate the correct values. Luckily, the DOS
+fdisk program will do all this for you if you tell it to give you a DOS
+partition, and you can change it to a 386BSD partition later. If you use
+no DOS partitioning, then the compiled in table in Boot1 will do just fine.
+
+If you want to do it by hand remember that BIOS counts sectors starting at 1.
+(cylinders and heads start at 0 (??))
+
+2/ you cannot overwrite the bottom 4k of ram until you have finished ALL
+bios calls, as BIOS uses this area as scratch memory.
+
+3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode,
+Boot 2 switches back to real mode just before each BIOS call and then
+back to protected mode on each return. Touch this at your peril.!
+
+#########################################################################
+In answering the prompt from Boot2:
+you can,
+1/ leave it alone.. it will boot the indicated file from the first
+partition of the first drive seen by the BIOS (C:)
+
+2/ enter only "-s" to boot the default to single user mode
+
+3/ enter only a filename (optionally with -s) to boot that kernel,
+
+4/ enter a whole line of the form shown in the prompt. This allows you to
+boot some other partition, possibly on the second drive, as root.
+
+
+##########################################################################
+In the case you have two drives the same type (both scsi or bith IDE/ESDI),
+wd(0,a)xxx
+ will boot xxx from drive 0, a partition.
+wd(1,a)xxx
+ will boot xxx from drive 1, a partition.
+
+similarly for sd.
+
+if you have one wd drive and one scsi drive, then you MUST
+use device 'hd'
+
+otherwise the following will happen:
+
+with wd0 and sd0, you specify sd1 or wd1 to indicate the 2nd drive.
+it boots the kernel correctly, then tells the kernel to use sd1 as root.
+you however may not have an sd1, and problems arise.
+
+hd is special in that the kernel is always told to use unit 0,
+The correct TYPE of device will be specified too, so the kernel
+will be told either sd0 or wd0.
+
+Whether sd or wd is specified to the kernel is read from the disklabel,
+so ensure that all SCSI disks have type SCSI in their disklabel or the
+boot code will assume they are ESDI or IDE. (Remember, because it is
+working through the BIOS it has ho idea what kind of disk it is.
+
+##########################################################################
+Installing:
+The makefile supplied has a target install which will create the
+files wdboot,bootwd ,sdboot and bootsd in /usr/mdec.
+BEWARE these will overwrite the existing wdboot and bootwd. (so back
+them up)
+
+there are also targets wd and sd which wil only do one of them
+
+The commented out targets wd0 and sd0 are examples of how to
+load the new bootblocks, however,make sure you change the
+device type and label to suit your drive if you uncomment them.
+(see 'man disklabel')
+
+If you already have made partitions using the old bootblocks
+these should install painlessly.
+
+Before you do this ensure you have a booting floppy with correct
+disktab and bootblock files on it so that if it doesn't work, you can
+re-disklabel from the floppy.
diff --git a/sys/i386/boot/biosboot/README.MACH b/sys/i386/boot/biosboot/README.MACH
new file mode 100644
index 0000000..d11f3e4
--- /dev/null
+++ b/sys/i386/boot/biosboot/README.MACH
@@ -0,0 +1,218 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer, September 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: README,v $
+ * Revision 2.2 92/04/04 11:33:55 rpd
+ * From 2.5
+ * [92/03/30 mg32]
+ *
+ */
+
+********NOTE: This is not all relevant to the 386BSD version**********
+
+ AT386 Protected Mode Bootstrap Loader
+ =====================================
+
+1. Overview of Startup
+ -------------------
+
+ After the system is rebooted, the BIOS bootstrap routine reads Sector
+ 1, Track 0 into memory at location 0000:7C00H. If location 0000:7DFEH
+ (last two bytes of that sector) contains the value AA55H, the BIOS
+ bootstrap routine will transfer control to 0000:7C00H. Otherwise, the
+ boot code in that sector is bad and the boot routine stops.
+
+ For DOS compatibility reason, one extra stage of boot is required if
+ the boot device is a hard disk. The first sector of the hard disk will
+ contain the MOS-DOS boot code and a boot record partition table.
+ When this sector is loaded into 0000:7C00H, it will relocate itself
+ to somewhere else and then load the first sector of the active
+ partition into 0000:7C00H. Both UNIX and DOS use the command "fdisk"
+[ 386bsd does not have an 'fdisk' (yet) ]
+ to install this first sector into the hard disk and to manipulate
+ the hard disk partitions.
+
+
+
+2. The First Stage Bootstrap Loader
+ --------------------------------
+
+ After startup, the first stage boot is loaded at 0000:7C00H. This
+ first stage boot will load itself and the second stage boot into
+ memory at location 0000:1000H. For floppy disks, the first cylinder
+ is reserved as the boot cylinder, and the boot code (first and second)
+ will be loaded from there. Currently, only double sided, high density
+ (15 sectors per track) floppies are supported. For hard disks, the
+ first 29 sectors of the active partition is reserved for boot code
+ which will be loaded by the first stage boot. All the disk types
+ recognized by BIOS are supported by this bootstrap loader.
+[for 386bsd we load the second stage booter to 9000:0]
+
+
+
+3. The Second Stage Bootstrap Loader
+ --------------------------------
+
+ After the boot code is loaded, the control is passed to the second
+ stage bootstrap loader "boot2()". In order to be able to load the
+ big kernel image (bigger than 512K or 640K, depends on the memory
+ configuration), the second stage boot loader will run on the protected
+ mode. This bootstarp loader does not have any stand alone device
+ drivers, all the I/O's are through the BIOS calls. Since the first
+ stage boot code will no longer be used at this moment, the memory
+ location of the first stage boot code (0000:1000H to 0000:1200H) will
+ be used as an internal buffer for BIOS calls. Immediately after this
+ internal buffer is the GDT table for the second stage boot loader.
+ Since this boot loader needs to switch back and forth between protected
+ and real mode in order to use BIOS calls, the limit of the boot code
+ and boot data segments must not be greater than 64K.
+
+ The boot loader loads the kernel image at memory location above 1 MB
+ to skip the memory hole between 521K/640K and 1MB. After the kernel
+ is loaded, the boot loader stores the information in the stack and
+ then passes control to kernel. Currently, the three information passed
+ fromm the boot loader to the kernel are type of the boot device, size
+ of the base memory and size of the extended memory.
+
+[ 386bsd receives: howto, bootdev]
+
+[ 386bsd is loaded where-ever the "MByte" bits of the load address specify,
+so if you link it for FE100000 it will load to 1MB, but if you link
+it for FE000000 it will load ad 0MB]
+
+[for machines with only 512KB normal ram the kernel will need to be linked
+for 1MB and the bootblocks modified to run below 512KB. (8000:0)]
+
+
+4. The UNIX Startup
+ ----------------
+
+ Since the boot loader loads the kernel image at memory location above
+ 1MB, the kernel has to start as protected mode. In addition, the
+ link editor description file (vuifile) has to indicate that
+ the text and data segments start above 1MB. Also, the boot loader
+ passes the infomation to the kernel through the stack.
+
+[MOST of what is mentionned below is NOT relevant to 386bsd]
+
+5. Disk Layout and Bad Block Handling
+ ---------------------------------
+
+ The System V/386 Release 3.2 (AT) disk layout will be used as the disk
+ layout for the MACH System on the AT platform.
+
+ This disk layout is as follows:
+
+ * Reserve the first sector of cylinder 0 for the DOS boot record which
+ contains the master boot code (446 bytes) and the partition table.
+ (Refer to DOS Technical Reference Manual page 9-6 to 9-10).
+
+ * Reserve the first 29 sectors of the UNIX partition for the first
+ and the second stage bootstrap.
+
+ * Reserve the 30th sector of the UNIX partition for the pdinfo and
+ the vtoc tables.
+
+ * Reserve the 31st to the 34th sectors of the UNIX partition for the
+ bad track and the bad block mapping tables.
+
+ * Reserve up to 253 consecutive tracks when required, beginning with
+ the 35th sector of the UNIX partition, for alternate tracks.
+
+ * Reserve up to 253 consecutive blocks, beginning with the first
+ sector after the alternate tracks area, for alternate blocks.
+
+ SEC
+ 1
+ ----------------------------------------------------
+ | X | | CYL 0, TRK 0
+ ---------------- .......... --------------------
+ | .......... |
+ ---------------- .......... --------------------
+ | .......... |
+ ===============================================================
+ ^ | BOOTSTRAP | CYL N, TRK M
+ | ----------------------------------------------------
+ | | |30 |31 |32 |33 |34 |
+ ---------------------------------------------------- ---
+ U | .......... | ^
+ N ---------------- .......... --------------------- |
+ I | .......... | Alternate Tracks
+ X ---------------- .......... --------------------- |
+ | .......... | V
+ P ---------------------------------------------------- ---
+ A | .......... | ^
+ R ---------------- .......... --------------------- |
+ T | .......... | Alternate Blocks
+ I ---------------- .......... -------------------- |
+ T | .......... | V
+ I ---------------------------------------------------- ---
+ O | Unix root partition starts from here |
+ N ---------------- -----------------
+ | |
+ ----------------------------------------------------
+ | |
+ ----------------------------------------------------
+ | |
+ | ---------------------------------------------------
+ | | |
+ | ----------------------------------------------------
+ V | |
+ ===============================================================
+ | ........ |
+ --------------- ........ --------------
+ | ........ |
+ ----------------------------------------------------
+
+
+ The bad block handling mechanism is as follows:
+
+ * Use the alternate track in the alternate tracks area if the
+ track containing the target sector is bad.
+
+ * Use the alternate block in the alternate blocks area if the
+ target sector is bad.
+
+
+
+
+6. How to make:
+ -----------
+
+ Since the kernel image is loaded above 1 MB, the kernel must start
+ as protected mode. This means that this bootstrap loader will work
+ only when the corresponding changes on the kernel startup code are done.
+
+ The make command to generate this bootstrap loader is:
+
+ make -f boot.mk fdboot (floppy boot loader)
+ make -f boot.mk hdboot (wini boot loader)
+[to make 386bsd bootblocks "make sd wd" (warning: they will be installed
+in /dev/mdec.. take backups)]
diff --git a/sys/i386/boot/biosboot/asm.h b/sys/i386/boot/biosboot/asm.h
new file mode 100644
index 0000000..9b86637
--- /dev/null
+++ b/sys/i386/boot/biosboot/asm.h
@@ -0,0 +1,192 @@
+/*
+ * Ported to Boot 386BSD by Julian Elsicher (julian@tfs.com) Sept. 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: asm.h,v $
+ * Revision 2.7 92/02/29 15:33:41 rpd
+ * Added ENTRY2.
+ * [92/02/28 rpd]
+ *
+ * Revision 2.6 92/02/19 15:07:52 elf
+ * Changed #if __STDC__ to #ifdef __STDC__
+ * [92/01/16 jvh]
+ *
+ * Revision 2.5 91/05/14 16:02:45 mrt
+ * Correcting copyright
+ *
+ * Revision 2.4 91/02/05 17:10:42 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:30:29 mrt]
+ *
+ * Revision 2.3 90/12/20 16:35:27 jeffreyh
+ * changes for __STDC__
+ * [90/12/06 jeffreyh]
+ *
+ * Revision 2.2 90/05/03 15:24:12 dbg
+ * First checkin.
+ *
+ *
+ * Typo on ENTRY if gprof
+ * [90/03/29 rvb]
+ *
+ * fix SVC for "ifdef wheeze" [kupfer]
+ * Fix the GPROF definitions.
+ * ENTRY(x) gets profiled iffdef GPROF.
+ * Entry(x) (and DATA(x)) is NEVER profiled.
+ * MCOUNT can be used by asm that intends to build a frame,
+ * after the frame is built.
+ * [90/02/26 rvb]
+ *
+ * Add #define addr16 .byte 0x67
+ * [90/02/09 rvb]
+ * Added LBi, SVC and ENTRY
+ * [89/11/10 09:51:33 rvb]
+ *
+ * New a.out and coff compatible .s files.
+ * [89/10/16 rvb]
+ */
+
+
+#define S_ARG0 4(%esp)
+#define S_ARG1 8(%esp)
+#define S_ARG2 12(%esp)
+#define S_ARG3 16(%esp)
+
+#define FRAME pushl %ebp; movl %esp, %ebp
+#define EMARF leave
+
+#define B_ARG0 8(%ebp)
+#define B_ARG1 12(%ebp)
+#define B_ARG2 16(%ebp)
+#define B_ARG3 20(%ebp)
+
+#ifdef wheeze
+
+#define ALIGN 4
+#define EXT(x) x
+#define LEXT(x) x:
+#define LCL(x) ./**/x
+
+#define LB(x,n) ./**/x
+#define LBb(x,n) ./**/x
+#define LBf(x,n) ./**/x
+
+#define SVC lcall $7,$0
+
+#define String .string
+#define Value .value
+#define Times(a,b) [a\*b]
+#define Divide(a,b) [a\\b]
+
+#define INB inb (%dx)
+#define OUTB outb (%dx)
+#define INL inl (%dx)
+#define OUTL outl (%dx)
+
+#else wheeze
+#define ALIGN
+#define LCL(x) x
+
+#define LB(x,n) n
+#ifdef __STDC__
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define LBb(x,n) n ## b
+#define LBf(x,n) n ## f
+#else __STDC__
+#define EXT(x) _/**/x
+#define LEXT(x) _/**/x/**/:
+#define LBb(x,n) n/**/b
+#define LBf(x,n) n/**/f
+#endif __STDC__
+#define SVC .byte 0x9a; .long 0; .word 0x7
+
+#define String .ascii
+#define Value .word
+#define Times(a,b) (a*b)
+#define Divide(a,b) (a/b)
+
+#define INB inb %dx, %al
+#define OUTB outb %al, %dx
+#define INL inl %dx, %eax
+#define OUTL outl %eax, %dx
+
+#endif wheeze
+
+#define data32 .byte 0x66
+#define data16 .byte 0x66
+#define addr16 .byte 0x67
+
+
+
+#ifdef GPROF
+#ifdef __STDC__
+
+#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#else __STDC__
+
+#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x: ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#endif __STDC__
+#else GPROF
+#ifdef __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x ## :
+
+#else __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x:
+
+#endif __STDC__
+#endif GPROF
+
+#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
diff --git a/sys/i386/boot/biosboot/boot.c b/sys/i386/boot/biosboot/boot.c
new file mode 100644
index 0000000..805303e
--- /dev/null
+++ b/sys/i386/boot/biosboot/boot.c
@@ -0,0 +1,323 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00159
+ * -------------------- ----- ----------------------
+ *
+ * 23 May 93 Rodney W. Grimes Added pad to kernel size for structs
+ * allocated by locore.s
+ */
+
+/*
+ * HISTORY
+ * $Log: boot.c,v $
+ * Revision 2.2 92/04/04 11:34:37 rpd
+ * Change date in banner.
+ * [92/04/03 16:51:14 rvb]
+ *
+ * Fix Intel Copyright as per B. Davies authorization.
+ * [92/04/03 rvb]
+ * From 2.5 version.
+ * [92/03/30 mg32]
+ *
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <sys/param.h>
+#include "boot.h"
+#include <a.out.h>
+#include <sys/reboot.h>
+
+
+struct exec head;
+int argv[10], esym;
+char *name;
+char *names[] = {
+ "/386bsd", "/386bsd.old",
+ "/vmunix", "/vmunix.old"
+};
+#define NUMNAMES (sizeof(names)/sizeof(char *))
+
+extern int end;
+boot(drive)
+int drive;
+{
+ int loadflags, currname = 0;
+ printf("\n>> 386bsd BOOT @ 0x%x: %d/%d k of memory [20/9/92]\n",
+ ouraddr,
+ argv[7] = memsize(0),
+ argv[8] = memsize(1));
+ printf("use options hd(1,...... to boot sd0 when wd0 is also installed\n");
+ gateA20();
+loadstart:
+ /***************************************************************\
+ * As a default set it to the first partition of the first *
+ * floppy or hard drive *
+ \***************************************************************/
+ part = unit = 0;
+ maj = (drive&0x80 ? 0 : 2); /* a good first bet */
+ name = names[currname++];
+
+ loadflags = 0;
+ if (currname == NUMNAMES)
+ currname = 0;
+ getbootdev(&loadflags);
+ if (openrd()) {
+ printf("Can't find %s\n", name);
+ goto loadstart;
+ }
+/* if (inode.i_mode&IEXEC)
+ loadflags |= RB_KDB;
+*/
+ loadprog(loadflags);
+ goto loadstart;
+}
+
+loadprog(howto)
+ int howto;
+{
+ long int startaddr;
+ long int addr; /* physical address.. not directly useable */
+ int i;
+ static int (*x_entry)() = 0;
+ unsigned char tmpbuf[4096]; /* we need to load the first 4k here */
+
+ argv[3] = 0;
+ argv[4] = 0;
+ read(&head, sizeof(head));
+ if (head.a_magic == 0413 )
+ {
+ poff = 4096;
+ }
+ else
+ {
+ printf("Invalid format!\n");
+ return;
+ }
+
+ startaddr = (int)head.a_entry;
+ addr = (startaddr & 0x00f00000); /* some MEG boundary */
+ printf("Booting %s(%d,%c)%s @ 0x%x\n"
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name
+ , addr);
+ if(addr < ouraddr)
+ {
+ if((addr + head.a_text + head.a_data) > ouraddr)
+ {
+ printf("kernel will not fit below loader\n");
+ return;
+ }
+ /*
+ * The +28672 is for memory allocated by locore.s that must
+ * fit in the bss!
+ */
+ if((addr + head.a_text + head.a_data + head.a_bss + 28672) > 0xa0000)
+ {
+ printf("kernel too big, won't fit in 640K with bss\n");
+ printf("Only hope is to link the kernel for > 1MB\n");
+ return;
+ }
+ if((addr + head.a_text + head.a_data + head.a_bss) > ouraddr)
+ {
+ printf("loader overlaps bss, kernel must bzero\n");
+ }
+ }
+ printf("text=0x%x", head.a_text);
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /* don't clobber the first 4k yet (BIOS NEEDS IT) */
+ /********************************************************/
+ read(tmpbuf,4096);
+ addr += 4096;
+ xread(addr, head.a_text - 4096);
+ addr += head.a_text - 4096;
+
+ /********************************************************/
+ /* Load the Initialised data after the text */
+ /********************************************************/
+ while (addr & CLOFSET)
+ *(char *)addr++ = 0;
+
+ printf(" data=0x%x", head.a_data);
+ xread(addr, head.a_data);
+ addr += head.a_data;
+
+ /********************************************************/
+ /* Skip over the uninitialised data */
+ /* (but clear it) */
+ /********************************************************/
+ printf(" bss=0x%x", head.a_bss);
+ if( (addr < ouraddr) && ((addr + head.a_bss) > ouraddr))
+ {
+ pbzero(addr,ouraddr - (int)addr);
+ }
+ else
+ {
+ pbzero(addr,head.a_bss);
+ }
+ argv[3] = (addr += head.a_bss);
+
+#ifdef LOADSYMS /* not yet, haven't worked this out yet */
+ if (addr > 0x100000)
+ {
+ /********************************************************/
+ /*copy in the symbol header */
+ /********************************************************/
+ pcpy(&head.a_syms, addr, sizeof(head.a_syms));
+ addr += sizeof(head.a_syms);
+
+ /********************************************************/
+ /* READ in the symbol table */
+ /********************************************************/
+ printf(" symbols=[+0x%x", head.a_syms);
+ xread(addr, head.a_syms);
+ addr += head.a_syms;
+
+ /********************************************************/
+ /* Followed by the next integer (another header) */
+ /* more debug symbols? */
+ /********************************************************/
+ read(&i, sizeof(int));
+ pcpy(&i, addr, sizeof(int));
+ i -= sizeof(int);
+ addr += sizeof(int);
+
+
+ /********************************************************/
+ /* and that many bytes of (debug symbols?) */
+ /********************************************************/
+ printf("+0x%x]", i);
+ xread(addr, i);
+ addr += i;
+ }
+#endif LOADSYMS
+ /********************************************************/
+ /* and note the end address of all this */
+ /********************************************************/
+
+ argv[4] = ((addr+sizeof(int)-1))&~(sizeof(int)-1);
+ printf(" total=0x%x",argv[4]);
+
+
+ /*
+ * We now pass the various bootstrap parameters to the loaded
+ * image via the argument list
+ * (THIS IS A BIT OF HISTORY FROM MACH.. LEAVE FOR NOW)
+ * arg1 = boot flags
+ * arg2 = boot device
+ * arg3 = start of symbol table (0 if not loaded)
+ * arg4 = end of symbol table (0 if not loaded)
+ * arg5 = transfer address from image
+ * arg6 = transfer address for next image pointer
+ */
+ switch(maj)
+ {
+ case 2:
+ printf("\n\nInsert file system floppy \n");
+ getchar();
+ break;
+ case 4:
+ break;
+ }
+ argv[1] = howto;
+ argv[2] = (MAKEBOOTDEV(maj, 0, 0, unit, part)) ;
+ argv[5] = (head.a_entry &= 0xfffffff);
+ argv[6] = (int) &x_entry;
+ argv[0] = 8;
+ /****************************************************************/
+ /* copy that first page and overwrite any BIOS variables */
+ /****************************************************************/
+ printf(" entry point=0x%x \n" ,((int)startaddr) & 0xffffff);
+ pcpy(tmpbuf, 0, 4096);
+ startprog(((int)startaddr & 0xffffff),argv);
+}
+
+char namebuf[100];
+getbootdev(howto)
+ int *howto;
+{
+ char c, *ptr = namebuf;
+ printf("Boot: [[[%s(%d,%c)]%s][-s][-a][-d]] :- "
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name);
+ if (gets(namebuf)) {
+ while (c=*ptr) {
+ while (c==' ')
+ c = *++ptr;
+ if (!c)
+ return;
+ if (c=='-')
+ while ((c = *++ptr) && c!=' ')
+ switch (c) {
+ case 'a':
+ *howto |= RB_ASKNAME; continue;
+ case 's':
+ *howto |= RB_SINGLE; continue;
+ case 'd':
+ *howto |= RB_KDB; continue;
+ case 'b':
+ *howto |= RB_HALT; continue;
+ }
+ else {
+ name = ptr;
+ while ((c = *++ptr) && c!=' ');
+ if (c)
+ *ptr++ = 0;
+ }
+ }
+ }
+}
+
diff --git a/sys/i386/boot/biosboot/boot.h b/sys/i386/boot/biosboot/boot.h
new file mode 100644
index 0000000..28a7a22
--- /dev/null
+++ b/sys/i386/boot/biosboot/boot.h
@@ -0,0 +1,48 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: boot.h,v $
+ * Revision 2.2 92/04/04 11:35:03 rpd
+ * Fabricated from 3.0 bootstrap. But too many things are global.
+ * [92/03/30 mg32]
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ufs/quota.h>
+#include <ufs/fs.h>
+#include <ufs/inode.h>
+
+extern char *devs[], *name, *iodest;
+extern struct fs *fs;
+extern struct inode inode;
+extern int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+extern long int ouraddr;
diff --git a/sys/i386/boot/biosboot/disk.c b/sys/i386/boot/biosboot/disk.c
new file mode 100644
index 0000000..87b30b2
--- /dev/null
+++ b/sys/i386/boot/biosboot/disk.c
@@ -0,0 +1,238 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: disk.c,v $
+ * Revision 2.2 92/04/04 11:35:49 rpd
+ * Fabricated from 3.0 bootstrap and 2.5 boot disk.c:
+ * with support for scsi
+ * [92/03/30 mg32]
+ *
+ */
+
+/*
+ * 9/20/92
+ * Peng-Toh Sim. sim@cory.berkeley.edu
+ * Added bad144 support under 386bsd for wd's
+ * So, bad block remapping is done when loading the kernel.
+ */
+
+#include "boot.h"
+#ifdef DO_BAD144
+#include <sys/dkbad.h>
+#endif DO_BAD144
+#include <sys/disklabel.h>
+
+#define BIOS_DEV_FLOPPY 0x0
+#define BIOS_DEV_WIN 0x80
+
+#define BPS 512
+#define SPT(di) ((di)&0xff)
+#define HEADS(di) ((((di)>>8)&0xff)+1)
+
+char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0};
+
+#ifdef DO_BAD144
+struct dkbad dkb;
+int do_bad144;
+int bsize;
+#endif DO_BAD144
+
+int spt, spc;
+
+char *iodest;
+struct fs *fs;
+struct inode inode;
+int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+
+/*#define EMBEDDED_DISKLABEL 1*/
+extern struct disklabel disklabel;
+/*struct disklabel disklabel;*/
+
+devopen()
+{
+ struct dos_partition *dptr;
+ struct disklabel *dl;
+ int dosdev = inode.i_dev;
+ int i, sector, di;
+
+ di = get_diskinfo(dosdev);
+ spc = (spt = SPT(di)) * HEADS(di);
+ if (dosdev == 2)
+ {
+ boff = 0;
+ part = (spt == 15 ? 3 : 1);
+ }
+ else
+ {
+#ifdef EMBEDDED_DISKLABEL
+ dl = &disklabel;
+#else EMBEDDED_DISKLABEL
+ Bread(dosdev, 0);
+ dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF);
+ for (i = 0; i < NDOSPART; i++, dptr++)
+ if (dptr->dp_typ == DOSPTYP_386BSD)
+ break;
+ sector = dptr->dp_start + LABELSECTOR;
+ Bread(dosdev, sector++);
+ dl=((struct disklabel *)0);
+ disklabel = *dl; /* structure copy (maybe useful later)*/
+#endif EMBEDDED_DISKLABEL
+ if (dl->d_magic != DISKMAGIC) {
+ printf("bad disklabel");
+ return 1;
+ }
+ if( (maj == 4) || (maj == 0) || (maj == 1))
+ {
+ if (dl->d_type == DTYPE_SCSI)
+ {
+ maj = 4; /* use scsi as boot dev */
+ }
+ else
+ {
+ maj = 0; /* must be ESDI/IDE */
+ }
+ }
+ boff = dl->d_partitions[part].p_offset;
+#ifdef DO_BAD144
+ bsize = dl->d_partitions[part].p_size;
+ do_bad144 = 0;
+ if (dl->d_flags & D_BADSECT) {
+ /* this disk uses bad144 */
+ int i;
+ int dkbbnum;
+ struct dkbad *dkbptr;
+
+ /* find the first readable bad144 sector */
+ /* some of this code is copied from ufs/disk_subr.c */
+ /* read a bad sector table */
+ dkbbnum = dl->d_secperunit - dl->d_nsectors;
+ if (dl->d_secsize > DEV_BSIZE)
+ dkbbnum *= dl->d_secsize / DEV_BSIZE;
+ else
+ dkbbnum /= DEV_BSIZE / dl->d_secsize;
+ i = 0;
+ do_bad144 = 0;
+ do {
+ /* XXX: what if the "DOS sector" < 512 bytes ??? */
+ Bread(dosdev, dkbbnum + i);
+ dkbptr = (struct dkbad *) 0;
+/* XXX why is this not in <sys/dkbad.h> ??? */
+#define DKBAD_MAGIC 0x4321
+ if (dkbptr->bt_mbz == 0 &&
+ dkbptr->bt_flag == DKBAD_MAGIC) {
+ dkb = *dkbptr; /* structure copy */
+ do_bad144 = 1;
+ break;
+ }
+ i += 2;
+ } while (i < 10 && i < dl->d_nsectors);
+ if (!do_bad144)
+ printf("Bad badsect table\n");
+ else
+ printf("Using bad144 bad sector at %d\n", dkbbnum+i);
+ }
+#endif DO_BAD144
+ }
+ return 0;
+}
+
+devread()
+{
+ int offset, sector = bnum;
+ int dosdev = inode.i_dev;
+ for (offset = 0; offset < cnt; offset += BPS)
+ {
+ Bread(dosdev, badsect(dosdev, sector++));
+ bcopy(0, iodest+offset, BPS);
+ }
+}
+
+Bread(dosdev,sector)
+ int dosdev,sector;
+{
+ int cyl = sector/spc, head = (sector%spc)/spt, secnum = sector%spt;
+ while (biosread(dosdev, cyl,head,secnum))
+ {
+ printf("Error: C:%d H:%d S:%d\n",cyl,head,secnum);
+ }
+}
+
+badsect(dosdev, sector)
+ int dosdev, sector;
+{
+ int i;
+#ifdef DO_BAD144
+ if (do_bad144) {
+ u_short cyl;
+ u_short head;
+ u_short sec;
+ int newsec;
+ struct disklabel *dl = &disklabel;
+
+ /* XXX */
+ /* from wd.c */
+ /* bt_cyl = cylinder number in sorted order */
+ /* bt_trksec is actually (head << 8) + sec */
+
+ /* only remap sectors in the partition */
+ if (sector < boff || sector >= boff + bsize) {
+ goto no_remap;
+ }
+
+ cyl = sector / dl->d_secpercyl;
+ head = (sector % dl->d_secpercyl) / dl->d_nsectors;
+ sec = sector % dl->d_nsectors;
+ sec = (head<<8) + sec;
+
+ /* now, look in the table for a possible bad sector */
+ for (i=0; i<126; i++) {
+ if (dkb.bt_bad[i].bt_cyl == cyl) {
+ /* found same cylinder */
+ if (dkb.bt_bad[i].bt_trksec == sec) {
+ /* FOUND! */
+ break;
+ }
+ } else if (dkb.bt_bad[i].bt_cyl > cyl) {
+ i = 126;
+ break;
+ }
+ }
+ if (i == 126) {
+ /* didn't find bad sector */
+ goto no_remap;
+ }
+ /* otherwise find replacement sector */
+ newsec = dl->d_secperunit - dl->d_nsectors - i -1;
+ return newsec;
+ }
+#endif DO_BAD144
+ no_remap:
+ return sector;
+}
diff --git a/sys/i386/boot/biosboot/io.c b/sys/i386/boot/biosboot/io.c
new file mode 100644
index 0000000..237b21c
--- /dev/null
+++ b/sys/i386/boot/biosboot/io.c
@@ -0,0 +1,189 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: io.c,v $
+ * Revision 2.2 92/04/04 11:35:57 rpd
+ * Fixed for IBM L40's A20 initialization.
+ * [92/03/30 rvb]
+ *
+ * Created.
+ * [92/03/30 mg32]
+ *
+ */
+
+#include <i386/include/pio.h>
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+unsigned char x_20 = KB_A20;
+gateA20()
+{
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+}
+
+/* printf - only handles %d as decimal, %c as char, %s as string */
+
+printf(format,data)
+ char *format;
+ int data;
+{
+ int *dataptr = &data;
+ char c;
+ while (c = *format++)
+ if (c != '%')
+ putchar(c);
+ else
+ switch (c = *format++) {
+ case 'd': {
+ int num = *dataptr++;
+ char buf[10], *ptr = buf;
+ if (num<0) {
+ num = -num;
+ putchar('-');
+ }
+ do
+ *ptr++ = '0'+num%10;
+ while (num /= 10);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'x': {
+ int num = *dataptr++, dig;
+ char buf[8], *ptr = buf;
+ do
+ *ptr++ = (dig=(num&0xf)) > 9?
+ 'a' + dig - 10 :
+ '0' + dig;
+ while (num >>= 4);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'c': putchar((*dataptr++)&0xff); break;
+ case 's': {
+ char *ptr = (char *)*dataptr++;
+ while (c = *ptr++)
+ putchar(c);
+ break;
+ }
+ }
+}
+
+putchar(c)
+{
+ if (c == '\n')
+ putc('\r');
+ putc(c);
+}
+
+getchar()
+{
+ int c;
+
+ if ((c=getc()) == '\r')
+ c = '\n';
+ if (c == '\b') {
+ putchar('\b');
+ putchar(' ');
+ }
+ putchar(c);
+ return(c);
+}
+
+gets(buf)
+char *buf;
+{
+ int i;
+ char *ptr=buf;
+
+ for (i = 240000; i>0; i--)
+ if (ischar())
+ for (;;)
+ switch(*ptr = getchar() & 0xff) {
+ case '\n':
+ case '\r':
+ *ptr = '\0';
+ return 1;
+ case '\b':
+ if (ptr > buf) ptr--;
+ continue;
+ default:
+ ptr++;
+ }
+ return 0;
+}
+
+strcmp(s1, s2)
+char *s1, *s2;
+{
+ while (*s1 == *s2) {
+ if (!*s1++)
+ return 0;
+ s2++;
+ }
+ return 1;
+}
+
+bcopy(from, to, len)
+char *from, *to;
+int len;
+{
+ while (len-- > 0)
+ *to++ = *from++;
+}
diff --git a/sys/i386/boot/biosboot/sys.c b/sys/i386/boot/biosboot/sys.c
new file mode 100644
index 0000000..bb34340
--- /dev/null
+++ b/sys/i386/boot/biosboot/sys.c
@@ -0,0 +1,240 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: sys.c,v $
+ * Revision 2.2 92/04/04 11:36:34 rpd
+ * Fabricated from 3.0 bootstrap and scratch.
+ * [92/03/30 mg32]
+ *
+ */
+
+#include "boot.h"
+#include <sys/dir.h>
+#include <sys/reboot.h>
+
+/* #define BUFSIZE 4096 */
+#define BUFSIZE MAXBSIZE
+
+char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
+
+int xread(addr, size)
+ char * addr;
+ int size;
+{
+ int count = BUFSIZE;
+ while (size > 0) {
+ if (BUFSIZE > size)
+ count = size;
+ read(buf, count);
+ pcpy(buf, addr, count);
+ size -= count;
+ addr += count;
+ }
+}
+
+read(buffer, count)
+ int count;
+ char *buffer;
+{
+ int logno, off, size;
+ int cnt2, bnum2;
+
+ while (count) {
+ off = blkoff(fs, poff);
+ logno = lblkno(fs, poff);
+ cnt2 = size = blksize(fs, &inode, logno);
+ bnum2 = fsbtodb(fs, block_map(logno)) + boff;
+ cnt = cnt2;
+ bnum = bnum2;
+ if ( (!off) && (size <= count))
+ {
+ iodest = buffer;
+ devread();
+ }
+ else
+ {
+ iodest = iobuf;
+ size -= off;
+ if (size > count)
+ size = count;
+ devread();
+ bcopy(iodest+off,buffer,size);
+ }
+ buffer += size;
+ count -= size;
+ poff += size;
+ }
+}
+
+find(path)
+ char *path;
+{
+ char *rest, ch;
+ int block, off, loc, ino = ROOTINO;
+ struct direct *dp;
+loop: iodest = iobuf;
+ cnt = fs->fs_bsize;
+ bnum = fsbtodb(fs,itod(fs,ino)) + boff;
+ devread();
+ bcopy(&((struct dinode *)iodest)[ino % fs->fs_inopb],
+ &inode.i_din,
+ sizeof (struct dinode));
+ if (!*path)
+ return 1;
+ while (*path == '/')
+ path++;
+ if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
+ return 0;
+ for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
+ *rest = 0;
+ loc = 0;
+ do {
+ if (loc >= inode.i_size)
+ return 0;
+ if (!(off = blkoff(fs, loc))) {
+ block = lblkno(fs, loc);
+ cnt = blksize(fs, &inode, block);
+ bnum = fsbtodb(fs, block_map(block)) + boff;
+ iodest = iobuf;
+ devread();
+ }
+ dp = (struct direct *)(iodest + off);
+ loc += dp->d_reclen;
+ } while (!dp->d_ino || strcmp(path, dp->d_name));
+ ino = dp->d_ino;
+ *(path = rest) = ch;
+ goto loop;
+}
+
+char mapbuf[MAXBSIZE];
+int mapblock = 0;
+
+block_map(file_block)
+ int file_block;
+{
+ if (file_block < NDADDR)
+ return(inode.i_db[file_block]);
+ if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
+ iodest = mapbuf;
+ cnt = fs->fs_bsize;
+ devread();
+ mapblock = bnum;
+ }
+ return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
+}
+
+openrd()
+{
+ char **devp, *cp = name;
+ /*******************************************************\
+ * If bracket given look for preceding device name *
+ \*******************************************************/
+ while (*cp && *cp!='(')
+ cp++;
+ if (!*cp)
+ {
+ cp = name;
+ }
+ else
+ {
+ if (cp++ != name)
+ {
+ for (devp = devs; *devp; devp++)
+ if (name[0] == (*devp)[0] &&
+ name[1] == (*devp)[1])
+ break;
+ if (!*devp)
+ {
+ printf("Unknown device\n");
+ return 1;
+ }
+ maj = devp-devs;
+ }
+ /*******************************************************\
+ * Look inside brackets for unit number, and partition *
+ \*******************************************************/
+ if (*cp >= '0' && *cp <= '9')
+ if ((unit = *cp++ - '0') > 1)
+ {
+ printf("Bad unit\n");
+ return 1;
+ }
+ if (!*cp || (*cp == ',' && !*++cp))
+ return 1;
+ if (*cp >= 'a' && *cp <= 'p')
+ part = *cp++ - 'a';
+ while (*cp && *cp++!=')') ;
+ if (!*cp)
+ return 1;
+ }
+ switch(maj)
+ {
+ case 1:
+ dosdev = unit | 0x80;
+ unit = 0;
+ break;
+ case 0:
+ case 4:
+ dosdev = unit | 0x80;
+ break;
+ case 2:
+ dosdev = unit;
+ break;
+ case 3:
+ printf("Wangtek unsupported\n");
+ return 1;
+ break;
+ }
+ inode.i_dev = dosdev;
+ /***********************************************\
+ * Now we know the disk unit and part, *
+ * Load disk info, (open the device) *
+ \***********************************************/
+ if (devopen())
+ return 1;
+
+ /***********************************************\
+ * Load Filesystem info (mount the device) *
+ \***********************************************/
+ iodest = (char *)(fs = (struct fs *)fsbuf);
+ cnt = SBSIZE;
+ bnum = SBLOCK + boff;
+ devread();
+ /***********************************************\
+ * Find the actual FILE on the mounted device *
+ \***********************************************/
+ if (!find(cp))
+ {
+ return 1;
+ }
+ poff = 0;
+ name = cp;
+ return 0;
+}
diff --git a/sys/i386/boot/biosboot/table.c b/sys/i386/boot/biosboot/table.c
new file mode 100644
index 0000000..c26490a
--- /dev/null
+++ b/sys/i386/boot/biosboot/table.c
@@ -0,0 +1,112 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: table.c,v $
+ * Revision 2.2 92/04/04 11:36:43 rpd
+ * Fix Intel Copyright as per B. Davies authorization.
+ * [92/04/03 rvb]
+ * Taken from 2.5 bootstrap.
+ * [92/03/30 rvb]
+ *
+ * Revision 2.2 91/04/02 14:42:22 mbj
+ * Add Intel copyright
+ * [90/02/09 rvb]
+ *
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#define NGDTENT 6
+#define GDTLIMIT 48 /* NGDTENT * 8 */
+
+/* Segment Descriptor
+ *
+ * 31 24 19 16 7 0
+ * ------------------------------------------------------------
+ * | | |B| |A| | | |1|0|E|W|A| |
+ * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
+ * | | |D| |L| 19..16| | |1|1|C|R|A| |
+ * ------------------------------------------------------------
+ * | | |
+ * | BASE 15..0 | LIMIT 15..0 |
+ * | | |
+ * ------------------------------------------------------------
+ */
+
+struct seg_desc {
+ unsigned short limit_15_0;
+ unsigned short base_15_0;
+ unsigned char base_23_16;
+ unsigned char bit_15_8;
+ unsigned char bit_23_16;
+ unsigned char base_31_24;
+ };
+
+
+struct seg_desc Gdt[NGDTENT] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */
+ {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */
+ {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */
+ {0xFFFF, 0x0000, 0x9, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */
+ {0xFFFF, 0x0000, 0x9, 0x92, 0x40, 0x0}, /* 0x20 : boot data */
+ {0xFFFF, 0x0000, 0x9, 0x9E, 0x0, 0x0} /* 0x28 : boot code, 16 bits */
+ };
+
+
+struct pseudo_desc {
+ unsigned short limit;
+ unsigned short base_low;
+ unsigned short base_high;
+ };
+
+struct pseudo_desc Gdtr = { GDTLIMIT, 0x0400, 9 };
+struct pseudo_desc Gdtr2 = { GDTLIMIT, 0xfe00, 9 };
+ /* boot is loaded at 0x90000, Gdt is at boot+1024 */
diff --git a/sys/i386/conf/GENERICAH b/sys/i386/conf/GENERICAH
new file mode 100644
index 0000000..5f8ed03
--- /dev/null
+++ b/sys/i386/conf/GENERICAH
@@ -0,0 +1,95 @@
+#
+# GENERICISA -- Generic ISA machine -- distribution floppy
+#
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00158
+# -------------------- ----- ----------------------
+#
+# 09 Feb 93 Nate Williams Added options for X code to
+# compiled in by default
+# 29 Mar 93 Rodney W. Grimes Fixed com ports to be com0, com1
+# Added com2, com3, lpt, lpa
+# Replaced as0 with Julian SCSI
+# Fixed secound wd0 to be wd1
+# Cleaned up file, added comments
+# Added ahb, order is important!
+# Added pseudo-device speaker
+# Note: All IO_xxx names are 1 based
+# 17 May 93 Rodney W. Grimes Updated IRQ's 2 to IRQ 9's for
+# intr-0.1 code. Changed ahb0 from
+# irq 12 to irq 11 the real default
+#
+
+machine "i386"
+cpu "i386"
+ident GENERICISA
+timezone 8 dst
+maxusers 10
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+
+config "386bsd" root on wd0 swap on wd0 and sd0
+
+controller isa0
+
+controller fd0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fd0 drive 0
+disk fd1 at fd0 drive 1
+
+controller wd0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wd0 drive 0
+disk wd1 at wd0 drive 1
+
+controller ahb0 at isa? bio irq 11 vector ahbintr
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+controller scbus0
+
+device sd0
+device sd1
+device sd2
+device sd3
+
+device st0
+device st1
+device st2
+device st3
+
+device cd0
+device cd1
+
+device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device com0 at isa? port "IO_COM1" tty irq 4 vector comintr
+device com1 at isa? port "IO_COM2" tty irq 3 vector comintr
+device com2 at isa? port "IO_COM3" tty irq 5 vector comintr
+device com3 at isa? port "IO_COM4" tty irq 9 vector comintr
+
+device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
+device lpa0 at isa? port "IO_LPT1" tty
+device lpa1 at isa? port "IO_LPT2" tty
+
+device we0 at isa? port 0x280 net irq 9 iomem 0xd0000 iosiz 8192 vector weintr
+device ne0 at isa? port 0x300 net irq 9 vector neintr
+device ec0 at isa? port 0x250 net irq 9 iomem 0xd8000 iosiz 8192 vector ecintr
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 4
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386
new file mode 100644
index 0000000..7eedfb8
--- /dev/null
+++ b/sys/i386/conf/Makefile.i386
@@ -0,0 +1,164 @@
+# Copyright 1990 W. Jolitz
+# @(#)Makefile.i386 7.1 5/10/91
+# Makefile for 4.3 BSD-Reno
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00158
+# -------------------- ----- ----------------------
+#
+# 29 Jun 92 Chris G. Demetriou Fix vers.o for kernel profiling and
+# plain old link
+# 25 Mar 93 Sean Eric Fagan Add support for assembler source
+# 25 Apr 93 Bruce Evans Support for intr-0.0, and some fixes
+# Rodney W. Grimes Added depedencies for conf.o due to
+# all the new drivers. And to param.c
+# because there were missing.
+# 26 May 97 Rodney W. Grimes Remove extra SYSTEM_LD_TAIL
+# Redirect stderr from dbsym to null,
+# this is bad, but atleast I won't get
+# 100's of bug reports about the silly
+# warning from dbsym.
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+
+S= ../..
+I386= ../../i386
+
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= -O ${COPTS}
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o ${OBJS} param.o ioconf.o conf.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -z -T FE000000 -o $@ -X vers.o ${SYSTEM_OBJS}
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ dbsym $@ 2>/dev/null || true; size $@; chmod 755 $@
+
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ex - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym
+
+lint: /tmp param.c
+ @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+ ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+ grep -v 'struct/union .* never defined' | \
+ grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h ${I386}/isa/debug.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depend on maxusers
+assym.s machdep.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ $S/sys/vmmeter.h \
+ $S/sys/proc.h $S/sys/msgbuf.h machine/vmparam.h
+
+assym.s: genassym
+ ./genassym >assym.s
+
+genassym:
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep ${COPTS} ${CFILES} ioconf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: $S/sys/param.h $S/sys/systm.h $S/sys/buf.h $S/sys/ioctl.h \
+ $S/sys/tty.h $S/sys/conf.h \
+ as.h bpfilter.h cd.h ch.h com.h dcfclk.h fd.h lpa.h \
+ lpt.h pty.h sd.h speaker.h st.h wd.h wt.h \
+ ${I386}/i386/conf.c
+ ${CC} -traditional -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c \
+ $S/sys/param.h $S/sys/systm.h $S/sys/socket.h $S/sys/proc.h \
+ $S/sys/vnode.h $S/sys/file.h $S/sys/callout.h $S/sys/clist.h \
+ $S/sys/mbuf.h $S/ufs/quota.h $S/sys/kernel.h machine/vmparam.h \
+ $S/sys/shm.h
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+newvers:
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386
new file mode 100644
index 0000000..84f7aff
--- /dev/null
+++ b/sys/i386/conf/devices.i386
@@ -0,0 +1,18 @@
+# This file tells what major numbers the various possible swap devices have.
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 1 00097
+# -------------------- ----- ----------------------
+#
+# 17 Feb 93 Julian Elischer Add devices for new scsi disks
+# 10 Mar 93 Rodney W. Grimes Add more devices, st and cd
+#
+wd 0
+dk 1
+fd 2
+wt 3
+sd 4
+as 4
+st 5
+cd 6
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
new file mode 100644
index 0000000..578472c
--- /dev/null
+++ b/sys/i386/conf/files.i386
@@ -0,0 +1,71 @@
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 3 00160
+# -------------------- ----- ----------------------
+#
+# 17 Feb 93 Julian Elischer Added files for scsi
+# 10 Mar 93 Rodney W. Grimes Added files for lpt and lpa
+# 25 Mar 93 Sean Eric Fagan Added microtime.s routine
+# 08 Apr 93 Rodney W. Grimes Cleaned up the tabs, sorted file names
+# Added ix, speaker, dcfclock
+# 23 Apr 93 Holger Veit Added codrv
+# 26 May 93 Rodney W. Grimes Rename of Bruce Evans com driver to sio
+# Gene Stark Add xten power controler driver (tw)
+# David Greenman Add ethernet driver (SMC/WD/3COM) (ed)
+# Rick Macklem Add bus mouse driver (mse)
+#
+i386/i386/autoconf.c standard device-driver
+i386/i386/cons.c standard
+i386/i386/db_disasm.c optional ddb
+i386/i386/db_interface.c optional ddb
+i386/i386/db_trace.c optional ddb
+i386/i386/in_cksum.c optional inet
+i386/i386/machdep.c standard config-dependent
+i386/i386/math_emulate.c standard
+i386/i386/mem.c standard
+i386/i386/microtime.s standard
+i386/i386/ns_cksum.c optional ns
+i386/i386/pmap.c standard
+i386/i386/sys_machdep.c standard
+i386/i386/trap.c standard
+i386/i386/vm_machdep.c standard
+i386/isa/aha1542.c optional aha device-driver
+i386/isa/aha1742.c optional ahb device-driver
+i386/isa/as.c optional as device-driver
+i386/isa/bt742a.c optional bt device-driver
+i386/isa/clock.c standard
+i386/isa/codrv/co_cons.c optional co device-driver
+i386/isa/codrv/co_kbd.c optional co device-driver
+i386/isa/codrv/co_vga.c optional co device-driver
+i386/isa/codrv/co_codrv1.c optional co device-driver
+i386/isa/codrv/co_vty.c optional vty
+i386/isa/codrv/co_pc3.c optional vtemul
+i386/isa/codrv/co_mini.c optional vtemul
+i386/isa/com.c optional com device-driver
+i386/isa/dcfclk.c optional dcfclk device-driver
+i386/isa/fd.c optional fd device-driver
+i386/isa/if_ec.c optional ec device-driver
+i386/isa/if_ed.c optional ed device-driver
+i386/isa/if_is.c optional is device-driver
+i386/isa/if_ix.c optional ix device-driver
+i386/isa/if_ne.c optional ne device-driver
+i386/isa/if_we.c optional we device-driver
+i386/isa/isa.c optional isa device-driver
+i386/isa/lpa.c optional lpa device-driver
+i386/isa/lpt.c optional lpt device-driver
+i386/isa/mse.c optional mse device-driver
+i386/isa/npx.c optional npx device-driver
+i386/isa/pccons.c optional pc device-driver
+i386/isa/sio.c optional sio device-driver
+i386/isa/spkr.c optional speaker
+i386/isa/tw.c optional tw device-driver
+i386/isa/ultra14f.c optional uha device-driver
+i386/isa/wd.c optional wd device-driver
+i386/isa/wt.c optional wt device-driver
+scsi/cd.c optional cd
+scsi/ch.c optional ch
+scsi/scsiconf.c optional scbus
+scsi/sd.c optional sd
+scsi/st.c optional st
+
diff --git a/sys/i386/eisa/aha1742.c b/sys/i386/eisa/aha1742.c
new file mode 100644
index 0000000..721f6f7
--- /dev/null
+++ b/sys/i386/eisa/aha1742.c
@@ -0,0 +1,1420 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ */
+
+#include <sys/types.h>
+#include <ahb.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#ifdef MACH /* EITHER CMU OR OSF */
+#include <i386/ipl.h>
+#include <i386at/scsi.h>
+#include <i386at/scsiconf.h>
+
+#ifdef OSF /* OSF ONLY */
+#include <sys/table.h>
+#include <i386/handler.h>
+#include <i386/dispatcher.h>
+#include <i386/AT386/atbus.h>
+
+#else OSF /* CMU ONLY */
+#include <i386at/atbus.h>
+#include <i386/pio.h>
+#endif OSF
+#endif MACH /* end of MACH specific */
+
+#ifdef __386BSD__ /* 386BSD specific */
+#define isa_dev isa_device
+#define dev_unit id_unit
+#define dev_addr id_iobase
+
+#include <i386/include/pio.h>
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif __386BSD__
+
+/* */
+
+#ifdef __386BSD__
+#include "ddb.h"
+#if NDDB > 0
+int Debugger();
+#else NDDB
+#define Debugger() panic("should call debugger here (adaptec.c)")
+#endif NDDB
+#endif __386BSD__
+
+#ifdef MACH
+int Debugger();
+#endif MACH
+
+typedef unsigned long int physaddr;
+
+#ifdef MACH
+extern physaddr kvtophys();
+#define PHYSTOKV(x) phystokv(x)
+#define KVTOPHYS(x) kvtophys(x)
+#endif MACH
+
+#ifdef __386BSD__
+#define PHYSTOKV(x) (x | 0xFE000000)
+#define KVTOPHYS(x) vtophys(x)
+#endif __386BSD__
+
+extern int delaycount; /* from clock setup code */
+#define NUM_CONCURRENT 16 /* number of concurrent ops per board */
+#define AHB_NSEG 33 /* number of dma segments supported */
+#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */
+/* */
+/***********************************************************************\
+* AHA1740 standard EISA Host ID regs (Offset from slot base) *
+\***********************************************************************/
+#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */
+#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */
+#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
+#define HID3 0xC83 /* firmware revision */
+
+#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
+#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
+#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
+
+/* AHA1740 EISA board control registers (Offset from slot base) */
+#define EBCTRL 0xC84
+#define CDEN 0x01
+/***********************************************************************\
+* AHA1740 EISA board mode registers (Offset from slot base) *
+\***********************************************************************/
+#define PORTADDR 0xCC0
+#define PORTADDR_ENHANCED 0x80
+#define BIOSADDR 0xCC1
+#define INTDEF 0xCC2
+#define SCSIDEF 0xCC3
+#define BUSDEF 0xCC4
+#define RESV0 0xCC5
+#define RESV1 0xCC6
+#define RESV2 0xCC7
+/**** bit definitions for INTDEF ****/
+#define INT9 0x00
+#define INT10 0x01
+#define INT11 0x02
+#define INT12 0x03
+#define INT14 0x05
+#define INT15 0x06
+#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
+#define INTEN 0x10
+/**** bit definitions for SCSIDEF ****/
+#define HSCSIID 0x0F /* our SCSI ID */
+#define RSTPWR 0x10 /* reset scsi bus on power up or reset */
+/**** bit definitions for BUSDEF ****/
+#define B0uS 0x00 /* give up bus immediatly */
+#define B4uS 0x01 /* delay 4uSec. */
+#define B8uS 0x02
+/***********************************************************************\
+* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) *
+\***********************************************************************/
+#define MBOXOUT0 0xCD0
+#define MBOXOUT1 0xCD1
+#define MBOXOUT2 0xCD2
+#define MBOXOUT3 0xCD3
+
+#define ATTN 0xCD4
+#define G2CNTRL 0xCD5
+#define G2INTST 0xCD6
+#define G2STAT 0xCD7
+
+#define MBOXIN0 0xCD8
+#define MBOXIN1 0xCD9
+#define MBOXIN2 0xCDA
+#define MBOXIN3 0xCDB
+
+#define G2STAT2 0xCDC
+
+/*******************************************************\
+* Bit definitions for the 5 control/status registers *
+\*******************************************************/
+#define ATTN_TARGET 0x0F
+#define ATTN_OPCODE 0xF0
+#define OP_IMMED 0x10
+#define AHB_TARG_RESET 0x80
+#define OP_START_ECB 0x40
+#define OP_ABORT_ECB 0x50
+
+#define G2CNTRL_SET_HOST_READY 0x20
+#define G2CNTRL_CLEAR_EISA_INT 0x40
+#define G2CNTRL_HARD_RESET 0x80
+
+#define G2INTST_TARGET 0x0F
+#define G2INTST_INT_STAT 0xF0
+#define AHB_ECB_OK 0x10
+#define AHB_ECB_RECOVERED 0x50
+#define AHB_HW_ERR 0x70
+#define AHB_IMMED_OK 0xA0
+#define AHB_ECB_ERR 0xC0
+#define AHB_ASN 0xD0 /* for target mode */
+#define AHB_IMMED_ERR 0xE0
+
+#define G2STAT_BUSY 0x01
+#define G2STAT_INT_PEND 0x02
+#define G2STAT_MBOX_EMPTY 0x04
+
+#define G2STAT2_HOST_READY 0x01
+/* */
+
+struct ahb_dma_seg
+{
+ physaddr addr;
+ long len;
+};
+
+struct ahb_ecb_status
+{
+ u_short status;
+# define ST_DON 0x0001
+# define ST_DU 0x0002
+# define ST_QF 0x0008
+# define ST_SC 0x0010
+# define ST_DO 0x0020
+# define ST_CH 0x0040
+# define ST_INT 0x0080
+# define ST_ASA 0x0100
+# define ST_SNS 0x0200
+# define ST_INI 0x0800
+# define ST_ME 0x1000
+# define ST_ECA 0x4000
+ u_char ha_status;
+# define HS_OK 0x00
+# define HS_CMD_ABORTED_HOST 0x04
+# define HS_CMD_ABORTED_ADAPTER 0x05
+# define HS_TIMED_OUT 0x11
+# define HS_HARDWARE_ERR 0x20
+# define HS_SCSI_RESET_ADAPTER 0x22
+# define HS_SCSI_RESET_INCOMING 0x23
+ u_char targ_status;
+# define TS_OK 0x00
+# define TS_CHECK_CONDITION 0x02
+# define TS_BUSY 0x08
+ u_long resid_count;
+ u_long resid_addr;
+ u_short addit_status;
+ u_char sense_len;
+ u_char unused[9];
+ u_char cdb[6];
+};
+
+/* */
+
+struct ecb
+{
+ u_char opcode;
+# define ECB_SCSI_OP 0x01
+ u_char :4;
+ u_char options:3;
+ u_char :1;
+ short opt1;
+# define ECB_CNE 0x0001
+# define ECB_DI 0x0080
+# define ECB_SES 0x0400
+# define ECB_S_G 0x1000
+# define ECB_DSB 0x4000
+# define ECB_ARS 0x8000
+ short opt2;
+# define ECB_LUN 0x0007
+# define ECB_TAG 0x0008
+# define ECB_TT 0x0030
+# define ECB_ND 0x0040
+# define ECB_DAT 0x0100
+# define ECB_DIR 0x0200
+# define ECB_ST 0x0400
+# define ECB_CHK 0x0800
+# define ECB_REC 0x4000
+# define ECB_NRB 0x8000
+ u_short unused1;
+ physaddr data;
+ u_long datalen;
+ physaddr status;
+ physaddr chain;
+ short unused2;
+ short unused3;
+ physaddr sense;
+ u_char senselen;
+ u_char cdblen;
+ short cksum;
+ u_char cdb[12];
+ /*-----------------end of hardware supported fields----------------*/
+ struct ecb *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ long int delta; /* difference from previous*/
+ struct ecb *later,*sooner;
+ int flags;
+#define ECB_FREE 0
+#define ECB_ACTIVE 1
+#define ECB_ABORTED 2
+#define ECB_IMMED 4
+#define ECB_IMMED_FAIL 8
+ struct ahb_dma_seg ahb_dma[AHB_NSEG];
+ struct ahb_ecb_status ecb_status;
+ struct scsi_sense_data ecb_sense;
+};
+
+struct ecb *ahb_soonest = (struct ecb *)0;
+struct ecb *ahb_latest = (struct ecb *)0;
+long int ahb_furtherest = 0; /* longest time in the timeout queue */
+/* */
+
+struct ahb_data
+{
+ int flags;
+#define AHB_INIT 0x01;
+ int baseport;
+ struct ecb ecbs[NUM_CONCURRENT];
+ struct ecb *free_ecb;
+ int our_id; /* our scsi id */
+ int vect;
+ struct ecb *immed_ecb; /* an outstanding immediete command */
+} ahb_data[NAHB];
+
+int ahbprobe();
+int ahb_attach();
+int ahbintr();
+int ahb_scsi_cmd();
+int ahb_timeout();
+struct ecb *cheat;
+void ahbminphys();
+long int ahb_adapter_info();
+
+#ifdef MACH
+struct isa_driver ahbdriver = { ahbprobe, 0, ahb_attach, "ahb", 0, 0, 0};
+int (*ahbintrs[])() = {ahbintr, 0};
+#endif MACH
+
+#ifdef __386BSD__
+struct isa_driver ahbdriver = { ahbprobe, ahb_attach, "ahb"};
+#endif __386BSD__
+
+#define MAX_SLOTS 8
+static ahb_slot = 0; /* slot last board was found in */
+static ahb_unit = 0;
+int ahb_debug = 0;
+#define AHB_SHOWECBS 0x01
+#define AHB_SHOWINTS 0x02
+#define AHB_SHOWCMDS 0x04
+#define AHB_SHOWMISC 0x08
+#define FAIL 1
+#define SUCCESS 0
+#define PAGESIZ 4096
+
+struct scsi_switch ahb_switch =
+{
+ ahb_scsi_cmd,
+ ahbminphys,
+ 0,
+ 0,
+ ahb_adapter_info,
+ 0,0,0
+};
+
+/* */
+/***********************************************************************\
+* Function to send a command out through a mailbox *
+\***********************************************************************/
+ahb_send_mbox( int unit
+ ,int opcode
+ ,int target
+ ,struct ecb *ecb)
+{
+ int port = ahb_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */
+ int s = splbio();
+ int stport = port + G2STAT;
+
+ while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ != (G2STAT_MBOX_EMPTY))
+ && (spincount--));
+ if(spincount == -1)
+ {
+ printf("ahb%d: board not responding\n",unit);
+ Debugger();
+ }
+
+ outl(port + MBOXOUT0,KVTOPHYS(ecb)); /* don't know this will work */
+ outb(port + ATTN, opcode|target);
+
+ splx(s);
+}
+
+/***********************************************************************\
+* Function to poll for command completion when in poll mode *
+\***********************************************************************/
+ahb_poll(int unit ,int wait) /* in msec */
+{
+ int port = ahb_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * wait; /* in msec */
+ int stport = port + G2STAT;
+int start = spincount;
+
+retry:
+ while( (spincount--) && (!(inb(stport) & G2STAT_INT_PEND)));
+ if(spincount == -1)
+ {
+ printf("ahb%d: board not responding\n",unit);
+ return(EIO);
+ }
+if ((int)cheat != PHYSTOKV(inl(port + MBOXIN0)))
+{
+ printf("discarding %x ",inl(port + MBOXIN0));
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ spinwait(50);
+ goto retry;
+}/* don't know this will work */
+ ahbintr(unit);
+ return(0);
+}
+/***********************************************************************\
+* Function to send an immediate type command to the adapter *
+\***********************************************************************/
+ahb_send_immed( int unit
+ ,int target
+ ,u_long cmd)
+{
+ int port = ahb_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */
+ int s = splbio();
+ int stport = port + G2STAT;
+
+ while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ != (G2STAT_MBOX_EMPTY))
+ && (spincount--));
+ if(spincount == -1)
+ {
+ printf("ahb%d: board not responding\n",unit);
+ Debugger();
+ }
+
+ outl(port + MBOXOUT0,cmd); /* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY);
+ outb(port + ATTN, OP_IMMED | target);
+ splx(s);
+}
+
+/* */
+
+/*******************************************************\
+* Check the slots looking for a board we recognise *
+* If we find one, note it's address (slot) and call *
+* the actual probe routine to check it out. *
+\*******************************************************/
+ahbprobe(dev)
+struct isa_dev *dev;
+{
+ int port;
+ u_char byte1,byte2,byte3;
+ ahb_slot++;
+ while (ahb_slot<8)
+ {
+ port = 0x1000 * ahb_slot;
+ byte1 = inb(port + HID0);
+ byte2 = inb(port + HID1);
+ byte3 = inb(port + HID2);
+ if(byte1 == 0xff)
+ {
+ ahb_slot++;
+ continue;
+ }
+ if ((CHAR1(byte1,byte2) == 'A')
+ && (CHAR2(byte1,byte2) == 'D')
+ && (CHAR3(byte1,byte2) == 'P')
+ && ((byte3 == 0 ) || (byte3 == 1)))
+ {
+ dev->dev_addr = port;
+ return(ahbprobe1(dev));
+ }
+ ahb_slot++;
+ }
+ return(0);
+}
+/*******************************************************\
+* Check if the device can be found at the port given *
+* and if so, set it up ready for further work *
+* as an argument, takes the isa_dev structure from *
+* autoconf.c *
+\*******************************************************/
+ahbprobe1(dev)
+struct isa_dev *dev;
+{
+ /***********************************************\
+ * find unit and check we have that many defined *
+ \***********************************************/
+ int unit = ahb_unit;
+#if defined(OSF)
+ static ihandler_t ahb_handler[NAHB];
+ static ihandler_id_t *ahb_handler_id[NAHB];
+ register ihandler_t *chp = &ahb_handler[unit];;
+#endif /* defined(OSF) */
+
+ dev->dev_unit = unit;
+ ahb_data[unit].baseport = dev->dev_addr;
+ if(unit >= NAHB)
+ {
+ printf("ahb: unit number (%d) too high\n",unit);
+ return(0);
+ }
+ /***********************************************\
+ * Try initialise a unit at this location *
+ * sets up dma and bus speed, loads ahb_data[unit].vect*
+ \***********************************************/
+ if (ahb_init(unit) != 0)
+ {
+ return(0);
+ }
+
+ /***********************************************\
+ * If it's there, put in it's interrupt vectors *
+ \***********************************************/
+#ifdef MACH
+#if defined(OSF) /* OSF */
+ chp->ih_level = dev->dev_pic;
+ chp->ih_handler = dev->dev_intr[0];
+ chp->ih_resolver = i386_resolver;
+ chp->ih_rdev = dev;
+ chp->ih_stats.intr_type = INTR_DEVICE;
+ chp->ih_stats.intr_cnt = 0;
+ chp->ih_hparam[0].intparam = unit;
+ if ((ahb_handler_id[unit] = handler_add(chp)) != NULL)
+ handler_enable(ahb_handler_id[unit]);
+ else
+ panic("Unable to add ahb interrupt handler");
+#else /* CMU */
+ dev->dev_pic = ahb_data[unit].vect;
+ take_dev_irq(dev);
+#endif /* !defined(OSF) */
+ printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl);
+#endif MACH
+#ifdef __386BSD__ /* 386BSD */
+ dev->id_irq = (1 << ahb_data[unit].vect);
+ dev->id_drq = -1; /* use EISA dma */
+ printf("\n **");
+#endif __386BSD__
+
+ ahb_unit++;
+ return(1);
+}
+
+/***********************************************\
+* Attach all the sub-devices we can find *
+\***********************************************/
+ahb_attach(dev)
+struct isa_dev *dev;
+{
+ int unit = dev->dev_unit;
+
+
+#ifdef __386BSD__
+ printf(" probing for scsi devices**\n");
+#endif __386BSD__
+
+ /***********************************************\
+ * ask the adapter what subunits are present *
+ \***********************************************/
+ scsi_attachdevs( unit, ahb_data[unit].our_id, &ahb_switch);
+#if defined(OSF)
+ ahb_attached[unit]=1;
+#endif /* defined(OSF) */
+ if(!unit) /* only one for all boards */
+ {
+ ahb_timeout(0);
+ }
+#ifdef __386BSD__
+ printf("ahb%d",unit);
+#endif __386BSD__
+ return;
+}
+
+/***********************************************\
+* Return some information to the caller about *
+* the adapter and it's capabilities *
+\***********************************************/
+long int ahb_adapter_info(unit)
+int unit;
+{
+ return(2); /* 2 outstanding requests at a time per device */
+}
+
+/***********************************************\
+* Catch an interrupt from the adaptor *
+\***********************************************/
+ahbintr(unit)
+{
+ struct ecb *ecb;
+ unsigned char stat;
+ register i;
+ u_char ahbstat;
+ int target;
+ long int mboxval;
+
+ int port = ahb_data[unit].baseport;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("ahbintr ");
+
+#if defined(OSF)
+ if (!ahb_attached[unit])
+ {
+ return(1);
+ }
+#endif /* defined(OSF) */
+ while(inb(port + G2STAT) & G2STAT_INT_PEND)
+ {
+ /***********************************************\
+ * First get all the information and then *
+ * acknowlege the interrupt *
+ \***********************************************/
+ ahbstat = inb(port + G2INTST);
+ target = ahbstat & G2INTST_TARGET;
+ stat = ahbstat & G2INTST_INT_STAT;
+ mboxval = inl(port + MBOXIN0);/* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("status = 0x%x ",stat);
+ /***********************************************\
+ * Process the completed operation *
+ \***********************************************/
+
+ if(stat == AHB_ECB_OK) /* common case is fast */
+ {
+ ecb = (struct ecb *)PHYSTOKV(mboxval);
+ }
+ else
+ {
+ switch(stat)
+ {
+ case AHB_IMMED_OK:
+ ecb = ahb_data[unit].immed_ecb;
+ ahb_data[unit].immed_ecb = 0;
+ break;
+ case AHB_IMMED_ERR:
+ ecb = ahb_data[unit].immed_ecb;
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb_data[unit].immed_ecb = 0;
+ break;
+ case AHB_ASN: /* for target mode */
+ ecb = 0;
+ break;
+ case AHB_HW_ERR:
+ ecb = 0;
+ break;
+ case AHB_ECB_RECOVERED:
+ ecb = (struct ecb *)PHYSTOKV(mboxval);
+ break;
+ case AHB_ECB_ERR:
+ ecb = (struct ecb *)PHYSTOKV(mboxval);
+ break;
+ default:
+ printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat);
+ ecb=0;
+ }
+ }
+ if(ecb)
+ {
+ if(ahb_debug & AHB_SHOWCMDS )
+ {
+ ahb_show_scsi_cmd(ecb->xs);
+ }
+ if((ahb_debug & AHB_SHOWECBS) && ecb)
+ printf("<int ecb(%x)>",ecb);
+ ahb_remove_timeout(ecb);
+ ahb_done(unit,ecb,((stat == AHB_ECB_OK)?SUCCESS:FAIL));
+ }
+ }
+ return(1);
+}
+
+/***********************************************\
+* We have a ecb which has been processed by the *
+* adaptor, now we look to see how the operation *
+* went. *
+\***********************************************/
+ahb_done(unit,ecb,state)
+int unit,state;
+struct ecb *ecb;
+{
+ struct ahb_ecb_status *stat = &ecb->ecb_status;
+ struct scsi_sense_data *s1,*s2;
+ struct scsi_xfer *xs = ecb->xs;
+
+ if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS))
+ printf("ahb_done ");
+ /***********************************************\
+ * Otherwise, put the results of the operation *
+ * into the xfer and call whoever started it *
+ \***********************************************/
+ if(ecb->flags & ECB_IMMED)
+ {
+ if(ecb->flags & ECB_IMMED_FAIL)
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ goto done;
+ }
+ if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK))
+ { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ xs->error = 0;
+ }
+ else
+ {
+
+ s1 = &(ecb->ecb_sense);
+ s2 = &(xs->sense);
+
+ if(stat->ha_status)
+ {
+ switch(stat->ha_status)
+ {
+ case HS_SCSI_RESET_ADAPTER:
+ break;
+ case HS_SCSI_RESET_INCOMING:
+ break;
+ case HS_CMD_ABORTED_HOST: /* No response */
+ case HS_CMD_ABORTED_ADAPTER: /* No response */
+ break;
+ case HS_TIMED_OUT: /* No response */
+ if (ahb_debug & AHB_SHOWMISC)
+ {
+ printf("timeout reported back\n");
+ }
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ if (ahb_debug & AHB_SHOWMISC)
+ {
+ printf("unexpected ha_status: %x\n",
+ stat->ha_status);
+ }
+ }
+
+ }
+ else
+ {
+ switch(stat->targ_status)
+ {
+ case TS_CHECK_CONDITION:
+ /* structure copy!!!!!*/
+ *s2=*s1;
+ xs->error = XS_SENSE;
+ break;
+ case TS_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ if (ahb_debug & AHB_SHOWMISC)
+ {
+ printf("unexpected targ_status: %x\n",
+ stat->targ_status);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+done: xs->flags |= ITSDONE;
+ ahb_free_ecb(unit,ecb, xs->flags);
+ if(xs->when_done)
+ (*(xs->when_done))(xs->done_arg,xs->done_arg2);
+}
+
+/***********************************************\
+* A ecb (and hence a mbx-out is put onto the *
+* free list. *
+\***********************************************/
+ahb_free_ecb(unit,ecb, flags)
+struct ecb *ecb;
+{
+ unsigned int opri;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("ecb%d(0x%x)> ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ecb->next = ahb_data[unit].free_ecb;
+ ahb_data[unit].free_ecb = ecb;
+ ecb->flags = ECB_FREE;
+ /***********************************************\
+ * If there were none, wake abybody waiting for *
+ * one to come free, starting with queued entries*
+ \***********************************************/
+ if (!ecb->next) {
+ wakeup(&ahb_data[unit].free_ecb);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/***********************************************\
+* Get a free ecb (and hence mbox-out entry) *
+\***********************************************/
+struct ecb *
+ahb_get_ecb(unit,flags)
+{
+ unsigned opri;
+ struct ecb *rc;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("<ecb%d(0x%x) ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /***********************************************\
+ * If we can and have to, sleep waiting for one *
+ * to come free *
+ \***********************************************/
+ while ((!(rc = ahb_data[unit].free_ecb)) && (!(flags & SCSI_NOSLEEP)))
+ {
+ sleep(&ahb_data[unit].free_ecb, PRIBIO);
+ }
+ if (rc)
+ {
+ ahb_data[unit].free_ecb = rc->next;
+ rc->flags = ECB_ACTIVE;
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+ return(rc);
+}
+
+
+
+/***********************************************\
+* Start the board, ready for normal operation *
+\***********************************************/
+ahb_init(unit)
+int unit;
+{
+ int port = ahb_data[unit].baseport;
+ int intdef;
+ int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */
+ int i;
+ int stport = port + G2STAT;
+#define NO_NO 1
+#ifdef NO_NO
+ /***********************************************\
+ * reset board, If it doesn't respond, assume *
+ * that it's not there.. good for the probe *
+ \***********************************************/
+ outb(port + EBCTRL,CDEN); /* enable full card */
+ outb(port + PORTADDR,PORTADDR_ENHANCED);
+
+ outb(port + G2CNTRL,G2CNTRL_HARD_RESET);
+ spinwait(1);
+ outb(port + G2CNTRL,0);
+ spinwait(10);
+ while( ((inb(stport) & G2STAT_BUSY ))
+ && (spincount--));
+ if(spincount == -1)
+ {
+ if (ahb_debug & AHB_SHOWMISC)
+ printf("ahb_init: No answer from bt742a board\n");
+ return(ENXIO);
+ }
+ i = inb(port + MBOXIN0) & 0xff;
+ if(i)
+ {
+ printf("self test failed, val = 0x%x\n",i);
+ return(EIO);
+ }
+#endif
+ while( inb(stport) & G2STAT_INT_PEND)
+ {
+ printf(".");
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ spinwait(10);
+ }
+ outb(port + EBCTRL,CDEN); /* enable full card */
+ outb(port + PORTADDR,PORTADDR_ENHANCED);
+ /***********************************************\
+ * Assume we have a board at this stage *
+ * setup dma channel from jumpers and save int *
+ * level *
+ \***********************************************/
+#ifdef __386BSD__
+ printf("ahb%d reading board settings, ",unit);
+#define PRNT(x)
+#else __386BSD__
+ printf("ahb%d:",unit);
+#define PRNT(x) printf(x)
+#endif __386BSD__
+
+ intdef = inb(port + INTDEF);
+ switch(intdef & 0x07)
+ {
+ case INT9:
+ ahb_data[unit].vect = 9;
+ PRNT("int=9 ");
+ break;
+ case INT10:
+ ahb_data[unit].vect = 10;
+ PRNT("int=10 ");
+ break;
+ case INT11:
+ ahb_data[unit].vect = 11;
+ PRNT("int=11 ");
+ break;
+ case INT12:
+ ahb_data[unit].vect = 12;
+ PRNT("int=12 ");
+ break;
+ case INT14:
+ ahb_data[unit].vect = 14;
+ PRNT("int=14 ");
+ break;
+ case INT15:
+ ahb_data[unit].vect = 15;
+ PRNT("int=15 ");
+ break;
+ default:
+ printf("illegal int setting\n");
+ return(EIO);
+ }
+ outb(port + INTDEF ,(intdef | INTEN)); /* make sure we can interrupt */
+ /* who are we on the scsi bus */
+ ahb_data[unit].our_id = (inb(port + SCSIDEF) & HSCSIID);
+
+ /***********************************************\
+ * link up all our ECBs into a free list *
+ \***********************************************/
+ for (i=0; i < NUM_CONCURRENT; i++)
+ {
+ ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb;
+ ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i];
+ ahb_data[unit].free_ecb->flags = ECB_FREE;
+ }
+
+ /***********************************************\
+ * Note that we are going and return (to probe) *
+ \***********************************************/
+ ahb_data[unit].flags |= AHB_INIT;
+ return( 0 );
+}
+
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif min
+
+
+void ahbminphys(bp)
+struct buf *bp;
+{
+#ifdef MACH
+#if !defined(OSF)
+ bp->b_flags |= B_NPAGES; /* can support scat/gather */
+#endif /* defined(OSF) */
+#endif MACH
+ if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ))
+ {
+ bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ);
+ }
+}
+
+/***********************************************\
+* start a scsi operation given the command and *
+* the data address. Also needs the unit, target *
+* and lu *
+\***********************************************/
+int ahb_scsi_cmd(xs)
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1,*s2;
+ struct ecb *ecb;
+ struct ahb_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int rc = 0;
+ int thiskv;
+ physaddr thisphys,nextphys;
+ int unit =xs->adapter;
+ int bytes_this_seg,bytes_this_page,datalen,flags;
+ struct iovec *iovp;
+ int s;
+ if(scsi_debug & PRINTROUTINES)
+ printf("ahb_scsi_cmd ");
+ /***********************************************\
+ * get a ecb (mbox-out) to use. If the transfer *
+ * is from a buf (possibly from interrupt time) *
+ * then we can't allow it to sleep *
+ \***********************************************/
+ flags = xs->flags;
+ if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if(flags & ITSDONE)
+ {
+ printf("Already done?");
+ xs->flags &= ~ITSDONE;
+ }
+ if(!(flags & INUSE))
+ {
+ printf("Not in use?");
+ xs->flags |= INUSE;
+ }
+ if (!(ecb = ahb_get_ecb(unit,flags)))
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+cheat = ecb;
+ if(ahb_debug & AHB_SHOWECBS)
+ printf("<start ecb(%x)>",ecb);
+ if(scsi_debug & SHOWCOMMANDS)
+ {
+ ahb_show_scsi_cmd(xs);
+ }
+ ecb->xs = xs;
+ /***********************************************\
+ * If it's a reset, we need to do an 'immediate' *
+ * command, and store it's ccb for later *
+ * if there is already an immediate waiting, *
+ * then WE must wait *
+ \***********************************************/
+ if(flags & SCSI_RESET)
+ {
+ ecb->flags |= ECB_IMMED;
+ if(ahb_data[unit].immed_ecb)
+ {
+ return(TRY_AGAIN_LATER);
+ }
+ ahb_data[unit].immed_ecb = ecb;
+ if (!(flags & SCSI_NOMASK))
+ {
+ s = splbio();
+ ahb_send_immed(unit,xs->targ,AHB_TARG_RESET);
+ ahb_add_timeout(ecb,xs->timeout);
+ splx(s);
+ return(SUCCESSFULLY_QUEUED);
+ }
+ else
+ {
+ ahb_send_immed(unit,xs->targ,AHB_TARG_RESET);
+ /***********************************************\
+ * If we can't use interrupts, poll on completion*
+ \***********************************************/
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("wait ");
+ if( ahb_poll(unit,xs->timeout))
+ {
+ ahb_free_ecb(unit,ecb,flags);
+ xs->error = XS_TIMEOUT;
+ return(HAD_ERROR);
+ }
+ return(COMPLETE);
+ }
+ }
+ /***********************************************\
+ * Put all the arguments for the xfer in the ecb *
+ \***********************************************/
+ ecb->opcode = ECB_SCSI_OP;
+ ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS;
+ if(xs->datalen)
+ {
+ ecb->opt1 |= ECB_S_G;
+ }
+ ecb->opt2 = xs->lu | ECB_NRB;
+ ecb->cdblen = xs->cmdlen;
+ ecb->sense = KVTOPHYS(&(ecb->ecb_sense));
+ ecb->senselen = sizeof(ecb->ecb_sense);
+ ecb->status = KVTOPHYS(&(ecb->ecb_status));
+
+ if(xs->datalen)
+ { /* should use S/G only if not zero length */
+ ecb->data = KVTOPHYS(ecb->ahb_dma);
+ sg = ecb->ahb_dma ;
+ seg = 0;
+ if(flags & SCSI_DATA_UIO)
+ {
+ iovp = ((struct uio *)xs->data)->uio_iov;
+ datalen = ((struct uio *)xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < AHB_NSEG))
+ {
+ sg->addr = (physaddr)iovp->iov_base;
+ xs->datalen += sg->len = iovp->iov_len;
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x@0x%x)"
+ ,iovp->iov_len
+ ,iovp->iov_base);
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ }
+ else
+ {
+ /***********************************************\
+ * Set up the scatter gather block *
+ \***********************************************/
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("%d @0x%x:- ",xs->datalen,xs->data);
+ datalen = xs->datalen;
+ thiskv = (int)xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < AHB_NSEG))
+ {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->addr = thisphys;
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("0x%x",thisphys);
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /*********************************************\
+ * This page is contiguous (physically) with *
+ * the the last, just extend the length *
+ \*********************************************/
+ {
+ /* how far to the end of the page */
+ nextphys= (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if(datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /********************************************\
+ * next page isn't contiguous, finish the seg *
+ \********************************************/
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x)",bytes_this_seg);
+ sg->len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ } /*end of iov/kv decision */
+ ecb->datalen = seg * sizeof(struct ahb_dma_seg);
+ if(scsi_debug & SHOWSCATGATH)
+ printf("\n");
+ if (datalen)
+ { /* there's still data, must have run out of segs! */
+ printf("ahb_scsi_cmd%d: more than %d DMA segs\n",
+ unit,AHB_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ ahb_free_ecb(unit,ecb,flags);
+ return(HAD_ERROR);
+ }
+
+ }
+ else
+ { /* No data xfer, use non S/G values */
+ ecb->data = (physaddr)0;
+ ecb->datalen = 0;
+ }
+ ecb->chain = (physaddr)0;
+ /***********************************************\
+ * Put the scsi command in the ecb and start it *
+ \***********************************************/
+ bcopy(xs->cmd, ecb->cdb, xs->cmdlen);
+ /***********************************************\
+ * Usually return SUCCESSFULLY QUEUED *
+ \***********************************************/
+ if (!(flags & SCSI_NOMASK))
+ {
+ s = splbio();
+ ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb);
+ ahb_add_timeout(ecb,xs->timeout);
+ splx(s);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("cmd_sent ");
+ return(SUCCESSFULLY_QUEUED);
+ }
+ /***********************************************\
+ * If we can't use interrupts, poll on completion*
+ \***********************************************/
+ ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("cmd_wait ");
+ do
+ {
+ if(ahb_poll(unit,xs->timeout))
+ {
+ if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n");
+ ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb);
+ if(ahb_poll(unit,2000))
+ {
+ printf("abort failed in wait\n");
+ ahb_free_ecb(unit,ecb,flags);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ splx(s);
+ return(HAD_ERROR);
+ }
+ } while (!(xs->flags & ITSDONE));/* something (?) else finished */
+ splx(s);
+scsi_debug = 0;ahb_debug = 0;
+ if(xs->error)
+ {
+ return(HAD_ERROR);
+ }
+ return(COMPLETE);
+}
+
+/*
+ * +----------+ +----------+ +----------+
+ * ahb_soonest--->| later |--->| later|--->| later|--->0
+ * | [Delta] | | [Delta] | | [Delta] |
+ * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest
+ * +----------+ +----------+ +----------+
+ *
+ * ahb_furtherest = sum(Delta[1..n])
+ */
+ahb_add_timeout(ecb,time)
+struct ecb *ecb;
+int time;
+{
+ int timeprev;
+ struct ecb *prev;
+ int s = splbio();
+
+ if(prev = ahb_latest) /* yes, an assign */
+ {
+ timeprev = ahb_furtherest;
+ }
+ else
+ {
+ timeprev = 0;
+ }
+ while(prev && (timeprev > time))
+ {
+ timeprev -= prev->delta;
+ prev = prev->sooner;
+ }
+ if(prev)
+ {
+ ecb->delta = time - timeprev;
+ if( ecb->later = prev->later) /* yes an assign */
+ {
+ ecb->later->sooner = ecb;
+ ecb->later->delta -= ecb->delta;
+ }
+ else
+ {
+ ahb_furtherest = time;
+ ahb_latest = ecb;
+ }
+ ecb->sooner = prev;
+ prev->later = ecb;
+ }
+ else
+ {
+ if( ecb->later = ahb_soonest) /* yes, an assign*/
+ {
+ ecb->later->sooner = ecb;
+ ecb->later->delta -= time;
+ }
+ else
+ {
+ ahb_furtherest = time;
+ ahb_latest = ecb;
+ }
+ ecb->delta = time;
+ ecb->sooner = (struct ecb *)0;
+ ahb_soonest = ecb;
+ }
+ splx(s);
+}
+
+ahb_remove_timeout(ecb)
+struct ecb *ecb;
+{
+ int s = splbio();
+
+ if(ecb->sooner)
+ {
+ ecb->sooner->later = ecb->later;
+ }
+ else
+ {
+ ahb_soonest = ecb->later;
+ }
+ if(ecb->later)
+ {
+ ecb->later->sooner = ecb->sooner;
+ ecb->later->delta += ecb->delta;
+ }
+ else
+ {
+ ahb_latest = ecb->sooner;
+ ahb_furtherest -= ecb->delta;
+ }
+ ecb->sooner = ecb->later = (struct ecb *)0;
+ splx(s);
+}
+
+
+extern int hz;
+#define ONETICK 500 /* milliseconds */
+#define SLEEPTIME ((hz * 1000) / ONETICK)
+ahb_timeout(arg)
+int arg;
+{
+ struct ecb *ecb;
+ int unit;
+ int s = splbio();
+
+ while( ecb = ahb_soonest )
+ {
+ if(ecb->delta <= ONETICK)
+ /***********************************************\
+ * It has timed out, we need to do some work *
+ \***********************************************/
+ {
+ unit = ecb->xs->adapter;
+ printf("ahb%d:%d device timed out\n",unit
+ ,ecb->xs->targ);
+ if(ahb_debug & AHB_SHOWECBS)
+ ahb_print_active_ecb();
+
+ /***************************************\
+ * Unlink it from the queue *
+ \***************************************/
+ ahb_remove_timeout(ecb);
+
+ /***************************************\
+ * If it's immediate, don't try abort it *
+ \***************************************/
+ if(ecb->flags & ECB_IMMED)
+ {
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb_done(unit,ecb,FAIL);
+ continue;
+ }
+ /***************************************\
+ * If it has been through before, then *
+ * a previous abort has failed, don't *
+ * try abort again *
+ \***************************************/
+ if(ecb->flags == ECB_ABORTED) /* abort timed out */
+ {
+ printf("AGAIN");
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST;
+ ahb_done(unit,ecb,FAIL);
+ }
+ else /* abort the operation that has timed out */
+ {
+ printf("\n");
+ ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb);
+ /* 2 secs for the abort */
+ ahb_add_timeout(ecb,2000 + ONETICK);
+ ecb->flags = ECB_ABORTED;
+ }
+ }
+ else
+ /***********************************************\
+ * It has not timed out, adjust and leave *
+ \***********************************************/
+ {
+ ecb->delta -= ONETICK;
+ ahb_furtherest -= ONETICK;
+ break;
+ }
+ }
+ splx(s);
+ timeout(ahb_timeout,arg,SLEEPTIME);
+}
+
+ahb_show_scsi_cmd(struct scsi_xfer *xs)
+{
+ u_char *b = (u_char *)xs->cmd;
+ int i = 0;
+ if(!(xs->flags & SCSI_RESET))
+ {
+ printf("ahb%d:%d:%d-"
+ ,xs->adapter
+ ,xs->targ
+ ,xs->lu);
+ while(i < xs->cmdlen )
+ {
+ if(i) printf(",");
+ printf("%x",b[i++]);
+ }
+ printf("-\n");
+ }
+ else
+ {
+ printf("ahb%d:%d:%d-RESET-\n"
+ ,xs->adapter
+ ,xs->targ
+ ,xs->lu
+ );
+ }
+}
+ahb_print_ecb(ecb)
+struct ecb *ecb;
+{
+ printf("ecb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ecb
+ ,ecb->opcode
+ ,ecb->cdblen
+ ,ecb->senselen);
+ printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n"
+ ,ecb->datalen
+ ,ecb->ecb_status.ha_status
+ ,ecb->ecb_status.targ_status
+ ,ecb->delta
+ ,ecb->flags);
+ ahb_show_scsi_cmd(ecb->xs);
+}
+
+ahb_print_active_ecb()
+{
+ struct ecb *ecb;
+ ecb = ahb_soonest;
+
+ while(ecb)
+ {
+ ahb_print_ecb(ecb);
+ ecb = ecb->later;
+ }
+ printf("Furtherest = %d\n",ahb_furtherest);
+}
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
new file mode 100644
index 0000000..7eee991
--- /dev/null
+++ b/sys/i386/i386/autoconf.c
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)autoconf.c 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00117
+ * -------------------- ----- ----------------------
+ *
+ * 09 Apr 93 ???(From sun-lamp) Fix to report sd when Julians
+ * scsi code is used, allow you to swap
+ * root floppies during a boot
+ */
+static char rcsid[] = "$Header: /b/source/CVS/src/sys.386bsd/i386/i386/autoconf.c,v 1.3 1993/04/10 21:58:52 cgd Exp $";
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the vba
+ * device tables and the memory controller monitoring. Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "dkstat.h"
+#include "conf.h"
+#include "dmap.h"
+#include "reboot.h"
+
+#include "machine/pte.h"
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int dkn; /* number of iostat dk numbers assigned so far */
+extern int cold; /* cold start flag initialized in locore.s */
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+configure()
+{
+
+#include "isa.h"
+#if NISA > 0
+ isa_configure();
+#endif
+
+#if GENERICxxx
+ if ((boothowto & RB_ASKNAME) == 0)
+ setroot();
+ setconf();
+#else
+ setroot();
+#endif
+ /*
+ * Configure swap area and related system
+ * parameter based on device(s) used.
+ */
+ swapconf();
+ cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+swapconf()
+{
+ register struct swdevt *swp;
+ register int nblks;
+extern int Maxmem;
+
+ for (swp = swdevt; swp->sw_dev > 0; swp++)
+ {
+ unsigned d = major(swp->sw_dev);
+
+ if (d > nblkdev) break;
+ if (bdevsw[d].d_psize) {
+ nblks = (*bdevsw[d].d_psize)(swp->sw_dev);
+ if (nblks > 0 &&
+ (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ swp->sw_nblks = nblks;
+ else
+ swp->sw_nblks = 0;
+ }
+ swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ }
+ if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
+ /*dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) - physmem;*/
+ dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) -
+ Maxmem*NBPG/512;
+ if (dumplo < 0)
+ dumplo = 0;
+}
+
+#define DOSWAP /* change swdevt and dumpdev */
+u_long bootdev = 0; /* should be dev_t, but not until 32 bits */
+
+#include "sd.h"
+static char devname[][2] = {
+ 'w','d', /* 0 = wd */
+ 's','w', /* 1 = sw */
+ 'f','d', /* 2 = fd */
+ 'w','t', /* 3 = wt */
+#if NSD < 1
+ 'a','s', /* 4 = as */
+#else
+ 's','d', /* 4 = sd -- new SCSI system */
+#endif
+};
+
+#define PARTITIONMASK 0x7
+#define PARTITIONSHIFT 3
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+setroot()
+{
+ int majdev, mindev, unit, part, adaptor;
+ dev_t temp, orootdev;
+ struct swdevt *swp;
+
+/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
+ if (boothowto & RB_DFLTROOT ||
+ (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
+ return;
+ majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
+ if (majdev > sizeof(devname) / sizeof(devname[0]))
+ return;
+ adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
+ part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
+ unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
+ mindev = (unit << PARTITIONSHIFT) + part;
+ orootdev = rootdev;
+ rootdev = makedev(majdev, mindev);
+ /*
+ * If the original rootdev is the same as the one
+ * just calculated, don't need to adjust the swap configuration.
+ */
+ if (rootdev == orootdev)
+ return;
+ if (devname[majdev][0] == 'f' && devname[majdev][1] == 'd') {
+ printf("");
+ printf("* insert the floppy you want to have mounted as\n");
+ printf("* root, and hit any key to continue booting:\n");
+ cngetc();
+ printf("");
+ }
+ printf("changing root device to %c%c%d%c\n",
+ devname[majdev][0], devname[majdev][1],
+ mindev >> PARTITIONSHIFT, part + 'a');
+#ifdef DOSWAP
+ mindev &= ~PARTITIONMASK;
+ for (swp = swdevt; swp->sw_dev; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev == 0)
+ return;
+ /*
+ * If dumpdev was the same as the old primary swap
+ * device, move it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+#endif
+}
diff --git a/sys/i386/i386/cons.c b/sys/i386/i386/cons.c
new file mode 100644
index 0000000..6189d72
--- /dev/null
+++ b/sys/i386/i386/cons.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cons.c 7.2 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00083
+ * -------------------- ----- ----------------------
+ *
+ * 16 Aug 92 Pace Willisson /dev/console redirect (xterm -C, etc.)
+ * 14 Mar 93 Chris G. Demetriou Moved pg() here from isa/pccons.c
+ */
+
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/systm.h"
+#include "sys/buf.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+#include "sys/file.h"
+#include "sys/conf.h"
+
+#include "cons.h"
+
+/* XXX - all this could be autoconfig()ed */
+int pccnprobe(), pccninit(), pccngetc(), pccnputc();
+#include "com.h"
+#if NCOM > 0
+int comcnprobe(), comcninit(), comcngetc(), comcnputc();
+#endif
+
+struct consdev constab[] = {
+ { pccnprobe, pccninit, pccngetc, pccnputc },
+#if NCOM > 0
+ { comcnprobe, comcninit, comcngetc, comcnputc },
+#endif
+ { 0 },
+};
+/* end XXX */
+
+struct tty *constty = 0; /* virtual console output device */
+struct consdev *cn_tab; /* physical console device info */
+struct tty *cn_tty; /* XXX: console tty struct for tprintf */
+
+cninit()
+{
+ register struct consdev *cp;
+
+ /*
+ * Collect information about all possible consoles
+ * and find the one with highest priority
+ */
+ for (cp = constab; cp->cn_probe; cp++) {
+ (*cp->cn_probe)(cp);
+ if (cp->cn_pri > CN_DEAD &&
+ (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
+ cn_tab = cp;
+ }
+ /*
+ * No console, we can handle it
+ */
+ if ((cp = cn_tab) == NULL)
+ return;
+ /*
+ * Turn on console
+ */
+ cn_tty = cp->cn_tp;
+ (*cp->cn_init)(cp);
+}
+
+cnopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
+}
+
+cnclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
+}
+
+cnread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
+}
+
+cnwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+{
+ if (cn_tab == NULL)
+ return (0);
+ if (constty) /* 16 Aug 92*/
+ dev = constty->t_dev;
+ else
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
+}
+
+cnioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ struct proc *p;
+{
+ int error;
+
+ if (cn_tab == NULL)
+ return (0);
+ /*
+ * Superuser can always use this to wrest control of console
+ * output from the "virtual" console.
+ */
+ if (cmd == TIOCCONS && constty) {
+ error = suser(p->p_ucred, (u_short *) NULL);
+ if (error)
+ return (error);
+ constty = NULL;
+ return (0);
+ }
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
+}
+
+/*ARGSUSED*/
+cnselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (1);
+ return (ttselect(cn_tab->cn_dev, rw, p));
+}
+
+cngetc()
+{
+ if (cn_tab == NULL)
+ return (0);
+ return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
+}
+
+cnputc(c)
+ register int c;
+{
+ if (cn_tab == NULL)
+ return;
+ if (c) {
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+ if (c == '\n')
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ }
+}
+
+pg(p,q,r,s,t,u,v,w,x,y,z) char *p; {
+ printf(p,q,r,s,t,u,v,w,x,y,z);
+ printf("\n>");
+ return(cngetc());
+}
+
+
diff --git a/sys/i386/i386/cons.h b/sys/i386/i386/cons.h
new file mode 100644
index 0000000..b3c7064
--- /dev/null
+++ b/sys/i386/i386/cons.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cons.h 7.2 (Berkeley) 5/9/91
+ */
+
+
+struct consdev {
+ int (*cn_probe)(); /* probe hardware and fill in consdev info */
+ int (*cn_init)(); /* turn on as console */
+ int (*cn_getc)(); /* kernel getchar interface */
+ int (*cn_putc)(); /* kernel putchar interface */
+ struct tty *cn_tp; /* tty structure for console device */
+ dev_t cn_dev; /* major/minor of device */
+ short cn_pri; /* pecking order; the higher the better */
+};
+
+/* values for cn_pri - reflect our policy for console selection */
+#define CN_DEAD 0 /* device doesn't exist */
+#define CN_NORMAL 1 /* device exists but is nothing special */
+#define CN_INTERNAL 2 /* "internal" bit-mapped display */
+#define CN_REMOTE 3 /* serial interface with remote bit set */
+
+/* XXX */
+#define CONSMAJOR 0
+
+#ifdef KERNEL
+extern struct consdev constab[];
+extern struct consdev *cn_tab;
+extern struct tty *cn_tty;
+#endif
diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c
new file mode 100644
index 0000000..20430b6
--- /dev/null
+++ b/sys/i386/i386/db_disasm.c
@@ -0,0 +1,1397 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_disasm.c,v $
+ * Revision 1.1 1992/03/25 21:42:01 pace
+ * Initial revision
+ *
+ * Revision 2.3 91/02/05 17:11:03 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:03 mrt]
+ *
+ * Revision 2.2 90/08/27 21:55:56 dbg
+ * Fix register operand for move to/from control/test/debug
+ * register instructions. Add i486 instructions.
+ * [90/08/27 dbg]
+ *
+ * Import db_sym.h. Print instruction displacements in
+ * current radix (signed). Change calling sequence of
+ * db_disasm.
+ * [90/08/21 dbg]
+ * Fix includes.
+ * [90/08/08 dbg]
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+
+/*
+ * Instruction disassembler.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Size attributes
+ */
+#define BYTE 0
+#define WORD 1
+#define LONG 2
+#define QUAD 3
+#define SNGL 4
+#define DBLR 5
+#define EXTR 6
+#define SDEP 7
+#define NONE 8
+
+/*
+ * Addressing modes
+ */
+#define E 1 /* general effective address */
+#define Eind 2 /* indirect address (jump, call) */
+#define Ew 3 /* address, word size */
+#define Eb 4 /* address, byte size */
+#define R 5 /* register, in 'reg' field */
+#define Rw 6 /* word register, in 'reg' field */
+#define Ri 7 /* register in instruction */
+#define S 8 /* segment reg, in 'reg' field */
+#define Si 9 /* segment reg, in instruction */
+#define A 10 /* accumulator */
+#define BX 11 /* (bx) */
+#define CL 12 /* cl, for shifts */
+#define DX 13 /* dx, for IO */
+#define SI 14 /* si */
+#define DI 15 /* di */
+#define CR 16 /* control register */
+#define DR 17 /* debug register */
+#define TR 18 /* test register */
+#define I 19 /* immediate, unsigned */
+#define Is 20 /* immediate, signed */
+#define Ib 21 /* byte immediate, unsigned */
+#define Ibs 22 /* byte immediate, signed */
+#define Iw 23 /* word immediate, unsigned */
+#define Il 24 /* long immediate */
+#define O 25 /* direct address */
+#define Db 26 /* byte displacement from EIP */
+#define Dl 27 /* long displacement from EIP */
+#define o1 28 /* constant 1 */
+#define o3 29 /* constant 3 */
+#define OS 30 /* immediate offset/segment */
+#define ST 31 /* FP stack top */
+#define STI 32 /* FP stack */
+#define X 33 /* extended FP op */
+#define XA 34 /* for 'fstcw %ax' */
+
+struct inst {
+ char * i_name; /* name */
+ short i_has_modrm; /* has regmodrm byte */
+ short i_size; /* operand size */
+ int i_mode; /* addressing modes */
+ char * i_extra; /* pointer to extra opcode table */
+};
+
+#define op1(x) (x)
+#define op2(x,y) ((x)|((y)<<8))
+#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16))
+
+struct finst {
+ char * f_name; /* name for memory instruction */
+ int f_size; /* size for memory instruction */
+ int f_rrmode; /* mode for rr instruction */
+ char * f_rrname; /* name for rr instruction
+ (or pointer to table) */
+};
+
+char * db_Grp6[] = {
+ "sldt",
+ "str",
+ "lldt",
+ "ltr",
+ "verr",
+ "verw",
+ "",
+ ""
+};
+
+char * db_Grp7[] = {
+ "sgdt",
+ "sidt",
+ "lgdt",
+ "lidt",
+ "smsw",
+ "",
+ "lmsw",
+ "invlpg"
+};
+
+char * db_Grp8[] = {
+ "",
+ "",
+ "",
+ "",
+ "bt",
+ "bts",
+ "btr",
+ "btc"
+};
+
+struct inst db_inst_0f0x[] = {
+/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 },
+/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 },
+/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
+/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
+/*04*/ { "", FALSE, NONE, 0, 0 },
+/*05*/ { "", FALSE, NONE, 0, 0 },
+/*06*/ { "clts", FALSE, NONE, 0, 0 },
+/*07*/ { "", FALSE, NONE, 0, 0 },
+
+/*08*/ { "invd", FALSE, NONE, 0, 0 },
+/*09*/ { "wbinvd",FALSE, NONE, 0, 0 },
+/*0a*/ { "", FALSE, NONE, 0, 0 },
+/*0b*/ { "", FALSE, NONE, 0, 0 },
+/*0c*/ { "", FALSE, NONE, 0, 0 },
+/*0d*/ { "", FALSE, NONE, 0, 0 },
+/*0e*/ { "", FALSE, NONE, 0, 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f2x[] = {
+/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */
+/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */
+/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 },
+/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 },
+/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 },
+/*25*/ { "", FALSE, NONE, 0, 0 },
+/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 },
+/*27*/ { "", FALSE, NONE, 0, 0 },
+
+/*28*/ { "", FALSE, NONE, 0, 0 },
+/*29*/ { "", FALSE, NONE, 0, 0 },
+/*2a*/ { "", FALSE, NONE, 0, 0 },
+/*2b*/ { "", FALSE, NONE, 0, 0 },
+/*2c*/ { "", FALSE, NONE, 0, 0 },
+/*2d*/ { "", FALSE, NONE, 0, 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f8x[] = {
+/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
+/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
+/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 },
+/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 },
+/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 },
+/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 },
+/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 },
+/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 },
+
+/*88*/ { "js", FALSE, NONE, op1(Dl), 0 },
+/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 },
+/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 },
+/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 },
+/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 },
+/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 },
+/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 },
+/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 },
+};
+
+struct inst db_inst_0f9x[] = {
+/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 },
+/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 },
+/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 },
+/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 },
+/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 },
+/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 },
+/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 },
+/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 },
+
+/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 },
+/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 },
+/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 },
+/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 },
+/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 },
+/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 },
+/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 },
+/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 },
+};
+
+struct inst db_inst_0fax[] = {
+/*a0*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*a2*/ { "", FALSE, NONE, 0, 0 },
+/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 },
+/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 },
+/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "", FALSE, NONE, 0, 0 },
+
+/*a8*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*aa*/ { "", FALSE, NONE, 0, 0 },
+/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 },
+/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 },
+/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 },
+};
+
+struct inst db_inst_0fbx[] = {
+/*b0*/ { "", FALSE, NONE, 0, 0 },
+/*b1*/ { "", FALSE, NONE, 0, 0 },
+/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 },
+/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 },
+/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 },
+/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 },
+/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 },
+/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 },
+
+/*b8*/ { "", FALSE, NONE, 0, 0 },
+/*b9*/ { "", FALSE, NONE, 0, 0 },
+/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 },
+/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
+/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
+/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
+/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 },
+/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 },
+};
+
+struct inst db_inst_0fcx[] = {
+/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+};
+
+struct inst db_inst_0fdx[] = {
+/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "", FALSE, NONE, 0, 0 },
+/*c9*/ { "", FALSE, NONE, 0, 0 },
+/*ca*/ { "", FALSE, NONE, 0, 0 },
+/*cb*/ { "", FALSE, NONE, 0, 0 },
+/*cc*/ { "", FALSE, NONE, 0, 0 },
+/*cd*/ { "", FALSE, NONE, 0, 0 },
+/*ce*/ { "", FALSE, NONE, 0, 0 },
+/*cf*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst *db_inst_0f[] = {
+ db_inst_0f0x,
+ 0,
+ db_inst_0f2x,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ db_inst_0f8x,
+ db_inst_0f9x,
+ db_inst_0fax,
+ db_inst_0fbx,
+ db_inst_0fcx,
+ db_inst_0fdx,
+ 0,
+ 0
+};
+
+char * db_Esc92[] = {
+ "fnop", "", "", "", "", "", "", ""
+};
+char * db_Esc93[] = {
+ "", "", "", "", "", "", "", ""
+};
+char * db_Esc94[] = {
+ "fchs", "fabs", "", "", "ftst", "fxam", "", ""
+};
+char * db_Esc95[] = {
+ "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz",""
+};
+char * db_Esc96[] = {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp",
+ "fincstp"
+};
+char * db_Esc97[] = {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"
+};
+
+char * db_Esca4[] = {
+ "", "fucompp","", "", "", "", "", ""
+};
+
+char * db_Escb4[] = {
+ "", "", "fnclex","fninit","", "", "", ""
+};
+
+char * db_Esce3[] = {
+ "", "fcompp","", "", "", "", "", ""
+};
+
+char * db_Escf4[] = {
+ "fnstsw","", "", "", "", "", "", ""
+};
+
+struct finst db_Esc8[] = {
+/*0*/ { "fadd", SNGL, op2(STI,ST), 0 },
+/*1*/ { "fmul", SNGL, op2(STI,ST), 0 },
+/*2*/ { "fcom", SNGL, op2(STI,ST), 0 },
+/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 },
+/*4*/ { "fsub", SNGL, op2(STI,ST), 0 },
+/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 },
+/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 },
+/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 },
+};
+
+struct finst db_Esc9[] = {
+/*0*/ { "fld", SNGL, op1(STI), 0 },
+/*1*/ { "", NONE, op1(STI), "fxch" },
+/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 },
+/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 },
+/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 },
+/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 },
+/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 },
+/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 },
+};
+
+struct finst db_Esca[] = {
+/*0*/ { "fiadd", WORD, 0, 0 },
+/*1*/ { "fimul", WORD, 0, 0 },
+/*2*/ { "ficom", WORD, 0, 0 },
+/*3*/ { "ficomp", WORD, 0, 0 },
+/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 },
+/*5*/ { "fisubr", WORD, 0, 0 },
+/*6*/ { "fidiv", WORD, 0, 0 },
+/*7*/ { "fidivr", WORD, 0, 0 }
+};
+
+struct finst db_Escb[] = {
+/*0*/ { "fild", WORD, 0, 0 },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fist", WORD, 0, 0 },
+/*3*/ { "fistp", WORD, 0, 0 },
+/*4*/ { "", WORD, op1(X), (char *)db_Escb4 },
+/*5*/ { "fld", EXTR, 0, 0 },
+/*6*/ { "", WORD, 0, 0 },
+/*7*/ { "fstp", EXTR, 0, 0 },
+};
+
+struct finst db_Escc[] = {
+/*0*/ { "fadd", DBLR, op2(ST,STI), 0 },
+/*1*/ { "fmul", DBLR, op2(ST,STI), 0 },
+/*2*/ { "fcom", DBLR, op2(ST,STI), 0 },
+/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 },
+/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" },
+/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" },
+/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" },
+/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" },
+};
+
+struct finst db_Escd[] = {
+/*0*/ { "fld", DBLR, op1(STI), "ffree" },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fst", DBLR, op1(STI), 0 },
+/*3*/ { "fstp", DBLR, op1(STI), 0 },
+/*4*/ { "frstor", NONE, op1(STI), "fucom" },
+/*5*/ { "", NONE, op1(STI), "fucomp" },
+/*6*/ { "fnsave", NONE, 0, 0 },
+/*7*/ { "fnstsw", NONE, 0, 0 },
+};
+
+struct finst db_Esce[] = {
+/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" },
+/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" },
+/*2*/ { "ficom", LONG, 0, 0 },
+/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 },
+/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" },
+/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" },
+/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" },
+/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" },
+};
+
+struct finst db_Escf[] = {
+/*0*/ { "fild", LONG, 0, 0 },
+/*1*/ { "", LONG, 0, 0 },
+/*2*/ { "fist", LONG, 0, 0 },
+/*3*/ { "fistp", LONG, 0, 0 },
+/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 },
+/*5*/ { "fld", QUAD, 0, 0 },
+/*6*/ { "fbstp", NONE, 0, 0 },
+/*7*/ { "fstp", QUAD, 0, 0 },
+};
+
+struct finst *db_Esc_inst[] = {
+ db_Esc8, db_Esc9, db_Esca, db_Escb,
+ db_Escc, db_Escd, db_Esce, db_Escf
+};
+
+char * db_Grp1[] = {
+ "add",
+ "or",
+ "adc",
+ "sbb",
+ "and",
+ "sub",
+ "xor",
+ "cmp"
+};
+
+char * db_Grp2[] = {
+ "rol",
+ "ror",
+ "rcl",
+ "rcr",
+ "shl",
+ "shr",
+ "shl",
+ "sar"
+};
+
+struct inst db_Grp3[] = {
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "not", TRUE, NONE, op1(E), 0 },
+ { "neg", TRUE, NONE, op1(E), 0 },
+ { "mul", TRUE, NONE, op2(E,A), 0 },
+ { "imul", TRUE, NONE, op2(E,A), 0 },
+ { "div", TRUE, NONE, op2(E,A), 0 },
+ { "idiv", TRUE, NONE, op2(E,A), 0 },
+};
+
+struct inst db_Grp4[] = {
+ { "inc", TRUE, BYTE, op1(E), 0 },
+ { "dec", TRUE, BYTE, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_Grp5[] = {
+ { "inc", TRUE, LONG, op1(E), 0 },
+ { "dec", TRUE, LONG, op1(E), 0 },
+ { "call", TRUE, NONE, op1(Eind),0 },
+ { "lcall", TRUE, NONE, op1(Eind),0 },
+ { "jmp", TRUE, NONE, op1(Eind),0 },
+ { "ljmp", TRUE, NONE, op1(Eind),0 },
+ { "push", TRUE, LONG, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_inst_table[256] = {
+/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 },
+/*01*/ { "add", TRUE, LONG, op2(R, E), 0 },
+/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 },
+/*03*/ { "add", TRUE, LONG, op2(E, R), 0 },
+/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 },
+/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 },
+/*06*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*07*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 },
+/*09*/ { "or", TRUE, LONG, op2(R, E), 0 },
+/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 },
+/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 },
+/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
+/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
+/*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+
+/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
+/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
+/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 },
+/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 },
+/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 },
+/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 },
+/*16*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*17*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 },
+/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 },
+/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 },
+/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 },
+/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 },
+/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 },
+/*1e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 },
+/*21*/ { "and", TRUE, LONG, op2(R, E), 0 },
+/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 },
+/*23*/ { "and", TRUE, LONG, op2(E, R), 0 },
+/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 },
+/*25*/ { "and", FALSE, LONG, op2(I, A), 0 },
+/*26*/ { "", FALSE, NONE, 0, 0 },
+/*27*/ { "aaa", FALSE, NONE, 0, 0 },
+
+/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 },
+/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 },
+/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 },
+/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 },
+/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 },
+/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "das", FALSE, NONE, 0, 0 },
+
+/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 },
+/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 },
+/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 },
+/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 },
+/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 },
+/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 },
+/*36*/ { "", FALSE, NONE, 0, 0 },
+/*37*/ { "daa", FALSE, NONE, 0, 0 },
+
+/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 },
+/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 },
+/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 },
+/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 },
+/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 },
+/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 },
+/*3e*/ { "", FALSE, NONE, 0, 0 },
+/*3f*/ { "aas", FALSE, NONE, 0, 0 },
+
+/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+
+/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+
+/*50*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*51*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*52*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*53*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*54*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*55*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*56*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*57*/ { "push", FALSE, LONG, op1(Ri), 0 },
+
+/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+
+/*60*/ { "pusha", FALSE, LONG, 0, 0 },
+/*61*/ { "popa", FALSE, LONG, 0, 0 },
+/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 },
+/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 },
+
+/*64*/ { "", FALSE, NONE, 0, 0 },
+/*65*/ { "", FALSE, NONE, 0, 0 },
+/*66*/ { "", FALSE, NONE, 0, 0 },
+/*67*/ { "", FALSE, NONE, 0, 0 },
+
+/*68*/ { "push", FALSE, LONG, op1(I), 0 },
+/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 },
+/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 },
+/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 },
+/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 },
+/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 },
+/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 },
+/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 },
+
+/*70*/ { "jo", FALSE, NONE, op1(Db), 0 },
+/*71*/ { "jno", FALSE, NONE, op1(Db), 0 },
+/*72*/ { "jb", FALSE, NONE, op1(Db), 0 },
+/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 },
+/*74*/ { "jz", FALSE, NONE, op1(Db), 0 },
+/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 },
+/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 },
+/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 },
+
+/*78*/ { "js", FALSE, NONE, op1(Db), 0 },
+/*79*/ { "jns", FALSE, NONE, op1(Db), 0 },
+/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 },
+/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 },
+/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 },
+/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 },
+/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
+/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
+
+/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 },
+/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 },
+/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 },
+/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 },
+/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
+/*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
+/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
+/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 },
+
+/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 },
+/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 },
+/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 },
+/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 },
+/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 },
+/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 },
+/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 },
+/*8f*/ { "pop", TRUE, LONG, op1(E), 0 },
+
+/*90*/ { "nop", FALSE, NONE, 0, 0 },
+/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+
+/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
+/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
+/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
+/*9b*/ { "wait", FALSE, NONE, 0, 0 },
+/*9c*/ { "pushf", FALSE, LONG, 0, 0 },
+/*9d*/ { "popf", FALSE, LONG, 0, 0 },
+/*9e*/ { "sahf", FALSE, NONE, 0, 0 },
+/*9f*/ { "lahf", FALSE, NONE, 0, 0 },
+
+/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 },
+/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 },
+/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 },
+/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 },
+/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 },
+/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 },
+/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 },
+/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 },
+
+/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 },
+/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 },
+/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 },
+/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 },
+/*ac*/ { "ldos", FALSE, BYTE, op1(SI), 0 },
+/*ad*/ { "ldos", FALSE, LONG, op1(SI), 0 },
+/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 },
+/*af*/ { "scas", FALSE, LONG, op1(SI), 0 },
+
+/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+
+/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+
+/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 },
+/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 },
+/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
+/*c3*/ { "ret", FALSE, NONE, 0, 0 },
+/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
+/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 },
+/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 },
+/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 },
+
+/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 },
+/*c9*/ { "leave", FALSE, NONE, 0, 0 },
+/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 },
+/*cb*/ { "lret", FALSE, NONE, 0, 0 },
+/*cc*/ { "int", FALSE, NONE, op1(o3), 0 },
+/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 },
+/*ce*/ { "into", FALSE, NONE, 0, 0 },
+/*cf*/ { "iret", FALSE, NONE, 0, 0 },
+
+/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 },
+/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 },
+/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 },
+/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 },
+/*d4*/ { "aam", TRUE, NONE, 0, 0 },
+/*d5*/ { "aad", TRUE, NONE, 0, 0 },
+/*d6*/ { "", FALSE, NONE, 0, 0 },
+/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
+
+/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 },
+/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 },
+/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca },
+/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb },
+/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc },
+/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd },
+/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce },
+/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf },
+
+/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
+/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
+/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
+/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
+/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
+/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
+/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
+/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 },
+
+/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 },
+/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 },
+/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 },
+/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 },
+/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 },
+/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 },
+/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 },
+/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 },
+
+/*f0*/ { "", FALSE, NONE, 0, 0 },
+/*f1*/ { "", FALSE, NONE, 0, 0 },
+/*f2*/ { "", FALSE, NONE, 0, 0 },
+/*f3*/ { "", FALSE, NONE, 0, 0 },
+/*f4*/ { "hlt", FALSE, NONE, 0, 0 },
+/*f5*/ { "cmc", FALSE, NONE, 0, 0 },
+/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 },
+/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 },
+
+/*f8*/ { "clc", FALSE, NONE, 0, 0 },
+/*f9*/ { "stc", FALSE, NONE, 0, 0 },
+/*fa*/ { "cli", FALSE, NONE, 0, 0 },
+/*fb*/ { "sti", FALSE, NONE, 0, 0 },
+/*fc*/ { "cld", FALSE, NONE, 0, 0 },
+/*fd*/ { "std", FALSE, NONE, 0, 0 },
+/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 },
+/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 },
+};
+
+struct inst db_bad_inst =
+ { "???", FALSE, NONE, 0, 0 }
+;
+
+#define f_mod(byte) ((byte)>>6)
+#define f_reg(byte) (((byte)>>3)&0x7)
+#define f_rm(byte) ((byte)&0x7)
+
+#define sib_ss(byte) ((byte)>>6)
+#define sib_index(byte) (((byte)>>3)&0x7)
+#define sib_base(byte) ((byte)&0x7)
+
+struct i_addr {
+ int is_reg; /* if reg, reg number is in 'disp' */
+ int disp;
+ char * base;
+ char * index;
+ int ss;
+};
+
+char * db_index_reg_16[8] = {
+ "%bx,%si",
+ "%bx,%di",
+ "%bp,%si",
+ "%bp,%di",
+ "%si",
+ "%di",
+ "%bp",
+ "%bx"
+};
+
+char * db_reg[3][8] = {
+ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
+ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"
+};
+
+char * db_seg_reg[8] = {
+ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", ""
+};
+
+/*
+ * lengths for size attributes
+ */
+int db_lengths[] = {
+ 1, /* BYTE */
+ 2, /* WORD */
+ 4, /* LONG */
+ 8, /* QUAD */
+ 4, /* SNGL */
+ 8, /* DBLR */
+ 10, /* EXTR */
+};
+
+#define get_value_inc(result, loc, size, is_signed) \
+ result = db_get_value((loc), (size), (is_signed)); \
+ (loc) += (size);
+
+/*
+ * Read address at location and return updated location.
+ */
+db_addr_t
+db_read_address(loc, short_addr, regmodrm, addrp)
+ db_addr_t loc;
+ int short_addr;
+ int regmodrm;
+ struct i_addr *addrp; /* out */
+{
+ int mod, rm, sib, index, ss, disp;
+
+ mod = f_mod(regmodrm);
+ rm = f_rm(regmodrm);
+
+ if (mod == 3) {
+ addrp->is_reg = TRUE;
+ addrp->disp = rm;
+ return (loc);
+ }
+ addrp->is_reg = FALSE;
+ addrp->index = 0;
+
+ if (short_addr) {
+ addrp->index = 0;
+ addrp->ss = 0;
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_index_reg_16[rm];
+ }
+ break;
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ case 2:
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ }
+ }
+ else {
+ if (mod != 3 && rm == 4) {
+ get_value_inc(sib, loc, 1, FALSE);
+ rm = sib_base(sib);
+ index = sib_index(sib);
+ if (index != 4)
+ addrp->index = db_reg[LONG][index];
+ addrp->ss = sib_ss(sib);
+ }
+
+ switch (mod) {
+ case 0:
+ if (rm == 5) {
+ get_value_inc(addrp->disp, loc, 4, FALSE);
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_reg[LONG][rm];
+ }
+ break;
+
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+
+ case 2:
+ get_value_inc(disp, loc, 4, FALSE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+ }
+ }
+ return (loc);
+}
+
+void
+db_print_address(seg, size, addrp)
+ char * seg;
+ int size;
+ struct i_addr *addrp;
+{
+ if (addrp->is_reg) {
+ db_printf("%s", db_reg[size][addrp->disp]);
+ return;
+ }
+
+ if (seg) {
+ db_printf("%s:", seg);
+ }
+
+ db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY);
+ if (addrp->base != 0 || addrp->index != 0) {
+ db_printf("(");
+ if (addrp->base)
+ db_printf("%s", addrp->base);
+ if (addrp->index)
+ db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
+ db_printf(")");
+ }
+}
+
+/*
+ * Disassemble floating-point ("escape") instruction
+ * and return updated location.
+ */
+db_addr_t
+db_disasm_esc(loc, inst, short_addr, size, seg)
+ db_addr_t loc;
+ int inst;
+ int short_addr;
+ int size;
+ char * seg;
+{
+ int regmodrm;
+ struct finst *fp;
+ int mod;
+ struct i_addr address;
+ char * name;
+
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)];
+ mod = f_mod(regmodrm);
+ if (mod != 3) {
+ /*
+ * Normal address modes.
+ */
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ db_printf(fp->f_name);
+ switch(fp->f_size) {
+ case SNGL:
+ db_printf("s");
+ break;
+ case DBLR:
+ db_printf("l");
+ break;
+ case EXTR:
+ db_printf("t");
+ break;
+ case WORD:
+ db_printf("s");
+ break;
+ case LONG:
+ db_printf("l");
+ break;
+ case QUAD:
+ db_printf("q");
+ break;
+ default:
+ break;
+ }
+ db_printf("\t");
+ db_print_address(seg, BYTE, &address);
+ }
+ else {
+ /*
+ * 'reg-reg' - special formats
+ */
+ switch (fp->f_rrmode) {
+ case op2(ST,STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
+ break;
+ case op2(STI,ST):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
+ break;
+ case op1(STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d)",name, f_rm(regmodrm));
+ break;
+ case op1(X):
+ db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ case op1(XA):
+ db_printf("%s\t%%ax",
+ ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ default:
+ db_printf("<bad instruction>");
+ break;
+ }
+ }
+
+ return (loc);
+}
+
+/*
+ * Disassemble instruction at 'loc'. 'altfmt' specifies an
+ * (optional) alternate format. Return address of start of
+ * next instruction.
+ */
+db_addr_t
+db_disasm(loc, altfmt)
+ db_addr_t loc;
+ boolean_t altfmt;
+{
+ int inst;
+ int size;
+ int short_addr;
+ char * seg;
+ struct inst * ip;
+ char * i_name;
+ int i_size;
+ int i_mode;
+ int regmodrm;
+ boolean_t first;
+ int displ;
+ int prefix;
+ int imm;
+ int imm2;
+ int len;
+ struct i_addr address;
+
+ get_value_inc(inst, loc, 1, FALSE);
+ short_addr = FALSE;
+ size = LONG;
+ seg = 0;
+
+ /*
+ * Get prefixes
+ */
+ prefix = TRUE;
+ do {
+ switch (inst) {
+ case 0x66: /* data16 */
+ size = WORD;
+ break;
+ case 0x67:
+ short_addr = TRUE;
+ break;
+ case 0x26:
+ seg = "%es";
+ break;
+ case 0x36:
+ seg = "%ss";
+ break;
+ case 0x2e:
+ seg = "%cs";
+ break;
+ case 0x3e:
+ seg = "%ds";
+ break;
+ case 0x64:
+ seg = "%fs";
+ break;
+ case 0x65:
+ seg = "%gs";
+ break;
+ case 0xf0:
+ db_printf("lock ");
+ break;
+ case 0xf2:
+ db_printf("repne ");
+ break;
+ case 0xf3:
+ db_printf("repe "); /* XXX repe VS rep */
+ break;
+ default:
+ prefix = FALSE;
+ break;
+ }
+ if (prefix) {
+ get_value_inc(inst, loc, 1, FALSE);
+ }
+ } while (prefix);
+
+ if (inst >= 0xd8 && inst <= 0xdf) {
+ loc = db_disasm_esc(loc, inst, short_addr, size, seg);
+ db_printf("\n");
+ return (loc);
+ }
+
+ if (inst == 0x0f) {
+ get_value_inc(inst, loc, 1, FALSE);
+ ip = db_inst_0f[inst>>4];
+ if (ip == 0) {
+ ip = &db_bad_inst;
+ }
+ else {
+ ip = &ip[inst&0xf];
+ }
+ }
+ else
+ ip = &db_inst_table[inst];
+
+ if (ip->i_has_modrm) {
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ }
+
+ i_name = ip->i_name;
+ i_size = ip->i_size;
+ i_mode = ip->i_mode;
+
+ if (ip->i_extra == (char *)db_Grp1 ||
+ ip->i_extra == (char *)db_Grp2 ||
+ ip->i_extra == (char *)db_Grp6 ||
+ ip->i_extra == (char *)db_Grp7 ||
+ ip->i_extra == (char *)db_Grp8) {
+ i_name = ((char **)ip->i_extra)[f_reg(regmodrm)];
+ }
+ else if (ip->i_extra == (char *)db_Grp3) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ }
+ else if (ip->i_extra == (char *)db_Grp4 ||
+ ip->i_extra == (char *)db_Grp5) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ i_size = ip->i_size;
+ }
+
+ if (i_size == SDEP) {
+ if (size == WORD)
+ db_printf(i_name);
+ else
+ db_printf(ip->i_extra);
+ }
+ else {
+ db_printf(i_name);
+ if (i_size != NONE) {
+ if (i_size == BYTE) {
+ db_printf("b");
+ size = BYTE;
+ }
+ else if (i_size == WORD) {
+ db_printf("w");
+ size = WORD;
+ }
+ else if (size == WORD)
+ db_printf("w");
+ else
+ db_printf("l");
+ }
+ }
+ db_printf("\t");
+ for (first = TRUE;
+ i_mode != 0;
+ i_mode >>= 8, first = FALSE)
+ {
+ if (!first)
+ db_printf(",");
+
+ switch (i_mode & 0xFF) {
+
+ case E:
+ db_print_address(seg, size, &address);
+ break;
+
+ case Eind:
+ db_printf("*");
+ db_print_address(seg, size, &address);
+ break;
+
+ case Ew:
+ db_print_address(seg, WORD, &address);
+ break;
+
+ case Eb:
+ db_print_address(seg, BYTE, &address);
+ break;
+
+ case R:
+ db_printf("%s", db_reg[size][f_reg(regmodrm)]);
+ break;
+
+ case Rw:
+ db_printf("%s", db_reg[WORD][f_reg(regmodrm)]);
+ break;
+
+ case Ri:
+ db_printf("%s", db_reg[size][f_rm(inst)]);
+ break;
+
+ case S:
+ db_printf("%s", db_seg_reg[f_reg(regmodrm)]);
+ break;
+
+ case Si:
+ db_printf("%s", db_seg_reg[f_reg(inst)]);
+ break;
+
+ case A:
+ db_printf("%s", db_reg[size][0]); /* acc */
+ break;
+
+ case BX:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%bx" : "%ebx");
+ break;
+
+ case CL:
+ db_printf("%%cl");
+ break;
+
+ case DX:
+ db_printf("%%dx");
+ break;
+
+ case SI:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%si" : "%esi");
+ break;
+
+ case DI:
+ db_printf("%%es:(%s)", short_addr ? "%di" : "%edi");
+ break;
+
+ case CR:
+ db_printf("%%cr%d", f_reg(regmodrm));
+ break;
+
+ case DR:
+ db_printf("%%dr%d", f_reg(regmodrm));
+ break;
+
+ case TR:
+ db_printf("%%tr%d", f_reg(regmodrm));
+ break;
+
+ case I:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, FALSE);/* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Is:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Ib:
+ get_value_inc(imm, loc, 1, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Ibs:
+ get_value_inc(imm, loc, 1, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Iw:
+ get_value_inc(imm, loc, 2, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Il:
+ get_value_inc(imm, loc, 4, FALSE);
+ db_printf("$%#n", imm);
+ break;
+
+ case O:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE);
+ }
+ if (seg)
+ db_printf("%s:%#r",seg, displ);
+ else
+ db_printsym((db_addr_t)displ, DB_STGY_ANY);
+ break;
+
+ case Db:
+ get_value_inc(displ, loc, 1, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case Dl:
+ get_value_inc(displ, loc, 4, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case o1:
+ db_printf("$1");
+ break;
+
+ case o3:
+ db_printf("$3");
+ break;
+
+ case OS:
+ get_value_inc(imm, loc, 4, FALSE); /* offset */
+ get_value_inc(imm2, loc, 2, FALSE); /* segment */
+ db_printf("$%#n,%#n", imm2, imm);
+ break;
+ }
+ }
+
+ if (altfmt == 0) {
+ if (inst == 0xe9 || inst == 0xeb) {
+ /*
+ * GAS pads to longword boundary after unconditional jumps.
+ */
+ loc = (loc + (4-1)) & ~(4-1);
+ }
+ }
+ db_printf("\n");
+ return (loc);
+}
+
diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c
new file mode 100644
index 0000000..31e7849
--- /dev/null
+++ b/sys/i386/i386/db_interface.c
@@ -0,0 +1,255 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_interface.c,v $
+ * Revision 1.1 1992/03/25 21:42:03 pace
+ * Initial revision
+ *
+ * Revision 2.4 91/02/05 17:11:13 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:17 mrt]
+ *
+ * Revision 2.3 90/12/04 14:45:55 jsb
+ * Changes for merged intel/pmap.{c,h}.
+ * [90/12/04 11:14:41 jsb]
+ *
+ * Revision 2.2 90/10/25 14:44:43 rwd
+ * Added watchpoint support.
+ * [90/10/18 rpd]
+ *
+ * Created.
+ * [90/07/25 dbg]
+ *
+ *
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <sys/reboot.h>
+#include <vm/vm_statistics.h>
+#include <vm/pmap.h>
+
+#include <setjmp.h>
+#include <sys/systm.h> /* just for boothowto --eichin */
+int db_active = 0;
+
+/*
+ * Received keyboard interrupt sequence.
+ */
+kdb_kbd_trap(regs)
+ struct i386_saved_state *regs;
+{
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ kdb_trap(-1, 0, regs);
+ }
+}
+
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+
+static jmp_buf *db_nofault = 0;
+
+kdb_trap(type, code, regs)
+ int type, code;
+ register struct i386_saved_state *regs;
+{
+#if 0
+ if ((boothowto&RB_KDB) == 0)
+ return(0);
+#endif
+
+ switch (type) {
+ case T_BPTFLT /* T_INT3 */: /* breakpoint */
+ case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */
+ case T_PRIVINFLT /* T_DEBUG */: /* single_step */
+
+ case -1: /* keyboard interrupt */
+ break;
+
+ default:
+ kdbprinttrap(type, code);
+
+ if (db_nofault) {
+ jmp_buf *no_fault = db_nofault;
+ db_nofault = 0;
+ longjmp(*no_fault, 1);
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ if ((regs->tf_cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ ddb_regs.tf_esp = (int)&regs->tf_esp; /* kernel stack pointer */
+#if 0
+ ddb_regs.ss = KERNEL_DS;
+#endif
+ asm(" movw %%ss,%%ax; movl %%eax,%0 "
+ : "=g" (ddb_regs.tf_ss)
+ :
+ : "ax");
+ }
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, code);
+ cnpollc(FALSE);
+ db_active--;
+
+ regs->tf_eip = ddb_regs.tf_eip;
+ regs->tf_eflags = ddb_regs.tf_eflags;
+ regs->tf_eax = ddb_regs.tf_eax;
+ regs->tf_ecx = ddb_regs.tf_ecx;
+ regs->tf_edx = ddb_regs.tf_edx;
+ regs->tf_ebx = ddb_regs.tf_ebx;
+ if (regs->tf_cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */
+ regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */
+ }
+ regs->tf_ebp = ddb_regs.tf_ebp;
+ regs->tf_esi = ddb_regs.tf_esi;
+ regs->tf_edi = ddb_regs.tf_edi;
+ regs->tf_es = ddb_regs.tf_es & 0xffff;
+ regs->tf_cs = ddb_regs.tf_cs & 0xffff;
+ regs->tf_ds = ddb_regs.tf_ds & 0xffff;
+#if 0
+ regs->tf_fs = ddb_regs.tf_fs & 0xffff;
+ regs->tf_gs = ddb_regs.tf_gs & 0xffff;
+#endif
+
+ return (1);
+}
+
+/*
+ * Print trap reason.
+ */
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ printf("type %d", type);
+ printf(" trap, code=%x\n", code);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+
+extern jmp_buf db_jmpbuf;
+
+void
+db_read_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *src;
+
+ db_nofault = &db_jmpbuf;
+
+ src = (char *)addr;
+ while (--size >= 0)
+ *data++ = *src++;
+
+ db_nofault = 0;
+}
+
+struct pte *pmap_pte(pmap_t, vm_offset_t);
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *dst;
+
+ register pt_entry_t *ptep0 = 0;
+ pt_entry_t oldmap0 = { 0 };
+ vm_offset_t addr1;
+ register pt_entry_t *ptep1 = 0;
+ pt_entry_t oldmap1 = { 0 };
+ extern char etext;
+
+ db_nofault = &db_jmpbuf;
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS &&
+ addr <= (vm_offset_t)&etext)
+ {
+ ptep0 = pmap_pte(kernel_pmap, addr);
+ oldmap0 = *ptep0;
+ *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW;
+
+ addr1 = i386_trunc_page(addr + size - 1);
+ if (i386_trunc_page(addr) != addr1) {
+ /* data crosses a page boundary */
+
+ ptep1 = pmap_pte(kernel_pmap, addr1);
+ oldmap1 = *ptep1;
+ *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW;
+ }
+ tlbflush();
+ }
+
+ dst = (char *)addr;
+
+ while (--size >= 0)
+ *dst++ = *data++;
+
+ db_nofault = 0;
+
+ if (ptep0) {
+ *ptep0 = oldmap0;
+ if (ptep1) {
+ *ptep1 = oldmap1;
+ }
+ tlbflush();
+ }
+}
+
+Debugger (msg)
+char *msg;
+{
+ asm ("int $3");
+}
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
new file mode 100644
index 0000000..cbffbbc
--- /dev/null
+++ b/sys/i386/i386/db_trace.c
@@ -0,0 +1,292 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_trace.c,v $
+ * Revision 1.1 1992/03/25 21:42:05 pace
+ * Initial revision
+ *
+ * Revision 2.6 91/02/05 17:11:21 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:32 mrt]
+ *
+ * Revision 2.5 91/01/09 19:55:27 rpd
+ * Fixed stack tracing for threads without kernel stacks.
+ * [91/01/09 rpd]
+ *
+ * Revision 2.4 91/01/08 15:10:22 rpd
+ * Reorganized the pcb.
+ * [90/12/11 rpd]
+ *
+ * Revision 2.3 90/11/05 14:27:07 rpd
+ * If we can not guess the number of args to a function, use 5 vs 0.
+ * [90/11/02 rvb]
+ *
+ * Revision 2.2 90/08/27 21:56:20 dbg
+ * Import db_sym.h.
+ * [90/08/21 dbg]
+ * Fix includes.
+ * [90/08/08 dbg]
+ * Created from rvb's code for new debugger.
+ * [90/07/11 dbg]
+ *
+ */
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+ "cs", (int *)&ddb_regs.tf_cs, FCN_NULL,
+ "ds", (int *)&ddb_regs.tf_ds, FCN_NULL,
+ "es", (int *)&ddb_regs.tf_es, FCN_NULL,
+#if 0
+ "fs", (int *)&ddb_regs.tf_fs, FCN_NULL,
+ "gs", (int *)&ddb_regs.tf_gs, FCN_NULL,
+#endif
+ "ss", (int *)&ddb_regs.tf_ss, FCN_NULL,
+ "eax", (int *)&ddb_regs.tf_eax, FCN_NULL,
+ "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL,
+ "edx", (int *)&ddb_regs.tf_edx, FCN_NULL,
+ "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL,
+ "esp", (int *)&ddb_regs.tf_esp,FCN_NULL,
+ "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL,
+ "esi", (int *)&ddb_regs.tf_esi, FCN_NULL,
+ "edi", (int *)&ddb_regs.tf_edi, FCN_NULL,
+ "eip", (int *)&ddb_regs.tf_eip, FCN_NULL,
+ "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL,
+};
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Stack trace.
+ */
+#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+struct i386_frame {
+ struct i386_frame *f_frame;
+ int f_retaddr;
+ int f_arg0;
+};
+
+#define TRAP 1
+#define INTERRUPT 2
+
+db_addr_t db_trap_symbol_value = 0;
+db_addr_t db_kdintr_symbol_value = 0;
+boolean_t db_trace_symbols_found = FALSE;
+
+void
+db_find_trace_symbols()
+{
+ db_expr_t value;
+ if (db_value_of_name("_trap", &value))
+ db_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_kdintr", &value))
+ db_kdintr_symbol_value = (db_addr_t) value;
+ db_trace_symbols_found = TRUE;
+}
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+int
+db_numargs(fp)
+ struct i386_frame *fp;
+{
+ int *argp;
+ int inst;
+ int args;
+ extern char etext[];
+
+ argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
+ if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
+ args = 5;
+ else {
+ inst = db_get_value((int)argp, 4, FALSE);
+ if ((inst & 0xff) == 0x59) /* popl %ecx */
+ args = 1;
+ else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
+ args = ((inst >> 16) & 0xff) / 4;
+ else
+ args = 5;
+ }
+ return (args);
+}
+
+/*
+ * Figure out the next frame up in the call stack.
+ * For trap(), we print the address of the faulting instruction and
+ * proceed with the calling frame. We return the ip that faulted.
+ * If the trap was caused by jumping through a bogus pointer, then
+ * the next line in the backtrace will list some random function as
+ * being called. It should get the argument list correct, though.
+ * It might be possible to dig out from the next frame up the name
+ * of the function that faulted, but that could get hairy.
+ */
+void
+db_nextframe(fp, ip, argp, is_trap)
+ struct i386_frame **fp; /* in/out */
+ db_addr_t *ip; /* out */
+ int *argp; /* in */
+ int is_trap; /* in */
+{
+ struct i386_saved_state *saved_regs;
+
+ if (is_trap == 0) {
+ *ip = (db_addr_t)
+ db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
+ *fp = (struct i386_frame *)
+ db_get_value((int) &(*fp)->f_frame, 4, FALSE);
+ } else {
+ /*
+ * We know that trap() has 1 argument and we know that
+ * it is an (int *).
+ */
+ saved_regs = (struct i386_saved_state *)
+ db_get_value((int)argp, 4, FALSE);
+ db_printf("--- trap (number %d) ---\n",
+ saved_regs->tf_trapno & 0xffff);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ }
+
+}
+
+void
+db_stack_trace_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct i386_frame *frame, *lastframe;
+ int *argp;
+ db_addr_t callpc;
+ int is_trap;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+
+ if (!db_trace_symbols_found)
+ db_find_trace_symbols();
+
+ {
+ register char *cp = modif;
+ register char c;
+
+ while ((c = *cp++) != 0) {
+ if (c == 't')
+ trace_thread = TRUE;
+ if (c == 'u')
+ kernel_only = FALSE;
+ }
+ }
+
+ if (count == -1)
+ count = 65535;
+
+ if (!have_addr) {
+ frame = (struct i386_frame *)ddb_regs.tf_ebp;
+ callpc = (db_addr_t)ddb_regs.tf_eip;
+ }
+ else if (trace_thread) {
+ printf ("db_trace.c: can't trace thread\n");
+ }
+ else {
+ frame = (struct i386_frame *)addr;
+ callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
+ }
+
+ lastframe = 0;
+ while (count-- && frame != 0) {
+ register int narg;
+ char * name;
+ db_expr_t offset;
+
+ if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) {
+ narg = 1;
+ is_trap = TRAP;
+ }
+ else
+ if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) {
+ is_trap = INTERRUPT;
+ narg = 0;
+ }
+ else {
+ is_trap = 0;
+ narg = db_numargs(frame);
+ }
+
+ db_find_sym_and_offset(callpc, &name, &offset);
+ db_printf("%s(", name);
+
+ argp = &frame->f_arg0;
+ while (narg) {
+ db_printf("%x", db_get_value((int)argp, 4, FALSE));
+ argp++;
+ if (--narg != 0)
+ db_printf(",");
+ }
+ db_printf(") at ");
+ db_printsym(callpc, DB_STGY_XTRN);
+ db_printf("\n");
+
+ lastframe = frame;
+ db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
+
+ if (frame == 0) {
+ /* end of chain */
+ break;
+ }
+ if (INKERNEL((int)frame)) {
+ /* staying in kernel */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ else if (INKERNEL((int)lastframe)) {
+ /* switch from user to kernel */
+ if (kernel_only)
+ break; /* kernel stack only */
+ }
+ else {
+ /* in user */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c
new file mode 100644
index 0000000..18ec37b
--- /dev/null
+++ b/sys/i386/i386/genassym.c
@@ -0,0 +1,174 @@
+/*-
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)genassym.c 5.11 (Berkeley) 5/10/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 24 Apr 93 Bruce Evans/Dave Rivers Npx-0.5 support
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/genassym.c,v 1.2 92/01/21 14:22:02 william Exp $";
+
+#ifndef lint
+static char sccsid[] = "@(#)genassym.c 5.11 (Berkeley) 5/10/91";
+#endif /* not lint */
+
+#include "sys/param.h"
+#include "sys/buf.h"
+#include "sys/vmmeter.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/mbuf.h"
+#include "sys/msgbuf.h"
+#include "sys/resourcevar.h"
+#include "machine/cpu.h"
+#include "machine/trap.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "sys/syscall.h"
+#include "vm/vm_param.h"
+#include "vm/vm_map.h"
+#include "machine/pmap.h"
+
+main()
+{
+ struct proc *p = (struct proc *)0;
+ struct vmmeter *vm = (struct vmmeter *)0;
+ struct user *up = (struct user *)0;
+ struct rusage *rup = (struct rusage *)0;
+ struct uprof *uprof = (struct uprof *)0;
+ struct vmspace *vms = (struct vmspace *)0;
+ vm_map_t map = (vm_map_t)0;
+ pmap_t pmap = (pmap_t)0;
+ struct pcb *pcb = (struct pcb *)0;
+ register unsigned i;
+
+ printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT);
+ printf("#define\tUDOT_SZ %d\n", sizeof(struct user));
+ printf("#define\tP_LINK %d\n", &p->p_link);
+ printf("#define\tP_RLINK %d\n", &p->p_rlink);
+ printf("#define\tP_VMSPACE %d\n", &p->p_vmspace);
+ printf("#define\tVM_PMAP %d\n", &vms->vm_pmap);
+ printf("#define\tP_ADDR %d\n", &p->p_addr);
+ printf("#define\tP_PRI %d\n", &p->p_pri);
+ printf("#define\tP_STAT %d\n", &p->p_stat);
+ printf("#define\tP_WCHAN %d\n", &p->p_wchan);
+ printf("#define\tP_FLAG %d\n", &p->p_flag);
+ printf("#define\tP_PID %d\n", &p->p_pid);
+ printf("#define\tSSLEEP %d\n", SSLEEP);
+ printf("#define\tSRUN %d\n", SRUN);
+ printf("#define\tV_SWTCH %d\n", &vm->v_swtch);
+ printf("#define\tV_TRAP %d\n", &vm->v_trap);
+ printf("#define\tV_SYSCALL %d\n", &vm->v_syscall);
+ printf("#define\tV_INTR %d\n", &vm->v_intr);
+ printf("#define\tV_SOFT %d\n", &vm->v_soft);
+ printf("#define\tV_PDMA %d\n", &vm->v_pdma);
+ printf("#define\tV_FAULTS %d\n", &vm->v_faults);
+ printf("#define\tV_PGREC %d\n", &vm->v_pgrec);
+ printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec);
+ printf("#define\tUPAGES %d\n", UPAGES);
+ printf("#define\tHIGHPAGES %d\n", HIGHPAGES);
+ printf("#define\tCLSIZE %d\n", CLSIZE);
+ printf("#define\tNBPG %d\n", NBPG);
+ printf("#define\tNPTEPG %d\n", NPTEPG);
+ printf("#define\tPGSHIFT %d\n", PGSHIFT);
+ printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE);
+ printf("#define\tUSRPTSIZE %d\n", USRPTSIZE);
+ printf("#define\tUSRIOSIZE %d\n", USRIOSIZE);
+#ifdef SYSVSHM
+ printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS);
+#endif
+ printf("#define\tUSRSTACK %d\n", USRSTACK);
+ printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf)));
+ printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS);
+ printf("#define\tMCLBYTES %d\n", MCLBYTES);
+ printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link);
+ printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0);
+ printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0);
+ printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1);
+ printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1);
+ printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2);
+ printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2);
+ printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3);
+ printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip);
+ printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags);
+ printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax);
+ printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx);
+ printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx);
+ printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx);
+ printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp);
+ printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp);
+ printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi);
+ printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi);
+ printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es);
+ printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs);
+ printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss);
+ printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds);
+ printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs);
+ printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs);
+ printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt);
+ printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt);
+ printf("#define\tNKMEMCLUSTERS %d\n", NKMEMCLUSTERS);
+ printf("#define\tU_PROF %d\n", &up->u_stats.p_prof);
+ printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale);
+ printf("#define\tPR_BASE %d\n", &uprof->pr_base);
+ printf("#define\tPR_SIZE %d\n", &uprof->pr_size);
+ printf("#define\tPR_OFF %d\n", &uprof->pr_off);
+ printf("#define\tPR_SCALE %d\n", &uprof->pr_scale);
+ printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt);
+ printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags);
+ printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu);
+#ifdef notused
+ printf("#define\tFP_WASUSED %d\n", FP_WASUSED);
+ printf("#define\tFP_NEEDSSAVE %d\n", FP_NEEDSSAVE);
+ printf("#define\tFP_NEEDSRESTORE %d\n", FP_NEEDSRESTORE);
+#endif
+ printf("#define\tFP_USESEMC %d\n", FP_USESEMC);
+ printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc);
+ printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2);
+ printf("#define\tPCB_SIGC %d\n", pcb->pcb_sigc);
+ printf("#define\tPCB_IML %d\n", &pcb->pcb_iml);
+ printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault);
+
+ printf("#define\tB_READ %d\n", B_READ);
+ printf("#define\tENOENT %d\n", ENOENT);
+ printf("#define\tEFAULT %d\n", EFAULT);
+ printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG);
+ exit(0);
+}
diff --git a/sys/i386/i386/in_cksum.c b/sys/i386/i386/in_cksum.c
new file mode 100644
index 0000000..335dd35
--- /dev/null
+++ b/sys/i386/i386/in_cksum.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from tahoe: in_cksum.c 1.2 86/01/05
+ * @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00104
+ * -------------------- ----- ----------------------
+ *
+ * 24 Jul 92 Bakul Shah Optimized some more
+ *
+ * 920724 i386 changes by Bakul Shah <bvs@bitblocks.com>
+ */
+
+#include "param.h"
+#include "sys/mbuf.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers.
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * This implementation is 386 version.
+ */
+
+#undef ADDCARRY
+#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff
+#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
+
+/*
+ * Thanks to gcc we don't have to guess
+ * which registers contain sum & w.
+ */
+#define CLC asm("clc")
+#define ADD(n) asm("adcl " #n "(%2), %0": "=r"(sum): "0"(sum), "r"(w))
+#define MOP asm("adcl $0, %0": "=r"(sum): "0"(sum))
+
+in_cksum(m, len)
+ register struct mbuf *m;
+ register int len;
+{
+ register u_short *w;
+ register unsigned sum = 0;
+ register int mlen = 0;
+ int byte_swapped = 0;
+ union { char c[2]; u_short s; } su;
+
+ for (;m && len; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ w = mtod(m, u_short *);
+ if (mlen == -1) {
+ /*
+ * The first byte of this mbuf is the continuation
+ * of a word spanning between this mbuf and the
+ * last mbuf.
+ */
+
+ /* su.c[0] is already saved when scanning previous
+ * mbuf. sum was REDUCEd when we found mlen == -1
+ */
+ su.c[1] = *(u_char *)w;
+ sum += su.s;
+ w = (u_short *)((char *)w + 1);
+ mlen = m->m_len - 1;
+ len--;
+ } else
+ mlen = m->m_len;
+ if (len < mlen)
+ mlen = len;
+ len -= mlen;
+ /*
+ * Force to long boundary so we do longword aligned
+ * memory operations
+ */
+ if (3 & (int) w) {
+ REDUCE;
+ if ((1 & (int) w) && (mlen > 0)) {
+ sum <<= 8;
+ su.c[0] = *(char *)w;
+ w = (u_short *)((char *)w + 1);
+ mlen--;
+ byte_swapped = 1;
+ }
+ if ((2 & (int) w) && (mlen >= 2)) {
+ sum += *w++;
+ mlen -= 2;
+ }
+ }
+ /*
+ * Do as much of the checksum as possible 32 bits at at time.
+ * In fact, this loop is unrolled to make overhead from
+ * branches &c small.
+ */
+ while ((mlen -= 32) >= 0) {
+ /*
+ * Clear the carry flag, add with carry 16 words
+ * and fold-in last carry by adding a 0 with carry.
+ */
+ CLC;
+ ADD(0); ADD(4); ADD(8); ADD(12);
+ ADD(16); ADD(20); ADD(24); ADD(28);
+ MOP; w += 16;
+ }
+ mlen += 32;
+ while ((mlen -= 8) >= 0) {
+ CLC;
+ ADD(0); ADD(4);
+ MOP;
+ w += 4;
+ }
+ mlen += 8;
+ if (mlen == 0 && byte_swapped == 0)
+ continue; /* worth 1% maybe ?? */
+ REDUCE;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++;
+ }
+ if (byte_swapped) {
+ sum <<= 8;
+ byte_swapped = 0;
+ if (mlen == -1) {
+ su.c[1] = *(char *)w;
+ sum += su.s;
+ mlen = 0;
+ } else
+ mlen = -1;
+ } else if (mlen == -1)
+ /*
+ * This mbuf has odd number of bytes.
+ * There could be a word split betwen
+ * this mbuf and the next mbuf.
+ * Save the last byte (to prepend to next mbuf).
+ */
+ su.c[0] = *(char *)w;
+ }
+
+ if (len)
+ printf("cksum: out of data\n");
+ if (mlen == -1) {
+ /* The last mbuf has odd # of bytes. Follow the
+ standard (the odd byte is shifted left by 8 bits) */
+ su.c[1] = 0;
+ sum += su.s;
+ }
+ REDUCE;
+ return (~sum & 0xffff);
+}
+
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
new file mode 100644
index 0000000..d558dba
--- /dev/null
+++ b/sys/i386/i386/locore.s
@@ -0,0 +1,1830 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)locore.s 7.3 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 06 Aug 92 Pace Willisson Allow VGA memory to be mapped
+ * 28 Nov 92 Frank MacLachlan Aligned addresses and data
+ * on 32bit boundaries.
+ * 25 Mar 93 Kevin Lahey Add syscall counter for vmstat
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1)
+ */
+
+
+/*
+ * locore.s: 4BSD machine support for the Intel 386
+ * Preliminary version
+ * Written by William F. Jolitz, 386BSD Project
+ */
+
+#include "assym.s"
+#include "machine/psl.h"
+#include "machine/pte.h"
+
+#include "errno.h"
+
+#include "machine/trap.h"
+
+#include "machine/specialreg.h"
+#include "i386/isa/debug.h"
+
+#define KDSEL 0x10
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+/*
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+ .set IDXSHIFT,10
+ .set SYSTEM,0xFE000000 # virtual address of system start
+ /*note: gas copys sign bit (e.g. arithmetic >>), can't do SYSTEM>>22! */
+ .set SYSPDROFF,0x3F8 # Page dir index of System Base
+
+#define ALIGN_DATA .align 2
+#define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */
+#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte boundaries better for 486 */
+
+/* NB: NOP now preserves registers so NOPs can be inserted anywhere */
+/* XXX: NOP and FASTER_NOP are misleadingly named */
+#ifdef BROKEN_HARDWARE_AND_OR_SOFTWARE /* XXX - rarely necessary */
+#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax
+#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax
+#else
+#define FASTER_NOP
+#define NOP
+#endif
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .set PDRPDROFF,0x3F7 # Page dir index of Page dir
+ .globl _PTmap, _PTD, _PTDpde, _Sysmap
+ .set _PTmap,0xFDC00000
+ .set _PTD,0xFDFF7000
+ .set _Sysmap,0xFDFF8000
+ .set _PTDpde,0xFDFF7000+4*PDRPDROFF
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .set APDRPDROFF,0x3FE # Page dir index of Page dir
+ .globl _APTmap, _APTD, _APTDpde
+ .set _APTmap,0xFF800000
+ .set _APTD,0xFFBFE000
+ .set _APTDpde,0xFDFF7000+4*APDRPDROFF
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack, USRSTACK
+ .globl _kstack
+ .set PPDROFF,0x3F6
+ .set PPTEOFF,0x400-UPAGES # 0x3FE
+
+#define ENTRY(name) \
+ .globl _/**/name; ALIGN_TEXT; _/**/name:
+#define ALTENTRY(name) ENTRY(name)
+
+/*
+ * Initialization
+ */
+ .data
+ .globl _cpu,_cold,_boothowto,_bootdev,_cyloffset,_atdevbase,_atdevphys
+_cpu: .long 0 # are we 386, 386sx, or 486
+_cold: .long 1 # cold till we are not
+_atdevbase: .long 0 # location of start of iomem in virtual
+_atdevphys: .long 0 # location of device mapping ptes (phys)
+
+ .globl _IdlePTD, _KPTphys
+_IdlePTD: .long 0
+_KPTphys: .long 0
+
+ .space 512
+tmpstk:
+ .text
+ .globl start
+start: movw $0x1234,%ax
+ movw %ax,0x472 # warm boot
+ jmp 1f
+ .space 0x500 # skip over warm boot shit
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-SYSTEM
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-SYSTEM
+ movl 12(%esp),%eax
+ movl %eax, _cyloffset-SYSTEM
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $ tmpstk-SYSTEM,%esp # bootstrap stack end location
+
+#ifdef garbage
+ /* count up memory */
+
+ xorl %eax,%eax # start with base memory at 0x0
+ #movl $ 0xA0000/NBPG,%ecx # look every 4K up to 640K
+ movl $ 0xA0,%ecx # look every 4K up to 640K
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ /* flush stupid cache here! (with bcopy (0,0,512*1024) ) */
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+
+ movl $0x100000,%eax # next, talley remaining memory
+ #movl $((0xFFF000-0x100000)/NBPG),%ecx
+ movl $(0xFFF-0x100),%ecx
+1: movl (%eax),%ebx # save location to check
+ movl $0xa55a5aa5,(%eax) # write test pattern
+ cmpl $0xa55a5aa5,(%eax) # does not check yet for rollover
+ jne 2f
+ movl %ebx,(%eax) # restore memory
+ addl $ NBPG,%eax
+ loop 1b
+2: shrl $12,%eax
+ movl %eax,_Maxmem-SYSTEM
+#endif
+
+/* find end of kernel image */
+ movl $_end-SYSTEM,%ecx
+ addl $ NBPG-1,%ecx
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi
+
+/* clear bss and memory for bootstrap pagetables. */
+ movl $_edata-SYSTEM,%edi
+ subl %edi,%ecx
+ addl $(UPAGES+5)*NBPG,%ecx
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * 0 1 2 3 4
+ */
+ xorl %eax,%eax # pattern
+ cld
+ rep
+ stosb
+
+ movl %esi,_IdlePTD-SYSTEM /*physical address of Idle Address space */
+
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $ NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ * N.B. don't bother with making kernel text RO, as 386
+ * ignores R/W AND U/S bits on kernel access (only v works) !
+ *
+ * First step - build page tables
+ */
+ movl %esi,%ecx # this much memory,
+ shrl $ PGSHIFT,%ecx # for this many pte s
+ addl $ UPAGES+4,%ecx # including our early context
+ movl $0xa0,%ecx # XXX - cover debugger pages
+ movl $PG_V|PG_KW,%eax # having these bits set,
+ lea (4*NBPG)(%esi),%ebx # physical address of KPT in proc 0,
+ movl %ebx,_KPTphys-SYSTEM # in the kernel page table,
+ fillkpt
+
+/* map I/O memory map */
+
+ movl $0x100-0xa0,%ecx # for this many pte s,
+ movl $(0xa0000|PG_V|PG_UW),%eax # having these bits set,(perhaps URW?) XXX 06 Aug 92
+ movl %ebx,_atdevphys-SYSTEM # remember phys addr of ptes
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $ UPAGES,%ecx # for this many pte s,
+ lea (1*NBPG)(%esi),%eax # physical address in proc 0
+ lea (SYSTEM)(%eax),%edx
+ movl %edx,_proc0paddr-SYSTEM # remember VA for 0th process init
+ orl $PG_V|PG_KW,%eax # having these bits set,
+ lea (3*NBPG)(%esi),%ebx # physical address of stack pt in proc 0
+ addl $(PPTEOFF*4),%ebx
+ fillkpt
+
+/*
+ * Construct a page table directory
+ * (of page directory elements - pde's)
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ lea (4*NBPG)(%esi),%eax # physical address of kernel page table
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax,(%esi) # which is where temp maps!
+
+ /* kernel pde's */
+ movl $ 3,%ecx # for this many pde s,
+ lea (SYSPDROFF*4)(%esi), %ebx # offset of pde for kernel
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ PG_V|PG_UW,%eax # pde entry is valid XXX 06 Aug 92
+ movl %eax, PDRPDROFF*4(%esi) # which is where PTmap maps!
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea (3*NBPG)(%esi),%eax # physical address of pt in proc 0
+ orl $PG_V|PG_KW,%eax # pde entry is valid
+ movl %eax,PPDROFF*4(%esi) # which is where kernel stack maps!
+
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 # XXX - debugger signature
+ jne 1f
+ movb $1,_bdb_exists-SYSTEM
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi # base address of current gdt
+ movl $_gdt-SYSTEM,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep # copy gdt
+ movsl
+ movl $_gdt-SYSTEM,-8+2(%edi) # adjust gdt self-ptr
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi # base address of current idt
+ movl 8+4(%esi),%eax # convert dbg descriptor to ...
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-SYSTEM # ... immediate offset ...
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-SYSTEM # ... and selector for ljmp
+ movl 24+4(%esi),%eax # same for bpt descriptor
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-SYSTEM
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-SYSTEM
+
+ movl $_idt-SYSTEM,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep # copy idt
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+
+ /* load base of page directory, and enable mapping */
+ movl %esi,%eax # phys address of ptd in proc 0
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3 # load ptd addr into mmu
+ movl %cr0,%eax # get control word
+#ifdef USE_486_WRITE_PROTECT
+ orl $CR0_PE|CR0_PG|CR0_WP,%eax # and let s page!
+#else
+ orl $CR0_PE|CR0_PG,%eax # and let s page!
+#endif
+ movl %eax,%cr0 # NOW!
+
+ pushl $begin # jump to high mem!
+ ret
+
+begin: /* now running relocated at SYSTEM where the system is linked to run */
+
+ .globl _Crtat
+ movl _Crtat,%eax
+ subl $0xfe0a0000,%eax
+ movl _atdevphys,%edx # get pte PA
+ subl _KPTphys,%edx # remove base of ptes, now have phys offset
+ shll $ PGSHIFT-2,%edx # corresponding to virt offset
+ addl $ SYSTEM,%edx # add virtual base
+ movl %edx, _atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack */
+ movl $ _kstack+UPAGES*NBPG-4*12,%esp # bootstrap stack end location
+ xorl %eax,%eax # mark end of frames
+ movl %eax,%ebp
+ movl _proc0paddr, %eax
+ movl %esi, PCB_CR3(%eax)
+
+ lea 7*NBPG(%esi),%esi # skip past stack.
+ pushl %esi
+
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax # adjust slots 9-17
+ movl $9,%ecx
+reloc_gdt:
+ movb $0xfe,7(%eax) # top byte of base addresses, was 0,
+ addl $8,%eax # now SYSTEM>>24
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+
+ call _init386 # wire 386 chip for unix operation
+
+ movl $0,_PTD
+ call _main
+ popl %esi
+
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ # build outer stack frame
+ pushl %ecx # user ss
+ pushl $ USRSTACK # user esp
+ pushl %eax # user cs
+ pushl $0 # user ip
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs # double map cs to fs
+ movl %cx,%gs # and ds to gs
+ lret # goto user!
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+ .set exec,59
+ .set exit,1
+
+#define LCALL(x,y) .byte 0x9a ; .long y; .word x
+/*
+ * Icode is copied out to process 1 to exec /etc/init.
+ * If the exec fails, process 1 exits.
+ */
+ENTRY(icode)
+ # pushl $argv-_icode # gas fucks up again
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax
+
+ # pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax
+ pushl %eax # dummy out rta
+
+ movl %esp,%ebp
+ movl $exec,%eax
+ LCALL(0x7,0x0)
+ pushl %eax
+ movl $exit,%eax
+ pushl %eax # dummy out rta
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode # argv[0] = "init" ("/sbin/init" + 6)
+ .long eicode-_icode # argv[1] follows icode after copyout
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+ENTRY(sigcode)
+ call 12(%esp)
+ lea 28(%esp),%eax # scp (the call may have clobbered the
+ # copy at 8(%esp))
+ # XXX - use genassym
+ pushl %eax
+ pushl %eax # junk to fake return address
+ movl $103,%eax # sigreturn()
+ LCALL(0x7,0) # enter kernel with args on stack
+ hlt # never gets here
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
+
+ /*
+ * Support routines for GCC
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inb %dx,%al
+ ret
+
+
+ENTRY(inw)
+ movl 4(%esp),%edx
+ subl %eax,%eax # clr eax
+ NOP
+ inw %dx,%ax
+ ret
+
+
+ENTRY(rtcin)
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ subl %eax,%eax # clr eax
+ inb $0x71,%al
+ ret
+
+ENTRY(outb)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw)
+ movl 4(%esp),%edx
+ NOP
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ /*
+ * void bzero(void *base, u_int cnt)
+ */
+
+ENTRY(bzero)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+
+ /*
+ * fillw (pat,base,cnt)
+ */
+
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je _bcopyw
+ cmpl $4,%eax
+ jne _bcopyb
+ /*
+ * Fall through to bcopy. ENTRY() provides harmless fill bytes.
+ */
+
+ /*
+ * (ov)bcopy (src,dst,cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ * Changed by bde to not bother returning %eax = 0.
+ */
+
+ENTRY(ovbcopy)
+ENTRY(bcopy)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+#ifdef notdef
+ENTRY(copyout)
+ movl _curpcb, %eax
+ movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp), %esi
+ movl 20(%esp), %edi
+ movl 24(%esp), %ebx
+
+ /* first, check to see if "write fault" */
+1: movl %edi, %eax
+#ifdef notyet
+ shrl $IDXSHIFT, %eax /* fetch pte associated with address */
+ andb $0xfc, %al
+ movl _PTmap(%eax), %eax
+
+ andb $7, %al /* if we are the one case that won't trap... */
+ cmpb $5, %al
+ jne 2f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+
+ cmpl $0, %eax /* if not ok, return */
+ jne cpyflt
+ /* otherwise, continue with reference */
+2:
+ movl %edi, %eax /* calculate remainder this pass */
+ andl $0xfffff000, %eax
+ movl $NBPG, %ecx
+ subl %eax, %ecx
+ cmpl %ecx, %ebx
+ jle 3f
+ movl %ebx, %ecx
+3: subl %ecx, %ebx
+ movl %ecx, %edx
+#else
+ movl %ebx, %ecx
+ movl %ebx, %edx
+#endif
+
+ shrl $2,%ecx /* movem */
+ cld
+ rep
+ movsl
+ movl %edx, %ecx /* don't depend on ecx here! */
+ andl $3, %ecx
+ rep
+ movsb
+
+#ifdef notyet
+ cmpl $0, %ebx
+ jl 1b
+#endif
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ pushl %ebx # XXX - not used, but affects stack offsets
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+#else
+ENTRY(copyout)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ shrl $2,%ecx
+ cld
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+cpyflt: popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $ EFAULT,%eax
+ ret
+
+#endif
+
+ # insb(port,addr,cnt)
+ENTRY(insb)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # insw(port,addr,cnt)
+ENTRY(insw)
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6d # rep insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ # outsw(port,addr,cnt)
+ENTRY(outsw)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ .byte 0x66,0xf2,0x6f # rep outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ # outsb(port,addr,cnt)
+ENTRY(outsb)
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ NOP
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ /*
+ * void lgdt(struct region_descriptor *rdp);
+ */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+ # movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+ /*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+ /*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+ /*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+ /*
+ * void lcr3(caddr_t cr3)
+ */
+ ALIGN_TEXT
+ENTRY(load_cr3)
+ALTENTRY(lcr3)
+ movl 4(%esp),%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # tlbflush()
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $ I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+ # lcr0(cr0)
+ENTRY(lcr0)
+ALTENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+ # rcr0()
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+ # rcr2()
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+ # rcr3()
+ENTRY(_cr3)
+ALTENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+ # ssdtosd(*ssdp,*sdp)
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+/*
+ * {fu,su},{byte,word}
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ .byte 0x65 # use gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ decl %eax
+ ret
+
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+
+#ifdef notdef
+ shrl $IDXSHIFT, %edx /* fetch pte associated with address */
+ andb $0xfc, %dl
+ movl _PTmap(%edx), %edx
+
+ andb $7, %dl /* if we are the one case that won't trap... */
+ cmpb $5 , %edx
+ jne 1f
+ /* ... then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ cmpl $0, %eax /* if not ok, return */
+ jne fusufault
+ movl 8(%esp),%eax /* otherwise, continue with reference */
+1:
+ movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+#ifdef notdef
+shrl $IDXSHIFT, %edx /* calculate pte address */
+andb $0xfc, %dl
+movl _PTmap(%edx), %edx
+andb $7, %edx /* if we are the one case that won't trap... */
+cmpb $5 , %edx
+jne 1f
+/* ..., then simulate the trap! */
+ pushl %edi
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+movl _curpcb, %ecx # restore trashed registers
+cmpl $0, %eax /* if not ok, return */
+jne fusufault
+movl 8(%esp),%eax
+1: movl 4(%esp),%edx
+#endif
+ .byte 0x65 # use gs
+ movb %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
+ ret
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx, (%eax) # save ebx
+ movl %esp, 4(%eax) # save esp
+ movl %ebp, 8(%eax) # save ebp
+ movl %esi,12(%eax) # save esi
+ movl %edi,16(%eax) # save edi
+ movl (%esp),%edx # get rta
+ movl %edx,20(%eax) # save eip
+ xorl %eax,%eax # return (0);
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx # restore ebx
+ movl 4(%eax),%esp # restore esp
+ movl 8(%eax),%ebp # restore ebp
+ movl 12(%eax),%esi # restore esi
+ movl 16(%eax),%edi # restore edi
+ movl 20(%eax),%edx # get rta
+ movl %edx,(%esp) # put in return frame
+ xorl %eax,%eax # return (1);
+ incl %eax
+ ret
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+
+ .globl _whichqs,_qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) # should not be on q already
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs # set q full bit
+ shll $3,%edx
+ addl $_qs,%edx # locate q hdr
+ movl %edx,P_LINK(%eax) # link process on tail of q
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs # clear full bit, panic if clear already
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx # unlink process
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx # q still has something?
+ je rem2
+ shrl $3,%edx # yes, set bit as still full
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) # zap reverse link to indicate off list
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, Swtch branches to idle
+ * to wait for something to come ready.
+ */
+ .globl Idle
+ ALIGN_TEXT
+Idle:
+sti_for_idle:
+ sti
+ SHOW_STI
+ ALIGN_TEXT
+idle:
+ call _spl0
+ cmpl $0,_whichqs
+ jne sw1
+ hlt # wait for interrupt
+ jmp idle
+
+ SUPERALIGN_TEXT /* so profiling doesn't lump Idle with swtch().. */
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax # Hardware registers
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2,%eax # save temporary map PTE
+ movl %eax,PCB_CMAP2(%ecx) # in our context
+ movl $0,_curproc # out of process
+
+ # movw _cpl, %ax
+ # movw %ax, PCB_IML(%ecx) # save ipl
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+ SHOW_CLI
+ movl _whichqs,%edi
+2:
+ # XXX - bsf is sloow
+ bsfl %edi,%eax # find a full q
+ je sti_for_idle # if none, idle
+ # XX update whichqs?
+swfnd:
+ btrl %eax,%edi # clear q full status
+ jnb 2b # if it was clear, look for another
+ movl %eax,%ebx # save which one we are using
+
+ shll $3,%eax
+ addl $_qs,%eax # select q
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax # linked to self? (e.g. not on list)
+ je badsw # not possible
+#endif
+
+ movl P_LINK(%eax),%ecx # unlink from front of process q
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi # q empty
+ je 3f
+ btsl %ebx,%edi # nope, set to indicate full
+3:
+ movl %edi,_whichqs # update q status
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $ SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx), %ebx
+ movl PCB_ESP(%edx), %esp
+ movl PCB_EBP(%edx), %ebp
+ movl PCB_ESI(%edx), %esi
+ movl PCB_EDI(%edx), %edi
+ movl PCB_EIP(%edx), %eax
+ movl %eax, (%esp)
+
+ movl PCB_CMAP2(%edx),%eax # get temporary map
+ movl %eax,_CMAP2 # reload temporary map PTE
+
+ movl %ecx,_curproc # into next process
+ movl %edx,_curpcb
+
+ pushl %edx # save p to return
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+ SHOW_STI
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax # return (p);
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(p) ; struct proc *p;
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx # old pc
+ popl %eax # arg, our return value
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 # good bye address space
+ #write buffer?
+ movl $tmpstk-4,%esp # temporary stack, compensated for call
+ jmp %edx # return, execute remainder of cleanup
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp), %ecx
+ movw _cpl, %ax
+ movw %ax, PCB_IML(%ecx)
+ movl (%esp), %eax
+ movl %eax, PCB_EIP(%ecx)
+ movl %ebx, PCB_EBX(%ecx)
+ movl %esp, PCB_ESP(%ecx)
+ movl %ebp, PCB_EBP(%ecx)
+ movl %esi, PCB_ESI(%ecx)
+ movl %edi, PCB_EDI(%ecx)
+
+#ifdef NPX
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif
+
+ movl _CMAP2, %edx # save temporary map PTE
+ movl %edx, PCB_CMAP2(%ecx) # in our context
+
+ cmpl $0, 8(%esp)
+ je 1f
+ movl %esp, %edx # relocate current sp relative to pcb
+ subl $_kstack, %edx # (sp is relative to kstack):
+ addl %edx, %ecx # pcb += sp - kstack;
+ movl %eax, (%ecx) # write return pc at (relocated) sp@
+ # this mess deals with replicating register state gcc hides
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax, %eax # return 0
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jl L1 /* if (pc < 0) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
+
+ # To be done:
+ ENTRY(astoff)
+ ret
+
+ .data
+ ALIGN_DATA
+ .globl _cyloffset, _curpcb
+_cyloffset: .long 0
+ .globl _proc0paddr
+_proc0paddr: .long 0
+LF: .asciz "swtch %x"
+ ALIGN_DATA
+
+#if 0
+#define PANIC(msg) xorl %eax,%eax; movl %eax,_waittime; pushl 1f; \
+ call _panic; MSG(msg)
+#define PRINTF(n,msg) pushal ; nop ; pushl 1f; call _printf; MSG(msg) ; \
+ popl %eax ; popal
+#define MSG(msg) .data; 1: .asciz msg; ALIGN_DATA; .text
+#endif /* 0 */
+
+/*
+ * Trap and fault vector routines
+ *
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#define IDTVEC(name) ALIGN_TEXT; .globl _X/**/name; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp alltraps
+#ifdef KGDB
+#define BPTTRAP(a) sti; pushl $(a) ; jmp bpttraps
+#else
+#define BPTTRAP(a) sti; TRAP(a)
+#endif
+
+ .text
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+#ifdef BDBTRAP
+ BDBTRAP(dbg)
+#endif
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+#ifdef BDBTRAP
+ BDBTRAP(bpt)
+#endif
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+ /*PANIC("Double Fault");*/
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+ /*PANIC("TSS not valid");*/
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#ifdef NPX
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop /* silly, the bug is for popal and it only
+ * bites when the next instruction has a
+ * complicated address mode */
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ pushl _cpl
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ call _npxintr
+ jmp doreti
+#else
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+alltraps:
+ pushal
+ nop
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+calltrap:
+ incl _cnt+V_TRAP
+ call _trap
+ /*
+ * Return through doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ movl $T_ASTFLT,4+4+32(%esp) /* new trap type (err code not used) */
+ pushl _cpl
+ pushl $0 /* dummy unit */
+ jmp doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ ALIGN_TEXT
+bpttraps:
+ pushal
+ nop
+ pushl %es
+ pushl %ds
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ # non-kernel mode?
+ jne calltrap # yes
+ call _kgdb_trap_glue
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl # only for stupid carry bit and more stupid wait3 cc kludge
+ # XXX - also for direction flag (bzero, etc. clear it)
+ pushal # only need eax,ecx,edx - trap resaves others
+ nop
+ movl $KDSEL,%eax # switch to kernel segments
+ movl %ax,%ds
+ movl %ax,%es
+ incl _cnt+V_SYSCALL # kml 3/25/93
+ call _syscall
+ /*
+ * Return through doreti to handle ASTs. Have to change syscall frame
+ * to interrupt frame.
+ *
+ * XXX - we should have set up the frame earlier to avoid the
+ * following popal/pushal (not much can be done to avoid shuffling
+ * the flags). Consistent frames would simplify things all over.
+ */
+ movl 32+0(%esp),%eax /* old flags, shuffle to above cs:eip */
+ movl 32+4(%esp),%ebx /* `int' frame should have been ef, eip, cs */
+ movl 32+8(%esp),%ecx
+ movl %ebx,32+0(%esp)
+ movl %ecx,32+4(%esp)
+ movl %eax,32+8(%esp)
+ popal
+ nop
+ pushl $0 /* dummy error code */
+ pushl $T_ASTFLT
+ pushal
+ nop
+ movl __udatasel,%eax /* switch back to user segments */
+ push %eax /* XXX - better to preserve originals? */
+ push %eax
+ pushl _cpl
+ pushl $0
+ jmp doreti
+
+ENTRY(htonl)
+ENTRY(ntohl)
+ movl 4(%esp),%eax
+#ifdef i486
+ /* XXX */
+ /* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ENTRY(htons)
+ENTRY(ntohs)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+#ifdef SHOW_A_LOT
+
+/*
+ * 'show_bits' was too big when defined as a macro. The line length for some
+ * enclosing macro was too big for gas. Perhaps the code would have blown
+ * the cache anyway.
+ */
+
+ ALIGN_TEXT
+show_bits:
+ pushl %eax
+ SHOW_BIT(0)
+ SHOW_BIT(1)
+ SHOW_BIT(2)
+ SHOW_BIT(3)
+ SHOW_BIT(4)
+ SHOW_BIT(5)
+ SHOW_BIT(6)
+ SHOW_BIT(7)
+ SHOW_BIT(8)
+ SHOW_BIT(9)
+ SHOW_BIT(10)
+ SHOW_BIT(11)
+ SHOW_BIT(12)
+ SHOW_BIT(13)
+ SHOW_BIT(14)
+ SHOW_BIT(15)
+ popl %eax
+ ret
+
+ .data
+bit_colors:
+ .byte GREEN,RED,0,0
+ .text
+
+#endif /* SHOW_A_LOT */
+
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
new file mode 100644
index 0000000..f0351a7
--- /dev/null
+++ b/sys/i386/i386/machdep.c
@@ -0,0 +1,1131 @@
+/*-
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 15 Aug 92 William Jolitz Large memory bug
+ * 15 Aug 92 Terry Lambert Fixed CMOS RAM size bug
+ * 25 Mar 93 Sean Eric Fagan Added #ifdef HZ around microtime for
+ * the new microtime.s routine
+ * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans New intr-0.1 code
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/machdep.c,v 1.2 92/01/21 14:22:09 william Exp Locker: root $";
+
+
+#include <stddef.h>
+#include "param.h"
+#include "systm.h"
+#include "signalvar.h"
+#include "kernel.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "reboot.h"
+#include "conf.h"
+#include "file.h"
+#include "callout.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "msgbuf.h"
+#include "net/netisr.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+extern vm_offset_t avail_end;
+
+#include "machine/cpu.h"
+#include "machine/reg.h"
+#include "machine/psl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/rtc.h"
+
+
+#define EXPECT_BASEMEM 640 /* The expected base memory*/
+#define INFORM_WAIT 1 /* Set to pause berfore crash in weird cases*/
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+int nswbuf = 0;
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+int msgbufmapped; /* set when safe to use msgbuf */
+extern int freebufspace;
+
+/*
+ * Machine-dependent startup code
+ */
+int boothowto = 0, Maxmem = 0;
+long dumplo;
+int physmem, maxmem;
+extern int bootdev;
+#ifdef SMALL
+extern int forcemaxmem;
+#endif
+int biosmem;
+
+extern cyloffset;
+
+cpu_startup()
+{
+ register int unixsize;
+ register unsigned i;
+ register struct pte *pte;
+ int mapaddr, j;
+ register caddr_t v;
+ int maxbufs, base, residual;
+ extern long Usrptsize;
+ vm_offset_t minaddr, maxaddr;
+ vm_size_t size;
+ int firstaddr;
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* avail_end was pre-decremented in pmap_bootstrap to compensate */
+ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
+ pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG,
+ VM_PROT_ALL, TRUE);
+ msgbufmapped = 1;
+
+#ifdef KDB
+ kdb_init(); /* startup kernel debugger */
+#endif
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ /*printf(version);
+ printf("real mem = %d\n", ctob(physmem));*/
+
+ /*
+ * Allocate space for system data structures.
+ * The first available kernel virtual address is in "v".
+ * As pages of kernel virtual memory are allocated, "v" is incremented.
+ * As pages of memory are allocated and cleared,
+ * "firstaddr" is incremented.
+ * An index into the kernel page table corresponding to the
+ * virtual memory address maintained in "v" is kept in "mapaddr".
+ */
+
+ /*
+ * Make two passes. The first pass calculates how much memory is
+ * needed and allocates it. The second pass assigns virtual
+ * addresses to the various data structures.
+ */
+ firstaddr = 0;
+again:
+ v = (caddr_t)firstaddr;
+
+#define valloc(name, type, num) \
+ (name) = (type *)v; v = (caddr_t)((name)+(num))
+#define valloclim(name, type, num, lim) \
+ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
+ valloc(callout, struct callout, ncallout);
+#ifdef SYSVSHM
+ valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
+#endif
+ /*
+ * Determine how many buffers to allocate.
+ * Use 10% of memory for the first 2 Meg, 5% of the remaining
+ * memory. Insure a minimum of 16 buffers.
+ * We allocate 1/2 as many swap buffer headers as file i/o buffers.
+ */
+ if (bufpages == 0)
+ if (physmem < (2 * 1024 * 1024))
+ bufpages = physmem / 10 / CLSIZE;
+ else
+ bufpages = ((2 * 1024 * 1024 + physmem) / 20) / CLSIZE;
+ /*
+ * 15 Aug 92 William Jolitz bufpages fix for too large
+ */
+ bufpages = min( NKMEMCLUSTERS*2/5, bufpages);
+
+ if (nbuf == 0) {
+ nbuf = bufpages / 2;
+ if (nbuf < 16)
+ nbuf = 16;
+ }
+ freebufspace = bufpages * NBPG;
+ if (nswbuf == 0) {
+ nswbuf = (nbuf / 2) &~ 1; /* force even */
+ if (nswbuf > 256)
+ nswbuf = 256; /* sanity */
+ }
+ valloc(swbuf, struct buf, nswbuf);
+ valloc(buf, struct buf, nbuf);
+
+ /*
+ * End of first pass, size has been calculated so allocate memory
+ */
+ if (firstaddr == 0) {
+ size = (vm_size_t)(v - firstaddr);
+ firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
+ if (firstaddr == 0)
+ panic("startup: no room for tables");
+ goto again;
+ }
+ /*
+ * End of second pass, addresses have been assigned
+ */
+ if ((vm_size_t)(v - firstaddr) != size)
+ panic("startup: table size inconsistency");
+ /*
+ * Allocate a submap for buffer space allocations.
+ */
+ buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ bufpages*NBPG, TRUE);
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, TRUE);
+
+ /*
+ * Finally, allocate mbuf pool. Since mclrefcnt is an off-size
+ * we use the more space efficient malloc in place of kmem_alloc.
+ */
+ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
+ M_MBUF, M_NOWAIT);
+ bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
+ mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
+ VM_MBUF_SIZE, FALSE);
+ /*
+ * Initialize callouts
+ */
+ callfree = callout;
+ for (i = 1; i < ncallout; i++)
+ callout[i-1].c_next = &callout[i];
+
+ /*printf("avail mem = %d\n", ptoa(vm_page_free_count));*/
+
+ /*
+ * Set up CPU-specific registers, cache, etc.
+ */
+ initcpu();
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ /*
+ * Configure the system.
+ */
+ configure();
+}
+
+#ifdef PGINPROF
+/*
+ * Return the difference (in microseconds)
+ * between the current time and a previous
+ * time as represented by the arguments.
+ * If there is a pending clock interrupt
+ * which has not been serviced due to high
+ * ipl, return error code.
+ */
+/*ARGSUSED*/
+vmtime(otime, olbolt, oicr)
+ register int otime, olbolt, oicr;
+{
+
+ return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
+}
+#endif
+
+struct sigframe {
+ int sf_signum;
+ int sf_code;
+ struct sigcontext *sf_scp;
+ sig_t sf_handler;
+ int sf_eax;
+ int sf_edx;
+ int sf_ecx;
+ struct sigcontext sf_sc;
+} ;
+
+extern int kstack[];
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig, mask;
+ unsigned code;
+{
+ register struct proc *p = curproc;
+ register int *regs;
+ register struct sigframe *fp;
+ struct sigacts *ps = p->p_sigacts;
+ int oonstack, frmtrap;
+
+ regs = p->p_regs;
+ oonstack = ps->ps_onstack;
+ frmtrap = curpcb->pcb_flags & FM_TRAP;
+ /*
+ * Allocate and validate space for the signal handler
+ * context. Note that if the stack is in P0 space, the
+ * call to grow() is a nop, and the useracc() check
+ * will fail if the process has not already allocated
+ * the space with a `brk'.
+ */
+ if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
+ fp = (struct sigframe *)(ps->ps_sigsp
+ - sizeof(struct sigframe));
+ ps->ps_onstack = 1;
+ } else {
+ if (frmtrap)
+ fp = (struct sigframe *)(regs[tESP]
+ - sizeof(struct sigframe));
+ else
+ fp = (struct sigframe *)(regs[sESP]
+ - sizeof(struct sigframe));
+ }
+
+ if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize))
+ (void)grow(p, (unsigned)fp);
+
+ if (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == 0) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ SIGACTION(p, SIGILL) = SIG_DFL;
+ sig = sigmask(SIGILL);
+ p->p_sigignore &= ~sig;
+ p->p_sigcatch &= ~sig;
+ p->p_sigmask &= ~sig;
+ psignal(p, SIGILL);
+ return;
+ }
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+ fp->sf_signum = sig;
+ fp->sf_code = code;
+ fp->sf_scp = &fp->sf_sc;
+ fp->sf_handler = catcher;
+
+ /* save scratch registers */
+ if(frmtrap) {
+ fp->sf_eax = regs[tEAX];
+ fp->sf_edx = regs[tEDX];
+ fp->sf_ecx = regs[tECX];
+ } else {
+ fp->sf_eax = regs[sEAX];
+ fp->sf_edx = regs[sEDX];
+ fp->sf_ecx = regs[sECX];
+ }
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ fp->sf_sc.sc_onstack = oonstack;
+ fp->sf_sc.sc_mask = mask;
+ if(frmtrap) {
+ fp->sf_sc.sc_sp = regs[tESP];
+ fp->sf_sc.sc_fp = regs[tEBP];
+ fp->sf_sc.sc_pc = regs[tEIP];
+ fp->sf_sc.sc_ps = regs[tEFLAGS];
+ regs[tESP] = (int)fp;
+ regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ } else {
+ fp->sf_sc.sc_sp = regs[sESP];
+ fp->sf_sc.sc_fp = regs[sEBP];
+ fp->sf_sc.sc_pc = regs[sEIP];
+ fp->sf_sc.sc_ps = regs[sEFLAGS];
+ regs[sESP] = (int)fp;
+ regs[sEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ }
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper priviledges or to cause
+ * a machine fault.
+ */
+sigreturn(p, uap, retval)
+ struct proc *p;
+ struct args {
+ struct sigcontext *sigcntxp;
+ } *uap;
+ int *retval;
+{
+ register struct sigcontext *scp;
+ register struct sigframe *fp;
+ register int *regs = p->p_regs;
+
+
+ /*
+ * (XXX old comment) regs[sESP] points to the return address.
+ * The user scp pointer is above that.
+ * The return address is faked in the signal trampoline code
+ * for consistency.
+ */
+ scp = uap->sigcntxp;
+ fp = (struct sigframe *)
+ ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
+
+ if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
+ return(EINVAL);
+
+ /* restore scratch registers */
+ regs[sEAX] = fp->sf_eax ;
+ regs[sEDX] = fp->sf_edx ;
+ regs[sECX] = fp->sf_ecx ;
+
+ if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
+ return(EINVAL);
+#ifdef notyet
+ if ((scp->sc_ps & PSL_MBZ) != 0 || (scp->sc_ps & PSL_MBO) != PSL_MBO) {
+ return(EINVAL);
+ }
+#endif
+ p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
+ p->p_sigmask = scp->sc_mask &~
+ (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
+ regs[sEBP] = scp->sc_fp;
+ regs[sESP] = scp->sc_sp;
+ regs[sEIP] = scp->sc_pc;
+ regs[sEFLAGS] = scp->sc_ps;
+ return(EJUSTRETURN);
+}
+
+int waittime = -1;
+struct pcb dumppcb;
+
+boot(arghowto)
+ int arghowto;
+{
+ register long dummy; /* r12 is reserved */
+ register int howto; /* r11 == how to boot */
+ register int devtype; /* r10 == major of root dev */
+ extern char *panicstr;
+ extern int cold;
+ int nomsg = 1;
+
+ if(cold) {
+ printf("hit reset please");
+ for(;;);
+ }
+ howto = arghowto;
+ if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
+ register struct buf *bp;
+ int iter, nbusy;
+
+ waittime = 0;
+ (void) splnet();
+ /*
+ * Release inodes held by texts before update.
+ */
+ if (panicstr == 0)
+ vnode_pager_umount(NULL);
+ sync((struct sigcontext *)0);
+
+ for (iter = 0; iter < 20; iter++) {
+ nbusy = 0;
+ for (bp = &buf[nbuf]; --bp >= buf; )
+ if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
+ nbusy++;
+ if (nbusy == 0)
+ break;
+ if (nomsg) {
+ printf("updating disks before rebooting... ");
+ nomsg = 0;
+ }
+ /* printf("%d ", nbusy); */
+ DELAY(40000 * iter);
+ }
+ if (nbusy)
+ printf(" failed!\n");
+ else if (nomsg == 0)
+ printf("succeded.\n");
+ DELAY(10000); /* wait for printf to finish */
+ }
+ splhigh();
+ devtype = major(rootdev);
+ if (howto&RB_HALT) {
+ pg("\nThe operating system has halted. Please press any key to reboot.\n\n");
+ } else {
+ if (howto & RB_DUMP) {
+ savectx(&dumppcb, 0);
+ dumppcb.pcb_ptd = rcr3();
+ dumpsys();
+ /*NOTREACHED*/
+ }
+ }
+#ifdef lint
+ dummy = 0; dummy = dummy;
+ printf("howto %d, devtype %d\n", arghowto, devtype);
+#endif
+ cpu_reset();
+ for(;;) ;
+ /*NOTREACHED*/
+}
+
+int dumpmag = 0x8fca0101; /* magic number for savecore */
+int dumpsize = 0; /* also for savecore */
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+dumpsys()
+{
+
+ if (dumpdev == NODEV)
+ return;
+ if ((minor(dumpdev)&07) != 1)
+ return;
+ printf("\nThe operating system is saving a copy of RAM memory to device %x, offset %d\n\
+(hit any key to abort): [ amount left to save (MB) ] ", dumpdev, dumplo);
+ dumpsize = physmem;
+ switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
+
+ case ENXIO:
+ printf("-- device bad\n");
+ break;
+
+ case EFAULT:
+ printf("-- device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("-- area improper\n");
+ break;
+
+ case EIO:
+ printf("-- i/o error\n");
+ break;
+
+ case EINTR:
+ printf("-- aborted from console\n");
+ break;
+
+ default:
+ printf(" succeeded\n");
+ break;
+ }
+ printf("system rebooting.\n\n");
+ DELAY(10000);
+}
+
+#ifdef HZ
+/*
+ * If HZ is defined we use this code, otherwise the code in
+ * /sys/i386/i386/microtime.s is used. The othercode only works
+ * for HZ=100.
+ */
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+
+ *tvp = time;
+ tvp->tv_usec += tick;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ splx(s);
+}
+#endif /* HZ */
+
+physstrat(bp, strat, prio)
+ struct buf *bp;
+ int (*strat)(), prio;
+{
+ register int s;
+ caddr_t baddr;
+
+ /*
+ * vmapbuf clobbers b_addr so we must remember it so that it
+ * can be restored after vunmapbuf. This is truely rude, we
+ * should really be storing this in a field in the buf struct
+ * but none are available and I didn't want to add one at
+ * this time. Note that b_addr for dirty page pushes is
+ * restored in vunmapbuf. (ugh!)
+ */
+ baddr = bp->b_un.b_addr;
+ vmapbuf(bp);
+ (*strat)(bp);
+ /* pageout daemon doesn't wait for pushed pages */
+ if (bp->b_flags & B_DIRTY)
+ return;
+ s = splbio();
+ while ((bp->b_flags & B_DONE) == 0)
+ sleep((caddr_t)bp, prio);
+ splx(s);
+ vunmapbuf(bp);
+ bp->b_un.b_addr = baddr;
+}
+
+initcpu()
+{
+}
+
+/*
+ * Clear registers on exec
+ */
+setregs(p, entry)
+ struct proc *p;
+ u_long entry;
+{
+
+ p->p_regs[sEBP] = 0; /* bottom of the fp chain */
+ p->p_regs[sEIP] = entry;
+
+ p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */
+ load_cr0(rcr0() | CR0_TS); /* start emulating */
+#ifdef NPX
+ npxinit(__INITIAL_NPXCW__);
+#endif
+}
+
+/*
+ * Initialize 386 and configure to run kernel
+ */
+
+/*
+ * Initialize segments & interrupt table
+ */
+
+
+#define GNULL_SEL 0 /* Null Descriptor */
+#define GCODE_SEL 1 /* Kernel Code Descriptor */
+#define GDATA_SEL 2 /* Kernel Data Descriptor */
+#define GLDT_SEL 3 /* LDT - eventually one per process */
+#define GTGATE_SEL 4 /* Process task switch gate */
+#define GPANIC_SEL 5 /* Task state to consider panic from */
+#define GPROC0_SEL 6 /* Task state process slot zero and up */
+#define NGDT GPROC0_SEL+1
+
+union descriptor gdt[GPROC0_SEL+1];
+
+/* interrupt descriptor table */
+struct gate_descriptor idt[NIDT];
+
+/* local descriptor table */
+union descriptor ldt[5];
+#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
+#define LSYS5SIGR_SEL 1
+
+#define L43BSDCALLS_SEL 2 /* notyet */
+#define LUCODE_SEL 3
+#define LUDATA_SEL 4
+/* seperate stack, es,fs,gs sels ? */
+/* #define LPOSIXCALLS_SEL 5 /* notyet */
+
+struct i386tss tss, panic_tss;
+
+extern struct user *proc0paddr;
+
+/* software prototypes -- in more palitable form */
+struct soft_segment_descriptor gdt_segs[] = {
+ /* Null Descriptor */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* LDT Descriptor */
+{ (int) ldt, /* segment base address */
+ sizeof(ldt)-1, /* length - all address space */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - Placeholder */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Panic Tss Descriptor */
+{ (int) &panic_tss, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Proc 0 Tss Descriptor */
+{ (int) kstack, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ }};
+
+struct soft_segment_descriptor ldt_segs[] = {
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0,0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0,0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ } };
+
+setidt(idx, func, typ, dpl) char *func; {
+ struct gate_descriptor *ip = idt + idx;
+
+ ip->gd_looffset = (int)func;
+ ip->gd_selector = 8;
+ ip->gd_stkcpy = 0;
+ ip->gd_xx = 0;
+ ip->gd_type = typ;
+ ip->gd_dpl = dpl;
+ ip->gd_p = 1;
+ ip->gd_hioffset = ((int)func)>>16 ;
+}
+
+#define IDTVEC(name) __CONCAT(X, name)
+extern IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
+ IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
+ IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
+ IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
+ IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
+ IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
+ IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
+ IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
+
+int lcr0(), lcr3(), rcr0(), rcr2();
+int _udatasel, _ucodesel, _gsel_tss;
+
+init386(first)
+{
+ extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
+ int x, *pi;
+ unsigned biosbasemem, biosextmem;
+ struct gate_descriptor *gdp;
+ extern int sigcode,szsigcode;
+ /* table descriptors - used to load tables by microp */
+ struct region_descriptor r_gdt, r_idt;
+ int pagesinbase, pagesinext;
+
+
+ proc0.p_addr = proc0paddr;
+
+ /*
+ * Initialize the console before we print anything out.
+ */
+
+ cninit (KERNBASE+0xa0000);
+
+ /* make gdt memory segments */
+ gdt_segs[GCODE_SEL].ssd_limit = btoc((int) &etext + NBPG);
+ for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
+ /* make ldt memory segments */
+ ldt_segs[LUCODE_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
+ ldt_segs[LUDATA_SEL].ssd_limit = btoc(UPT_MIN_ADDRESS);
+ /* Note. eventually want private ldts per process */
+ for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
+
+ /* exceptions */
+ setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL);
+ setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL);
+ setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL);
+ setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL);
+ setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_KPL);
+ setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL);
+ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL);
+ setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL);
+ setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL);
+ setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL);
+ setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL);
+ setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL);
+ setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL);
+ setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL);
+ setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL);
+ setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL);
+ setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL);
+ setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL);
+ setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL);
+ setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL);
+ setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL);
+ setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL);
+ setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL);
+ setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL);
+ setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL);
+ setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL);
+ setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL);
+ setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL);
+ setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL);
+ setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL);
+ setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL);
+ setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL);
+
+#include "isa.h"
+#if NISA >0
+ isa_defaultirq();
+#endif
+
+ r_gdt.rd_limit = sizeof(gdt)-1;
+ r_gdt.rd_base = (int) gdt;
+ lgdt(&r_gdt);
+ r_idt.rd_limit = sizeof(idt)-1;
+ r_idt.rd_base = (int) idt;
+ lidt(&r_idt);
+ lldt(GSEL(GLDT_SEL, SEL_KPL));
+
+#include "ddb.h"
+#if NDDB > 0
+ kdb_init();
+ if (boothowto & RB_KDB)
+ Debugger();
+#endif
+
+ /* Use BIOS values stored in RTC CMOS RAM, since probing
+ * breaks certain 386 AT relics.
+ */
+ biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
+ biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+/*printf("bios base %d ext %d ", biosbasemem, biosextmem);*/
+
+ /*
+ * 15 Aug 92 Terry Lambert The real fix for the CMOS bug
+ */
+ if( biosbasemem != EXPECT_BASEMEM) {
+ printf( "Warning: Base memory %dK, assuming %dK\n", biosbasemem, EXPECT_BASEMEM);
+ biosbasemem = EXPECT_BASEMEM; /* assume base*/
+ }
+
+ if( biosextmem > 65536) {
+ printf( "Warning: Extended memory %dK(>64M), assuming 0K\n", biosextmem);
+ biosextmem = 0; /* assume none*/
+ }
+
+ /*
+ * Go into normal calculation; Note that we try to run in 640K, and
+ * that invalid CMOS values of non 0xffff are no longer a cause of
+ * ptdi problems. I have found a gutted kernel can run in 640K.
+ */
+ pagesinbase = 640/4 - first/NBPG;
+ pagesinext = biosextmem/4;
+ /* use greater of either base or extended memory. do this
+ * until I reinstitue discontiguous allocation of vm_page
+ * array.
+ */
+ if (pagesinbase > pagesinext)
+ Maxmem = 640/4;
+ else {
+ Maxmem = pagesinext + 0x100000/NBPG;
+ first = 0x100000; /* skip hole */
+ }
+
+ /* This used to explode, since Maxmem used to be 0 for bas CMOS*/
+ maxmem = Maxmem - 1; /* highest page of usable memory */
+ physmem = maxmem; /* number of pages of physmem addr space */
+/*printf("using first 0x%x to 0x%x\n ", first, maxmem*NBPG);*/
+ if (maxmem < 2048/4) {
+ printf("Too little RAM memory. Warning, running in degraded mode.\n");
+#ifdef INFORM_WAIT
+ /*
+ * People with less than 2 Meg have to hit return; this way
+ * we see the messages and can tell them why they blow up later.
+ * If they get working well enough to recompile, they can unset
+ * the flag; otherwise, it's a toy and they have to lump it.
+ */
+ getchar(); /* kernel getchar in /sys/i386/isa/pccons.c*/
+#endif /* !INFORM_WAIT*/
+ }
+ /*
+ * End of CMOS bux fix
+ */
+
+ /* call pmap initialization to make new kernel address space */
+ pmap_bootstrap (first, 0);
+ /* now running on new page tables, configured,and u/iom is accessible */
+
+ /* make a initial tss so microp can get interrupt stack on syscall! */
+ proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
+ proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+ ltr(_gsel_tss);
+
+ /* make a call gate to reenter kernel with */
+ gdp = &ldt[LSYS5CALLS_SEL].gd;
+
+ x = (int) &IDTVEC(syscall);
+ gdp->gd_looffset = x++;
+ gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
+ gdp->gd_stkcpy = 0;
+ gdp->gd_type = SDT_SYS386CGT;
+ gdp->gd_dpl = SEL_UPL;
+ gdp->gd_p = 1;
+ gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
+
+ /* transfer to user mode */
+
+ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
+ _udatasel = LSEL(LUDATA_SEL, SEL_UPL);
+
+ /* setup proc 0's pcb */
+ bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
+ proc0.p_addr->u_pcb.pcb_flags = 0;
+ proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
+}
+
+extern struct pte *CMAP1, *CMAP2;
+extern caddr_t CADDR1, CADDR2;
+/*
+ * zero out physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+clearseg(n) {
+
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(n);
+ load_cr3(rcr3());
+ bzero(CADDR2,NBPG);
+ *(int *) CADDR2 = 0;
+}
+
+/*
+ * copy a page of physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+copyseg(frm, n) {
+
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(n);
+ load_cr3(rcr3());
+ bcopy((void *)frm, (void *)CADDR2, NBPG);
+}
+
+/*
+ * copy a page of physical memory
+ * specified in relocation units (NBPG bytes)
+ */
+physcopyseg(frm, to) {
+
+ *(int *)CMAP1 = PG_V | PG_KW | ctob(frm);
+ *(int *)CMAP2 = PG_V | PG_KW | ctob(to);
+ load_cr3(rcr3());
+ bcopy(CADDR1, CADDR2, NBPG);
+}
+
+/*aston() {
+ schednetisr(NETISR_AST);
+}*/
+
+setsoftclock() {
+ schednetisr(NETISR_SCLK);
+}
+
+/*
+ * insert an element into a queue
+ */
+#undef insque
+_insque(element, head)
+ register struct prochd *element, *head;
+{
+ element->ph_link = head->ph_link;
+ head->ph_link = (struct proc *)element;
+ element->ph_rlink = (struct proc *)head;
+ ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+#undef remque
+_remque(element)
+ register struct prochd *element;
+{
+ ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
+ ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
+ element->ph_rlink = (struct proc *)0;
+}
+
+vmunaccess() {}
+
+/*
+ * Below written in C to allow access to debugging code
+ */
+copyinstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *toaddr, *fromaddr; {
+ int c,tally;
+
+ tally = 0;
+ while (maxlength--) {
+ c = fubyte(fromaddr++);
+ if (c == -1) {
+ if(lencopied) *lencopied = tally;
+ return(EFAULT);
+ }
+ tally++;
+ *(char *)toaddr++ = (char) c;
+ if (c == 0){
+ if(lencopied) *lencopied = (u_int)tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = (u_int)tally;
+ return(ENAMETOOLONG);
+}
+
+copyoutstr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *fromaddr, *toaddr; {
+ int c;
+ int tally;
+
+ tally = 0;
+ while (maxlength--) {
+ c = subyte(toaddr++, *(char *)fromaddr);
+ if (c == -1) return(EFAULT);
+ tally++;
+ if (*(char *)fromaddr++ == 0){
+ if(lencopied) *lencopied = tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = tally;
+ return(ENAMETOOLONG);
+}
+
+copystr(fromaddr, toaddr, maxlength, lencopied) u_int *lencopied, maxlength;
+ void *fromaddr, *toaddr; {
+ u_int tally;
+
+ tally = 0;
+ while (maxlength--) {
+ *(u_char *)toaddr = *(u_char *)fromaddr++;
+ tally++;
+ if (*(u_char *)toaddr++ == 0) {
+ if(lencopied) *lencopied = tally;
+ return(0);
+ }
+ }
+ if(lencopied) *lencopied = tally;
+ return(ENAMETOOLONG);
+}
diff --git a/sys/i386/i386/math_emu.h b/sys/i386/i386/math_emu.h
new file mode 100644
index 0000000..537fba5
--- /dev/null
+++ b/sys/i386/i386/math_emu.h
@@ -0,0 +1,154 @@
+/*
+ * linux/include/linux/math_emu.h
+ *
+ * (C) 1991 Linus Torvalds
+ */
+#ifndef _LINUX_MATH_EMU_H
+#define _LINUX_MATH_EMU_H
+
+/*#define math_abort(x,y) \
+(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))*/
+
+/*
+ * Gcc forces this stupid alignment problem: I want to use only two longs
+ * for the temporary real 64-bit mantissa, but then gcc aligns out the
+ * structure to 12 bytes which breaks things in math_emulate.c. Shit. I
+ * want some kind of "no-alignt" pragma or something.
+ */
+
+typedef struct {
+ long a,b;
+ short exponent;
+} temp_real;
+
+typedef struct {
+ short m0,m1,m2,m3;
+ short exponent;
+} temp_real_unaligned;
+
+#define real_to_real(a,b) \
+((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent))
+
+typedef struct {
+ long a,b;
+} long_real;
+
+typedef long short_real;
+
+typedef struct {
+ long a,b;
+ short sign;
+} temp_int;
+
+struct swd {
+ int ie:1;
+ int de:1;
+ int ze:1;
+ int oe:1;
+ int ue:1;
+ int pe:1;
+ int sf:1;
+ int ir:1;
+ int c0:1;
+ int c1:1;
+ int c2:1;
+ int top:3;
+ int c3:1;
+ int b:1;
+};
+struct i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+#define I387 (*(struct i387_struct *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
+#define SWD (*(struct swd *) &I387.swd)
+#define ROUNDING ((I387.cwd >> 10) & 3)
+#define PRECISION ((I387.cwd >> 8) & 3)
+
+#define BITS24 0
+#define BITS53 2
+#define BITS64 3
+
+#define ROUND_NEAREST 0
+#define ROUND_DOWN 1
+#define ROUND_UP 2
+#define ROUND_0 3
+
+#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000}
+#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF}
+#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000}
+#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE}
+#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD}
+#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF}
+#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000}
+
+#define set_IE() (I387.swd |= 1)
+#define set_DE() (I387.swd |= 2)
+#define set_ZE() (I387.swd |= 4)
+#define set_OE() (I387.swd |= 8)
+#define set_UE() (I387.swd |= 16)
+#define set_PE() (I387.swd |= 32)
+
+#define set_C0() (I387.swd |= 0x0100)
+#define set_C1() (I387.swd |= 0x0200)
+#define set_C2() (I387.swd |= 0x0400)
+#define set_C3() (I387.swd |= 0x4000)
+
+/* ea.c */
+
+char * ea(struct trapframe *, unsigned short);
+
+/* convert.c */
+
+void frndint(const temp_real * __a, temp_real * __b);
+void Fscale(const temp_real *, const temp_real *, temp_real *);
+void short_to_temp(const short_real * __a, temp_real * __b);
+void long_to_temp(const long_real * __a, temp_real * __b);
+void temp_to_short(const temp_real * __a, short_real * __b);
+void temp_to_long(const temp_real * __a, long_real * __b);
+void real_to_int(const temp_real * __a, temp_int * __b);
+void int_to_real(const temp_int * __a, temp_real * __b);
+
+/* get_put.c */
+
+void get_short_real(temp_real *, struct trapframe *, unsigned short);
+void get_long_real(temp_real *, struct trapframe *, unsigned short);
+void get_temp_real(temp_real *, struct trapframe *, unsigned short);
+void get_short_int(temp_real *, struct trapframe *, unsigned short);
+void get_long_int(temp_real *, struct trapframe *, unsigned short);
+void get_longlong_int(temp_real *, struct trapframe *, unsigned short);
+void get_BCD(temp_real *, struct trapframe *, unsigned short);
+void put_short_real(const temp_real *, struct trapframe *, unsigned short);
+void put_long_real(const temp_real *, struct trapframe *, unsigned short);
+void put_temp_real(const temp_real *, struct trapframe *, unsigned short);
+void put_short_int(const temp_real *, struct trapframe *, unsigned short);
+void put_long_int(const temp_real *, struct trapframe *, unsigned short);
+void put_longlong_int(const temp_real *, struct trapframe *, unsigned short);
+void put_BCD(const temp_real *, struct trapframe *, unsigned short);
+
+/* add.c */
+
+void fadd(const temp_real *, const temp_real *, temp_real *);
+
+/* mul.c */
+
+void fmul(const temp_real *, const temp_real *, temp_real *);
+
+/* div.c */
+
+void fdiv(const temp_real *, const temp_real *, temp_real *);
+
+/* compare.c */
+
+void fcom(const temp_real *, const temp_real *);
+void fucom(const temp_real *, const temp_real *);
+void ftst(const temp_real *);
+
+#endif
diff --git a/sys/i386/i386/math_emulate.c b/sys/i386/i386/math_emulate.c
new file mode 100644
index 0000000..faf55a4
--- /dev/null
+++ b/sys/i386/i386/math_emulate.c
@@ -0,0 +1,1487 @@
+/* [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj] */
+/*
+ * linux/kernel/math/math_emulate.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
+ * even for soft-float, unless you use bruce evans' patches. The patches
+ * are great, but they have to be re-applied for every version, and the
+ * library is different for soft-float and 80387. So emulation is more
+ * practical, even though it's slower.
+ *
+ * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
+ * about add/sub/mul/div. Urgel. I should find some good source, but I'll
+ * just fake up something.
+ *
+ * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
+ * test every possible combination.
+ */
+
+/*
+ * This file is full of ugly macros etc: one problem was that gcc simply
+ * didn't want to make the structures as they should be: it has to try to
+ * align them. Sickening code, but at least I've hidden the ugly things
+ * in this one file: the other files don't need to know about these things.
+ *
+ * The other files also don't care about ST(x) etc - they just get addresses
+ * to 80-bit temporary reals, and do with them as they please. I wanted to
+ * hide most of the 387-specific things here.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00060
+ * -------------------- ----- ----------------------
+ *
+ * 19 Sep 92 Ishii Masahiro Fix 0x1fd instruction
+ * kym@bingsuns.cc.binghamton.edu Fix fscale
+ * 28 Nov 92 Poul-Henning Kamp Reduce kernel size if you have
+ * a 387 or 486 chip
+ */
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#include "signal.h"
+
+#define __ALIGNED_TEMP_REAL 1
+#include "i386/i386/math_emu.h"
+
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define ST(x) (*__st((x)))
+#define PST(x) ((const temp_real *) __st((x)))
+#define math_abort(tfp, signo) tfp->tf_eip = oldeip; return (signo);
+
+/*
+ * We don't want these inlined - it gets too messy in the machine-code.
+ */
+static void fpop(void);
+static void fpush(void);
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
+static temp_real_unaligned * __st(int i);
+
+unsigned char get_fs_byte(char *adr) { return(fubyte(adr)); }
+unsigned short get_fs_word(unsigned short *adr) { return(fuword(adr)); }
+unsigned long get_fs_long(unsigned long *adr) { return(fuword(adr)); }
+put_fs_byte(unsigned char val, char *adr) { (void)subyte(adr,val); }
+put_fs_word(unsigned short val, short *adr) { (void)susword(adr,val); }
+put_fs_long(unsigned long val, unsigned long *adr) { (void)suword(adr,val); }
+
+math_emulate(struct trapframe * info)
+{
+#if defined(i486) || defined(i387)
+ panic("math_emulate(), shouldn't happen with -Di486 or -Di387");
+}
+#else
+ unsigned short code;
+ temp_real tmp;
+ char * address;
+ u_long oldeip;
+
+ /* ever used fp? */
+ if ((((struct pcb *)curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
+ ((struct pcb *)curproc->p_addr)->pcb_flags |= FP_SOFTFP;
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ }
+
+ if (I387.cwd & I387.swd & 0x3f)
+ I387.swd |= 0x8000;
+ else
+ I387.swd &= 0x7fff;
+ oldeip = info->tf_eip;
+/* 0x001f means user code space */
+ if ((u_short)info->tf_cs != 0x001F) {
+ printf("math_emulate: %04x:%08x\n\r", (u_short)info->tf_cs,
+ oldeip);
+ panic("?Math emulation needed in kernel?");
+ }
+ code = get_fs_word((unsigned short *) oldeip);
+ bswapw(code);
+ code &= 0x7ff;
+ I387.fip = oldeip;
+ *(unsigned short *) &I387.fcs = (u_short) info->tf_cs;
+ *(1+(unsigned short *) &I387.fcs) = code;
+ info->tf_eip += 2;
+ switch (code) {
+ case 0x1d0: /* fnop */
+ return(0);
+ case 0x1d1: case 0x1d2: case 0x1d3:
+ case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
+ math_abort(info,SIGILL);
+ case 0x1e0:
+ ST(0).exponent ^= 0x8000;
+ return(0);
+ case 0x1e1:
+ ST(0).exponent &= 0x7fff;
+ return(0);
+ case 0x1e2: case 0x1e3:
+ math_abort(info,SIGILL);
+ case 0x1e4:
+ ftst(PST(0));
+ return(0);
+ case 0x1e5:
+ printf("fxam not implemented\n\r");
+ math_abort(info,SIGILL);
+ case 0x1e6: case 0x1e7:
+ math_abort(info,SIGILL);
+ case 0x1e8:
+ fpush();
+ ST(0) = CONST1;
+ return(0);
+ case 0x1e9:
+ fpush();
+ ST(0) = CONSTL2T;
+ return(0);
+ case 0x1ea:
+ fpush();
+ ST(0) = CONSTL2E;
+ return(0);
+ case 0x1eb:
+ fpush();
+ ST(0) = CONSTPI;
+ return(0);
+ case 0x1ec:
+ fpush();
+ ST(0) = CONSTLG2;
+ return(0);
+ case 0x1ed:
+ fpush();
+ ST(0) = CONSTLN2;
+ return(0);
+ case 0x1ee:
+ fpush();
+ ST(0) = CONSTZ;
+ return(0);
+ case 0x1ef:
+ math_abort(info,SIGILL);
+ case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
+ case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
+ case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
+ case 0x1fe: case 0x1ff:
+ uprintf(
+ "math_emulate: instruction %04x not implemented\n",
+ code + 0xd800);
+ math_abort(info,SIGILL);
+ case 0x1fd:
+ /* incomplete and totally inadequate -wfj */
+ Fscale(PST(0), PST(1), &tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0); /* 19 Sep 92*/
+ case 0x1fc:
+ frndint(PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x2e9:
+ fucom(PST(1),PST(0));
+ fpop(); fpop();
+ return(0);
+ case 0x3d0: case 0x3d1:
+ return(0);
+ case 0x3e2:
+ I387.swd &= 0x7f00;
+ return(0);
+ case 0x3e3:
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return(0);
+ case 0x3e4:
+ return(0);
+ case 0x6d9:
+ fcom(PST(1),PST(0));
+ fpop(); fpop();
+ return(0);
+ case 0x7e0:
+ *(short *) &info->tf_eax = I387.swd;
+ return(0);
+ }
+ switch (code >> 3) {
+ case 0x18:
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x19:
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1a:
+ fcom(PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1b:
+ fcom(PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ fpop();
+ return(0);
+ case 0x1c:
+ real_to_real(&ST(code & 7),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1d:
+ ST(0).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1e:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1f:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x38:
+ fpush();
+ ST(0) = ST((code & 7)+1);
+ return(0);
+ case 0x39:
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0x3b:
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ case 0x98:
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x99:
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9a:
+ fcom(PST(code & 7),PST(0));
+ return(0);
+ case 0x9b:
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0x9c:
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9d:
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9e:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9f:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0xb8:
+ printf("ffree not implemented\n\r");
+ math_abort(info,SIGILL);
+ case 0xb9:
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0xba:
+ ST(code & 7) = ST(0);
+ return(0);
+ case 0xbb:
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ case 0xbc:
+ fucom(PST(code & 7),PST(0));
+ return(0);
+ case 0xbd:
+ fucom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0xd8:
+ fadd(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xd9:
+ fmul(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xda:
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0xdc:
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xdd:
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xde:
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xdf:
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xf8:
+ printf("ffree not implemented\n\r");
+ math_abort(info,SIGILL);
+ fpop();
+ return(0);
+ case 0xf9:
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0xfa:
+ case 0xfb:
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ }
+ switch ((code>>3) & 0xe7) {
+ case 0x22:
+ put_short_real(PST(0),info,code);
+ return(0);
+ case 0x23:
+ put_short_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0x24:
+ address = ea(info,code);
+ for (code = 0 ; code < 7 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0x25:
+ address = ea(info,code);
+ *(unsigned short *) &I387.cwd =
+ get_fs_word((unsigned short *) address);
+ return(0);
+ case 0x26:
+ address = ea(info,code);
+ /*verify_area(address,28);*/
+ for (code = 0 ; code < 7 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0x27:
+ address = ea(info,code);
+ /*verify_area(address,2);*/
+ put_fs_word(I387.cwd,(short *) address);
+ return(0);
+ case 0x62:
+ put_long_int(PST(0),info,code);
+ return(0);
+ case 0x63:
+ put_long_int(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0x65:
+ fpush();
+ get_temp_real(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x67:
+ put_temp_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xa2:
+ put_long_real(PST(0),info,code);
+ return(0);
+ case 0xa3:
+ put_long_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xa4:
+ address = ea(info,code);
+ for (code = 0 ; code < 27 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0xa6:
+ address = ea(info,code);
+ /*verify_area(address,108);*/
+ for (code = 0 ; code < 27 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return(0);
+ case 0xa7:
+ address = ea(info,code);
+ /*verify_area(address,2);*/
+ put_fs_word(I387.swd,(short *) address);
+ return(0);
+ case 0xe2:
+ put_short_int(PST(0),info,code);
+ return(0);
+ case 0xe3:
+ put_short_int(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xe4:
+ fpush();
+ get_BCD(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0xe5:
+ fpush();
+ get_longlong_int(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0xe6:
+ put_BCD(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xe7:
+ put_longlong_int(PST(0),info,code);
+ fpop();
+ return(0);
+ }
+ switch (code >> 9) {
+ case 0:
+ get_short_real(&tmp,info,code);
+ break;
+ case 1:
+ get_long_int(&tmp,info,code);
+ break;
+ case 2:
+ get_long_real(&tmp,info,code);
+ break;
+ case 4:
+ get_short_int(&tmp,info,code);
+ }
+ switch ((code>>3) & 0x27) {
+ case 0:
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 1:
+ fmul(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 2:
+ fcom(&tmp,PST(0));
+ return(0);
+ case 3:
+ fcom(&tmp,PST(0));
+ fpop();
+ return(0);
+ case 4:
+ tmp.exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 5:
+ ST(0).exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 6:
+ fdiv(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 7:
+ fdiv(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ }
+ if ((code & 0x138) == 0x100) {
+ fpush();
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ }
+ printf("Unknown math-insns: %04x:%08x %04x\n\r",(u_short)info->tf_cs,
+ info->tf_eip,code);
+ math_abort(info,SIGFPE);
+}
+
+static void fpop(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ff;
+ I387.swd += 0x00000800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fpush(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ff;
+ I387.swd += 0x00003800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
+{
+ temp_real_unaligned c;
+
+ c = *a;
+ *a = *b;
+ *b = c;
+}
+
+static temp_real_unaligned * __st(int i)
+{
+ i += I387.swd >> 11;
+ i &= 7;
+ return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
+}
+
+/*
+ * linux/kernel/math/ea.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * Calculate the effective address.
+ */
+
+
+static int __regoffset[] = {
+ tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI
+};
+
+#define REG(x) (curproc->p_regs[__regoffset[(x)]])
+
+static char * sib(struct trapframe * info, int mod)
+{
+ unsigned char ss,index,base;
+ long offset = 0;
+
+ base = get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+ if (index == 4)
+ offset = 0;
+ else
+ offset = REG(index);
+ offset <<= ss;
+ if (mod || base != 5)
+ offset += REG(base);
+ if (mod == 1) {
+ offset += (signed char) get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ } else if (mod == 2 || base == 5) {
+ offset += (signed) get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+}
+
+char * ea(struct trapframe * info, unsigned short code)
+{
+ unsigned char mod,rm;
+ long * tmp;
+ int offset = 0;
+
+ mod = (code >> 6) & 3;
+ rm = code & 7;
+ if (rm == 4 && mod != 3)
+ return sib(info,mod);
+ if (rm == 5 && !mod) {
+ offset = get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+ }
+ tmp = & (long)REG(rm);
+ switch (mod) {
+ case 0: offset = 0; break;
+ case 1:
+ offset = (signed char) get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ break;
+ case 2:
+ offset = (signed) get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ break;
+#ifdef notyet
+ case 3:
+ math_abort(info,1<<(SIGILL-1));
+#endif
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return offset + (char *) *tmp;
+}
+/*
+ * linux/kernel/math/get_put.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This file handles all accesses to user memory: getting and putting
+ * ints/reals/BCD etc. This is the only part that concerns itself with
+ * other than temporary real format. All other cals are strictly temp_real.
+ */
+
+void get_short_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ sr = get_fs_long((unsigned long *) addr);
+ short_to_temp(&sr,tmp);
+}
+
+void get_long_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ lr.a = get_fs_long((unsigned long *) addr);
+ lr.b = get_fs_long(1 + (unsigned long *) addr);
+ long_to_temp(&lr,tmp);
+}
+
+void get_temp_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ tmp->a = get_fs_long((unsigned long *) addr);
+ tmp->b = get_fs_long(1 + (unsigned long *) addr);
+ tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
+}
+
+void get_short_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = (signed short) get_fs_word((unsigned short *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_long_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_longlong_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = get_fs_long(1 + (unsigned long *) addr);
+ if (ti.sign = (ti.b < 0))
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ int_to_real(&ti,tmp);
+}
+
+#define MUL10(low,high) \
+__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
+"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %%ecx,%0 ; adcl %%ebx,%1" \
+:"=a" (low),"=d" (high) \
+:"0" (low),"1" (high):"cx","bx")
+
+#define ADD64(val,low,high) \
+__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
+:"0" (low),"1" (high),"r" ((unsigned long) (val)))
+
+void get_BCD(temp_real * tmp, struct trapframe * info, unsigned short code)
+{
+ int k;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ addr += 9;
+ i.sign = 0x80 & get_fs_byte(addr--);
+ i.a = i.b = 0;
+ for (k = 0; k < 9; k++) {
+ c = get_fs_byte(addr--);
+ MUL10(i.a, i.b);
+ ADD64((c>>4), i.a, i.b);
+ MUL10(i.a, i.b);
+ ADD64((c&0xf), i.a, i.b);
+ }
+ int_to_real(&i,tmp);
+}
+
+void put_short_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,4);*/
+ temp_to_short(tmp,&sr);
+ put_fs_long(sr,(unsigned long *) addr);
+}
+
+void put_long_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,8);*/
+ temp_to_long(tmp,&lr);
+ put_fs_long(lr.a, (unsigned long *) addr);
+ put_fs_long(lr.b, 1 + (unsigned long *) addr);
+}
+
+void put_temp_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,10);*/
+ put_fs_long(tmp->a, (unsigned long *) addr);
+ put_fs_long(tmp->b, 1 + (unsigned long *) addr);
+ put_fs_word(tmp->exponent, 4 + (short *) addr);
+}
+
+void put_short_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,2);*/
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_word(ti.a,(short *) addr);
+}
+
+void put_long_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,4);*/
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_long(ti.a,(unsigned long *) addr);
+}
+
+void put_longlong_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,8);*/
+ if (ti.sign)
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ put_fs_long(ti.a,(unsigned long *) addr);
+ put_fs_long(ti.b,1 + (unsigned long *) addr);
+}
+
+#define DIV10(low,high,rem) \
+__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
+ :"=d" (rem),"=a" (low),"=r" (high) \
+ :"0" (0),"1" (high),"2" (low),"c" (10))
+
+void put_BCD(const temp_real * tmp,struct trapframe * info, unsigned short code)
+{
+ int k,rem;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ /*verify_area(addr,10);*/
+ real_to_int(tmp,&i);
+ if (i.sign)
+ put_fs_byte(0x80, addr+9);
+ else
+ put_fs_byte(0, addr+9);
+ for (k = 0; k < 9; k++) {
+ DIV10(i.a,i.b,rem);
+ c = rem;
+ DIV10(i.a,i.b,rem);
+ c += rem<<4;
+ put_fs_byte(c,addr++);
+ }
+}
+
+/*
+ * linux/kernel/math/mul.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real multiplication routine.
+ */
+
+
+static void shift(int * c)
+{
+ __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
+ "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
+ "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
+ "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
+ ::"r" ((long) c):"ax");
+}
+
+static void mul64(const temp_real * a, const temp_real * b, int * c)
+{
+ __asm__("movl (%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "movl %%eax,(%2)\n\t"
+ "movl %%edx,4(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "movl %%eax,8(%2)\n\t"
+ "movl %%edx,12(%2)\n\t"
+ "movl (%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)"
+ ::"S" ((long) a),"c" ((long) b),"D" ((long) c)
+ :"ax","dx");
+}
+
+void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ int i,sign;
+ int tmp[4] = {0,0,0,0};
+
+ sign = (src1->exponent ^ src2->exponent) & 0x8000;
+ i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
+ if (i<0) {
+ result->exponent = sign;
+ result->a = result->b = 0;
+ return;
+ }
+ if (i>0x7fff) {
+ set_OE();
+ return;
+ }
+ mul64(src1,src2,tmp);
+ if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
+ while (i && tmp[3] >= 0) {
+ i--;
+ shift(tmp);
+ }
+ else
+ i = 0;
+ result->exponent = i | sign;
+ result->a = tmp[2];
+ result->b = tmp[3];
+}
+
+/*
+ * linux/kernel/math/div.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real division routine.
+ */
+
+#include "i386/i386/math_emu.h"
+
+static void shift_left(int * c)
+{
+ __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
+ "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
+ "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
+ "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
+ ::"r" ((long) c):"ax");
+}
+
+static void shift_right(int * c)
+{
+ __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
+ ::"r" ((long) c));
+}
+
+static int try_sub(int * a, int * b)
+{
+ char ok;
+
+ __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
+ "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
+ "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
+ "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
+ "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b));
+ return ok;
+}
+
+static void div64(int * a, int * b, int * c)
+{
+ int tmp[4];
+ int i;
+ unsigned int mask = 0;
+
+ c += 4;
+ for (i = 0 ; i<64 ; i++) {
+ if (!(mask >>= 1)) {
+ c--;
+ mask = 0x80000000;
+ }
+ tmp[0] = a[0]; tmp[1] = a[1];
+ tmp[2] = a[2]; tmp[3] = a[3];
+ if (try_sub(b,tmp)) {
+ *c |= mask;
+ a[0] = tmp[0]; a[1] = tmp[1];
+ a[2] = tmp[2]; a[3] = tmp[3];
+ }
+ shift_right(b);
+ }
+}
+
+void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ int i,sign;
+ int a[4],b[4],tmp[4] = {0,0,0,0};
+
+ sign = (src1->exponent ^ src2->exponent) & 0x8000;
+ if (!(src2->a || src2->b)) {
+ set_ZE();
+ return;
+ }
+ i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
+ if (i<0) {
+ set_UE();
+ result->exponent = sign;
+ result->a = result->b = 0;
+ return;
+ }
+ a[0] = a[1] = 0;
+ a[2] = src1->a;
+ a[3] = src1->b;
+ b[0] = b[1] = 0;
+ b[2] = src2->a;
+ b[3] = src2->b;
+ while (b[3] >= 0) {
+ i++;
+ shift_left(b);
+ }
+ div64(a,b,tmp);
+ if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
+ while (i && tmp[3] >= 0) {
+ i--;
+ shift_left(tmp);
+ }
+ if (tmp[3] >= 0)
+ set_DE();
+ } else
+ i = 0;
+ if (i>0x7fff) {
+ set_OE();
+ return;
+ }
+ if (tmp[0] || tmp[1])
+ set_PE();
+ result->exponent = i | sign;
+ result->a = tmp[2];
+ result->b = tmp[3];
+}
+
+/*
+ * linux/kernel/math/add.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real addition routine.
+ *
+ * NOTE! These aren't exact: they are only 62 bits wide, and don't do
+ * correct rounding. Fast hack. The reason is that we shift right the
+ * values by two, in order not to have overflow (1 bit), and to be able
+ * to move the sign into the mantissa (1 bit). Much simpler algorithms,
+ * and 62 bits (61 really - no rounding) accuracy is usually enough. The
+ * only time you should notice anything weird is when adding 64-bit
+ * integers together. When using doubles (52 bits accuracy), the
+ * 61-bit accuracy never shows at all.
+ */
+
+#define NEGINT(a) \
+__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
+ :"=r" (a->a),"=r" (a->b) \
+ :"0" (a->a),"1" (a->b))
+
+static void signify(temp_real * a)
+{
+ a->exponent += 2;
+ __asm__("shrdl $2,%1,%0 ; shrl $2,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ if (a->exponent < 0)
+ NEGINT(a);
+ a->exponent &= 0x7fff;
+}
+
+static void unsignify(temp_real * a)
+{
+ if (!(a->a || a->b)) {
+ a->exponent = 0;
+ return;
+ }
+ a->exponent &= 0x7fff;
+ if (a->b < 0) {
+ NEGINT(a);
+ a->exponent |= 0x8000;
+ }
+ while (a->b >= 0) {
+ a->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ }
+}
+
+void fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ temp_real a,b;
+ int x1,x2,shift;
+
+ x1 = src1->exponent & 0x7fff;
+ x2 = src2->exponent & 0x7fff;
+ if (x1 > x2) {
+ a = *src1;
+ b = *src2;
+ shift = x1-x2;
+ } else {
+ a = *src2;
+ b = *src1;
+ shift = x2-x1;
+ }
+ if (shift >= 64) {
+ *result = a;
+ return;
+ }
+ if (shift >= 32) {
+ b.a = b.b;
+ b.b = 0;
+ shift -= 32;
+ }
+ __asm__("shrdl %4,%1,%0 ; shrl %4,%1"
+ :"=r" (b.a),"=r" (b.b)
+ :"0" (b.a),"1" (b.b),"c" ((char) shift));
+ signify(&a);
+ signify(&b);
+ __asm__("addl %4,%0 ; adcl %5,%1"
+ :"=r" (a.a),"=r" (a.b)
+ :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
+ unsignify(&a);
+ *result = a;
+}
+
+/*
+ * linux/kernel/math/compare.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real comparison routines
+ */
+
+
+#define clear_Cx() (I387.swd &= ~0x4500)
+
+static void normalize(temp_real * a)
+{
+ int i = a->exponent & 0x7fff;
+ int sign = a->exponent & 0x8000;
+
+ if (!(a->a || a->b)) {
+ a->exponent = 0;
+ return;
+ }
+ while (i && a->b >= 0) {
+ i--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ }
+ a->exponent = i | sign;
+}
+
+void ftst(const temp_real * a)
+{
+ temp_real b;
+
+ clear_Cx();
+ b = *a;
+ normalize(&b);
+ if (b.a || b.b || b.exponent) {
+ if (b.exponent < 0)
+ set_C0();
+ } else
+ set_C3();
+}
+
+void fcom(const temp_real * src1, const temp_real * src2)
+{
+ temp_real a;
+
+ a = *src1;
+ a.exponent ^= 0x8000;
+ fadd(&a,src2,&a);
+ ftst(&a);
+}
+
+void fucom(const temp_real * src1, const temp_real * src2)
+{
+ fcom(src1,src2);
+}
+
+/*
+ * linux/kernel/math/convert.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+
+/*
+ * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
+ * and temp_to_short conversion routines: don't touch them if you don't
+ * know what's going on. They are the adding of one in the rounding: the
+ * overflow bit is also used for adding one into the exponent. Thus it
+ * looks like the overflow would be incorrectly handled, but due to the
+ * way the IEEE numbers work, things are correct.
+ *
+ * There is no checking for total overflow in the conversions, though (ie
+ * if the temp-real number simply won't fit in a short- or long-real.)
+ */
+
+void short_to_temp(const short_real * a, temp_real * b)
+{
+ if (!(*a & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (*a)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((*a>>23) & 0xff)-127+16383;
+ if (*a<0)
+ b->exponent |= 0x8000;
+ b->b = (*a<<8) | 0x80000000;
+ b->a = 0;
+}
+
+void long_to_temp(const long_real * a, temp_real * b)
+{
+ if (!a->a && !(a->b & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (a->b)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
+ if (a->b<0)
+ b->exponent |= 0x8000;
+ b->b = 0x80000000 | (a->b<<11) | (((unsigned long)a->a)>>21);
+ b->a = a->a<<11;
+}
+
+void temp_to_short(const temp_real * a, short_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ *b = (a->exponent)?0x80000000:0;
+ return;
+ }
+ *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
+ if (a->exponent < 0)
+ *b |= 0x80000000;
+ *b |= (a->b >> 8) & 0x007fffff;
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->b & 0xff) > 0x80)
+ ++*b;
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ }
+}
+
+void temp_to_long(const temp_real * a, long_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ b->a = 0;
+ b->b = (a->exponent)?0x80000000:0;
+ return;
+ }
+ b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
+ if (a->exponent < 0)
+ b->b |= 0x80000000;
+ b->b |= (a->b >> 11) & 0x000fffff;
+ b->a = a->b << 21;
+ b->a |= (a->a >> 11) & 0x001fffff;
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->a & 0x7ff) > 0x400)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void frndint(const temp_real * a, temp_real * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ if ((shift < 0) || (shift == 16383+63)) {
+ *b = *a;
+ return;
+ }
+ b->a = b->b = underflow = 0;
+ b->exponent = a->exponent;
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ b->exponent += 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ b->exponent += 64;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
+ b->exponent += shift;
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if ((b->exponent >= 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((b->exponent < 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+ if (b->a || b->b)
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+ else
+ b->exponent = 0;
+}
+
+void Fscale(const temp_real *a, const temp_real *b, temp_real *c)
+{
+ temp_int ti;
+
+ *c = *a;
+ if(!c->a && !c->b) { /* 19 Sep 92*/
+ c->exponent = 0;
+ return;
+ }
+ real_to_int(b, &ti);
+ if(ti.sign)
+ c->exponent -= ti.a;
+ else
+ c->exponent += ti.a;
+}
+
+void real_to_int(const temp_real * a, temp_int * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ b->a = b->b = underflow = 0;
+ b->sign = (a->exponent < 0);
+ if (shift < 0) {
+ set_OE();
+ return;
+ }
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch (ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if (!b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if (b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void int_to_real(const temp_int * a, temp_real * b)
+{
+ b->a = a->a;
+ b->b = a->b;
+ if (b->a || b->b)
+ b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
+ else {
+ b->exponent = 0;
+ return;
+ }
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+}
+#endif /* defined(i486) || defined(i387) */
diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c
new file mode 100644
index 0000000..650e21e
--- /dev/null
+++ b/sys/i386/i386/mem.c
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and code derived from software contributed to
+ * Berkeley by William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: mem.c 1.13 89/10/08$
+ * @(#)mem.c 7.2 (Berkeley) 5/9/91
+ */
+
+/*
+ * Memory special file
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "uio.h"
+#include "malloc.h"
+
+#include "machine/cpu.h"
+
+#include "vm/vm_param.h"
+#include "vm/lock.h"
+#include "vm/vm_statistics.h"
+#include "vm/pmap.h"
+#include "vm/vm_prot.h"
+
+extern char *vmmap; /* poor name! */
+/*ARGSUSED*/
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register int o;
+ register u_int c, v;
+ register struct iovec *iov;
+ int error = 0;
+ caddr_t zbuf = NULL;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+ case 0:
+ v = uio->uio_offset;
+ pmap_enter(pmap_kernel(), vmmap, v,
+ uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
+ TRUE);
+ o = (int)uio->uio_offset & PGOFSET;
+ c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
+ c = MIN(c, (u_int)(NBPG - o));
+ c = MIN(c, (u_int)iov->iov_len);
+ error = uiomove((caddr_t)&vmmap[o], (int)c, uio);
+ pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]);
+ continue;
+
+/* minor device 1 is kernel memory */
+ case 1:
+ c = iov->iov_len;
+ if (!kernacc((caddr_t)uio->uio_offset, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return(EFAULT);
+ error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
+ continue;
+
+/* minor device 2 is EOF/RATHOLE */
+ case 2:
+ if (uio->uio_rw == UIO_READ)
+ return (0);
+ c = iov->iov_len;
+ break;
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+ case 12:
+ if (uio->uio_rw == UIO_WRITE) {
+ c = iov->iov_len;
+ break;
+ }
+ if (zbuf == NULL) {
+ zbuf = (caddr_t)
+ malloc(CLBYTES, M_TEMP, M_WAITOK);
+ bzero(zbuf, CLBYTES);
+ }
+ c = MIN(iov->iov_len, CLBYTES);
+ error = uiomove(zbuf, (int)c, uio);
+ continue;
+
+#ifdef notyet
+/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
+ i/o device address bus, different than memory bus. Semantics here are
+ very different than ordinary read/write, as if iov_len is a multiple
+ an implied string move from a single port will be done. Note that lseek
+ must be used to set the port number reliably. */
+ case 14:
+ if (iov->iov_len == 1) {
+ u_char tmp;
+ tmp = inb(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insb(uio->uio_offset, iov->iov_base,
+ iov->iov_len);
+ }
+ break;
+ case 15:
+ if (iov->iov_len == sizeof (short)) {
+ u_short tmp;
+ tmp = inw(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insw(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (short));
+ }
+ break;
+ case 16:
+ if (iov->iov_len == sizeof (long)) {
+ u_long tmp;
+ tmp = inl(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insl(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (long));
+ }
+ break;
+#endif
+
+ default:
+ return (ENXIO);
+ }
+ if (error)
+ break;
+ iov->iov_base += c;
+ iov->iov_len -= c;
+ uio->uio_offset += c;
+ uio->uio_resid -= c;
+ }
+ if (zbuf)
+ free(zbuf, M_TEMP);
+ return (error);
+}
diff --git a/sys/i386/i386/microtime.s b/sys/i386/i386/microtime.s
new file mode 100644
index 0000000..4af938b
--- /dev/null
+++ b/sys/i386/i386/microtime.s
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header$
+ */
+
+#include "asm.h"
+#include "../isa/isa.h"
+#include "../isa/timerreg.h"
+
+/*
+ * Use a higher resolution version of microtime if HZ is not
+ * overridden (i.e. it is 100Hz).
+ */
+#ifndef HZ
+ENTRY(microtime)
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ movl $_time,%ebx
+
+ cli # disable interrupts
+
+ movl (%ebx),%edi # sec = time.tv_sec
+ movl 4(%ebx),%esi # usec = time.tv_usec
+
+ movl $(TIMER_SEL0|TIMER_LATCH),%eax
+ outb %al,$TIMER_MODE # latch timer 0's counter
+
+ #
+ # Read counter value into ebx, LSB first
+ #
+ inb $TIMER_CNTR0,%al
+ movzbl %al,%ebx
+ inb $TIMER_CNTR0,%al
+ movzbl %al,%eax
+ sall $8,%eax
+ orl %eax,%ebx
+
+ #
+ # Now check for counter overflow. This is tricky because the
+ # timer chip doesn't let us atomically read the current counter
+ # value and the output state (i.e., overflow state). We have
+ # to read the ICU interrupt request register (IRR) to see if the
+ # overflow has occured. Because we lack atomicity, we use
+ # the (very accurate) heuristic that we only check for
+ # overflow if the value read is close to the interrupt period.
+ # E.g., if we just checked the IRR, we might read a non-overflowing
+ # value close to 0, experience overflow, then read this overflow
+ # from the IRR, and mistakenly add a correction to the "close
+ # to zero" value.
+ #
+ # We compare the counter value to heuristic constant 11890.
+ # If the counter value is less than this, we assume the counter
+ # didn't overflow between disabling interrupts above and latching
+ # the counter value. For example, we assume that the above 10 or so
+ # instructions take less than 11932 - 11890 = 42 microseconds to
+ # execute.
+ #
+ # Otherwise, the counter might have overflowed. We check for this
+ # condition by reading the interrupt request register out of the ICU.
+ # If it overflowed, we add in one clock period.
+ #
+ # The heuristic is "very accurate" because it works 100% if
+ # we're called from an ipl less than the clock. Otherwise,
+ # it might not work. Currently, only gettimeofday and bpf
+ # call microtime so it's not a problem.
+ #
+ cmpl $11890,%ebx
+ jle 2f
+ movl $0x0a,%eax # tell ICU we want IRR
+ outb %al,$IO_ICU1
+
+ inb $IO_ICU1,%al # read IRR in ICU
+ testb $1,%al # is a timer interrupt pending?
+ je 1f
+ addl $-11932,%ebx # yes, subtract one clock period
+1:
+ movl $0x0b,%eax # tell ICU we want ISR
+ outb %al,$IO_ICU1 # (rest of kernel expects this)
+2:
+ sti # enable interrupts
+
+ movl $11932,%eax # subtract counter value from 11932 since
+ subl %ebx,%eax # it is a count-down value
+ imull $1000,%eax,%eax
+ movl $0,%edx # zero extend eax for div
+ movl $1193,%ecx
+ idivl %ecx # convert to usecs: mult by 1000/1193
+
+ addl %eax,%esi # add counter usecs to time.tv_usec
+ cmpl $1000000,%esi # carry in timeval?
+ jl 3f
+ subl $1000000,%esi # adjust usec
+ incl %edi # bump sec
+3:
+ movl 16(%esp),%ecx # load timeval pointer arg
+ movl %edi,(%ecx) # tvp->tv_sec = sec
+ movl %esi,4(%ecx) # tvp->tv_usec = usec
+
+ popl %ebx # restore regs
+ popl %esi
+ popl %edi
+ ret
+#endif
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
new file mode 100644
index 0000000..66c7fec
--- /dev/null
+++ b/sys/i386/i386/pmap.c
@@ -0,0 +1,1728 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pmap.c 7.7 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00063
+ * -------------------- ----- ----------------------
+ *
+ * 28 Nov 1991 Poul-Henning Kamp Speedup processing.
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $";
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90
+ */
+
+/*
+ * Reno i386 version, from Mike Hibler's hp300 version.
+ */
+
+/*
+ * Manages physical address maps.
+ *
+ * In addition to hardware address maps, this
+ * module is called upon to provide software-use-only
+ * maps which may or may not be stored in the same
+ * form as hardware maps. These pseudo-maps are
+ * used to store intermediate results from copy
+ * operations to and from address spaces.
+ *
+ * Since the information managed by this module is
+ * also stored by the logical address mapping module,
+ * this module may throw away valid virtual-to-physical
+ * mappings at almost any time. However, invalidations
+ * of virtual-to-physical mappings must be done as
+ * requested.
+ *
+ * In order to cope with hardware architectures which
+ * make virtual-to-physical map invalidates expensive,
+ * this module may delay invalidate or reduced protection
+ * operations until such time as they are actually
+ * necessary. This module is given full information as
+ * to which processors are currently using which maps,
+ * and to when physical maps must be made correct.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "malloc.h"
+#include "user.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+/*#include "vm/vm_pageout.h"*/
+
+#include "i386/isa/isa.h"
+
+/*
+ * Allocate various and sundry SYSMAPs used in the days of old VM
+ * and not yet converted. XXX.
+ */
+#define BSDVM_COMPAT 1
+
+#ifdef DEBUG
+struct {
+ int kernel; /* entering kernel mapping */
+ int user; /* entering user mapping */
+ int ptpneeded; /* needed to allocate a PT page */
+ int pwchange; /* no mapping change, just wiring or protection */
+ int wchange; /* no mapping change, just wiring */
+ int mchange; /* was mapped but mapping to different page */
+ int managed; /* a managed page */
+ int firstpv; /* first mapping for this PA */
+ int secondpv; /* second mapping for this PA */
+ int ci; /* cache inhibited */
+ int unmanaged; /* not a managed page */
+ int flushes; /* cache flushes */
+} enter_stats;
+struct {
+ int calls;
+ int removes;
+ int pvfirst;
+ int pvsearch;
+ int ptinvalid;
+ int uflushes;
+ int sflushes;
+} remove_stats;
+
+int debugmap = 0;
+int pmapdebug = 0 /* 0xffff */;
+#define PDB_FOLLOW 0x0001
+#define PDB_INIT 0x0002
+#define PDB_ENTER 0x0004
+#define PDB_REMOVE 0x0008
+#define PDB_CREATE 0x0010
+#define PDB_PTPAGE 0x0020
+#define PDB_CACHE 0x0040
+#define PDB_BITS 0x0080
+#define PDB_COLLECT 0x0100
+#define PDB_PROTECT 0x0200
+#define PDB_PDRTAB 0x0400
+#define PDB_PARANOIA 0x2000
+#define PDB_WIRING 0x4000
+#define PDB_PVDUMP 0x8000
+
+int pmapvacflush = 0;
+#define PVF_ENTER 0x01
+#define PVF_REMOVE 0x02
+#define PVF_PROTECT 0x04
+#define PVF_TOTAL 0x80
+#endif
+
+/*
+ * Get PDEs and PTEs for user/kernel address space
+ */
+#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
+
+#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
+
+#define pmap_pde_v(pte) ((pte)->pd_v)
+#define pmap_pte_w(pte) ((pte)->pg_w)
+/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */
+#define pmap_pte_m(pte) ((pte)->pg_m)
+#define pmap_pte_u(pte) ((pte)->pg_u)
+#define pmap_pte_v(pte) ((pte)->pg_v)
+#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v))
+#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v))
+
+/*
+ * Given a map and a machine independent protection code,
+ * convert to a vax protection code.
+ */
+#define pte_prot(m, p) (protection_codes[p])
+int protection_codes[8];
+
+struct pmap kernel_pmap_store;
+pmap_t kernel_pmap;
+
+vm_offset_t avail_start; /* PA of first available physical page */
+vm_offset_t avail_end; /* PA of last available physical page */
+vm_size_t mem_size; /* memory size in bytes */
+vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/
+vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
+vm_offset_t vm_first_phys; /* PA of first managed page */
+vm_offset_t vm_last_phys; /* PA just past last managed page */
+int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
+boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
+char *pmap_attributes; /* reference and modify bits */
+
+boolean_t pmap_testbit();
+void pmap_clear_modify();
+
+#if BSDVM_COMPAT
+#include "msgbuf.h"
+
+/*
+ * All those kernel PT submaps that BSD is so fond of
+ */
+struct pte *CMAP1, *CMAP2, *mmap;
+caddr_t CADDR1, CADDR2, vmmap;
+struct pte *msgbufmap;
+struct msgbuf *msgbufp;
+#endif
+
+/*
+ * Bootstrap the system enough to run with virtual memory.
+ * Map the kernel's code and data, and allocate the system page table.
+ *
+ * On the I386 this is called after mapping has already been enabled
+ * and just syncs the pmap module with what has already been done.
+ * [We can't call it easily with mapping off since the kernel is not
+ * mapped with PA == VA, hence we would have to relocate every address
+ * from the linked base (virtual) address 0xFE000000 to the actual
+ * (physical) address starting relative to 0]
+ */
+struct pte *pmap_pte();
+
+void
+pmap_bootstrap(firstaddr, loadaddr)
+ vm_offset_t firstaddr;
+ vm_offset_t loadaddr;
+{
+#if BSDVM_COMPAT
+ vm_offset_t va;
+ struct pte *pte;
+#endif
+ extern vm_offset_t maxmem, physmem;
+extern int IdlePTD;
+
+ avail_start = firstaddr;
+ avail_end = maxmem << PG_SHIFT;
+
+ /* XXX: allow for msgbuf */
+ avail_end -= i386_round_page(sizeof(struct msgbuf));
+
+ mem_size = physmem << PG_SHIFT;
+ virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG;
+ virtual_end = VM_MAX_KERNEL_ADDRESS;
+ i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE;
+
+ /*
+ * Initialize protection array.
+ */
+ i386_protection_init();
+
+ /*
+ * The kernel's pmap is statically allocated so we don't
+ * have to use pmap_create, which is unlikely to work
+ * correctly at this part of the boot sequence.
+ */
+ kernel_pmap = &kernel_pmap_store;
+
+#ifdef notdef
+ /*
+ * Create Kernel page directory table and page maps.
+ * [ currently done in locore. i have wild and crazy ideas -wfj ]
+ */
+ bzero(firstaddr, 4*NBPG);
+ kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS;
+ kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG;
+
+ firstaddr += NBPG;
+ for (x = i386_btod(VM_MIN_KERNEL_ADDRESS);
+ x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) {
+ struct pde *pde;
+ pde = kernel_pmap->pm_pdir + x;
+ *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW;
+ }
+#else
+ kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD);
+#endif
+
+
+ simple_lock_init(&kernel_pmap->pm_lock);
+ kernel_pmap->pm_count = 1;
+
+#if BSDVM_COMPAT
+ /*
+ * Allocate all the submaps we need
+ */
+#define SYSMAP(c, p, v, n) \
+ v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n);
+
+ va = virtual_avail;
+ pte = pmap_pte(kernel_pmap, va);
+
+ SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 )
+ SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 )
+ SYSMAP(caddr_t ,mmap ,vmmap ,1 )
+ SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 )
+ virtual_avail = va;
+#endif
+ /*
+ * reserve special hunk of memory for use by bus dma as a bounce
+ * buffer (contiguous virtual *and* physical memory). for now,
+ * assume vm does not use memory beneath hole, and we know that
+ * the bootstrap uses top 32k of base memory. -wfj
+ */
+ {
+ extern vm_offset_t isaphysmem;
+ isaphysmem = va;
+
+ virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL);
+ }
+
+ *(int *)PTD = 0;
+ load_cr3(rcr3());
+
+}
+
+/*
+ * Initialize the pmap module.
+ * Called by vm_init, to initialize any structures that the pmap
+ * system needs to map virtual memory.
+ */
+void
+pmap_init(phys_start, phys_end)
+ vm_offset_t phys_start, phys_end;
+{
+ vm_offset_t addr, addr2;
+ vm_size_t npg, s;
+ int rv;
+ extern int KPTphys;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_init(%x, %x)\n", phys_start, phys_end);
+#endif
+ /*
+ * Now that kernel map has been allocated, we can mark as
+ * unavailable regions which we have mapped in locore.
+ */
+ addr = atdevbase;
+ (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
+ &addr, (0x100000-0xa0000), FALSE);
+
+ addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */;
+ vm_object_reference(kernel_object);
+ (void) vm_map_find(kernel_map, kernel_object, addr,
+ &addr, 2*NBPG, FALSE);
+
+ /*
+ * Allocate memory for random pmap data structures. Includes the
+ * pv_head_table and pmap_attributes.
+ */
+ npg = atop(phys_end - phys_start);
+ s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg);
+ s = round_page(s);
+ addr = (vm_offset_t) kmem_alloc(kernel_map, s);
+ pv_table = (pv_entry_t) addr;
+ addr += sizeof(struct pv_entry) * npg;
+ pmap_attributes = (char *) addr;
+#ifdef DEBUG
+ if (pmapdebug & PDB_INIT)
+ printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n",
+ s, npg, pv_table, pmap_attributes);
+#endif
+
+ /*
+ * Now it is safe to enable pv_table recording.
+ */
+ vm_first_phys = phys_start;
+ vm_last_phys = phys_end;
+ pmap_initialized = TRUE;
+}
+
+/*
+ * Used to map a range of physical addresses into kernel
+ * virtual address space.
+ *
+ * For now, VM is already on, we only need to map the
+ * specified memory.
+ */
+vm_offset_t
+pmap_map(virt, start, end, prot)
+ vm_offset_t virt;
+ vm_offset_t start;
+ vm_offset_t end;
+ int prot;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot);
+#endif
+ while (start < end) {
+ pmap_enter(kernel_pmap, virt, start, prot, FALSE);
+ virt += PAGE_SIZE;
+ start += PAGE_SIZE;
+ }
+ return(virt);
+}
+
+/*
+ * Create and return a physical map.
+ *
+ * If the size specified for the map
+ * is zero, the map is an actual physical
+ * map, and may be referenced by the
+ * hardware.
+ *
+ * If the size specified is non-zero,
+ * the map will be used in software only, and
+ * is bounded by that size.
+ *
+ * [ just allocate a ptd and mark it uninitialize -- should we track
+ * with a table which process has which ptd? -wfj ]
+ */
+
+pmap_t
+pmap_create(size)
+ vm_size_t size;
+{
+ register pmap_t pmap;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+ printf("pmap_create(%x)\n", size);
+#endif
+ /*
+ * Software use map does not need a pmap
+ */
+ if (size)
+ return(NULL);
+
+ /* XXX: is it ok to wait here? */
+ pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
+#ifdef notifwewait
+ if (pmap == NULL)
+ panic("pmap_create: cannot allocate a pmap");
+#endif
+ bzero(pmap, sizeof(*pmap));
+ pmap_pinit(pmap);
+ return (pmap);
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+void
+pmap_pinit(pmap)
+ register struct pmap *pmap;
+{
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
+ pg("pmap_pinit(%x)\n", pmap);
+#endif
+
+ /*
+ * No need to allocate page table space yet but we do need a
+ * valid page directory table.
+ */
+ pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG);
+
+ /* wire in kernel global address entries */
+ bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST,
+ (KPTDI_LAST-KPTDI_FIRST+1)*4);
+
+ /* install self-referential address mapping entry */
+ *(int *)(pmap->pm_pdir+PTDPTDI) =
+ (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW;
+
+ pmap->pm_count = 1;
+ simple_lock_init(&pmap->pm_lock);
+}
+
+/*
+ * Retire the given physical map from service.
+ * Should only be called if the map contains
+ * no valid mappings.
+ */
+void
+pmap_destroy(pmap)
+ register pmap_t pmap;
+{
+ int count;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_destroy(%x)\n", pmap);
+#endif
+ if (pmap == NULL)
+ return;
+
+ simple_lock(&pmap->pm_lock);
+ count = --pmap->pm_count;
+ simple_unlock(&pmap->pm_lock);
+ if (count == 0) {
+ pmap_release(pmap);
+ free((caddr_t)pmap, M_VMPMAP);
+ }
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap)
+ register struct pmap *pmap;
+{
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ pg("pmap_release(%x)\n", pmap);
+#endif
+#ifdef notdef /* DIAGNOSTIC */
+ /* count would be 0 from pmap_destroy... */
+ simple_lock(&pmap->pm_lock);
+ if (pmap->pm_count != 1)
+ panic("pmap_release count");
+#endif
+ kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG);
+}
+
+/*
+ * Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap)
+ pmap_t pmap;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_reference(%x)", pmap);
+#endif
+ if (pmap != NULL) {
+ simple_lock(&pmap->pm_lock);
+ pmap->pm_count++;
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+/*
+ * Remove the given range of addresses from the specified map.
+ *
+ * It is assumed that the start and end are properly
+ * rounded to the page size.
+ */
+void
+pmap_remove(pmap, sva, eva)
+ struct pmap *pmap;
+ register vm_offset_t sva;
+ register vm_offset_t eva;
+{
+ register pt_entry_t *ptp,*ptq;
+ vm_offset_t va;
+ vm_offset_t pa;
+ pt_entry_t *pte;
+ pv_entry_t pv, npv;
+ int ix;
+ int s, bits;
+#ifdef DEBUG
+ pt_entry_t opte;
+
+ if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
+ pg("pmap_remove(%x, %x, %x)", pmap, sva, eva);
+#endif
+
+ if (pmap == NULL)
+ return;
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ ptp=PTmap;
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+#ifdef DEBUG
+ remove_stats.calls++;
+#endif
+
+ /* this is essential since we must check the PDE(sva) for precense */
+ while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva)))
+ sva = (sva & PD_MASK) + (1<<PD_SHIFT);
+ sva = i386_btop(sva);
+ eva = i386_btop(eva);
+
+ for (; sva < eva; sva++) {
+ /*
+ * Weed out invalid mappings.
+ * Note: we assume that the page directory table is
+ * always allocated, and in kernel virtual.
+ */
+ ptq=ptp+sva;
+ while((sva & 0x3ff) && !pmap_pte_pa(ptq))
+ {
+ if(++sva >= eva)
+ return;
+ ptq++;
+ }
+
+
+ if(!(sva & 0x3ff)) /* Only check once in a while */
+ {
+ if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva))))
+ {
+ /* We can race ahead here, straight to next pde.. */
+ sva = (sva & 0xffc00) + (1<<10) -1 ;
+ continue;
+ }
+ }
+ if(!pmap_pte_pa(ptp+sva))
+ continue;
+
+ pte = ptp + sva;
+ pa = pmap_pte_pa(pte);
+ va = i386_ptob(sva);
+#ifdef DEBUG
+ opte = *pte;
+ remove_stats.removes++;
+#endif
+ /*
+ * Update statistics
+ */
+ if (pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * Invalidate the PTEs.
+ * XXX: should cluster them up and invalidate as many
+ * as possible at once.
+ */
+#ifdef DEBUG
+ if (pmapdebug & PDB_REMOVE)
+ printf("remove: inv %x ptes at %x(%x) ",
+ i386pagesperpage, pte, *(int *)pte);
+#endif
+ bits = ix = 0;
+ do {
+ bits |= *(int *)pte & (PG_U|PG_M);
+ *(int *)pte++ = 0;
+ /*TBIS(va + ix * I386_PAGE_SIZE);*/
+ } while (++ix != i386pagesperpage);
+ if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pmap, (struct pcb *)curproc->p_addr);
+ /* are we current address space or kernel? */
+ /*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ load_cr3(curpcb->pcb_ptd);*/
+ tlbflush();
+
+#ifdef needednotdone
+reduce wiring count on page table pages as references drop
+#endif
+
+ /*
+ * Remove from the PV table (raise IPL since we
+ * may be called at interrupt time).
+ */
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ continue;
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * If it is the first entry on the list, it is actually
+ * in the header and we must copy the following entry up
+ * to the header. Otherwise we must search the list for
+ * the entry. In either case we free the now unused entry.
+ */
+ if (pmap == pv->pv_pmap && va == pv->pv_va) {
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free((caddr_t)npv, M_VMPVENT);
+ } else
+ pv->pv_pmap = NULL;
+#ifdef DEBUG
+ remove_stats.pvfirst++;
+#endif
+ } else {
+ for (npv = pv->pv_next; npv; npv = npv->pv_next) {
+#ifdef DEBUG
+ remove_stats.pvsearch++;
+#endif
+ if (pmap == npv->pv_pmap && va == npv->pv_va)
+ break;
+ pv = npv;
+ }
+#ifdef DEBUG
+ if (npv == NULL)
+ panic("pmap_remove: PA not in pv_tab");
+#endif
+ pv->pv_next = npv->pv_next;
+ free((caddr_t)npv, M_VMPVENT);
+ pv = pa_to_pvh(pa);
+ }
+
+#ifdef notdef
+[tally number of pagetable pages, if sharing of ptpages adjust here]
+#endif
+ /*
+ * Update saved attributes for managed page
+ */
+ pmap_attributes[pa_index(pa)] |= bits;
+ splx(s);
+ }
+#ifdef notdef
+[cache and tlb flushing, if needed]
+#endif
+}
+
+/*
+ * Routine: pmap_remove_all
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ */
+void
+pmap_remove_all(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+ int s;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
+ printf("pmap_remove_all(%x)", pa);
+ /*pmap_pvdump(pa);*/
+#endif
+ /*
+ * Not one of ours
+ */
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Do it the easy way for now
+ */
+ while (pv->pv_pmap != NULL) {
+#ifdef DEBUG
+ if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) ||
+ pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa)
+ panic("pmap_remove_all: bad mapping");
+#endif
+ pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE);
+ }
+ splx(s);
+}
+
+/*
+ * Routine: pmap_copy_on_write
+ * Function:
+ * Remove write privileges from all
+ * physical maps for this physical page.
+ */
+void
+pmap_copy_on_write(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
+ printf("pmap_copy_on_write(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_RO, TRUE);
+}
+
+/*
+ * Set the physical protection on the
+ * specified range of this map as requested.
+ */
+void
+pmap_protect(pmap, sva, eva, prot)
+ register pmap_t pmap;
+ vm_offset_t sva, eva;
+ vm_prot_t prot;
+{
+ register pt_entry_t *pte;
+ register vm_offset_t va;
+ register int ix;
+ int i386prot;
+ boolean_t firstpage = TRUE;
+ register pt_entry_t *ptp;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
+ printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot);
+#endif
+ if (pmap == NULL)
+ return;
+
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+ pmap_remove(pmap, sva, eva);
+ return;
+ }
+ if (prot & VM_PROT_WRITE)
+ return;
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ ptp=PTmap;
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+ for (va = sva; va < eva; va += PAGE_SIZE) {
+ /*
+ * Page table page is not allocated.
+ * Skip it, we don't want to force allocation
+ * of unnecessary PTE pages just to set the protection.
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ /* XXX: avoid address wrap around */
+ if (va >= i386_trunc_pdr((vm_offset_t)-1))
+ break;
+ va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE;
+ continue;
+ }
+
+ pte = ptp + i386_btop(va);
+
+ /*
+ * Page not valid. Again, skip it.
+ * Should we do this? Or set protection anyway?
+ */
+ if (!pmap_pte_v(pte))
+ continue;
+
+ ix = 0;
+ i386prot = pte_prot(pmap, prot);
+ if(va < UPT_MAX_ADDRESS)
+ i386prot |= 2 /*PG_u*/;
+ do {
+ /* clear VAC here if PG_RO? */
+ pmap_pte_set_prot(pte++, i386prot);
+ /*TBIS(va + ix * I386_PAGE_SIZE);*/
+ } while (++ix != i386pagesperpage);
+ }
+ if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pmap, (struct pcb *)curproc->p_addr);
+}
+
+/*
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * If specified, the page will be wired down, meaning
+ * that the related pte can not be reclaimed.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+void
+pmap_enter(pmap, va, pa, prot, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+ vm_prot_t prot;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register int npte, ix;
+ vm_offset_t opa;
+ boolean_t cacheable = TRUE;
+ boolean_t checkpv = TRUE;
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))
+ printf("pmap_enter(%x, %x, %x, %x, %x)",
+ pmap, va, pa, prot, wired);
+#endif
+ if (pmap == NULL)
+ return;
+
+ if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig");
+ /* also, should not muck with PTD va! */
+
+#ifdef DEBUG
+ if (pmap == kernel_pmap)
+ enter_stats.kernel++;
+ else
+ enter_stats.user++;
+#endif
+
+ /*
+ * Page Directory table entry not valid, we need a new PT page
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ pg("ptdi %x", pmap->pm_pdir[PTDPTDI]);
+ }
+
+ pte = pmap_pte(pmap, va);
+ opa = pmap_pte_pa(pte);
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: pte %x, *pte %x ", pte, *(int *)pte);
+#endif
+
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+#ifdef DEBUG
+ enter_stats.pwchange++;
+#endif
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ pg("enter: wiring change -> %x ", wired);
+#endif
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+#ifdef DEBUG
+ enter_stats.wchange++;
+#endif
+ }
+ goto validate;
+ }
+
+ /*
+ * Mapping has changed, invalidate old range and fall through to
+ * handle validating new mapping.
+ */
+ if (opa) {
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: removing old mapping %x pa %x ", va, opa);
+#endif
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+#ifdef DEBUG
+ enter_stats.mchange++;
+#endif
+ }
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+ if (pa >= vm_first_phys && pa < vm_last_phys) {
+ register pv_entry_t pv, npv;
+ int s;
+
+#ifdef DEBUG
+ enter_stats.managed++;
+#endif
+ pv = pa_to_pvh(pa);
+ s = splimp();
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: pv at %x: %x/%x/%x ",
+ pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
+#endif
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+#ifdef DEBUG
+ enter_stats.firstpv++;
+#endif
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ pv->pv_flags = 0;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ /*printf("second time: ");*/
+#ifdef DEBUG
+ for (npv = pv; npv; npv = npv->pv_next)
+ if (pmap == npv->pv_pmap && va == npv->pv_va)
+ panic("pmap_enter: already in pv_tab");
+#endif
+ npv = (pv_entry_t)
+ malloc(sizeof *npv, M_VMPVENT, M_NOWAIT);
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+#ifdef DEBUG
+ if (!npv->pv_next)
+ enter_stats.secondpv++;
+#endif
+ }
+ splx(s);
+ }
+ /*
+ * Assumption: if it is not part of our managed memory
+ * then it must be device memory which may be volitile.
+ */
+ if (pmap_initialized) {
+ checkpv = cacheable = FALSE;
+#ifdef DEBUG
+ enter_stats.unmanaged++;
+#endif
+ }
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+ if (wired)
+ pmap->pm_stats.wired_count++;
+
+validate:
+ /*
+ * Now validate mapping with desired protection/wiring.
+ * Assume uniform modified and referenced status for all
+ * I386 pages in a MACH page.
+ */
+ npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V;
+ npte |= (*(int *)pte & (PG_M|PG_U));
+ if (wired)
+ npte |= PG_W;
+ if(va < UPT_MIN_ADDRESS)
+ npte |= PG_u;
+ else if(va < UPT_MAX_ADDRESS)
+ npte |= PG_u | PG_RW;
+#ifdef DEBUG
+ if (pmapdebug & PDB_ENTER)
+ printf("enter: new pte value %x ", npte);
+#endif
+ ix = 0;
+ do {
+ *(int *)pte++ = npte;
+ /*TBIS(va);*/
+ npte += I386_PAGE_SIZE;
+ va += I386_PAGE_SIZE;
+ } while (++ix != i386pagesperpage);
+ pte--;
+#ifdef DEBUGx
+cache, tlb flushes
+#endif
+/*pads(pmap);*/
+ /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/
+ tlbflush();
+}
+
+/*
+ * pmap_page_protect:
+ *
+ * Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(phys, prot)
+ vm_offset_t phys;
+ vm_prot_t prot;
+{
+ switch (prot) {
+ case VM_PROT_READ:
+ case VM_PROT_READ|VM_PROT_EXECUTE:
+ pmap_copy_on_write(phys);
+ break;
+ case VM_PROT_ALL:
+ break;
+ default:
+ pmap_remove_all(phys);
+ break;
+ }
+}
+
+/*
+ * Routine: pmap_change_wiring
+ * Function: Change the wiring attribute for a map/virtual-address
+ * pair.
+ * In/out conditions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap, va, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired);
+#endif
+ if (pmap == NULL)
+ return;
+
+ pte = pmap_pte(pmap, va);
+#ifdef DEBUG
+ /*
+ * Page table page is not allocated.
+ * Should this ever happen? Ignore it for now,
+ * we don't want to force allocation of unnecessary PTE pages.
+ */
+ if (!pmap_pde_v(pmap_pde(pmap, va))) {
+ if (pmapdebug & PDB_PARANOIA)
+ pg("pmap_change_wiring: invalid PDE for %x ", va);
+ return;
+ }
+ /*
+ * Page not valid. Should this ever happen?
+ * Just continue and change wiring anyway.
+ */
+ if (!pmap_pte_v(pte)) {
+ if (pmapdebug & PDB_PARANOIA)
+ pg("pmap_change_wiring: invalid PTE for %x ", va);
+ }
+#endif
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ /*
+ * Wiring is not a hardware characteristic so there is no need
+ * to invalidate TLB.
+ */
+ ix = 0;
+ do {
+ pmap_pte_set_w(pte++, wired);
+ } while (++ix != i386pagesperpage);
+}
+
+/*
+ * Routine: pmap_pte
+ * Function:
+ * Extract the page table entry associated
+ * with the given map/virtual_address pair.
+ * [ what about induced faults -wfj]
+ */
+
+struct pte *pmap_pte(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_pte(%x, %x) ->\n", pmap, va);
+#endif
+ if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+
+ /* are we current address space or kernel? */
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
+ || pmap == kernel_pmap)
+ return ((struct pte *) vtopte(va));
+
+ /* otherwise, we are alternate address space */
+ else {
+ if (pmap->pm_pdir[PTDPTDI].pd_pfnum
+ != APTDpde.pd_pfnum) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ return((struct pte *) avtopte(va));
+ }
+ }
+ return(0);
+}
+
+/*
+ * Routine: pmap_extract
+ * Function:
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ */
+
+vm_offset_t
+pmap_extract(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+ register vm_offset_t pa;
+
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ pg("pmap_extract(%x, %x) -> ", pmap, va);
+#endif
+ pa = 0;
+ if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
+ pa = *(int *) pmap_pte(pmap, va);
+ }
+ if (pa)
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+#ifdef DEBUGx
+ if (pmapdebug & PDB_FOLLOW)
+ printf("%x\n", pa);
+#endif
+ return(pa);
+}
+
+/*
+ * Copy the range specified by src_addr/len
+ * from the source map to the range dst_addr/len
+ * in the destination map.
+ *
+ * This routine is only advisory and need not do anything.
+ */
+void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
+ pmap_t dst_pmap;
+ pmap_t src_pmap;
+ vm_offset_t dst_addr;
+ vm_size_t len;
+ vm_offset_t src_addr;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_copy(%x, %x, %x, %x, %x)",
+ dst_pmap, src_pmap, dst_addr, len, src_addr);
+#endif
+}
+
+/*
+ * Require that all active physical maps contain no
+ * incorrect entries NOW. [This update includes
+ * forcing updates of any address map caching.]
+ *
+ * Generally used to insure that a thread about
+ * to run will see a semantically correct world.
+ */
+void pmap_update()
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_update()");
+#endif
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_collect
+ * Function:
+ * Garbage collects the physical map system for
+ * pages which are no longer used.
+ * Success need not be guaranteed -- that is, there
+ * may well be pages which are not referenced, but
+ * others may be collected.
+ * Usage:
+ * Called by the pageout daemon when pages are scarce.
+ * [ needs to be written -wfj ]
+ */
+void
+pmap_collect(pmap)
+ pmap_t pmap;
+{
+ register vm_offset_t pa;
+ register pv_entry_t pv;
+ register int *pte;
+ vm_offset_t kpa;
+ int s;
+
+#ifdef DEBUG
+ int *pde;
+ int opmapdebug;
+ printf("pmap_collect(%x) ", pmap);
+#endif
+ if (pmap != kernel_pmap)
+ return;
+
+}
+
+/* [ macro again?, should I force kstack into user map here? -wfj ] */
+void
+pmap_activate(pmap, pcbp)
+ register pmap_t pmap;
+ struct pcb *pcbp;
+{
+int x;
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB))
+ pg("pmap_activate(%x, %x) ", pmap, pcbp);
+#endif
+ PMAP_ACTIVATE(pmap, pcbp);
+/*printf("pde ");
+for(x=0x3f6; x < 0x3fA; x++)
+ printf("%x ", pmap->pm_pdir[x]);*/
+/*pads(pmap);*/
+/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/
+}
+
+/*
+ * Routine: pmap_kernel
+ * Function:
+ * Returns the physical map handle for the kernel.
+ */
+pmap_t
+pmap_kernel()
+{
+ return (kernel_pmap);
+}
+
+/*
+ * pmap_zero_page zeros the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bzero to clear its contents, one machine dependent page
+ * at a time.
+ */
+pmap_zero_page(phys)
+ register vm_offset_t phys;
+{
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_zero_page(%x)", phys);
+#endif
+ phys >>= PG_SHIFT;
+ ix = 0;
+ do {
+ clearseg(phys++);
+ } while (++ix != i386pagesperpage);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bcopy to copy the page, one machine dependent page at a
+ * time.
+ */
+pmap_copy_page(src, dst)
+ register vm_offset_t src, dst;
+{
+ register int ix;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_copy_page(%x, %x)", src, dst);
+#endif
+ src >>= PG_SHIFT;
+ dst >>= PG_SHIFT;
+ ix = 0;
+ do {
+ physcopyseg(src++, dst++);
+ } while (++ix != i386pagesperpage);
+}
+
+
+/*
+ * Routine: pmap_pageable
+ * Function:
+ * Make the specified pages (by pmap, offset)
+ * pageable (or not) as requested.
+ *
+ * A page which is not pageable may not take
+ * a fault; therefore, its page table entry
+ * must remain valid for the duration.
+ *
+ * This routine is merely advisory; pmap_enter
+ * will specify that these pages are to be wired
+ * down (or not) as appropriate.
+ */
+pmap_pageable(pmap, sva, eva, pageable)
+ pmap_t pmap;
+ vm_offset_t sva, eva;
+ boolean_t pageable;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_pageable(%x, %x, %x, %x)",
+ pmap, sva, eva, pageable);
+#endif
+ /*
+ * If we are making a PT page pageable then all valid
+ * mappings must be gone from that page. Hence it should
+ * be all zeros and there is no need to clean it.
+ * Assumptions:
+ * - we are called with only one page at a time
+ * - PT pages have only one pv_table entry
+ */
+ if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) {
+ register pv_entry_t pv;
+ register vm_offset_t pa;
+
+#ifdef DEBUG
+ if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE)
+ printf("pmap_pageable(%x, %x, %x, %x)",
+ pmap, sva, eva, pageable);
+#endif
+ /*if (!pmap_pde_v(pmap_pde(pmap, sva)))
+ return;*/
+ if(pmap_pte(pmap, sva) == 0)
+ return;
+ pa = pmap_pte_pa(pmap_pte(pmap, sva));
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+ pv = pa_to_pvh(pa);
+ /*if (!ispt(pv->pv_va))
+ return;*/
+#ifdef DEBUG
+ if (pv->pv_va != sva || pv->pv_next) {
+ pg("pmap_pageable: bad PT page va %x next %x\n",
+ pv->pv_va, pv->pv_next);
+ return;
+ }
+#endif
+ /*
+ * Mark it unmodified to avoid pageout
+ */
+ pmap_clear_modify(pa);
+#ifdef needsomethinglikethis
+ if (pmapdebug & PDB_PTPAGE)
+ pg("pmap_pageable: PT page %x(%x) unmodified\n",
+ sva, *(int *)pmap_pte(pmap, sva));
+ if (pmapdebug & PDB_WIRING)
+ pmap_check_wiring("pageable", sva);
+#endif
+ }
+}
+
+/*
+ * Clear the modify bits on the specified physical page.
+ */
+
+void
+pmap_clear_modify(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_clear_modify(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_M, FALSE);
+}
+
+/*
+ * pmap_clear_reference:
+ *
+ * Clear the reference bit on the specified physical page.
+ */
+
+void pmap_clear_reference(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW)
+ printf("pmap_clear_reference(%x)", pa);
+#endif
+ pmap_changebit(pa, PG_U, FALSE);
+}
+
+/*
+ * pmap_is_referenced:
+ *
+ * Return whether or not the specified physical page is referenced
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_referenced(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW) {
+ boolean_t rv = pmap_testbit(pa, PG_U);
+ printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]);
+ return(rv);
+ }
+#endif
+ return(pmap_testbit(pa, PG_U));
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Return whether or not the specified physical page is modified
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_modified(pa)
+ vm_offset_t pa;
+{
+#ifdef DEBUG
+ if (pmapdebug & PDB_FOLLOW) {
+ boolean_t rv = pmap_testbit(pa, PG_M);
+ printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]);
+ return(rv);
+ }
+#endif
+ return(pmap_testbit(pa, PG_M));
+}
+
+vm_offset_t
+pmap_phys_address(ppn)
+ int ppn;
+{
+ return(i386_ptob(ppn));
+}
+
+/*
+ * Miscellaneous support routines follow
+ */
+
+i386_protection_init()
+{
+ register int *kp, prot;
+
+ kp = protection_codes;
+ for (prot = 0; prot < 8; prot++) {
+ switch (prot) {
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
+ *kp++ = 0;
+ break;
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
+ *kp++ = PG_RO;
+ break;
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ *kp++ = PG_RW;
+ break;
+ }
+ }
+}
+
+boolean_t
+pmap_testbit(pa, bit)
+ register vm_offset_t pa;
+ int bit;
+{
+ register pv_entry_t pv;
+ register int *pte, ix;
+ int s;
+
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return(FALSE);
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Check saved info first
+ */
+ if (pmap_attributes[pa_index(pa)] & bit) {
+ splx(s);
+ return(TRUE);
+ }
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va);
+ ix = 0;
+ do {
+ if (*pte++ & bit) {
+ splx(s);
+ return(TRUE);
+ }
+ } while (++ix != i386pagesperpage);
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+pmap_changebit(pa, bit, setem)
+ register vm_offset_t pa;
+ int bit;
+ boolean_t setem;
+{
+ register pv_entry_t pv;
+ register int *pte, npte, ix;
+ vm_offset_t va;
+ int s;
+ boolean_t firstpage = TRUE;
+
+#ifdef DEBUG
+ if (pmapdebug & PDB_BITS)
+ printf("pmap_changebit(%x, %x, %s)",
+ pa, bit, setem ? "set" : "clear");
+#endif
+ if (pa < vm_first_phys || pa >= vm_last_phys)
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * Clear saved attributes (modify, reference)
+ */
+ if (!setem)
+ pmap_attributes[pa_index(pa)] &= ~bit;
+ /*
+ * Loop over all current mappings setting/clearing as appropos
+ * If setting RO do we need to clear the VAC?
+ */
+ if (pv->pv_pmap != NULL) {
+#ifdef DEBUG
+ int toflush = 0;
+#endif
+ for (; pv; pv = pv->pv_next) {
+#ifdef DEBUG
+ toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1;
+#endif
+ va = pv->pv_va;
+
+ /*
+ * XXX don't write protect pager mappings
+ */
+ if (bit == PG_RO) {
+ extern vm_offset_t pager_sva, pager_eva;
+
+ if (va >= pager_sva && va < pager_eva)
+ continue;
+ }
+
+ pte = (int *) pmap_pte(pv->pv_pmap, va);
+ ix = 0;
+ do {
+ if (setem)
+ npte = *pte | bit;
+ else
+ npte = *pte & ~bit;
+ if (*pte != npte) {
+ *pte = npte;
+ /*TBIS(va);*/
+ }
+ va += I386_PAGE_SIZE;
+ pte++;
+ } while (++ix != i386pagesperpage);
+
+ if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap)
+ pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr);
+ }
+#ifdef somethinglikethis
+ if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) {
+ if ((pmapvacflush & PVF_TOTAL) || toflush == 3)
+ DCIA();
+ else if (toflush == 2)
+ DCIS();
+ else
+ DCIU();
+ }
+#endif
+ }
+ splx(s);
+}
+
+#ifdef DEBUG
+pmap_pvdump(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+
+ printf("pa %x", pa);
+ for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
+ printf(" -> pmap %x, va %x, flags %x",
+ pv->pv_pmap, pv->pv_va, pv->pv_flags);
+ pads(pv->pv_pmap);
+ }
+ printf(" ");
+}
+
+#ifdef notyet
+pmap_check_wiring(str, va)
+ char *str;
+ vm_offset_t va;
+{
+ vm_map_entry_t entry;
+ register int count, *pte;
+
+ va = trunc_page(va);
+ if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) ||
+ !pmap_pte_v(pmap_pte(kernel_pmap, va)))
+ return;
+
+ if (!vm_map_lookup_entry(pt_map, va, &entry)) {
+ pg("wired_check: entry for %x not found\n", va);
+ return;
+ }
+ count = 0;
+ for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++)
+ if (*pte)
+ count++;
+ if (entry->wired_count != count)
+ pg("*%s*: %x: w%d/a%d\n",
+ str, va, entry->wired_count, count);
+}
+#endif
+
+/* print address space of pmap*/
+pads(pm) pmap_t pm; {
+ unsigned va, i, j;
+ struct pte *ptep;
+
+ if(pm == kernel_pmap) return;
+ for (i = 0; i < 1024; i++)
+ if(pm->pm_pdir[i].pd_v)
+ for (j = 0; j < 1024 ; j++) {
+ va = (i<<22)+(j<<12);
+ if (pm == kernel_pmap && va < 0xfe000000)
+ continue;
+ if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
+ continue;
+ ptep = pmap_pte(pm, va);
+ if(pmap_pte_v(ptep))
+ printf("%x:%x ", va, *(int *)ptep);
+ } ;
+
+}
+#endif
diff --git a/sys/i386/i386/swapgeneric.c b/sys/i386/i386/swapgeneric.c
new file mode 100644
index 0000000..0d76e72
--- /dev/null
+++ b/sys/i386/i386/swapgeneric.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)swapgeneric.c 5.5 (Berkeley) 5/9/91
+ */
+
+#include "machine/pte.h"
+
+#include "sys/param.h"
+#include "sys/conf.h"
+#include "sys/buf.h"
+#include "sys/vm.h"
+#include "sys/systm.h"
+#include "sys/reboot.h"
+
+/*
+ * Generic configuration; all in one
+ */
+dev_t rootdev = makedev(0,0);
+dev_t dumpdev = makedev(0,1);
+int nswap;
+struct swdevt swdevt[] = {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+};
+long dumplo;
+int dmmin, dmmax, dmtext;
+
+extern struct driver wddriver;
+
+struct genericconf {
+ caddr_t gc_driver;
+ char *gc_name;
+ dev_t gc_root;
+} genericconf[] = {
+ { (caddr_t)&wddriver, "wd", makedev(0, 0), },
+ { 0 },
+};
+
+setconf()
+{
+#ifdef notdef
+ register struct genericconf *gc;
+ int unit, swaponroot = 0;
+
+ if (rootdev != NODEV)
+ goto doswap;
+ if (boothowto & RB_ASKNAME) {
+ char name[128];
+retry:
+ printf("root device? ");
+ gets(name);
+ for (gc = genericconf; gc->gc_driver; gc++)
+ if (gc->gc_name[0] == name[0] &&
+ gc->gc_name[1] == name[1])
+ goto gotit;
+ goto bad;
+gotit:
+ if (name[3] == '*') {
+ name[3] = name[4];
+ swaponroot++;
+ }
+ if (name[2] >= '0' && name[2] <= '7' && name[3] == 0) {
+ unit = name[2] - '0';
+ goto found;
+ }
+ printf("bad/missing unit number\n");
+bad:
+ printf("use dk%%d\n");
+ goto retry;
+ }
+ unit = 0;
+ for (gc = genericconf; gc->gc_driver; gc++) {
+ for (ui = vbdinit; ui->ui_driver; ui++) {
+ if (ui->ui_alive == 0)
+ continue;
+ if (ui->ui_unit == 0 && ui->ui_driver ==
+ (struct vba_driver *)gc->gc_driver) {
+ printf("root on %s0\n",
+ ui->ui_driver->ud_dname);
+ goto found;
+ }
+ }
+ }
+ printf("no suitable root\n");
+ asm("halt");
+found:
+ gc->gc_root = makedev(major(gc->gc_root), unit*8);
+ rootdev = gc->gc_root;
+doswap:
+ swdevt[0].sw_dev = argdev = dumpdev =
+ makedev(major(rootdev), minor(rootdev)+1);
+ /* swap size and dumplo set during autoconfigure */
+ if (swaponroot)
+ rootdev = dumpdev;
+#endif
+}
+
+gets(cp)
+ char *cp;
+{
+ register char *lp;
+ register c;
+
+ lp = cp;
+ for (;;) {
+ printf("%c", c = cngetc()&0177);
+ switch (c) {
+ case '\n':
+ case '\r':
+ *lp++ = '\0';
+ return;
+ case '\b':
+ case '\177':
+ if (lp > cp) {
+ printf(" \b");
+ lp--;
+ }
+ continue;
+ case '#':
+ lp--;
+ if (lp < cp)
+ lp = cp;
+ continue;
+ case '@':
+ case 'u'&037:
+ lp = cp;
+ printf("%c", '\n');
+ continue;
+ default:
+ *lp++ = c;
+ }
+ }
+}
diff --git a/sys/i386/i386/symbols.raw b/sys/i386/i386/symbols.raw
new file mode 100644
index 0000000..56e5ab4
--- /dev/null
+++ b/sys/i386/i386/symbols.raw
@@ -0,0 +1,89 @@
+# @(#)symbols.raw 7.6 (Berkeley) 5/8/91
+#
+# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+# -------------------- ----- ----------------------
+# CURRENT PATCH LEVEL: 1 00066
+# -------------------- ----- ----------------------
+#
+# 28 Nov 1991 Warren Toomey Let symorder -t keep some needed
+# symbols used by common programs
+#
+
+
+#gdb
+ _IdlePTD
+ _PTD
+ _curpcb
+ _kstack
+ _panicstr
+ _atdevbase
+# _version
+#dmesg
+ _msgbufp
+# _msgbuf
+#iostat
+ _dk_busy
+ _dk_time
+ _dk_xfer
+ _dk_wds
+ _tk_nin
+ _tk_nout
+ _dk_seek
+ _cp_time
+ _dk_wpms
+# _io_info
+#ps
+ _nswap
+ _maxslp
+ _ccpu
+ _fscale
+ _avail_start
+ _avail_end
+#pstat
+# _cons
+ _nswap
+ _swapmap
+#vmstat
+ _cp_time
+ _rate
+ _total
+ _sum
+# _rectime
+# _pgintime
+ _dk_xfer
+ _boottime
+#w
+ _swapdev
+ _nswap
+ _averunnable
+ _boottime
+#netstat
+ _mbstat
+ _ipstat
+ _tcb
+ _tcpstat
+ _udb
+ _udpstat
+ _rawcb
+ _Sysmap
+ _ifnet
+ _rthost
+ _rtnet
+ _icmpstat
+ _filehead
+ _nfiles
+ _rthashsize
+#routed
+ _ifnet
+#rwho
+ _boottime
+#savecore
+ _dumpdev
+ _dumplo
+ _version
+ _time
+ _dumpsize
+ _panicstr
+ _dumpmag
+#deprecated
+# _avenrun
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
new file mode 100644
index 0000000..10b9ac2
--- /dev/null
+++ b/sys/i386/i386/sys_machdep.c
@@ -0,0 +1,105 @@
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "file.h"
+#include "time.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "mtio.h"
+#include "buf.h"
+#include "trace.h"
+
+#ifdef TRACE
+int nvualarm;
+
+vtrace(p, uap, retval)
+ struct proc *p;
+ register struct args {
+ int request;
+ int value;
+ } *uap;
+ int *retval;
+{
+ int vdoualarm();
+
+ switch (uap->request) {
+
+ case VTR_DISABLE: /* disable a trace point */
+ case VTR_ENABLE: /* enable a trace point */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ traceflags[uap->value] = uap->request;
+ break;
+
+ case VTR_VALUE: /* return a trace point setting */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ break;
+
+ case VTR_UALARM: /* set a real-time ualarm, less than 1 min */
+ if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+ return (EINVAL);
+ nvualarm++;
+ timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+ break;
+
+ case VTR_STAMP:
+ trace(TR_STAMP, uap->value, p->p_pid);
+ break;
+ }
+ return (0);
+}
+
+vdoualarm(arg)
+ int arg;
+{
+ register struct proc *p;
+
+ p = pfind(arg);
+ if (p)
+ psignal(p, 16);
+ nvualarm--;
+}
+#endif
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
new file mode 100644
index 0000000..57195f3
--- /dev/null
+++ b/sys/i386/i386/trap.c
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.c 7.4 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00137
+ * -------------------- ----- ----------------------
+ *
+ * 08 Apr 93 Bruce Evans Several VM system fixes
+ * Paul Kranenburg Add counter for vmstat
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $";
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+
+struct sysent sysent[];
+int nsysent;
+int dostacklimits;
+unsigned rcr2();
+extern short cpl;
+
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#include "ddb.h"
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, rcr2(), frame.tf_esp);*/
+if(curpcb == 0 || curproc == 0) goto we_re_toast;
+ if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) {
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+ }
+
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+ switch (type) {
+
+ default:
+ we_re_toast:
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+
+ printf("trap type %d code = %x eip = %x cs = %x eflags = %x ",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, frame.tf_eflags);
+ eva = rcr2();
+ printf("cr2 %x cpl %x\n", eva, cpl);
+ /* type &= ~T_USER; */ /* XXX what the hell is this */
+ panic("trap");
+ /*NOTREACHED*/
+
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#ifdef NPX
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif
+ i = math_emulate(&frame);
+ if (i == 0) return;
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+#if 0
+ /* XXX - check only applies to 386's and 486's with WP off */
+ if (code & PGEX_P) goto we_re_toast;
+#endif
+
+ /* fall into */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ register vm_offset_t va;
+ register struct vmspace *vm = p->p_vmspace;
+ register vm_map_t map;
+ int rv;
+ vm_prot_t ftype;
+ extern vm_map_t kernel_map;
+ unsigned nss,v;
+
+ va = trunc_page((vm_offset_t)eva);
+ /*
+ * Avoid even looking at pde_v(va) for high va's. va's
+ * above VM_MAX_KERNEL_ADDRESS don't correspond to normal
+ * PDE's (half of them correspond to APDEpde and half to
+ * an unmapped kernel PDE). va's betweeen 0xFEC00000 and
+ * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's
+ * (XXX - why are only 3 initialized when 6 are required to
+ * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped
+ * kernel page table would give inconsistent PTD's.
+ *
+ * XXX - faulting in unmapped page tables wastes a page if
+ * va turns out to be invalid.
+ *
+ * XXX - should "kernel address space" cover the kernel page
+ * tables? Might have same problem with PDEpde as with
+ * APDEpde (or there may be no problem with APDEpde).
+ */
+ if (va > 0xFEBFF000) {
+ rv = KERN_FAILURE; /* becomes SIGBUS */
+ goto nogo;
+ }
+ /*
+ * It is only a kernel address space fault iff:
+ * 1. (type & T_USER) == 0 and
+ * 2. pcb_onfault not set or
+ * 3. pcb_onfault set but supervisor space fault
+ * The last can occur during an exec() copyin where the
+ * argument space is lazy-allocated.
+ */
+ if (type == T_PAGEFLT && va >= KERNBASE)
+ map = kernel_map;
+ else
+ map = &vm->vm_map;
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+#ifdef DEBUG
+ if (map == kernel_map && va == 0) {
+ printf("trap: bad kernel access at %x\n", va);
+ goto we_re_toast;
+ }
+#endif
+
+ /*
+ * XXX: rude hack to make stack limits "work"
+ */
+ nss = 0;
+ if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map
+ && dostacklimits) {
+ nss = clrnd(btoc((unsigned)vm->vm_maxsaddr
+ + MAXSSIZ - (unsigned)va));
+ if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
+/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/
+ rv = KERN_FAILURE;
+ goto nogo;
+ }
+ }
+
+ /* check if page table is mapped, if not, fault it first */
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+ if (!pde_v(va)) {
+ v = trunc_page(vtopte(va));
+ rv = vm_fault(map, v, ftype, FALSE);
+ if (rv != KERN_SUCCESS) goto nogo;
+ /* check if page table fault, increment wiring */
+ vm_map_pageable(map, v, round_page(v+1), FALSE);
+ } else v=0;
+ rv = vm_fault(map, va, ftype, FALSE);
+ if (rv == KERN_SUCCESS) {
+ /*
+ * XXX: continuation of rude stack hack
+ */
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ va = trunc_page(vtopte(va));
+ /* for page table, increment wiring
+ as long as not a page table fault as well */
+ if (!v && type != T_PAGEFLT)
+ vm_map_pageable(map, va, round_page(va+1), FALSE);
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+ printf("vm_fault(%x, %x, %x, 0) -> %x\n",
+ map, va, ftype, rv);
+ printf(" type %x, code %x\n",
+ type, code);
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#include "isa.h"
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if(isa_nmi(code) == 0) return;
+ else goto we_re_toast;
+#endif
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR)
+ */
+int trapwrite(unsigned addr) {
+ int rv;
+ vm_offset_t va;
+
+ va = trunc_page((vm_offset_t)addr);
+ if (va > VM_MAXUSER_ADDRESS) return(1);
+ rv = vm_fault(&curproc->p_vmspace->vm_map, va,
+ VM_PROT_READ | VM_PROT_WRITE, FALSE);
+ if (rv == KERN_SUCCESS) return(0);
+ else return(1);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+syscall(frame)
+ volatile struct syscframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.sf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.sf_eax;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.sf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.sf_eip - 7;
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ if (callp == sysent) {
+ i = fuword(params);
+ params += sizeof (int);
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ }
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.sf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.sf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.sf_eax = rval[0];
+ frame.sf_edx = rval[1];
+ frame.sf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.sf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.sf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.sf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.sf_ss, code);
+ if ((frame.sf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.sf_cs, code);
+ if (frame.sf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.sf_eip, code);
+ frame.sf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c
new file mode 100644
index 0000000..0fb7701
--- /dev/null
+++ b/sys/i386/i386/tsc.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 14 Aug 92 Arne Henrik Juul Added code in the kernel to
+ * allow for DST in the BIOS.
+ * 17 Jan 93 Bruce Evans Fixed leap year and second
+ * calculations
+ * 01 Feb 93 Julian Elischer Added code to for the cpu
+ * speed independent spinwait()
+ * function, (used by scsi and others)
+ * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1
+ * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock
+ * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait
+ * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I
+ * still kept the other fixes... Had to
+ * add back in findcpuspeed that Bruce
+ * had removed.
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+#define DAYST 119
+#define DAYEN 303
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+
+startrtclock() {
+ int s;
+
+ findcpuspeed(); /* use the clock (while it's free)
+ to find the cpu speed */
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
+ outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+ outb (IO_RTC, RTC_DIAG);
+ outb (IO_RTC+1, 0);
+}
+
+unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
+
+#define FIRST_GUESS 0x2000
+findcpuspeed()
+{
+ unsigned char low;
+ unsigned int remainder;
+
+ /* Put counter in count down mode */
+ outb(IO_TIMER1+3, 0x34);
+ outb(IO_TIMER1, 0xff);
+ outb(IO_TIMER1, 0xff);
+ delaycount = FIRST_GUESS;
+ spinwait(1);
+ /* Read the value left in the counter */
+ low = inb(IO_TIMER1); /* least siginifcant */
+ remainder = inb(IO_TIMER1); /* most significant */
+ remainder = (remainder<<8) + low ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ */
+ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
+}
+
+
+/* convert 2 digit BCD number */
+bcd(i)
+int i;
+{
+ return ((i/16)*10 + (i%16));
+}
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(y)
+int y;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+/* convert months to seconds */
+unsigned long
+mtos(m,leap)
+int m,leap;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1;i<m;i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+inittodr(base)
+ time_t base;
+{
+ unsigned long sec;
+ int leap,day_week,t,yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+
+ /* XXX off by one? Need to calculate DST on SUNDAY */
+ /* Perhaps we should have the RTC hold GMT time to save */
+ /* us the bother of converting. */
+ yd = yd / (24*60*60);
+ if ((yd >= DAYST) && ( yd <= DAYEN)) {
+ sec -= 60*60;
+ }
+ sec += tz.tz_minuteswest * 60;
+
+ time.tv_sec = sec;
+}
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(base)
+ time_t base;
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Restart the clock.
+ */
+resettodr()
+{
+}
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern V(clk)();
+enablertclock() {
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(millisecs)
+ int millisecs;
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
new file mode 100644
index 0000000..27ef912
--- /dev/null
+++ b/sys/i386/i386/vm_machdep.c
@@ -0,0 +1,410 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/vm_machdep.c,v 1.2 92/01/21 14:22:17 william Exp $";
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "user.h"
+
+#include "../include/cpu.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+cpu_fork(p1, p2)
+ register struct proc *p1, *p2;
+{
+ register struct user *up = p2->p_addr;
+ int foo, offset, addr, i;
+ extern char kstack[];
+ extern int mvesp();
+
+ /*
+ * Copy pcb and stack from proc p1 to p2.
+ * We do this as cheaply as possible, copying only the active
+ * part of the stack. The stack and pcb need to agree;
+ * this is tricky, as the final pcb is constructed by savectx,
+ * but its frame isn't yet on the stack when the stack is copied.
+ * swtch compensates for this when the child eventually runs.
+ * This should be done differently, with a single call
+ * that copies and updates the pcb+stack,
+ * replacing the bcopy and savectx.
+ */
+ p2->p_addr->u_pcb = p1->p_addr->u_pcb;
+ offset = mvesp() - (int)kstack;
+ bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
+ (unsigned) ctob(UPAGES) - offset);
+ p2->p_regs = p1->p_regs;
+
+ /*
+ * Wire top of address space of child to it's kstack.
+ * First, fault in a page of pte's to map it.
+ */
+ addr = trunc_page((u_int)vtopte(kstack));
+ vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
+ for (i=0; i < UPAGES; i++)
+ pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
+ pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG), VM_PROT_READ, 1);
+
+ pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
+
+ /*
+ *
+ * Arrange for a non-local goto when the new process
+ * is started, to resume here, returning nonzero from setjmp.
+ */
+ if (savectx(up, 1)) {
+ /*
+ * Return 1 in child.
+ */
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef notyet
+/*
+ * cpu_exit is called as the last action during exit.
+ *
+ * We change to an inactive address space and a "safe" stack,
+ * passing thru an argument to the new stack. Now, safely isolated
+ * from the resources we're shedding, we release the address space
+ * and any remaining machine-dependent resources, including the
+ * memory for the user structure and kernel stack.
+ *
+ * Next, we assign a dummy context to be written over by swtch,
+ * calling it to send this process off to oblivion.
+ * [The nullpcb allows us to minimize cost in swtch() by not having
+ * a special case].
+ */
+struct proc *swtch_to_inactive();
+cpu_exit(p)
+ register struct proc *p;
+{
+ static struct pcb nullpcb; /* pcb to overwrite on last swtch */
+
+#ifdef NPX
+ npxexit(p);
+#endif
+
+ /* move to inactive space and stack, passing arg accross */
+ p = swtch_to_inactive(p);
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+
+ p->p_addr = (struct user *) &nullpcb;
+ splclock();
+ swtch();
+ /* NOTREACHED */
+}
+#else
+cpu_exit(p)
+ register struct proc *p;
+{
+
+#ifdef NPX
+ npxexit(p);
+#endif
+ splclock();
+ swtch();
+}
+
+cpu_wait(p) struct proc *p; {
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+}
+#endif
+
+/*
+ * Set a red zone in the kernel stack after the u. area.
+ */
+setredzone(pte, vaddr)
+ u_short *pte;
+ caddr_t vaddr;
+{
+/* eventually do this by setting up an expand-down stack segment
+ for ss0: selector, allowing stack access down to top of u.
+ this means though that protection violations need to be handled
+ thru a double fault exception that must do an integral task
+ switch to a known good context, within which a dump can be
+ taken. a sensible scheme might be to save the initial context
+ used by sched (that has physical memory mapped 1:1 at bottom)
+ and take the dump while still in mapped mode */
+}
+
+/*
+ * Move pages from one kernel virtual address to another.
+ * Both addresses are assumed to reside in the Sysmap,
+ * and size must be a multiple of CLSIZE.
+ */
+pagemove(from, to, size)
+ register caddr_t from, to;
+ int size;
+{
+ register struct pte *fpte, *tpte;
+
+ if (size % CLBYTES)
+ panic("pagemove");
+ fpte = kvtopte(from);
+ tpte = kvtopte(to);
+ while (size > 0) {
+ *tpte++ = *fpte;
+ *(int *)fpte++ = 0;
+ from += NBPG;
+ to += NBPG;
+ size -= NBPG;
+ }
+ tlbflush();
+}
+
+/*
+ * Convert kernel VA to physical address
+ */
+kvtop(addr)
+ register caddr_t addr;
+{
+ vm_offset_t va;
+
+ va = pmap_extract(kernel_pmap, (vm_offset_t)addr);
+ if (va == 0)
+ panic("kvtop: zero page frame");
+ return((int)va);
+}
+
+#ifdef notdef
+/*
+ * The probe[rw] routines should probably be redone in assembler
+ * for efficiency.
+ */
+prober(addr)
+ register u_int addr;
+{
+ register int page;
+ register struct proc *p;
+
+ if (addr >= USRSTACK)
+ return(0);
+ p = u.u_procp;
+ page = btop(addr);
+ if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
+ return(1);
+ return(0);
+}
+
+probew(addr)
+ register u_int addr;
+{
+ register int page;
+ register struct proc *p;
+
+ if (addr >= USRSTACK)
+ return(0);
+ p = u.u_procp;
+ page = btop(addr);
+ if (page < dptov(p, p->p_dsize) || page > sptov(p, p->p_ssize))
+ return((*(int *)vtopte(p, page) & PG_PROT) == PG_UW);
+ return(0);
+}
+
+/*
+ * NB: assumes a physically contiguous kernel page table
+ * (makes life a LOT simpler).
+ */
+kernacc(addr, count, rw)
+ register u_int addr;
+ int count, rw;
+{
+ register struct pde *pde;
+ register struct pte *pte;
+ register int ix, cnt;
+ extern long Syssize;
+
+ if (count <= 0)
+ return(0);
+ pde = (struct pde *)((u_int)u.u_procp->p_p0br + u.u_procp->p_szpt * NBPG);
+ ix = (addr & PD_MASK) >> PD_SHIFT;
+ cnt = ((addr + count + (1 << PD_SHIFT) - 1) & PD_MASK) >> PD_SHIFT;
+ cnt -= ix;
+ for (pde += ix; cnt; cnt--, pde++)
+ if (pde->pd_v == 0)
+ return(0);
+ ix = btop(addr-0xfe000000);
+ cnt = btop(addr-0xfe000000+count+NBPG-1);
+ if (cnt > (int)&Syssize)
+ return(0);
+ cnt -= ix;
+ for (pte = &Sysmap[ix]; cnt; cnt--, pte++)
+ if (pte->pg_v == 0 /*|| (rw == B_WRITE && pte->pg_prot == 1)*/)
+ return(0);
+ return(1);
+}
+
+useracc(addr, count, rw)
+ register u_int addr;
+ int count, rw;
+{
+ register int (*func)();
+ register u_int addr2;
+ extern int prober(), probew();
+
+ if (count <= 0)
+ return(0);
+ addr2 = addr;
+ addr += count;
+ func = (rw == B_READ) ? prober : probew;
+ do {
+ if ((*func)(addr2) == 0)
+ return(0);
+ addr2 = (addr2 + NBPG) & ~PGOFSET;
+ } while (addr2 < addr);
+ return(1);
+}
+#endif
+
+extern vm_map_t phys_map;
+
+/*
+ * Map an IO request into kernel virtual address space. Requests fall into
+ * one of five catagories:
+ *
+ * B_PHYS|B_UAREA: User u-area swap.
+ * Address is relative to start of u-area (p_addr).
+ * B_PHYS|B_PAGET: User page table swap.
+ * Address is a kernel VA in usrpt (Usrptmap).
+ * B_PHYS|B_DIRTY: Dirty page push.
+ * Address is a VA in proc2's address space.
+ * B_PHYS|B_PGIN: Kernel pagein of user pages.
+ * Address is VA in user's address space.
+ * B_PHYS: User "raw" IO request.
+ * Address is VA in user's address space.
+ *
+ * All requests are (re)mapped into kernel VA space via the useriomap
+ * (a name with only slightly more meaning than "kernelmap")
+ */
+vmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr;
+ register long flags = bp->b_flags;
+ struct proc *p;
+ int off;
+ vm_offset_t kva;
+ register vm_offset_t pa;
+
+ if ((flags & B_PHYS) == 0)
+ panic("vmapbuf");
+ addr = bp->b_saveaddr = bp->b_un.b_addr;
+ off = (int)addr & PGOFSET;
+ p = bp->b_proc;
+ npf = btoc(round_page(bp->b_bcount + off));
+ kva = kmem_alloc_wait(phys_map, ctob(npf));
+ bp->b_un.b_addr = (caddr_t) (kva + off);
+ while (npf--) {
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
+ if (pa == 0)
+ panic("vmapbuf: null page frame");
+ pmap_enter(vm_map_pmap(phys_map), kva, trunc_page(pa),
+ VM_PROT_READ|VM_PROT_WRITE, TRUE);
+ addr += PAGE_SIZE;
+ kva += PAGE_SIZE;
+ }
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also invalidate the TLB entries and restore the original b_addr.
+ */
+vunmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr = bp->b_un.b_addr;
+ vm_offset_t kva;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+ npf = btoc(round_page(bp->b_bcount + ((int)addr & PGOFSET)));
+ kva = (vm_offset_t)((int)addr & ~PGOFSET);
+ kmem_free_wakeup(phys_map, kva, ctob(npf));
+ bp->b_un.b_addr = bp->b_saveaddr;
+ bp->b_saveaddr = NULL;
+}
+
+/*
+ * Force reset the processor by invalidating the entire address space!
+ */
+cpu_reset() {
+
+ /* force a shutdown by unmapping entire address space ! */
+ bzero((caddr_t) PTD, NBPG);
+
+ /* "good night, sweet prince .... <THUNK!>" */
+ tlbflush();
+ /* NOTREACHED */
+}
diff --git a/sys/i386/include/_limits.h b/sys/i386/include/_limits.h
new file mode 100644
index 0000000..73474608
--- /dev/null
+++ b/sys/i386/include/_limits.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define CLK_TCK 60 /* ticks per second */
+#define MB_LEN_MAX 1 /* no multibyte characters */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
diff --git a/sys/i386/include/ansi.h b/sys/i386/include/ansi.h
new file mode 100644
index 0000000..ca67748
--- /dev/null
+++ b/sys/i386/include/ansi.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ansi.h 7.1 (Berkeley) 3/9/91
+ */
+
+#ifndef _ANSI_H_
+#define _ANSI_H_
+
+/*
+ * Types which are fundamental to the implementation and may appear in
+ * more than one standard header are defined here. Standard headers
+ * then use:
+ * #ifdef _SIZE_T_
+ * typedef _SIZE_T_ size_t;
+ * #undef _SIZE_T_
+ * #endif
+ *
+ * Thanks, ANSI!
+ */
+#define _CLOCK_T_ unsigned long /* clock() */
+#define _PTRDIFF_T_ int /* ptr1 - ptr2 */
+#define _SIZE_T_ unsigned int /* sizeof() */
+#define _TIME_T_ long /* time() */
+#define _VA_LIST_ char * /* va_list */
+#define _WCHAR_T_ unsigned short /* wchar_t */
+
+#endif /* _ANSI_H_ */
diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h
new file mode 100644
index 0000000..583d76c
--- /dev/null
+++ b/sys/i386/include/cpu.h
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cpu.h 5.4 (Berkeley) 5/9/91
+ */
+
+/*
+ * Definitions unique to i386 cpu support.
+ */
+#include "machine/frame.h"
+#include "machine/segments.h"
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */
+
+/*
+ * function vs. inline configuration;
+ * these are defined to get generic functions
+ * rather than inline or machine-dependent implementations
+ */
+#define NEED_MINMAX /* need {,i,l,ul}{min,max} functions */
+#define NEED_FFS /* need ffs function */
+#define NEED_BCMP /* need bcmp function */
+#define NEED_STRLEN /* need strlen function */
+
+#define cpu_exec(p) /* nothing */
+
+/*
+ * Arguments to hardclock, softclock and gatherstats
+ * encapsulate the previous machine state in an opaque
+ * clockframe; for now, use generic intrframe.
+ */
+typedef struct intrframe clockframe;
+
+#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL)
+#define CLKF_BASEPRI(framep) ((framep)->if_ppl == 0)
+#define CLKF_PC(framep) ((framep)->if_eip)
+
+#define resettodr() /* no todr to set */
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+#define need_resched() { want_resched++; aston(); }
+
+/*
+ * Give a profiling tick to the current process from the softclock
+ * interrupt. On tahoe, request an ast to send us through trap(),
+ * marking the proc as needing a profiling tick.
+ */
+#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); }
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+#define signotify(p) aston()
+
+#define aston() (astpending++)
+
+int astpending; /* need to trap before returning to user mode */
+int want_resched; /* resched() was called */
+
+/*
+ * Kinds of processor
+ */
+
+#define CPU_386SX 0
+#define CPU_386 1
+#define CPU_486SX 2
+#define CPU_486 3
+#define CPU_586 4
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
new file mode 100644
index 0000000..e3b4a8c
--- /dev/null
+++ b/sys/i386/include/cpufunc.h
@@ -0,0 +1,82 @@
+/*
+ * Functions to provide access to special i386 instructions.
+ * XXX - bezillions more are defined in locore.s but are not declared anywhere.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#ifdef __GNUC__
+
+static __inline int bdb(void)
+{
+ extern int bdb_exists;
+
+ if (!bdb_exists)
+ return (0);
+ __asm("int $3");
+ return (1);
+}
+
+static __inline void
+disable_intr(void)
+{
+ __asm __volatile("cli");
+}
+
+static __inline void
+enable_intr(void)
+{
+ __asm __volatile("sti");
+}
+
+/*
+ * This roundabout method of returning a u_char helps stop gcc-1.40 from
+ * generating unnecessary movzbl's.
+ */
+#define inb(port) ((u_char) u_int_inb(port))
+
+static __inline u_int
+u_int_inb(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static __inline void
+outb(u_int port, u_char data)
+{
+ register u_char al asm("ax");
+
+ al = data; /* help gcc-1.40's register allocator */
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
+
+#else /* not __GNUC__ */
+
+int bdb __P((void));
+void disable_intr __P((void));
+void enable_intr __P((void));
+u_char inb __P((u_int port));
+void outb __P((u_int port, u_int data)); /* XXX - incompat */
+
+#endif /* __GNUC__ */
+
+#define really_u_int int /* XXX */
+#define really_void int /* XXX */
+
+void load_cr0 __P((u_int cr0));
+really_u_int rcr0 __P((void));
+
+#ifdef notyet
+really_void setidt __P((int idx, /*XXX*/caddr_t func, int typ, int dpl));
+#endif
+
+#undef really_u_int
+#undef really_void
diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h
new file mode 100644
index 0000000..8e37eec
--- /dev/null
+++ b/sys/i386/include/db_machdep.h
@@ -0,0 +1,154 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log: db_machdep.h,v $
+ * Revision 2.8 92/02/19 15:07:56 elf
+ * Added db_thread_fp_used.
+ * [92/02/19 rpd]
+ *
+ * Revision 2.7 91/10/09 16:06:28 af
+ * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh
+ * Added access and task name macros.
+ * [91/08/29 tak]
+ *
+ * Revision 2.6.3.1 91/10/05 13:10:32 jeffreyh
+ * Added access and task name macros.
+ * [91/08/29 tak]
+ *
+ * Revision 2.6 91/05/14 16:05:58 mrt
+ * Correcting copyright
+ *
+ * Revision 2.5 91/02/05 17:11:17 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:31:24 mrt]
+ *
+ * Revision 2.4 91/01/08 15:10:16 rpd
+ * Added dummy inst_load/inst_store macros.
+ * [90/12/11 rpd]
+ *
+ * Revision 2.3 90/10/25 14:44:49 rwd
+ * Added watchpoint support.
+ * [90/10/18 rpd]
+ *
+ * Revision 2.2 90/08/27 21:56:15 dbg
+ * Created.
+ * [90/07/25 dbg]
+ *
+ */
+
+#ifndef _I386_DB_MACHDEP_H_
+#define _I386_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+
+/* #include <mach/i386/vm_types.h> */
+/* #include <mach/i386/vm_param.h> */
+#include <vm/vm_prot.h>
+#include <vm/vm_param.h>
+#include <vm/vm_inherit.h>
+#include <vm/lock.h>
+/* #include <i386/thread.h> */ /* for thread_status */
+#include <machine/frame.h> /* for struct trapframe */
+/* #include <i386/eflags.h> */
+#include <machine/eflags.h> /* from Mach... */
+/* #include <i386/trap.h> */
+#include <machine/trap.h>
+
+#define i386_saved_state trapframe
+/* end of mangling */
+
+typedef vm_offset_t db_addr_t; /* address - unsigned */
+typedef int db_expr_t; /* expression - signed */
+
+typedef struct i386_saved_state db_regs_t;
+db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip)
+
+#define BKPT_INST 0xcc /* breakpoint instruction */
+#define BKPT_SIZE (1) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1;
+
+#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF)
+#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF)
+
+/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */
+/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */
+/* using the 386bsd values, rather than the Mach ones: */
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
+#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP)
+
+#define I_CALL 0xe8
+#define I_CALLI 0xff
+#define I_RET 0xc3
+#define I_IRET 0xcf
+
+#define inst_trap_return(ins) (((ins)&0xff) == I_IRET)
+#define inst_return(ins) (((ins)&0xff) == I_RET)
+#define inst_call(ins) (((ins)&0xff) == I_CALL || \
+ (((ins)&0xff) == I_CALLI && \
+ ((ins)&0x3800) == 0x1000))
+#define inst_load(ins) 0
+#define inst_store(ins) 0
+
+/* access capability and access macros */
+
+#define DB_ACCESS_LEVEL 2 /* access any space */
+#define DB_CHECK_ACCESS(addr,size,task) \
+ db_check_access(addr,size,task)
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) \
+ db_phys_eq(task1,addr1,task2,addr2)
+#define DB_VALID_KERN_ADDR(addr) \
+ ((addr) >= VM_MIN_KERNEL_ADDRESS && \
+ (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) \
+ ((!(user) && DB_VALID_KERN_ADDR(addr)) || \
+ ((user) && (addr) < VM_MIN_KERNEL_ADDRESS))
+
+boolean_t db_check_access(/* vm_offset_t, int, task_t */);
+boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */);
+
+/* macros for printing OS server dependent task name */
+
+#define DB_TASK_NAME(task) db_task_name(task)
+#define DB_TASK_NAME_TITLE "COMMAND "
+#define DB_TASK_NAME_LEN 23
+#define DB_NULL_TASK_NAME "? "
+
+void db_task_name(/* task_t */);
+
+/* macro for checking if a thread has used floating-point */
+
+#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0)
+
+#endif /* _I386_DB_MACHDEP_H_ */
diff --git a/sys/i386/include/endian.h b/sys/i386/include/endian.h
new file mode 100644
index 0000000..404bf49
--- /dev/null
+++ b/sys/i386/include/endian.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1987, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)endian.h 7.8 (Berkeley) 4/3/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00093
+ * -------------------- ----- ----------------------
+ *
+ * 27 Feb 93 Charles Hannum Better byte-swapping macros for
+ * i386/i486.
+ */
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
+#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */
+
+#define BYTE_ORDER LITTLE_ENDIAN
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+#endif
+
+#define __word_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("rorl $16, %1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#if __GNUC__ >= 2
+#define __byte_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("xchgb %h1, %b1\n\trorl $16, %1\n\txchgb %h1, %b1" \
+ : "=q" (X) \
+ : "0" (X)); \
+ X; })
+#define __byte_swap_word(x) \
+({ register u_short X = (x); \
+ asm ("xchgb %h1, %b1" \
+ : "=q" (X) \
+ : "0" (X)); \
+ X; })
+#else /* __GNUC__ >= 2 */
+#define __byte_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("rorw $8, %w1\n\trorl $16, %1\n\trorw $8, %w1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#define __byte_swap_word(x) \
+({ register u_short X = (x); \
+ asm ("rorw $8, %w1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#endif /* __GNUC__ >= 2 */
+
+/*
+ * Macros for network/external number representation conversion.
+ */
+#if BYTE_ORDER == BIG_ENDIAN && !defined(lint)
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+
+#define NTOHL(x) (x)
+#define NTOHS(x) (x)
+#define HTONL(x) (x)
+#define HTONS(x) (x)
+
+#else
+
+#define ntohl __byte_swap_long
+#define ntohs __byte_swap_word
+#define htonl __byte_swap_long
+#define htons __byte_swap_word
+
+#define NTOHL(x) (x) = ntohl((u_long)x)
+#define NTOHS(x) (x) = ntohs((u_short)x)
+#define HTONL(x) (x) = htonl((u_long)x)
+#define HTONS(x) (x) = htons((u_short)x)
+#endif
diff --git a/sys/i386/include/float.h b/sys/i386/include/float.h
new file mode 100644
index 0000000..edfe0d9
--- /dev/null
+++ b/sys/i386/include/float.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)float.h 7.1 (Berkeley) 5/8/90
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00086
+ * -------------------- ----- ----------------------
+ *
+ * 27 Feb 93 Handel/da Silva/Poirot Adjust value for MAX_DOUBLE
+ */
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS 1 /* FP addition rounds to nearest */
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP -125 /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP -37 /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP -1021
+#define DBL_MIN 2.225073858507201E-308
+#define DBL_MIN_10_EXP -307
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.797693134862315E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
diff --git a/sys/i386/include/frame.h b/sys/i386/include/frame.h
new file mode 100644
index 0000000..4dbabd1
--- /dev/null
+++ b/sys/i386/include/frame.h
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)frame.h 5.2 (Berkeley) 1/18/91
+ */
+
+/*
+ * System stack frames.
+ */
+
+/*
+ * Exception/Trap Stack Frame
+ */
+
+struct trapframe {
+ int tf_es;
+ int tf_ds;
+ int tf_edi;
+ int tf_esi;
+ int tf_ebp;
+ int tf_isp;
+ int tf_ebx;
+ int tf_edx;
+ int tf_ecx;
+ int tf_eax;
+ int tf_trapno;
+ /* below portion defined in 386 hardware */
+ int tf_err;
+ int tf_eip;
+ int tf_cs;
+ int tf_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int tf_esp;
+ int tf_ss;
+};
+
+/* Interrupt stack frame */
+
+struct intrframe {
+ int if_vec;
+ int if_ppl;
+ int if_es;
+ int if_ds;
+ int if_edi;
+ int if_esi;
+ int if_ebp;
+ int :32;
+ int if_ebx;
+ int if_edx;
+ int if_ecx;
+ int if_eax;
+ int :32; /* for compat with trap frame - trapno */
+ int :32; /* for compat with trap frame - err */
+ /* below portion defined in 386 hardware */
+ int if_eip;
+ int if_cs;
+ int if_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int if_esp;
+ int if_ss;
+};
+
+/*
+ * Call Gate/System Call Stack Frame
+ */
+
+struct syscframe {
+ int sf_edi;
+ int sf_esi;
+ int sf_ebp;
+ int :32; /* redundant save of isp */
+ int sf_ebx;
+ int sf_edx;
+ int sf_ecx;
+ int sf_eax;
+ int sf_eflags;
+ /* below portion defined in 386 hardware */
+/* int sf_args[N]; /* if call gate copy args enabled!*/
+ int sf_eip;
+ int sf_cs;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int sf_esp;
+ int sf_ss;
+};
diff --git a/sys/i386/include/limits.h b/sys/i386/include/limits.h
new file mode 100644
index 0000000..73474608
--- /dev/null
+++ b/sys/i386/include/limits.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define CLK_TCK 60 /* ticks per second */
+#define MB_LEN_MAX 1 /* no multibyte characters */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
diff --git a/sys/i386/include/mtpr.h b/sys/i386/include/mtpr.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sys/i386/include/mtpr.h
diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h
new file mode 100644
index 0000000..134e0c1
--- /dev/null
+++ b/sys/i386/include/npx.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.h 5.3 (Berkeley) 1/18/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+#ifndef dontdef
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h
new file mode 100644
index 0000000..1ee217a
--- /dev/null
+++ b/sys/i386/include/param.h
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)param.h 5.8 (Berkeley) 6/28/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00166
+ * -------------------- ----- ----------------------
+ *
+ * 08 Apr 93 Andrew Herbert Fixes for kmem_alloc panics
+ * Rodney W. Grimes Tuneable mbuf sizes
+ * 04 Jun 93 Rodney W. Grimes Change default mbuf size to 2048 via
+ * MCLSHIFT.
+ */
+
+/*
+ * Machine dependent constants for Intel 386.
+ */
+
+#define MACHINE "i386"
+
+/*
+ * Round p (pointer or byte index) up to a correctly-aligned value
+ * for all data types (int, long, ...). The result is u_int and
+ * must be cast to any desired pointer type.
+ */
+#define ALIGN(p) (((u_int)(p) + (sizeof(int) - 1)) &~ (sizeof(int) - 1))
+
+#define NBPG 4096 /* bytes/page */
+#define PGOFSET (NBPG-1) /* byte offset into page */
+#define PGSHIFT 12 /* LOG2(NBPG) */
+#define NPTEPG (NBPG/(sizeof (struct pte)))
+
+#define NBPDR (1024*NBPG) /* bytes/page dir */
+#define PDROFSET (NBPDR-1) /* byte offset into page dir */
+#define PDRSHIFT 22 /* LOG2(NBPDR) */
+
+#define KERNBASE 0xFE000000 /* start of kernel virtual */
+#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT)
+
+#define DEV_BSIZE 512
+#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */
+#define BLKDEV_IOSIZE 2048
+#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */
+
+#define CLSIZE 1
+#define CLSIZELOG2 0
+
+/* NOTE: SSIZE, SINCR and UPAGES must be multiples of CLSIZE */
+#define SSIZE 1 /* initial stack size/NBPG */
+#define SINCR 1 /* increment of stack/NBPG */
+
+#define UPAGES 2 /* pages of u-area */
+
+/*
+ * Constants related to network buffer management.
+ * MCLBYTES must be no larger than CLBYTES (the software page size), and,
+ * on machines that exchange pages of input or output buffers with mbuf
+ * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple
+ * of the hardware page size.
+ */
+#ifndef MSIZE
+#define MSIZE 128 /* size of an mbuf */
+#endif /* MSIZE */
+
+#ifndef MCLSHIFT
+#define MCLSHIFT 11 /* convert bytes to m_buf clusters */
+#endif /* MCLSHIFT */
+#define MCLBYTES (1 << MCLSHIFT) /* size of an m_buf cluster */
+#define MCLOFSET (MCLBYTES - 1) /* offset within an m_buf cluster */
+
+#ifndef NMBCLUSTERS
+#ifdef GATEWAY
+#define NMBCLUSTERS 512 /* map size, max cluster allocation */
+#else
+#define NMBCLUSTERS 256 /* map size, max cluster allocation */
+#endif /* GATEWAY */
+#endif /* NMBCLUSTERS */
+
+/*
+ * Size of kernel malloc arena in CLBYTES-sized logical pages
+ */
+#ifndef NKMEMCLUSTERS
+#define NKMEMCLUSTERS (3072*1024/CLBYTES)
+#endif
+/*
+ * Some macros for units conversion
+ */
+/* Core clicks (4096 bytes) to segments and vice versa */
+#define ctos(x) (x)
+#define stoc(x) (x)
+
+/* Core clicks (4096 bytes) to disk blocks */
+#define ctod(x) ((x)<<(PGSHIFT-DEV_BSHIFT))
+#define dtoc(x) ((x)>>(PGSHIFT-DEV_BSHIFT))
+#define dtob(x) ((x)<<DEV_BSHIFT)
+
+/* clicks to bytes */
+#define ctob(x) ((x)<<PGSHIFT)
+
+/* bytes to clicks */
+#define btoc(x) (((unsigned)(x)+(NBPG-1))>>PGSHIFT)
+
+#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \
+ ((unsigned)(bytes) >> DEV_BSHIFT)
+#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \
+ ((unsigned)(db) << DEV_BSHIFT)
+
+/*
+ * Map a ``block device block'' to a file system block.
+ * This should be device dependent, and will be if we
+ * add an entry to cdevsw/bdevsw for that purpose.
+ * For now though just use DEV_BSIZE.
+ */
+#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE))
+
+/*
+ * Mach derived conversion macros
+ */
+#define i386_round_pdr(x) ((((unsigned)(x)) + NBPDR - 1) & ~(NBPDR-1))
+#define i386_trunc_pdr(x) ((unsigned)(x) & ~(NBPDR-1))
+#define i386_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1))
+#define i386_trunc_page(x) ((unsigned)(x) & ~(NBPG-1))
+#define i386_btod(x) ((unsigned)(x) >> PDRSHIFT)
+#define i386_dtob(x) ((unsigned)(x) << PDRSHIFT)
+#define i386_btop(x) ((unsigned)(x) >> PGSHIFT)
+#define i386_ptob(x) ((unsigned)(x) << PGSHIFT)
+
+#ifndef KERNEL
+#define DELAY(n) { volatile int N = (n); while (--N > 0); }
+#endif
diff --git a/sys/i386/include/pc/display.h b/sys/i386/include/pc/display.h
new file mode 100644
index 0000000..cab46e4
--- /dev/null
+++ b/sys/i386/include/pc/display.h
@@ -0,0 +1,43 @@
+/*
+ * IBM PC display definitions
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/i386/include/pc/msdos.h b/sys/i386/include/pc/msdos.h
new file mode 100644
index 0000000..8d1eb7b
--- /dev/null
+++ b/sys/i386/include/pc/msdos.h
@@ -0,0 +1,63 @@
+/*
+ * msdos common header file
+ * [obtained from mtools -wfj]
+ * how to decipher DOS disk structures in coexisting with DOS
+ */
+
+#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */
+#define MDIR_SIZE 32 /* MSDOS directory size in bytes */
+#define MAX_CLUSTER 8192 /* largest cluster size */
+#define MAX_PATH 128 /* largest MSDOS path length */
+#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
+
+#define NEW 1
+#define OLD 0
+
+struct directory {
+ unsigned char name[8]; /* file name */
+ unsigned char ext[3]; /* file extension */
+ unsigned char attr; /* attribute byte */
+ unsigned char reserved[10]; /* ?? */
+ unsigned char time[2]; /* time stamp */
+ unsigned char date[2]; /* date stamp */
+ unsigned char start[2]; /* starting cluster number */
+ unsigned char size[4]; /* size of the file */
+};
+
+struct bootsector {
+ unsigned char jump[3]; /* Jump to boot code */
+ unsigned char banner[8]; /* OEM name & version */
+ unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */
+ unsigned char clsiz; /* Cluster size in sectors */
+ unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */
+ unsigned char nfat; /* Number of FAT tables hopefully 2 */
+ unsigned char dirents[2]; /* Number of directory slots */
+ unsigned char psect[2]; /* Total sectors on disk */
+ unsigned char descr; /* Media descriptor=first byte of FAT */
+ unsigned char fatlen[2]; /* Sectors in FAT */
+ unsigned char nsect[2]; /* Sectors/track */
+ unsigned char nheads[2]; /* Heads */
+ unsigned char nhs[4]; /* number of hidden sectors */
+ unsigned char bigsect[4]; /* big total sectors */
+ unsigned char junk[476]; /* who cares? */
+};
+
+/* DOS partition table -- located in boot block */
+
+#define DOSBBSECTOR 0 /* DOS boot block relative sector number */
+#define DOSPARTOFF 446
+#define NDOSPART 4
+
+struct dos_partition {
+ unsigned char dp_flag; /* bootstrap flags */
+ unsigned char dp_shd; /* starting head */
+ unsigned char dp_ssect; /* starting sector */
+ unsigned char dp_scyl; /* starting cylinder */
+ unsigned char dp_typ; /* partition type */
+#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
+ unsigned char dp_ehd; /* end head */
+ unsigned char dp_esect; /* end sector */
+ unsigned char dp_ecyl; /* end cylinder */
+ unsigned long dp_start; /* absolute starting sector number */
+ unsigned long dp_size; /* partition size in sectors */
+} dos_partitions[NDOSPART];
diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h
new file mode 100644
index 0000000..92bd810
--- /dev/null
+++ b/sys/i386/include/pcb.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pcb.h 5.10 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Intel 386 process control block
+ */
+#include "machine/tss.h"
+#include "machine/npx.h"
+
+struct pcb {
+ struct i386tss pcb_tss;
+#define pcb_ksp pcb_tss.tss_esp0
+#define pcb_ptd pcb_tss.tss_cr3
+#define pcb_cr3 pcb_ptd
+#define pcb_pc pcb_tss.tss_eip
+#define pcb_psl pcb_tss.tss_eflags
+#define pcb_usp pcb_tss.tss_esp
+#define pcb_fp pcb_tss.tss_ebp
+#ifdef notyet
+ u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */
+#endif
+ struct save87 pcb_savefpu; /* floating point state for 287/387 */
+ struct emcsts pcb_saveemc; /* Cyrix EMC state */
+/*
+ * Software pcb (extension)
+ */
+ int pcb_flags;
+#ifdef notused
+#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */
+#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */
+#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */
+#endif
+#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */
+#define FM_TRAP 0x10 /* process entered kernel on a trap frame */
+#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */
+ short pcb_iml; /* interrupt mask level */
+ caddr_t pcb_onfault; /* copyin/out fault recovery */
+ long pcb_sigc[8]; /* XXX signal code trampoline */
+ int pcb_cmap2; /* XXX temporary PTE - will prefault instead */
+};
+
+#ifdef KERNEL
+struct pcb *curpcb; /* our current running pcb */
+#endif
diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h
new file mode 100644
index 0000000..2eff22f
--- /dev/null
+++ b/sys/i386/include/pmap.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pmap.h 7.4 (Berkeley) 5/12/91
+ */
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * from hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90
+ */
+
+#ifndef _PMAP_MACHINE_
+#define _PMAP_MACHINE_ 1
+
+/*
+ * 386 page table entry and page table directory
+ * W.Jolitz, 8/89
+ */
+
+struct pde
+{
+unsigned int
+ pd_v:1, /* valid bit */
+ pd_prot:2, /* access control */
+ pd_mbz1:2, /* reserved, must be zero */
+ pd_u:1, /* hardware maintained 'used' bit */
+ :1, /* not used */
+ pd_mbz2:2, /* reserved, must be zero */
+ :3, /* reserved for software */
+ pd_pfnum:20; /* physical page frame number of pte's*/
+};
+
+#define PD_MASK 0xffc00000 /* page directory address bits */
+#define PT_MASK 0x003ff000 /* page table address bits */
+#define PD_SHIFT 22 /* page directory address shift */
+#define PG_SHIFT 12 /* page table address shift */
+
+struct pte
+{
+unsigned int
+ pg_v:1, /* valid bit */
+ pg_prot:2, /* access control */
+ pg_mbz1:2, /* reserved, must be zero */
+ pg_u:1, /* hardware maintained 'used' bit */
+ pg_m:1, /* hardware maintained modified bit */
+ pg_mbz2:2, /* reserved, must be zero */
+ pg_w:1, /* software, wired down page */
+ :1, /* software (unused) */
+ pg_nc:1, /* 'uncacheable page' bit */
+ pg_pfnum:20; /* physical page frame number */
+};
+
+#define PG_V 0x00000001
+#define PG_RO 0x00000000
+#define PG_RW 0x00000002
+#define PG_u 0x00000004
+#define PG_PROT 0x00000006 /* all protection bits . */
+#define PG_W 0x00000200
+#define PG_N 0x00000800 /* Non-cacheable */
+#define PG_M 0x00000040
+#define PG_U 0x00000020
+#define PG_FRAME 0xfffff000
+
+#define PG_NOACC 0
+#define PG_KR 0x00000000
+#define PG_KW 0x00000002
+#define PG_URKR 0x00000004
+#define PG_URKW 0x00000004
+#define PG_UW 0x00000006
+
+/* Garbage for current bastardized pager that assumes a hp300 */
+#define PG_NV 0
+#define PG_CI 0
+/*
+ * Page Protection Exception bits
+ */
+
+#define PGEX_P 0x01 /* Protection violation vs. not present */
+#define PGEX_W 0x02 /* during a Write cycle */
+#define PGEX_U 0x04 /* access from User mode (UPL) */
+
+typedef struct pde pd_entry_t; /* page directory entry */
+typedef struct pte pt_entry_t; /* Mach page table entry */
+
+/*
+ * One page directory, shared between
+ * kernel and user modes.
+ */
+#define I386_PAGE_SIZE NBPG
+#define I386_PDR_SIZE NBPDR
+
+#define I386_KPDES 8 /* KPT page directory size */
+#define I386_UPDES NBPDR/sizeof(struct pde)-8 /* UPT page directory size */
+
+#define UPTDI 0x3f6 /* ptd entry for u./kernel&user stack */
+#define PTDPTDI 0x3f7 /* ptd entry that points to ptd! */
+#define KPTDI_FIRST 0x3f8 /* start of kernel virtual pde's */
+#define KPTDI_LAST 0x3fA /* last of kernel virtual pde's */
+
+/*
+ * Address of current and alternate address space page table maps
+ * and directories.
+ */
+#ifdef KERNEL
+extern struct pte PTmap[], APTmap[], Upte;
+extern struct pde PTD[], APTD[], PTDpde, APTDpde, Upde;
+extern pt_entry_t *Sysmap;
+
+extern int IdlePTD; /* physical address of "Idle" state directory */
+#endif
+
+/*
+ * virtual address to page table entry and
+ * to physical address. Likewise for alternate address space.
+ * Note: these work recursively, thus vtopte of a pte will give
+ * the corresponding pde that in turn maps it.
+ */
+#define vtopte(va) (PTmap + i386_btop(va))
+#define kvtopte(va) vtopte(va)
+#define ptetov(pt) (i386_ptob(pt - PTmap))
+#define vtophys(va) (i386_ptob(vtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS)
+
+#define avtopte(va) (APTmap + i386_btop(va))
+#define ptetoav(pt) (i386_ptob(pt - APTmap))
+#define avtophys(va) (i386_ptob(avtopte(va)->pg_pfnum) | ((int)(va) & PGOFSET))
+
+/*
+ * macros to generate page directory/table indicies
+ */
+
+#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT)
+#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT)
+
+/*
+ * Pmap stuff
+ */
+
+struct pmap {
+ pd_entry_t *pm_pdir; /* KVA of page directory */
+ boolean_t pm_pdchanged; /* pdir changed */
+ short pm_dref; /* page directory ref count */
+ short pm_count; /* pmap reference count */
+ simple_lock_data_t pm_lock; /* lock on pmap */
+ struct pmap_statistics pm_stats; /* pmap statistics */
+ long pm_ptpages; /* more stats: PT pages */
+};
+
+typedef struct pmap *pmap_t;
+
+#ifdef KERNEL
+extern pmap_t kernel_pmap;
+#endif
+
+/*
+ * Macros for speed
+ */
+#define PMAP_ACTIVATE(pmapp, pcbp) \
+ if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \
+ (pcbp)->pcb_cr3 = \
+ pmap_extract(kernel_pmap, (pmapp)->pm_pdir); \
+ if ((pmapp) == &curproc->p_vmspace->vm_pmap) \
+ load_cr3((pcbp)->pcb_cr3); \
+ (pmapp)->pm_pdchanged = FALSE; \
+ }
+
+#define PMAP_DEACTIVATE(pmapp, pcbp)
+
+/*
+ * For each vm_page_t, there is a list of all currently valid virtual
+ * mappings of that page. An entry is a pv_entry_t, the list is pv_table.
+ */
+typedef struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ pmap_t pv_pmap; /* pmap where mapping lies */
+ vm_offset_t pv_va; /* virtual address for mapping */
+ int pv_flags; /* flags */
+} *pv_entry_t;
+
+#define PV_ENTRY_NULL ((pv_entry_t) 0)
+
+#define PV_CI 0x01 /* all entries must be cache inhibited */
+#define PV_PTPAGE 0x02 /* entry maps a page table page */
+
+#ifdef KERNEL
+
+pv_entry_t pv_table; /* array of entries, one per page */
+
+#define pa_index(pa) atop(pa - vm_first_phys)
+#define pa_to_pvh(pa) (&pv_table[pa_index(pa)])
+
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+
+#endif KERNEL
+
+#endif _PMAP_MACHINE_
diff --git a/sys/i386/include/proc.h b/sys/i386/include/proc.h
new file mode 100644
index 0000000..02f3c01
--- /dev/null
+++ b/sys/i386/include/proc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)proc.h 7.1 (Berkeley) 5/15/91
+ */
+
+/*
+ * Machine-dependent part of the proc structure for hp300.
+ */
+struct mdproc {
+ int md_flags; /* machine-dependent flags */
+#ifdef notyet
+ int *p_regs; /* registers on current frame */
+#endif
+};
+
+/* md_flags */
+#define MDP_AST 0x0001 /* async trap pending */
diff --git a/sys/i386/include/psl.h b/sys/i386/include/psl.h
new file mode 100644
index 0000000..aee73ed
--- /dev/null
+++ b/sys/i386/include/psl.h
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)psl.h 5.2 (Berkeley) 1/18/91
+ */
+
+/*
+ * 386 processor status longword.
+ */
+#define PSL_C 0x00000001 /* carry bit */
+#define PSL_PF 0x00000004 /* parity bit */
+#define PSL_AF 0x00000010 /* bcd carry bit */
+#define PSL_Z 0x00000040 /* zero bit */
+#define PSL_N 0x00000080 /* negative bit */
+#define PSL_T 0x00000100 /* trace enable bit */
+#define PSL_I 0x00000200 /* interrupt enable bit */
+#define PSL_D 0x00000400 /* string instruction direction bit */
+#define PSL_V 0x00000800 /* overflow bit */
+#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */
+#define PSL_NT 0x00004000 /* nested task bit */
+#define PSL_RF 0x00010000 /* restart flag bit */
+#define PSL_VM 0x00020000 /* virtual 8086 mode bit */
+
+#define PSL_MBZ 0xfffc7fb7 /* must be zero bits */
+#define PSL_MBO 0x00000002 /* must be one bits */
+
+#define PSL_USERSET (PSL_IOPL)
+#define PSL_USERCLR (PSL_I|PSL_NT)
diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h
new file mode 100644
index 0000000..bc2f05c
--- /dev/null
+++ b/sys/i386/include/reg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)reg.h 5.5 (Berkeley) 1/18/91
+ */
+
+/*
+ * Location of the users' stored
+ * registers within appropriate frame of 'trap' and 'syscall', relative to
+ * base of stack frame.
+ * Normal usage is u.u_ar0[XX] in kernel.
+ */
+
+/* When referenced during a trap/exception, registers are at these offsets */
+
+#define tES (0)
+#define tDS (1)
+#define tEDI (2)
+#define tESI (3)
+#define tEBP (4)
+
+#define tEBX (6)
+#define tEDX (7)
+#define tECX (8)
+#define tEAX (9)
+
+#define tEIP (12)
+#define tCS (13)
+#define tEFLAGS (14)
+#define tESP (15)
+#define tSS (16)
+
+/* During a system call, registers are at these offsets instead of above. */
+
+#define sEDI (0)
+#define sESI (1)
+#define sEBP (2)
+
+#define sEBX (4)
+#define sEDX (5)
+#define sECX (6)
+#define sEAX (7)
+#define sEFLAGS (8)
+#define sEIP (9)
+#define sCS (10)
+#define sESP (11)
+#define sSS (12)
+
+#define PC sEIP
+#define SP sESP
+#define PS sEFLAGS
+#define R0 sEDX
+#define R1 sECX
+/*
+ * Registers accessible to ptrace(2) syscall for debugger
+ */
+#ifdef IPCREG
+#define NIPCREG 14
+int ipcreg[NIPCREG] =
+ { tES,tDS,tEDI,tESI,tEBP,tEBX,tEDX,tECX,tEAX,tEIP,tCS,tEFLAGS,tESP,tSS };
+#endif
diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h
new file mode 100644
index 0000000..0456e59
--- /dev/null
+++ b/sys/i386/include/segments.h
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)segments.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * 386 Segmentation Data Structures and definitions
+ * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989
+ */
+
+/*
+ * Selectors
+ */
+
+#define ISPL(s) ((s)&3) /* what is the priority level of a selector */
+#define SEL_KPL 0 /* kernel priority level */
+#define SEL_UPL 3 /* user priority level */
+#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
+#define SEL_LDT 4 /* local descriptor table */
+#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */
+#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
+#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
+
+/*
+ * Memory and System segment descriptors
+ */
+struct segment_descriptor {
+ unsigned sd_lolimit:16 ; /* segment extent (lsb) */
+ unsigned sd_lobase:24 ; /* segment base address (lsb) */
+ unsigned sd_type:5 ; /* segment type */
+ unsigned sd_dpl:2 ; /* segment descriptor priority level */
+ unsigned sd_p:1 ; /* segment descriptor present */
+ unsigned sd_hilimit:4 ; /* segment extent (msb) */
+ unsigned sd_xx:2 ; /* unused */
+ unsigned sd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/
+ unsigned sd_hibase:8 ; /* segment base address (msb) */
+} ;
+
+/*
+ * Gate descriptors (e.g. indirect descriptors)
+ */
+struct gate_descriptor {
+ unsigned gd_looffset:16 ; /* gate offset (lsb) */
+ unsigned gd_selector:16 ; /* gate segment selector */
+ unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
+ unsigned gd_xx:3 ; /* unused */
+ unsigned gd_type:5 ; /* segment type */
+ unsigned gd_dpl:2 ; /* segment descriptor priority level */
+ unsigned gd_p:1 ; /* segment descriptor present */
+ unsigned gd_hioffset:16 ; /* gate offset (msb) */
+} ;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+ struct segment_descriptor sd;
+ struct gate_descriptor gd;
+};
+
+ /* system segments and gate types */
+#define SDT_SYSNULL 0 /* system null */
+#define SDT_SYS286TSS 1 /* system 286 TSS available */
+#define SDT_SYSLDT 2 /* system local descriptor table */
+#define SDT_SYS286BSY 3 /* system 286 TSS busy */
+#define SDT_SYS286CGT 4 /* system 286 call gate */
+#define SDT_SYSTASKGT 5 /* system task gate */
+#define SDT_SYS286IGT 6 /* system 286 interrupt gate */
+#define SDT_SYS286TGT 7 /* system 286 trap gate */
+#define SDT_SYSNULL2 8 /* system null again */
+#define SDT_SYS386TSS 9 /* system 386 TSS available */
+#define SDT_SYSNULL3 10 /* system null again */
+#define SDT_SYS386BSY 11 /* system 386 TSS busy */
+#define SDT_SYS386CGT 12 /* system 386 call gate */
+#define SDT_SYSNULL4 13 /* system null again */
+#define SDT_SYS386IGT 14 /* system 386 interrupt gate */
+#define SDT_SYS386TGT 15 /* system 386 trap gate */
+
+ /* memory segment types */
+#define SDT_MEMRO 16 /* memory read only */
+#define SDT_MEMROA 17 /* memory read only accessed */
+#define SDT_MEMRW 18 /* memory read write */
+#define SDT_MEMRWA 19 /* memory read write accessed */
+#define SDT_MEMROD 20 /* memory read only expand dwn limit */
+#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
+#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
+#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */
+#define SDT_MEME 24 /* memory execute only */
+#define SDT_MEMEA 25 /* memory execute only accessed */
+#define SDT_MEMER 26 /* memory execute read */
+#define SDT_MEMERA 27 /* memory execute read accessed */
+#define SDT_MEMEC 28 /* memory execute only conforming */
+#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
+#define SDT_MEMERC 30 /* memory execute read conforming */
+#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
+
+/* is memory segment descriptor pointer ? */
+#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC)
+
+/* is 286 gate descriptor pointer ? */
+#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \
+ && (s->d_type) < SDT_SYS286TGT))
+
+/* is 386 gate descriptor pointer ? */
+#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \
+ && (s->d_type) < SDT_SYS386TGT))
+
+/* is gate descriptor pointer ? */
+#define ISGDP(s) (IS286GDP(s) || IS386GDP(s))
+
+/* is segment descriptor pointer ? */
+#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s))
+
+/* is system segment descriptor pointer ? */
+#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s))
+
+/*
+ * Software definitions are in this convenient format,
+ * which are translated into inconvenient segment descriptors
+ * when needed to be used by the 386 hardware
+ */
+
+struct soft_segment_descriptor {
+ unsigned ssd_base ; /* segment base address */
+ unsigned ssd_limit ; /* segment extent */
+ unsigned ssd_type:5 ; /* segment type */
+ unsigned ssd_dpl:2 ; /* segment descriptor priority level */
+ unsigned ssd_p:1 ; /* segment descriptor present */
+ unsigned ssd_xx:4 ; /* unused */
+ unsigned ssd_xx1:2 ; /* unused */
+ unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/
+};
+
+extern ssdtosd() ; /* to decode a ssd */
+extern sdtossd() ; /* to encode a sd */
+
+/*
+ * region descriptors, used to load gdt/idt tables before segments yet exist.
+ */
+struct region_descriptor {
+ unsigned rd_limit:16; /* segment extent */
+ unsigned rd_base:32; /* base address */
+};
+
+/*
+ * Segment Protection Exception code bits
+ */
+
+#define SEGEX_EXT 0x01 /* recursive or externally induced */
+#define SEGEX_IDT 0x02 /* interrupt descriptor table */
+#define SEGEX_TI 0x04 /* local descriptor table */
+ /* other bits are affected descriptor index */
+#define SEGEX_IDX(s) ((s)>>3)&0x1fff)
+
+/*
+ * Size of IDT table
+ */
+
+#define NIDT 256
+#define NRSVIDT 32 /* reserved entries for cpu exceptions */
diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h
new file mode 100644
index 0000000..d1908c9
--- /dev/null
+++ b/sys/i386/include/specialreg.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ *
+ */
+
+/*
+ * Bits in 386 special registers:
+ */
+
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
+#ifdef notused
+#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
+#endif
+#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
+#ifdef notused
+#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */
+#endif
+#define CR0_PG 0x80000000 /* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */
+#ifdef notyet
+#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */
+#endif
diff --git a/sys/i386/include/stdarg.h b/sys/i386/include/stdarg.h
new file mode 100644
index 0000000..f499253
--- /dev/null
+++ b/sys/i386/include/stdarg.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stdarg.h 7.2 (Berkeley) 5/4/91
+ */
+
+typedef char *va_list;
+
+#ifdef KERNEL
+#define va_arg(ap, type) \
+ ((type *)(ap += sizeof(type)))[-1]
+#else
+#define va_arg(ap, type) \
+ ((type *)(ap += sizeof(type) < sizeof(int) ? \
+ (abort(), 0) : sizeof(type)))[-1]
+#endif
+
+#define va_end(ap)
+
+#define __va_promote(type) \
+ (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
+
+#define va_start(ap, last) \
+ (ap = ((char *)&(last) + __va_promote(last)))
diff --git a/sys/i386/include/trap.h b/sys/i386/include/trap.h
new file mode 100644
index 0000000..6015605
--- /dev/null
+++ b/sys/i386/include/trap.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.h 5.4 (Berkeley) 5/9/91
+ */
+
+/*
+ * Trap type values
+ * also known in trap.c for name strings
+ */
+
+#define T_RESADFLT 0 /* reserved addressing */
+#define T_PRIVINFLT 1 /* privileged instruction */
+#define T_RESOPFLT 2 /* reserved operand */
+#define T_BPTFLT 3 /* breakpoint instruction */
+#define T_SYSCALL 5 /* system call (kcall) */
+#define T_ARITHTRAP 6 /* arithmetic trap */
+#define T_ASTFLT 7 /* system forced exception */
+#define T_SEGFLT 8 /* segmentation (limit) fault */
+#define T_PROTFLT 9 /* protection fault */
+#define T_TRCTRAP 10 /* trace trap */
+#define T_PAGEFLT 12 /* page fault */
+#define T_TABLEFLT 13 /* page table fault */
+#define T_ALIGNFLT 14 /* alignment fault */
+#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */
+#define T_BUSERR 16 /* bus error */
+#define T_KDBTRAP 17 /* kernel debugger trap */
+
+#define T_DIVIDE 18 /* integer divide fault */
+#define T_NMI 19 /* non-maskable trap */
+#define T_OFLOW 20 /* overflow trap */
+#define T_BOUND 21 /* bound instruction fault */
+#define T_DNA 22 /* device not available fault */
+#define T_DOUBLEFLT 23 /* double fault */
+#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */
+#define T_TSSFLT 25 /* invalid tss fault */
+#define T_SEGNPFLT 26 /* segment not present fault */
+#define T_STKFLT 27 /* stack fault */
+#define T_RESERVED 28 /* reserved fault base */
+
+/* definitions for <sys/signal.h> */
+#define ILL_RESAD_FAULT T_RESADFLT
+#define ILL_PRIVIN_FAULT T_PRIVINFLT
+#define ILL_RESOP_FAULT T_RESOPFLT
+#define ILL_ALIGN_FAULT T_ALIGNFLT
+#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */
+
+/* codes for SIGFPE/ARITHTRAP */
+#define FPE_INTOVF_TRAP 0x1 /* integer overflow */
+#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */
+#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */
+#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */
+#define FPE_FLTUND_TRAP 0x5 /* floating underflow */
+#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */
+#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */
+
+/* codes for SIGBUS */
+#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */
+#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */
+#define BUS_STK_FAULT T_STKFLT /* stack segment */
+#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */
+
+/* Trap's coming from user mode */
+#define T_USER 0x100
diff --git a/sys/i386/include/tss.h b/sys/i386/include/tss.h
new file mode 100644
index 0000000..8ba140d
--- /dev/null
+++ b/sys/i386/include/tss.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tss.h 5.4 (Berkeley) 1/18/91
+ */
+
+/*
+ * Intel 386 Context Data Type
+ */
+
+struct i386tss {
+ int tss_link; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp0; /* kernel stack pointer priviledge level 0 */
+#define tss_ksp tss_esp0
+ int tss_ss0; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp1; /* kernel stack pointer priviledge level 1 */
+ int tss_ss1; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp2; /* kernel stack pointer priviledge level 2 */
+ int tss_ss2; /* actually 16 bits: top 16 bits must be zero */
+ /* struct ptd *tss_cr3; /* page table directory */
+ int tss_cr3; /* page table directory */
+#define tss_ptd tss_cr3
+ int tss_eip; /* program counter */
+#define tss_pc tss_eip
+ int tss_eflags; /* program status longword */
+#define tss_psl tss_eflags
+ int tss_eax;
+ int tss_ecx;
+ int tss_edx;
+ int tss_ebx;
+ int tss_esp; /* user stack pointer */
+#define tss_usp tss_esp
+ int tss_ebp; /* user frame pointer */
+#define tss_fp tss_ebp
+ int tss_esi;
+ int tss_edi;
+ int tss_es; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ss; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ds; /* actually 16 bits: top 16 bits must be zero */
+ int tss_fs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_gs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ldt; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ioopt; /* options & io offset bitmap: currently zero */
+ /* XXX unimplemented .. i/o permission bitmap */
+};
diff --git a/sys/i386/include/types.h b/sys/i386/include/types.h
new file mode 100644
index 0000000..9eeaef3
--- /dev/null
+++ b/sys/i386/include/types.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 7.5 (Berkeley) 3/9/91
+ */
+
+#ifndef _MACHTYPES_H_
+#define _MACHTYPES_H_
+
+typedef struct _physadr {
+ int r[1];
+} *physadr;
+
+typedef struct label_t {
+ int val[6];
+} label_t;
+
+typedef u_long vm_offset_t;
+typedef u_long vm_size_t;
+
+#endif /* _MACHTYPES_H_ */
diff --git a/sys/i386/include/vmparam.h b/sys/i386/include/vmparam.h
new file mode 100644
index 0000000..39403d6
--- /dev/null
+++ b/sys/i386/include/vmparam.h
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)vmparam.h 5.9 (Berkeley) 5/12/91
+ */
+
+
+/*
+ * Machine dependent constants for 386.
+ */
+
+/*
+ * Virtual address space arrangement. On 386, both user and kernel
+ * share the address space, not unlike the vax.
+ * USRTEXT is the start of the user text/data space, while USRSTACK
+ * is the top (end) of the user stack. Immediately above the user stack
+ * resides the user structure, which is UPAGES long and contains the
+ * kernel stack.
+ *
+ * Immediately after the user structure is the page table map, and then
+ * kernal address space.
+ */
+#define USRTEXT 0
+#define USRSTACK 0xFDBFE000
+#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */
+#define LOWPAGES 0
+#define HIGHPAGES UPAGES
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#define MAXTSIZ (6*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ (6*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (32*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (512*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ MAXDSIZ /* max stack size */
+#endif
+
+/*
+ * Default sizes of swap allocation chunks (see dmap.h).
+ * The actual values may be changed in vminit() based on MAXDSIZ.
+ * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024.
+ */
+#define DMMIN 32 /* smallest swap allocation */
+#define DMMAX 4096 /* largest potential swap allocation */
+#define DMTEXT 1024 /* swap allocation for text */
+
+/*
+ * Sizes of the system and user portions of the system page table.
+ */
+#define SYSPTSIZE (2*NPTEPG)
+#define USRPTSIZE (2*NPTEPG)
+
+/*
+ * Size of User Raw I/O map
+ */
+#define USRIOSIZE 300
+
+/*
+ * The size of the clock loop.
+ */
+#define LOOPPAGES (maxfree - firstfree)
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+/*
+ * A swapped in process is given a small amount of core without being bothered
+ * by the page replacement algorithm. Basically this says that if you are
+ * swapped in you deserve some resources. We protect the last SAFERSS
+ * pages against paging and will just swap you out rather than paging you.
+ * Note that each process has at least UPAGES+CLSIZE pages which are not
+ * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this
+ * number just means a swapped in process is given around 25k bytes.
+ * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81),
+ * so we loan each swapped in process memory worth 100$, or just admit
+ * that we don't consider it worthwhile and swap it out to disk which costs
+ * $30/mb or about $0.75.
+ * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17
+ * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) }
+ */
+#define SAFERSS 8 /* nominal ``small'' resident set size
+ protected against replacement */
+
+/*
+ * DISKRPM is used to estimate the number of paging i/o operations
+ * which one can expect from a single disk controller.
+ */
+#define DISKRPM 60
+
+/*
+ * Klustering constants. Klustering is the gathering
+ * of pages together for pagein/pageout, while clustering
+ * is the treatment of hardware page size as though it were
+ * larger than it really is.
+ *
+ * KLMAX gives maximum cluster size in CLSIZE page (cluster-page)
+ * units. Note that KLMAX*CLSIZE must be <= DMMIN in dmap.h.
+ */
+
+#define KLMAX (4/CLSIZE)
+#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */
+#define KLIN (4/CLSIZE) /* default data/stack in klust */
+#define KLTXT (4/CLSIZE) /* default text in klust */
+#define KLOUT (4/CLSIZE)
+
+/*
+ * KLSDIST is the advance or retard of the fifo reclaim for sequential
+ * processes data space.
+ */
+#define KLSDIST 3 /* klusters advance/retard for seq. fifo */
+
+/*
+ * Paging thresholds (see vm_sched.c).
+ * Strategy of 1/19/85:
+ * lotsfree is 512k bytes, but at most 1/4 of memory
+ * desfree is 200k bytes, but at most 1/8 of memory
+ * minfree is 64k bytes, but at most 1/2 of desfree
+ */
+#define LOTSFREE (512 * 1024)
+#define LOTSFREEFRACT 4
+#define DESFREE (200 * 1024)
+#define DESFREEFRACT 8
+#define MINFREE (64 * 1024)
+#define MINFREEFRACT 2
+
+/*
+ * There are two clock hands, initially separated by HANDSPREAD bytes
+ * (but at most all of user memory). The amount of time to reclaim
+ * a page once the pageout process examines it increases with this
+ * distance and decreases as the scan rate rises.
+ */
+#define HANDSPREAD (2 * 1024 * 1024)
+
+/*
+ * The number of times per second to recompute the desired paging rate
+ * and poke the pagedaemon.
+ */
+#define RATETOSCHEDPAGING 4
+
+/*
+ * Believed threshold (in megabytes) for which interleaved
+ * swapping area is desirable.
+ */
+#define LOTSOFMEM 2
+
+#define mapin(pte, v, pfnum, prot) \
+ {(*(int *)(pte) = ((pfnum)<<PGSHIFT) | (prot)) ; }
+
+/*
+ * Mach derived constants
+ */
+
+/* user/kernel map constants */
+#define VM_MIN_ADDRESS ((vm_offset_t)0)
+#define VM_MAXUSER_ADDRESS ((vm_offset_t)0xFDBFE000)
+#define UPT_MIN_ADDRESS ((vm_offset_t)0xFDC00000)
+#define UPT_MAX_ADDRESS ((vm_offset_t)0xFDFF7000)
+#define VM_MAX_ADDRESS UPT_MAX_ADDRESS
+#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xFDFF7000)
+#define UPDT VM_MIN_KERNEL_ADDRESS
+#define KPT_MIN_ADDRESS ((vm_offset_t)0xFDFF8000)
+#define KPT_MAX_ADDRESS ((vm_offset_t)0xFDFFF000)
+#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)0xFF7FF000)
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES)
+#define VM_KMEM_SIZE (NKMEMCLUSTERS*CLBYTES)
+#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES)
+
+/* # of kernel PT pages (initial only, can grow dynamically) */
+#define VM_KERNEL_PT_PAGES ((vm_size_t)2) /* XXX: SYSPTSIZE */
+
+/* pcb base */
+#define pcbb(p) ((u_int)(p)->p_addr)
+
+/*
+ * Flush MMU TLB
+ */
+
+#ifndef I386_CR3PAT
+#define I386_CR3PAT 0x0
+#endif
+
+#ifdef notyet
+#define _cr3() ({u_long rtn; \
+ asm (" movl %%cr3,%%eax; movl %%eax,%0 " \
+ : "=g" (rtn) \
+ : \
+ : "ax"); \
+ rtn; \
+})
+
+#define load_cr3(s) ({ u_long val; \
+ val = (s) | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+
+#define tlbflush() ({ u_long val; \
+ val = u.u_pcb.pcb_ptd | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+#endif
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c
new file mode 100644
index 0000000..85271fc
--- /dev/null
+++ b/sys/i386/isa/aha1542.c
@@ -0,0 +1,1644 @@
+/*
+ * (Mostly) Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+ * HISTORY
+ * $Log: aha1542.c,v $
+ * Revision 1.6 1992/08/24 21:01:58 jason
+ * many changes and bugfixes for osf1
+ *
+ * Revision 1.5 1992/07/31 01:22:03 julian
+ * support improved scsi.h layout
+ *
+ * Revision 1.4 1992/07/25 03:11:26 julian
+ * check each request fro sane flags.
+ *
+ * Revision 1.3 1992/07/24 00:52:45 julian
+ * improved timeout handling.
+ * added support for two arguments to the sd_done (or equiv) call so that
+ * they can pre-queue several arguments.
+ * slightly clean up error handling
+ *
+ * Revision 1.2 1992/07/17 22:03:54 julian
+ * upgraded the timeout code.
+ * added support for UIO-based i/o (as used for pmem operations)
+ *
+ * Revision 1.1 1992/05/27 00:51:12 balsup
+ * machkern/cor merge
+ */
+
+/*
+ * a FEW lines in this driver come from a MACH adaptec-disk driver
+ * so the copyright below is included:
+ *
+ * Copyright 1990 by Open Software Foundation,
+ * Grenoble, FRANCE
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OSF or Open Software
+ * Foundation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#include <sys/types.h>
+#include <aha.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#ifdef MACH /* EITHER CMU OR OSF */
+#include <i386/ipl.h>
+#include <i386at/scsi.h>
+#include <i386at/scsiconf.h>
+
+#ifdef OSF /* OSF ONLY */
+#include <sys/table.h>
+#include <i386/handler.h>
+#include <i386/dispatcher.h>
+#include <i386/AT386/atbus.h>
+
+#else OSF /* CMU ONLY */
+#include <i386at/atbus.h>
+#include <i386/pio.h>
+#endif OSF
+#endif MACH /* end of MACH specific */
+
+#ifdef __386BSD__ /* 386BSD specific */
+#define isa_dev isa_device
+#define dev_unit id_unit
+#define dev_addr id_iobase
+
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif __386BSD__
+
+
+#ifdef __386BSD__
+#include "ddb.h"
+#if NDDB > 0
+int Debugger();
+#else NDDB
+#define Debugger() panic("should call debugger here (adaptec.c)")
+#endif NDDB
+#endif __386BSD__
+extern int delaycount; /* from clock setup code */
+
+/************************** board definitions *******************************/
+/*
+ * I/O Port Interface
+ */
+
+#define AHA_BASE aha_base[unit]
+#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */
+#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */
+#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */
+
+/*
+ * AHA_CTRL_STAT bits (write)
+ */
+
+#define AHA_HRST 0x80 /* Hardware reset */
+#define AHA_SRST 0x40 /* Software reset */
+#define AHA_IRST 0x20 /* Interrupt reset */
+#define AHA_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * AHA_CTRL_STAT bits (read)
+ */
+
+#define AHA_STST 0x80 /* Self test in Progress */
+#define AHA_DIAGF 0x40 /* Diagnostic Failure */
+#define AHA_INIT 0x20 /* Mbx Init required */
+#define AHA_IDLE 0x10 /* Host Adapter Idle */
+#define AHA_CDF 0x08 /* cmd/data out port full */
+#define AHA_DF 0x04 /* Data in port full */
+#define AHA_INVDCMD 0x01 /* Invalid command */
+
+/*
+ * AHA_CMD_DATA bits (write)
+ */
+
+#define AHA_NOP 0x00 /* No operation */
+#define AHA_MBX_INIT 0x01 /* Mbx initialization */
+#define AHA_START_SCSI 0x02 /* start scsi command */
+#define AHA_START_BIOS 0x03 /* start bios command */
+#define AHA_INQUIRE 0x04 /* Adapter Inquiry */
+#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define AHA_SPEED_SET 0x09 /* set transfer speed */
+#define AHA_DEV_GET 0x0a /* return installed devices */
+#define AHA_CONF_GET 0x0b /* return configuration data */
+#define AHA_TARGET_EN 0x0c /* enable target mode */
+#define AHA_SETUP_GET 0x0d /* return setup data */
+#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */
+#define AHA_READ_CH2 0x1b /* read channel 2 buffer */
+#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */
+#define AHA_READ_FIFO 0x1d /* read fifo buffer */
+#define AHA_ECHO 0x1e /* Echo command data */
+
+struct aha_cmd_buf {
+ u_char byte[16];
+};
+
+/*
+ * AHA_INTR_PORT bits (read)
+ */
+
+#define AHA_ANY_INTR 0x80 /* Any interrupt */
+#define AHA_SCRD 0x08 /* SCSI reset detected */
+#define AHA_HACC 0x04 /* Command complete */
+#define AHA_MBOA 0x02 /* MBX out empty */
+#define AHA_MBIF 0x01 /* MBX in full */
+
+/*
+ * Mail box defs
+ */
+
+#define AHA_MBX_SIZE 16 /* mail box size */
+
+struct aha_mbx {
+ struct aha_mbx_out {
+ unsigned char cmd;
+ unsigned char ccb_addr[3];
+ } mbo [AHA_MBX_SIZE];
+ struct aha_mbx_in{
+ unsigned char stat;
+ unsigned char ccb_addr[3];
+ } mbi[AHA_MBX_SIZE];
+};
+
+/*
+ * mbo.cmd values
+ */
+
+#define AHA_MBO_FREE 0x0 /* MBO entry is free */
+#define AHA_MBO_START 0x1 /* MBO activate entry */
+#define AHA_MBO_ABORT 0x2 /* MBO abort entry */
+
+#define AHA_MBI_FREE 0x0 /* MBI entry is free */
+#define AHA_MBI_OK 0x1 /* completed without error */
+#define AHA_MBI_ABORT 0x2 /* aborted ccb */
+#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define AHA_MBI_ERROR 0x4 /* Completed with error */
+
+extern struct aha_mbx aha_mbx[];
+
+/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
+#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
+ /* allow 64 K i/o (min) */
+
+struct aha_ccb {
+ unsigned char opcode;
+ unsigned char lun:3;
+ unsigned char data_in:1; /* must be 0 */
+ unsigned char data_out:1; /* must be 0 */
+ unsigned char target:3;
+ unsigned char scsi_cmd_length;
+ unsigned char req_sense_length;
+ unsigned char data_length[3];
+ unsigned char data_addr[3];
+ unsigned char link_addr[3];
+ unsigned char link_id;
+ unsigned char host_stat;
+ unsigned char target_stat;
+ unsigned char reserved[2];
+ struct scsi_generic scsi_cmd;
+ struct scsi_sense_data scsi_sense;
+ struct aha_scat_gath {
+ unsigned char seg_len[3];
+ unsigned char seg_addr[3];
+ } scat_gath[AHA_NSEG];
+ struct aha_ccb *next;
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ struct aha_mbx_out *mbx; /* pointer to mail box */
+ long int delta; /* difference from previous*/
+ struct aha_ccb *later,*sooner;
+ int flags;
+#define CCB_FREE 0
+#define CCB_ACTIVE 1
+#define CCB_ABORTED 2
+
+};
+
+struct aha_ccb *aha_soonest = (struct aha_ccb *)0;
+struct aha_ccb *aha_latest = (struct aha_ccb *)0;
+long int aha_furtherest = 0; /* longest time in the timeout queue */
+
+/*
+ * opcode fields
+ */
+
+#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/
+#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */
+
+
+/*
+ * aha_ccb.host_stat values
+ */
+
+#define AHA_OK 0x00 /* cmd ok */
+#define AHA_LINK_OK 0x0a /* Link cmd ok */
+#define AHA_LINK_IT 0x0b /* Link cmd ok + int */
+#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */
+#define AHA_OVER_UNDER 0x12 /* Data over/under run */
+#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define AHA_INV_TARGET 0x18 /* Invalid target direction */
+#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */
+#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define AHA_ABORTED 42
+
+
+
+
+struct aha_setup
+{
+ u_char sync_neg:1;
+ u_char parity:1;
+ u_char :6;
+ u_char speed;
+ u_char bus_on;
+ u_char bus_off;
+ u_char num_mbx;
+ u_char mbx[3];
+ struct
+ {
+ u_char offset:4;
+ u_char period:3;
+ u_char valid:1;
+ }sync[8];
+ u_char disc_sts;
+};
+
+struct aha_config
+{
+ u_char chan;
+ u_char intr;
+ u_char scsi_dev:3;
+ u_char :5;
+};
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
+
+
+/*********************************** end of board definitions***************/
+
+
+#ifdef MACH
+#define PHYSTOKV(x) phystokv(x)
+#define KVTOPHYS(x) kvtophys(x)
+#else MACH
+#ifdef __386BSD__
+#define PHYSTOKV(x) (x | 0xFE000000)
+#define KVTOPHYS(x) vtophys(x)
+#else __386BSD__
+#endif __386BSD__
+#endif MACH
+#define AHA_DMA_PAGES AHA_NSEG
+
+#define PAGESIZ 4096
+#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
+
+
+u_char aha_scratch_buf[256];
+#ifdef MACH
+caddr_t aha_base[NAHA]; /* base port for each board */
+#else
+short aha_base[NAHA]; /* base port for each board */
+#endif
+struct aha_mbx aha_mbx[NAHA];
+struct aha_ccb *aha_ccb_free[NAHA];
+struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE];
+struct scsi_xfer aha_scsi_xfer[NAHA];
+struct isa_dev *ahainfo[NAHA];
+struct aha_ccb *aha_get_ccb();
+int aha_int[NAHA];
+int aha_dma[NAHA];
+int aha_scsi_dev[NAHA];
+int aha_initialized[NAHA];
+#ifdef OSF
+int aha_attached[NAHA];
+#endif OSF
+int aha_debug = 0;
+
+int ahaprobe(), ahaattach(), ahaintr();
+#ifdef MACH
+struct isa_driver ahadriver = { ahaprobe, 0, ahaattach, "aha", 0, 0, 0};
+int (*ahaintrs[])() = {ahaintr, 0};
+#endif
+#ifdef __386BSD__
+struct isa_driver ahadriver = { ahaprobe, ahaattach, "aha",};
+#endif __386BSD__
+static int ahaunit = 0;
+
+
+#define aha_abortmbx(mbx) \
+ (mbx)->cmd = AHA_MBO_ABORT; \
+ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
+#define aha_startmbx(mbx) \
+ (mbx)->cmd = AHA_MBO_START; \
+ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
+
+
+
+int aha_scsi_cmd();
+int aha_timeout();
+void ahaminphys();
+long int aha_adapter_info();
+
+struct scsi_switch aha_switch =
+{
+ aha_scsi_cmd,
+ ahaminphys,
+ 0,
+ 0,
+ aha_adapter_info,
+ 0,0,0
+};
+#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */
+#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */
+#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */
+
+
+/***********************************************************************\
+* aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args) *
+* Activate Adapter command *
+* icnt: number of args (outbound bytes written after opcode) *
+* ocnt: number of expected returned bytes *
+* wait: number of seconds to wait for response *
+* retval: buffer where to place returned bytes *
+* opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... *
+* args: parameters *
+* *
+* Performs an adapter command through the ports. Not to be confused *
+* with a scsi command, which is read in via the dma *
+* One of the adapter commands tells it to read in a scsi command *
+\***********************************************************************/
+
+
+aha_cmd(unit,icnt, ocnt, wait,retval, opcode, args)
+
+u_char *retval;
+unsigned opcode;
+u_char args;
+{
+ unsigned *ic = &opcode;
+ u_char oc;
+ register i;
+ int sts;
+
+ /*******************************************************\
+ * multiply the wait argument by a big constant *
+ * zero defaults to 1 *
+ \*******************************************************/
+ if(!wait)
+ wait = AHA_CMD_TIMEOUT_FUDGE * delaycount;
+ else
+ wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount;
+ /*******************************************************\
+ * Wait for the adapter to go idle, unless it's one of *
+ * the commands which don't need this *
+ \*******************************************************/
+ if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI)
+ {
+ i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/
+ while (--i)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts & AHA_IDLE)
+ {
+ break;
+ }
+ }
+ if (!i)
+ {
+ printf("aha_cmd: aha1542 host not idle(0x%x)\n",sts);
+ return(ENXIO);
+ }
+ }
+ /*******************************************************\
+ * Now that it is idle, if we expect output, preflush the*
+ * queue feeding to us. *
+ \*******************************************************/
+ if (ocnt)
+ {
+ while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
+ inb(AHA_CMD_DATA_PORT);
+ }
+
+ /*******************************************************\
+ * Output the command and the number of arguments given *
+ * for each byte, first check the port is empty. *
+ \*******************************************************/
+ icnt++; /* include the command */
+ while (icnt--)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ for (i=0; i< wait; i++)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (!(sts & AHA_CDF))
+ break;
+ }
+ if (i >= wait)
+ {
+ printf("aha_cmd: aha1542 cmd/data port full\n");
+ outb(AHA_CTRL_STAT_PORT, AHA_SRST);
+ return(ENXIO);
+ }
+ outb(AHA_CMD_DATA_PORT, (u_char)(*ic++));
+ }
+ /*******************************************************\
+ * If we expect input, loop that many times, each time, *
+ * looking for the data register to have valid data *
+ \*******************************************************/
+ while (ocnt--)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ for (i=0; i< wait; i++)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts & AHA_DF)
+ break;
+ }
+ if (i >= wait)
+ {
+ printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt);
+ return(ENXIO);
+ }
+ oc = inb(AHA_CMD_DATA_PORT);
+ if (retval)
+ *retval++ = oc;
+ }
+ /*******************************************************\
+ * Wait for the board to report a finised instruction *
+ \*******************************************************/
+ i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */
+ while (--i)
+ {
+ sts = inb(AHA_INTR_PORT);
+ if (sts & AHA_HACC)
+ {
+ break;
+ }
+ }
+ if (!i)
+ {
+ printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts);
+ return(ENXIO);
+ }
+ outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+ return(0);
+}
+
+/*******************************************************\
+* Check if the device can be found at the port given *
+* and if so, set it up ready for further work *
+* as an argument, takes the isa_dev structure from *
+* autoconf.c *
+\*******************************************************/
+ahaprobe(dev)
+struct isa_dev *dev;
+{
+ int unit = ahaunit;
+#if defined(OSF)
+ static ihandler_t aha_handler[NAHA];
+ static ihandler_id_t *aha_handler_id[NAHA];
+ register ihandler_t *chp = &aha_handler[unit];;
+#endif /* defined(OSF) */
+
+ /***********************************************\
+ /***********************************************\
+ * find unit and check we have that many defined *
+ \***********************************************/
+ dev->dev_unit = unit;
+ aha_base[unit] = dev->dev_addr;
+ if(unit >= NAHA)
+ {
+ printf("aha: unit number (%d) too high\n",unit);
+ return(0);
+ }
+ /***********************************************\
+ * Try initialise a unit at this location *
+ * sets up dma and bus speed, loads aha_int[unit]*
+ \***********************************************/
+ if (aha_init(unit) != 0)
+ {
+ return(0);
+ }
+
+ /***********************************************\
+ * If it's there, put in it's interrupt vectors *
+ \***********************************************/
+#if !defined(OSF)
+#if defined MACH
+ iunit[aha_int[unit]] =unit;
+ ivect[aha_int[unit]] = ahaintr;
+ intpri[aha_int[unit]] = dev->dev_spl;
+ form_pic_mask();
+ /*take_dev_irq(dev);*/
+#else
+#ifdef __386BSD__
+ dev->id_irq = (1 << aha_int[unit]);
+ dev->id_drq = aha_dma[unit];
+#endif __386BSD__
+#endif
+#else /* !defined(OSF) */
+
+ chp->ih_level = dev->dev_pic;
+ chp->ih_handler = dev->dev_intr[0];
+ chp->ih_resolver = i386_resolver;
+ chp->ih_rdev = dev;
+ chp->ih_stats.intr_type = INTR_DEVICE;
+ chp->ih_stats.intr_cnt = 0;
+ chp->ih_hparam[0].intparam = unit;
+ if ((aha_handler_id[unit] = handler_add(chp)) != NULL)
+ handler_enable(aha_handler_id[unit]);
+ else
+ panic("Unable to add aha interrupt handler");
+#endif /* !defined(OSF) */
+#ifdef __386BSD__
+ printf("\n **");
+#else __386BSD__
+ printf("port=%x spl=%d\n",
+ dev->dev_addr, dev->dev_spl);
+#endif __386BSD__
+ ahaunit ++;
+ return(1);
+}
+
+/***********************************************\
+* Attach all the sub-devices we can find *
+\***********************************************/
+ahaattach(dev)
+struct isa_dev *dev;
+{
+ int unit = dev->dev_unit;
+
+#ifdef __386BSD__
+ printf(" probing for scsi devices**\n");
+#endif __386BSD__
+ /***********************************************\
+ * ask the adapter what subunits are present *
+ \***********************************************/
+ scsi_attachdevs( unit, aha_scsi_dev[unit], &aha_switch);
+#if defined(OSF)
+ aha_attached[unit]=1;
+#endif /* defined(OSF) */
+ if(!unit) /* only one for all boards */
+ {
+ aha_timeout(0);
+ }
+#ifdef __386BSD__
+ printf("aha%d",unit);
+#endif __386BSD__
+ return;
+
+}
+
+
+/***********************************************\
+* Return some information to the caller about *
+* the adapter and it's capabilities *
+\***********************************************/
+long int aha_adapter_info(unit)
+int unit;
+{
+ return(2); /* 2 outstanding requests at a time per device */
+}
+
+/***********************************************\
+* Catch an interrupt from the adaptor *
+\***********************************************/
+ahaintr(unit)
+{
+ struct aha_ccb *ccb;
+ unsigned char stat;
+ register i;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("ahaintr ");
+ /***********************************************\
+ * First acknowlege the interrupt, Then if it's *
+ * not telling about a completed operation *
+ * just return. *
+ \***********************************************/
+ stat = inb(AHA_INTR_PORT);
+ outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("int ");
+ if (! (stat & AHA_MBIF))
+ return(1);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("b ");
+#if defined(OSF)
+ if (!aha_attached[unit])
+ {
+ return(1);
+ }
+#endif /* defined(OSF) */
+ /***********************************************\
+ * If it IS then process the competed operation *
+ \***********************************************/
+ for (i = 0; i < AHA_MBX_SIZE; i++)
+ {
+ if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE)
+ {
+ ccb = (struct aha_ccb *)PHYSTOKV(
+ (_3btol(aha_mbx[unit].mbi[i].ccb_addr)));
+
+ if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK)
+ {
+ switch(stat)
+ {
+ case AHA_MBI_ABORT:
+ if(aha_debug)
+ printf("abort");
+ ccb->host_stat = AHA_ABORTED;
+ break;
+
+ case AHA_MBI_UNKNOWN:
+ ccb = (struct aha_ccb *)0;
+ if(aha_debug)
+ printf("unknown ccb for abort ");
+ /* may have missed it */
+ /* no such ccb known for abort */
+
+ case AHA_MBI_ERROR:
+ break;
+
+ default:
+ panic("Impossible mbxi status");
+
+ }
+ if( aha_debug && ccb )
+ {
+ u_char *cp;
+ cp = (u_char *)(&(ccb->scsi_cmd));
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2],
+ cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi[%d]\n"
+ , aha_mbx[unit].mbi[i].stat, i);
+ printf("addr = 0x%x\n", ccb);
+ }
+ }
+ if(ccb)
+ {
+ aha_remove_timeout(ccb);
+ aha_done(unit,ccb);
+ }
+ aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
+ }
+ }
+ return(1);
+}
+
+/***********************************************\
+* A ccb (and hence a mbx-out is put onto the *
+* free list. *
+\***********************************************/
+aha_free_ccb(unit,ccb, flags)
+struct aha_ccb *ccb;
+{
+ unsigned int opri;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("ccb%d(0x%x)> ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ccb->next = aha_ccb_free[unit];
+ aha_ccb_free[unit] = ccb;
+ ccb->flags = CCB_FREE;
+ if(ccb->sooner || ccb->later)
+ {
+ printf("yikes, still in timeout queue\n");
+ aha_remove_timeout(ccb);
+ }
+ /***********************************************\
+ * If there were none, wake abybody waiting for *
+ * one to come free, starting with queued entries*
+ \***********************************************/
+ if (!ccb->next) {
+ wakeup(&aha_ccb_free[unit]);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/***********************************************\
+* Get a free ccb (and hence mbox-out entry) *
+\***********************************************/
+struct aha_ccb *
+aha_get_ccb(unit,flags)
+{
+ unsigned opri;
+ struct aha_ccb *rc;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("<ccb%d(0x%x) ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /***********************************************\
+ * If we can and have to, sleep waiting for one *
+ * to come free *
+ \***********************************************/
+ while ((!(rc = aha_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP)))
+ {
+ sleep(&aha_ccb_free[unit], PRIBIO);
+ }
+ if (rc)
+ {
+ aha_ccb_free[unit] = aha_ccb_free[unit]->next;
+ rc->flags = CCB_ACTIVE;
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+ return(rc);
+}
+
+
+/***********************************************\
+* We have a ccb which has been processed by the *
+* adaptor, now we look to see how the operation *
+* went. Wake up the owner if waiting *
+\***********************************************/
+aha_done(unit,ccb)
+struct aha_ccb *ccb;
+{
+ struct scsi_sense_data *s1,*s2;
+ struct scsi_xfer *xs = ccb->xfer;
+
+ if(scsi_debug & PRINTROUTINES )
+ printf("aha_done ");
+ /***********************************************\
+ * Otherwise, put the results of the operation *
+ * into the xfer and call whoever started it *
+ \***********************************************/
+ if(!(xs->flags & INUSE))
+ {
+ printf("exiting but not in use! ");
+ Debugger();
+ }
+ if ( ( ccb->host_stat != AHA_OK
+ || ccb->target_stat != SCSI_OK)
+ && (!(xs->flags & SCSI_ERR_OK)))
+ {
+ s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd))
+ + ccb->scsi_cmd_length);
+ s2 = &(xs->sense);
+
+ if(ccb->host_stat)
+ {
+ switch(ccb->host_stat)
+ {
+ case AHA_ABORTED:
+ case AHA_SEL_TIMEOUT: /* No response */
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ if (aha_debug > 1)
+ {
+ printf("host_stat%x\n",
+ ccb->host_stat);
+ }
+ }
+
+ }
+ else
+ {
+ switch(ccb->target_stat)
+ {
+ case 0x02:
+ /* structure copy!!!!!*/
+ *s2=*s1;
+ xs->error = XS_SENSE;
+ break;
+ case 0x08:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ if (aha_debug > 1)
+ {
+ printf("target_stat%x\n",
+ ccb->target_stat);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+ else /* All went correctly OR errors expected */
+ {
+ xs->resid = 0;
+ }
+ xs->flags |= ITSDONE;
+ aha_free_ccb(unit,ccb, xs->flags);
+ if(xs->when_done)
+ (*(xs->when_done))(xs->done_arg,xs->done_arg2);
+}
+
+
+/***********************************************\
+* Start the board, ready for normal operation *
+\***********************************************/
+aha_init(unit)
+int unit;
+{
+ unsigned char ad[3];
+ volatile int i,sts;
+ struct aha_config conf;
+
+ /***********************************************\
+ * reset board, If it doesn't respond, assume *
+ * that it's not there.. good for the probe *
+ \***********************************************/
+
+ outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST);
+
+ for (i=0; i < AHA_RESET_TIMEOUT; i++)
+ {
+ sts = inb(AHA_CTRL_STAT_PORT) ;
+ if ( sts == (AHA_IDLE | AHA_INIT))
+ break;
+ }
+ if (i >= AHA_RESET_TIMEOUT)
+ {
+ if (aha_debug)
+ printf("aha_init: No answer from adaptec board\n");
+ return(ENXIO);
+ }
+
+ /***********************************************\
+ * Assume we have a board at this stage *
+ * setup dma channel from jumpers and save int *
+ * level *
+ \***********************************************/
+#ifdef __386BSD__
+ printf("aha%d reading board settings, ",unit);
+#define PRNT(x)
+#else __386BSD__
+ printf("aha%d:",unit);
+#define PRNT(x) printf(x)
+#endif __386BSD__
+ aha_cmd(unit,0, sizeof(conf), 0 ,&conf, AHA_CONF_GET);
+ switch(conf.chan)
+ {
+ case CHAN0:
+ outb(0x0b, 0x0c);
+ outb(0x0a, 0x00);
+ aha_dma[unit] = 0;
+ PRNT("dma=0 ");
+ break;
+ case CHAN5:
+ outb(0xd6, 0xc1);
+ outb(0xd4, 0x01);
+ aha_dma[unit] = 5;
+ PRNT("dma=5 ");
+ break;
+ case CHAN6:
+ outb(0xd6, 0xc2);
+ outb(0xd4, 0x02);
+ aha_dma[unit] = 6;
+ PRNT("dma=6 ");
+ break;
+ case CHAN7:
+ outb(0xd6, 0xc3);
+ outb(0xd4, 0x03);
+ aha_dma[unit] = 7;
+ PRNT("dma=7 ");
+ break;
+ default:
+ printf("illegal dma jumper setting\n");
+ return(EIO);
+ }
+ switch(conf.intr)
+ {
+ case INT9:
+ aha_int[unit] = 9;
+ PRNT("int=9 ");
+ break;
+ case INT10:
+ aha_int[unit] = 10;
+ PRNT("int=10 ");
+ break;
+ case INT11:
+ aha_int[unit] = 11;
+ PRNT("int=11 ");
+ break;
+ case INT12:
+ aha_int[unit] = 12;
+ PRNT("int=12 ");
+ break;
+ case INT14:
+ aha_int[unit] = 14;
+ PRNT("int=14 ");
+ break;
+ case INT15:
+ aha_int[unit] = 15;
+ PRNT("int=15 ");
+ break;
+ default:
+ printf("illegal int jumper setting\n");
+ return(EIO);
+ }
+ /* who are we on the scsi bus */
+ aha_scsi_dev[unit] = conf.scsi_dev;
+
+
+ /***********************************************\
+ * Initialize memory transfer speed *
+ \***********************************************/
+ if(!(aha_set_bus_speed(unit)))
+ {
+ return(EIO);
+ }
+
+
+ /***********************************************\
+ * Initialize mail box *
+ \***********************************************/
+
+ lto3b(KVTOPHYS(&aha_mbx[unit]), ad);
+
+ aha_cmd(unit,4, 0, 0, 0, AHA_MBX_INIT,
+ AHA_MBX_SIZE,
+ ad[0],
+ ad[1],
+ ad[2]);
+
+
+ /***********************************************\
+ * link the ccb's with the mbox-out entries and *
+ * into a free-list *
+ \***********************************************/
+ for (i=0; i < AHA_MBX_SIZE; i++) {
+ aha_ccb[unit][i].next = aha_ccb_free[unit];
+ aha_ccb_free[unit] = &aha_ccb[unit][i];
+ aha_ccb_free[unit]->flags = CCB_FREE;
+ aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i];
+ lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr);
+ }
+
+ /***********************************************\
+ * Note that we are going and return (to probe) *
+ \***********************************************/
+ aha_initialized[unit]++;
+ return(0);
+}
+
+
+
+
+
+void ahaminphys(bp)
+struct buf *bp;
+{
+#ifdef MACH
+#if !defined(OSF)
+ bp->b_flags |= B_NPAGES; /* can support scat/gather */
+#endif /* !defined(OSF) */
+#endif MACH
+/* aha seems to explode with 17 segs (64k may require 17 segs) */
+/* on old boards so use a max of 16 segs if you have problems here*/
+ if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ))
+ {
+ bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/***********************************************\
+* start a scsi operation given the command and *
+* the data address. Also needs the unit, target *
+* and lu *
+\***********************************************/
+int aha_scsi_cmd(xs)
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1,*s2;
+ struct aha_ccb *ccb;
+ struct aha_scat_gath *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int rc = 0;
+ int thiskv;
+ int thisphys,nextphys;
+ int unit =xs->adapter;
+ int bytes_this_seg,bytes_this_page,datalen,flags;
+ struct iovec *iovp;
+ int s;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("aha_scsi_cmd ");
+ /***********************************************\
+ * get a ccb (mbox-out) to use. If the transfer *
+ * is from a buf (possibly from interrupt time) *
+ * then we can't allow it to sleep *
+ \***********************************************/
+ flags = xs->flags;
+ if(!(flags & INUSE))
+ {
+ printf("not in use!");
+ Debugger();
+ xs->flags |= INUSE;
+ }
+ if(flags & ITSDONE)
+ {
+ printf("Already done! check device retry code ");
+ Debugger();
+ xs->flags &= ~ITSDONE;
+ }
+ if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (!(ccb = aha_get_ccb(unit,flags)))
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+ if (ccb->mbx->cmd != AHA_MBO_FREE)
+ printf("MBO not free\n");
+
+ /***********************************************\
+ * Put all the arguments for the xfer in the ccb *
+ \***********************************************/
+ ccb->xfer = xs;
+ if(flags & SCSI_RESET)
+ {
+ ccb->opcode = AHA_RESET_CCB;
+ }
+ else
+ {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen?
+ AHA_INIT_SCAT_GATH_CCB
+ :AHA_INITIATOR_CCB);
+ }
+ ccb->target = xs->targ;;
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->lun = xs->lu;
+ ccb->scsi_cmd_length = xs->cmdlen;
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+
+ if((xs->datalen) && (!(flags & SCSI_RESET)))
+ { /* can use S/G only if not zero length */
+ lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr );
+ sg = ccb->scat_gath ;
+ seg = 0;
+ if(flags & SCSI_DATA_UIO)
+ {
+ iovp = ((struct uio *)xs->data)->uio_iov;
+ datalen = ((struct uio *)xs->data)->uio_iovcnt;
+ while ((datalen) && (seg < AHA_NSEG))
+ {
+ lto3b(iovp->iov_base,&(sg->seg_addr));
+ lto3b(iovp->iov_len,&(sg->seg_len));
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x@0x%x)"
+ ,iovp->iov_len
+ ,iovp->iov_base);
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ }
+ else
+ {
+ /***********************************************\
+ * Set up the scatter gather block *
+ \***********************************************/
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("%d @0x%x:- ",xs->datalen,xs->data);
+ datalen = xs->datalen;
+ thiskv = (int)xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < AHA_NSEG))
+ {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ lto3b(thisphys,&(sg->seg_addr));
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("0x%x",thisphys);
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /***************************************\
+ * This page is contiguous (physically) *
+ * with the the last, just extend the *
+ * length *
+ \***************************************/
+ {
+ /** how far to the end of the page ***/
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /**** get more ready for the next page ****/
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if(datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /***************************************\
+ * next page isn't contiguous, finish the seg*
+ \***************************************/
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x)",bytes_this_seg);
+ lto3b(bytes_this_seg,&(sg->seg_len));
+ sg++;
+ seg++;
+ }
+ }
+ lto3b(seg * sizeof(struct aha_scat_gath),ccb->data_length);
+ if(scsi_debug & SHOWSCATGATH)
+ printf("\n");
+ if (datalen)
+ { /* there's still data, must have run out of segs! */
+ printf("aha_scsi_cmd%d: more than %d DMA segs\n",
+ unit,AHA_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ aha_free_ccb(unit,ccb,flags);
+ return(HAD_ERROR);
+ }
+
+ }
+ else
+ { /* No data xfer, use non S/G values */
+ lto3b(0, ccb->data_addr );
+ lto3b(0,ccb->data_length);
+ }
+ lto3b(0, ccb->link_addr );
+ /***********************************************\
+ * Put the scsi command in the ccb and start it *
+ \***********************************************/
+ if(!(flags & SCSI_RESET))
+ bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
+ if(scsi_debug & SHOWCOMMANDS)
+ {
+ u_char *b = (u_char *)&ccb->scsi_cmd;
+ if(!(flags & SCSI_RESET))
+ {
+ int i = 0;
+ printf("aha%d:%d:%d-"
+ ,unit
+ ,ccb->target
+ ,ccb->lun );
+ while(i < ccb->scsi_cmd_length )
+ {
+ if(i) printf(",");
+ printf("%x",b[i++]);
+ }
+ }
+ else
+ {
+ printf("aha%d:%d:%d-RESET- "
+ ,unit
+ ,ccb->target
+ ,ccb->lun
+ );
+ }
+ }
+ if (!(flags & SCSI_NOMASK))
+ {
+ s= splbio(); /* stop instant timeouts */
+ aha_add_timeout(ccb,xs->timeout);
+ aha_startmbx(ccb->mbx);
+ /***********************************************\
+ * Usually return SUCCESSFULLY QUEUED *
+ \***********************************************/
+ splx(s);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("sent ");
+ return(SUCCESSFULLY_QUEUED);
+ }
+ aha_startmbx(ccb->mbx);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("cmd_sent, waiting ");
+ /***********************************************\
+ * If we can't use interrupts, poll on completion*
+ \***********************************************/
+ {
+ int done = 0;
+ int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE;
+ while((!done) && count)
+ {
+ i=0;
+ while ( (!done) && i<AHA_MBX_SIZE)
+ {
+ if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
+ && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
+ == (int)ccb)))
+ {
+ aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
+ aha_done(unit,ccb);
+ done++;
+ }
+ i++;
+ }
+ count--;
+ }
+ if (!count)
+ {
+ if (!(xs->flags & SCSI_SILENT))
+ printf("cmd fail\n");
+ aha_abortmbx(ccb->mbx);
+ count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE;
+ while((!done) && count)
+ {
+ i=0;
+ while ( (!done) && i<AHA_MBX_SIZE)
+ {
+ if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
+ && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
+ == (int)ccb)))
+ {
+ aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
+ aha_done(unit,ccb);
+ done++;
+ }
+ i++;
+ }
+ count--;
+ }
+ if(!count)
+ {
+ printf("abort failed in wait\n");
+ ccb->mbx->cmd = AHA_MBO_FREE;
+ }
+ aha_free_ccb(unit,ccb,flags);
+ ahaintr(unit);
+ xs->error = XS_DRIVER_STUFFUP;
+ return(HAD_ERROR);
+ }
+ ahaintr(unit);
+ if(xs->error) return(HAD_ERROR);
+ return(COMPLETE);
+
+ }
+}
+/***************************************************************\
+* try each speed in turn, when we find one that works, use *
+* the NEXT one for a safety margin, unless that doesn't exist *
+* or doesn't work. returns the nSEC value of the time used *
+* or 0 if it could get a working speed ( or the NEXT speed *
+* failed) *
+\***************************************************************/
+
+int aha_set_bus_speed(unit)
+int unit;
+{
+ int speed;
+ int retval,retval2;
+
+#ifdef EISA
+ speed = 0; /* start at the fastest */
+#else EISA
+ speed = 1; /* 100 ns can crash some ISA busses (!?!) */
+#endif EISA
+ while (1)
+ {
+ retval = aha_bus_speed_check(unit,speed);
+ if(retval == HAD_ERROR)
+ {
+ printf("no working bus speed!!!\n");
+ return(0);
+ }
+ if(retval == 0)
+ {
+ speed++;
+ }
+ else /* Go one slower to be safe */
+ { /* unless eisa at 100 ns.. trust it */
+ if(speed != 0)
+ {
+ speed++;
+ }
+ printf("%d nSEC ok, use ",retval);
+ retval2 = aha_bus_speed_check(unit,speed);
+ if(retval2 == HAD_ERROR) /* retval is slowest already */
+ {
+ printf("marginal ");
+ retval2 = retval;
+ }
+ if(retval2)
+ {
+ printf("%d nSEC ",retval2);
+ return(retval2);
+ }
+ else
+ {
+ printf(".. slower failed, abort.\n",retval);
+ return(0);
+ }
+
+ }
+ }
+}
+
+/***************************************************************\
+* Set the DMA speed to the Nth speed and try an xfer. If it *
+* fails return 0, if it succeeds return the nSec value selected *
+* If there is no such speed return HAD_ERROR. *
+\***************************************************************/
+static struct bus_speed
+{
+ char arg;
+ int nsecs;
+}aha_bus_speeds[] =
+{
+ {0x88,100},
+ {0x99,150},
+ {0xaa,200},
+ {0xbb,250},
+ {0xcc,300},
+ {0xdd,350},
+ {0xee,400},
+ {0xff,450}
+};
+static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
+
+int aha_bus_speed_check(unit,speed)
+int unit,speed;
+{
+ int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed);
+ u_char ad[3];
+
+ /*******************************************************\
+ * Check we have such an entry *
+ \*******************************************************/
+ if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */
+
+ /*******************************************************\
+ * Set the dma-speed *
+ \*******************************************************/
+ aha_cmd(unit,1, 0, 0, 0, AHA_SPEED_SET,aha_bus_speeds[speed].arg);
+
+ /*******************************************************\
+ * put the test data into the buffer and calculate *
+ * it's address. Read it onto the board *
+ \*******************************************************/
+ strcpy(aha_scratch_buf,aha_test_string);
+ lto3b(KVTOPHYS(aha_scratch_buf),ad);
+
+ aha_cmd(unit,3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
+
+ /*******************************************************\
+ * clear the buffer then copy the contents back from the *
+ * board. *
+ \*******************************************************/
+ bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */
+
+ aha_cmd(unit,3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
+
+ /*******************************************************\
+ * Compare the original data and the final data and *
+ * return the correct value depending upon the result *
+ \*******************************************************/
+ if(strcmp(aha_test_string,aha_scratch_buf))
+ { /* copy failed.. assume too fast */
+ return(0);
+ }
+ else
+ { /* copy succeded assume speed ok */
+ return(aha_bus_speeds[speed].nsecs);
+ }
+}
+
+
+/*
+ * +----------+ +----------+ +----------+
+ * aha_soonest--->| later |--->| later|--->| later|-->0
+ * | [Delta] | | [Delta] | | [Delta] |
+ * 0<---|sooner |<---|sooner |<---|sooner |<---aha_latest
+ * +----------+ +----------+ +----------+
+ *
+ * aha_furtherest = sum(Delta[1..n])
+ */
+aha_add_timeout(ccb,time)
+struct aha_ccb *ccb;
+int time;
+{
+ int timeprev;
+ struct aha_ccb *prev;
+ int s = splbio();
+
+ if(prev = aha_latest) /* yes, an assign */
+ {
+ timeprev = aha_furtherest;
+ }
+ else
+ {
+ timeprev = 0;
+ }
+ while(prev && (timeprev > time))
+ {
+ timeprev -= prev->delta;
+ prev = prev->sooner;
+ }
+ if(prev)
+ {
+ ccb->delta = time - timeprev;
+ if( ccb->later = prev->later) /* yes an assign */
+ {
+ ccb->later->sooner = ccb;
+ ccb->later->delta -= ccb->delta;
+ }
+ else
+ {
+ aha_furtherest = time;
+ aha_latest = ccb;
+ }
+ ccb->sooner = prev;
+ prev->later = ccb;
+ }
+ else
+ {
+ if( ccb->later = aha_soonest) /* yes, an assign*/
+ {
+ ccb->later->sooner = ccb;
+ ccb->later->delta -= time;
+ }
+ else
+ {
+ aha_furtherest = time;
+ aha_latest = ccb;
+ }
+ ccb->delta = time;
+ ccb->sooner = (struct aha_ccb *)0;
+ aha_soonest = ccb;
+ }
+ splx(s);
+}
+
+aha_remove_timeout(ccb)
+struct aha_ccb *ccb;
+{
+ int s = splbio();
+
+ if(ccb->sooner)
+ {
+ ccb->sooner->later = ccb->later;
+ }
+ else
+ {
+ aha_soonest = ccb->later;
+ }
+ if(ccb->later)
+ {
+ ccb->later->sooner = ccb->sooner;
+ ccb->later->delta += ccb->delta;
+ }
+ else
+ {
+ aha_latest = ccb->sooner;
+ aha_furtherest -= ccb->delta;
+ }
+ ccb->sooner = ccb->later = (struct aha_ccb *)0;
+ splx(s);
+}
+
+
+extern int hz;
+#define ONETICK 500 /* milliseconds */
+#define SLEEPTIME ((hz * 1000) / ONETICK)
+aha_timeout(arg)
+int arg;
+{
+ struct aha_ccb *ccb;
+ int unit;
+ int s = splbio();
+
+ while( ccb = aha_soonest )
+ {
+ if(ccb->delta <= ONETICK)
+ /***********************************************\
+ * It has timed out, we need to do some work *
+ \***********************************************/
+ {
+ unit = ccb->xfer->adapter;
+ printf("aha%d: device %d timed out ",unit
+ ,ccb->xfer->targ);
+
+ /***************************************\
+ * Unlink it from the queue *
+ \***************************************/
+ aha_remove_timeout(ccb);
+
+ /***************************************\
+ * If The ccb's mbx is not free, then *
+ * the board has gone south *
+ \***************************************/
+ if(ccb->mbx->cmd != AHA_MBO_FREE)
+ {
+ printf("aha%d not taking commands!\n"
+ ,unit);
+ Debugger();
+ }
+ /***************************************\
+ * If it has been through before, then *
+ * a previous abort has failed, don't *
+ * try abort again *
+ \***************************************/
+ if(ccb->flags == CCB_ABORTED) /* abort timed out */
+ {
+ printf(" AGAIN\n");
+ ccb->xfer->retries = 0; /* I MEAN IT ! */
+ ccb->host_stat = AHA_ABORTED;
+ aha_done(unit,ccb);
+ }
+ else /* abort the operation that has timed out */
+ {
+ printf("\n");
+ aha_abortmbx(ccb->mbx);
+ /* 2 secs for the abort */
+ aha_add_timeout(ccb,2000 + ONETICK);
+ ccb->flags = CCB_ABORTED;
+ }
+ }
+ else
+ /***********************************************\
+ * It has not timed out, adjust and leave *
+ \***********************************************/
+ {
+ ccb->delta -= ONETICK;
+ aha_furtherest -= ONETICK;
+ break;
+ }
+ }
+ splx(s);
+ timeout(aha_timeout,arg,SLEEPTIME);
+}
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
new file mode 100644
index 0000000..0fb7701
--- /dev/null
+++ b/sys/i386/isa/clock.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 14 Aug 92 Arne Henrik Juul Added code in the kernel to
+ * allow for DST in the BIOS.
+ * 17 Jan 93 Bruce Evans Fixed leap year and second
+ * calculations
+ * 01 Feb 93 Julian Elischer Added code to for the cpu
+ * speed independent spinwait()
+ * function, (used by scsi and others)
+ * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1
+ * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock
+ * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait
+ * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I
+ * still kept the other fixes... Had to
+ * add back in findcpuspeed that Bruce
+ * had removed.
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+#define DAYST 119
+#define DAYEN 303
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+
+startrtclock() {
+ int s;
+
+ findcpuspeed(); /* use the clock (while it's free)
+ to find the cpu speed */
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
+ outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+ outb (IO_RTC, RTC_DIAG);
+ outb (IO_RTC+1, 0);
+}
+
+unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
+
+#define FIRST_GUESS 0x2000
+findcpuspeed()
+{
+ unsigned char low;
+ unsigned int remainder;
+
+ /* Put counter in count down mode */
+ outb(IO_TIMER1+3, 0x34);
+ outb(IO_TIMER1, 0xff);
+ outb(IO_TIMER1, 0xff);
+ delaycount = FIRST_GUESS;
+ spinwait(1);
+ /* Read the value left in the counter */
+ low = inb(IO_TIMER1); /* least siginifcant */
+ remainder = inb(IO_TIMER1); /* most significant */
+ remainder = (remainder<<8) + low ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ */
+ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
+}
+
+
+/* convert 2 digit BCD number */
+bcd(i)
+int i;
+{
+ return ((i/16)*10 + (i%16));
+}
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(y)
+int y;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+/* convert months to seconds */
+unsigned long
+mtos(m,leap)
+int m,leap;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1;i<m;i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+inittodr(base)
+ time_t base;
+{
+ unsigned long sec;
+ int leap,day_week,t,yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+
+ /* XXX off by one? Need to calculate DST on SUNDAY */
+ /* Perhaps we should have the RTC hold GMT time to save */
+ /* us the bother of converting. */
+ yd = yd / (24*60*60);
+ if ((yd >= DAYST) && ( yd <= DAYEN)) {
+ sec -= 60*60;
+ }
+ sec += tz.tz_minuteswest * 60;
+
+ time.tv_sec = sec;
+}
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(base)
+ time_t base;
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Restart the clock.
+ */
+resettodr()
+{
+}
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern V(clk)();
+enablertclock() {
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(millisecs)
+ int millisecs;
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
new file mode 100644
index 0000000..a461e81
--- /dev/null
+++ b/sys/i386/isa/fd.c
@@ -0,0 +1,903 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fd.c 7.4 (Berkeley) 5/25/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ *
+ * Largely rewritten to handle multiple controllers and drives
+ * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993
+ */
+char rev[] = "$Revision: 1.10 $";
+/*
+ * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $
+ */
+/*
+ * $Log: fd.c,v $
+ * Revision 1.10 93/04/13 16:53:29 root
+ * make sure turning off a drive motor doesn't deselect another
+ * drive active at the time.
+ * Also added a pointer from the fd_data to it's fd_type.
+ *
+ * Revision 1.9 93/04/13 15:31:02 root
+ * make all seeks go through DOSEEK state so are sure of being done right.
+ *
+ * Revision 1.8 93/04/12 21:20:13 root
+ * only check if old fd is the one we are working on if there IS
+ * an old fd pointer. (in fdstate())
+ *
+ * Revision 1.7 93/04/11 17:05:35 root
+ * cleanup timeouts etc.
+ * also fix bug to select teh correct drive when running > 1 drive
+ * at a time.
+ *
+ * Revision 1.6 93/04/05 00:48:45 root
+ * change a timeout and add version to banner message
+ *
+ * Revision 1.5 93/04/04 16:39:08 root
+ * first working version.. some floppy controllers don't seem to
+ * like 2 int. status inquiries in a row.
+ *
+ */
+
+#include "fd.h"
+#if NFD > 0
+
+#include "param.h"
+#include "dkbad.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "ioctl.h"
+#include "buf.h"
+#include "uio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+#undef NFD
+#define NFD 2
+
+#define FDUNIT(s) ((s>>3)&1)
+#define FDTYPE(s) ((s)&7)
+
+#define b_cylin b_resid
+#define FDBLK 512
+#define NUMTYPES 4
+
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int gap; /* gap len between sectors */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int steptrac; /* steps per cylinder */
+ int trans; /* transfer speed code */
+ int heads; /* number of heads */
+};
+
+struct fd_type fd_types[NUMTYPES] =
+{
+ { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */
+ { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */
+ { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */
+ { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */
+};
+
+#define DRVS_PER_CTLR 2
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+}fdc_data[(NFD+1)/DRVS_PER_CTLR];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (presently 2) (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc;
+ int fdu; /* this unit number */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else DEBUG
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif DEBUG
+
+extern int hz;
+/* state needed for current transfer */
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+int fdprobe(), fdattach(), fd_turnoff();
+
+struct isa_driver fddriver = {
+ fdprobe, fdattach, "fd",
+};
+
+/*
+ * probe for existance of controller
+ */
+fdprobe(dev)
+struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+fdattach(dev)
+struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+
+ fdt = rtcin(RTC_FDISKETTE);
+ hdr = 0;
+
+ /* check for each floppy drive */
+ for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0;
+ ((fdu < NFD) && (fdsu < DRVS_PER_CTLR));
+ fdu++,fdsu++)
+ {
+ /* is there a unit? */
+ if ((fdt & 0xf0) == RTCFDT_NONE)
+ continue;
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd_data[fdu].track = -2;
+ fd_data[fdu].fdc = fdc;
+ fd_data[fdu].fdsu = fdsu;
+ /* yes, announce it */
+ if (!hdr)
+ printf(" drives ");
+ else
+ printf(", ");
+ printf("%d: ", fdu);
+
+
+ if ((fdt & 0xf0) == RTCFDT_12M) {
+ printf("1.2M");
+ fd_data[fdu].type = 1;
+ fd_data[fdu].ft = fd_types + 1;
+
+ }
+ if ((fdt & 0xf0) == RTCFDT_144M) {
+ printf("1.44M");
+ fd_data[fdu].type = 0;
+ fd_data[fdu].ft = fd_types + 0;
+ }
+
+ fdt <<= 4;
+ fd_turnoff(fdu);
+ hdr = 1;
+ }
+
+ printf(" %s ",rev);
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+}
+
+int
+fdsize(dev)
+dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+fdstrategy(bp)
+ register struct buf *bp; /* IO operation to perform */
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+ /*type = FDTYPE(minor(bp->b_dev));*/
+
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff,fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+set_motor(fdcu_t fdcu, fdu_t fdu, int reset)
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+fd_turnoff(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+fd_motor_on(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fd_pseudointr(fd->fdc->fdcu);
+ }
+}
+
+fd_turnon(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */
+ }
+}
+
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu_t fdcu)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+out_fdc(fdcu_t fdcu,int x)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i = 100000;
+
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1);
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+static fdopenf;
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ /*int type = FDTYPE(minor(dev));*/
+ int s;
+
+ /* check bounds */
+ if (fdu >= NFD) return(ENXIO);
+ /*if (type >= NUMTYPES) return(ENXIO);*/
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+fdclose(dev, flags)
+ dev_t dev;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+fdstart(fdcu_t fdcu)
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+fd_timeout(fdcu_t fdcu)
+{
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+
+ dp = &fdc_data[fdcu].head;
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fd_pseudointr(fdcu);
+}
+
+/* just ensure it has the right spl */
+fd_pseudointr(fdcu_t fdcu)
+{
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ while(fdstate(fdcu, fdc));
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int fdstate(fdcu_t fdcu, fdc_p fdc)
+{
+ int read,head,trac,sec,i,s,sectrac,cyl,st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, fdu);
+ timeout(fd_turnoff,fdu,4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ return(0); /* will return later */
+ case SEEKWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu,
+ descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout,fdcu,2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout,fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+retrier(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ printf("fd%d: hard error (ST0 %b ",
+ fdc->fdu, fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[4], fdc->status[5], fdc->status[6]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+#endif
+
diff --git a/sys/i386/isa/fdreg.h b/sys/i386/isa/fdreg.h
new file mode 100644
index 0000000..948f566
--- /dev/null
+++ b/sys/i386/isa/fdreg.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
+
diff --git a/sys/i386/isa/ic/i8042.h b/sys/i386/isa/ic/i8042.h
new file mode 100644
index 0000000..4d04ce5
--- /dev/null
+++ b/sys/i386/isa/ic/i8042.h
@@ -0,0 +1,23 @@
+#define KBSTATP 0x64 /* kbd controller status port (I) */
+#define KBS_DIB 0x01 /* kbd data in buffer */
+#define KBS_IBF 0x02 /* kbd input buffer low */
+#define KBS_WARM 0x04 /* kbd input buffer low */
+#define KBS_OCMD 0x08 /* kbd output buffer has command */
+#define KBS_NOSEC 0x10 /* kbd security lock not engaged */
+#define KBS_TERR 0x20 /* kbd transmission error */
+#define KBS_RERR 0x40 /* kbd receive error */
+#define KBS_PERR 0x80 /* kbd parity error */
+
+#define KBCMDP 0x64 /* kbd controller port (O) */
+#define KBDATAP 0x60 /* kbd data port (I) */
+#define KBOUTP 0x60 /* kbd data port (O) */
+
+#define K_LDCMDBYTE 0x60
+
+#define KC8_TRANS 0x40 /* convert to old scan codes */
+#define KC8_OLDPC 0x20 /* old 9bit codes instead of new 11bit */
+#define KC8_DISABLE 0x10 /* disable keyboard */
+#define KC8_IGNSEC 0x08 /* ignore security lock */
+#define KC8_CPU 0x04 /* exit from protected mode reset */
+#define KC8_IEN 0x01 /* enable interrupt */
+#define CMDBYTE (KC8_TRANS|KC8_IGNSEC|KC8_CPU|KC8_IEN)
diff --git a/sys/i386/isa/ic/i8237.h b/sys/i386/isa/ic/i8237.h
new file mode 100644
index 0000000..dc269f2
--- /dev/null
+++ b/sys/i386/isa/ic/i8237.h
@@ -0,0 +1,9 @@
+/*
+ * Intel 8237 DMA Controller
+ */
+
+#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
+#define DMA37MD_READ 0x08 /* write the device, read memory operation */
+
diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h
new file mode 100644
index 0000000..b84b46e
--- /dev/null
+++ b/sys/i386/isa/ic/nec765.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/i386/isa/ic/ns16450.h b/sys/i386/isa/ic/ns16450.h
new file mode 100644
index 0000000..f059035
--- /dev/null
+++ b/sys/i386/isa/ic/ns16450.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ns16450.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16450 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/i386/isa/ic/ns16550.h b/sys/i386/isa/ic/ns16550.h
new file mode 100644
index 0000000..e20e9aa
--- /dev/null
+++ b/sys/i386/isa/ic/ns16550.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h
new file mode 100644
index 0000000..4866d8d
--- /dev/null
+++ b/sys/i386/isa/icu.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)icu.h 5.6 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00158
+ * -------------------- ----- ----------------------
+ *
+ * 25 Apr 93 Bruce Evans New fast interrupt code (intr-0.1)
+ */
+
+/*
+ * AT/386 Interrupt Control constants
+ * W. Jolitz 8/89
+ */
+
+#ifndef __ICU__
+#define __ICU__
+
+#ifndef LOCORE
+
+/*
+ * Interrupt "level" mechanism variables, masks, and macros
+ */
+extern unsigned imen; /* interrupt mask enable */
+extern unsigned cpl; /* current priority level mask */
+
+extern unsigned highmask; /* group of interrupts masked with splhigh() */
+extern unsigned ttymask; /* group of interrupts masked with spltty() */
+extern unsigned biomask; /* group of interrupts masked with splbio() */
+extern unsigned netmask; /* group of interrupts masked with splimp() */
+
+#define INTREN(s) (imen &= ~(s), SET_ICUS())
+#define INTRDIS(s) (imen |= (s), SET_ICUS())
+#define INTRMASK(msk,s) (msk |= (s))
+#if 0
+#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8))
+#else
+/*
+ * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to
+ * include isa.h, while too many things include icu.h.
+ */
+#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8))
+#endif
+
+#endif
+
+/*
+ * Interrupt enable bits -- in order of priority
+ */
+#define IRQ0 0x0001 /* highest priority - timer */
+#define IRQ1 0x0002
+#define IRQ_SLAVE 0x0004
+#define IRQ8 0x0100
+#define IRQ9 0x0200
+#define IRQ2 IRQ9
+#define IRQ10 0x0400
+#define IRQ11 0x0800
+#define IRQ12 0x1000
+#define IRQ13 0x2000
+#define IRQ14 0x4000
+#define IRQ15 0x8000
+#define IRQ3 0x0008
+#define IRQ4 0x0010
+#define IRQ5 0x0020
+#define IRQ6 0x0040
+#define IRQ7 0x0080 /* lowest - parallel printer */
+
+/*
+ * Interrupt Control offset into Interrupt descriptor table (IDT)
+ */
+#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
+#define ICU_LEN 16 /* 32-47 are ISA interrupts */
+
+#endif __ICU__
diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s
new file mode 100644
index 0000000..1b93c65
--- /dev/null
+++ b/sys/i386/isa/icu.s
@@ -0,0 +1,376 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)icu.s 7.2 (Berkeley) 5/21/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00167
+ * -------------------- ----- ----------------------
+ *
+ * 28 Nov 92 Frank MacLachlan Aligned addresses and data
+ * on 32bit boundaries.
+ * 24 Mar 93 Rodney W. Grimes Added interrupt counters for vmstat
+ * also stray and false intr counters added
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 25 Apr 93 Bruce Evans Support new interrupt code (intr-0.1)
+ * Rodney W. Grimes Reimplement above patches..
+ * 17 May 93 Rodney W. Grimes Redid the interrupt counter stuff
+ * moved the counters to vectors.s so
+ * they are next to the name tables.
+ * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple
+ * devices configed on the same irq with
+ * respect to ipending. Restructured
+ * not to use BUILD_VECTORS.
+ * Rodney W. Grimes softsio1 only works if you have sio
+ * serial driver, added #include sio.h
+ * and #ifdef NSIO > 0 to protect it.
+ */
+
+/*
+ * AT/386
+ * Vector interrupt control section
+ */
+
+/*
+ * XXX - this file is now misnamed. All spls are now soft and the only thing
+ * related to the hardware icu is that the bit numbering is the same in the
+ * soft priority masks as in the hard ones.
+ */
+
+#include "sio.h"
+#define HIGHMASK 0xffff
+#define SOFTCLOCKMASK 0x8000
+
+ .data
+ .globl _cpl
+_cpl: .long 0xffff # current priority (all off)
+ .globl _imen
+_imen: .long 0xffff # interrupt mask enable (all off)
+# .globl _highmask
+_highmask: .long HIGHMASK
+ .globl _ttymask
+_ttymask: .long 0
+ .globl _biomask
+_biomask: .long 0
+ .globl _netmask
+_netmask: .long 0
+ .globl _ipending
+_ipending: .long 0
+vec:
+ .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7
+ .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15
+
+#define GENSPL(name, mask, event) \
+ .globl _spl/**/name ; \
+ ALIGN_TEXT ; \
+_spl/**/name: ; \
+ COUNT_EVENT(_intrcnt_spl, event) ; \
+ movl _cpl,%eax ; \
+ movl %eax,%edx ; \
+ orl mask,%edx ; \
+ movl %edx,_cpl ; \
+ SHOW_CPL ; \
+ ret
+
+#define FASTSPL(mask) \
+ movl mask,_cpl ; \
+ SHOW_CPL
+
+#define FASTSPL_VARMASK(varmask) \
+ movl varmask,%eax ; \
+ movl %eax,_cpl ; \
+ SHOW_CPL
+
+ .text
+
+ ALIGN_TEXT
+unpend_v:
+ COUNT_EVENT(_intrcnt_spl, 0)
+ bsfl %eax,%eax # slow, but not worth optimizing
+ btrl %eax,_ipending
+ jnc unpend_v_next # some intr cleared the in-memory bit
+ SHOW_IPENDING
+ movl Vresume(,%eax,4),%eax
+ testl %eax,%eax
+ je noresume
+ jmp %eax
+
+ ALIGN_TEXT
+/*
+ * XXX - must be some fastintr, need to register those too.
+ */
+noresume:
+#if NSIO > 0
+ call _softsio1
+#endif
+unpend_v_next:
+ movl _cpl,%eax
+ movl %eax,%edx
+ notl %eax
+ andl _ipending,%eax
+ je none_to_unpend
+ jmp unpend_v
+
+/*
+ * Handle return from interrupt after device handler finishes
+ */
+ ALIGN_TEXT
+doreti:
+ COUNT_EVENT(_intrcnt_spl, 1)
+ addl $4,%esp # discard unit arg
+ popl %eax # get previous priority
+/*
+ * Now interrupt frame is a trap frame!
+ *
+ * XXX - setting up the interrupt frame to be almost a stack frame is mostly
+ * a waste of time.
+ */
+ movl %eax,_cpl
+ SHOW_CPL
+ movl %eax,%edx
+ notl %eax
+ andl _ipending,%eax
+ jne unpend_v
+none_to_unpend:
+ testl %edx,%edx # returning to zero priority?
+ jne 1f # nope, going to non-zero priority
+ movl _netisr,%eax
+ testl %eax,%eax # check for softint s/traps
+ jne 2f # there are some
+ jmp test_resched # XXX - schedule jumps better
+ COUNT_EVENT(_intrcnt_spl, 2) # XXX
+
+ ALIGN_TEXT # XXX
+1: # XXX
+ COUNT_EVENT(_intrcnt_spl, 3)
+ popl %es
+ popl %ds
+ popal
+ addl $8,%esp
+ iret
+
+#include "../net/netisr.h"
+
+#define DONET(s, c, event) ; \
+ .globl c ; \
+ btrl $s,_netisr ; \
+ jnc 1f ; \
+ COUNT_EVENT(_intrcnt_spl, event) ; \
+ call c ; \
+1:
+
+ ALIGN_TEXT
+2:
+ COUNT_EVENT(_intrcnt_spl, 4)
+/*
+ * XXX - might need extra locking while testing reg copy of netisr, but
+ * interrupt routines setting it would not cause any new problems (since we
+ * don't loop, fresh bits will not be processed until the next doreti or spl0).
+ */
+ testl $~((1 << NETISR_SCLK) | (1 << NETISR_AST)),%eax
+ je test_ASTs # no net stuff, just temporary AST's
+ FASTSPL_VARMASK(_netmask)
+ DONET(NETISR_RAW, _rawintr, 5)
+#ifdef INET
+ DONET(NETISR_IP, _ipintr, 6)
+#endif
+#ifdef IMP
+ DONET(NETISR_IMP, _impintr, 7)
+#endif
+#ifdef NS
+ DONET(NETISR_NS, _nsintr, 8)
+#endif
+ FASTSPL($0)
+test_ASTs:
+ btrl $NETISR_SCLK,_netisr
+ jnc test_resched
+ COUNT_EVENT(_intrcnt_spl, 9)
+ FASTSPL($SOFTCLOCKMASK)
+/*
+ * Back to an interrupt frame for a moment.
+ */
+ pushl $0 # previous cpl (probably not used)
+ pushl $0x7f # dummy unit number
+ call _softclock
+ addl $8,%esp # discard dummies
+ FASTSPL($0)
+test_resched:
+#ifdef notused1
+ btrl $NETISR_AST,_netisr
+ jnc 2f
+#endif
+#ifdef notused2
+ cmpl $0,_want_resched
+ je 2f
+#endif
+ cmpl $0,_astpending # XXX - put it back in netisr to
+ je 2f # reduce the number of tests
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ # to non-kernel (i.e., user)?
+ je 2f # nope, leave
+ COUNT_EVENT(_intrcnt_spl, 10)
+ movl $0,_astpending
+ call _trap
+2:
+ COUNT_EVENT(_intrcnt_spl, 11)
+ popl %es
+ popl %ds
+ popal
+ addl $8,%esp
+ iret
+
+/*
+ * Interrupt priority mechanism
+ * -- soft splXX masks with group mechanism (cpl)
+ * -- h/w masks for currently active or unused interrupts (imen)
+ * -- ipending = active interrupts currently masked by cpl
+ */
+
+ GENSPL(bio, _biomask, 12)
+ GENSPL(clock, $HIGHMASK, 13) /* splclock == splhigh ex for count */
+ GENSPL(high, $HIGHMASK, 14)
+ GENSPL(imp, _netmask, 15) /* splimp == splnet except for count */
+ GENSPL(net, _netmask, 16)
+ GENSPL(softclock, $SOFTCLOCKMASK, 17)
+ GENSPL(tty, _ttymask, 18)
+
+ .globl _splnone
+ .globl _spl0
+ ALIGN_TEXT
+_splnone:
+_spl0:
+ COUNT_EVENT(_intrcnt_spl, 19)
+in_spl0:
+ movl _cpl,%eax
+ pushl %eax # save old priority
+ testl $(1 << NETISR_RAW) | (1 << NETISR_IP),_netisr
+ je over_net_stuff_for_spl0
+ movl _netmask,%eax # mask off those network devices
+ movl %eax,_cpl # set new priority
+ SHOW_CPL
+/*
+ * XXX - what about other net intrs?
+ */
+ DONET(NETISR_RAW, _rawintr, 20)
+#ifdef INET
+ DONET(NETISR_IP, _ipintr, 21)
+#endif
+over_net_stuff_for_spl0:
+ movl $0,_cpl # set new priority
+ SHOW_CPL
+ movl _ipending,%eax
+ testl %eax,%eax
+ jne unpend_V
+ popl %eax # return old priority
+ ret
+
+ .globl _splx
+ ALIGN_TEXT
+_splx:
+ COUNT_EVENT(_intrcnt_spl, 22)
+ movl 4(%esp),%eax # new priority
+ testl %eax,%eax
+ je in_spl0 # going to "zero level" is special
+ COUNT_EVENT(_intrcnt_spl, 23)
+ movl _cpl,%edx # save old priority
+ movl %eax,_cpl # set new priority
+ SHOW_CPL
+ notl %eax
+ andl _ipending,%eax
+ jne unpend_V_result_edx
+ movl %edx,%eax # return old priority
+ ret
+
+ ALIGN_TEXT
+unpend_V_result_edx:
+ pushl %edx
+unpend_V:
+ COUNT_EVENT(_intrcnt_spl, 24)
+ bsfl %eax,%eax
+ btrl %eax,_ipending
+ jnc unpend_V_next
+ SHOW_IPENDING
+ movl Vresume(,%eax,4),%edx
+ testl %edx,%edx
+ je noresumeV
+/*
+ * We would prefer to call the intr handler directly here but that doesn't
+ * work for badly behaved handlers that want the interrupt frame. Also,
+ * there's a problem determining the unit number. We should change the
+ * interface so that the unit number is not determined at config time.
+ */
+ jmp *vec(,%eax,4)
+
+ ALIGN_TEXT
+/*
+ * XXX - must be some fastintr, need to register those too.
+ */
+noresumeV:
+#if NSIO > 0
+ call _softsio1
+#endif
+unpend_V_next:
+ movl _cpl,%eax
+ notl %eax
+ andl _ipending,%eax
+ jne unpend_V
+ popl %eax
+ ret
+
+#define BUILD_VEC(irq_num) \
+ ALIGN_TEXT ; \
+vec/**/irq_num: ; \
+ int $ICU_OFFSET + (irq_num) ; \
+ popl %eax ; \
+ ret
+
+ BUILD_VEC(0)
+ BUILD_VEC(1)
+ BUILD_VEC(2)
+ BUILD_VEC(3)
+ BUILD_VEC(4)
+ BUILD_VEC(5)
+ BUILD_VEC(6)
+ BUILD_VEC(7)
+ BUILD_VEC(8)
+ BUILD_VEC(9)
+ BUILD_VEC(10)
+ BUILD_VEC(11)
+ BUILD_VEC(12)
+ BUILD_VEC(13)
+ BUILD_VEC(14)
+ BUILD_VEC(15)
diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c
new file mode 100644
index 0000000..8707b43
--- /dev/null
+++ b/sys/i386/isa/isa.c
@@ -0,0 +1,766 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa.c 7.2 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 4 00163
+ * -------------------- ----- ----------------------
+ *
+ * 18 Aug 92 Frank Maclachlan *See comments below
+ * 25 Mar 93 Rodney W. Grimes Added counter for stray interrupt,
+ * turned on logging of stray interrupts,
+ * Now prints maddr, msize, and flags
+ * after finding a device.
+ * 26 Apr 93 Bruce Evans New intr-0.1 code
+ * Rodney W. Grimes Only print io address if id_alive != -1
+ * 17 May 93 Rodney W. Grimes renamed stray interrupt counters to
+ * work with new intr-0.1 code.
+ * Enabled printf for interrupt masks to
+ * aid in bug reports.
+ * 27 May 93 Guido van Rooij New routine add find_isa_dev
+ */
+static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/RCS/isa.c,v 1.2 92/01/21 14:34:23 william Exp Locker: root $";
+
+/*
+ * code to manage AT bus
+ *
+ * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
+ * Fixed uninitialized variable problem and added code to deal
+ * with DMA page boundaries in isa_dmarangecheck(). Fixed word
+ * mode DMA count compution and reorganized DMA setup code in
+ * isa_dmastart()
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "uio.h"
+#include "syslog.h"
+#include "malloc.h"
+#include "rlist.h"
+#include "machine/segments.h"
+#include "vm/vm.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/ic/i8237.h"
+#include "i386/isa/ic/i8042.h"
+
+/*
+** Register definitions for DMA controller 1 (channels 0..3):
+*/
+#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
+#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
+#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
+#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
+
+/*
+** Register definitions for DMA controller 2 (channels 4..7):
+*/
+#define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */
+#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
+#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
+#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
+
+int config_isadev __P((struct isa_device *, u_int *));
+
+#ifdef notyet
+struct rlist *isa_iomem;
+
+/*
+ * Configure all ISA devices
+ */
+isa_configure() {
+ struct isa_device *dvp;
+ struct isa_driver *dp;
+
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/
+ for (dvp = isa_devtab_tty; dvp; dvp++)
+ (void) config_isadev(dvp, &ttymask);
+ for (dvp = isa_devtab_bio; dvp; dvp++)
+ (void) config_isadev(dvp, &biomask);
+ for (dvp = isa_devtab_net; dvp; dvp++)
+ (void) config_isadev(dvp, &netmask);
+ for (dvp = isa_devtab_null; dvp; dvp++)
+ (void) config_isadev(dvp, (u_int *) NULL);
+#include "sl.h"
+#if NSL > 0
+ netmask |= ttymask;
+ ttymask |= netmask;
+#endif
+/* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp;
+ static short drqseen, irqseen;
+
+ if (dp = isdp->id_driver) {
+ /* if a device with i/o memory, convert to virtual address */
+ if (isdp->id_maddr) {
+ extern unsigned int atdevbase;
+
+ isdp->id_maddr -= IOM_BEGIN;
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+
+ printf("%s%d at port 0x%x ", dp->name,
+ isdp->id_unit, isdp->id_iobase);
+
+ /* check for conflicts */
+ if (irqseen & isdp->id_irq) {
+ printf("INTERRUPT CONFLICT - irq%d\n",
+ ffs(isdp->id_irq) - 1);
+ return (0);
+ }
+ if (isdp->id_drq != -1
+ && (drqseen & (1<<isdp->id_drq))) {
+ printf("DMA CONFLICT - drq%d\n", isdp->id_drq);
+ return (0);
+ }
+ /* NEED TO CHECK IOMEM CONFLICT HERE */
+
+ /* allocate and wire in device */
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ printf("irq %d ", intrno);
+ INTREN(isdp->id_irq);
+ if(mp)INTRMASK(*mp,isdp->id_irq);
+ setidt(NRSVIDT + intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ irqseen |= isdp->id_irq;
+ }
+ if (isdp->id_drq != -1) {
+ printf("drq %d ", isdp->id_drq);
+ drqseen |= 1 << isdp->id_drq;
+ }
+
+ (*dp->attach)(isdp);
+
+ printf("on isa\n");
+ }
+ return (1);
+ } else return(0);
+}
+#else /* notyet */
+/*
+ * Configure all ISA devices
+ */
+isa_configure() {
+ struct isa_device *dvp;
+ struct isa_driver *dp;
+
+ enable_intr();
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++);
+ for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++);
+ for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++);
+ for (dvp = isa_devtab_null; config_isadev(dvp,(u_int *) NULL); dvp++);
+#include "sl.h"
+#if NSL > 0
+ netmask |= ttymask;
+ ttymask |= netmask;
+#endif
+ /* biomask |= ttymask ; can some tty devices use buffers? */
+ printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask);
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp;
+
+ if (dp = isdp->id_driver) {
+ if (isdp->id_maddr) {
+ extern u_int atdevbase;
+
+ isdp->id_maddr -= 0xa0000; /* XXX should be a define */
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+ printf("%s%d", dp->name, isdp->id_unit);
+ /*
+ * The attach should really be after all the printf's
+ * but until all the drivers are fixed do it here.
+ * There is a comment below that shows where this
+ * really belongs. Rod Grimes 04/10/93
+ */
+ (*dp->attach)(isdp);
+ /*
+ * Only print the I/O address range if id_alive != -1
+ * Right now this is a temporary fix just for the new
+ * NPX code so that if it finds a 486 that can use trap
+ * 16 it will not report I/O addresses.
+ * Rod Grimes 04/26/94
+ */
+ if (isdp->id_alive != -1) {
+ printf(" at 0x%x", isdp->id_iobase);
+ if ((isdp->id_iobase + isdp->id_alive - 1) !=
+ isdp->id_iobase)
+ printf("-0x%x",
+ isdp->id_iobase +
+ isdp->id_alive - 1);
+ }
+ if(isdp->id_irq)
+ printf(" irq %d", ffs(isdp->id_irq)-1);
+ if (isdp->id_drq != -1)
+ printf(" drq %d", isdp->id_drq);
+ if (isdp->id_maddr != 0)
+ printf(" maddr 0x%x", kvtop(isdp->id_maddr));
+ if (isdp->id_msize != 0)
+ printf(" msize %d", isdp->id_msize);
+ if (isdp->id_flags != 0)
+ printf(" flags 0x%x", isdp->id_flags);
+ printf(" on isa\n");
+
+ /* This is the place the attach should be done! */
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ setidt(ICU_OFFSET+intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ if(mp)
+ INTRMASK(*mp,isdp->id_irq);
+ INTREN(isdp->id_irq);
+ }
+ }
+ return (1);
+ } else return(0);
+}
+#endif /* (!) notyet */
+
+#define IDTVEC(name) __CONCAT(X,name)
+/* default interrupt vector table entries */
+extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
+ IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
+ IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
+ IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
+
+static *defvec[16] = {
+ &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
+ &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
+ &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
+ &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
+
+/* out of range default interrupt vector gate entry */
+extern IDTVEC(intrdefault);
+
+/*
+ * Fill in default interrupt table (in case of spuruious interrupt
+ * during configuration of kernel, setup interrupt control unit
+ */
+isa_defaultirq() {
+ int i;
+
+ /* icu vectors */
+ for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
+ setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL);
+
+ /* out of range vectors */
+ for (i = NRSVIDT; i < NIDT; i++)
+ setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL);
+
+ /* initialize 8259's */
+ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
+ outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
+#ifdef AUTO_EOI_1
+ outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU1+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU1, 0x0a); /* default to IRR on read */
+ outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
+
+ outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
+ outb(IO_ICU2+1,2); /* my slave id is 2 */
+#ifdef AUTO_EOI_2
+ outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU2+1,1); /* 8086 mode */
+#endif
+ outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU2, 0x0a); /* default to IRR on read */
+}
+
+/* region of physical memory known to be contiguous */
+vm_offset_t isaphysmem;
+static caddr_t dma_bounce[8]; /* XXX */
+static char bounced[8]; /* XXX */
+#define MAXDMASZ 512 /* XXX */
+
+/* high byte of address is stored in this port for i-th dma channel */
+static short dmapageport[8] =
+ { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
+
+/*
+ * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * external dma control by a board.
+ */
+void isa_dmacascade(unsigned chan)
+{
+ if (chan > 7)
+ panic("isa_dmacascade: impossible request");
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0) {
+ outb(DMA1_MODE, DMA37MD_CASCADE | chan);
+ outb(DMA1_SMSK, chan);
+ } else {
+ outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+/*
+ * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * problems by using a bounce buffer.
+ */
+void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
+{ vm_offset_t phys;
+ int waport;
+ caddr_t newaddr;
+
+ if ( chan > 7
+ || (chan < 4 && nbytes > (1<<16))
+ || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
+ panic("isa_dmastart: impossible request");
+
+ if (isa_dmarangecheck(addr, nbytes, chan)) {
+ if (dma_bounce[chan] == 0)
+ dma_bounce[chan] =
+ /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
+ (caddr_t) isaphysmem + NBPG*chan;
+ bounced[chan] = 1;
+ newaddr = dma_bounce[chan];
+ *(int *) newaddr = 0; /* XXX */
+
+ /* copy bounce buffer on write */
+ if (!(flags & B_READ))
+ bcopy(addr, newaddr, nbytes);
+ addr = newaddr;
+ }
+
+ /* translate to physical */
+ phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+
+ if ((chan & 4) == 0) {
+ /*
+ * Program one of DMA channels 0..3. These are
+ * byte mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
+ else
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
+ outb(DMA1_FFC, 0);
+
+ /* send start address */
+ waport = DMA1_CHN(chan);
+ outb(waport, phys);
+ outb(waport, phys>>8);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ outb(waport + 1, --nbytes);
+ outb(waport + 1, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA1_SMSK, chan);
+ } else {
+ /*
+ * Program one of DMA channels 4..7. These are
+ * word mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
+ else
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
+ outb(DMA2_FFC, 0);
+
+ /* send start address */
+ waport = DMA2_CHN(chan - 4);
+ outb(waport, phys>>1);
+ outb(waport, phys>>9);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ nbytes >>= 1;
+ outb(waport + 2, --nbytes);
+ outb(waport + 2, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
+{
+
+ /* copy bounce buffer on read */
+ /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
+ if (bounced[chan]) {
+ bcopy(dma_bounce[chan], addr, nbytes);
+ bounced[chan] = 0;
+ }
+}
+
+/*
+ * Check for problems with the address range of a DMA transfer
+ * (non-contiguous physical pages, outside of bus address space,
+ * crossing DMA page boundaries).
+ * Return true if special handling needed.
+ */
+
+isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
+ vm_offset_t phys, priorpage = 0, endva;
+ u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
+
+ endva = (vm_offset_t)round_page(va + length);
+ for (; va < (caddr_t) endva ; va += NBPG) {
+ phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
+#define ISARAM_END RAM_END
+ if (phys == 0)
+ panic("isa_dmacheck: no physical page present");
+ if (phys > ISARAM_END)
+ return (1);
+ if (priorpage) {
+ if (priorpage + NBPG != phys)
+ return (1);
+ /* check if crossing a DMA page boundary */
+ if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
+ return (1);
+ }
+ priorpage = phys;
+ }
+ return (0);
+}
+
+/* head of queue waiting for physmem to become available */
+struct buf isa_physmemq;
+
+/* blocked waiting for resource to become free for exclusive use */
+static isaphysmemflag;
+/* if waited for and call requested when free (B_CALL) */
+static void (*isaphysmemunblock)(); /* needs to be a list */
+
+/*
+ * Allocate contiguous physical memory for transfer, returning
+ * a *virtual* address to region. May block waiting for resource.
+ * (assumed to be called at splbio())
+ */
+caddr_t
+isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
+
+ isaphysmemunblock = func;
+ while (isaphysmemflag & B_BUSY) {
+ isaphysmemflag |= B_WANTED;
+ sleep(&isaphysmemflag, PRIBIO);
+ }
+ isaphysmemflag |= B_BUSY;
+
+ return((caddr_t)isaphysmem);
+}
+
+/*
+ * Free contiguous physical memory used for transfer.
+ * (assumed to be called at splbio())
+ */
+void
+isa_freephysmem(caddr_t va, unsigned length) {
+
+ isaphysmemflag &= ~B_BUSY;
+ if (isaphysmemflag & B_WANTED) {
+ isaphysmemflag &= B_WANTED;
+ wakeup(&isaphysmemflag);
+ if (isaphysmemunblock)
+ (*isaphysmemunblock)();
+ }
+}
+
+/*
+ * Handle a NMI, possibly a machine check.
+ * return true to panic system, false to ignore.
+ */
+isa_nmi(cd) {
+
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ return(0);
+}
+
+/*
+ * Caught a stray interrupt, notify
+ */
+isa_strayintr(d) {
+
+ /* DON'T BOTHER FOR NOW! */
+ /* for some reason, we get bursts of intr #7, even if not enabled! */
+ /*
+ * Well the reason you got bursts of intr #7 is because someone
+ * raised an interrupt line and dropped it before the 8259 could
+ * prioritize it. This is documented in the intel data book. This
+ * means you have BAD hardware! I have changed this so that only
+ * the first 5 get logged, then it quits logging them, and puts
+ * out a special message. rgrimes 3/25/1993
+ */
+ extern u_long intrcnt_stray;
+
+ intrcnt_stray++;
+ if (intrcnt_stray <= 5)
+ log(LOG_ERR,"ISA strayintr %x\n", d);
+ if (intrcnt_stray == 5)
+ log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
+}
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz) at
+ * (2 * TIMER_FREQ) Hz.
+ * Note: timer had better have been programmed before this is first used!
+ * (The standard programming causes the timer to generate a square wave and
+ * the counter is decremented twice every cycle.)
+ */
+#define CF (2 * TIMER_FREQ)
+#define TIMER_FREQ 1193182 /* XXX - should be elsewhere */
+
+extern int hz; /* XXX - should be elsewhere */
+
+int DELAY(n)
+ int n;
+{
+ int counter_limit;
+ int prev_tick;
+ int tick;
+ int ticks_left;
+ int sec;
+ int usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+
+ /*
+ * Calculate (n * (CF / 1e6)) without using floating point and without
+ * any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * CF
+ + usec * (CF / 1000000)
+ + usec * ((CF % 1000000) / 1000) / 1000
+ + usec * (CF % 1000) / 1000000;
+
+ counter_limit = TIMER_FREQ / hz;
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - counter_limit);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+getit(unit, timer) {
+ int high;
+ int low;
+
+ /*
+ * XXX - isa.h defines bogus timers. There's no such timer as
+ * IO_TIMER_2 = 0x48. There's a timer in the CMOS RAM chip but
+ * its interface is quite different. Neither timer is an 8252.
+ * We actually only call this with unit = 0 and timer = 0. It
+ * could be static...
+ */
+ /*
+ * Protect ourself against interrupts.
+ * XXX - sysbeep() and sysbeepstop() need protection.
+ */
+ disable_intr();
+ /*
+ * Latch the count for 'timer' (cc00xxxx, c = counter, x = any).
+ */
+ outb(IO_TIMER1 + 3, timer << 6);
+
+ low = inb(IO_TIMER1 + timer);
+ high = inb(IO_TIMER1 + timer);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+static beeping;
+static
+sysbeepstop(f)
+{
+ /* disable counter 2 */
+ outb(0x61, inb(0x61) & 0xFC);
+ if (f)
+ timeout(sysbeepstop, 0, f);
+ else
+ beeping = 0;
+}
+
+void sysbeep(int pitch, int period)
+{
+
+ outb(0x61, inb(0x61) | 3); /* enable counter 2 */
+ /*
+ * XXX - move timer stuff to clock.c.
+ * Program counter 2:
+ * ccaammmb, c counter, a = access, m = mode, b = BCD
+ * 1011x110, 11 for aa = LSB then MSB, x11 for mmm = square wave.
+ */
+ outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */
+
+ outb(0x42, pitch);
+ outb(0x42, (pitch>>8));
+
+ if (!beeping) {
+ beeping = period;
+ timeout(sysbeepstop, period/2, period);
+ }
+}
+
+/*
+ * Pass command to keyboard controller (8042)
+ */
+unsigned kbc_8042cmd(val) {
+
+ while (inb(KBSTATP)&KBS_IBF);
+ if (val) outb(KBCMDP, val);
+ while (inb(KBSTATP)&KBS_IBF);
+ return (inb(KBDATAP));
+}
+
+/*
+ * find an ISA device in a given isa_devtab_* table, given
+ * the table to search, the expected id_driver entry, and the unit number.
+ *
+ * this function is defined in isa_device.h, and this location is debatable;
+ * i put it there because it's useless w/o, and directly operates on
+ * the other stuff in that file.
+ *
+ */
+
+struct isa_device *find_isadev(table, driverp, unit)
+ struct isa_device *table;
+ struct isa_driver *driverp;
+ int unit;
+{
+ if (driverp == NULL) /* sanity check */
+ return NULL;
+
+ while ((table->id_driver != driverp) || (table->id_unit != unit)) {
+ if (table->id_driver == 0)
+ return NULL;
+
+ table++;
+ }
+
+ return table;
+}
+
+/*
+ * Return nonzero if a (masked) irq is pending for a given device.
+ */
+int
+isa_irq_pending(dvp)
+ struct isa_device *dvp;
+{
+ unsigned id_irq;
+
+ id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
+ if (id_irq & 0xff)
+ return (inb(IO_ICU1) & id_irq);
+ return (inb(IO_ICU2) & (id_irq >> 8));
+}
diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h
new file mode 100644
index 0000000..a9c042d
--- /dev/null
+++ b/sys/i386/isa/isa.h
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa.h 5.7 (Berkeley) 5/9/91
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 3 00158
+ * -------------------- ----- ----------------------
+ *
+ * 15 Feb 93 Julian Elischer Added entries for some scsi adapters
+ * 06 Apr 93 Rodney W. Grimes Added com3 and com4, added IO_ISASIZES
+ * section
+ * 26 Apr 93 Bruce Evans Support for intr-0.1
+ */
+
+/*
+ * ISA Bus conventions
+ */
+
+#ifndef LOCORE
+#include <sys/cdefs.h>
+
+unsigned char rtcin __P((int));
+extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
+void sysbeep __P((int, int));
+unsigned kbd_8042cmd __P((int));
+struct isa_device;
+int isa_irq_pending __P((struct isa_device *dvp));
+#endif
+
+
+/*
+ * Input / Output Port Assignments
+ */
+
+#ifndef IO_BEGIN
+#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
+
+ /* CPU Board */
+#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */
+#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
+#define IO_TIMER1 0x040 /* 8252 Timer #1 */
+#define IO_TIMER2 0x048 /* 8252 Timer #2 */
+#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_RTC 0x070 /* RTC */
+#define IO_NMI IO_RTC /* NMI Control */
+#define IO_DMAPG 0x080 /* DMA Page Registers */
+#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
+#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */
+#define IO_NPX 0x0F0 /* Numeric Coprocessor */
+
+ /* Cards */
+ /* 0x100 - 0x16F Open */
+
+#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */
+
+ /* 0x178 - 0x1EF Open */
+
+#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */
+#define IO_GAME 0x200 /* Game Controller */
+
+ /* 0x208 - 0x277 Open */
+
+#define IO_LPT2 0x278 /* Parallel Port #2 */
+
+ /* 0x280 - 0x2E7 Open */
+
+#define IO_COM4 0x2e8 /* COM4 i/o address */
+
+ /* 0x2F0 - 0x2F7 Open */
+
+#define IO_COM2 0x2f8 /* COM2 i/o address */
+ /* 0x300 - 0x32F Open */
+
+#define IO_BT0 0x330 /* bustek 742a default addr. */
+#define IO_AHA0 0x330 /* adaptec 1542 default addr. */
+#define IO_UHA0 0x330 /* ultrastore 14f default addr. */
+#define IO_BT1 0x334 /* bustek 742a default addr. */
+#define IO_AHA1 0x334 /* adaptec 1542 default addr. */
+ /* 0x338 - 0x36F Open */
+
+#define IO_FD2 0x370 /* secondary base i/o address */
+#define IO_LPT1 0x378 /* Parallel Port #1 */
+
+ /* 0x380 - 0x3AF Open */
+
+#define IO_MDA 0x3B0 /* Monochome Adapter */
+#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */
+#define IO_VGA 0x3C0 /* E/VGA Ports */
+#define IO_CGA 0x3D0 /* CGA Ports */
+
+ /* 0x3E0 - 0x3E7 Open */
+
+#define IO_COM3 0x3e8 /* COM3 i/o address */
+#define IO_FD1 0x3f0 /* primary base i/o address */
+#define IO_COM1 0x3f8 /* COM1 i/o address */
+
+#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */
+#endif IO_ISABEGIN
+
+/*
+ * Input / Output Port Sizes - these are from several sources, and tend
+ * to be the larger of what was found, ie COM ports can be 4, but some
+ * boards do not fully decode the address, thus 8 ports are used.
+ */
+
+#ifndef IO_ISASIZES
+#define IO_ISASIZES
+
+#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */
+#define IO_CGASIZE 16 /* CGA controllers */
+#define IO_DMASIZE 16 /* 8237 DMA controllers */
+#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */
+#define IO_FDCSIZE 8 /* Nec765 floppy controllers */
+#define IO_WDCSIZE 8 /* WD compatible disk controllers */
+#define IO_GAMSIZE 16 /* AT compatible game controllers */
+#define IO_ICUSIZE 16 /* 8259A interrupt controllers */
+#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */
+#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */
+#define IO_MDASIZE 16 /* Monochrome display controllers */
+#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */
+#define IO_TMRSIZE 16 /* 8253 programmable timers */
+#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */
+#define IO_VGASIZE 16 /* VGA controllers */
+
+#endif /* IO_ISASIZES */
+
+/*
+ * Input / Output Memory Physical Addresses
+ */
+
+#ifndef IOM_BEGIN
+#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */
+#define IOM_END 0x100000 /* End of I/O Memory "hole" */
+#define IOM_SIZE (IOM_END - IOM_BEGIN)
+#endif IOM_BEGIN
+
+/*
+ * RAM Physical Address Space (ignoring the above mentioned "hole")
+ */
+
+#ifndef RAM_BEGIN
+#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */
+#define RAM_END 0x1000000 /* End of RAM Memory */
+#define RAM_SIZE (RAM_END - RAM_BEGIN)
+#endif RAM_BEGIN
+
+/*
+ * Oddball Physical Memory Addresses
+ */
+#ifndef COMPAQ_RAMRELOC
+#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */
+#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */
+#define WEITEK_FPU 0xC0000000 /* WTL 2167 */
+#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */
+#endif COMPAQ_RAMRELOC
diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h
new file mode 100644
index 0000000..eea71ec
--- /dev/null
+++ b/sys/i386/isa/isa_device.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa_device.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00163
+ * -------------------- ----- ----------------------
+ *
+ * 27 Feb 93 Chris Demetriou Add proper flag handling.
+ * 10 Mar 93 Rodney W. Grimes Fixed isa_device->id_irq to be
+ * the u_short instead of short. This
+ * enables us to use irq15!
+ * 27 May 93 Guido van Rooij Add prototype find_isadev()
+ *
+ */
+
+/*
+ * ISA Bus Autoconfiguration
+ */
+
+/*
+ * Per device structure.
+ */
+struct isa_device {
+ struct isa_driver *id_driver;
+ short id_iobase; /* base i/o address */
+ u_short id_irq; /* interrupt request */
+ short id_drq; /* DMA request */
+ caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
+ int id_msize; /* size of i/o memory */
+ int (*id_intr)(); /* interrupt interface routine */
+ int id_unit; /* unit number */
+ int id_flags; /* flags */
+ int id_scsiid; /* scsi id if needed */
+ int id_alive; /* device is present */
+};
+
+/*
+ * Per-driver structure.
+ *
+ * Each device driver defines entries for a set of routines
+ * as well as an array of types which are acceptable to it.
+ * These are used at boot time by the configuration program.
+ */
+struct isa_driver {
+ int (*probe)(); /* test whether device is present */
+ int (*attach)(); /* setup driver for a device */
+ char *name; /* device name */
+};
+
+extern struct isa_device isa_devtab_bio[], isa_devtab_tty[], isa_devtab_net[],
+ isa_devtab_null[];
+
+extern struct isa_device *find_isadev(/* table, driver, unit*/);
diff --git a/sys/i386/isa/kbd.h b/sys/i386/isa/kbd.h
new file mode 100644
index 0000000..f60e8c2
--- /dev/null
+++ b/sys/i386/isa/kbd.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00162
+ * -------------------- ----- ----------------------
+ *
+ * 26 May 93 Holger Veit added more 8042 defines
+ *
+ * Keyboard definitions
+ */
+
+/* Reference: IBM AT Technical Reference Manual,
+ * pp. 1-38 to 1-43, 4-3 to 4-22
+ */
+
+/* commands sent to KBCMDP */
+
+#define KBC_CMDREAD 0x20 /* read kbd cntrl command byte */
+#define KBC_CMDWRITE 0x60 /* == LD_CMDBYTE in kd.h, write command */
+#define KBC_SELFTEST 0xAA /* perform self test, returns 55 when ok */
+#define KBC_IFTEST 0xAB /* perform interface test */
+#define KBC_DIAGDUMP 0xAC /* send 19 status bytes to system */
+#define KBC_DISKBD 0xAD /* disable keyboard */
+#define KBC_ENAKBD 0xAE /* enable keyboard */
+#define KBC_RDINP 0xC0 /* read input port */
+#define KBC_RDID 0xC4 /* read keyboard ID */
+#define KBC_RDOUTP 0xD0 /* read output port */
+#define KBC_WROUTP 0xD1 /* write output port */
+#define KBC_RDTINP 0xE0 /* read test inputs */
+
+/* commands sent to KBDATAP */
+#define KBC_STSIND 0xED /* set keyboard status indicators */
+#define KBC_ECHO 0xEE /* reply with 0xEE */
+#define KBC_SETTPM 0xF3 /* Set typematic rate/delay */
+#define KBC_ENABLE 0xF4 /* Start scanning */
+#define KBC_SETDEFD 0xF5 /* =KBC_SETDEF, but disable scanning */
+#define KBC_SETDEF 0xF6 /* Set power on defaults */
+#define KBC_RESEND 0xFE /* system wants keyboard to resend last code */
+#define KBC_RESET 0xFF /* Reset the keyboard */
+
+/* responses */
+#define KBR_OVERRUN 0x00 /* Keyboard flooded */
+#define KBR_STOK 0x55 /* Selftest ok response */
+#define KBR_IFOK 0x00 /* Interface test ok */
+#define KBR_IFCL_SA0 0x01 /* Clock Stuck-at-0 fault */
+#define KBR_IFCL_SA1 0x02 /* Clock Stuck-at-1 fault */
+#define KBR_IFDA_SA0 0x03 /* Data Stuck-at-0 fault */
+#define KBR_IFDA_SA1 0x04 /* Data Stuck-at-1 fault */
+#define KBR_RSTDONE 0xAA /* Keyboard reset (BAT) complete */
+#define KBR_E0 0xE0 /* Extended prefix */
+#define KBR_E1 0xE1 /* BREAK'S HIT :-( */
+#define KBR_ECHO 0xEE /* Echo response */
+#define KBR_F0 0xF0 /* Break code prefix */
+#define KBR_ACK 0xFA /* Keyboard did receive command */
+#define KBR_BATFAIL 0xFC /* BAT failed */
+#define KBR_DIAGFAIL 0xFD /* Diagnostic failed response */
+#define KBR_RESEND 0xFE /* Keyboard needs resend of command */
diff --git a/sys/i386/isa/lpt.c b/sys/i386/isa/lpt.c
new file mode 100644
index 0000000..46d1e47
--- /dev/null
+++ b/sys/i386/isa/lpt.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00164
+ * -------------------- ----- ----------------------
+ *
+ * 06 Apr 93 Eric Haug Fixed comments and includes. [Ed: I did
+ * not include the unit-1 thing, that is a
+ * DOSism, fixed the config file instead]
+ * 06 Apr 93 Rodney W. Grimes A real probe routine, may even cause on
+ * interrupt if a printer is attached.
+ *
+ * 01 Jun 93 Rodney W. Grimes Made lpflag uniq now is lptflag
+ * Added timeout loop to lpt_port_test.
+ * lpt_port_test should move to a common
+ * routine..
+ *
+ */
+
+/*
+ * Device Driver for AT parallel printer port
+ * Written by William Jolitz 12/18/90
+ */
+
+#include "lpt.h"
+#if NLPT > 0
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/lptreg.h"
+
+#define LPINITRDY 4 /* wait up to 4 seconds for a ready */
+#define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
+#define LPPRI (PZERO+8)
+#define BUFSIZE 1024
+
+#ifndef DEBUG
+#define lprintf
+#else
+#define lprintf if (lptflag) printf
+int lptflag = 1;
+#endif
+
+int lptout();
+#ifdef DEBUG
+int lptflag = 1;
+#endif
+
+int lptprobe(), lptattach(), lptintr();
+
+struct isa_driver lptdriver = {
+ lptprobe, lptattach, "lpt"
+};
+
+#define LPTUNIT(s) (((s)>>6)&0x3)
+#define LPTFLAGS(s) ((s)&0x3f)
+
+struct lpt_softc {
+ short sc_port;
+ short sc_state;
+ /* default case: negative prime, negative ack, handshake strobe,
+ prime once */
+ u_char sc_control;
+ char sc_flags;
+#define LP_POS_INIT 0x01 /* if we are a postive init signal */
+#define LP_POS_ACK 0x02 /* if we are a positive going ack */
+#define LP_NO_PRIME 0x04 /* don't prime the printer at all */
+#define LP_PRIMEOPEN 0x08 /* prime on every open */
+#define LP_AUTOLF 0x10 /* tell printer to do an automatic lf */
+#define LP_BYPASS 0x20 /* bypass printer ready checks */
+ struct buf *sc_inbuf;
+ short sc_xfercnt ;
+ char sc_primed;
+ char *sc_cp ;
+} lpt_sc[NLPT] ;
+
+/* bits for state */
+#define OPEN (1<<0) /* device is open */
+#define ASLP (1<<1) /* awaiting draining of printer */
+#define ERROR (1<<2) /* error was received from printer */
+#define OBUSY (1<<3) /* printer is busy doing output */
+#define LPTOUT (1<<4) /* timeout while not selected */
+#define TOUT (1<<5) /* timeout while not selected */
+#define INIT (1<<6) /* waiting to initialize for open */
+
+/*
+ * Internal routine to lptprobe to do port tests of one byte value
+ */
+int
+lpt_port_test(short port, u_char data, u_char mask)
+ {
+ int temp, timeout;
+
+ data = data & mask;
+ outb(port, data);
+ timeout = 100;
+ do
+ temp = inb(port) & mask;
+ while (temp != data && --timeout);
+ lprintf("Port 0x%x\tout=%x\tin=%x\n", port, data, temp);
+ return (temp == data);
+ }
+
+/*
+ * New lptprobe routine written by Rodney W. Grimes, 3/25/1993
+ *
+ * Logic:
+ * 1) You should be able to write to and read back the same value
+ * to the data port. Do an alternating zeros, alternating ones,
+ * walking zero, and walking one test to check for stuck bits.
+ *
+ * 2) You should be able to write to and read back the same value
+ * to the control port lower 5 bits, the upper 3 bits are reserved
+ * per the IBM PC technical reference manauls and different boards
+ * do different things with them. Do an alternating zeros, alternating
+ * ones, walking zero, and walking one test to check for stuck bits.
+ *
+ * Some printers drag the strobe line down when the are powered off
+ * so this bit has been masked out of the control port test.
+ *
+ * XXX Some printers may not like a fast pulse on init or strobe, I
+ * don't know at this point, if that becomes a problem these bits
+ * should be turned off in the mask byte for the control port test.
+ *
+ * 3) Set the data and control ports to a value of 0
+ */
+
+int
+lptprobe(struct isa_device *dvp)
+ {
+ int status;
+ short port;
+ u_char data;
+ u_char mask;
+ int i;
+
+ status = IO_LPTSIZE;
+
+ port = dvp->id_iobase + lpt_data;
+ mask = 0xff;
+ while (mask != 0)
+ {
+ data = 0x55; /* Alternating zeros */
+ if (!lpt_port_test(port, data, mask)) status = 0;
+
+ data = 0xaa; /* Alternating ones */
+ if (!lpt_port_test(port, data, mask)) status = 0;
+
+ for (i = 0; i < 8; i++) /* Walking zero */
+ {
+ data = ~(1 << i);
+ if (!lpt_port_test(port, data, mask)) status = 0;
+ }
+
+ for (i = 0; i < 8; i++) /* Walking one */
+ {
+ data = (1 << i);
+ if (!lpt_port_test(port, data, mask)) status = 0;
+ }
+
+ if (port == dvp->id_iobase + lpt_data)
+ {
+ port = dvp->id_iobase + lpt_control;
+ mask = 0x1e;
+ }
+ else
+ mask = 0;
+ }
+ outb(dvp->id_iobase+lpt_data, 0);
+ outb(dvp->id_iobase+lpt_control, 0);
+ return (status);
+ }
+
+lptattach(isdp)
+ struct isa_device *isdp;
+{
+ struct lpt_softc *sc;
+
+ sc = lpt_sc + isdp->id_unit;
+ sc->sc_port = isdp->id_iobase;
+ outb(sc->sc_port+lpt_control, LPC_NINIT);
+ return (1);
+}
+
+/*
+ * lptopen -- reset the printer, then wait until it's selected and not busy.
+ */
+
+lptopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
+ int s;
+ int trys, port;
+
+ if (sc->sc_state) {
+lprintf("lp: still open\n") ;
+printf("still open %x\n", sc->sc_state);
+ return(EBUSY);
+ } else sc->sc_state |= INIT;
+
+ s = spltty();
+ sc->sc_flags = LPTFLAGS(minor(dev));
+lprintf("lp flags 0x%x\n", sc->sc_flags);
+ port = sc->sc_port;
+
+ /* init printer */
+ if((sc->sc_flags & LP_NO_PRIME) == 0) {
+ if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
+ outb(port+lpt_control, 0);
+ sc->sc_primed++;
+ DELAY(500);
+ }
+ }
+ outb(port+lpt_control, LPC_SEL|LPC_NINIT);
+
+ /* wait till ready (printer running diagnostics) */
+ trys = 0;
+ do {
+ /* ran out of waiting for the printer */
+ if (trys++ >= LPINITRDY*4) {
+ splx(s);
+ sc->sc_state = 0;
+printf ("status %x\n", inb(port+lpt_status) );
+ return (EBUSY);
+ }
+
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep (sc, LPPRI|PCATCH, "lptinit", hz/4) != EWOULDBLOCK) {
+ sc->sc_state = 0;
+ splx(s);
+ return (EBUSY);
+ }
+
+ /* is printer online and ready for output */
+ } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR));
+
+ if(sc->sc_flags&LP_AUTOLF) {
+ outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL);
+ sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA|LPC_AUTOL;
+ } else {
+ outb(port+lpt_control, LPC_SEL|LPC_NINIT|LPC_ENA);
+ sc->sc_control = LPC_SEL|LPC_NINIT|LPC_ENA;
+ }
+
+ sc->sc_state = OPEN | TOUT;
+ sc->sc_inbuf = geteblk(BUFSIZE);
+ sc->sc_xfercnt = 0;
+ splx(s);
+ timeout (lptout, sc, hz/2);
+lprintf("opened.\n");
+ return(0);
+}
+
+lptout (sc)
+ struct lpt_softc *sc;
+{ int pl;
+
+lprintf ("T %x ", inb(sc->sc_port+lpt_status));
+ if (sc->sc_state&OPEN)
+ timeout (lptout, sc, hz/2);
+ else sc->sc_state &= ~TOUT;
+
+ if (sc->sc_state & ERROR)
+ sc->sc_state &= ~ERROR;
+
+ /*
+ * Avoid possible hangs do to missed interrupts
+ */
+ if (sc->sc_xfercnt) {
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ splx(pl);
+ } else {
+ sc->sc_state &= ~OBUSY;
+ wakeup((caddr_t)sc);
+ }
+}
+
+/*
+ * lptclose -- close the device, free the local line buffer.
+ */
+
+lptclose(dev, flag)
+ int flag;
+{
+ struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
+ int port = sc->sc_port;
+
+ sc->sc_state &= ~OPEN;
+ while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep (sc, LPPRI|PCATCH, "lpclose", hz) != EWOULDBLOCK)
+ break;
+
+ sc->sc_state = 0;
+ sc->sc_xfercnt = 0;
+ outb(sc->sc_port+lpt_control, LPC_NINIT);
+ brelse(sc->sc_inbuf);
+lprintf("closed.\n");
+ return(0);
+}
+
+/*
+ * lptwrite --copy a line from user space to a local buffer, then call
+ * putc to get the chars moved to the output queue.
+ */
+
+lptwrite(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register unsigned n;
+ int pl, err;
+ struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
+
+ while (n = MIN(BUFSIZE, uio->uio_resid)) {
+ sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
+ uiomove(sc->sc_cp, n, uio);
+ sc->sc_xfercnt = n ;
+ while (sc->sc_xfercnt > 0) {
+ /* if the printer is ready for a char, give it one */
+ if ((sc->sc_state & OBUSY) == 0){
+lprintf("\nC %d. ", sc->sc_xfercnt);
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ (void) splx(pl);
+ }
+lprintf("W ");
+ if (err = tsleep (sc, LPPRI|PCATCH, "lpwrite", 0))
+ return(err);
+ }
+ }
+ return(0);
+}
+
+/*
+ * lptintr -- handle printer interrupts which occur when the printer is
+ * ready to accept another char.
+ */
+
+lptintr(unit)
+{
+ struct lpt_softc *sc = lpt_sc + unit;
+ int port = sc->sc_port,sts;
+
+ /* is printer online and ready for output */
+ if (((sts=inb(port+lpt_status)) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR/*|LPS_NACK*/)) ==
+ (LPS_SEL|LPS_NBSY|LPS_NERR)) {
+ /* is this a false interrupt ? */
+ if ((sc->sc_state & OBUSY)
+ && (sts & LPS_NACK) == 0) return;
+ sc->sc_state |= OBUSY; sc->sc_state &= ~ERROR;
+
+ if (sc->sc_xfercnt) {
+ /* send char */
+/*lprintf("%x ", *sc->sc_cp); */
+ outb(port+lpt_data, *sc->sc_cp++) ; sc->sc_xfercnt-- ;
+ outb(port+lpt_control, sc->sc_control|LPC_STB);
+ /* DELAY(X) */
+ outb(port+lpt_control, sc->sc_control);
+ }
+
+ /* any more bytes for the printer? */
+ if (sc->sc_xfercnt > 0) return;
+
+ /* none, wake up the top half to get more */
+ sc->sc_state &= ~OBUSY;
+ wakeup((caddr_t)sc);
+lprintf("w ");
+return;
+ } else sc->sc_state |= ERROR;
+lprintf("sts %x ", sts);
+}
+
+int
+lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
+{
+ int error;
+
+ error = 0;
+ switch (cmd) {
+#ifdef THISISASAMPLE
+ case XXX:
+ dothis; andthis; andthat;
+ error=x;
+ break;
+#endif /* THISISASAMPLE */
+ default:
+ error = ENODEV;
+ }
+
+ return(error);
+}
+
+#endif /* NLPT */
diff --git a/sys/i386/isa/lptreg.h b/sys/i386/isa/lptreg.h
new file mode 100644
index 0000000..2605fa0
--- /dev/null
+++ b/sys/i386/isa/lptreg.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * %sccs.include.noredist.c%
+ *
+ * @(#)lptreg.h 1.1 (Berkeley) 12/19/90
+ */
+
+/*
+ * AT Parallel Port (for lineprinter)
+ * Interface port and bit definitions
+ * Written by William Jolitz 12/18/90
+ * Copyright (C) William Jolitz 1990
+ */
+
+#define lpt_data 0 /* Data to/from printer (R/W) */
+
+#define lpt_status 1 /* Status of printer (R) */
+#define LPS_NERR 0x08 /* printer no error */
+#define LPS_SEL 0x10 /* printer selected */
+#define LPS_OUT 0x20 /* printer out of paper */
+#define LPS_NACK 0x40 /* printer no ack of data */
+#define LPS_NBSY 0x80 /* printer no ack of data */
+
+#define lpt_control 2 /* Control printer (R/W) */
+#define LPC_STB 0x01 /* strobe data to printer */
+#define LPC_AUTOL 0x02 /* automatic linefeed */
+#define LPC_NINIT 0x04 /* initialize printer */
+#define LPC_SEL 0x08 /* printer selected */
+#define LPC_ENA 0x10 /* printer out of paper */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
new file mode 100644
index 0000000..73392fa
--- /dev/null
+++ b/sys/i386/isa/npx.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)npx.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00154
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Bruce Evans New npx-0.5 code
+ * 23 May 93 Rodney W. Grimes Return a special value of -1 from
+ * the probe code to keep isa_config from
+ * printing out the I/O address when we
+ * are using trap 16 handling.
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/npx.c,v 1.2 92/01/21 14:34:27 william Exp $";
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0mask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al /* EOI (asm in strings loses cpp features) */
+ outb %al,$0xa0 /* IO_ICU2 */
+ outb %al,$0x20 /* IO_ICU1 */
+ movb $0,%al
+ outb %al,$0xf0 /* clear BUSY# latch */
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0mask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ return (IO_NPXSIZE);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (npx_ex16)
+ printf(" <Errors reported via Exception 16>");
+ else if (npx_irq13)
+ printf(" <Errors reported via IRQ 13>");
+ else if (npx_exists)
+ printf(" <Error reporting broken, using 387 emulator>");
+ else
+ printf(" <387 Emulator>");
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ curpcb->pcb_flags &= ~FM_TRAP;
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0mask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0mask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0mask) | (old_icu1_mask & npx0mask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0mask >> 8))
+ | (old_icu2_mask & (npx0mask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/i386/isa/rtc.h b/sys/i386/isa/rtc.h
new file mode 100644
index 0000000..2de060d
--- /dev/null
+++ b/sys/i386/isa/rtc.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rtc.h 7.1 (Berkeley) 5/12/91
+ */
+
+/*
+ * RTC Register locations
+ */
+
+#define RTC_SEC 0x00 /* seconds */
+#define RTC_SECALRM 0x01 /* seconds alarm */
+#define RTC_MIN 0x02 /* minutes */
+#define RTC_MINALRM 0x03 /* minutes alarm */
+#define RTC_HRS 0x04 /* hours */
+#define RTC_HRSALRM 0x05 /* hours alarm */
+#define RTC_WDAY 0x06 /* week day */
+#define RTC_DAY 0x07 /* day of month */
+#define RTC_MONTH 0x08 /* month of year */
+#define RTC_YEAR 0x09 /* month of year */
+#define RTC_STATUSA 0x0a /* status register A */
+#define RTCSA_TUP 0x80 /* time update, don't look now */
+
+#define RTC_STATUSB 0x0b /* status register B */
+
+#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_UPDATE 0x10 /* update intr */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_PERIOD 0x40 /* periodic intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
+#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
+#define RTCSD_PWR 0x80 /* clock lost power */
+
+#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
+#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
+
+#define RTC_RESET 0x0f /* status register F - reset code byte */
+#define RTCRS_RST 0x00 /* normal reset */
+#define RTCRS_LOAD 0x04 /* load system */
+
+#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */
+#define RTCFDT_NONE 0 /* none present */
+#define RTCFDT_360K 0x10 /* 360K */
+#define RTCFDT_12M 0x20 /* 1.2M */
+#define RTCFDT_144M 0x40 /* 1.44M */
+
+#define RTC_BASELO 0x15 /* low byte of basemem size */
+#define RTC_BASEHI 0x16 /* high byte of basemem size */
+#define RTC_EXTLO 0x17 /* low byte of extended mem size */
+#define RTC_EXTHI 0x18 /* low byte of extended mem size */
+
+#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/
diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c
new file mode 100644
index 0000000..38503fd
--- /dev/null
+++ b/sys/i386/isa/sio.c
@@ -0,0 +1,1721 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sio.c 7.5 (Berkeley) 5/16/91
+ *
+ * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt
+ * com port driver.
+ * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR
+ * code, add multiport support.
+ * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting
+ * into the patch kit. Added in sioselect
+ * from com.c. Added port 4 support.
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $";
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * COM driver, based on HP dca driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#undef CRTS_IFLOW
+#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TS_RTSBLOCK TS_TBLOCK /* XXX */
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+#ifndef COM_BIDIR
+#define UNIT(x) (minor(x)) /* XXX */
+#else /* COM_BIDIR */
+#define COM_UNITMASK 0x7f
+#define COM_CALLOUTMASK 0x80
+
+#define UNIT(x) (minor(x) & COM_UNITMASK)
+#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
+#endif /* COM_BIDIR */
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#endif /* COM_MULTIPORT */
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+#define schedsoftcom() (ipending |= 1 << 4) /* XXX */
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef int Bool_t; /* promoted boolean */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+ bool_t softDCD; /* nonzero for faked carrier detect */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+
+/*
+ * These functions in the com module ought to be declared (with a prototype)
+ * in a com-driver system header. The void ones may need to be int to match
+ * ancient devswitch declarations, but they don't actually return anything.
+ */
+#define Dev_t int /* promoted dev_t */
+struct consdev;
+
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+void siointr __P((int unit));
+#ifdef COM_MULTIPORT
+bool_t comintr1 __P((struct com_s *com));
+#endif /* COM_MULTIPORT */
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+int siocngetc __P((Dev_t dev));
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+/*
+ * sioopen gets compared to the d_open entry in struct cdevsw. d_open and
+ * other functions are declared in <sys/conf.h> with short types like dev_t
+ * in the prototype. Such declarations are broken because they vary with
+ * __P (significantly in theory - the compiler is allowed to push a short
+ * arg if it has seen the prototype; insignificantly in practice - gcc
+ * doesn't push short args and it would be slower on 386's to do so).
+ *
+ * Also, most of the device switch functions are still declared old-style
+ * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler
+ * and faster if dev_t's were always promoted (to ints or whatever) as
+ * early as possible.
+ *
+ * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type
+ * when comparing it to the d_open entry just to avoid compiler warnings.
+ */
+typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+void siostop __P((struct tty *tp, int rw));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+void softsio0 __P((void));
+void softsio1 __P((void));
+void softsio2 __P((void));
+void softsio3 __P((void));
+void softsio4 __P((void));
+void softsio5 __P((void));
+void softsio6 __P((void));
+void softsio7 __P((void));
+void softsio8 __P((void));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void cominit __P((int unit, int rate));
+static int commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void compoll __P((void));
+static int comstart __P((struct tty *tp));
+static void comwakeup __P((void));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static bool_t comconsinit;
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+struct tty sio_tty[NSIO];
+extern struct tty *constty;
+extern u_int ipending; /* XXX */
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = 1;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+ || !isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ enable_intr();
+
+ return (result);
+}
+
+static int /* XXX - should be void */
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ if (unit == comconsole)
+ DELAY(1000); /* XXX */
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit];
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+#if 0
+ com->softDCD = TRUE;
+#endif
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+ com->tp = &sio_tty[unit];
+#ifdef COM_BIDIR
+ /*
+ * if bidirectional ports possible, clear the bidir port info;
+ */
+ com->bidir = FALSE;
+ com->active = FALSE;
+ com->active_in = com->active_out = FALSE;
+#endif /* COM_BIDIR */
+
+ /* attempt to determine UART type */
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a)
+ printf(" <8250>");
+ else {
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" <16450>");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" <16450?>");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" <16550?>");
+ break;
+ case FIFO_TRIGGER_14:
+ com->hasfifo = TRUE;
+ printf(" <16550A>");
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+ }
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ struct isa_device *masterdev;
+
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(iobase + com_mcr, 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase+com_scr, 0x80);
+ }
+ else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ cominit(unit, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("com%d: ", unit);
+ kgdb_connect(1);
+ }
+ else
+ printf("com%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ /*
+ * Need to reset baud rate, etc. of next print so reset comconsinit.
+ * Also make sure console is always "hardwired"
+ */
+ if (unit == comconsole) {
+ comconsinit = FALSE;
+ com->softDCD = TRUE;
+ }
+
+ com_addr(unit) = com;
+
+ splx(s);
+
+ if (!comwakeup_started) {
+ comwakeup();
+ comwakeup_started = TRUE;
+ }
+
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error = 0;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit = UNIT(dev);
+#ifdef COM_BIDIR
+ bool_t callout = CALLOUT(dev);
+#endif /* COM_BIDIR */
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+ tp = com->tp;
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ com->softDCD = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep(&com->active_out,
+ TTIPRI|PCATCH,
+ "comoth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ } else if (com->last_modem_status & MSR_DCD) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* put DTR & RTS up */
+ /* NOTE: cgd'sdriver used the ier register
+ * to enable/disable interrupts. This one
+ * uses both ier and IENABLE in the mcr.
+ */
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+ /* wait for it... */
+ error = tsleep(&com->active_in,
+ TTIPRI|PCATCH,
+ "comdcd",
+ 0);
+
+ /* if not active, turn DTR & RTS off */
+ if (!com->active)
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We no longer use the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off. It's useful to have clocal on
+ * initially so that "stty changed-defaults </dev/comx"
+ * doesn't hang waiting for carrier.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8 | CLOCAL;
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ }
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ disable_intr();
+ if (com->hasfifo)
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ com->last_modem_status =
+ com->prev_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->softDCD || com->prev_modem_status & MSR_DCD)
+ tp->t_state |= TS_CARR_ON;
+ }
+ else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ splx(s);
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remainded hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+{
+ comhardclose(com);
+}
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ comhardclose(com);
+ ttyclose(tp);
+ return (0);
+}
+
+void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ s = spltty();
+ iobase = com->iobase;
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts if debugging */
+ if (kgdb_dev != makedev(commajor, com - &com_structs[0]))
+#endif
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+ || !(tp->t_state & TS_ISOPEN))
+ (void) commctl(com, 0, DMSET);
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+ com->softDCD = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+void
+siointr(unit)
+ int unit;
+{
+ struct com_s *com;
+#ifndef COM_MULTIPORT
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+ com = com_addr(unit);
+#else /* COM_MULTIPORT */
+ int i;
+ bool_t donesomething;
+
+ do {
+ donesomething = FALSE;
+ for(i=0;i<NSIO;i++) {
+ com=com_addr(i);
+ if(com != NULL) {
+ /* XXX When siointr is called
+ * to start output, maybe
+ * it should be changed to a
+ * call to comintr1. Doesn't
+ * seem a good idea: interrupts
+ * are disabled all the time.
+ */
+enable_intr();
+disable_intr();
+ donesomething = comintr1(com);
+ }
+ }
+ } while (donesomething);
+ return;
+}
+
+bool_t
+comintr1(struct com_s *com)
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+ bool_t donesomething;
+
+ donesomething = FALSE;
+#endif /* COM_MULTIPORT */
+
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ schedsoftcom();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ ioptr = com->optr;
+ outb(com->data_port, *ioptr);
+ ++com->bytes_out;
+ com->optr = ++ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ schedsoftcom(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#ifdef COM_MULTIPORT
+ return (donesomething);
+#else
+ return;
+#endif /* COM_MULTIPORT */
+ }
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS);
+ break;
+ case TIOCCDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+ break;
+ case TIOCMSET:
+ (void) commctl(com, *(int *)data, DMSET);
+ break;
+ case TIOCMBIS:
+ (void) commctl(com, *(int *)data, DMBIS);
+ break;
+ case TIOCMBIC:
+ (void) commctl(com, *(int *)data, DMBIC);
+ break;
+ case TIOCMGET:
+ *(int *)data = commctl(com, 0, DMGET);
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ if (p->p_ucred->cr_uid != 0)
+ return(EPERM);
+
+ /* if it's the console, can't do it */
+ if (UNIT(dev) == comconsole)
+ return(ENOTTY);
+
+ /* can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+
+ /* if the port is active, don't do it */
+ /* if (com->active)
+ return(EBUSY); */
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = &com->tp->t_out;
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+static void
+compoll()
+{
+ static bool_t awake = FALSE;
+ struct com_s *com;
+ int s;
+ int unit;
+
+ if (com_events == 0)
+ return;
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf))
+ incc = 0;
+ else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ if (!(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTSBLOCK))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD &&
+ unit != comconsole) {
+#ifdef COM_BIDIR
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ com->softDCD = FALSE;
+ wakeup((caddr_t) &com->active_in);
+ }
+#else
+ if (com->prev_modem_status & MSR_DCD)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#endif /* COM_BIDIR */
+ else if ((*linesw[tp->t_line].l_modem)(tp, 0)
+ == 0) {
+ disable_intr();
+ outb(com->modem_ctl_port,
+ com->mcr_image
+ &= ~(MCR_DTR | MCR_RTS));
+ enable_intr();
+ }
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ u_int delta_error_counts[CE_NTYPES];
+ int errnum;
+ u_long total;
+
+ disable_intr();
+ bcopy(com->delta_error_counts, delta_error_counts,
+ sizeof delta_error_counts);
+ bzero(com->delta_error_counts,
+ sizeof delta_error_counts);
+ enable_intr();
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ delta = delta_error_counts[errnum];
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "com%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTSBLOCK)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTSBLOCK;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(&tp->t_raw, (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ }
+ else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+ splx(s);
+ awake = FALSE;
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0) {
+ (void) commctl(com, 0, DMSET); /* hang up line */
+ splx(s);
+ return (0);
+ }
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ "comparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ * Note that DCD flow control stupidly uses the same state flag
+ * (TS_TTSTOP) as XON/XOFF flow control.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->prev_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ enable_intr();
+ siointr(unit); /* recover from fiddling with CS_TTGO */
+ splx(s);
+ return (0);
+}
+
+static int /* XXX - should be void */
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTSBLOCK) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ }
+ else {
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ else if (RB_LEN(&tp->t_out) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(&tp->t_out);
+ disable_intr();
+ com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr(unit); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+ return (1);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+static int
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits);
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | MCR_IENABLE);
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits));
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits & ~MCR_IENABLE));
+ break;
+ case DMGET:
+ bits = com->prev_modem_status;
+ break;
+ }
+ enable_intr();
+ return (bits);
+}
+
+static void
+comwakeup()
+{
+ struct com_s *com;
+ int unit;
+
+ timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1);
+ if (com_events != 0)
+ /* schedule compoll() to run when the cpl allows */
+ schedsoftcom();
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ }
+}
+
+void
+softsio0() { compoll(); }
+
+void
+softsio1() { compoll(); }
+
+void
+softsio2() { compoll(); }
+
+void
+softsio3() { compoll(); }
+
+void
+softsio4() { compoll(); }
+
+void
+softsio5() { compoll(); }
+
+void
+softsio6() { compoll(); }
+
+void
+softsio7() { compoll(); }
+
+void
+softsio8() { compoll(); }
+
+/*
+ * Following are all routines needed for COM to act as console
+ * XXX - not tested in this version
+ * XXX - check that the corresponding serial interrupts are never enabled
+ */
+#include "i386/i386/cons.h"
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == (bogus_open_t) sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = CONUNIT;
+ com_addr(unit) = &com_structs[unit];
+ com_addr(unit)->iobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+ cp->cn_tp = &sio_tty[unit];
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ unit = UNIT(cp->cn_dev);
+ cominit(unit, comdefaultrate);
+ comconsole = unit;
+ comconsinit = TRUE;
+}
+
+static void
+cominit(unit, rate)
+ int unit;
+ int rate;
+{
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(unit)->iobase;
+ s = splhigh();
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ rate = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_data, rate & 0xFF);
+ outb(iobase + com_ier, rate >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+
+ /*
+ * XXX - fishy to enable interrupts and then poll.
+ * It shouldn't be necessary to ready the iir.
+ */
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ (void) inb(iobase + com_iir);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ Port_t iobase;
+ int s;
+ int timo;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (!comconsinit) {
+ (void) cominit(UNIT(dev), comdefaultrate);
+ comconsinit = TRUE;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ outb(iobase + com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+/*
+ * 10 Feb 93 Jordan K. Hubbard Added select code
+ * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5
+ */
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct tty *tp = &sio_tty[UNIT(dev)];
+ int nread;
+ int s = spltty();
+ struct proc *selp;
+
+ switch (rw) {
+
+ case FREAD:
+ nread = ttnread(tp);
+ if (nread > 0 ||
+ ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+ goto win;
+ if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_RCOLL;
+ else
+ tp->t_rsel = p->p_pid;
+ break;
+
+ case FWRITE:
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+ goto win;
+ if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_WCOLL;
+ else
+ tp->t_wsel = p->p_pid;
+ break;
+ }
+ splx(s);
+ return (0);
+ win:
+ splx(s);
+ return (1);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/i386/isa/sioreg.h b/sys/i386/isa/sioreg.h
new file mode 100644
index 0000000..2a62683
--- /dev/null
+++ b/sys/i386/isa/sioreg.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/i386/isa/spkr.c b/sys/i386/isa/spkr.c
new file mode 100644
index 0000000..ffeec08
--- /dev/null
+++ b/sys/i386/isa/spkr.c
@@ -0,0 +1,520 @@
+/*
+ * spkr.c -- device driver for console speaker on 80386
+ *
+ * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
+ * modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
+ * 386bsd only clean version, all SYSV stuff removed
+ * use hz value from param.c
+ */
+
+#include "speaker.h"
+
+#if NSPEAKER > 0
+
+#include "param.h"
+#include "kernel.h"
+#include "errno.h"
+#include "buf.h"
+#include "uio.h"
+#include "spkr.h"
+
+/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+ *
+ * This section defines a function tone() which causes a tone of given
+ * frequency and duration from the 80x86's console speaker.
+ * Another function endtone() is defined to force sound off, and there is
+ * also a rest() entry point to do pauses.
+ *
+ * Audible sound is generated using the Programmable Interval Timer (PIT) and
+ * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+ * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+ * used to generate clicks (a square wave) of whatever frequency is desired.
+ */
+
+/*
+ * PIT and PPI port addresses and control values
+ *
+ * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+ * channel 2, frequency LSB first, square-wave mode and binary encoding.
+ * The encoding is as follows:
+ *
+ * +----------+----------+---------------+-----+
+ * | 1 0 | 1 1 | 0 1 1 | 0 |
+ * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD |
+ * +----------+----------+---------------+-----+
+ * Counter Write Mode 3 Binary
+ * Channel 2 LSB first, (Square Wave) Encoding
+ * MSB second
+ */
+#define PPI 0x61 /* port of Programmable Peripheral Interface */
+#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
+#define PIT_CTRL 0x43 /* PIT control address */
+#define PIT_COUNT 0x42 /* PIT count address */
+#define PIT_MODE 0xB6 /* set timer mode for sound generation */
+
+/*
+ * Magic numbers for timer control.
+ */
+#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */
+
+static int endtone()
+/* turn off the speaker, ending current tone */
+{
+ wakeup((caddr_t)endtone);
+ outb(PPI, inb(PPI) & ~PPI_SPKR);
+}
+
+static void tone(hz, ticks)
+/* emit tone of frequency hz for given number of ticks */
+unsigned int hz, ticks;
+{
+ unsigned int divisor = TIMER_CLK / hz;
+ int sps;
+
+#ifdef DEBUG
+ printf("tone: hz=%d ticks=%d\n", hz, ticks);
+#endif /* DEBUG */
+
+ /* set timer to generate clicks at given frequency in Hertz */
+ sps = spltty();
+ outb(PIT_CTRL, PIT_MODE); /* prepare timer */
+ outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */
+ outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */
+ splx(sps);
+
+ /* turn the speaker on */
+ outb(PPI, inb(PPI) | PPI_SPKR);
+
+ /*
+ * Set timeout to endtone function, then give up the timeslice.
+ * This is so other processes can execute while the tone is being
+ * emitted.
+ */
+ timeout((caddr_t)endtone, (caddr_t)NULL, ticks);
+ sleep((caddr_t)endtone, PZERO - 1);
+}
+
+static int endrest()
+/* end a rest */
+{
+ wakeup((caddr_t)endrest);
+}
+
+static void rest(ticks)
+/* rest for given number of ticks */
+int ticks;
+{
+ /*
+ * Set timeout to endrest function, then give up the timeslice.
+ * This is so other processes can execute while the rest is being
+ * waited out.
+ */
+#ifdef DEBUG
+ printf("rest: %d\n", ticks);
+#endif /* DEBUG */
+ timeout((caddr_t)endrest, (caddr_t)NULL, ticks);
+ sleep((caddr_t)endrest, PZERO - 1);
+}
+
+/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+ *
+ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+ * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
+ * Requires tone(), rest(), and endtone(). String play is not interruptible
+ * except possibly at physical block boundaries.
+ */
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define dtoi(c) ((c) - '0')
+
+static int octave; /* currently selected octave */
+static int whole; /* whole-note time at current tempo, in ticks */
+static int value; /* whole divisor for note time, quarter note = 1 */
+static int fill; /* controls spacing of notes */
+static bool octtrack; /* octave-tracking on? */
+static bool octprefix; /* override current octave-tracking state? */
+
+/*
+ * Magic number avoidance...
+ */
+#define SECS_PER_MIN 60 /* seconds per minute */
+#define WHOLE_NOTE 4 /* quarter notes per whole note */
+#define MIN_VALUE 64 /* the most we can divide a note by */
+#define DFLT_VALUE 4 /* default value (quarter-note) */
+#define FILLTIME 8 /* for articulation, break note in parts */
+#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
+#define NORMAL 7 /* 7/8ths of note interval is filled */
+#define LEGATO 8 /* all of note interval is filled */
+#define DFLT_OCTAVE 4 /* default octave */
+#define MIN_TEMPO 32 /* minimum tempo */
+#define DFLT_TEMPO 120 /* default tempo */
+#define MAX_TEMPO 255 /* max tempo */
+#define NUM_MULT 3 /* numerator of dot multiplier */
+#define DENOM_MULT 2 /* denominator of dot multiplier */
+
+/* letter to half-tone: A B C D E F G */
+static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+
+/*
+ * This is the American Standard A440 Equal-Tempered scale with frequencies
+ * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+ * our octave 0 is standard octave 2.
+ */
+#define OCTAVE_NOTES 12 /* semitones per octave */
+static int pitchtab[] =
+{
+/* C C# D D# E F F# G G# A A# B*/
+/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
+/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
+/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
+/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
+/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+};
+
+static void playinit()
+{
+ octave = DFLT_OCTAVE;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+ fill = NORMAL;
+ value = DFLT_VALUE;
+ octtrack = FALSE;
+ octprefix = TRUE; /* act as though there was an initial O(n) */
+}
+
+static void playtone(pitch, value, sustain)
+/* play tone of proper duration for current rhythm signature */
+int pitch, value, sustain;
+{
+ register int sound, silence, snum = 1, sdenom = 1;
+
+ /* this weirdness avoids floating-point arithmetic */
+ for (; sustain; sustain--)
+ {
+ snum *= NUM_MULT;
+ sdenom *= DENOM_MULT;
+ }
+
+ if (pitch == -1)
+ rest(whole * snum / (value * sdenom));
+ else
+ {
+ sound = (whole * snum) / (value * sdenom)
+ - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+ silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+
+#ifdef DEBUG
+ printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+ pitch, sound, silence);
+#endif /* DEBUG */
+
+ tone(pitchtab[pitch], sound);
+ if (fill != LEGATO)
+ rest(silence);
+ }
+}
+
+static int abs(n)
+int n;
+{
+ if (n < 0)
+ return(-n);
+ else
+ return(n);
+}
+
+static void playstring(cp, slen)
+/* interpret and play an item from a notation string */
+char *cp;
+size_t slen;
+{
+ int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+
+#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+ {v = v * 10 + (*++cp - '0'); slen--;}
+ for (; slen--; cp++)
+ {
+ int sustain, timeval, tempo;
+ register char c = toupper(*cp);
+
+#ifdef DEBUG
+ printf("playstring: %c (%x)\n", c, c);
+#endif /* DEBUG */
+
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+
+ /* compute pitch */
+ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+
+ /* this may be followed by an accidental sign */
+ if (cp[1] == '#' || cp[1] == '+')
+ {
+ ++pitch;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == '-')
+ {
+ --pitch;
+ ++cp;
+ slen--;
+ }
+
+ /*
+ * If octave-tracking mode is on, and there has been no octave-
+ * setting prefix, find the version of the current letter note
+ * closest to the last regardless of octave.
+ */
+ if (octtrack && !octprefix)
+ {
+ if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+ {
+ ++octave;
+ pitch += OCTAVE_NOTES;
+ }
+
+ if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+ {
+ --octave;
+ pitch -= OCTAVE_NOTES;
+ }
+ }
+ octprefix = FALSE;
+ lastpitch = pitch;
+
+ /* ...which may in turn be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+
+ /* ...and/or sustain dots */
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+
+ /* time to emit the actual tone */
+ playtone(pitch, timeval, sustain);
+ break;
+
+ case 'O':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ octprefix = octtrack = FALSE;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ octtrack = TRUE;
+ ++cp;
+ slen--;
+ }
+ else
+ {
+ GETNUM(cp, octave);
+ if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+ octave = DFLT_OCTAVE;
+ octprefix = TRUE;
+ }
+ break;
+
+ case '>':
+ if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+ octave++;
+ octprefix = TRUE;
+ break;
+
+ case '<':
+ if (octave > 0)
+ octave--;
+ octprefix = TRUE;
+ break;
+
+ case 'N':
+ GETNUM(cp, pitch);
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(pitch - 1, value, sustain);
+ break;
+
+ case 'L':
+ GETNUM(cp, value);
+ if (value <= 0 || value > MIN_VALUE)
+ value = DFLT_VALUE;
+ break;
+
+ case 'P':
+ case '~':
+ /* this may be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(-1, timeval, sustain);
+ break;
+
+ case 'T':
+ GETNUM(cp, tempo);
+ if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+ tempo = DFLT_TEMPO;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+ break;
+
+ case 'M':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ fill = NORMAL;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'S' || cp[1] == 's')
+ {
+ fill = STACCATO;
+ ++cp;
+ slen--;
+ }
+ break;
+ }
+ }
+}
+
+/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+ *
+ * This section implements driver hooks to run playstring() and the tone(),
+ * endtone(), and rest() functions defined above.
+ */
+
+static int spkr_active; /* exclusion flag */
+static struct buf *spkr_inbuf; /* incoming buf */
+
+int spkropen(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ printf("spkropen: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (spkr_active)
+ return(EBUSY);
+ else
+ {
+ playinit();
+ spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_active = 1;
+ }
+ return(0);
+}
+
+int spkrwrite(dev, uio)
+dev_t dev;
+struct uio *uio;
+{
+ register unsigned n;
+ char *cp;
+ int error;
+#ifdef DEBUG
+ printf("spkrwrite: entering with dev = %x, count = %d\n",
+ dev, uio->uio_resid);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ n = MIN(DEV_BSIZE, uio->uio_resid);
+ cp = spkr_inbuf->b_un.b_addr;
+ error = uiomove(cp, n, uio);
+ if (!error)
+ playstring(cp, n);
+ return(error);
+ }
+}
+
+int spkrclose(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ printf("spkrclose: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ endtone();
+ brelse(spkr_inbuf);
+ spkr_active = 0;
+ }
+ return(0);
+}
+
+int spkrioctl(dev, cmd, cmdarg)
+dev_t dev;
+int cmd;
+caddr_t cmdarg;
+{
+#ifdef DEBUG
+ printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (cmd == SPKRTONE)
+ {
+ tone_t *tp = (tone_t *)cmdarg;
+
+ if (tp->frequency == 0)
+ rest(tp->duration);
+ else
+ tone(tp->frequency, tp->duration);
+ }
+ else if (cmd == SPKRTUNE)
+ {
+ tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
+ tone_t ttp;
+ int error;
+
+ for (; ; tp++) {
+ error = copyin(tp, &ttp, sizeof(tone_t));
+ if (error)
+ return(error);
+ if (ttp.duration == 0)
+ break;
+ if (ttp.frequency == 0)
+ rest(ttp.duration);
+ else
+ tone(ttp.frequency, ttp.duration);
+ }
+ }
+ else
+ return(EINVAL);
+ return(0);
+}
+
+#endif /* NSPEAKER > 0 */
+/* spkr.c ends here */
diff --git a/sys/i386/isa/timerreg.h b/sys/i386/isa/timerreg.h
new file mode 100644
index 0000000..72c7022
--- /dev/null
+++ b/sys/i386/isa/timerreg.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c
new file mode 100644
index 0000000..46626b7
--- /dev/null
+++ b/sys/i386/isa/ultra14f.c
@@ -0,0 +1,1308 @@
+/*
+ * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
+ * Thanks to Julian Elischer for advice and help with this port.
+ *
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ */
+
+#include <sys/types.h>
+#include <uha.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#ifdef MACH /* EITHER CMU OR OSF */
+#include <i386/ipl.h>
+#include <i386at/scsi.h>
+#include <i386at/scsiconf.h>
+
+#ifdef OSF /* OSF ONLY */
+#include <sys/table.h>
+#include <i386/handler.h>
+#include <i386/dispatcher.h>
+#include <i386/AT386/atbus.h>
+
+#else OSF /* CMU ONLY */
+#include <i386at/atbus.h>
+#include <i386/pio.h>
+#endif OSF
+#endif MACH /* end of MACH specific */
+
+#ifdef __386BSD__ /* 386BSD specific */
+#define isa_dev isa_device
+#define dev_unit id_unit
+#define dev_addr id_iobase
+
+#include <i386/include/pio.h>
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#endif __386BSD__
+
+/* */
+
+#ifdef __386BSD__
+#include "ddb.h"
+#if NDDB > 0
+int Debugger();
+#else NDDB
+#define Debugger() panic("should call debugger here")
+#endif NDDB
+#endif __386BSD__
+
+#ifdef MACH
+int Debugger();
+#endif MACH
+
+typedef struct {unsigned char addr[4]; } physaddr;
+typedef struct {unsigned char len[4]; } physlen;
+
+
+#ifdef MACH
+extern physaddr kvtophys();
+#define PHYSTOKV(x) phystokv(x)
+#define KVTOPHYS(x) kvtophys(x)
+#endif MACH
+
+#ifdef __386BSD__
+#define PHYSTOKV(x) (x | 0xFE000000)
+#define KVTOPHYS(x) vtophys(x)
+#endif __386BSD__
+
+extern int delaycount; /* from clock setup code */
+#define NUM_CONCURRENT 16 /* number of concurrent ops per board */
+#define UHA_NSEG 33 /* number of dma segments supported */
+#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */
+/* */
+/************************** board definitions *******************************/
+/*
+ * I/O Port Interface
+*/
+ #define UHA_LMASK (0x000) /* local doorbell mask reg */
+ #define UHA_LINT (0x001) /* local doorbell int/stat reg */
+ #define UHA_SMASK (0x002) /* system doorbell mask reg */
+ #define UHA_SINT (0x003) /* system doorbell int/stat reg */
+ #define UHA_ID0 (0x004) /* product id reg 0 */
+ #define UHA_ID1 (0x005) /* product id reg 1 */
+ #define UHA_CONF1 (0x006) /* config reg 1 */
+ #define UHA_CONF2 (0x007) /* config reg 2 */
+ #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */
+ #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */
+ #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */
+ #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */
+ #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */
+ #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */
+ #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */
+ #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */
+
+ /*
+* UHA_LMASK bits (read only)
+*/
+
+#define UHA_LDIE 0x80 /* local doorbell int enabled */
+#define UHA_SRSTE 0x40 /* soft reset enabled */
+#define UHA_ABORTEN 0x10 /* abort MSCP enabled */
+#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */
+
+/*
+* UHA_LINT bits (read)
+*/
+
+#define UHA_LDIP 0x80 /* local doorbell int pending */
+
+/*
+* UHA_LINT bits (write)
+*/
+
+#define UHA_ADRST 0x40 /* adapter soft reset */
+#define UHA_SBRST 0x20 /* scsi bus reset */
+#define UHA_ASRST 0x60 /* adapter and scsi reset */
+#define UHA_ABORT 0x10 /* abort MSCP */
+#define UHA_OGMINT 0x01 /* tell adapter to get mail */
+
+/*
+* UHA_SMASK bits (read)
+*/
+
+#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */
+#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */
+#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled
+
+/*
+* UHA_SMASK bits (write)
+*/
+
+#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */
+#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */
+#define UHA_ENICM 0x01 /* enable ICM interrupt */
+
+/*
+* UHA_SINT bits (read)
+*/
+
+#define UHA_SINTP 0x80 /* system doorbell int pending */
+#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */
+#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */
+
+/*
+* UHA_SINT bits (write)
+*/
+
+#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */
+#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */
+
+/*
+* UHA_CONF1 bits (read only)
+*/
+
+#define UHA_DMA_CH5 0x00 /* DMA channel 5 */
+#define UHA_DMA_CH6 0x40 /* 6 */
+#define UHA_DMA_CH7 0x80 /* 7 */
+#define UHA_IRQ15 0x00 /* IRQ 15 */
+#define UHA_IRQ14 0x10 /* 14 */
+#define UHA_IRQ11 0x20 /* 11 */
+#define UHA_IRQ10 0x30 /* 10 */
+
+/***********************************
+* ha_status error codes
+\***********************************/
+
+#define UHA_NO_ERR 0x00 /* No error supposedly */
+#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */
+#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */
+#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */
+#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */
+#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */
+#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */
+#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */
+
+/* */
+
+struct uha_dma_seg
+{
+ physaddr addr;
+ physlen len;
+};
+/* */
+
+struct mscp
+{
+ unsigned char opcode:3;
+ #define U14_HAC 0x01 /*host adapter command*/
+ #define U14_TSP 0x02 /*target scsi pass through command*/
+ #define U14_SDR 0x04 /*scsi device reset*/
+ unsigned char xdir:2; /*xfer direction*/
+ #define U14_SDET 0x00 /*determined by scsi command*/
+ #define U14_SDIN 0x01 /*scsi data in*/
+ #define U14_SDOUT 0x02 /*scsi data out*/
+ #define U14_NODATA 0x03 /*no data xfer*/
+ unsigned char dcn:1; /*disable disconnect for this command*/
+ unsigned char ca:1; /*Cache control*/
+ unsigned char sgth:1; /*scatter gather flag*/
+ unsigned char target:3;
+ unsigned char chan:2; /*scsi channel (always 0 for 14f)*/
+ unsigned char lun:3;
+ physaddr data;
+ physlen datalen;
+ physaddr link;
+ unsigned char link_id;
+ unsigned char sg_num; /*number of scat gath segs */
+ /*in s-g list if sg flag is*/
+ /*set. starts at 1, 8bytes per*/
+ unsigned char senselen;
+ unsigned char cdblen;
+ unsigned char cdb[12];
+ unsigned char ha_status;
+ unsigned char targ_status;
+ physaddr sense; /* if 0 no auto sense */
+ /*-----------------end of hardware supported fields----------------*/
+ struct mscp *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ long int delta; /* difference from previous*/
+ struct mscp *later,*sooner;
+ int flags;
+#define MSCP_FREE 0
+#define MSCP_ACTIVE 1
+#define MSCP_ABORTED 2
+ struct uha_dma_seg uha_dma[UHA_NSEG];
+ struct scsi_sense_data mscp_sense;
+};
+
+struct mscp *uha_soonest = (struct mscp *)0;
+struct mscp *uha_latest = (struct mscp *)0;
+long int uha_furtherest = 0; /* longest time in the timeout queue */
+/* */
+
+struct uha_data
+{
+ int flags;
+#define UHA_INIT 0x01;
+ int baseport;
+ struct mscp mscps[NUM_CONCURRENT];
+ struct mscp *free_mscp;
+ int our_id; /* our scsi id */
+ int vect;
+ int dma;
+} uha_data[NUHA];
+
+int uhaprobe();
+int uha_attach();
+int uhaintr();
+int uha_scsi_cmd();
+int uha_timeout();
+int uha_abort();
+struct mscp *cheat;
+void uhaminphys();
+long int uha_adapter_info();
+
+unsigned long int scratch;
+
+#ifdef MACH
+struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0};
+int (*uhaintrs[])() = {uhaintr, 0};
+#endif MACH
+
+#ifdef __386BSD__
+struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"};
+#endif __386BSD__
+
+static uha_unit = 0;
+int uha_debug = 0;
+#define UHA_SHOWMSCPS 0x01
+#define UHA_SHOWINTS 0x02
+#define UHA_SHOWCMDS 0x04
+#define UHA_SHOWMISC 0x08
+#define FAIL 1
+#define SUCCESS 0
+#define PAGESIZ 4096
+
+struct scsi_switch uha_switch =
+{
+ uha_scsi_cmd,
+ uhaminphys,
+ 0,
+ 0,
+ uha_adapter_info,
+ 0,0,0
+};
+
+/* */
+/***********************************************************************\
+* Function to send a command out through a mailbox *
+\***********************************************************************/
+uha_send_mbox( int unit
+ ,struct mscp *mscp)
+{
+ int port = uha_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */
+ int s = splbio();
+
+ while( ((inb(port + UHA_LINT) & (UHA_LDIP))
+ != (0))
+ && (spincount--));
+ if(spincount == -1)
+ {
+ printf("uha%d: board not responding\n",unit);
+ Debugger();
+ }
+
+ outl(port + UHA_OGM0,KVTOPHYS(mscp));
+ outb(port + UHA_LINT, (UHA_OGMINT));
+ splx(s);
+}
+
+/***********************************************************************\
+* Function to send abort to 14f *
+\***********************************************************************/
+
+uha_abort( int unit
+ ,struct mscp *mscp)
+{
+ int port = uha_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * 1;
+ int abortcount = FUDGE(delaycount) * 2000;
+ int s = splbio();
+
+ while(((inb(port + UHA_LINT) & (UHA_LDIP))
+ != (0))
+ && (spincount--));
+ if(spincount == -1);
+ {
+ printf("uha%d: board not responding\n",unit);
+ Debugger();
+ }
+
+ outl(port + UHA_OGM0,KVTOPHYS(mscp));
+ outb(port + UHA_LINT,UHA_ABORT);
+
+ while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL)));
+ if(abortcount == -1)
+ {
+ printf("uha%d: board not responding\n",unit);
+ Debugger();
+ }
+ if((inb(port + UHA_SINT) & 0x10) != 0)
+ {
+ outb(port + UHA_SINT,UHA_ABORT_ACK);
+ return(1);
+ }
+ else
+ {
+ outb(port + UHA_SINT,UHA_ABORT_ACK);
+ return(0);
+ }
+}
+
+/***********************************************************************\
+* Function to poll for command completion when in poll mode *
+\***********************************************************************/
+uha_poll(int unit ,int wait) /* in msec */
+{
+ int port = uha_data[unit].baseport;
+ int spincount = FUDGE(delaycount) * wait; /* in msec */
+ int stport = port + UHA_SINT;
+ int start = spincount;
+
+retry:
+ while( (spincount--) && (!(inb(stport) & UHA_SINTP)));
+ if(spincount == -1)
+ {
+ printf("uha%d: board not responding\n",unit);
+ return(EIO);
+ }
+if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0)))
+{
+ printf("discarding %x ",inl(port + UHA_ICM0));
+ outb(port + UHA_SINT, UHA_ICM_ACK);
+ spinwait(50);
+ goto retry;
+}/* don't know this will work */
+ uhaintr(unit);
+ return(0);
+}
+
+/*******************************************************\
+* Check if the device can be found at the port given *
+* and if so, set it up ready for further work *
+* as an argument, takes the isa_dev structure from *
+* autoconf.c *
+\*******************************************************/
+uhaprobe(dev)
+struct isa_dev *dev;
+{
+ int unit = uha_unit;
+ dev->dev_unit = unit;
+ uha_data[unit].baseport = dev->dev_addr;
+ if(unit >= NUHA)
+ {
+ printf("uha: unit number (%d) too high\n",unit);
+ return(0);
+ }
+
+ /*try and initialize unit at this location*/
+ if (uha_init(unit) != 0)
+ {
+ return(0);
+ }
+
+ /* if its there put in it's interrupt and DRQ vectors */
+
+ dev->id_irq = (1 << uha_data[unit].vect);
+ dev->id_drq = uha_data[unit].dma;
+
+
+ uha_unit ++;
+return(1);
+}
+
+/***********************************************\
+* Attach all the sub-devices we can find *
+\***********************************************/
+uha_attach(dev)
+struct isa_dev *dev;
+{
+ int unit = dev->dev_unit;
+
+
+#ifdef __386BSD__
+ printf(" probing for scsi devices**\n");
+#endif __386BSD__
+
+ /***********************************************\
+ * ask the adapter what subunits are present *
+ \***********************************************/
+ scsi_attachdevs( unit, uha_data[unit].our_id, &uha_switch);
+
+#if defined(OSF)
+ uha_attached[unit]=1;
+#endif /* defined(OSF) */
+ if(!unit) /* only one for all boards */
+ {
+ uha_timeout(0);
+ }
+
+
+#ifdef __386BSD__
+ printf("uha%d",unit);
+#endif __386BSD__
+ return;
+}
+
+/***********************************************\
+* Return some information to the caller about *
+* the adapter and it's capabilities *
+\***********************************************/
+long int uha_adapter_info(unit)
+int unit;
+{
+ return(2); /* 2 outstanding requests at a time per device */
+}
+
+/***********************************************\
+* Catch an interrupt from the adaptor *
+\***********************************************/
+uhaintr(unit)
+{
+ struct mscp *mscp;
+ u_char uhastat;
+ unsigned long int mboxval;
+
+ int port = uha_data[unit].baseport;
+
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("uhaintr ");
+
+#if defined(OSF)
+ if (!uha_attached[unit])
+ {
+ return(1);
+ }
+#endif /* defined(OSF) */
+ while(inb(port + UHA_SINT) & UHA_SINTP)
+ {
+ /***********************************************\
+ * First get all the information and then *
+ * acknowlege the interrupt *
+ \***********************************************/
+ uhastat = inb(port + UHA_SINT);
+ mboxval = inl(port + UHA_ICM0);
+ outb(port + UHA_SINT,UHA_ICM_ACK);
+
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("status = 0x%x ",uhastat);
+ /***********************************************\
+ * Process the completed operation *
+ \***********************************************/
+
+ mscp = (struct mscp *)(PHYSTOKV(mboxval));
+
+ if(uha_debug & UHA_SHOWCMDS )
+ {
+ uha_show_scsi_cmd(mscp->xs);
+ }
+ if((uha_debug & UHA_SHOWMSCPS) && mscp)
+ printf("<int mscp(%x)>",mscp);
+ uha_remove_timeout(mscp);
+
+ uha_done(unit,mscp);
+ }
+ return(1);
+}
+
+/***********************************************\
+* We have a mscp which has been processed by the *
+* adaptor, now we look to see how the operation *
+* went. *
+\***********************************************/
+
+uha_done(unit,mscp)
+int unit;
+struct mscp *mscp;
+{
+ struct scsi_sense_data *s1,*s2;
+ struct scsi_xfer *xs = mscp->xs;
+
+ if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS))
+ printf("uha_done ");
+ /***********************************************\
+ * Otherwise, put the results of the operation *
+ * into the xfer and call whoever started it *
+ \***********************************************/
+ if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK))
+ { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ xs->error = 0;
+ }
+ else
+ {
+
+ s1 = &(mscp->mscp_sense);
+ s2 = &(xs->sense);
+
+ if(mscp->ha_status != UHA_NO_ERR)
+ {
+ switch(mscp->ha_status)
+ {
+ case UHA_SBUS_TIMEOUT: /* No response */
+ if (uha_debug & UHA_SHOWMISC)
+ {
+ printf("timeout reported back\n");
+ }
+ xs->error = XS_TIMEOUT;
+ break;
+ case UHA_SBUS_OVER_UNDER:
+ if (uha_debug & UHA_SHOWMISC)
+ {
+ printf("scsi bus xfer over/underrun\n");
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case UHA_BAD_SG_LIST:
+ if (uha_debug & UHA_SHOWMISC)
+ {
+ printf("bad sg list reported back\n");
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ if (uha_debug & UHA_SHOWMISC)
+ {
+ printf("unexpected ha_status: %x\n",
+ mscp->ha_status);
+ }
+ }
+
+ }
+ else
+ {
+
+ if (mscp->targ_status != 0)
+/**************************************************************************\
+* I have no information for any possible value of target status field *
+* other than 0 means no error!! So I guess any error is unexpected in that *
+* event!! *
+\**************************************************************************/
+
+ {
+ if (uha_debug & UHA_SHOWMISC)
+ {
+ printf("unexpected targ_status: %x\n",
+ mscp->targ_status);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+done: xs->flags |= ITSDONE;
+ uha_free_mscp(unit,mscp, xs->flags);
+ if(xs->when_done)
+ (*(xs->when_done))(xs->done_arg,xs->done_arg2);
+}
+
+/***********************************************\
+* A mscp (and hence a mbx-out is put onto the *
+* free list. *
+\***********************************************/
+uha_free_mscp(unit,mscp, flags)
+struct mscp *mscp;
+{
+ unsigned int opri;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("mscp%d(0x%x)> ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ mscp->next = uha_data[unit].free_mscp;
+ uha_data[unit].free_mscp = mscp;
+ mscp->flags = MSCP_FREE;
+ /***********************************************\
+ * If there were none, wake abybody waiting for *
+ * one to come free, starting with queued entries*
+ \***********************************************/
+ if (!mscp->next) {
+ wakeup(&uha_data[unit].free_mscp);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/***********************************************\
+* Get a free mscp (and hence mbox-out entry) *
+\***********************************************/
+struct mscp *
+uha_get_mscp(unit,flags)
+{
+ unsigned opri;
+ struct mscp *rc;
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("<mscp%d(0x%x) ",unit,flags);
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /***********************************************\
+ * If we can and have to, sleep waiting for one *
+ * to come free *
+ \***********************************************/
+ while ((!(rc = uha_data[unit].free_mscp)) && (!(flags & SCSI_NOSLEEP)))
+ {
+ sleep(&uha_data[unit].free_mscp, PRIBIO);
+ }
+ if (rc)
+ {
+ uha_data[unit].free_mscp = rc->next;
+ rc->flags = MSCP_ACTIVE;
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+ return(rc);
+}
+
+
+
+/***********************************************\
+* Start the board, ready for normal operation *
+\***********************************************/
+
+uha_init(unit)
+int unit;
+{
+ unsigned char ad[4];
+ volatile unsigned char model;
+ volatile unsigned char submodel;
+ unsigned char config_reg1;
+ unsigned char config_reg2;
+ unsigned char dma_ch;
+ unsigned char irq_ch;
+ unsigned char uha_id;
+ int port = uha_data[unit].baseport;
+ int i;
+ int resetcount = FUDGE(delaycount) * 4000;
+
+ model = inb(port + UHA_ID0);
+ submodel = inb(port + UHA_ID1);
+ if ((model != 0x56) & (submodel != 0x40))
+ { printf("ultrastor 14f not responding\n");
+ return(ENXIO); }
+
+ printf("uha%d reading board settings, ",unit);
+
+ config_reg1 = inb(port + UHA_CONF1);
+ config_reg2 = inb(port + UHA_CONF2);
+ dma_ch = (config_reg1 & 0xc0);
+ irq_ch = (config_reg1 & 0x30);
+ uha_id = (config_reg2 & 0x07);
+
+ switch(dma_ch)
+ {
+ case UHA_DMA_CH5:
+ uha_data[unit].dma = 5;
+ printf("dma=5 ");
+ break;
+ case UHA_DMA_CH6:
+ uha_data[unit].dma = 6;
+ printf("dma=6 ");
+ break;
+ case UHA_DMA_CH7:
+ uha_data[unit].dma = 7;
+ printf("dma=7 ");
+ break;
+ default:
+ printf("illegal dma jumper setting\n");
+ return(EIO);
+ }
+ switch(irq_ch)
+ {
+ case UHA_IRQ10:
+ uha_data[unit].vect = 10;
+ printf("int=10 ");
+ break;
+ case UHA_IRQ11:
+ uha_data[unit].vect = 11;
+ printf("int=11 ");
+ break;
+ case UHA_IRQ14:
+ uha_data[unit].vect = 14;
+ printf("int=14 ");
+ break;
+ case UHA_IRQ15:
+ uha_data[unit].vect = 15;
+ printf("int=15 ");
+ break;
+ default:
+ printf("illegal int jumper setting\n");
+ return(EIO);
+ }
+ /* who are we on the scsi bus */
+ printf("id=%x\n",uha_id);
+ uha_data[unit].our_id = uha_id;
+
+
+ /***********************************************\
+ * link up all our MSCPs into a free list *
+ \***********************************************/
+ for (i=0; i < NUM_CONCURRENT; i++)
+ {
+ uha_data[unit].mscps[i].next = uha_data[unit].free_mscp;
+ uha_data[unit].free_mscp = &uha_data[unit].mscps[i];
+ uha_data[unit].free_mscp->flags = MSCP_FREE;
+ }
+
+ /***********************************************\
+ * Note that we are going and return (to probe) *
+ \***********************************************/
+ outb(port + UHA_LINT, UHA_ASRST);
+ while( (resetcount--) && (!(inb(port + UHA_LINT))));
+ if(resetcount == -1)
+ {
+ printf("uha%d: board timed out during reset\n",unit);
+ return(ENXIO);
+ }
+
+ outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */
+ uha_data[unit].flags |= UHA_INIT;
+ return(0);
+}
+
+
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif min
+
+
+void uhaminphys(bp)
+struct buf *bp;
+{
+#ifdef MACH
+#if !defined(OSF)
+ bp->b_flags |= B_NPAGES; /* can support scat/gather */
+#endif /* defined(OSF) */
+#endif MACH
+ if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ))
+ {
+ bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ);
+ }
+}
+
+/***********************************************\
+* start a scsi operation given the command and *
+* the data address. Also needs the unit, target *
+* and lu *
+\***********************************************/
+int uha_scsi_cmd(xs)
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1,*s2;
+ struct mscp *mscp;
+ struct uha_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int rc = 0;
+ int thiskv;
+ unsigned long int thisphys,nextphys;
+ int unit =xs->adapter;
+ int bytes_this_seg,bytes_this_page,datalen,flags;
+ struct iovec *iovp;
+ int s;
+ unsigned int stat;
+ int port = uha_data[unit].baseport;
+ unsigned long int templen;
+
+
+ if(scsi_debug & PRINTROUTINES)
+ printf("uha_scsi_cmd ");
+ /***********************************************\
+ * get a mscp (mbox-out) to use. If the transfer *
+ * is from a buf (possibly from interrupt time) *
+ * then we can't allow it to sleep *
+ \***********************************************/
+ flags = xs->flags;
+ if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if(flags & ITSDONE)
+ {
+ printf("Already done?");
+ xs->flags &= ~ITSDONE;
+ }
+ if(!(flags & INUSE))
+ {
+ printf("Not in use?");
+ xs->flags |= INUSE;
+ }
+ if (!(mscp = uha_get_mscp(unit,flags)))
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ return(TRY_AGAIN_LATER);
+ }
+
+cheat = mscp;
+ if(uha_debug & UHA_SHOWMSCPS)
+ printf("<start mscp(%x)>",mscp);
+ if(scsi_debug & SHOWCOMMANDS)
+ {
+ uha_show_scsi_cmd(xs);
+ }
+ mscp->xs = xs;
+ /***********************************************\
+ * Put all the arguments for the xfer in the mscp *
+ \***********************************************/
+
+ if (flags & SCSI_RESET)
+ {
+ mscp->opcode = 0x04;
+ mscp->ca = 0x01;
+ }
+ else
+ {
+ mscp->opcode = 0x02;
+ mscp->ca = 0x01;
+ }
+
+ if (flags & SCSI_DATA_IN)
+ {
+ mscp->xdir = 0x01;
+ }
+ if (flags & SCSI_DATA_OUT)
+ {
+ mscp->xdir = 0x02;
+ }
+
+ if (xs->lu != 0)
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ uha_free_mscp(unit,mscp,flags);
+ return(HAD_ERROR);
+ }
+
+ mscp->dcn = 0x00;
+ mscp->chan = 0x00;
+ mscp->target = xs->targ;
+ mscp->lun = xs->lu;
+ mscp->link.addr[0] = 0x00;
+ mscp->link.addr[1] = 0x00;
+ mscp->link.addr[2] = 0x00;
+ mscp->link.addr[3] = 0x00;
+ mscp->link_id = 0x00;
+ mscp->cdblen = xs->cmdlen;
+ scratch = KVTOPHYS(&(mscp->mscp_sense));
+ mscp->sense.addr[0] = (scratch & 0xff);
+ mscp->sense.addr[1] = ((scratch >> 8) & 0xff);
+ mscp->sense.addr[2] = ((scratch >> 16) & 0xff);
+ mscp->sense.addr[3] = ((scratch >> 24) & 0xff);
+ mscp->senselen = sizeof(mscp->mscp_sense);
+ mscp->ha_status = 0x00;
+ mscp->targ_status = 0x00;
+
+ if(xs->datalen)
+ { /* should use S/G only if not zero length */
+ scratch = KVTOPHYS(mscp->uha_dma);
+ mscp->data.addr[0] = (scratch & 0xff);
+ mscp->data.addr[1] = ((scratch >> 8) & 0xff);
+ mscp->data.addr[2] = ((scratch >> 16) & 0xff);
+ mscp->data.addr[3] = ((scratch >> 24) & 0xff);
+ sg = mscp->uha_dma ;
+ seg = 0;
+ mscp->sgth = 0x01;
+
+ if(flags & SCSI_DATA_UIO)
+ {
+ iovp = ((struct uio *)xs->data)->uio_iov;
+ datalen = ((struct uio *)xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < UHA_NSEG))
+ {
+ scratch = (unsigned long)iovp->iov_base;
+ sg->addr.addr[0] = (scratch & 0xff);
+ sg->addr.addr[1] = ((scratch >> 8) & 0xff);
+ sg->addr.addr[2] = ((scratch >> 16) & 0xff);
+ sg->addr.addr[3] = ((scratch >> 24) & 0xff);
+ xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len;
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x@0x%x)"
+ ,iovp->iov_len
+ ,iovp->iov_base);
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ }
+ else
+ {
+ /***********************************************\
+ * Set up the scatter gather block *
+ \***********************************************/
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("%d @0x%x:- ",xs->datalen,xs->data);
+ datalen = xs->datalen;
+ thiskv = (int)xs->data;
+ thisphys = KVTOPHYS(thiskv);
+ templen = 0;
+
+ while ((datalen) && (seg < UHA_NSEG))
+ {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->addr.addr[0] = (thisphys & 0xff);
+ sg->addr.addr[1] = ((thisphys >> 8) & 0xff);
+ sg->addr.addr[2] = ((thisphys >> 16) & 0xff);
+ sg->addr.addr[3] = ((thisphys >> 24) & 0xff);
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("0x%x",thisphys);
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /*********************************************\
+ * This page is contiguous (physically) with *
+ * the the last, just extend the length *
+ \*********************************************/
+ {
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if(datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /********************************************\
+ * next page isn't contiguous, finish the seg *
+ \********************************************/
+ if(scsi_debug & SHOWSCATGATH)
+ printf("(0x%x)",bytes_this_seg);
+ sg->len.len[0] = (bytes_this_seg & 0xff);
+ sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff);
+ sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff);
+ sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff);
+ templen += bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ } /*end of iov/kv decision */
+ mscp->datalen.len[0] = (templen & 0xff);
+ mscp->datalen.len[1] = ((templen >> 8) & 0xff);
+ mscp->datalen.len[2] = ((templen >> 16) & 0xff);
+ mscp->datalen.len[3] = ((templen >> 24) & 0xff);
+ mscp->sg_num = seg;
+
+ if(scsi_debug & SHOWSCATGATH)
+ printf("\n");
+ if (datalen)
+ { /* there's still data, must have run out of segs! */
+ printf("uha_scsi_cmd%d: more than %d DMA segs\n",
+ unit,UHA_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ uha_free_mscp(unit,mscp,flags);
+ return(HAD_ERROR);
+ }
+
+ }
+ else
+ { /* No data xfer, use non S/G values */
+ mscp->data.addr[0] = 0x00;
+ mscp->data.addr[1] = 0x00;
+ mscp->data.addr[2] = 0x00;
+ mscp->data.addr[3] = 0x00;
+ mscp->datalen.len[0] = 0x00;
+ mscp->datalen.len[1] = 0x00;
+ mscp->datalen.len[2] = 0x00;
+ mscp->datalen.len[3] = 0x00;
+ mscp->xdir = 0x03;
+ mscp->sgth = 0x00;
+ mscp->sg_num = 0x00;
+ }
+
+ /***********************************************\
+ * Put the scsi command in the mscp and start it *
+ \***********************************************/
+ bcopy(xs->cmd, mscp->cdb, xs->cmdlen);
+
+ /***********************************************\
+ * Usually return SUCCESSFULLY QUEUED *
+ \***********************************************/
+ if (!(flags & SCSI_NOMASK))
+ {
+ s = splbio();
+ uha_send_mbox(unit,mscp);
+ uha_add_timeout(mscp,xs->timeout);
+ splx(s);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("cmd_sent ");
+ return(SUCCESSFULLY_QUEUED);
+ }
+ /***********************************************\
+ * If we can't use interrupts, poll on completion*
+ \***********************************************/
+ uha_send_mbox(unit,mscp);
+ if(scsi_debug & TRACEINTERRUPTS)
+ printf("cmd_wait ");
+ do
+ {
+ if(uha_poll(unit,xs->timeout))
+ {
+ if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n");
+ if(!(uha_abort(unit,mscp)))
+ {
+ printf("abort failed in wait\n");
+ uha_free_mscp(unit,mscp,flags);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ splx(s);
+ return(HAD_ERROR);
+ }
+ } while (!(xs->flags & ITSDONE));/* something (?) else finished */
+ splx(s);
+scsi_debug = 0;uha_debug = 0;
+ if(xs->error)
+ {
+ return(HAD_ERROR);
+ }
+ return(COMPLETE);
+}
+
+/*
+ * +----------+ +----------+ +----------+
+ * uha_soonest--->| later |--->| later|--->| later|--->0
+ * | [Delta] | | [Delta] | | [Delta] |
+ * 0<---|sooner |<---|sooner |<---|sooner |<---uha_latest
+ * +----------+ +----------+ +----------+
+ *
+ * uha_furtherest = sum(Delta[1..n])
+ */
+uha_add_timeout(mscp,time)
+struct mscp *mscp;
+int time;
+{
+ int timeprev;
+ struct mscp *prev;
+ int s = splbio();
+
+ if(prev = uha_latest) /* yes, an assign */
+ {
+ timeprev = uha_furtherest;
+ }
+ else
+ {
+ timeprev = 0;
+ }
+ while(prev && (timeprev > time))
+ {
+ timeprev -= prev->delta;
+ prev = prev->sooner;
+ }
+ if(prev)
+ {
+ mscp->delta = time - timeprev;
+ if( mscp->later = prev->later) /* yes an assign */
+ {
+ mscp->later->sooner = mscp;
+ mscp->later->delta -= mscp->delta;
+ }
+ else
+ {
+ uha_furtherest = time;
+ uha_latest = mscp;
+ }
+ mscp->sooner = prev;
+ prev->later = mscp;
+ }
+ else
+ {
+ if( mscp->later = uha_soonest) /* yes, an assign*/
+ {
+ mscp->later->sooner = mscp;
+ mscp->later->delta -= time;
+ }
+ else
+ {
+ uha_furtherest = time;
+ uha_latest = mscp;
+ }
+ mscp->delta = time;
+ mscp->sooner = (struct mscp *)0;
+ uha_soonest = mscp;
+ }
+ splx(s);
+}
+
+uha_remove_timeout(mscp)
+struct mscp *mscp;
+{
+ int s = splbio();
+
+ if(mscp->sooner)
+ {
+ mscp->sooner->later = mscp->later;
+ }
+ else
+ {
+ uha_soonest = mscp->later;
+ }
+ if(mscp->later)
+ {
+ mscp->later->sooner = mscp->sooner;
+ mscp->later->delta += mscp->delta;
+ }
+ else
+ {
+ uha_latest = mscp->sooner;
+ uha_furtherest -= mscp->delta;
+ }
+ mscp->sooner = mscp->later = (struct mscp *)0;
+ splx(s);
+}
+
+
+extern int hz;
+#define ONETICK 500 /* milliseconds */
+#define SLEEPTIME ((hz * 1000) / ONETICK)
+uha_timeout(arg)
+int arg;
+{
+ struct mscp *mscp;
+ int unit;
+ int s = splbio();
+ unsigned int stat;
+ int port = uha_data[unit].baseport;
+
+ while( mscp = uha_soonest )
+ {
+ if(mscp->delta <= ONETICK)
+ /***********************************************\
+ * It has timed out, we need to do some work *
+ \***********************************************/
+ {
+ unit = mscp->xs->adapter;
+ printf("uha%d:%d device timed out\n",unit
+ ,mscp->xs->targ);
+ if(uha_debug & UHA_SHOWMSCPS)
+ uha_print_active_mscp();
+
+ /***************************************\
+ * Unlink it from the queue *
+ \***************************************/
+ uha_remove_timeout(mscp);
+
+ if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED))
+ {
+ printf("AGAIN");
+ mscp->xs->retries = 0; /* I MEAN IT ! */
+ uha_done(unit,mscp,FAIL);
+ }
+ else /* abort the operation that has timed out */
+ {
+ printf("\n");
+ uha_add_timeout(mscp,2000 + ONETICK);
+ mscp->flags = MSCP_ABORTED;
+ }
+ }
+ else
+ /***********************************************\
+ * It has not timed out, adjust and leave *
+ \***********************************************/
+ {
+ mscp->delta -= ONETICK;
+ uha_furtherest -= ONETICK;
+ break;
+ }
+ }
+ splx(s);
+ timeout(uha_timeout,arg,SLEEPTIME);
+}
+
+uha_show_scsi_cmd(struct scsi_xfer *xs)
+{
+ u_char *b = (u_char *)xs->cmd;
+ int i = 0;
+ if(!(xs->flags & SCSI_RESET))
+ {
+ printf("uha%d:%d:%d-"
+ ,xs->adapter
+ ,xs->targ
+ ,xs->lu);
+ while(i < xs->cmdlen )
+ {
+ if(i) printf(",");
+ printf("%x",b[i++]);
+ }
+ printf("-\n");
+ }
+ else
+ {
+ printf("uha%d:%d:%d-RESET-\n"
+ ,xs->adapter
+ ,xs->targ
+ ,xs->lu
+ );
+ }
+}
+uha_print_mscp(mscp)
+struct mscp *mscp;
+{
+ printf("mscp:%x op:%x cmdlen:%d senlen:%d\n"
+ ,mscp
+ ,mscp->opcode
+ ,mscp->cdblen
+ ,mscp->senselen);
+ printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n"
+ ,mscp->sgth
+ ,mscp->sg_num
+ ,mscp->datalen
+ ,mscp->ha_status
+ ,mscp->targ_status
+ ,mscp->delta
+ ,mscp->flags);
+ uha_show_scsi_cmd(mscp->xs);
+}
+
+uha_print_active_mscp()
+{
+ struct mscp *mscp;
+ mscp = uha_soonest;
+
+ while(mscp)
+ {
+ uha_print_mscp(mscp);
+ mscp = mscp->later;
+ }
+ printf("Furtherest = %d\n",uha_furtherest);
+}
diff --git a/sys/i386/isa/vector.s b/sys/i386/isa/vector.s
new file mode 100644
index 0000000..38ac79c
--- /dev/null
+++ b/sys/i386/isa/vector.s
@@ -0,0 +1,376 @@
+/* vector.s */
+/*
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00167
+ * -------------------- ----- ----------------------
+ *
+ * 04 Jun 93 Bruce Evans Fixed irq_num vs id_num for multiple
+ * devices configed on the same irq with
+ * respect to ipending.
+ *
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#ifdef AUTO_EOI_1
+#undef ENABLE_ICU1 /* we now use auto-EOI to reduce i/o */
+#define ENABLE_ICU1
+#endif
+
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#ifdef AUTO_EOI_2
+#undef ENABLE_ICU1_AND_2 /* data sheet says no auto-EOI on slave ... */
+#define ENABLE_ICU1_AND_2 /* ... but it works */
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ /* pushl %es ; know compiler doesn't do string insns */ \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ /* movl %ax,%es ; */ \
+ SHOW_CLI ; /* although it interferes with "ASAP" */ \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ SHOW_STI ; \
+ /* popl %es ; */ \
+ popl %ds ; \
+ popl %edx; \
+ popl %ecx; \
+ popl %eax; \
+ iret
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dummy error code */ \
+ pushl $T_ASTFLT ; \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early in case SHOW_A_LOT is on */ \
+ movl %ax,%es ; \
+ SHOW_CLI ; /* interrupt did an implicit cli */ \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ COUNT_EVENT(_intrcnt_actv, id_num) ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ SHOW_CPL ; \
+ SHOW_STI ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ SHOW_IMEN ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ jmp doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ COUNT_EVENT(_intrcnt_pend, id_num) ; \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,Vresume + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ SHOW_IPENDING ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _highmask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+IDTVEC(intrdefault)
+ STRAYINTR(7,1,1, al) /* XXX */
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+Vresume: .space 16 * 4 /* where to resume intr handler after unpend */
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _intrcnt_pend
+_intrcnt_pend: .space NR_REAL_INT_HANDLERS * 4 /* pending interrupts */
+ .globl _intrcnt_spl
+_intrcnt_spl: .space 32 * 4 /* XXX 32 should not be hard coded ? */
+ .globl _intrcnt_show
+_intrcnt_show: .space 8 * 4 /* XXX 16 should not be hard coded ? */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .asciz "name pend"
+
+ BUILD_VECTORS
+
+/*
+ * now the spl names
+ */
+ .asciz "unpend_v"
+ .asciz "doreti"
+ .asciz "p0!ni"
+ .asciz "!p0!ni"
+ .asciz "p0ni"
+ .asciz "netisr_raw"
+ .asciz "netisr_ip"
+ .asciz "netisr_imp"
+ .asciz "netisr_ns"
+ .asciz "softclock"
+ .asciz "trap"
+ .asciz "doreti_exit2"
+ .asciz "splbio"
+ .asciz "splclock"
+ .asciz "splhigh"
+ .asciz "splimp"
+ .asciz "splnet"
+ .asciz "splsoftclock"
+ .asciz "spltty"
+ .asciz "spl0"
+ .asciz "netisr_raw2"
+ .asciz "netisr_ip2"
+ .asciz "splx"
+ .asciz "splx!0"
+ .asciz "unpend_V"
+ .asciz "spl25" /* spl25-spl31 are spares */
+ .asciz "spl26"
+ .asciz "spl27"
+ .asciz "spl28"
+ .asciz "spl29"
+ .asciz "spl30"
+ .asciz "spl31"
+/*
+ * now the mask names
+ */
+ .asciz "cli"
+ .asciz "cpl"
+ .asciz "imen"
+ .asciz "ipending"
+ .asciz "sti"
+ .asciz "mask5" /* mask5-mask7 are spares */
+ .asciz "mask6"
+ .asciz "mask7"
+
+_eintrnames:
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
new file mode 100644
index 0000000..bbec45b
--- /dev/null
+++ b/sys/i386/isa/wd.c
@@ -0,0 +1,1352 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:@(#)wd.c 7.2 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 6 00155
+ * -------------------- ----- ----------------------
+ *
+ * 17 Sep 92 Frank Maclachlan Fixed I/O error reporting on raw device
+ * 31 Jul 92 Christoph Robitschko Fixed second disk recognition,
+ * bzero of malloced memory for warm
+ * boot problem.
+ * 19 Aug 92 Frank Maclachlan Fixed bug when first sector of a
+ * multisector read is in bad144 table.
+ * 17 Jan 93 B. Evans & A.Chernov Fixed bugs from previous patches,
+ * driver initialization, and cylinder
+ * boundary conditions.
+ * 28 Mar 93 Charles Hannum Add missing splx calls.
+ * 20 Apr 93 Terry Lee Always report disk errors
+ * 20 Apr 93 Brett Lymn Change infinite while loops to
+ * timeouts
+ * 17 May 93 Rodney W. Grimes Fixed all 1000000 to use WDCTIMEOUT,
+ * and increased to 1000000*10 for new
+ * intr-0.1 code.
+ */
+
+/* TODO:peel out buffer at low ipl, speed improvement */
+
+
+#include "wd.h"
+#if NWD > 0
+
+#include "param.h"
+#include "dkbad.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "stat.h"
+#include "ioctl.h"
+#include "disklabel.h"
+#include "buf.h"
+#include "uio.h"
+#include "malloc.h"
+#include "machine/cpu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/wdreg.h"
+#include "syslog.h"
+#include "vm/vm.h"
+
+#define _NWD (NWD - 1) /* One is for the controller XXX 31 Jul 92*/
+
+#ifndef WDCTIMEOUT
+#define WDCTIMEOUT 10000000 /* arbitrary timeout for drive ready waits */
+#endif
+
+#define RETRIES 5 /* number of retries before giving up */
+#define MAXTRANSFER 32 /* max size of transfer in page clusters */
+
+#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
+#define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */
+#define wdunit(dev) ((minor(dev) & 0x38) >> 3)
+#define wdpart(dev) (minor(dev) & 0x7)
+#define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part)))
+#define WDRAW 3 /* 'd' partition isn't a partition! */
+
+#define b_cylin b_resid /* cylinder number for doing IO to */
+ /* shares an entry in the buf struct */
+
+/*
+ * Drive states. Used to initialize drive.
+ */
+
+#define CLOSED 0 /* disk is closed. */
+#define WANTOPEN 1 /* open requested, not started */
+#define RECAL 2 /* doing restore */
+#define OPEN 3 /* done with open */
+
+/*
+ * The structure of a disk drive.
+ */
+struct disk {
+ long dk_bc; /* byte count left */
+ short dk_skip; /* blocks already transferred */
+ char dk_unit; /* physical unit number */
+ char dk_state; /* control state */
+ u_char dk_status; /* copy of status reg. */
+ u_char dk_error; /* copy of error reg. */
+ short dk_port; /* i/o port base */
+
+ u_long dk_copenpart; /* character units open on this drive */
+ u_long dk_bopenpart; /* block units open on this drive */
+ u_long dk_openpart; /* all units open on this drive */
+ short dk_wlabel; /* label writable? */
+ short dk_flags; /* drive characteistics found */
+#define DKFL_DOSPART 0x00001 /* has DOS partition table */
+#define DKFL_QUIET 0x00002 /* report errors back, but don't complain */
+#define DKFL_SINGLE 0x00004 /* sector at a time mode */
+#define DKFL_ERROR 0x00008 /* processing a disk error */
+#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */
+#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */
+#define DKFL_WRITEPROT 0x00040 /* manual unit write protect */
+ struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
+ struct disklabel dk_dd; /* device configuration data */
+ struct dos_partition
+ dk_dospartitions[NDOSPART]; /* DOS view of disk */
+ struct dkbad dk_bad; /* bad sector table */
+};
+
+struct disk *wddrives[_NWD]; /* table of units */
+struct buf wdtab;
+struct buf wdutab[_NWD]; /* head of queue per drive */
+struct buf rwdbuf[_NWD]; /* buffers for raw IO */
+long wdxfer[_NWD]; /* count of transfers */
+#ifdef WDDEBUG
+int wddebug;
+#endif
+
+struct isa_driver wddriver = {
+ wdprobe, wdattach, "wd",
+};
+
+void wdustart(struct disk *);
+void wdstart();
+int wdcommand(struct disk *, int);
+int wdcontrol(struct buf *);
+int wdsetctlr(dev_t, struct disk *);
+int wdgetctlr(int, struct disk *);
+
+/*
+ * Probe for controller.
+ */
+int
+wdprobe(struct isa_device *dvp)
+{
+ int unit = dvp->id_unit;
+ struct disk *du;
+ int wdc;
+
+ if (unit >= _NWD) /* 31 Jul 92*/
+ return(0);
+
+ if ((du = wddrives[unit]) == 0) {
+ du = wddrives[unit] = (struct disk *)
+ malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
+ bzero (du, sizeof(struct disk)); /* 31 Jul 92*/
+ du->dk_unit = unit;
+ }
+
+ wdc = du->dk_port = dvp->id_iobase;
+
+ /* check if we have registers that work */
+ outb(wdc+wd_cyl_lo, 0xa5) ; /* wd_cyl_lo is read/write */
+ if(inb(wdc+wd_cyl_lo) != 0xa5)
+ goto nodevice;
+
+ /* reset the device */
+ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
+ DELAY(1000);
+ outb(wdc+wd_ctlr, WDCTL_IDS);
+ DELAY(1000);
+
+ /* execute a controller only command */
+ if (wdcommand(du, WDCC_DIAGNOSE) < 0)
+ goto nodevice;
+
+ (void) inb(wdc+wd_error); /* XXX! */
+ outb(wdc+wd_ctlr, WDCTL_4BIT);
+ return (1);
+
+nodevice:
+ free(du, M_TEMP);
+ wddrives[unit] = 0;
+ return (0);
+}
+
+/*
+ * Attach each drive if possible.
+ */
+int
+wdattach(struct isa_device *dvp)
+{
+ int unit;
+/* int unit = dvp->id_unit;*/
+
+ for (unit=0; unit< _NWD; unit++) {
+ struct disk *du;
+ if ((du = wddrives[unit]) == 0) {
+ du = wddrives[unit] = (struct disk *)
+ malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
+ bzero (du, sizeof(struct disk));
+ du->dk_unit = unit;
+ du->dk_port = dvp->id_iobase;
+ }
+
+ /* print out description of drive, suppressing multiple blanks*/
+ if(wdgetctlr(unit, du) == 0) {
+ int i, blank;
+ char c;
+ printf(" %d:<", unit);
+ for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) {
+ char c = du->dk_params.wdp_model[i];
+
+ if (blank && c == ' ') continue;
+ if (blank && c != ' ') {
+ printf(" %c", c);
+ blank = 0;
+ continue;
+ }
+ if (c == ' ')
+ blank = 1;
+ else
+ printf("%c", c);
+ }
+ printf(">");
+ du->dk_unit = unit;
+ }
+ else {
+ /* old ST506 controller */
+ printf(" %d:<wdgetctlr failed, assuming OK>",
+ unit);
+ }
+ }
+ return(1);
+}
+
+/* Read/write routine for a buffer. Finds the proper unit, range checks
+ * arguments, and schedules the transfer. Does not wait for the transfer
+ * to complete. Multi-page transfers are supported. All I/O requests must
+ * be a multiple of a sector in length.
+ */
+int
+wdstrategy(register struct buf *bp)
+{
+ register struct buf *dp;
+ struct disklabel *lp;
+ register struct partition *p;
+ struct disk *du; /* Disk unit to do the IO. */
+ long maxsz, sz;
+ int unit = wdunit(bp->b_dev);
+ int s;
+
+ /* valid unit, controller, and request? */
+ if (unit >= _NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) {
+
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /* "soft" write protect check */
+ if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /* have partitions and want to use them? */
+ if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
+
+ /*
+ * do bounds checking, adjust transfer. if error, process.
+ * if end of partition, just return
+ */
+ if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0)
+ goto done;
+ /* otherwise, process transfer request */
+ }
+
+q:
+ /* queue transfer on drive, activate drive and controller if idle */
+ dp = &wdutab[unit];
+ s = splbio();
+ disksort(dp, bp);
+ if (dp->b_active == 0)
+ wdustart(du); /* start drive */
+ if (wdtab.b_active == 0)
+ wdstart(s); /* start controller */
+ splx(s);
+ return;
+
+done:
+ /* toss transfer, we're done early */
+ biodone(bp);
+}
+
+/*
+ * Routine to queue a command to the controller. The unit's
+ * request is linked into the active list for the controller.
+ * If the controller is idle, the transfer is started.
+ */
+static void
+wdustart(register struct disk *du)
+{
+ register struct buf *bp, *dp = &wdutab[du->dk_unit];
+
+ /* unit already active? */
+ if (dp->b_active)
+ return;
+
+ /* anything to start? */
+ bp = dp->b_actf;
+ if (bp == NULL)
+ return;
+
+ /* link onto controller queue */
+ dp->b_forw = NULL;
+ if (wdtab.b_actf == NULL)
+ wdtab.b_actf = dp;
+ else
+ wdtab.b_actl->b_forw = dp;
+ wdtab.b_actl = dp;
+
+ /* mark the drive unit as busy */
+ dp->b_active = 1;
+}
+
+/*
+ * Controller startup routine. This does the calculation, and starts
+ * a single-sector read or write operation. Called to start a transfer,
+ * or from the interrupt routine to continue a multi-sector transfer.
+ * RESTRICTIONS:
+ * 1. The transfer length must be an exact multiple of the sector size.
+ */
+
+static void
+wdstart()
+{
+ register struct disk *du; /* disk unit for IO */
+ register struct buf *bp;
+ struct disklabel *lp;
+ struct buf *dp;
+ register struct bt_bad *bt_ptr;
+ long blknum, pagcnt, cylin, head, sector;
+ long secpertrk, secpercyl, addr, i, timeout;
+ int unit, s, wdc;
+
+loop:
+ /* is there a drive for the controller to do a transfer with? */
+ dp = wdtab.b_actf;
+ if (dp == NULL)
+ return;
+
+ /* is there a transfer to this drive ? if so, link it on
+ the controller's queue */
+ bp = dp->b_actf;
+ if (bp == NULL) {
+ wdtab.b_actf = dp->b_forw;
+ goto loop;
+ }
+
+ /* obtain controller and drive information */
+ unit = wdunit(bp->b_dev);
+ du = wddrives[unit];
+
+ /* if not really a transfer, do control operations specially */
+ if (du->dk_state < OPEN) {
+ (void) wdcontrol(bp);
+ return;
+ }
+
+ /* calculate transfer details */
+ blknum = bp->b_blkno + du->dk_skip;
+/*if(wddebug)printf("bn%d ", blknum);*/
+#ifdef WDDEBUG
+ if (du->dk_skip == 0)
+ printf("\nwdstart %d: %s %d@%d; map ", unit,
+ (bp->b_flags & B_READ) ? "read" : "write",
+ bp->b_bcount, blknum);
+ else
+ printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts));
+#endif
+ addr = (int) bp->b_un.b_addr;
+ if (du->dk_skip == 0)
+ du->dk_bc = bp->b_bcount;
+
+ lp = &du->dk_dd;
+ secpertrk = lp->d_nsectors;
+ secpercyl = lp->d_secpercyl;
+ if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
+ blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+
+ /*
+ * See if the current block is in the bad block list.
+ * (If we have one, and not formatting.)
+ */
+ if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/
+ == (DKFL_SINGLE|DKFL_BADSECT))
+ for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
+ if (bt_ptr->bt_cyl > cylin)
+ /* Sorted list, and we passed our cylinder. quit. */
+ break;
+ if (bt_ptr->bt_cyl == cylin &&
+ bt_ptr->bt_trksec == (head << 8) + sector) {
+ /*
+ * Found bad block. Calculate new block addr.
+ * This starts at the end of the disk (skip the
+ * last track which is used for the bad block list),
+ * and works backwards to the front of the disk.
+ */
+#ifdef WDDEBUG
+ printf("--- badblock code -> Old = %d; ",
+ blknum);
+#endif
+ blknum = lp->d_secperunit - lp->d_nsectors
+ - (bt_ptr - du->dk_bad.bt_bad) - 1;
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+#ifdef WDDEBUG
+ printf("new = %d\n", blknum);
+#endif
+ break;
+ }
+ }
+/*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/
+ sector += 1; /* sectors begin with 1, not 0 */
+
+ wdtab.b_active = 1; /* mark controller active */
+ wdc = du->dk_port;
+
+RETRY:
+ /* if starting a multisector transfer, or doing single transfers */
+ if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
+ if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0)
+ du->dk_bc += DEV_BSIZE;
+
+ /* controller idle? */
+ timeout = 0;
+ while (inb(wdc+wd_status) & WDCS_BUSY)
+ {
+ if (++timeout > WDCTIMEOUT)
+ {
+ printf("wd.c: Controller busy too long!\n");
+ /* reset the device */
+ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
+ DELAY(1000);
+ outb(wdc+wd_ctlr, WDCTL_IDS);
+ DELAY(1000);
+ (void) inb(wdc+wd_error); /* XXX! */
+ outb(wdc+wd_ctlr, WDCTL_4BIT);
+ break;
+ }
+ }
+
+ /* stuff the task file */
+ outb(wdc+wd_precomp, lp->d_precompcyl / 4);
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT) {
+ outb(wdc+wd_sector, lp->d_gap3);
+ outb(wdc+wd_seccnt, lp->d_nsectors);
+ } else {
+#endif
+ if (du->dk_flags & DKFL_SINGLE)
+ outb(wdc+wd_seccnt, 1);
+ else
+ outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE));
+ outb(wdc+wd_sector, sector);
+
+#ifdef B_FORMAT
+ }
+#endif
+
+ outb(wdc+wd_cyl_lo, cylin);
+ outb(wdc+wd_cyl_hi, cylin >> 8);
+
+ /* set up the SDH register (select drive) */
+ outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
+
+ /* wait for drive to become ready */
+ timeout = 0;
+ while ((inb(wdc+wd_status) & WDCS_READY) == 0)
+ {
+ if (++timeout > WDCTIMEOUT)
+ {
+ printf("wd.c: Drive busy too long!\n");
+ /* reset the device */
+ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
+ DELAY(1000);
+ outb(wdc+wd_ctlr, WDCTL_IDS);
+ DELAY(1000);
+ (void) inb(wdc+wd_error); /* XXX! */
+ outb(wdc+wd_ctlr, WDCTL_4BIT);
+ goto RETRY;
+ }
+ }
+
+ /* initiate command! */
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT)
+ outb(wdc+wd_command, WDCC_FORMAT);
+ else
+#endif
+ outb(wdc+wd_command,
+ (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
+#ifdef WDDEBUG
+ printf("sector %d cylin %d head %d addr %x sts %x\n",
+ sector, cylin, head, addr, inb(wdc+wd_altsts));
+#endif
+ }
+
+ /* if this is a read operation, just go away until it's done. */
+ if (bp->b_flags & B_READ) return;
+
+ /* ready to send data? */
+ timeout = 0;
+ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
+ {
+ if (++timeout > WDCTIMEOUT)
+ {
+ printf("wd.c: Drive not ready for too long!\n");
+ /* reset the device */
+ outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
+ DELAY(1000);
+ outb(wdc+wd_ctlr, WDCTL_IDS);
+ DELAY(1000);
+ (void) inb(wdc+wd_error); /* XXX! */
+ outb(wdc+wd_ctlr, WDCTL_4BIT);
+ goto RETRY;
+ }
+ }
+
+ /* then send it! */
+ outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
+ DEV_BSIZE/sizeof(short));
+ du->dk_bc -= DEV_BSIZE;
+}
+
+/* Interrupt routine for the controller. Acknowledge the interrupt, check for
+ * errors on the current operation, mark it done if necessary, and start
+ * the next request. Also check for a partially done transfer, and
+ * continue with the next chunk if so.
+ */
+void
+wdintr(struct intrframe wdif)
+{
+ register struct disk *du;
+ register struct buf *bp, *dp;
+ int status, wdc;
+ char partch ;
+
+ if (!wdtab.b_active) {
+#ifdef nyet
+ printf("wd: extra interrupt\n");
+#endif
+ return;
+ }
+
+ dp = wdtab.b_actf;
+ bp = dp->b_actf;
+ du = wddrives[wdunit(bp->b_dev)];
+ wdc = du->dk_port;
+
+#ifdef WDDEBUG
+ printf("I ");
+#endif
+
+ while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
+
+ /* is it not a transfer, but a control operation? */
+ if (du->dk_state < OPEN) {
+ if (wdcontrol(bp))
+ wdstart();
+ return;
+ }
+
+ /* have we an error? */
+ if (status & (WDCS_ERR | WDCS_ECCCOR)) {
+
+ du->dk_status = status;
+ du->dk_error = inb(wdc + wd_error);
+#ifdef WDDEBUG
+ printf("status %x error %x\n", status, du->dk_error);
+#endif
+ if((du->dk_flags & DKFL_SINGLE) == 0) {
+ du->dk_flags |= DKFL_ERROR;
+ goto outt;
+ }
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT) {
+ bp->b_error = EIO; /* 17 Sep 92*/
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+#endif
+
+ /* error or error correction? */
+ if (status & WDCS_ERR) {
+ if (++wdtab.b_errcnt < RETRIES) {
+ wdtab.b_active = 0;
+ } else {
+ if((du->dk_flags&DKFL_QUIET) == 0) {
+ diskerr(bp, "wd", "hard error",
+ LOG_PRINTF, du->dk_skip,
+ &du->dk_dd);
+#ifdef WDDEBUG
+ printf( "status %b error %b\n",
+ status, WDCS_BITS,
+ inb(wdc+wd_error), WDERR_BITS);
+#endif
+ }
+ bp->b_error = EIO; /* 17 Sep 92*/
+ bp->b_flags |= B_ERROR; /* flag the error */
+ }
+ } else if((du->dk_flags&DKFL_QUIET) == 0) {
+ diskerr(bp, "wd", "soft ecc", 0,
+ du->dk_skip, &du->dk_dd);
+ }
+ }
+outt:
+
+ /*
+ * If this was a successful read operation, fetch the data.
+ */
+ if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
+ int chk, dummy;
+
+ chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
+
+ /* ready to receive data? */
+ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
+ ;
+
+ /* suck in data */
+ insw (wdc+wd_data,
+ (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
+ du->dk_bc -= chk * sizeof(short);
+
+ /* for obselete fractional sector reads */
+ while (chk++ < 256) insw (wdc+wd_data, &dummy, 1);
+ }
+
+ wdxfer[du->dk_unit]++;
+ if (wdtab.b_active) {
+ if ((bp->b_flags & B_ERROR) == 0) {
+ du->dk_skip++; /* Add to successful sectors. */
+ if (wdtab.b_errcnt && (du->dk_flags & DKFL_QUIET) == 0)
+ diskerr(bp, "wd", "soft error", 0,
+ du->dk_skip, &du->dk_dd);
+ wdtab.b_errcnt = 0;
+
+ /* see if more to transfer */
+ if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
+ wdstart();
+ return; /* next chunk is started */
+ } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR))
+ == DKFL_ERROR) {
+ du->dk_skip = 0;
+ du->dk_flags &= ~DKFL_ERROR;
+ du->dk_flags |= DKFL_SINGLE;
+ wdstart();
+ return; /* redo xfer sector by sector */
+ }
+ }
+
+done:
+ /* done with this transfer, with or without error */
+ du->dk_flags &= ~DKFL_SINGLE;
+ wdtab.b_actf = dp->b_forw;
+ wdtab.b_errcnt = 0;
+ du->dk_skip = 0;
+ dp->b_active = 0;
+ dp->b_actf = bp->av_forw;
+ dp->b_errcnt = 0;
+ bp->b_resid = 0;
+ biodone(bp);
+ }
+
+ /* controller idle */
+ wdtab.b_active = 0;
+
+ /* anything more on drive queue? */
+ if (dp->b_actf)
+ wdustart(du);
+ /* anything more for controller to do? */
+ if (wdtab.b_actf)
+ wdstart();
+}
+
+/*
+ * Initialize a drive.
+ */
+int
+wdopen(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ register unsigned int unit;
+ register struct disk *du;
+ int part = wdpart(dev), mask = 1 << part;
+ struct partition *pp;
+ struct dkbad *db;
+ int i, error = 0;
+ char *msg;
+
+ unit = wdunit(dev);
+ if (unit >= _NWD) return (ENXIO) ;
+
+ du = wddrives[unit];
+ if (du == 0) return (ENXIO) ;
+
+ if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
+ du->dk_flags |= DKFL_WRITEPROT;
+ wdutab[unit].b_actf = NULL;
+
+ /*
+ * Use the default sizes until we've read the label,
+ * or longer if there isn't one there.
+ */
+ bzero(&du->dk_dd, sizeof(du->dk_dd));
+#undef d_type /* fix goddamn segments.h! XXX */
+ du->dk_dd.d_type = DTYPE_ST506;
+ du->dk_dd.d_ncylinders = 1024;
+ du->dk_dd.d_secsize = DEV_BSIZE;
+ du->dk_dd.d_ntracks = 8;
+ du->dk_dd.d_nsectors = 17;
+ du->dk_dd.d_secpercyl = 17*8;
+ du->dk_state = WANTOPEN;
+ du->dk_unit = unit;
+ du->dk_flags &= ~DKFL_QUIET;
+
+ /* read label using "c" partition */
+ if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
+ wdstrategy, &du->dk_dd, du->dk_dospartitions,
+ &du->dk_bad, 0)) {
+ if((du->dk_flags&DKFL_QUIET) == 0) {
+ log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
+ unit, msg);
+ error = EINVAL; /* XXX needs translation */
+ }
+ goto done;
+ } else {
+
+ wdsetctlr(dev, du);
+ du->dk_flags |= DKFL_BSDLABEL;
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if (du->dk_dd.d_flags & D_BADSECT)
+ du->dk_flags |= DKFL_BADSECT;
+ }
+
+done:
+ if (error)
+ return(error);
+
+ }
+ /*
+ * Warn if a partion is opened
+ * that overlaps another partition which is open
+ * unless one is the "raw" partition (whole disk).
+ */
+ if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
+ int start, end;
+
+ pp = &du->dk_dd.d_partitions[part];
+ start = pp->p_offset;
+ end = pp->p_offset + pp->p_size;
+ for (pp = du->dk_dd.d_partitions;
+ pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
+ pp++) {
+ if (pp->p_offset + pp->p_size <= start ||
+ pp->p_offset >= end)
+ continue;
+ /*if (pp - du->dk_dd.d_partitions == RAWPART)
+ continue; */
+ if (pp - du->dk_dd.d_partitions == WDRAW)
+ continue;
+ if (du->dk_openpart & (1 << (pp -
+ du->dk_dd.d_partitions)))
+ log(LOG_WARNING,
+ "wd%d%c: overlaps open partition (%c)\n",
+ unit, part + 'a',
+ pp - du->dk_dd.d_partitions + 'a');
+ }
+ }
+ if (part >= du->dk_dd.d_npartitions && part != WDRAW)
+ return (ENXIO);
+
+ /* insure only one open at a time */
+ du->dk_openpart |= mask;
+ switch (fmt) {
+ case S_IFCHR:
+ du->dk_copenpart |= mask;
+ break;
+ case S_IFBLK:
+ du->dk_bopenpart |= mask;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Implement operations other than read/write.
+ * Called from wdstart or wdintr during opens and formats.
+ * Uses finite-state-machine to track progress of operation in progress.
+ * Returns 0 if operation still in progress, 1 if completed.
+ */
+static int
+wdcontrol(register struct buf *bp)
+{
+ register struct disk *du;
+ register unit;
+ unsigned char stat;
+ int s, cnt;
+ extern int bootdev;
+ int cyl, trk, sec, i, wdc;
+ struct wdparams foo;
+
+ du = wddrives[wdunit(bp->b_dev)];
+ unit = du->dk_unit;
+ wdc = du->dk_port;
+
+ switch (du->dk_state) {
+
+ tryagainrecal:
+ case WANTOPEN: /* set SDH, step rate, do restore */
+#ifdef WDDEBUG
+ printf("wd%d: recal ", unit);
+#endif
+ s = splbio(); /* not called from intr level ... */
+ wdgetctlr(unit, du);
+
+ outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
+ wdtab.b_active = 1;
+
+ /* wait for drive and controller to become ready */
+ for (i = WDCTIMEOUT; (inb(wdc+wd_status) & (WDCS_READY|WDCS_BUSY))
+ != WDCS_READY && i-- != 0; )
+ ;
+ outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
+ du->dk_state++;
+ splx(s);
+ return(0);
+
+ case RECAL:
+ if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
+ if ((du->dk_flags & DKFL_QUIET) == 0) {
+ printf("wd%d: recal", du->dk_unit);
+ printf(": status %b error %b\n",
+ stat, WDCS_BITS, inb(wdc+wd_error),
+ WDERR_BITS);
+ }
+ if (++wdtab.b_errcnt < RETRIES) {
+ du->dk_state = WANTOPEN;
+ goto tryagainrecal;
+ }
+ bp->b_error = ENXIO; /* XXX needs translation */
+ goto badopen;
+ }
+
+ /* some controllers require this ... */
+ wdsetctlr(bp->b_dev, du);
+
+ wdtab.b_errcnt = 0;
+ du->dk_state = OPEN;
+ /*
+ * The rest of the initialization can be done
+ * by normal means.
+ */
+ return(1);
+
+ default:
+ panic("wdcontrol");
+ }
+ /* NOTREACHED */
+
+badopen:
+ if ((du->dk_flags & DKFL_QUIET) == 0)
+ printf(": status %b error %b\n",
+ stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS);
+ bp->b_flags |= B_ERROR;
+ return(1);
+}
+
+/*
+ * send a command and wait uninterruptibly until controller is finished.
+ * return -1 if controller busy for too long, otherwise
+ * return status. intended for brief controller commands at critical points.
+ * assumes interrupts are blocked.
+ */
+static int
+wdcommand(struct disk *du, int cmd) {
+ int timeout = WDCTIMEOUT, stat, wdc;
+
+ /* controller ready for command? */
+ wdc = du->dk_port;
+ while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
+ timeout--;
+ if (timeout <= 0)
+ return(-1);
+
+ /* send command, await results */
+ outb(wdc+wd_command, cmd);
+ while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
+ timeout--;
+ if (timeout <= 0)
+ return(-1);
+ if (cmd != WDCC_READP)
+ return (stat);
+
+ /* is controller ready to return data? */
+ while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
+ timeout > 0)
+ timeout--;
+ if (timeout <= 0)
+ return(-1);
+
+ return (stat);
+}
+
+/*
+ * issue IDC to drive to tell it just what geometry it is to be.
+ */
+static int
+wdsetctlr(dev_t dev, struct disk *du) {
+ int stat, x, wdc;
+
+/*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
+ du->dk_dd.d_nsectors);*/
+
+ x = splbio();
+ wdc = du->dk_port;
+ outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
+ outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
+ outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
+ outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
+ stat = wdcommand(du, WDCC_IDC);
+
+ if (stat < 0) {
+ splx(x);
+ return(stat);
+ }
+ if (stat & WDCS_ERR)
+ printf("wdsetctlr: status %b error %b\n",
+ stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
+ splx(x);
+ return(stat);
+}
+
+/*
+ * issue READP to drive to ask it what it is.
+ */
+static int
+wdgetctlr(int u, struct disk *du) {
+ int stat, x, i, wdc;
+ char tb[DEV_BSIZE];
+ struct wdparams *wp;
+
+ x = splbio(); /* not called from intr level ... */
+ wdc = du->dk_port;
+ outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
+ stat = wdcommand(du, WDCC_READP);
+
+ if (stat < 0) {
+ splx(x);
+ return(stat);
+ }
+ if (stat & WDCS_ERR) {
+ stat = inb(wdc+wd_error);
+ splx(x);
+ return(stat);
+ }
+
+ /* obtain parameters */
+ wp = &du->dk_params;
+ insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
+ bcopy(tb, wp, sizeof(struct wdparams));
+
+ /* shuffle string byte order */
+ for (i=0; i < sizeof(wp->wdp_model) ;i+=2) {
+ u_short *p;
+ p = (u_short *) (wp->wdp_model + i);
+ *p = ntohs(*p);
+ }
+/*printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config,
+wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors,
+wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);*/
+
+ /* update disklabel given drive information */
+ du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
+ du->dk_dd.d_ntracks = wp->wdp_heads;
+ du->dk_dd.d_nsectors = wp->wdp_sectors;
+ du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
+ du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl *
+ wp->wdp_sectors;
+ du->dk_dd.d_partitions[1].p_offset = 0;
+ /* dubious ... */
+ bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
+ bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1);
+ /* better ... */
+ du->dk_dd.d_type = DTYPE_ESDI;
+ du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
+
+ /* XXX sometimes possibly needed */
+ (void) inb(wdc+wd_status);
+ return (0);
+}
+
+
+/* ARGSUSED */
+int
+wdclose(dev_t dev, int flags, int fmt)
+{
+ register struct disk *du;
+ int part = wdpart(dev), mask = 1 << part;
+
+ du = wddrives[wdunit(dev)];
+
+ /* insure only one open at a time */
+ du->dk_openpart &= ~mask;
+ switch (fmt) {
+ case S_IFCHR:
+ du->dk_copenpart &= ~mask;
+ break;
+ case S_IFBLK:
+ du->dk_bopenpart &= ~mask;
+ break;
+ }
+ return(0);
+}
+
+int
+wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ int unit = wdunit(dev);
+ register struct disk *du;
+ int error = 0;
+ struct uio auio;
+ struct iovec aiov;
+
+ du = wddrives[unit];
+
+ switch (cmd) {
+
+ case DIOCSBAD:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ du->dk_bad = *(struct dkbad *)addr;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)addr = du->dk_dd;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)addr)->disklab = &du->dk_dd;
+ ((struct partinfo *)addr)->part =
+ &du->dk_dd.d_partitions[wdpart(dev)];
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&du->dk_dd,
+ (struct disklabel *)addr,
+ /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0,
+ du->dk_dospartitions);
+ if (error == 0) {
+ du->dk_flags |= DKFL_BSDLABEL;
+ wdsetctlr(dev, du);
+ }
+ break;
+
+ case DIOCWLABEL:
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ du->dk_wlabel = *(int *)addr;
+ break;
+
+ case DIOCWDINFO:
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
+ /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0,
+ du->dk_dospartitions)) == 0) {
+ int wlab;
+
+ du->dk_flags |= DKFL_BSDLABEL;
+ wdsetctlr(dev, du);
+
+ /* simulate opening partition 0 so write succeeds */
+ du->dk_openpart |= (1 << 0); /* XXX */
+ wlab = du->dk_wlabel;
+ du->dk_wlabel = 1;
+ error = writedisklabel(dev, wdstrategy,
+ &du->dk_dd, du->dk_dospartitions);
+ du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
+ du->dk_wlabel = wlab;
+ }
+ break;
+
+#ifdef notyet
+ case DIOCGDINFOP:
+ *(struct disklabel **)addr = &(du->dk_dd);
+ break;
+
+ case DIOCWFORMAT:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else {
+ register struct format_op *fop;
+
+ fop = (struct format_op *)addr;
+ aiov.iov_base = fop->df_buf;
+ aiov.iov_len = fop->df_count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = fop->df_count;
+ auio.uio_segflg = 0;
+ auio.uio_offset =
+ fop->df_startblk * du->dk_dd.d_secsize;
+ error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
+ minphys, &auio);
+ fop->df_count -= auio.uio_resid;
+ fop->df_reg[0] = du->dk_status;
+ fop->df_reg[1] = du->dk_error;
+ }
+ break;
+#endif
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+#ifdef B_FORMAT
+int
+wdformat(struct buf *bp)
+{
+
+ bp->b_flags |= B_FORMAT;
+ return (wdstrategy(bp));
+}
+#endif
+
+int
+wdsize(dev_t dev)
+{
+ int unit = wdunit(dev), part = wdpart(dev), val;
+ struct disk *du;
+
+ if (unit >= _NWD) /* 31 Jul 92*/
+ return(-1);
+
+ du = wddrives[unit];
+ if (du == 0 || du->dk_state == 0)
+ val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0);
+ if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT)
+ return (-1);
+
+ return((int)du->dk_dd.d_partitions[part].p_size);
+}
+
+extern char *vmmap; /* poor name! */
+
+int
+wddump(dev_t dev) /* dump core after a system crash */
+{
+ register struct disk *du; /* disk unit to do the IO */
+ register struct bt_bad *bt_ptr;
+ long num; /* number of sectors to write */
+ int unit, part, wdc;
+ long blkoff, blknum, blkcnt;
+ long cylin, head, sector, stat;
+ long secpertrk, secpercyl, nblocks, i;
+ char *addr;
+ extern int Maxmem;
+ static wddoingadump = 0 ;
+ extern caddr_t CADDR1;
+
+ addr = (char *) 0; /* starting address */
+
+ /* toss any characters present prior to dump */
+ while (sgetc(1))
+ ;
+
+ /* size of memory to dump */
+ num = Maxmem;
+ unit = wdunit(dev); /* eventually support floppies? */
+ part = wdpart(dev); /* file system */
+ /* check for acceptable drive number */
+ if (unit >= _NWD) return(ENXIO); /* 31 Jul 92*/
+
+ du = wddrives[unit];
+ if (du == 0) return(ENXIO);
+ /* was it ever initialized ? */
+ if (du->dk_state < OPEN) return (ENXIO) ;
+ if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO);
+ wdc = du->dk_port;
+
+ /* Convert to disk sectors */
+ num = (u_long) num * NBPG / du->dk_dd.d_secsize;
+
+ /* check if controller active */
+ /*if (wdtab.b_active) return(EFAULT); */
+ if (wddoingadump) return(EFAULT);
+
+ secpertrk = du->dk_dd.d_nsectors;
+ secpercyl = du->dk_dd.d_secpercyl;
+ nblocks = du->dk_dd.d_partitions[part].p_size;
+ blkoff = du->dk_dd.d_partitions[part].p_offset;
+
+/*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
+ /* check transfer bounds against partition size */
+ if ((dumplo < 0) || ((dumplo + num) > nblocks))
+ return(EINVAL);
+
+ /*wdtab.b_active = 1; /* mark controller active for if we
+ panic during the dump */
+ wddoingadump = 1 ; i = 100000 ;
+ while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
+ outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
+ outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
+ while (inb(wdc+wd_status) & WDCS_BUSY) ;
+
+ /* some compaq controllers require this ... */
+ wdsetctlr(dev, du);
+
+ blknum = dumplo + blkoff;
+ while (num > 0) {
+#ifdef notdef
+ if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
+ if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
+ blkcnt = secpercyl - (blknum % secpercyl);
+ /* keep transfer within current cylinder */
+#endif
+ pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
+
+ /* compute disk address */
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+
+#ifdef notyet
+ /*
+ * See if the current block is in the bad block list.
+ * (If we have one.)
+ */
+ for (bt_ptr = du->dk_bad.bt_bad;
+ bt_ptr->bt_cyl != -1; bt_ptr++) {
+ if (bt_ptr->bt_cyl > cylin)
+ /* Sorted list, and we passed our cylinder.
+ quit. */
+ break;
+ if (bt_ptr->bt_cyl == cylin &&
+ bt_ptr->bt_trksec == (head << 8) + sector) {
+ /*
+ * Found bad block. Calculate new block addr.
+ * This starts at the end of the disk (skip the
+ * last track which is used for the bad block list),
+ * and works backwards to the front of the disk.
+ */
+ blknum = (du->dk_dd.d_secperunit)
+ - du->dk_dd.d_nsectors
+ - (bt_ptr - du->dk_bad.bt_bad) - 1;
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+ break;
+ }
+
+#endif
+ sector++; /* origin 1 */
+
+ /* select drive. */
+ outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
+ while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
+
+ /* transfer some blocks */
+ outb(wdc+wd_sector, sector);
+ outb(wdc+wd_seccnt,1);
+ outb(wdc+wd_cyl_lo, cylin);
+ outb(wdc+wd_cyl_hi, cylin >> 8);
+#ifdef notdef
+ /* lets just talk about this first...*/
+ pg ("sdh 0%o sector %d cyl %d addr 0x%x",
+ inb(wdc+wd_sdh), inb(wdc+wd_sector),
+ inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
+#endif
+ outb(wdc+wd_command, WDCC_WRITE);
+
+ /* Ready to send data? */
+ while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
+ if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
+
+ outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
+
+ if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
+ /* Check data request (should be done). */
+ if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
+
+ /* wait for completion */
+ for ( i = WDCTIMEOUT ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
+ if (i < 0) return (EIO) ;
+ }
+ /* error check the xfer */
+ if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
+
+ if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ;
+ /* update block count */
+ num--;
+ blknum++ ;
+ (int) addr += 512;
+
+ /* operator aborting dump? */
+ if (sgetc(1))
+ return(EINTR);
+ }
+ return(0);
+}
+#endif
diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h
new file mode 100644
index 0000000..d938915
--- /dev/null
+++ b/sys/i386/isa/wdreg.h
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wdreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Disk Controller register definitions.
+ */
+#define wd_data 0x0 /* data register (R/W - 16 bits) */
+#define wd_error 0x1 /* error register (R) */
+#define wd_precomp wd_error /* write precompensation (W) */
+#define wd_seccnt 0x2 /* sector count (R/W) */
+#define wd_sector 0x3 /* first sector number (R/W) */
+#define wd_cyl_lo 0x4 /* cylinder address, low byte (R/W) */
+#define wd_cyl_hi 0x5 /* cylinder address, high byte (R/W)*/
+#define wd_sdh 0x6 /* sector size/drive/head (R/W)*/
+#define wd_command 0x7 /* command register (W) */
+#define wd_status wd_command /* immediate status (R) */
+
+#define wd_altsts 0x206 /*alternate fixed disk status(via 1015) (R)*/
+#define wd_ctlr 0x206 /*fixed disk controller control(via 1015) (W)*/
+#define WDCTL_4BIT 0x8 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x4 /* reset the controller */
+#define WDCTL_IDS 0x2 /* disable controller interrupts */
+#define wd_digin 0x207 /* disk controller input(via 1015) (R)*/
+
+/*
+ * Status Bits.
+ */
+#define WDCS_BUSY 0x80 /* Controller busy bit. */
+#define WDCS_READY 0x40 /* Selected drive is ready */
+#define WDCS_WRTFLT 0x20 /* Write fault */
+#define WDCS_SEEKCMPLT 0x10 /* Seek complete */
+#define WDCS_DRQ 0x08 /* Data request bit. */
+#define WDCS_ECCCOR 0x04 /* ECC correction made in data */
+#define WDCS_INDEX 0x02 /* Index pulse from selected drive */
+#define WDCS_ERR 0x01 /* Error detect bit. */
+
+#define WDCS_BITS "\020\010busy\006rdy\006wrtflt\005seekdone\004drq\003ecc_cor\002index\001err"
+
+#define WDERR_BITS "\020\010badblk\007uncorr\006id_crc\005no_id\003abort\002tr000\001no_dam"
+
+/*
+ * Commands for Disk Controller.
+ */
+#define WDCC_RESTORE 0x10 /* disk restore code -- resets cntlr */
+
+#define WDCC_READ 0x20 /* disk read code */
+#define WDCC_WRITE 0x30 /* disk write code */
+#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
+#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
+
+#define WDCC_FORMAT 0x50 /* disk format code */
+#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
+#define WDCC_IDC 0x91 /* initialize drive command */
+
+#define WDCC_EXTDCMD 0xE0 /* send extended command */
+#define WDCC_READP 0xEC /* read parameters from controller */
+#define WDCC_CACHEC 0xEF /* cache control */
+
+#define WD_STEP 0 /* winchester- default 35us step */
+
+#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
+
+
+#ifdef KERNEL
+/*
+ * read parameters command returns this:
+ */
+struct wdparams {
+ /* drive info */
+ short wdp_config; /* general configuration */
+ short wdp_fixedcyl; /* number of non-removable cylinders */
+ short wdp_removcyl; /* number of removable cylinders */
+ short wdp_heads; /* number of heads */
+ short wdp_unfbytespertrk; /* number of unformatted bytes/track */
+ short wdp_unfbytes; /* number of unformatted bytes/sector */
+ short wdp_sectors; /* number of sectors */
+ short wdp_minisg; /* minimum bytes in inter-sector gap*/
+ short wdp_minplo; /* minimum bytes in postamble */
+ short wdp_vendstat; /* number of words of vendor status */
+ /* controller info */
+ char wdp_cnsn[20]; /* controller serial number */
+ short wdp_cntype; /* controller type */
+#define WDTYPE_SINGLEPORTSECTOR 1 /* single port, single sector buffer */
+#define WDTYPE_DUALPORTMULTI 2 /* dual port, multiple sector buffer */
+#define WDTYPE_DUALPORTMULTICACHE 3 /* above plus track cache */
+ short wdp_cnsbsz; /* sector buffer size, in sectors */
+ short wdp_necc; /* ecc bytes appended */
+ char wdp_rev[8]; /* firmware revision */
+ char wdp_model[40]; /* model name */
+ short wdp_nsecperint; /* sectors per interrupt */
+ short wdp_usedmovsd; /* can use double word read/write? */
+};
+
+/*
+ * wd driver entry points
+ */
+int wdprobe(struct isa_device *);
+int wdattach(struct isa_device *);
+int wdstrategy(struct buf *);
+void wdintr(struct intrframe);
+int wdopen(dev_t, int, int, struct proc *);
+int wdclose(dev_t dev, int flags, int fmt);
+int wdioctl(dev_t, int, caddr_t, int);
+/* int wdformat(struct buf *bp); */
+int wdsize(dev_t);
+int wddump(dev_t);
+
+#endif KERNEL
diff --git a/sys/i386/isa/wt.c b/sys/i386/isa/wt.c
new file mode 100644
index 0000000..4376395
--- /dev/null
+++ b/sys/i386/isa/wt.c
@@ -0,0 +1,1162 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wt.c 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ *
+ * Copyright (c) 1989 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Robert Baron
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "wt.h"
+#if NWT > 0
+/*
+ * HISTORY
+ * $Log: wt.c,v $
+ * Revision 2.2.1.3 90/01/08 13:29:38 rvb
+ * Add Intel copyright.
+ * [90/01/08 rvb]
+ *
+ * Revision 2.2.1.2 89/12/21 18:00:09 rvb
+ * Change WTPRI to make the streamer tape read/write
+ * interruptible. [lin]
+ *
+ * Revision 2.2.1.1 89/11/10 09:49:49 rvb
+ * ORC likes their streamer port at 0x288.
+ * [89/11/08 rvb]
+ *
+ * Revision 2.2 89/09/25 12:33:02 rvb
+ * Driver was provided by Intel 9/18/89.
+ * [89/09/23 rvb]
+ *
+ */
+
+/*
+ *
+ * Copyright 1988, 1989 by Intel Corporation
+ *
+ * Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02
+ */
+
+/*#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/types.h>*/
+#include "sys/param.h"
+#include "sys/buf.h"
+#include "sys/file.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "i386/isa/wtreg.h"
+
+#ifdef ORC
+unsigned wtport = 0x288; /* base I/O port of controller */
+#else ORC
+unsigned wtport = 0x300; /* base I/O port of controller */
+#endif ORC
+ /* standard = 0x300 */
+ /* alternate = 0x338 */
+
+unsigned wtchan = 1; /* DMA channel number */
+ /* stardard = 1 */
+ /* hardware permits 1, 2 or 3. */
+ /* (Avoid DMA 2: used by disks) */
+
+int first_wtopen_ever = 1;
+
+
+#define ERROR 1 /* return from tape routines */
+#define SUCCESS 0 /* return from tape routines */
+
+int wci = 0;
+int exflag = 0;
+int bytes = 0;
+
+static unsigned char eqdma = 0x8;
+static unsigned char pagereg = 0x83;
+static unsigned char dmareg = 2;
+static unsigned char dma_write = 0x49;
+static unsigned char dma_read = 0x45;
+static unsigned char dma_done = 2;
+static unsigned char mode = 0;
+static unsigned char mbits; /* map bits into each other */
+static long bufptr;
+static unsigned numbytes;
+/*
+_wci dw 0 ; interrupt chain finished normally
+_exflag dw 0 ; exception variable
+_bytes dw 0 ; current bytes
+
+eqdma db 8h ; enable dma command: ch1,ch2=8h, ch3=10h
+pagereg db 83h ; ch1=83h, ch2=81h, ch3=82h
+dmareg db 2 ; ch1=2, ch2=4, ch3=6
+dma_write db 49h ; write dma command: 48h+_wtchan
+dma_read db 45h ; read dma command: 44h+_wtchan
+dma_done db 2 ; dma done flag: 1<<_wtchan
+mode db 0 ; dma operation mode
+lbufptr dw 0 ; buffer pointer to data buffers, low word
+hbufptr dw 0 ; buffer pointer to data buffers, high word
+numbytes dw 0 ; number of bytes to read or write (new)
+*/
+
+#define PAGESIZ 4096
+#define HZ 60
+
+/* tape controller ports */
+#define STATPORT wtport
+#define CTLPORT STATPORT
+#define CMDPORT (wtport+1)
+#define DATAPORT CMDPORT
+
+/* defines for reading out status from wangtek tape controller */
+#define READY 0x01 /* ready bit define */
+#define EXCEP 0x02 /* exception bit define */
+#define STAT (READY|EXCEP)
+#define RESETMASK 0x7
+#define RESETVAL (RESETMASK & ~EXCEP)
+
+/* tape controller control bits (CTLPORT) */
+#define ONLINE 0x01
+#define RESET 0x02
+#define REQUEST 0x04 /* request command */
+#define CMDOFF 0xC0
+
+/* QIC-02 commands (CMDPORT) */
+#define RDDATA 0x80 /* read data */
+#define READFM 0xA0 /* read file mark */
+#define WRTDATA 0x40 /* write data */
+#define WRITEFM 0x60 /* write file mark */
+#define RDSTAT 0xC0 /* read status command */
+#define REWIND 0x21 /* rewind command (position+bot) */
+
+/* 8237 DMA controller regs */
+#define STATUSREG 0x8
+#define MASKREG 0xA
+#define MODEREG 0xB
+#define CLEARFF 0xC
+
+/* streamer tape block size */
+#define BLKSIZE 512
+
+/* Tape characteristics */
+#define NBPS 512 /* 512-byte blocks */
+#define ERROR 1 /* return from tape routines */
+#define SUCCESS 0 /* return from tape routines */
+
+/* Minor devs */
+#define TP_REWCLOSE(d) ((minor(d)&04) == 0) /* Rewind tape on close if read/write */
+#define TP_DENS(dev) ((minor(dev) >> 3) & 03) /* set density */
+#define TPHOG(d) 0 /* use Hogproc during tape I/O */
+
+/* defines for wtflags */
+#define TPINUSE 0x0001 /* tape is already open */
+#define TPREAD 0x0002 /* tape is only open for reading */
+#define TPWRITE 0x0004 /* tape is only open for writing */
+#define TPSTART 0x0008 /* tape must be rewound and reset */
+#define TPDEAD 0x0010 /* tape drive does not work or driver error */
+#define TPSESS 0x0020 /* no more reads or writes allowed in session */
+ /* for example, when tape has to be changed */
+#define TPSTOP 0x0040 /* Stop command outstanding */
+#define TPREW 0x0080 /* Rewind command outstanding, see wtdsl2() */
+#define TPVOL 0x0100 /* Read file mark, or hit end of tape */
+#define TPWO 0x0200 /* write command outstanding */
+#define TPRO 0x0400 /* read command outstanding */
+#define TPWANY 0x0800 /* write command requested */
+#define TPRANY 0x1000 /* read command requested */
+#define TPWP 0x2000 /* write protect error seen */
+
+unsigned int wtflags = TPSTART; /* state of tape drive */
+
+struct buf rwtbuf; /* header for raw i/o */
+struct proc *myproc; /* process which opened tape driver */
+
+char wtimeron; /* wtimer() active flag */
+char wtio; /* dma (i/o) active flag */
+char isrlock; /* isr() flag */
+
+struct proc * Hogproc; /* no Hogproc on Microport */
+#define ftoseg(x) ((unsigned) (x >> 16))
+
+struct wtstatus {
+ ushort wt_err; /* code for error encountered */
+ ushort wt_ercnt; /* number of error blocks */
+ ushort wt_urcnt; /* number of underruns */
+} wterror;
+
+/* defines for wtstatus.wt_err */
+#define TP_POR 0x100 /* Power on/reset occurred */
+#define TP_RES1 0x200 /* Reserved for end of media */
+#define TP_RES2 0x400 /* Reserved for bus parity */
+#define TP_BOM 0x800 /* Beginning of media */
+#define TP_MBD 0x1000 /* Marginal block detected */
+#define TP_NDT 0x2000 /* No data detected */
+#define TP_ILL 0x4000 /* Illegal command */
+#define TP_ST1 0x8000 /* Status byte 1 bits */
+#define TP_FIL 0x01 /* File mark detected */
+#define TP_BNL 0x02 /* Bad block not located */
+#define TP_UDA 0x04 /* Unrecoverable data error */
+#define TP_EOM 0x08 /* End of media */
+#define TP_WRP 0x10 /* Write protected cartridge */
+#define TP_USL 0x20 /* Unselected drive */
+#define TP_CNI 0x40 /* Cartridge not in place */
+#define TP_ST0 0x80 /* Status byte 0 bits */
+
+/* Grounds for reporting I/O error to user */
+#define TP_ERR0 (TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL)
+#define TP_ERR1 (TP_MBD|TP_NDT|TP_ILL)
+/* TP_ILL should never happen! */
+/*
+#define TP_ERR0 0x7f
+#define TP_ERR1 0x7700
+*/
+
+/* defines for reading out status from wangtek tape controller */
+#define READY 0x01 /* ready bit define */
+#define EXCEP 0x02 /* exception bit define */
+
+/* sleep priority */
+#define WTPRI (PZERO+10)
+
+char pagebuf[NBPS]; /* buffer of size NBPS */
+unsigned long pageaddr; /* physical addr of pagebuf */
+ /* pageaddr is used with DMA controller */
+time_t Hogtime; /* lbolt when Hog timer started */
+extern time_t lbolt;
+
+#define debug printf
+
+/*
+ * Strategy routine.
+ *
+ * Arguments:
+ * Pointer to buffer structure
+ * Function:
+ * Start transfer.
+ *
+ * It would be nice to have this multiple-threaded.
+ * There is a version of dump from Berkeley that works with multiple processes
+ * trading off with disk & tape I/O.
+ */
+
+int
+wtstrategy(bp)
+register struct buf *bp;
+{
+ unsigned ucnt1, ucnt2, finished;
+ unsigned long adr1, adr2;
+ int bad;
+
+ adr1 = kvtop(bp->b_un.b_addr);
+#ifdef DEBUG
+ debug("bpaddr %x\n", adr1);
+#endif
+ ucnt1 = bp->b_bcount % NBPG;
+ ucnt2 = 0;
+ adr2 = 0;
+#ifdef DEBUG
+ debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1);
+#endif
+ /* 64K boundary? (XXX) */
+ if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1))
+ {
+ adr2 = (adr1 & 0xffff0000L) + 0x10000L;
+ ucnt2 = (adr1 + ucnt1) - adr2;
+ ucnt1 -= ucnt2;
+ }
+ /* page boundary? */
+ if (trunc_page(adr1) != trunc_page(adr1 + (unsigned) ucnt1 - 1))
+ { unsigned u;
+ u = NBPG - ((unsigned)bp->b_un.b_addr & (NBPG-1));
+ adr2 = kvtop(bp->b_un.b_addr + u);
+ ucnt2 = ucnt1 - u;
+ ucnt1 = u;
+ }
+ /* at file marks and end of tape, we just return '0 bytes available' */
+ if (wtflags & TPVOL) {
+ bp->b_resid = bp->b_bcount;
+ goto xit;
+ }
+ if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev))
+ {
+#ifdef DEBUG
+ printf("setting Hogproc\n");
+#endif
+ Hogtime = 0;
+ Hogproc = myproc;
+ }
+ if (bp->b_flags & B_READ) {
+ bad = 0;
+
+ /* For now, we assume that all data will be copied out */
+ /* If read command outstanding, just skip down */
+ if (!(wtflags & TPRO)) {
+ if (ERROR == wtsense(TP_WRP)) /* clear status */
+ goto errxit;
+#ifdef DEBUG
+ debug("WTread: Start read\n");
+#endif
+ if (!(wtflags & TPREAD) || (wtflags & TPWANY) ||
+ (rstart() == ERROR)) {
+#ifdef DEBUG
+ debug("Tpstart: read init error\n"); /* */
+#endif
+ goto errxit;
+ }
+ wtflags |= TPRO|TPRANY;
+ }
+
+ finished = 0;
+ /* Take a deep breath */
+ if (ucnt1) {
+ if ((rtape(adr1, ucnt1) == ERROR) &&
+ (wtsense(TP_WRP) == ERROR))
+ goto endio;
+ /* wait for it */
+ bad = pollrdy();
+ finished = bytes;
+ if (bad)
+ goto endio;
+ }
+ /* if a second I/O region, start it */
+ if (ucnt2) {
+ if ((rtape(adr2, ucnt2) == ERROR) &&
+ (wtsense(TP_WRP) == ERROR))
+ ucnt2 = 0; /* don't poll for me */
+ }
+
+ /* if second i/o pending wait for it */
+ if (ucnt2) {
+ pollrdy();
+ /* whether pollrdy is ok or not */
+ finished += bytes;
+ }
+ } else {
+ if (wtflags & TPWP) /* write protected */
+ goto errxit;
+
+ /* If write command outstanding, just skip down */
+ if (!(wtflags & TPWO)) {
+ if (ERROR == wtsense(0)) /* clear status */
+ {
+#ifdef DEBUG
+ debug("TPstart: sense 0\n");
+#endif
+ goto errxit;
+ }
+ if (!(wtflags & TPWRITE) || (wtflags & TPRANY) ||
+ (wstart() == ERROR)) {
+#ifdef DEBUG
+ debug("Tpstart: write init error\n"); /* */
+#endif
+ wtsense(0);
+
+errxit: bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ goto xit;
+ }
+ wtflags |= TPWO|TPWANY;
+ }
+
+ /* and hold your nose */
+ if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR)
+ && (wtsense(0) == ERROR)))
+ finished = bytes;
+
+ else if (ucnt2 &&
+ (((ucnt1 && pollrdy()) ||
+ (wtape(adr2, ucnt2) == ERROR)) &&
+ (wtsense(0) == ERROR)))
+ finished = ucnt1 + NBPS + bytes;
+ /* All writes and/or copyins were fine! */
+ else
+ finished = bp->b_bcount;
+ bad = pollrdy();
+ }
+
+ endio:
+ if(bad == EIO) bad = 0;
+ wterror.wt_err = 0;
+ if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) {
+ if ((wterror.wt_err & TP_ST0)
+ && (wterror.wt_err & (TP_FIL|TP_EOM))) {
+#ifdef DEBUG
+ debug("WTsta: Hit end of tape\n"); /* */
+#endif
+ wtflags |= TPVOL;
+ if (wterror.wt_err & TP_FIL) {
+ if (wtflags & TPRO)
+ /* interrupter is bogus */
+ rstart(); /* restart read command */
+ else
+ wtflags &= ~TPWO;
+ finished += NBPS;
+ }
+ /* Reading file marks or writing end of tape return 0 bytes */
+ } else {
+ bp->b_flags |= B_ERROR;
+ wtflags &= ~(TPWO|TPRO);
+ }
+ }
+
+ if(bad) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = bad;
+ }
+ bp->b_resid = bp->b_bcount - finished;
+xit:
+ biodone(bp);
+ if (wtimeron)
+ Hogtime = lbolt;
+ else if (Hogproc == myproc)
+ Hogproc = (struct proc *) 0;
+}
+
+/*
+ * simulate an interrupt periodically while I/O is going
+ * this is necessary in case interrupts get eaten due to
+ * multiple devices on a single IRQ line
+ */
+wtimer()
+{
+ /* If I/O going and not in isr(), simulate interrupt
+ * If no I/O for at least 1 second, stop being a Hog
+ * If I/O done and not a Hog, turn off wtimer()
+ */
+ if (wtio && !isrlock)
+ isr();
+
+ if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ))
+ Hogproc = (struct proc *) 0;
+
+ if (wtio || (Hogproc == myproc))
+ timeout(wtimer, (caddr_t) 0, HZ);
+ else
+ wtimeron = 0;
+}
+
+
+wtrawio(bp)
+struct buf *bp;
+{
+ wtstrategy(bp);
+ biowait(bp);
+ return(0);
+}
+
+/*
+ * ioctl routine
+ * for user level QIC commands only
+ */
+wtioctl(dev, cmd, arg, mode)
+int dev, cmd;
+unsigned long arg;
+int mode;
+{
+ if (cmd == WTQICMD)
+ {
+ if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR))
+ {
+ wtsense(0);
+ return(EIO);
+ }
+ return(0);
+ }
+ return(EINVAL);
+}
+
+/*
+ * open routine
+ * called on every device open
+ */
+wtopen(dev, flag)
+int dev, flag;
+{
+ if (first_wtopen_ever) {
+ wtinit();
+ first_wtopen_ever = 0;
+ }
+#ifdef DEBUG
+ printf("wtopen ...\n");
+#endif
+ if (!pageaddr) {
+ return(ENXIO);
+ }
+ if (wtflags & (TPINUSE)) {
+ return(ENXIO);
+ }
+ if (wtflags & (TPDEAD)) {
+ return(EIO);
+ }
+ /* If a rewind from the last session is going on, wait */
+ while(wtflags & TPREW) {
+#ifdef DEBUG
+ debug("Waiting for rew to finish\n");
+#endif
+ DELAY(1000000); /* delay one second */
+ }
+ /* Only do reset and select when tape light is off, and tape is rewound.
+ * This allows multiple volumes. */
+ if (wtflags & TPSTART) {
+ if (t_reset() != SUCCESS) {
+ return(ENXIO);
+ }
+#ifdef DEBUG
+ debug("reset done. calling wtsense\n");
+#endif
+ if (wtsense(TP_WRP) == ERROR) {
+ return (EIO);
+ }
+#ifdef DEBUG
+ debug("wtsense done\n");
+#endif
+ wtflags &= ~TPSTART;
+ }
+
+ wtflags = TPINUSE;
+ if (flag & FREAD)
+ wtflags |= TPREAD;
+ if (flag & FWRITE)
+ wtflags |= TPWRITE;
+ rwtbuf.b_flags = 0;
+ myproc = curproc; /* for comparison */
+#ifdef not
+ switch(TP_DENS(dev)) {
+case 0:
+cmds(0x28);
+break;
+case 1:
+cmds(0x29);
+break;
+case 2:
+cmds(0x27);
+break;
+case 3:
+cmds(0x24);
+ }
+#endif
+ return(0);
+}
+
+/*
+ * close routine
+ * called on last device close
+ * If not rewind-on-close, leave read or write command intact.
+ */
+wtclose(dev)
+{
+ int wtdsl2();
+
+#ifdef DEBUG
+ debug("WTclose:\n");
+#endif
+ if (Hogproc == myproc)
+ Hogproc = (struct proc *) 0;
+ if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) {
+ if (!(wtflags & TPWO))
+ wstart();
+#ifdef DEBUG
+ debug("WT: Writing file mark\n");
+#endif
+ wmark(); /* write file mark */
+#ifdef DEBUG
+ debug("WT: Wrote file mark, going to wait\n");
+#endif
+ if (rdyexc(HZ/10) == ERROR) {
+ wtsense(0);
+ }
+ }
+ if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) {
+ /* rewind tape to beginning of tape, deselect tape, and make a note */
+ /* don't wait until rewind, though */
+ /* Ending read or write causes rewind to happen, if no error,
+ * and READY and EXCEPTION stay up until it finishes */
+ if (wtflags & (TPRO|TPWO))
+ {
+#ifdef DEBUG
+ debug("End read or write\n");
+#endif
+ rdyexc(HZ/10);
+ ioend();
+ wtflags &= ~(TPRO|TPWO);
+ }
+ else wtwind();
+ wtflags |= TPSTART | TPREW;
+ timeout(wtdsl2, 0, HZ);
+ }
+ else if (!(wtflags & (TPVOL|TPWANY)))
+ {
+ /* space forward to after next file mark no writing done */
+ /* This allows skipping data without reading it.*/
+#ifdef DEBUG
+ debug("Reading past file mark\n");
+#endif
+ if (!(wtflags & TPRO))
+ rstart();
+ rmark();
+ if (rdyexc(HZ/10))
+ {
+ wtsense(TP_WRP);
+ }
+ }
+ wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO;
+ return(0);
+}
+
+/* return ERROR if user I/O request should receive an I/O error code */
+
+wtsense(ignor)
+{
+ wtflags &= ~(TPRO|TPWO);
+#ifdef DEBUGx
+ debug("WTsense: start ");
+#endif
+ if (rdstatus(&wterror) == ERROR)
+ {
+#ifdef DEBUG
+ debug("WTsense: Can't read status\n");
+#endif
+ return(ERROR);
+ }
+#ifdef DEBUG
+ if (wterror.wt_err & (TP_ST0|TP_ST1))
+ {
+ debug("Tperror: status %x error %d underruns %d\n",
+ wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt);
+ }
+ else
+ debug("done. no error\n");
+#endif
+ wterror.wt_err &= ~ignor; /* ignore certain errors */
+ reperr(wterror.wt_err);
+ if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) ||
+ ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1)))
+ return ERROR;
+
+ return SUCCESS;
+}
+
+/* lifted from tdriver.c from Wangtek */
+reperr(srb0)
+int srb0;
+{
+ int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */
+
+ if (s0) {
+ if (s0 & TP_USL)
+ sterr("Drive not online");
+ else if (s0 & TP_CNI)
+ sterr("No cartridge");
+ else if ((s0 & TP_WRP) && !(wtflags & TPWP))
+ {
+ sterr("Tape is write protected");
+ wtflags |= TPWP;
+ }
+ /*
+ if (s0 & TP_FIL)
+ sterr("Filemark detected");
+ */
+ else if (s0 & TP_BNL)
+ sterr("Block in error not located");
+ else if (s0 & TP_UDA)
+ sterr("Unrecoverable data error");
+ /*
+ else if (s0 & TP_EOM)
+ sterr("End of tape");
+ */
+ else if (s0 & TP_NDT)
+ sterr("No data detected");
+ /*
+ if (s0 & TP_POR)
+ sterr("Reset occured");
+ */
+ else if (s0 & TP_BOM)
+ sterr("Beginning of tape");
+ else if (s0 & TP_ILL)
+ sterr("Illegal command");
+ }
+}
+
+sterr(errstr)
+char *errstr;
+{
+ printf("Streamer: %s\n", errstr);
+}
+
+/* Wait until rewind finishes, and deselect drive */
+wtdsl2() {
+ int stat;
+
+ stat = inb(wtport) & (READY|EXCEP);
+#ifdef DEBUG
+ debug("Timeout: Waiting for rewind to finish: stat %x\n", stat);
+#endif
+ switch (stat) {
+ /* They're active low, ya'know */
+ case READY|EXCEP:
+ timeout(wtdsl2, (caddr_t) 0, HZ);
+ return;
+ case EXCEP:
+ wtflags &= ~TPREW;
+ return;
+ case READY:
+ case 0:
+ wtflags &= ~TPREW;
+ sterr("Rewind failed");
+ wtsense(TP_WRP);
+ return;
+ }
+ }
+
+wtwind() {
+#ifdef DEBUG
+ debug("WT: About to rewind\n");
+#endif
+ rwind(); /* actually start rewind */
+}
+
+wtintr(unit) {
+ if (wtflags & (TPWO|TPRO))
+ {
+ isrlock = 1;
+ if (wtio) isr();
+ isrlock = 0;
+ }
+}
+
+wtinit() {
+ if (wtchan < 1 || wtchan > 3)
+ {
+ sterr("Bad DMA channel, cannot init driver");
+ return;
+ }
+ wtlinit(); /* init assembly language variables */
+ pageset();
+}
+
+rdyexc(ticks)
+{
+ int s;
+#ifdef DEBUG
+ int os = 0xffff; /* force printout first time */
+#endif
+ for (;;) { /* loop until ready or exception */
+ s=(inb(wtport) & 0xff); /* read the status register */
+#ifdef DEBUG
+ if (os != s) {
+ debug("Status reg = %x\n", s); /* */
+ os = s;
+ }
+#endif
+ if (!(s & EXCEP)) /* check if exception have occured */
+ break;
+ if (!(s & READY)) /* check if controller is ready */
+ break;
+ s = splbio();
+ DELAY((ticks/HZ)*1000000); /* */
+ splx(s);
+ }
+#ifdef DEBUG
+ debug("Status reg = %x on return\n", s); /* */
+#endif
+ return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */
+}
+
+pollrdy()
+{
+ int sps;
+#ifdef DEBUG
+ debug("Pollrdy\n");
+#endif
+ sps = splbio();
+ while (wtio) {
+ int error;
+
+ if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH,
+ "wtpoll", 0)) {
+ splx(sps);
+ return(error);
+ }
+ }
+ splx(sps);
+#ifdef DEBUG
+ debug("Finish poll, wci %d exflag %d\n", wci, exflag);
+#endif
+ return (EIO);
+}
+
+wtdma() /* start up i/o operation, called from dma() in wtlib1.s */
+{
+ wtio = 1;
+ if (!wtimeron)
+ {
+ wtimeron = 1;
+ timeout(wtimer, (caddr_t) 0, HZ/2);
+ }
+}
+
+wtwake() /* end i/o operation, called from isr() in wtlib1.s */
+{
+ wtio = 0;
+ wakeup(&wci);
+}
+
+pageset()
+{
+ unsigned long pp;
+
+ pp = (unsigned long) pagebuf;
+ pageaddr = kvtop(pp);
+#ifdef DEBUG
+ debug("pageset: addr %lx\n", pageaddr);
+#endif
+}
+
+
+
+#define near
+
+static near
+sendcmd()
+{
+ /* desired command in global mbits */
+
+ outb(CTLPORT, mbits | REQUEST); /* set request */
+ while (inb(STATPORT) & READY); /* wait for ready */
+ outb(CTLPORT, mbits & ~REQUEST); /* reset request */
+ while ((inb(STATPORT) & READY) == 0); /* wait for not ready */
+}
+
+static near /* execute command */
+cmds(cmd)
+{
+ register s;
+
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready */
+
+ if ((s & EXCEP) == 0) /* if exception */
+ return ERROR; /* error */
+
+ outb(CMDPORT, cmd); /* output the command */
+
+ outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */
+ sendcmd();
+
+ return SUCCESS;
+}
+
+qicmd(cmd)
+{
+ return cmds(cmd);
+}
+
+rstart()
+{
+ return cmds(RDDATA);
+}
+
+rmark()
+{
+ return cmds(READFM);
+}
+
+wstart()
+{
+ return cmds(WRTDATA);
+}
+
+ioend()
+{
+ register s;
+ register rval = SUCCESS;
+
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready */
+
+ if ((s & EXCEP) == 0) /* if exception */
+ rval = ERROR; /* error */
+
+ mbits &= ~ONLINE;
+ outb(CTLPORT, mbits); /* reset ONLINE */
+ outb(MASKREG, wtchan+4); /* turn off dma */
+ outb(CLEARFF, 0); /* reset direction flag */
+
+ return rval;
+}
+
+wmark()
+{
+ register s;
+
+ if (cmds(WRITEFM) == ERROR)
+ return ERROR;
+
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready */
+
+ if ((s & EXCEP) == 0) /* if exception */
+ return ERROR; /* error */
+
+ return SUCCESS;
+}
+
+rwind()
+{
+ register s;
+
+ mbits = CMDOFF;
+
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready */
+
+ outb(CMDPORT, REWIND);
+ sendcmd();
+
+ return SUCCESS;
+}
+
+rdstatus(stp)
+char *stp; /* pointer to 6 byte buffer */
+{
+ register s;
+ int n;
+
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready or exception */
+
+ outb(CMDPORT, RDSTAT);
+ sendcmd(); /* send read status command */
+
+ for (n=0; n<6; n++)
+ {
+#ifdef DEBUGx
+ debug("rdstatus: waiting, byte %d\n", n);
+#endif
+ do s = inb(STATPORT);
+ while ((s & STAT) == STAT); /* wait for ready */
+#ifdef DEBUGx
+ debug("rdstatus: done\n");
+#endif
+ if ((s & EXCEP) == 0) /* if exception */
+ return ERROR; /* error */
+
+ *stp++ = inb(DATAPORT); /* read status byte */
+
+ outb(CTLPORT, mbits | REQUEST); /* set request */
+#ifdef DEBUGx
+ debug("rdstatus: waiting after request, byte %d\n", n);
+#endif
+ while ((inb(STATPORT)&READY) == 0); /* wait for not ready */
+ for (s=100; s>0; s--); /* wait an additional time */
+
+ outb(CTLPORT, mbits & ~REQUEST);/* unset request */
+#ifdef DEBUGx
+ debug("rdstatus: done\n");
+#endif
+ }
+ return SUCCESS;
+}
+
+t_reset()
+{
+ register i;
+ mbits |= RESET;
+ outb(CTLPORT, mbits); /* send reset */
+ DELAY(20);
+ mbits &= ~RESET;
+ outb(CTLPORT, mbits); /* turn off reset */
+ if ((inb(STATPORT) & RESETMASK) == RESETVAL)
+ return SUCCESS;
+ return ERROR;
+}
+
+static
+dma()
+{
+ int x=splbio();
+ wtdma();
+ outb(CLEARFF, 0);
+ outb(MODEREG, mode); /* set dma mode */
+ outb(dmareg, bufptr & 0xFF);
+ outb(dmareg, (bufptr>>8) & 0xFF);
+ outb(pagereg, (bufptr>>16) & 0xFF);
+ outb(dmareg+1, (BLKSIZE-1) & 0xFF);
+ outb(dmareg+1, (BLKSIZE-1) >> 8);
+ outb(wtport, eqdma+ONLINE);
+ outb(MASKREG, wtchan); /* enable command to 8237, start dma */
+ splx(x);
+}
+
+static near
+wtstart(buf, cnt)
+long buf;
+int cnt;
+{
+ register s;
+
+ bufptr = buf; /* init statics */
+ numbytes = cnt;
+ wci = 0; /* init flags */
+ exflag = 0;
+ bytes = 0; /* init counter */
+
+ do s = inb(STATPORT) & STAT;
+ while (s == STAT); /* wait for ready or error */
+
+ if (s & EXCEP) /* no error */
+ {
+ dma();
+ return SUCCESS;
+ }
+ return ERROR; /* error */
+}
+
+rtape(buf, cnt)
+long buf; /* physical address */
+int cnt; /* number of bytes */
+{
+ mode = dma_read;
+ return wtstart(buf,cnt);
+}
+
+wtape(buf, cnt)
+long buf; /* physical address */
+int cnt; /* number of bytes */
+{
+ mode = dma_write;
+ return wtstart(buf,cnt);
+}
+
+isr()
+{
+ int stat = inb(wtport);
+ if (!(stat & EXCEP)) /* exception during I/O */
+ {
+ if (bytes + BLKSIZE >= numbytes) wci = 1;
+ exflag = 1;
+ goto isrwake;
+ }
+ if ((stat & READY) || !(inb(STATUSREG) & dma_done))
+ return;
+ exflag = 0;
+ outb(wtport, ONLINE);
+ bytes += BLKSIZE;
+ if (bytes >= numbytes) /* normal completion of I/O */
+ {
+ wci = 1;
+isrwake:
+ outb(MASKREG, 4+wtchan); /* turn off dma */
+ wtwake(); /* wake up user level */
+ }
+ else
+ { /* continue I/O */
+ bufptr += BLKSIZE;
+ dma();
+ }
+}
+
+wtlinit()
+{
+ switch (wtchan) {
+ case 1:
+ return;
+ case 2:
+ pagereg = 0x81;
+ dma_done = 4;
+ break;
+ case 3:
+ eqdma = 0x10;
+ pagereg = 0x82;
+ dma_done = 8;
+ break;
+ }
+ dma_write = wtchan+0x48;
+ dma_read = wtchan+0x44;
+ dmareg = wtchan+wtchan;
+}
+
+wtsize()
+{
+}
+
+wtdump()
+{
+}
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+
+int wtprobe(), wtattach();
+struct isa_driver wtdriver = {
+ wtprobe, wtattach, "wt",
+};
+
+wtprobe(dvp)
+ struct isa_device *dvp;
+{
+ int val,i,s;
+
+#ifdef lint
+ wtintr(0);
+#endif
+
+ wtport = dvp->id_iobase;
+ if(t_reset() != SUCCESS) return(0);
+ return(1);
+}
+
+wtattach() { }
+
+#endif NWT
diff --git a/sys/i386/isa/wtreg.h b/sys/i386/isa/wtreg.h
new file mode 100644
index 0000000..8f79ca1
--- /dev/null
+++ b/sys/i386/isa/wtreg.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)wtreg.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ *
+ * Copyright (c) 1989 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Robert Baron
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: wtreg.h,v $
+ * Revision 2.2.1.1 90/01/08 13:29:25 rvb
+ * Add Intel copyright.
+ * [90/01/08 rvb]
+ *
+ * Revision 2.2 89/09/25 12:33:09 rvb
+ * Driver was provided by Intel 9/18/89.
+ * [89/09/23 rvb]
+ *
+ */
+
+/*
+ *
+ * Copyright 1988, 1989 by Intel Corporation
+ *
+ */
+
+/*
+ * wtioctl.h
+ * defines ioctl parameters for direct QIC commands
+ */
+
+#define WTIOC ('W'<<8)
+#define WTQICMD (WTIOC|0)
+
+/* QIC commands allowed */
+#define SELECT 0x01
+#define REWIND 0x21
+#define ERASE 0x22
+#define RETENS 0x24
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
new file mode 100644
index 0000000..0fb7701
--- /dev/null
+++ b/sys/isa/atrtc.c
@@ -0,0 +1,271 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 7.2 (Berkeley) 5/12/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 5 00158
+ * -------------------- ----- ----------------------
+ *
+ * 14 Aug 92 Arne Henrik Juul Added code in the kernel to
+ * allow for DST in the BIOS.
+ * 17 Jan 93 Bruce Evans Fixed leap year and second
+ * calculations
+ * 01 Feb 93 Julian Elischer Added code to for the cpu
+ * speed independent spinwait()
+ * function, (used by scsi and others)
+ * 25 Mar 93 Sean Eric Fagan Add microtimer support using timer 1
+ * 08 Apr 93 Poul-Henning Kamp/P-HK Fixes, and support for dcfclock
+ * 26 Apr 93 Bruce Evans Eliminate findspeed, new spinwait
+ * 26 Apr 93 Rodney W. Grimes I merged in Bruce changes and hope I
+ * still kept the other fixes... Had to
+ * add back in findcpuspeed that Bruce
+ * had removed.
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+#define DAYST 119
+#define DAYEN 303
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+
+startrtclock() {
+ int s;
+
+ findcpuspeed(); /* use the clock (while it's free)
+ to find the cpu speed */
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
+ outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+ outb (IO_RTC, RTC_DIAG);
+ outb (IO_RTC+1, 0);
+}
+
+unsigned int delaycount; /* calibrated loop variable (1 millisecond) */
+
+#define FIRST_GUESS 0x2000
+findcpuspeed()
+{
+ unsigned char low;
+ unsigned int remainder;
+
+ /* Put counter in count down mode */
+ outb(IO_TIMER1+3, 0x34);
+ outb(IO_TIMER1, 0xff);
+ outb(IO_TIMER1, 0xff);
+ delaycount = FIRST_GUESS;
+ spinwait(1);
+ /* Read the value left in the counter */
+ low = inb(IO_TIMER1); /* least siginifcant */
+ remainder = inb(IO_TIMER1); /* most significant */
+ remainder = (remainder<<8) + low ;
+ /* Formula for delaycount is :
+ * (loopcount * timer clock speed)/ (counter ticks * 1000)
+ */
+ delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
+}
+
+
+/* convert 2 digit BCD number */
+bcd(i)
+int i;
+{
+ return ((i/16)*10 + (i%16));
+}
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(y)
+int y;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+/* convert months to seconds */
+unsigned long
+mtos(m,leap)
+int m,leap;
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1;i<m;i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+inittodr(base)
+ time_t base;
+{
+ unsigned long sec;
+ int leap,day_week,t,yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+
+ /* XXX off by one? Need to calculate DST on SUNDAY */
+ /* Perhaps we should have the RTC hold GMT time to save */
+ /* us the bother of converting. */
+ yd = yd / (24*60*60);
+ if ((yd >= DAYST) && ( yd <= DAYEN)) {
+ sec -= 60*60;
+ }
+ sec += tz.tz_minuteswest * 60;
+
+ time.tv_sec = sec;
+}
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(base)
+ time_t base;
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+/*
+ * Restart the clock.
+ */
+resettodr()
+{
+}
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern V(clk)();
+enablertclock() {
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(millisecs)
+ int millisecs;
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/isa/fd.c b/sys/isa/fd.c
new file mode 100644
index 0000000..a461e81
--- /dev/null
+++ b/sys/isa/fd.c
@@ -0,0 +1,903 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fd.c 7.4 (Berkeley) 5/25/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ *
+ * Largely rewritten to handle multiple controllers and drives
+ * By Julian Elischer, Sun Apr 4 16:34:33 WST 1993
+ */
+char rev[] = "$Revision: 1.10 $";
+/*
+ * $Header: /usr/src/sys.386bsd/i386/isa/RCS/fd.c,v 1.10 93/04/13 16:53:29 root Exp $
+ */
+/*
+ * $Log: fd.c,v $
+ * Revision 1.10 93/04/13 16:53:29 root
+ * make sure turning off a drive motor doesn't deselect another
+ * drive active at the time.
+ * Also added a pointer from the fd_data to it's fd_type.
+ *
+ * Revision 1.9 93/04/13 15:31:02 root
+ * make all seeks go through DOSEEK state so are sure of being done right.
+ *
+ * Revision 1.8 93/04/12 21:20:13 root
+ * only check if old fd is the one we are working on if there IS
+ * an old fd pointer. (in fdstate())
+ *
+ * Revision 1.7 93/04/11 17:05:35 root
+ * cleanup timeouts etc.
+ * also fix bug to select teh correct drive when running > 1 drive
+ * at a time.
+ *
+ * Revision 1.6 93/04/05 00:48:45 root
+ * change a timeout and add version to banner message
+ *
+ * Revision 1.5 93/04/04 16:39:08 root
+ * first working version.. some floppy controllers don't seem to
+ * like 2 int. status inquiries in a row.
+ *
+ */
+
+#include "fd.h"
+#if NFD > 0
+
+#include "param.h"
+#include "dkbad.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "ioctl.h"
+#include "buf.h"
+#include "uio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+#undef NFD
+#define NFD 2
+
+#define FDUNIT(s) ((s>>3)&1)
+#define FDTYPE(s) ((s)&7)
+
+#define b_cylin b_resid
+#define FDBLK 512
+#define NUMTYPES 4
+
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int gap; /* gap len between sectors */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int steptrac; /* steps per cylinder */
+ int trans; /* transfer speed code */
+ int heads; /* number of heads */
+};
+
+struct fd_type fd_types[NUMTYPES] =
+{
+ { 18,2,0xFF,0x1B,80,2880,1,0,2 }, /* 1.44 meg HD 3.5in floppy */
+ { 15,2,0xFF,0x1B,80,2400,1,0,2 }, /* 1.2 meg HD floppy */
+ { 9,2,0xFF,0x23,40,720,2,1,2 }, /* 360k floppy in 1.2meg drive */
+ { 9,2,0xFF,0x2A,40,720,1,1,2 }, /* 360k floppy in DD drive */
+};
+
+#define DRVS_PER_CTLR 2
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+}fdc_data[(NFD+1)/DRVS_PER_CTLR];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (presently 2) (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc;
+ int fdu; /* this unit number */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else DEBUG
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif DEBUG
+
+extern int hz;
+/* state needed for current transfer */
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+int fdprobe(), fdattach(), fd_turnoff();
+
+struct isa_driver fddriver = {
+ fdprobe, fdattach, "fd",
+};
+
+/*
+ * probe for existance of controller
+ */
+fdprobe(dev)
+struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+fdattach(dev)
+struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+
+ fdt = rtcin(RTC_FDISKETTE);
+ hdr = 0;
+
+ /* check for each floppy drive */
+ for (fdu = (fdcu * DRVS_PER_CTLR),fdsu = 0;
+ ((fdu < NFD) && (fdsu < DRVS_PER_CTLR));
+ fdu++,fdsu++)
+ {
+ /* is there a unit? */
+ if ((fdt & 0xf0) == RTCFDT_NONE)
+ continue;
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd_data[fdu].track = -2;
+ fd_data[fdu].fdc = fdc;
+ fd_data[fdu].fdsu = fdsu;
+ /* yes, announce it */
+ if (!hdr)
+ printf(" drives ");
+ else
+ printf(", ");
+ printf("%d: ", fdu);
+
+
+ if ((fdt & 0xf0) == RTCFDT_12M) {
+ printf("1.2M");
+ fd_data[fdu].type = 1;
+ fd_data[fdu].ft = fd_types + 1;
+
+ }
+ if ((fdt & 0xf0) == RTCFDT_144M) {
+ printf("1.44M");
+ fd_data[fdu].type = 0;
+ fd_data[fdu].ft = fd_types + 0;
+ }
+
+ fdt <<= 4;
+ fd_turnoff(fdu);
+ hdr = 1;
+ }
+
+ printf(" %s ",rev);
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+}
+
+int
+fdsize(dev)
+dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+fdstrategy(bp)
+ register struct buf *bp; /* IO operation to perform */
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+ /*type = FDTYPE(minor(bp->b_dev));*/
+
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff,fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+set_motor(fdcu_t fdcu, fdu_t fdu, int reset)
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+fd_turnoff(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+fd_motor_on(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fd_pseudointr(fd->fdc->fdcu);
+ }
+}
+
+fd_turnon(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on,fdu,hz); /* in 1 sec its ok */
+ }
+}
+
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu_t fdcu)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+out_fdc(fdcu_t fdcu,int x)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i = 100000;
+
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1);
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+static fdopenf;
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ /*int type = FDTYPE(minor(dev));*/
+ int s;
+
+ /* check bounds */
+ if (fdu >= NFD) return(ENXIO);
+ /*if (type >= NUMTYPES) return(ENXIO);*/
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+fdclose(dev, flags)
+ dev_t dev;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+fdstart(fdcu_t fdcu)
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+fd_timeout(fdcu_t fdcu)
+{
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+
+ dp = &fdc_data[fdcu].head;
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fd_pseudointr(fdcu);
+}
+
+/* just ensure it has the right spl */
+fd_pseudointr(fdcu_t fdcu)
+{
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ while(fdstate(fdcu, fdc));
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int fdstate(fdcu_t fdcu, fdc_p fdc)
+{
+ int read,head,trac,sec,i,s,sectrac,cyl,st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, fdu);
+ timeout(fd_turnoff,fdu,4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ return(0); /* will return later */
+ case SEEKWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", fdu,
+ descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout,fdcu,2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout,fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr,fdcu,hz/30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+retrier(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ printf("fd%d: hard error (ST0 %b ",
+ fdc->fdu, fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf(" ST3 %b ", fdc->status[3], NE7_ST3BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[4], fdc->status[5], fdc->status[6]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+#endif
+
diff --git a/sys/isa/fdreg.h b/sys/isa/fdreg.h
new file mode 100644
index 0000000..948f566
--- /dev/null
+++ b/sys/isa/fdreg.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00153
+ * -------------------- ----- ----------------------
+ *
+ * 20 Apr 93 Julian Elischer Heavily re worked, see notes below
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
+
diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h
new file mode 100644
index 0000000..b84b46e
--- /dev/null
+++ b/sys/isa/ic/nec765.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/isa/ic/ns16550.h b/sys/isa/ic/ns16550.h
new file mode 100644
index 0000000..e20e9aa
--- /dev/null
+++ b/sys/isa/ic/ns16550.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h
new file mode 100644
index 0000000..2de060d
--- /dev/null
+++ b/sys/isa/rtc.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rtc.h 7.1 (Berkeley) 5/12/91
+ */
+
+/*
+ * RTC Register locations
+ */
+
+#define RTC_SEC 0x00 /* seconds */
+#define RTC_SECALRM 0x01 /* seconds alarm */
+#define RTC_MIN 0x02 /* minutes */
+#define RTC_MINALRM 0x03 /* minutes alarm */
+#define RTC_HRS 0x04 /* hours */
+#define RTC_HRSALRM 0x05 /* hours alarm */
+#define RTC_WDAY 0x06 /* week day */
+#define RTC_DAY 0x07 /* day of month */
+#define RTC_MONTH 0x08 /* month of year */
+#define RTC_YEAR 0x09 /* month of year */
+#define RTC_STATUSA 0x0a /* status register A */
+#define RTCSA_TUP 0x80 /* time update, don't look now */
+
+#define RTC_STATUSB 0x0b /* status register B */
+
+#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_UPDATE 0x10 /* update intr */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_PERIOD 0x40 /* periodic intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
+#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
+#define RTCSD_PWR 0x80 /* clock lost power */
+
+#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
+#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
+
+#define RTC_RESET 0x0f /* status register F - reset code byte */
+#define RTCRS_RST 0x00 /* normal reset */
+#define RTCRS_LOAD 0x04 /* load system */
+
+#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */
+#define RTCFDT_NONE 0 /* none present */
+#define RTCFDT_360K 0x10 /* 360K */
+#define RTCFDT_12M 0x20 /* 1.2M */
+#define RTCFDT_144M 0x40 /* 1.44M */
+
+#define RTC_BASELO 0x15 /* low byte of basemem size */
+#define RTC_BASEHI 0x16 /* high byte of basemem size */
+#define RTC_EXTLO 0x17 /* low byte of extended mem size */
+#define RTC_EXTHI 0x18 /* low byte of extended mem size */
+
+#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
new file mode 100644
index 0000000..38503fd
--- /dev/null
+++ b/sys/isa/sio.c
@@ -0,0 +1,1721 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sio.c 7.5 (Berkeley) 5/16/91
+ *
+ * 27 May 93 Bruce Evans From com-0.2 package, fast interrupt
+ * com port driver.
+ * 27 May 93 Guido van Rooij Ported in Chris Demetriou's BIDIR
+ * code, add multiport support.
+ * 27 May 93 Rodney W. Grimes I then renamed it to sio.c for putting
+ * into the patch kit. Added in sioselect
+ * from com.c. Added port 4 support.
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/isa/RCS/com.c,v 1.2 92/01/21 14:34:11 william Exp $";
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * COM driver, based on HP dca driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#undef CRTS_IFLOW
+#define CRTS_IFLOW CRTSCTS /* XXX, CCTS_OFLOW = CRTSCTS already */
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TS_RTSBLOCK TS_TBLOCK /* XXX */
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+#ifndef COM_BIDIR
+#define UNIT(x) (minor(x)) /* XXX */
+#else /* COM_BIDIR */
+#define COM_UNITMASK 0x7f
+#define COM_CALLOUTMASK 0x80
+
+#define UNIT(x) (minor(x) & COM_UNITMASK)
+#define CALLOUT(x) (minor(x) & COM_CALLOUTMASK)
+#endif /* COM_BIDIR */
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#endif /* COM_MULTIPORT */
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+#define schedsoftcom() (ipending |= 1 << 4) /* XXX */
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef int Bool_t; /* promoted boolean */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+ bool_t softDCD; /* nonzero for faked carrier detect */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+
+/*
+ * These functions in the com module ought to be declared (with a prototype)
+ * in a com-driver system header. The void ones may need to be int to match
+ * ancient devswitch declarations, but they don't actually return anything.
+ */
+#define Dev_t int /* promoted dev_t */
+struct consdev;
+
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+void siointr __P((int unit));
+#ifdef COM_MULTIPORT
+bool_t comintr1 __P((struct com_s *com));
+#endif /* COM_MULTIPORT */
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+int siocngetc __P((Dev_t dev));
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+/*
+ * sioopen gets compared to the d_open entry in struct cdevsw. d_open and
+ * other functions are declared in <sys/conf.h> with short types like dev_t
+ * in the prototype. Such declarations are broken because they vary with
+ * __P (significantly in theory - the compiler is allowed to push a short
+ * arg if it has seen the prototype; insignificantly in practice - gcc
+ * doesn't push short args and it would be slower on 386's to do so).
+ *
+ * Also, most of the device switch functions are still declared old-style
+ * so they take a Dev_t arg and shorten it to a dev_t. It would be simpler
+ * and faster if dev_t's were always promoted (to ints or whatever) as
+ * early as possible.
+ *
+ * Until <sys/conf.h> is fixed, we cast sioopen to the following `wrong' type
+ * when comparing it to the d_open entry just to avoid compiler warnings.
+ */
+typedef int (*bogus_open_t) __P((dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+void siostop __P((struct tty *tp, int rw));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+void softsio0 __P((void));
+void softsio1 __P((void));
+void softsio2 __P((void));
+void softsio3 __P((void));
+void softsio4 __P((void));
+void softsio5 __P((void));
+void softsio6 __P((void));
+void softsio7 __P((void));
+void softsio8 __P((void));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void cominit __P((int unit, int rate));
+static int commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void compoll __P((void));
+static int comstart __P((struct tty *tp));
+static void comwakeup __P((void));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static bool_t comconsinit;
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+struct tty sio_tty[NSIO];
+extern struct tty *constty;
+extern u_int ipending; /* XXX */
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = 1;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+ || !isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ enable_intr();
+
+ return (result);
+}
+
+static int /* XXX - should be void */
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ if (unit == comconsole)
+ DELAY(1000); /* XXX */
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit];
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+#if 0
+ com->softDCD = TRUE;
+#endif
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+ com->tp = &sio_tty[unit];
+#ifdef COM_BIDIR
+ /*
+ * if bidirectional ports possible, clear the bidir port info;
+ */
+ com->bidir = FALSE;
+ com->active = FALSE;
+ com->active_in = com->active_out = FALSE;
+#endif /* COM_BIDIR */
+
+ /* attempt to determine UART type */
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a)
+ printf(" <8250>");
+ else {
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(iobase + com_iir) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" <16450>");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" <16450?>");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" <16550?>");
+ break;
+ case FIFO_TRIGGER_14:
+ com->hasfifo = TRUE;
+ printf(" <16550A>");
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+ }
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ struct isa_device *masterdev;
+
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(iobase + com_mcr, 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase+com_scr, 0x80);
+ }
+ else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ cominit(unit, kgdb_rate);
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("com%d: ", unit);
+ kgdb_connect(1);
+ }
+ else
+ printf("com%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ /*
+ * Need to reset baud rate, etc. of next print so reset comconsinit.
+ * Also make sure console is always "hardwired"
+ */
+ if (unit == comconsole) {
+ comconsinit = FALSE;
+ com->softDCD = TRUE;
+ }
+
+ com_addr(unit) = com;
+
+ splx(s);
+
+ if (!comwakeup_started) {
+ comwakeup();
+ comwakeup_started = TRUE;
+ }
+
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error = 0;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit = UNIT(dev);
+#ifdef COM_BIDIR
+ bool_t callout = CALLOUT(dev);
+#endif /* COM_BIDIR */
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+ tp = com->tp;
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ com->softDCD = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep(&com->active_out,
+ TTIPRI|PCATCH,
+ "comoth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ } else if (com->last_modem_status & MSR_DCD) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ com->softDCD = FALSE;
+ } else {
+ /* put DTR & RTS up */
+ /* NOTE: cgd'sdriver used the ier register
+ * to enable/disable interrupts. This one
+ * uses both ier and IENABLE in the mcr.
+ */
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+ /* wait for it... */
+ error = tsleep(&com->active_in,
+ TTIPRI|PCATCH,
+ "comdcd",
+ 0);
+
+ /* if not active, turn DTR & RTS off */
+ if (!com->active)
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We no longer use the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off. It's useful to have clocal on
+ * initially so that "stty changed-defaults </dev/comx"
+ * doesn't hang waiting for carrier.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8 | CLOCAL;
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ }
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ disable_intr();
+ if (com->hasfifo)
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ com->last_modem_status =
+ com->prev_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->softDCD || com->prev_modem_status & MSR_DCD)
+ tp->t_state |= TS_CARR_ON;
+ }
+ else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ splx(s);
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remainded hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+{
+ comhardclose(com);
+}
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ comhardclose(com);
+ ttyclose(tp);
+ return (0);
+}
+
+void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ s = spltty();
+ iobase = com->iobase;
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts if debugging */
+ if (kgdb_dev != makedev(commajor, com - &com_structs[0]))
+#endif
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+ || !(tp->t_state & TS_ISOPEN))
+ (void) commctl(com, 0, DMSET);
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+ com->softDCD = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+void
+siointr(unit)
+ int unit;
+{
+ struct com_s *com;
+#ifndef COM_MULTIPORT
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+ com = com_addr(unit);
+#else /* COM_MULTIPORT */
+ int i;
+ bool_t donesomething;
+
+ do {
+ donesomething = FALSE;
+ for(i=0;i<NSIO;i++) {
+ com=com_addr(i);
+ if(com != NULL) {
+ /* XXX When siointr is called
+ * to start output, maybe
+ * it should be changed to a
+ * call to comintr1. Doesn't
+ * seem a good idea: interrupts
+ * are disabled all the time.
+ */
+enable_intr();
+disable_intr();
+ donesomething = comintr1(com);
+ }
+ }
+ } while (donesomething);
+ return;
+}
+
+bool_t
+comintr1(struct com_s *com)
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+ bool_t donesomething;
+
+ donesomething = FALSE;
+#endif /* COM_MULTIPORT */
+
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ schedsoftcom();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+#ifdef COM_MULTIPORT
+ donesomething = TRUE;
+#endif /* COM_MULTIPORT */
+ ioptr = com->optr;
+ outb(com->data_port, *ioptr);
+ ++com->bytes_out;
+ com->optr = ++ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ schedsoftcom(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#ifdef COM_MULTIPORT
+ return (donesomething);
+#else
+ return;
+#endif /* COM_MULTIPORT */
+ }
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIS);
+ break;
+ case TIOCCDTR:
+ (void) commctl(com, MCR_DTR | MCR_RTS, DMBIC);
+ break;
+ case TIOCMSET:
+ (void) commctl(com, *(int *)data, DMSET);
+ break;
+ case TIOCMBIS:
+ (void) commctl(com, *(int *)data, DMBIS);
+ break;
+ case TIOCMBIC:
+ (void) commctl(com, *(int *)data, DMBIC);
+ break;
+ case TIOCMGET:
+ *(int *)data = commctl(com, 0, DMGET);
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ if (p->p_ucred->cr_uid != 0)
+ return(EPERM);
+
+ /* if it's the console, can't do it */
+ if (UNIT(dev) == comconsole)
+ return(ENOTTY);
+
+ /* can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+
+ /* if the port is active, don't do it */
+ /* if (com->active)
+ return(EBUSY); */
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = &com->tp->t_out;
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+static void
+compoll()
+{
+ static bool_t awake = FALSE;
+ struct com_s *com;
+ int s;
+ int unit;
+
+ if (com_events == 0)
+ return;
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf))
+ incc = 0;
+ else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ if (!(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTSBLOCK))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD &&
+ unit != comconsole) {
+#ifdef COM_BIDIR
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+ com->softDCD = FALSE;
+ wakeup((caddr_t) &com->active_in);
+ }
+#else
+ if (com->prev_modem_status & MSR_DCD)
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#endif /* COM_BIDIR */
+ else if ((*linesw[tp->t_line].l_modem)(tp, 0)
+ == 0) {
+ disable_intr();
+ outb(com->modem_ctl_port,
+ com->mcr_image
+ &= ~(MCR_DTR | MCR_RTS));
+ enable_intr();
+ }
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ u_int delta_error_counts[CE_NTYPES];
+ int errnum;
+ u_long total;
+
+ disable_intr();
+ bcopy(com->delta_error_counts, delta_error_counts,
+ sizeof delta_error_counts);
+ bzero(com->delta_error_counts,
+ sizeof delta_error_counts);
+ enable_intr();
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ delta = delta_error_counts[errnum];
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "com%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(&tp->t_raw) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTSBLOCK)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTSBLOCK;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(&tp->t_raw, (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ }
+ else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+ splx(s);
+ awake = FALSE;
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (divisor < 0 || t->c_ispeed != 0 && t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0) {
+ (void) commctl(com, 0, DMSET); /* hang up line */
+ splx(s);
+ return (0);
+ }
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
+ "comparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ * Note that DCD flow control stupidly uses the same state flag
+ * (TS_TTSTOP) as XON/XOFF flow control.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->prev_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ enable_intr();
+ siointr(unit); /* recover from fiddling with CS_TTGO */
+ splx(s);
+ return (0);
+}
+
+static int /* XXX - should be void */
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTSBLOCK) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ }
+ else {
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)&tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ else if (RB_LEN(&tp->t_out) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(&tp->t_out);
+ disable_intr();
+ com->obufend = (com->optr = (u_char *) tp->t_out.rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr(unit); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+ return (1);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+static int
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits);
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | MCR_IENABLE);
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+#ifdef COM_MULTIPORT
+ /* YYY maybe your card doesn't want IENABLE to be reset? */
+ if(com->multiport)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits));
+ else
+#endif /* COM_MULTIPORT */
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~(bits & ~MCR_IENABLE));
+ break;
+ case DMGET:
+ bits = com->prev_modem_status;
+ break;
+ }
+ enable_intr();
+ return (bits);
+}
+
+static void
+comwakeup()
+{
+ struct com_s *com;
+ int unit;
+
+ timeout((timeout_func_t) comwakeup, (caddr_t) NULL, 1);
+ if (com_events != 0)
+ /* schedule compoll() to run when the cpl allows */
+ schedsoftcom();
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr(unit);
+ enable_intr();
+ }
+ }
+}
+
+void
+softsio0() { compoll(); }
+
+void
+softsio1() { compoll(); }
+
+void
+softsio2() { compoll(); }
+
+void
+softsio3() { compoll(); }
+
+void
+softsio4() { compoll(); }
+
+void
+softsio5() { compoll(); }
+
+void
+softsio6() { compoll(); }
+
+void
+softsio7() { compoll(); }
+
+void
+softsio8() { compoll(); }
+
+/*
+ * Following are all routines needed for COM to act as console
+ * XXX - not tested in this version
+ * XXX - check that the corresponding serial interrupts are never enabled
+ */
+#include "i386/i386/cons.h"
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == (bogus_open_t) sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = CONUNIT;
+ com_addr(unit) = &com_structs[unit];
+ com_addr(unit)->iobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+ cp->cn_tp = &sio_tty[unit];
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ unit = UNIT(cp->cn_dev);
+ cominit(unit, comdefaultrate);
+ comconsole = unit;
+ comconsinit = TRUE;
+}
+
+static void
+cominit(unit, rate)
+ int unit;
+ int rate;
+{
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(unit)->iobase;
+ s = splhigh();
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ rate = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_data, rate & 0xFF);
+ outb(iobase + com_ier, rate >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+
+ /*
+ * XXX - fishy to enable interrupts and then poll.
+ * It shouldn't be necessary to ready the iir.
+ */
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
+ outb(iobase + com_fifo,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14);
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ (void) inb(iobase + com_iir);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ Port_t iobase;
+ int s;
+ int timo;
+
+ iobase = com_addr(UNIT(dev))->iobase;
+ s = splhigh();
+#ifdef KGDB
+ if (dev != kgdb_dev)
+#endif
+ if (!comconsinit) {
+ (void) cominit(UNIT(dev), comdefaultrate);
+ comconsinit = TRUE;
+ }
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ outb(iobase + com_data, c);
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!(inb(iobase + com_lsr) & LSR_TXRDY) && --timo)
+ ;
+ /* clear any interrupts generated by this transmission */
+ (void) inb(iobase + com_iir);
+ splx(s);
+}
+
+/*
+ * 10 Feb 93 Jordan K. Hubbard Added select code
+ * 27 May 93 Rodney W. Grimes Stole the select code from com.c.pl5
+ */
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct tty *tp = &sio_tty[UNIT(dev)];
+ int nread;
+ int s = spltty();
+ struct proc *selp;
+
+ switch (rw) {
+
+ case FREAD:
+ nread = ttnread(tp);
+ if (nread > 0 ||
+ ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+ goto win;
+ if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_RCOLL;
+ else
+ tp->t_rsel = p->p_pid;
+ break;
+
+ case FWRITE:
+ if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+ goto win;
+ if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
+ tp->t_state |= TS_WCOLL;
+ else
+ tp->t_wsel = p->p_pid;
+ break;
+ }
+ splx(s);
+ return (0);
+ win:
+ splx(s);
+ return (1);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/isa/sioreg.h b/sys/isa/sioreg.h
new file mode 100644
index 0000000..2a62683
--- /dev/null
+++ b/sys/isa/sioreg.h
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/isa/timerreg.h b/sys/isa/timerreg.h
new file mode 100644
index 0000000..72c7022
--- /dev/null
+++ b/sys/isa/timerreg.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp $
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/kern/subr_rlist.c b/sys/kern/subr_rlist.c
new file mode 100644
index 0000000..3adf5a8
--- /dev/null
+++ b/sys/kern/subr_rlist.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1992 William F. Jolitz, TeleMuse
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software is a component of "386BSD" developed by
+ William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/subr_rlist.c,v 1.2 92/01/21 21:29:31 william Exp $";
+
+#include "sys/param.h"
+#include "sys/cdefs.h"
+#include "sys/malloc.h"
+#include "rlist.h"
+
+/*
+ * Resource lists.
+ */
+
+/*
+ * Add space to a resource list. Used to either
+ * initialize a list or return free space to it.
+ */
+rlist_free (rlp, start, end)
+register struct rlist **rlp; unsigned start, end; {
+ struct rlist *head;
+
+ head = *rlp;
+
+loop:
+ /* if nothing here, insert (tail of list) */
+ if (*rlp == 0) {
+ *rlp = (struct rlist *)malloc(sizeof(**rlp), M_TEMP, M_NOWAIT);
+ (*rlp)->rl_start = start;
+ (*rlp)->rl_end = end;
+ (*rlp)->rl_next = 0;
+ return;
+ }
+
+ /* if new region overlaps something currently present, panic */
+ if (start >= (*rlp)->rl_start && start <= (*rlp)->rl_end) {
+ printf("Frag %d:%d, ent %d:%d ", start, end,
+ (*rlp)->rl_start, (*rlp)->rl_end);
+ panic("overlapping front rlist_free: freed twice?");
+ }
+ if (end >= (*rlp)->rl_start && end <= (*rlp)->rl_end) {
+ printf("Frag %d:%d, ent %d:%d ", start, end,
+ (*rlp)->rl_start, (*rlp)->rl_end);
+ panic("overlapping tail rlist_free: freed twice?");
+ }
+
+ /* are we adjacent to this element? (in front) */
+ if (end+1 == (*rlp)->rl_start) {
+ /* coalesce */
+ (*rlp)->rl_start = start;
+ goto scan;
+ }
+
+ /* are we before this element? */
+ if (end < (*rlp)->rl_start) {
+ register struct rlist *nlp;
+
+ nlp = (struct rlist *)malloc(sizeof(*nlp), M_TEMP, M_NOWAIT);
+ nlp->rl_start = start;
+ nlp->rl_end = end;
+ nlp->rl_next = *rlp;
+ *rlp = nlp;
+ return;
+ }
+
+ /* are we adjacent to this element? (at tail) */
+ if ((*rlp)->rl_end + 1 == start) {
+ /* coalesce */
+ (*rlp)->rl_end = end;
+ goto scan;
+ }
+
+ /* are we after this element */
+ if (start > (*rlp)->rl_end) {
+ rlp = &((*rlp)->rl_next);
+ goto loop;
+ } else
+ panic("rlist_free: can't happen");
+
+scan:
+ /* can we coalesce list now that we've filled a void? */
+ {
+ register struct rlist *lp, *lpn;
+
+ for (lp = head; lp->rl_next ;) {
+ lpn = lp->rl_next;
+
+ /* coalesce ? */
+ if (lp->rl_end + 1 == lpn->rl_start) {
+ lp->rl_end = lpn->rl_end;
+ lp->rl_next = lpn->rl_next;
+ free(lpn, M_TEMP);
+ } else
+ lp = lp->rl_next;
+ }
+ }
+}
+
+/*
+ * Obtain a region of desired size from a resource list.
+ * If nothing available of that size, return 0. Otherwise,
+ * return a value of 1 and set resource start location with
+ * "*loc". (Note: loc can be zero if we don't wish the value)
+ */
+int rlist_alloc (rlp, size, loc)
+struct rlist **rlp; unsigned size, *loc; {
+ register struct rlist *lp;
+
+
+ /* walk list, allocating first thing that's big enough (first fit) */
+ for (; *rlp; rlp = &((*rlp)->rl_next))
+ if(size <= (*rlp)->rl_end - (*rlp)->rl_start + 1) {
+
+ /* hand it to the caller */
+ if (loc) *loc = (*rlp)->rl_start;
+ (*rlp)->rl_start += size;
+
+ /* did we eat this element entirely? */
+ if ((*rlp)->rl_start > (*rlp)->rl_end) {
+ lp = (*rlp)->rl_next;
+ free (*rlp, M_TEMP);
+ *rlp = lp;
+ }
+
+ return (1);
+ }
+
+ /* nothing in list that's big enough */
+ return (0);
+}
+
+/*
+ * Finished with this resource list, reclaim all space and
+ * mark it as being empty.
+ */
+rlist_destroy (rlp)
+struct rlist **rlp; {
+ struct rlist *lp, *nlp;
+
+ lp = *rlp;
+ *rlp = 0;
+ for (; lp; lp = nlp) {
+ nlp = lp->rl_next;
+ free (lp, M_TEMP);
+ }
+}
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
new file mode 100644
index 0000000..57195f3
--- /dev/null
+++ b/sys/kern/subr_trap.c
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.c 7.4 (Berkeley) 5/13/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00137
+ * -------------------- ----- ----------------------
+ *
+ * 08 Apr 93 Bruce Evans Several VM system fixes
+ * Paul Kranenburg Add counter for vmstat
+ */
+static char rcsid[] = "$Header: /usr/bill/working/sys/i386/i386/RCS/trap.c,v 1.2 92/01/21 14:22:13 william Exp $";
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+
+struct sysent sysent[];
+int nsysent;
+int dostacklimits;
+unsigned rcr2();
+extern short cpl;
+
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#include "ddb.h"
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+/*pg("trap type %d code = %x eip = %x cs = %x eva = %x esp %x",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, rcr2(), frame.tf_esp);*/
+if(curpcb == 0 || curproc == 0) goto we_re_toast;
+ if (curpcb->pcb_onfault && frame.tf_trapno != 0xc) {
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ curpcb->pcb_flags |= FM_TRAP; /* used by sendsig */
+ }
+
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+ switch (type) {
+
+ default:
+ we_re_toast:
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+
+ printf("trap type %d code = %x eip = %x cs = %x eflags = %x ",
+ frame.tf_trapno, frame.tf_err, frame.tf_eip,
+ frame.tf_cs, frame.tf_eflags);
+ eva = rcr2();
+ printf("cr2 %x cpl %x\n", eva, cpl);
+ /* type &= ~T_USER; */ /* XXX what the hell is this */
+ panic("trap");
+ /*NOTREACHED*/
+
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#ifdef NPX
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif
+ i = math_emulate(&frame);
+ if (i == 0) return;
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+#if 0
+ /* XXX - check only applies to 386's and 486's with WP off */
+ if (code & PGEX_P) goto we_re_toast;
+#endif
+
+ /* fall into */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ register vm_offset_t va;
+ register struct vmspace *vm = p->p_vmspace;
+ register vm_map_t map;
+ int rv;
+ vm_prot_t ftype;
+ extern vm_map_t kernel_map;
+ unsigned nss,v;
+
+ va = trunc_page((vm_offset_t)eva);
+ /*
+ * Avoid even looking at pde_v(va) for high va's. va's
+ * above VM_MAX_KERNEL_ADDRESS don't correspond to normal
+ * PDE's (half of them correspond to APDEpde and half to
+ * an unmapped kernel PDE). va's betweeen 0xFEC00000 and
+ * VM_MAX_KERNEL_ADDRESS correspond to unmapped kernel PDE's
+ * (XXX - why are only 3 initialized when 6 are required to
+ * reach VM_MAX_KERNEL_ADDRESS?). Faulting in an unmapped
+ * kernel page table would give inconsistent PTD's.
+ *
+ * XXX - faulting in unmapped page tables wastes a page if
+ * va turns out to be invalid.
+ *
+ * XXX - should "kernel address space" cover the kernel page
+ * tables? Might have same problem with PDEpde as with
+ * APDEpde (or there may be no problem with APDEpde).
+ */
+ if (va > 0xFEBFF000) {
+ rv = KERN_FAILURE; /* becomes SIGBUS */
+ goto nogo;
+ }
+ /*
+ * It is only a kernel address space fault iff:
+ * 1. (type & T_USER) == 0 and
+ * 2. pcb_onfault not set or
+ * 3. pcb_onfault set but supervisor space fault
+ * The last can occur during an exec() copyin where the
+ * argument space is lazy-allocated.
+ */
+ if (type == T_PAGEFLT && va >= KERNBASE)
+ map = kernel_map;
+ else
+ map = &vm->vm_map;
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+#ifdef DEBUG
+ if (map == kernel_map && va == 0) {
+ printf("trap: bad kernel access at %x\n", va);
+ goto we_re_toast;
+ }
+#endif
+
+ /*
+ * XXX: rude hack to make stack limits "work"
+ */
+ nss = 0;
+ if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map
+ && dostacklimits) {
+ nss = clrnd(btoc((unsigned)vm->vm_maxsaddr
+ + MAXSSIZ - (unsigned)va));
+ if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
+/*pg("trap rlimit %d, maxsaddr %x va %x ", nss, vm->vm_maxsaddr, va);*/
+ rv = KERN_FAILURE;
+ goto nogo;
+ }
+ }
+
+ /* check if page table is mapped, if not, fault it first */
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+ if (!pde_v(va)) {
+ v = trunc_page(vtopte(va));
+ rv = vm_fault(map, v, ftype, FALSE);
+ if (rv != KERN_SUCCESS) goto nogo;
+ /* check if page table fault, increment wiring */
+ vm_map_pageable(map, v, round_page(v+1), FALSE);
+ } else v=0;
+ rv = vm_fault(map, va, ftype, FALSE);
+ if (rv == KERN_SUCCESS) {
+ /*
+ * XXX: continuation of rude stack hack
+ */
+ if (nss > vm->vm_ssize)
+ vm->vm_ssize = nss;
+ va = trunc_page(vtopte(va));
+ /* for page table, increment wiring
+ as long as not a page table fault as well */
+ if (!v && type != T_PAGEFLT)
+ vm_map_pageable(map, va, round_page(va+1), FALSE);
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+ printf("vm_fault(%x, %x, %x, 0) -> %x\n",
+ map, va, ftype, rv);
+ printf(" type %x, code %x\n",
+ type, code);
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#include "isa.h"
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if(isa_nmi(code) == 0) return;
+ else goto we_re_toast;
+#endif
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR)
+ */
+int trapwrite(unsigned addr) {
+ int rv;
+ vm_offset_t va;
+
+ va = trunc_page((vm_offset_t)addr);
+ if (va > VM_MAXUSER_ADDRESS) return(1);
+ rv = vm_fault(&curproc->p_vmspace->vm_map, va,
+ VM_PROT_READ | VM_PROT_WRITE, FALSE);
+ if (rv == KERN_SUCCESS) return(0);
+ else return(1);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+syscall(frame)
+ volatile struct syscframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.sf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.sf_eax;
+ curpcb->pcb_flags &= ~FM_TRAP; /* used by sendsig */
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.sf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.sf_eip - 7;
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ if (callp == sysent) {
+ i = fuword(params);
+ params += sizeof (int);
+ callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
+ }
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, &args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.sf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.sf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.sf_eax = error;
+ frame.sf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.sf_eax = rval[0];
+ frame.sf_edx = rval[1];
+ frame.sf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ (void) splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ (void) splnone();
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.sf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.sf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.sf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.sf_ss, code);
+ if ((frame.sf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.sf_cs, code);
+ if (frame.sf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.sf_eip, code);
+ frame.sf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c
new file mode 100644
index 0000000..6189d72
--- /dev/null
+++ b/sys/kern/tty_cons.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cons.c 7.2 (Berkeley) 5/9/91
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00083
+ * -------------------- ----- ----------------------
+ *
+ * 16 Aug 92 Pace Willisson /dev/console redirect (xterm -C, etc.)
+ * 14 Mar 93 Chris G. Demetriou Moved pg() here from isa/pccons.c
+ */
+
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/systm.h"
+#include "sys/buf.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+#include "sys/file.h"
+#include "sys/conf.h"
+
+#include "cons.h"
+
+/* XXX - all this could be autoconfig()ed */
+int pccnprobe(), pccninit(), pccngetc(), pccnputc();
+#include "com.h"
+#if NCOM > 0
+int comcnprobe(), comcninit(), comcngetc(), comcnputc();
+#endif
+
+struct consdev constab[] = {
+ { pccnprobe, pccninit, pccngetc, pccnputc },
+#if NCOM > 0
+ { comcnprobe, comcninit, comcngetc, comcnputc },
+#endif
+ { 0 },
+};
+/* end XXX */
+
+struct tty *constty = 0; /* virtual console output device */
+struct consdev *cn_tab; /* physical console device info */
+struct tty *cn_tty; /* XXX: console tty struct for tprintf */
+
+cninit()
+{
+ register struct consdev *cp;
+
+ /*
+ * Collect information about all possible consoles
+ * and find the one with highest priority
+ */
+ for (cp = constab; cp->cn_probe; cp++) {
+ (*cp->cn_probe)(cp);
+ if (cp->cn_pri > CN_DEAD &&
+ (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
+ cn_tab = cp;
+ }
+ /*
+ * No console, we can handle it
+ */
+ if ((cp = cn_tab) == NULL)
+ return;
+ /*
+ * Turn on console
+ */
+ cn_tty = cp->cn_tp;
+ (*cp->cn_init)(cp);
+}
+
+cnopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
+}
+
+cnclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
+}
+
+cnread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
+}
+
+cnwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+{
+ if (cn_tab == NULL)
+ return (0);
+ if (constty) /* 16 Aug 92*/
+ dev = constty->t_dev;
+ else
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
+}
+
+cnioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ caddr_t data;
+ struct proc *p;
+{
+ int error;
+
+ if (cn_tab == NULL)
+ return (0);
+ /*
+ * Superuser can always use this to wrest control of console
+ * output from the "virtual" console.
+ */
+ if (cmd == TIOCCONS && constty) {
+ error = suser(p->p_ucred, (u_short *) NULL);
+ if (error)
+ return (error);
+ constty = NULL;
+ return (0);
+ }
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
+}
+
+/*ARGSUSED*/
+cnselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (1);
+ return (ttselect(cn_tab->cn_dev, rw, p));
+}
+
+cngetc()
+{
+ if (cn_tab == NULL)
+ return (0);
+ return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
+}
+
+cnputc(c)
+ register int c;
+{
+ if (cn_tab == NULL)
+ return;
+ if (c) {
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+ if (c == '\n')
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ }
+}
+
+pg(p,q,r,s,t,u,v,w,x,y,z) char *p; {
+ printf(p,q,r,s,t,u,v,w,x,y,z);
+ printf("\n>");
+ return(cngetc());
+}
+
+
diff --git a/sys/powerpc/include/_limits.h b/sys/powerpc/include/_limits.h
new file mode 100644
index 0000000..73474608
--- /dev/null
+++ b/sys/powerpc/include/_limits.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define CLK_TCK 60 /* ticks per second */
+#define MB_LEN_MAX 1 /* no multibyte characters */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
diff --git a/sys/powerpc/include/limits.h b/sys/powerpc/include/limits.h
new file mode 100644
index 0000000..73474608
--- /dev/null
+++ b/sys/powerpc/include/limits.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define CLK_TCK 60 /* ticks per second */
+#define MB_LEN_MAX 1 /* no multibyte characters */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
diff --git a/sys/scsi/README b/sys/scsi/README
new file mode 100644
index 0000000..16e0998
--- /dev/null
+++ b/sys/scsi/README
@@ -0,0 +1,182 @@
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+This release consists of the following files
+(relative to the base of the kernel tree)
+
+
+MAKEDEV
+
+scsi
+scsi/README
+scsi/scsiconf.h
+scsi/scsiconf.c
+scsi/scsi_all.h
+
+scsi/scsi_disk.h
+scsi/sd.c
+
+scsi/scsi_tape.h
+scsi/st.c
+
+sys/chio.h
+scsi/scsi_changer.h
+scsi/ch.c
+
+sys/cdio.h
+scsi/scsi_cd.h
+scsi/cd.c
+
+i386/conf/SCSITEST
+i386/isa/aha1542.c
+
+README.AHA1742
+i386/conf/AHBTEST
+i386/isa/aha1742.c
+
+i386/conf/UHATEST
+i386/isa/ultra14f.c
+
+i386/conf/BTTEST
+i386/isa/bt742a.c
+
+
+
+----------------------------------------------------------------
+This scsi system is designed to allow the re-use of top end drivers
+such as disk and tape drivers, with different scsi adapters.
+
+As of writing this document, There are top end drivers working for:
+----------------------------------------------------------------
+generic scsi disk
+generic scsi tape
+cd-rom (plays music under the xcplayer (?) program)
+AEG Character recognition devices *
+Calera Character recognition devices *
+Kodak IL900 scanner *
+Exabyte tape changer device.
+----------------------------------------------------------------
+
+
+There are also working bottom end drivers for:
+----------------------------------------------------------------
+adaptec 1542 (and 1742 in 1542 mode)
+bustec 742a
+adaptec 174x
+Ultrastore 14f
+----------------------------------------------------------------
+
+
+Work is proceeding on the following bottom end drivers:
+----------------------------------------------------------------
+Future Domain (1680)** hosler@tfs.com & me
+Future Domain (8 bit)**** rpr@oce.nl
+WD7000** terry@icarus.weber.edu
+seagate st01/st02**** overby@aspen.cray.com ?
+----------------------------------------------------------------
+* drivers not made public (proprietary.. proof that the concept works though)
+** driver not yet released but working.
+*** just a dream so far.
+**** some amount more than just a dream so far.
+
+
+################## Using the scsi system ##################
+------------minor numbers---------------
+This scsi system does not allocate minor numbers to devices depending
+on their SCSI IDs is any way. A devices minor number is dependant
+on the order in which it was found.
+e.g. the first tape found will become st0 (minor number 0)
+ the second found will become st1 (minor number 16)
+ the third will become st2 (minor 32)
+ etc.
+
+These devices could be on the same scsi bus or different scsi busses.
+That would not change their minor numbers.
+
+It is possible to run two different TYPES of scsi adapters at the
+same time and have st0 on one and st1 on another. (for example)
+
+There is a scheme supported in which scsi devices can be 'wired in' even
+if they are not present or powered on at probe time. (see scsiconf.c)
+
+--------------getting started------------
+It should be possible to use the /dev entries for as0 as if they were
+/dev entries for sd0 and the old as bootblocks should
+continue to work if you are using an adaptec 1542b.
+
+--------------making devices------------
+A changed version of /dev/MAKEDEV is supplied that
+can be used to make devices sd[01234] and st[01234]
+
+e.g.
+cd /dev
+sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0
+
+
+The tape devices are as follows:
+rst0 basic raw device, will rewind on close
+nrst0 will not rewind on close
+erst0 will rewind and EJECTon close
+nerst0 will not rewind and WILL eject (some devices may rewind anyhow)
+
+------------future enhancements--------------
+Some people have indicated that they would like to have the SCSI ID
+encoded into the minor number in some way, and
+this may be supported at some timein the future, using
+minor numbers greater than 128. (or maybe a different major number)
+
+I will also be writing (probably) a generic scsi-error
+handling routine that will be table driven, so that the routine can
+be removed from each individual driver. With enough care,
+two similar devices with different error codes (quite common) could run
+the same driver but use different error tables.
+
+--------------file layout-------------------
+Originally I had all scsi definitions in one file: scsi.h
+I have since moved definitions of commands so that all
+definitions needed for a particular type of device are
+found together in the include file of that name.
+This approximatly follows the layout of their definition
+in the SCSI-2 spec.
+As such they are:
+
+scsi_all.h general commands for all devices --- CHAPTER 7
+scsi-disk.h commands relevant to disk --- CHAPTER 8
+scsi-tape.h commands for scsi tapes --- CHAPTER 9
+scsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13
+scsi-changer.h commands medium changer devices --- CHAPTER 16
+
+---------ioctl definitions-------------
+User accessable structures (e.g. ioctl definitions) have been
+placed in sys/cdio and sys/chio (based after sys/mtio for
+the ioctls for mag tapes (including st).
+
+-----------cd-rom-----------------
+The cd rom driver ha been tested by a number of people and
+grefen@wilbur.zdv.uni-mainz.de has completed the audio play
+functions.
+He tells me he has some Public Domain package that
+allows an control of the cd player from an Xwindow
+but I don't have it.
+
+-------------media changer---------------
+Once again courtesy of grefen@wilbur.zdv.uni-mainz.de.
+I have not tested this but he assures me it's ready for testing.
+If anyone has an exabyte tape changer or similar,
+contact the author for information regarding the control interface
+and program.
+
+-----------booting from an AHA-174x---------
+For some reason I have not yet worked out,
+the BIOS-based bootblocks I have posted will not boot
+from the aha1742 in extended mode. (it can't be serious
+because the MACH version works) This is in fact not a
+problem because the aha1742 driver will force the board into extended
+mode during probe, so it can be left in standard mode during the boot.
+During the next reboot, the bios will place it back in standard mode
+ready for the NEXT boot.
+
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c
new file mode 100644
index 0000000..2a2261e
--- /dev/null
+++ b/sys/scsi/cd.c
@@ -0,0 +1,1722 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ */
+static char rev[] = "$Revision: 1.3 $";
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00149
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * 20 Apr 93 Julian Elishcer Fixed error reporting
+ */
+
+#define SPLCD splbio
+#define ESUCCESS 0
+#include <cd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/cdio.h>
+
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_cd.h>
+#include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */
+#include <scsi/scsiconf.h>
+
+long int cdstrats,cdqueues;
+
+
+#include <ddb.h>
+#if NDDB > 0
+int Debugger();
+#else NDDB > 0
+#define Debugger()
+#endif NDDB > 0
+
+
+#define PAGESIZ 4096
+#define SECSIZE 2048 /* XXX */ /* default only */
+#define CDOUTSTANDING 2
+#define CDQSIZE 4
+#define CD_RETRIES 4
+
+#define UNITSHIFT 3
+#define PARTITION(z) (minor(z) & 0x07)
+#define RAW_PART 3
+#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
+
+
+extern int hz;
+int cd_done();
+int cdstrategy();
+int cd_debug = 0;
+
+struct buf cd_buf_queue[NCD];
+struct scsi_xfer cd_scsi_xfer[NCD][CDOUTSTANDING]; /* XXX */
+struct scsi_xfer *cd_free_xfer[NCD];
+int cd_xfer_block_wait[NCD];
+
+struct cd_data
+{
+ int flags;
+#define CDVALID 0x02 /* PARAMS LOADED */
+#define CDINIT 0x04 /* device has been init'd */
+#define CDWAIT 0x08 /* device has someone waiting */
+#define CDHAVELABEL 0x10 /* have read the label */
+ struct scsi_switch *sc_sw; /* address of scsi low level switch */
+ int ctlr; /* so they know which one we want */
+ int targ; /* our scsi target ID */
+ int lu; /* out scsi lu */
+ int cmdscount; /* cmds allowed outstanding by board*/
+ struct cd_parms
+ {
+ int blksize;
+ u_long disksize; /* total number sectors */
+ }params;
+ struct disklabel disklabel;
+ int partflags[MAXPARTITIONS]; /* per partition flags */
+#define CDOPEN 0x01
+ int openparts; /* one bit for each open partition */
+}cd_data[NCD];
+
+#define CD_STOP 0
+#define CD_START 1
+#define CD_EJECT -2
+
+
+static int next_cd_unit = 0;
+/***********************************************************************\
+* The routine called by the low level scsi routine when it discovers *
+* A device suitable for this driver *
+\***********************************************************************/
+int cdattach(ctlr,targ,lu,scsi_switch)
+struct scsi_switch *scsi_switch;
+{
+ int unit,i;
+ unsigned char *tbl;
+ struct cd_data *cd;
+ struct cd_parms *dp;
+
+ unit = next_cd_unit++;
+ cd = cd_data + unit;
+ dp = &(cd->params);
+ if(scsi_debug & PRINTROUTINES) printf("cdattach: ");
+ /*******************************************************\
+ * Check we have the resources for another drive *
+ \*******************************************************/
+ if( unit >= NCD)
+ {
+ printf("Too many scsi CDs..(%d > %d) reconfigure kernel",(unit + 1),NCD);
+ return(0);
+ }
+ /*******************************************************\
+ * Store information needed to contact our base driver *
+ \*******************************************************/
+ cd->sc_sw = scsi_switch;
+ cd->ctlr = ctlr;
+ cd->targ = targ;
+ cd->lu = lu;
+ cd->cmdscount = CDOUTSTANDING; /* XXX (ask the board) */
+
+
+ i = cd->cmdscount;
+ while(i-- )
+ {
+ cd_scsi_xfer[unit][i].next = cd_free_xfer[unit];
+ cd_free_xfer[unit] = &cd_scsi_xfer[unit][i];
+ }
+ /*******************************************************\
+ * Use the subdriver to request information regarding *
+ * the drive. We cannot use interrupts yet, so the *
+ * request must specify this. *
+ \*******************************************************/
+ cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ if(dp->disksize)
+ {
+ printf("cd present\n");
+ }
+ else
+ {
+ printf("drive empty\n");
+ }
+ cd->flags |= CDINIT;
+ return;
+
+}
+
+
+
+/*******************************************************\
+* open the device. Make sure the partition info *
+* is a up-to-date as can be. *
+\*******************************************************/
+cdopen(dev)
+{
+ int errcode = 0;
+ int unit, part;
+ struct cd_parms cd_parms;
+ struct cd_data *cd ;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ cd = cd_data + unit;
+ if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
+ printf("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
+ , dev, unit, NCD, part);
+ /*******************************************************\
+ * Check the unit is legal *
+ \*******************************************************/
+ if ( unit >= NCD )
+ {
+ return(ENXIO);
+ }
+ /*******************************************************\
+ * Make sure the disk has been initialised *
+ * At some point in the future, get the scsi driver *
+ * to look for a new device if we are not initted *
+ \*******************************************************/
+ if (! (cd->flags & CDINIT))
+ return(ENXIO);
+
+ /*******************************************************\
+ * If it's been invalidated, and not everybody has *
+ * closed it then forbid re-entry. *
+ * (may have changed media) *
+ \*******************************************************/
+ if ((! (cd->flags & CDVALID))
+ && ( cd->openparts))
+ return(ENXIO);
+ /*******************************************************\
+ * Check that it is still responding and ok. *
+ * if the media has been changed this will result in a *
+ * "unit attention" error which the error code will *
+ * disregard because the CDVALID flag is not yet set *
+ \*******************************************************/
+ if (cd_req_sense(unit, SCSI_SILENT) != 0) {
+ if(scsi_debug & TRACEOPENS)
+ printf("not reponding\n");
+ return(ENXIO);
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("Device present\n");
+ /*******************************************************\
+ * In case it is a funny one, tell it to start *
+ * not needed for hard drives *
+ \*******************************************************/
+ cd_start_unit(unit,part,CD_START);
+ cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT);
+ if(scsi_debug & TRACEOPENS)
+ printf("started ");
+ /*******************************************************\
+ * Load the physical device parameters *
+ \*******************************************************/
+ cd_get_parms(unit, 0);
+ if(scsi_debug & TRACEOPENS)
+ printf("Params loaded ");
+ /*******************************************************\
+ * Load the partition info if not already loaded *
+ \*******************************************************/
+ cdgetdisklabel(unit);
+ if(scsi_debug & TRACEOPENS)
+ printf("Disklabel fabricated ");
+ /*******************************************************\
+ * Check the partition is legal *
+ \*******************************************************/
+ if (( part >= cd->disklabel.d_npartitions )
+ && (part != RAW_PART))
+ {
+ if(scsi_debug & TRACEOPENS)
+ printf("partition %d > %d\n",part
+ ,cd->disklabel.d_npartitions);
+ cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
+ return(ENXIO);
+ }
+ /*******************************************************\
+ * Check that the partition exists *
+ \*******************************************************/
+ if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED )
+ || (part == RAW_PART))
+ {
+ cd->partflags[part] |= CDOPEN;
+ cd->openparts |= (1 << part);
+ if(scsi_debug & TRACEOPENS)
+ printf("open complete\n");
+ cd->flags |= CDVALID;
+ }
+ else
+ {
+ if(scsi_debug & TRACEOPENS)
+ printf("part %d type UNUSED\n",part);
+ cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
+ return(ENXIO);
+ }
+ return(0);
+}
+
+/*******************************************************\
+* Get ownership of a scsi_xfer structure *
+* If need be, sleep on it, until it comes free *
+\*******************************************************/
+struct scsi_xfer *cd_get_xs(unit,flags)
+int flags;
+int unit;
+{
+ struct scsi_xfer *xs;
+ int s;
+
+ if(flags & (SCSI_NOSLEEP | SCSI_NOMASK))
+ {
+ if (xs = cd_free_xfer[unit])
+ {
+ cd_free_xfer[unit] = xs->next;
+ xs->flags = 0;
+ }
+ }
+ else
+ {
+ s = SPLCD();
+ while (!(xs = cd_free_xfer[unit]))
+ {
+ cd_xfer_block_wait[unit]++; /* someone waiting! */
+ sleep((caddr_t)&cd_free_xfer[unit], PRIBIO+1);
+ cd_xfer_block_wait[unit]--;
+ }
+ cd_free_xfer[unit] = xs->next;
+ splx(s);
+ xs->flags = 0;
+ }
+ return(xs);
+}
+
+/*******************************************************\
+* Free a scsi_xfer, wake processes waiting for it *
+\*******************************************************/
+cd_free_xs(unit,xs,flags)
+struct scsi_xfer *xs;
+int unit;
+int flags;
+{
+ int s;
+
+ if(flags & SCSI_NOMASK)
+ {
+ if (cd_xfer_block_wait[unit])
+ {
+ printf("doing a wakeup from NOMASK mode\n");
+ wakeup((caddr_t)&cd_free_xfer[unit]);
+ }
+ xs->next = cd_free_xfer[unit];
+ cd_free_xfer[unit] = xs;
+ }
+ else
+ {
+ s = SPLCD();
+ if (cd_xfer_block_wait[unit])
+ wakeup((caddr_t)&cd_free_xfer[unit]);
+ xs->next = cd_free_xfer[unit];
+ cd_free_xfer[unit] = xs;
+ splx(s);
+ }
+}
+
+/*******************************************************\
+* trim the size of the transfer if needed, *
+* called by physio *
+* basically the smaller of our max and the scsi driver's*
+* minphys (note we have no max ourselves) *
+\*******************************************************/
+/* Trim buffer length if buffer-size is bigger than page size */
+void cdminphys(bp)
+struct buf *bp;
+{
+ (*(cd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp);
+}
+
+/*******************************************************\
+* Actually translate the requested transfer into *
+* one the physical driver can understand *
+* The transfer is described by a buf and will include *
+* only one physical transfer. *
+\*******************************************************/
+
+int cdstrategy(bp)
+struct buf *bp;
+{
+ struct buf *dp;
+ unsigned int opri;
+ struct cd_data *cd ;
+ int unit;
+
+ cdstrats++;
+ unit = UNIT((bp->b_dev));
+ cd = cd_data + unit;
+ if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy ");
+ if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n",
+ unit,bp->b_bcount,bp->b_blkno);
+ cdminphys(bp);
+ /*******************************************************\
+ * If the device has been made invalid, error out *
+ * maybe the media changed *
+ \*******************************************************/
+ if(!(cd->flags & CDVALID))
+ {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*******************************************************\
+ * can't ever write to a CD *
+ \*******************************************************/
+ if ((bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+ /*******************************************************\
+ * If it's a null transfer, return immediatly *
+ \*******************************************************/
+ if (bp->b_bcount == 0) {
+ goto done;
+ }
+
+ /*******************************************************\
+ * Decide which unit and partition we are talking about *
+ \*******************************************************/
+ if(PARTITION(bp->b_dev) != RAW_PART)
+ {
+ if (!(cd->flags & CDHAVELABEL))
+ {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*
+ * do bounds checking, adjust transfer. if error, process.
+ * if end of partition, just return
+ */
+ if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0)
+ goto done;
+ /* otherwise, process transfer request */
+ }
+
+ opri = SPLCD();
+ dp = &cd_buf_queue[unit];
+
+ /*******************************************************\
+ * Place it in the queue of disk activities for this disk*
+ \*******************************************************/
+ disksort(dp, bp);
+
+ /*******************************************************\
+ * Tell the device to get going on the transfer if it's *
+ * not doing anything, otherwise just wait for completion*
+ \*******************************************************/
+ cdstart(unit);
+
+ splx(opri);
+ return;
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+
+ /*******************************************************\
+ * Correctly set the buf to indicate a completed xfer *
+ \*******************************************************/
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return;
+}
+
+/***************************************************************\
+* cdstart looks to see if there is a buf waiting for the device *
+* and that the device is not already busy. If both are true, *
+* It deques the buf and creates a scsi command to perform the *
+* transfer in the buf. The transfer request will call cd_done *
+* on completion, which will in turn call this routine again *
+* so that the next queued transfer is performed. *
+* The bufs are queued by the strategy routine (cdstrategy) *
+* *
+* This routine is also called after other non-queued requests *
+* have been made of the scsi driver, to ensure that the queue *
+* continues to be drained. *
+* *
+* must be called at the correct (highish) spl level *
+\***************************************************************/
+/* cdstart() is called at SPLCD from cdstrategy and cd_done*/
+cdstart(unit)
+int unit;
+{
+ register struct buf *bp = 0;
+ register struct buf *dp;
+ struct scsi_xfer *xs;
+ struct scsi_rw_big cmd;
+ int blkno, nblk;
+ struct cd_data *cd = cd_data + unit;
+ struct partition *p ;
+
+ if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit);
+ /*******************************************************\
+ * See if there is a buf to do and we are not already *
+ * doing one *
+ \*******************************************************/
+ if(!cd_free_xfer[unit])
+ {
+ return; /* none for us, unit already underway */
+ }
+
+ if(cd_xfer_block_wait[unit]) /* there is one, but a special waits */
+ {
+ return; /* give the special that's waiting a chance to run */
+ }
+
+
+ dp = &cd_buf_queue[unit];
+ if ((bp = dp->b_actf) != NULL) /* yes, an assign */
+ {
+ dp->b_actf = bp->av_forw;
+ }
+ else
+ {
+ return;
+ }
+
+ xs=cd_get_xs(unit,0); /* ok we can grab it */
+ xs->flags = INUSE; /* Now ours */
+ /***************************************************************\
+ * Should reject all queued entries if CDVALID is not true *
+ \***************************************************************/
+ if(!(cd->flags & CDVALID))
+ {
+ goto bad; /* no I/O.. media changed or something */
+ }
+
+ /*******************************************************\
+ * We have a buf, now we should move the data into *
+ * a scsi_xfer definition and try start it *
+ \*******************************************************/
+ /*******************************************************\
+ * First, translate the block to absolute *
+ * and put it in terms of the logical blocksize of the *
+ * device.. *
+ \*******************************************************/
+ p = cd->disklabel.d_partitions + PARTITION(bp->b_dev);
+ blkno = ((bp->b_blkno / (cd->params.blksize/512)) + p->p_offset);
+ nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize);
+
+ /*******************************************************\
+ * Fill out the scsi command *
+ \*******************************************************/
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = READ_BIG;
+ cmd.addr_3 = (blkno & 0xff000000) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ * Note: we cannot sleep as we may be an interrupt *
+ \*******************************************************/
+ xs->flags |= SCSI_NOSLEEP;
+ xs->adapter = cd->ctlr;
+ xs->targ = cd->targ;
+ xs->lu = cd->lu;
+ xs->retries = CD_RETRIES;
+ xs->timeout = 10000;/* 10000 millisecs for a disk !*/
+ xs->cmd = (struct scsi_generic *)&cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->resid = bp->b_bcount;
+ xs->when_done = cd_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+ xs->error = XS_NOERROR;
+ xs->bp = bp;
+ xs->data = (u_char *)bp->b_un.b_addr;
+ xs->datalen = bp->b_bcount;
+
+ /*******************************************************\
+ * Pass all this info to the scsi driver. *
+ \*******************************************************/
+ if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
+ {
+ printf("cd%d: oops not queued",unit);
+ goto bad;
+ }
+ cdqueues++;
+ return;
+bad: xs->error = XS_DRIVER_STUFFUP;
+ cd_done(unit,xs);
+}
+
+/*******************************************************\
+* This routine is called by the scsi interrupt when *
+* the transfer is complete. (or failed) *
+\*******************************************************/
+int cd_done(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct buf *bp;
+ int retval;
+
+ if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit);
+ if (! (xs->flags & INUSE)) /* paranoia always pays off */
+ panic("scsi_xfer not in use!");
+ if(bp = xs->bp)
+ {
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ break;
+
+ case XS_SENSE:
+ retval = (cd_interpret_sense(unit,xs));
+ if(retval)
+ {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = retval;
+ }
+ break;
+
+ case XS_TIMEOUT:
+ printf("cd%d timeout\n",unit);
+
+ case XS_BUSY:
+ /***********************************\
+ * Just resubmit it straight back to *
+ * the SCSI driver to try it again *
+ \***********************************/
+ if(xs->retries--)
+ {
+ xs->error = XS_NOERROR;
+ xs->flags &= ~ITSDONE;
+ if ( (*(cd_data[unit].sc_sw->scsi_cmd))(xs)
+ == SUCCESSFULLY_QUEUED)
+ { /* shhh! don't wake the job, ok? */
+ /* don't tell cdstart either, */
+ return;
+ }
+ /* xs->error is set by the scsi driver */
+ } /* Fall through */
+
+ case XS_DRIVER_STUFFUP:
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ break;
+ default:
+ printf("cd%d: unknown error category from scsi driver\n"
+ ,unit);
+ }
+ biodone(bp);
+ cd_free_xs(unit,xs,0);
+ cdstart(unit); /* If there's anything waiting.. do it */
+ }
+ else /* special has finished */
+ {
+ wakeup(xs);
+ }
+}
+/*******************************************************\
+* Perform special action on behalf of the user *
+* Knows about the internals of this device *
+\*******************************************************/
+cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ int error = 0;
+ unsigned int opri;
+ unsigned char unit, part;
+ register struct cd_data *cd;
+
+
+ /*******************************************************\
+ * Find the device that the user is talking about *
+ \*******************************************************/
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ cd = &cd_data[unit];
+ if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit);
+
+ /*******************************************************\
+ * If the device is not valid.. abandon ship *
+ \*******************************************************/
+ if (!(cd_data[unit].flags & CDVALID))
+ return(EIO);
+ switch(cmd)
+ {
+
+ case DIOCSBAD:
+ error = EINVAL;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)addr = cd->disklabel;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)addr)->disklab = &cd->disklabel;
+ ((struct partinfo *)addr)->part =
+ &cd->disklabel.d_partitions[PARTITION(dev)];
+ break;
+
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&cd->disklabel,
+ (struct disklabel *)addr,
+ /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0,
+ 0);
+ if (error == 0) {
+ cd->flags |= CDHAVELABEL;
+ }
+ break;
+
+ case DIOCWLABEL:
+ error = EBADF;
+ break;
+
+ case CDIOCPLAYTRACKS:
+ {
+ struct ioc_play_track *args
+ = (struct ioc_play_track *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.sotc = 0;
+ data.page.audio.immed = 1;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ return(cd_play_tracks(unit
+ ,args->start_track
+ ,args->start_index
+ ,args->end_track
+ ,args->end_index
+ ));
+ }
+ break;
+ case CDIOCPLAYBLOCKS:
+ {
+ struct ioc_play_blocks *args
+ = (struct ioc_play_blocks *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.sotc = 0;
+ data.page.audio.immed = 1;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ return(cd_play(unit,args->blk,args->len));
+
+
+ }
+ break;
+ case CDIOCREADSUBCHANNEL:
+ {
+ struct ioc_read_subchannel *args
+ = (struct ioc_read_subchannel *)addr;
+ struct cd_sub_channel_info data;
+ int len=args->data_len;
+ if(len>sizeof(data)||
+ len<sizeof(struct cd_sub_channel_header)) {
+ error=EINVAL;
+ break;
+ }
+ if(error = cd_read_subchannel(unit,args->address_format,
+ args->data_format,args->track,&data,len)) {
+ break;
+ }
+ len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+
+ sizeof(struct cd_sub_channel_header)));
+ if(copyout(&data,args->data,len)!=0) {
+ error=EFAULT;
+ }
+ }
+ break;
+ case CDIOREADTOCHEADER:
+ {
+ struct ioc_toc_header th;
+ if( error = cd_read_toc(unit,0,0,&th,sizeof(th)))
+ break;
+ th.len=(th.len&0xff)<<8+((th.len>>8)&0xff);
+ bcopy(&th,addr,sizeof(th));
+ }
+ break;
+ case CDIOREADTOCENTRYS:
+ {
+ struct ioc_read_toc_entry *te=
+ (struct ioc_read_toc_entry *)addr;
+ struct cd_toc_entry data[65];
+ struct ioc_toc_header *th;
+ int len=te->data_len;
+ th=(struct ioc_toc_header *)data;
+
+ if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) {
+ error=EINVAL;
+ break;
+ }
+ if(error = cd_read_toc(unit,te->address_format,
+ te->starting_track,
+ data,
+ len))
+ break;
+ len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+
+ sizeof(*th)));
+ if(copyout(th,te->data,len)!=0) {
+ error=EFAULT;
+ }
+
+ }
+ break;
+ case CDIOCSETPATCH:
+ {
+ struct ioc_patch *arg = (struct ioc_patch *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
+ data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
+ data.page.audio.port[2].channels = arg->patch[2];
+ data.page.audio.port[3].channels = arg->patch[3];
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCGETVOL:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
+ arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
+ arg->vol[2] = data.page.audio.port[2].volume;
+ arg->vol[3] = data.page.audio.port[3].volume;
+ }
+ break;
+ case CDIOCSETVOL:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
+ data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
+ data.page.audio.port[2].volume = arg->vol[2];
+ data.page.audio.port[3].volume = arg->vol[3];
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCSETMONO:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8;
+ data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCSETSTERIO:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
+ data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCSETMUTE:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = 0;
+ data.page.audio.port[RIGHT_PORT].channels = 0;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCSETLEFT:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = 15;
+ data.page.audio.port[RIGHT_PORT].channels = 15;
+ data.page.audio.port[2].channels = 15;
+ data.page.audio.port[3].channels = 15;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCSETRIGHT:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *)addr;
+ struct cd_mode_data data;
+ if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if(error = cd_set_mode(unit,&data))
+ break;
+ }
+ break;
+ case CDIOCRESUME:
+ error = cd_pause(unit,1);
+ break;
+ case CDIOCPAUSE:
+ error = cd_pause(unit,0);
+ break;
+ case CDIOCSTART:
+ error = cd_start_unit(unit,part,CD_START);
+ break;
+ case CDIOCSTOP:
+ error = cd_start_unit(unit,part,CD_STOP);
+ break;
+ case CDIOCEJECT:
+ error = cd_start_unit(unit,part,CD_EJECT);
+ break;
+ case CDIOCSETDEBUG:
+ scsi_debug = 0xfff; cd_debug = 0xfff;
+ break;
+ case CDIOCCLRDEBUG:
+ scsi_debug = 0; cd_debug = 0;
+ break;
+ case CDIOCRESET:
+ return(cd_reset(unit));
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+
+/*******************************************************\
+* Load the label information on the named device *
+* *
+* EVENTUALLY take information about different *
+* data tracks from the TOC and put it in the disklabel *
+\*******************************************************/
+int cdgetdisklabel(unit)
+unsigned char unit;
+{
+ /*unsigned int n, m;*/
+ char *errstring;
+ struct dos_partition *dos_partition_p;
+ struct cd_data *cd = cd_data + unit;
+
+ /*******************************************************\
+ * If the inflo is already loaded, use it *
+ \*******************************************************/
+ if(cd->flags & CDHAVELABEL) return;
+
+ bzero(&cd->disklabel,sizeof(struct disklabel));
+ /*******************************************************\
+ * make partition 3 the whole disk in case of failure *
+ * then get pdinfo *
+ \*******************************************************/
+ strncpy(cd->disklabel.d_typename,"scsi cd_rom",16);
+ strncpy(cd->disklabel.d_packname,"ficticious",16);
+ cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */
+ cd->disklabel.d_nsectors = 100;
+ cd->disklabel.d_ntracks = 1;
+ cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1;
+ cd->disklabel.d_secpercyl = 100;
+ cd->disklabel.d_secperunit = cd->params.disksize;
+ cd->disklabel.d_rpm = 300;
+ cd->disklabel.d_interleave = 1;
+ cd->disklabel.d_flags = D_REMOVABLE;
+
+ cd->disklabel.d_npartitions = 1;
+ cd->disklabel.d_partitions[0].p_offset = 0;
+ cd->disklabel.d_partitions[0].p_size = cd->params.disksize;
+ cd->disklabel.d_partitions[0].p_fstype = 9;
+
+ cd->disklabel.d_magic = DISKMAGIC;
+ cd->disklabel.d_magic2 = DISKMAGIC;
+ cd->disklabel.d_checksum = dkcksum(&(cd->disklabel));
+
+ /*******************************************************\
+ * Signal to other users and routines that we now have a *
+ * disklabel that represents the media (maybe) *
+ \*******************************************************/
+ cd->flags |= CDHAVELABEL;
+ return(ESUCCESS);
+}
+
+/*******************************************************\
+* Find out form the device what it's capacity is *
+\*******************************************************/
+cd_size(unit, flags)
+{
+ struct scsi_read_cd_cap_data rdcap;
+ struct scsi_read_cd_capacity scsi_cmd;
+ int size;
+ int blksize;
+
+ /*******************************************************\
+ * make up a scsi command and ask the scsi driver to do *
+ * it for you. *
+ \*******************************************************/
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CD_CAPACITY;
+
+ /*******************************************************\
+ * If the command works, interpret the result as a 4 byte*
+ * number of blocks *
+ \*******************************************************/
+ if (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &rdcap,
+ sizeof(rdcap),
+ 2000,
+ flags) != 0)
+ {
+ printf("could not get size of unit %d\n", unit);
+ return(0);
+ } else {
+ size = rdcap.addr_0 + 1 ;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ blksize = rdcap.length_0 ;
+ blksize += rdcap.length_1 << 8;
+ blksize += rdcap.length_2 << 16;
+ blksize += rdcap.length_3 << 24;
+ }
+ if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize);
+ cd_data[unit].params.disksize = size;
+ cd_data[unit].params.blksize = blksize;
+ return(size);
+}
+
+/*******************************************************\
+* Check with the device that it is ok, (via scsi driver)*
+\*******************************************************/
+cd_req_sense(unit, flags)
+{
+ struct scsi_sense_data sense_data;
+ struct scsi_sense scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = REQUEST_SENSE;
+ scsi_cmd.length = sizeof(sense_data);
+
+ if (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &sense_data,
+ sizeof(sense_data),
+ 2000,
+ flags) != 0)
+ {
+ return(ENXIO);
+ }
+ else
+ return(0);
+}
+
+/*******************************************************\
+* Get the requested page into the buffer given *
+\*******************************************************/
+cd_get_mode(unit,data,page)
+int unit;
+struct cd_mode_data *data;
+int page;
+{
+ struct scsi_mode_sense scsi_cmd;
+ int retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(data,sizeof(*data));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.page_code = page;
+ scsi_cmd.length = sizeof(*data) & 0xff;
+ retval = cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ data,
+ sizeof(*data),
+ 20000, /* should be immed */
+ 0);
+ return (retval);
+}
+/*******************************************************\
+* Get the requested page into the buffer given *
+\*******************************************************/
+cd_set_mode(unit,data)
+int unit;
+struct cd_mode_data *data;
+{
+ struct scsi_mode_select scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SELECT;
+ scsi_cmd.pf = 1;
+ scsi_cmd.length = sizeof(*data) & 0xff;
+ data->header.data_length = 0;
+ /*show_mem(data,sizeof(*data));/**/
+ return (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ data,
+ sizeof(*data),
+ 20000, /* should be immed */
+ 0)
+ );
+}
+/*******************************************************\
+* Get scsi driver to send a "start playing" command *
+\*******************************************************/
+cd_play(unit,blk,len)
+int unit,blk,len;
+{
+ struct scsi_play scsi_cmd;
+ int retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY;
+ scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
+ scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
+ scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
+ scsi_cmd.blk_addr[3] = blk & 0xff;
+ scsi_cmd.xfer_len[0] = (len >> 8) & 0xff;
+ scsi_cmd.xfer_len[1] = len & 0xff;
+ retval = cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 200000, /* should be immed */
+ 0);
+ return(retval);
+}
+/*******************************************************\
+* Get scsi driver to send a "start playing" command *
+\*******************************************************/
+cd_play_big(unit,blk,len)
+int unit,blk,len;
+{
+ struct scsi_play_big scsi_cmd;
+ int retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY_BIG;
+ scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
+ scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
+ scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
+ scsi_cmd.blk_addr[3] = blk & 0xff;
+ scsi_cmd.xfer_len[0] = (len >> 24) & 0xff;
+ scsi_cmd.xfer_len[1] = (len >> 16) & 0xff;
+ scsi_cmd.xfer_len[2] = (len >> 8) & 0xff;
+ scsi_cmd.xfer_len[3] = len & 0xff;
+ retval = cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 20000, /* should be immed */
+ 0);
+ return(retval);
+}
+/*******************************************************\
+* Get scsi driver to send a "start playing" command *
+\*******************************************************/
+cd_play_tracks(unit,strack,sindex,etrack,eindex)
+int unit,strack,sindex,etrack,eindex;
+{
+ struct scsi_play_track scsi_cmd;
+ int retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY_TRACK;
+ scsi_cmd.start_track = strack;
+ scsi_cmd.start_index = sindex;
+ scsi_cmd.end_track = etrack;
+ scsi_cmd.end_index = eindex;
+ retval = cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 20000, /* should be immed */
+ 0);
+ return(retval);
+}
+/*******************************************************\
+* Get scsi driver to send a "start up" command *
+\*******************************************************/
+cd_pause(unit,go)
+int unit,go;
+{
+ struct scsi_pause scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PAUSE;
+ scsi_cmd.resume = go;
+
+ return (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2000,
+ 0));
+}
+/*******************************************************\
+* Get scsi driver to send a "start up" command *
+\*******************************************************/
+cd_reset(unit)
+int unit;
+{
+ return(cd_scsi_cmd(unit,0,0,0,0,2000,SCSI_RESET));
+}
+/*******************************************************\
+* Get scsi driver to send a "start up" command *
+\*******************************************************/
+cd_start_unit(unit,part,type)
+{
+ struct scsi_start_stop scsi_cmd;
+
+ if(type==CD_EJECT && (cd_data[unit].openparts&~(1<<part)) == 0 ) {
+ cd_prevent_unit(unit,CD_EJECT,0);
+ }
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = START_STOP;
+ scsi_cmd.start = type==CD_START?1:0;
+ scsi_cmd.loej = type==CD_EJECT?1:0;
+
+ if (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2000,
+ 0) != 0) {
+ return(ENXIO);
+ } else
+ return(0);
+}
+/*******************************************************\
+* Prevent or allow the user to remove the disk *
+\*******************************************************/
+cd_prevent_unit(unit,type,flags)
+int unit,type,flags;
+{
+ struct scsi_prevent scsi_cmd;
+
+ if(type==CD_EJECT || type==PR_PREVENT || cd_data[unit].openparts == 0 ) {
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PREVENT_ALLOW;
+ scsi_cmd.prevent=type==CD_EJECT?PR_ALLOW:type;
+ if (cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(struct scsi_prevent),
+ 0,
+ 0,
+ 5000,
+ 0) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("cannot prevent/allow on cd%d\n", unit);
+ return(0);
+ }
+ }
+ return(1);
+}
+
+/******************************************************\
+* Read Subchannel *
+\******************************************************/
+
+cd_read_subchannel(unit,mode,format,track,data,len)
+int unit,mode,format,len;
+struct cd_sub_channel_info *data;
+{
+ struct scsi_read_subchannel scsi_cmd;
+ int error;
+
+ bzero(&scsi_cmd,sizeof(scsi_cmd));
+
+ scsi_cmd.op_code=READ_SUBCHANNEL;
+ if(mode==CD_MSF_FORMAT)
+ scsi_cmd.msf=1;
+ scsi_cmd.subQ=1;
+ scsi_cmd.subchan_format=format;
+ scsi_cmd.track=track;
+ scsi_cmd.data_len[0]=(len)>>8;
+ scsi_cmd.data_len[1]=(len)&0xff;
+ return cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(struct scsi_read_subchannel),
+ data,
+ len,
+ 5000,
+ 0);
+}
+
+/*******************************************************\
+* Read Table of contents *
+\*******************************************************/
+cd_read_toc(unit,mode,start,data,len)
+int unit,mode,start,len;
+struct cd_toc_entry *data;
+{
+ struct scsi_read_toc scsi_cmd;
+ int error;
+ int ntoc;
+
+ bzero(&scsi_cmd,sizeof(scsi_cmd));
+ /*if(len!=sizeof(struct ioc_toc_header))
+ ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
+ else*/
+ ntoc=len;
+
+ scsi_cmd.op_code=READ_TOC;
+ if(mode==CD_MSF_FORMAT)
+ scsi_cmd.msf=1;
+ scsi_cmd.from_track=start;
+ scsi_cmd.data_len[0]=(ntoc)>>8;
+ scsi_cmd.data_len[1]=(ntoc)&0xff;
+ return cd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(struct scsi_read_toc),
+ data,
+ len,
+ 5000,
+ 0);
+}
+
+
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+
+/*******************************************************\
+* Get the scsi driver to send a full inquiry to the *
+* device and use the results to fill out the disk *
+* parameter structure. *
+\*******************************************************/
+
+int cd_get_parms(unit, flags)
+{
+ struct cd_data *cd = cd_data + unit;
+
+ /*******************************************************\
+ * First check if we have it all loaded *
+ \*******************************************************/
+ if(cd->flags & CDVALID) return(0);
+ /*******************************************************\
+ * give a number of sectors so that sec * trks * cyls *
+ * is <= disk_size *
+ \*******************************************************/
+ if(cd_size(unit, flags))
+ {
+ cd->flags |= CDVALID;
+ return(0);
+ }
+ else
+ {
+ return(ENXIO);
+ }
+}
+
+/*******************************************************\
+* close the device.. only called if we are the LAST *
+* occurence of an open device *
+\*******************************************************/
+cdclose(dev)
+dev_t dev;
+{
+ unsigned char unit, part;
+ unsigned int old_priority;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ if(scsi_debug & TRACEOPENS)
+ printf("closing cd%d part %d\n",unit,part);
+ cd_data[unit].partflags[part] &= ~CDOPEN;
+ cd_data[unit].openparts &= ~(1 << part);
+ cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
+ return(0);
+}
+
+/*******************************************************\
+* ask the scsi driver to perform a command for us. *
+* Call it through the switch table, and tell it which *
+* sub-unit we want, and what target and lu we wish to *
+* talk to. Also tell it where to find the command *
+* how long int is. *
+* Also tell it where to read/write the data, and how *
+* long the data is supposed to be *
+\*******************************************************/
+int cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
+
+int unit,flags;
+struct scsi_generic *scsi_cmd;
+int cmdlen;
+int timeout;
+u_char *data_addr;
+int datalen;
+{
+ struct scsi_xfer *xs;
+ int retval;
+ int s;
+ struct cd_data *cd = cd_data + unit;
+
+ if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit);
+ if(cd->sc_sw) /* If we have a scsi driver */
+ {
+ xs = cd_get_xs(unit,flags); /* should wait unless booting */
+ if(!xs)
+ {
+ printf("cd_scsi_cmd%d: controller busy"
+ " (this should never happen)\n",unit);
+ return(EBUSY);
+ }
+ xs->flags |= INUSE;
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ \*******************************************************/
+ xs->flags |= flags;
+ xs->adapter = cd->ctlr;
+ xs->targ = cd->targ;
+ xs->lu = cd->lu;
+ xs->retries = CD_RETRIES;
+ xs->timeout = timeout;
+ xs->cmd = scsi_cmd;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->resid = datalen;
+ xs->when_done = (flags & SCSI_NOMASK)
+ ?(int (*)())0
+ :cd_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+retry: xs->error = XS_NOERROR;
+ xs->bp = 0;
+ retval = (*(cd->sc_sw->scsi_cmd))(xs);
+ switch(retval)
+ {
+ case SUCCESSFULLY_QUEUED:
+ s = splbio();
+ while(!(xs->flags & ITSDONE))
+ sleep(xs,PRIBIO+1);
+ splx(s);
+
+ case HAD_ERROR:
+ /*printf("err = %d ",xs->error);*/
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ retval = ESUCCESS;
+ break;
+ case XS_SENSE:
+ retval = (cd_interpret_sense(unit,xs));
+ break;
+ case XS_DRIVER_STUFFUP:
+ retval = EIO;
+ break;
+
+
+ case XS_BUSY:
+ case XS_TIMEOUT:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ printf("cd%d: unknown error category from scsi driver\n"
+ ,unit);
+ }
+ break;
+ case COMPLETE:
+ retval = ESUCCESS;
+ break;
+ case TRY_AGAIN_LATER:
+ if(xs->retries-- )
+ {
+ if(tsleep( 0,PRIBIO + 2,"retry",hz * 2))
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ }
+ cd_free_xs(unit,xs,flags);
+ cdstart(unit); /* check if anything is waiting fr the xs */
+ }
+ else
+ {
+ printf("cd%d: not set up\n",unit);
+ return(EINVAL);
+ }
+ return(retval);
+}
+/***************************************************************\
+* Look at the returned sense and act on the error and detirmine *
+* The unix error number to pass back... (0 = report no error) *
+\***************************************************************/
+
+int cd_interpret_sense(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *sense;
+ int key;
+ int silent;
+
+ /***************************************************************\
+ * If the flags say errs are ok, then always return ok. *
+ \***************************************************************/
+ if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
+ silent = (xs->flags & SCSI_SILENT);
+
+ sense = &(xs->sense);
+ switch(sense->error_class)
+ {
+ case 7:
+ {
+ key=sense->ext.extended.sense_key;
+ switch(key)
+ {
+ case 0x0:
+ return(ESUCCESS);
+ case 0x1:
+ if(!silent)
+ {
+ printf("cd%d: soft error(corrected) ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(ESUCCESS);
+ case 0x2:
+ if(!silent)printf("cd%d: not ready\n ",
+ unit);
+ return(ENODEV);
+ case 0x3:
+ if(!silent)
+ {
+ printf("cd%d: medium error ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0x4:
+ if(!silent)printf("cd%d: non-media hardware failure\n ",
+ unit);
+ return(EIO);
+ case 0x5:
+ if(!silent)printf("cd%d: illegal request\n ",
+ unit);
+ return(EINVAL);
+ case 0x6:
+ if(!silent)printf("cd%d: Unit attention.\n ", unit);
+ if (cd_data[unit].openparts)
+ cd_data[unit].flags &= ~(CDVALID | CDHAVELABEL);
+ {
+ return(EIO);
+ }
+ return(ESUCCESS);
+ case 0x7:
+ if(!silent)
+ {
+ printf("cd%d: attempted protection violation ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EACCES);
+ case 0x8:
+ if(!silent)
+ {
+ printf("cd%d: block wrong state (worm)\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0x9:
+ if(!silent)printf("cd%d: vendor unique\n",
+ unit);
+ return(EIO);
+ case 0xa:
+ if(!silent)printf("cd%d: copy aborted\n ",
+ unit);
+ return(EIO);
+ case 0xb:
+ if(!silent)printf("cd%d: command aborted\n ",
+ unit);
+ return(EIO);
+ case 0xc:
+ if(!silent)
+ {
+ printf("cd%d: search returned\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(ESUCCESS);
+ case 0xd:
+ if(!silent)printf("cd%d: volume overflow\n ",
+ unit);
+ return(ENOSPC);
+ case 0xe:
+ if(!silent)
+ {
+ printf("cd%d: verify miscompare\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0xf:
+ if(!silent)printf("cd%d: unknown error key\n ",
+ unit);
+ return(EIO);
+ }
+ break;
+ }
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ {
+ if(!silent)printf("cd%d: error class %d code %d\n",
+ unit,
+ sense->error_class,
+ sense->error_code);
+ if(sense->valid)
+ if(!silent)printf("block no. %d (decimal)\n",
+ (sense->ext.unextended.blockhi <<16)
+ + (sense->ext.unextended.blockmed <<8)
+ + (sense->ext.unextended.blocklow ));
+ }
+ return(EIO);
+ }
+}
+
+
+
+
+int
+cdsize(dev_t dev)
+{
+ return (-1);
+}
+
+show_mem(address,num)
+unsigned char *address;
+int num;
+{
+ int x,y;
+ printf("------------------------------");
+ for (y = 0; y<num; y += 1)
+ {
+ if(!(y % 16))
+ printf("\n%03d: ",y);
+ printf("%02x ",*address++);
+ }
+ printf("\n------------------------------\n");
+}
+
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h
new file mode 100644
index 0000000..430c70c
--- /dev/null
+++ b/sys/scsi/scsi_all.h
@@ -0,0 +1,373 @@
+/*
+ * HISTORY
+ * $Log: scsi_all.h,v $
+ * Revision 1.2 1992/11/20 23:07:13 julian
+ * add a definition for device type T_NODEVICE
+ *
+ * Revision 1.1 1992/09/26 22:14:02 julian
+ * Initial revision
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ *
+ */
+
+/*
+ * SCSI general interface description
+ */
+
+
+/*
+ * Largely written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+ * SCSI command format
+ */
+
+
+struct scsi_generic
+{
+ u_char opcode;
+ u_char bytes[11];
+};
+
+struct scsi_test_unit_ready
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:4;
+ u_char :3;
+};
+
+struct scsi_send_diag
+{
+ u_char op_code;
+ u_char uol:1;
+ u_char dol:1;
+ u_char selftest:1;
+ u_char :1;
+ u_char pf:1;
+ u_char lun:3;
+ u_char unused[1];
+ u_char paramlen[2];
+ u_char link:1;
+ u_char flag:4;
+ u_char :3;
+};
+
+struct scsi_sense
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_inquiry
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_mode_sense
+{
+ u_char op_code;
+ u_char :3;
+ u_char dbd:1;
+ u_char rsvd:1;
+ u_char lun:3;
+ u_char page_code:6;
+ u_char page_ctrl:2;
+ u_char unused;
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_mode_sense_big
+{
+ u_char op_code;
+ u_char :3;
+ u_char dbd:1;
+ u_char rsvd:1;
+ u_char lun:3;
+ u_char page_code:6;
+ u_char page_ctrl:2;
+ u_char unused[4];
+ u_char length[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_mode_select
+{
+ u_char op_code;
+ u_char sp:1;
+ u_char :3;
+ u_char pf:1;
+ u_char lun:3;
+ u_char unused[2];
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_mode_select_big
+{
+ u_char op_code;
+ u_char sp:1;
+ u_char :3;
+ u_char pf:1;
+ u_char lun:3;
+ u_char unused[5];
+ u_char length[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_reserve
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_release
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_prevent
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char prevent:1;
+ u_char :7;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+#define PR_PREVENT 1
+#define PR_ALLOW 0
+
+/*
+ * Opcodes
+ */
+
+#define TEST_UNIT_READY 0x00
+#define REQUEST_SENSE 0x03
+#define INQUIRY 0x12
+#define MODE_SELECT 0x15
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define RESERVE 0x16
+#define RELEASE 0x17
+#define PREVENT_ALLOW 0x1e
+#define POSITION_TO_ELEMENT 0x2b
+#define MODE_SENSE_BIG 0x54
+#define MODE_SELECT_BIG 0x55
+#define MOVE_MEDIUM 0xa5
+#define READ_ELEMENT_STATUS 0xb8
+
+
+/*
+ * sense data format
+ */
+#define T_DIRECT 0
+#define T_SEQUENTIAL 1
+#define T_PRINTER 2
+#define T_PROCESSOR 3
+#define T_WORM 4
+#define T_READONLY 5
+#define T_SCANNER 6
+#define T_OPTICAL 7
+#define T_NODEVICE 0x1F
+
+#define T_CHANGER 8
+#define T_COMM 9
+
+#define T_REMOV 1
+#define T_FIXED 0
+
+struct scsi_inquiry_data
+{
+ u_char device_type:5;
+ u_char device_qualifier:3;
+ u_char dev_qual2:7;
+ u_char removable:1;
+ u_char ansii_version:3;
+ u_char :5;
+ u_char response_format;
+ u_char additional_length;
+ u_char unused[2];
+ u_char :3;
+ u_char can_link:1;
+ u_char can_sync:1;
+ u_char :3;
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ u_char extra[8];
+};
+
+
+struct scsi_sense_data
+{
+ u_char error_code:4;
+ u_char error_class:3;
+ u_char valid:1;
+ union
+ {
+ struct
+ {
+ u_char blockhi:5;
+ u_char vendor:3;
+ u_char blockmed;
+ u_char blocklow;
+ } unextended;
+ struct
+ {
+ u_char segment;
+ u_char sense_key:4;
+ u_char :1;
+ u_char ili:1;
+ u_char eom:1;
+ u_char filemark:1;
+ u_char info[4];
+ u_char extra_len;
+ /* allocate enough room to hold new stuff
+ u_char cmd_spec_info[4];
+ u_char add_sense_code;
+ u_char add_sense_code_qual;
+ u_char fru;
+ u_char sense_key_spec_1:7;
+ u_char sksv:1;
+ u_char sense_key_spec_2;
+ u_char sense_key_spec_3;
+ ( by increasing 16 to 26 below) */
+ u_char extra_bytes[26];
+ } extended;
+ }ext;
+};
+struct scsi_sense_data_new
+{
+ u_char error_code:7;
+ u_char valid:1;
+ union
+ {
+ struct
+ {
+ u_char blockhi:5;
+ u_char vendor:3;
+ u_char blockmed;
+ u_char blocklow;
+ } unextended;
+ struct
+ {
+ u_char segment;
+ u_char sense_key:4;
+ u_char :1;
+ u_char ili:1;
+ u_char eom:1;
+ u_char filemark:1;
+ u_char info[4];
+ u_char extra_len;
+ u_char cmd_spec_info[4];
+ u_char add_sense_code;
+ u_char add_sense_code_qual;
+ u_char fru;
+ u_char sense_key_spec_1:7;
+ u_char sksv:1;
+ u_char sense_key_spec_2;
+ u_char sense_key_spec_3;
+ u_char extra_bytes[16];
+ } extended;
+ }ext;
+};
+
+struct blk_desc
+{
+ u_char density;
+ u_char nblocks[3];
+ u_char reserved;
+ u_char blklen[3];
+};
+
+struct scsi_mode_header
+{
+ u_char data_length; /* Sense data length */
+ u_char medium_type;
+ u_char dev_spec;
+ u_char blk_desc_len;
+};
+
+struct scsi_mode_header_big
+{
+ u_char data_length[2]; /* Sense data length */
+ u_char medium_type;
+ u_char dev_spec;
+ u_char unused[2];
+ u_char blk_desc_len[2];
+};
+
+
+/*
+ * Status Byte
+ */
+#define SCSI_OK 0x00
+#define SCSI_CHECK 0x02
+#define SCSI_BUSY 0x08
+#define SCSI_INTERM 0x10
diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h
new file mode 100644
index 0000000..c35bdff
--- /dev/null
+++ b/sys/scsi/scsi_cd.h
@@ -0,0 +1,295 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ */
+
+
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+ * SCSI command format
+ */
+
+struct scsi_read_capacity_cd
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_pause
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[6];
+ u_char resume:1;
+ u_char :7;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+#define PA_PAUSE 1
+#define PA_RESUME 0
+
+struct scsi_play_msf
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused;
+ u_char start_m;
+ u_char start_s;
+ u_char start_f;
+ u_char end_m;
+ u_char end_s;
+ u_char end_f;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_play_track
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char start_track;
+ u_char start_index;
+ u_char unused1;
+ u_char end_track;
+ u_char end_index;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_play
+{
+ u_char op_code;
+ u_char reladdr:1;
+ u_char :4;
+ u_char lun:3;
+ u_char blk_addr[4];
+ u_char unused;
+ u_char xfer_len[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_play_big
+{
+ u_char op_code;
+ u_char reladdr:1;
+ u_char :4;
+ u_char lun:3;
+ u_char blk_addr[4];
+ u_char xfer_len[4];
+ u_char unused;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_play_rel_big
+{
+ u_char op_code;
+ u_char reladdr:1;
+ u_char :4;
+ u_char lun:3;
+ u_char blk_addr[4];
+ u_char xfer_len[4];
+ u_char track;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_read_header
+{
+ u_char op_code;
+ u_char :1;
+ u_char msf:1;
+ u_char :3;
+ u_char lun:3;
+ u_char blk_addr[4];
+ u_char unused;
+ u_char data_len[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_read_subchannel
+{
+ u_char op_code;
+ u_char :1;
+ u_char msf:1;
+ u_char :3;
+ u_char lun:3;
+ u_char :6;
+ u_char subQ:1;
+ u_char :1;
+ u_char subchan_format;
+ u_char unused[2];
+ u_char track;
+ u_char data_len[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_read_toc
+{
+ u_char op_code;
+ u_char :1;
+ u_char msf:1;
+ u_char :3;
+ u_char lun:3;
+ u_char unused[4];
+ u_char from_track;
+ u_char data_len[2];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+;
+
+struct scsi_read_cd_capacity
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+/*
+ * Opcodes
+ */
+
+#define READ_CD_CAPACITY 0x25 /* slightly different from disk */
+#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */
+#define READ_TOC 0x43 /* cdrom read TOC */
+#define READ_HEADER 0x44 /* cdrom read header */
+#define PLAY 0x45 /* cdrom play 'play audio' mode */
+#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */
+#define PLAY_TRACK 0x48 /* cdrom play track/index mode */
+#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */
+#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */
+#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */
+#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */
+
+
+struct cd_inquiry_data /* in case there is some special info */
+{
+ u_char device_type:5;
+ u_char device_qualifier:3;
+ u_char dev_qual2:7;
+ u_char removable:1;
+ u_char ansii_version:3;
+ u_char :5;
+ u_char response_format;
+ u_char additional_length;
+ u_char unused[2];
+ u_char :3;
+ u_char can_link:1;
+ u_char can_sync:1;
+ u_char :3;
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ u_char extra[8];
+};
+
+struct scsi_read_cd_cap_data
+{
+ u_char addr_3; /* Most significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least significant */
+ u_char length_3; /* Most significant */
+ u_char length_2;
+ u_char length_1;
+ u_char length_0; /* Least significant */
+};
+
+union cd_pages
+{
+#define AUDIO_PAGE 0x0e
+ struct audio_page
+ {
+ u_char page_code:6;
+ u_char :1;
+ u_char ps:1;
+ u_char param_len;
+ u_char :1;
+ u_char sotc:1;
+ u_char immed:1;
+ u_char :5;
+ u_char unused[2];
+ u_char format_lba:4;
+ u_char :3;
+ u_char apr_valid:1;
+ u_char lb_per_sec[2];
+ struct port_control
+ {
+ u_char channels:4;
+#define CHANNEL_0 1
+#define CHANNEL_1 2
+#define CHANNEL_2 4
+#define CHANNEL_3 8
+#define LEFT_CHANNEL CHANNEL_0
+#define RIGHT_CHANNEL CHANNEL_1
+ u_char :4;
+ u_char volume;
+ } port[4];
+#define LEFT_PORT 0
+#define RIGHT_PORT 1
+ }audio;
+};
+
+struct cd_mode_data
+{
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ union cd_pages page;
+};
+
diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h
new file mode 100644
index 0000000..35a3b78
--- /dev/null
+++ b/sys/scsi/scsi_disk.h
@@ -0,0 +1,249 @@
+/*
+ * HISTORY
+ * $Log: scsi_disk.h,v $
+ * Revision 1.2 1992/10/13 03:14:21 julian
+ * added the load-eject field in 'start/stop' for removable devices.
+ *
+ * Revision 1.1 1992/09/26 22:11:29 julian
+ * Initial revision
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ *
+ */
+
+/*
+ * SCSI interface description
+ */
+
+/*
+ * Some lines of this file comes from a file of the name "scsi.h"
+ * distributed by OSF as part of mach2.5,
+ * so the following disclaimer has been kept.
+ *
+ * Copyright 1990 by Open Software Foundation,
+ * Grenoble, FRANCE
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OSF or Open Software
+ * Foundation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Largely written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+ * SCSI command format
+ */
+
+
+struct scsi_reassign_blocks
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_rw
+{
+ u_char op_code;
+ u_char addr_2:5; /* Most significant */
+ u_char lun:3;
+ u_char addr_1;
+ u_char addr_0; /* least significant */
+ u_char length;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_rw_big
+{
+ u_char op_code;
+ u_char rel_addr:1;
+ u_char :4; /* Most significant */
+ u_char lun:3;
+ u_char addr_3;
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* least significant */
+ u_char reserved;;
+ u_char length2;
+ u_char length1;
+ u_char link:1;
+ u_char flag:1;
+ u_char :4;
+ u_char vendor:2;
+};
+
+struct scsi_read_capacity
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+struct scsi_start_stop
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[2];
+ u_char start:1;
+ u_char loej:1;
+ u_char :6;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+};
+
+
+
+/*
+ * Opcodes
+ */
+
+#define REASSIGN_BLOCKS 0x07
+#define READ_COMMAND 0x08
+#define WRITE_COMMAND 0x0a
+#define MODE_SELECT 0x15
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define PREVENT_ALLOW 0x1e
+#define READ_CAPACITY 0x25
+#define READ_BIG 0x28
+#define WRITE_BIG 0x2a
+
+
+
+struct scsi_read_cap_data
+{
+ u_char addr_3; /* Most significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least significant */
+ u_char length_3; /* Most significant */
+ u_char length_2;
+ u_char length_1;
+ u_char length_0; /* Least significant */
+};
+
+struct scsi_reassign_blocks_data
+{
+ u_char reserved[2];
+ u_char length_msb;
+ u_char length_lsb;
+ struct
+ {
+ u_char dlbaddr_3; /* defect logical block address (MSB) */
+ u_char dlbaddr_2;
+ u_char dlbaddr_1;
+ u_char dlbaddr_0; /* defect logical block address (LSB) */
+ } defect_descriptor[1];
+};
+
+union disk_pages /* this is the structure copied from osf */
+{
+ struct page_disk_format {
+ u_char pg_code:6; /* page code (should be 3) */
+ u_char :2;
+ u_char pg_length; /* page length (should be 0x16) */
+ u_char trk_z_1; /* tracks per zone (MSB) */
+ u_char trk_z_0; /* tracks per zone (LSB) */
+ u_char alt_sec_1; /* alternate sectors per zone (MSB) */
+ u_char alt_sec_0; /* alternate sectors per zone (LSB) */
+ u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */
+ u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */
+ u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */
+ u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */
+ u_char ph_sec_t_1; /* physical sectors per track (MSB) */
+ u_char ph_sec_t_0; /* physical sectors per track (LSB) */
+ u_char bytes_s_1; /* bytes per sector (MSB) */
+ u_char bytes_s_0; /* bytes per sector (LSB) */
+ u_char interleave_1;/* interleave (MSB) */
+ u_char interleave_0;/* interleave (LSB) */
+ u_char trk_skew_1; /* track skew factor (MSB) */
+ u_char trk_skew_0; /* track skew factor (LSB) */
+ u_char cyl_skew_1; /* cylinder skew (MSB) */
+ u_char cyl_skew_0; /* cylinder skew (LSB) */
+ u_char reserved1:4;
+ u_char surf:1;
+ u_char rmb:1;
+ u_char hsec:1;
+ u_char ssec:1;
+ u_char reserved2;
+ u_char reserved3;
+ } disk_format;
+ struct page_rigid_geometry {
+ u_char pg_code:7; /* page code (should be 4) */
+ u_char mbone:1; /* must be one */
+ u_char pg_length; /* page length (should be 0x16) */
+ u_char ncyl_2; /* number of cylinders (MSB) */
+ u_char ncyl_1; /* number of cylinders */
+ u_char ncyl_0; /* number of cylinders (LSB) */
+ u_char nheads; /* number of heads */
+ u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */
+ u_char st_cyl_wp_1; /* starting cyl., write precomp */
+ u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */
+ u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/
+ u_char st_cyl_rwc_1;/* starting cyl., red. write cur */
+ u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/
+ u_char driv_step_1; /* drive step rate (MSB) */
+ u_char driv_step_0; /* drive step rate (LSB) */
+ u_char land_zone_2; /* landing zone cylinder (MSB) */
+ u_char land_zone_1; /* landing zone cylinder */
+ u_char land_zone_0; /* landing zone cylinder (LSB) */
+ u_char reserved1;
+ u_char reserved2;
+ u_char reserved3;
+ } rigid_geometry;
+} ;
diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h
new file mode 100644
index 0000000..2b8a82f
--- /dev/null
+++ b/sys/scsi/scsi_tape.h
@@ -0,0 +1,169 @@
+/*
+ * HISTORY
+ * $Log: scsi_tape.h,v $
+ * Revision 1.2 1993/01/26 18:39:08 julian
+ * add the 'write protected' bit in the device status struct.
+ *
+ * Revision 1.1 1992/09/26 22:10:21 julian
+ * Initial revision
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ *
+ */
+
+/*
+ * SCSI tape interface description
+ */
+
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+ * SCSI command format
+ */
+
+
+struct scsi_rw_tape
+{
+ u_char op_code;
+ u_char fixed:1;
+ u_char :4;
+ u_char lun:3;
+ u_char len[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} rw_tape;
+
+struct scsi_space
+{
+ u_char op_code;
+ u_char code:2;
+ u_char :3;
+ u_char lun:3;
+ u_char number[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} space;
+#define SP_BLKS 0
+#define SP_FILEMARKS 1
+#define SP_SEQ_FILEMARKS 2
+#define SP_EOM 3
+
+struct scsi_write_filemarks
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char number[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} write_filemarks;
+
+struct scsi_rewind
+{
+ u_char op_code;
+ u_char immed:1;
+ u_char :4;
+ u_char lun:3;
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} rewind;
+
+struct scsi_load
+{
+ u_char op_code;
+ u_char immed:1;
+ u_char :4;
+ u_char lun:3;
+ u_char unused[2];
+ u_char load:1;
+ u_char reten:1;
+ u_char :6;
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} load;
+#define LD_UNLOAD 0
+#define LD_LOAD 1
+
+struct scsi_blk_limits
+{
+ u_char op_code;
+ u_char :5;
+ u_char lun:3;
+ u_char unused[3];
+ u_char link:1;
+ u_char flag:1;
+ u_char :6;
+} blk_limits;
+
+/*
+ * Opcodes
+ */
+
+#define REWIND 0x01
+#define READ_BLK_LIMITS 0x05
+#define READ_COMMAND_TAPE 0x08
+#define WRITE_COMMAND_TAPE 0x0a
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+#define LOAD_UNLOAD 0x1b /* same as above */
+
+
+
+struct scsi_blk_limits_data
+{
+ u_char reserved;
+ u_char max_length_2; /* Most significant */
+ u_char max_length_1;
+ u_char max_length_0; /* Least significant */
+ u_char min_length_1; /* Most significant */
+ u_char min_length_0; /* Least significant */
+};
+
+struct scsi_mode_header_tape
+{
+ u_char data_length; /* Sense data length */
+ u_char medium_type;
+ u_char speed:4;
+ u_char buf_mode:3;
+ u_char write_protected:1;
+ u_char blk_desc_len;
+};
+
+
+#define QIC_120 0x0f
+#define QIC_150 0x10
+#define QIC_320 0x11
+#define QIC_525 0x11
+#define QIC_1320 0x12
+
+
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
new file mode 100644
index 0000000..fc1b5ca
--- /dev/null
+++ b/sys/scsi/scsiconf.c
@@ -0,0 +1,761 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00149
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * 23 May 93 Rodney W. Grimes ADDED Pioneer DRM-600 cd changer
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/*
+$Log:
+*
+*/
+#include <sys/types.h>
+#include "st.h"
+#include "sd.h"
+#include "ch.h"
+#include "cd.h"
+
+#ifdef MACH
+#include <i386/machparam.h>
+#endif MACH
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#if !defined(OSF) && !defined(__386BSD__)
+#include "bll.h"
+#include "cals.h"
+#include "kil.h"
+#else
+#define NBLL 0
+#define NCALS 0
+#define NKIL 0
+#endif /* !defined(OSF) && !defined(__386BSD__) */
+
+#if NSD > 0
+extern sdattach();
+#endif NSD
+#if NST > 0
+extern stattach();
+#endif NST
+#if NCH > 0
+extern chattach();
+#endif NCH
+#if NCD > 0
+extern cdattach();
+#endif NCD
+#if NBLL > 0
+extern bllattach();
+#endif NBLL
+#if NCALS > 0
+extern calsattach();
+#endif NCALS
+#if NKIL > 0
+extern kil_attach();
+#endif NKIL
+
+/***************************************************************\
+* The structure of pre-configured devices that might be turned *
+* off and therefore may not show up *
+\***************************************************************/
+struct predefined
+{
+ u_char scsibus;
+ u_char dev;
+ u_char lu;
+ int (*attach_rtn)();
+ char *devname;
+ char flags;
+}
+pd[] =
+{
+#ifdef EXAMPLE_PREDEFINE
+#if NSD > 0
+ {0,0,0,sdattach,"sd",0},/* define a disk at scsibus=0 dev=0 lu=0 */
+#endif NSD
+#endif EXAMPLE_PREDEFINE
+ {0,9,9} /*illegal dummy end entry */
+};
+
+
+/***************************************************************\
+* The structure of known drivers for autoconfiguration *
+\***************************************************************/
+static struct scsidevs
+{
+ int type;
+ int removable;
+ char *manufacturer;
+ char *model;
+ char *version;
+ int (*attach_rtn)();
+ char *devname;
+ char flags; /* 1 show my comparisons during boot(debug) */
+}
+#define SC_SHOWME 0x01
+#define SC_ONE_LU 0x00
+#define SC_MORE_LUS 0x02
+knowndevs[] = {
+#if NSD > 0
+ { T_DIRECT,T_FIXED,"standard","any"
+ ,"any",sdattach,"sd",SC_ONE_LU },
+ { T_DIRECT,T_FIXED,"MAXTOR ","XT-4170S "
+ ,"B5A ",sdattach,"mx1",SC_ONE_LU },
+#endif NSD
+#if NST > 0
+ { T_SEQUENTIAL,T_REMOV,"standard","any"
+ ,"any",stattach,"st",SC_ONE_LU },
+#endif NST
+#if NCALS > 0
+ { T_PROCESSOR,T_FIXED,"standard","any"
+ ,"any",calsattach,"cals",SC_MORE_LUS },
+#endif NCALS
+#if NCH > 0
+ { T_CHANGER,T_REMOV,"standard","any"
+ ,"any",chattach,"ch",SC_ONE_LU },
+#endif NCH
+#if NCD > 0
+ { T_READONLY,T_REMOV,"SONY ","CD-ROM CDU-8012 "
+ ,"3.1a",cdattach,"cd",SC_ONE_LU },
+ { T_READONLY,T_REMOV,"PIONEER ","CD-ROM DRM-600 "
+ ,"any",cdattach,"cd",SC_MORE_LUS },
+#endif NCD
+#if NBLL > 0
+ { T_PROCESSOR,T_FIXED,"AEG ","READER "
+ ,"V1.0",bllattach,"bll",SC_MORE_LUS },
+#endif NBLL
+#if NKIL > 0
+ { T_SCANNER,T_FIXED,"KODAK ","IL Scanner 900 "
+ ,"any",kil_attach,"kil",SC_ONE_LU },
+#endif NKIL
+
+{0}
+};
+/***************************************************************\
+* Declarations *
+\***************************************************************/
+struct predefined *scsi_get_predef();
+struct scsidevs *scsi_probedev();
+struct scsidevs *selectdev();
+
+/* controls debug level within the scsi subsystem */
+/* see scsiconf.h for values */
+int scsi_debug = 0x0;
+int scsibus = 0x0; /* This is the Nth scsibus */
+
+/***************************************************************\
+* The routine called by the adapter boards to get all their *
+* devices configured in. *
+\***************************************************************/
+scsi_attachdevs( unit, scsi_addr, scsi_switch)
+int unit,scsi_addr;
+struct scsi_switch *scsi_switch;
+{
+ int targ,lun;
+ struct scsidevs *bestmatch = (struct scsidevs *)0;
+ struct predefined *predef;
+ int maybe_more;
+
+#ifdef SCSI_DELAY
+#if SCSI_DELAY > 2
+ printf("waiting for scsi devices to settle\n");
+#else SCSI_DELAY > 2
+#define SCSI_DELAY 15
+#endif SCSI_DELAY > 2
+#else
+#define SCSI_DELAY 2
+#endif SCSI_DELAY
+ spinwait(1000 * SCSI_DELAY);
+ targ = 0;
+ while(targ < 8)
+ {
+ maybe_more = 0; /* by default only check 1 lun */
+ if (targ == scsi_addr)
+ {
+ targ++;
+ continue;
+ }
+ lun = 0;
+ while(lun < 8)
+ {
+ predef = scsi_get_predef(scsibus
+ ,targ
+ ,lun
+ ,&maybe_more);
+ bestmatch = scsi_probedev(unit
+ ,targ
+ ,lun
+ ,scsi_switch
+ ,&maybe_more);
+ if((bestmatch) && (predef)) /* both exist */
+ {
+ if(bestmatch->attach_rtn
+ != predef->attach_rtn)
+ {
+ printf("Clash in found/expected devices\n");
+ printf("will link in FOUND\n");
+ }
+ (*(bestmatch->attach_rtn))(unit,
+ targ,
+ lun,
+ scsi_switch);
+ }
+ if((bestmatch) && (!predef)) /* just FOUND */
+ {
+ (*(bestmatch->attach_rtn))(unit,
+ targ,
+ lun,
+ scsi_switch);
+ }
+ if((!bestmatch) && (predef)) /* just predef */
+ {
+ (*(predef->attach_rtn))(unit,
+ targ,
+ lun,
+ scsi_switch);
+ }
+ if(!(maybe_more)) /* nothing suggests we'll find more */
+ {
+ break; /* nothing here, skip to next targ */
+ }
+ /* otherwise something says we should look further*/
+ lun++;
+ }
+ targ++;
+ }
+#if NGENSCSI > 0
+ /***************************************************************\
+ * If available hook up the generic scsi driver, letting it *
+ * know which target is US. (i.e. illegal or at least special) *
+ \***************************************************************/
+ genscsi_attach(unit,scsi_addr,0,scsi_switch);
+#endif
+ scsibus++; /* next time we are on the NEXT scsi bus */
+}
+
+/***********************************************\
+* given a target and lu, check if there is a *
+* predefined device for that address *
+\***********************************************/
+struct predefined *scsi_get_predef(unit,target,lu,maybe_more)
+int unit,target,lu,*maybe_more;
+{
+ int upto,numents;
+
+ numents = (sizeof(pd)/sizeof(struct predefined)) - 1;
+
+ for(upto = 0;upto < numents;upto++)
+ {
+ if(pd[upto].scsibus != unit)
+ continue;
+ if(pd[upto].dev != target)
+ continue;
+ if(pd[upto].lu != lu)
+ continue;
+
+ printf(" dev%d,lu%d: %s - PRECONFIGURED -\n"
+ ,target
+ ,lu
+ ,pd[upto].devname);
+ *maybe_more = pd[upto].flags & SC_MORE_LUS;
+ return(&(pd[upto]));
+ }
+ return((struct predefined *)0);
+}
+
+/***********************************************\
+* given a target and lu, ask the device what *
+* it is, and find the correct driver table *
+* entry. *
+\***********************************************/
+struct scsidevs *scsi_probedev(unit,target,lu,scsi_switch, maybe_more)
+
+struct scsi_switch *scsi_switch;
+int unit,target,lu;
+int *maybe_more;
+{
+ struct scsidevs *bestmatch = (struct scsidevs *)0;
+ char *dtype=(char *)0,*desc;
+ char *qtype;
+ static struct scsi_inquiry_data inqbuf;
+ int len,qualifier,type,remov;
+ char manu[32];
+ char model[32];
+ char version[32];
+
+
+ bzero(&inqbuf,sizeof(inqbuf));
+ /***********************************************\
+ * Ask the device what it is *
+ \***********************************************/
+#ifdef DEBUG
+ if((target == 0) && (lu == 0))
+ scsi_debug = 0xfff;
+ else
+ scsi_debug = 0;
+#endif DEBUG
+ if(scsi_ready( unit,
+ target,
+ lu,
+ scsi_switch,
+ SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
+ {
+ return(struct scsidevs *)0;
+ }
+ if(scsi_inquire(unit,
+ target,
+ lu,
+ scsi_switch,
+ &inqbuf,
+ SCSI_NOSLEEP | SCSI_NOMASK) != COMPLETE)
+ {
+ return(struct scsidevs *)0;
+ }
+
+ /***********************************************\
+ * note what BASIC type of device it is *
+ \***********************************************/
+ if(scsi_debug & SHOWINQUIRY)
+ {
+ desc=(char *)&inqbuf;
+ printf("inq: %x %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ desc[0], desc[1], desc[2], desc[3],
+ desc[4], desc[5], desc[6], desc[7],
+ desc[8], desc[9], desc[10], desc[11],
+ desc[12]);
+ }
+
+ type = inqbuf.device_type;
+ qualifier = inqbuf.device_qualifier;
+ remov = inqbuf.removable;
+
+ /* Check for a non-existent unit. If the device is returning
+ * this much, then we must set the flag that has
+ * the searcher keep looking on other luns.
+ */
+ if (qualifier == 3 && type == T_NODEVICE)
+ {
+ *maybe_more = 1;
+ return (struct scsidevs *)0;
+ }
+
+ /* Any device qualifier that has
+ * the top bit set (qualifier&4 != 0) is vendor specific and
+ * won't match in this switch.
+ */
+
+ switch(qualifier)
+ {
+ case 0:
+ qtype="";
+ break;
+ case 1:
+ qtype=", Unit not Connected!";
+ break;
+ case 2:
+ qtype=", Reserved Peripheral Qualifier!";
+ break;
+ case 3:
+ qtype=", The Target can't support this Unit!";
+ break;
+
+ default:
+ dtype="vendor specific";
+ qtype="";
+ *maybe_more = 1;
+ break;
+ }
+
+ if (dtype == 0)
+ switch(type)
+ {
+ case T_DIRECT:
+ dtype="direct";
+ break;
+ case T_SEQUENTIAL:
+ dtype="sequential";
+ break;
+ case T_PRINTER:
+ dtype="printer";
+ break;
+ case T_PROCESSOR:
+ dtype="processor";
+ break;
+ case T_READONLY:
+ dtype="readonly";
+ break;
+ case T_WORM:
+ dtype="worm";
+ break;
+ case T_SCANNER:
+ dtype="scanner";
+ break;
+ case T_OPTICAL:
+ dtype="optical";
+ break;
+ case T_CHANGER:
+ dtype="changer";
+ break;
+ case T_COMM:
+ dtype="communication";
+ break;
+ default:
+ dtype="unknown";
+ break;
+ }
+
+ /***********************************************\
+ * Then if it's advanced enough, more detailed *
+ * information *
+ \***********************************************/
+ if(inqbuf.ansii_version > 0)
+ {
+ if ((len = inqbuf.additional_length
+ + ( (char *)inqbuf.unused
+ - (char *)&inqbuf))
+ > (sizeof(struct scsi_inquiry_data) - 1))
+ len = sizeof(struct scsi_inquiry_data) - 1;
+ desc=inqbuf.vendor;
+ desc[len-(desc - (char *)&inqbuf)] = 0;
+ strncpy(manu,inqbuf.vendor,8);manu[8]=0;
+ strncpy(model,inqbuf.product,16);model[16]=0;
+ strncpy(version,inqbuf.revision,4);version[4]=0;
+ }
+ else
+ /***********************************************\
+ * If not advanced enough, use default values *
+ \***********************************************/
+ {
+ desc="early protocol device";
+ strncpy(manu,"unknown",8);
+ strncpy(model,"unknown",16);
+ strncpy(version,"????",4);
+ }
+ printf(" dev%d,lu%d: type %d:%d(%s%s),%s '%s%s%s' scsi%d\n"
+ ,target
+ ,lu
+ ,qualifier,type
+ ,dtype,qtype
+ ,remov?"removable":"fixed"
+ ,manu
+ ,model
+ ,version
+ ,inqbuf.ansii_version
+ );
+ /***********************************************\
+ * Try make as good a match as possible with *
+ * available sub drivers *
+ \***********************************************/
+ bestmatch = (selectdev(unit,target,lu,&scsi_switch,
+ qualifier,type,remov,manu,model,version));
+ if((bestmatch) && (bestmatch->flags & SC_MORE_LUS))
+ {
+ *maybe_more = 1;
+ }
+ return(bestmatch);
+}
+
+/***********************************************\
+* Try make as good a match as possible with *
+* available sub drivers *
+\***********************************************/
+struct scsidevs
+*selectdev(unit,target,lu,dvr_switch,qualifier,type,remov,manu,model,rev)
+int unit,target,lu;
+struct scsi_switch *dvr_switch;
+int qualifier,type,remov;
+char *manu,*model,*rev;
+{
+ int numents = (sizeof(knowndevs)/sizeof(struct scsidevs)) - 1;
+ int count = 0;
+ int bestmatches = 0;
+ struct scsidevs *bestmatch = (struct scsidevs *)0;
+ struct scsidevs *thisentry = knowndevs;
+
+ type |= (qualifier << 5);
+
+ thisentry--;
+ while( count++ < numents)
+ {
+ thisentry++;
+ if(type != thisentry->type)
+ {
+ continue;
+ }
+ if(bestmatches < 1)
+ {
+ bestmatches = 1;
+ bestmatch = thisentry;
+ }
+ if(remov != thisentry->removable)
+ {
+ continue;
+ }
+ if(bestmatches < 2)
+ {
+ bestmatches = 2;
+ bestmatch = thisentry;
+ }
+ if(thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-",thisentry->manufacturer, manu);
+ if(strcmp(thisentry->manufacturer, manu))
+ {
+ continue;
+ }
+ if(bestmatches < 3)
+ {
+ bestmatches = 3;
+ bestmatch = thisentry;
+ }
+ if(thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-",thisentry->model, model);
+ if(strcmp(thisentry->model, model))
+ {
+ continue;
+ }
+ if(bestmatches < 4)
+ {
+ bestmatches = 4;
+ bestmatch = thisentry;
+ }
+ if(thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-",thisentry->version, rev);
+ if(strcmp(thisentry->version, rev))
+ {
+ continue;
+ }
+ if(bestmatches < 5)
+ {
+ bestmatches = 5;
+ bestmatch = thisentry;
+ break;
+ }
+ }
+
+ if (bestmatch == (struct scsidevs *)0)
+ printf(" No explicit device driver match for \"%s %s\".\n",
+ manu, model);
+
+ return(bestmatch);
+}
+
+static int recurse = 0;
+/***********************************************\
+* Do a scsi operation asking a device if it is *
+* ready. Use the scsi_cmd routine in the switch *
+* table. *
+\***********************************************/
+scsi_ready(unit,target,lu,scsi_switch, flags)
+struct scsi_switch *scsi_switch;
+{
+ struct scsi_test_unit_ready scsi_cmd;
+ struct scsi_xfer scsi_xfer;
+ volatile int rval;
+ int key;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(&scsi_xfer, sizeof(scsi_xfer));
+ scsi_cmd.op_code = TEST_UNIT_READY;
+
+ scsi_xfer.flags=flags | INUSE;
+ scsi_xfer.adapter=unit;
+ scsi_xfer.targ=target;
+ scsi_xfer.lu=lu;
+ scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
+ scsi_xfer.retries=8;
+ scsi_xfer.timeout=10000;
+ scsi_xfer.cmdlen=sizeof(scsi_cmd);
+ scsi_xfer.data=0;
+ scsi_xfer.datalen=0;
+ scsi_xfer.resid=0;
+ scsi_xfer.when_done=0;
+ scsi_xfer.done_arg=0;
+retry: scsi_xfer.error=0;
+ /*******************************************************\
+ * do not use interrupts *
+ \*******************************************************/
+ rval = (*(scsi_switch->scsi_cmd))(&scsi_xfer);
+ if (rval != COMPLETE)
+ {
+ if(scsi_debug)
+ {
+ printf("scsi error, rval = 0x%x\n",rval);
+ printf("code from driver: 0x%x\n",scsi_xfer.error);
+ }
+ switch(scsi_xfer.error)
+ {
+ case XS_SENSE:
+ /*******************************************************\
+ * Any sense value is illegal except UNIT ATTENTION *
+ * In which case we need to check again to get the *
+ * correct response. *
+ *( especially exabytes) *
+ \*******************************************************/
+ if(scsi_xfer.sense.error_class == 7 )
+ {
+ key = scsi_xfer.sense.ext.extended.sense_key ;
+ switch(key)
+ {
+ case 2: /* not ready BUT PRESENT! */
+ return(COMPLETE);
+ case 6:
+ spinwait(1000);
+ if(scsi_xfer.retries--)
+ {
+ scsi_xfer.flags &= ~ITSDONE;
+ goto retry;
+ }
+ return(COMPLETE);
+ default:
+ if(scsi_debug)
+ printf("%d:%d,key=%x.",
+ target,lu,key);
+ }
+ }
+ return(HAD_ERROR);
+ case XS_BUSY:
+ spinwait(1000);
+ if(scsi_xfer.retries--)
+ {
+ scsi_xfer.flags &= ~ITSDONE;
+ goto retry;
+ }
+ return(COMPLETE); /* it's busy so it's there */
+ case XS_TIMEOUT:
+ default:
+ return(HAD_ERROR);
+ }
+ }
+ return(COMPLETE);
+}
+/***********************************************\
+* Do a scsi operation asking a device what it is*
+* Use the scsi_cmd routine in the switch table. *
+\***********************************************/
+scsi_inquire(unit,target,lu,scsi_switch,inqbuf, flags)
+struct scsi_switch *scsi_switch;
+u_char *inqbuf;
+{
+ struct scsi_inquiry scsi_cmd;
+ struct scsi_xfer scsi_xfer;
+ volatile int rval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(&scsi_xfer, sizeof(scsi_xfer));
+ scsi_cmd.op_code = INQUIRY;
+ scsi_cmd.length = sizeof(struct scsi_inquiry_data);
+
+ scsi_xfer.flags=flags | SCSI_DATA_IN | INUSE;
+ scsi_xfer.adapter=unit;
+ scsi_xfer.targ=target;
+ scsi_xfer.lu=lu;
+ scsi_xfer.retries=8;
+ scsi_xfer.timeout=10000;
+ scsi_xfer.cmd=(struct scsi_generic *)&scsi_cmd;
+ scsi_xfer.cmdlen= sizeof(struct scsi_inquiry);
+ scsi_xfer.data=inqbuf;
+ scsi_xfer.datalen=sizeof(struct scsi_inquiry_data);
+ scsi_xfer.resid=sizeof(struct scsi_inquiry_data);
+ scsi_xfer.when_done=0;
+ scsi_xfer.done_arg=0;
+retry: scsi_xfer.error=0;
+ /*******************************************************\
+ * do not use interrupts *
+ \*******************************************************/
+ if ((*(scsi_switch->scsi_cmd))(&scsi_xfer) != COMPLETE)
+ {
+ if(scsi_debug) printf("inquiry had error(0x%x) ",scsi_xfer.error);
+ switch(scsi_xfer.error)
+ {
+ case XS_NOERROR:
+ break;
+ case XS_SENSE:
+ /*******************************************************\
+ * Any sense value is illegal except UNIT ATTENTION *
+ * In which case we need to check again to get the *
+ * correct response. *
+ *( especially exabytes) *
+ \*******************************************************/
+ if((scsi_xfer.sense.error_class == 7 )
+ && (scsi_xfer.sense.ext.extended.sense_key == 6))
+ { /* it's changed so it's there */
+ spinwait(1000);
+ {
+ if(scsi_xfer.retries--)
+ {
+ scsi_xfer.flags &= ~ITSDONE;
+ goto retry;
+ }
+ }
+ return( COMPLETE);
+ }
+ return(HAD_ERROR);
+ case XS_BUSY:
+ spinwait(1000);
+ if(scsi_xfer.retries--)
+ {
+ scsi_xfer.flags &= ~ITSDONE;
+ goto retry;
+ }
+ case XS_TIMEOUT:
+ default:
+ return(HAD_ERROR);
+ }
+ }
+ return(COMPLETE);
+}
+
+
+
+
+/***********************************************\
+* Utility routines often used in SCSI stuff *
+\***********************************************/
+
+/***********************************************\
+* convert a physical address to 3 bytes, *
+* MSB at the lowest address, *
+* LSB at the highest. *
+\***********************************************/
+
+lto3b(val, bytes)
+u_char *bytes;
+{
+ *bytes++ = (val&0xff0000)>>16;
+ *bytes++ = (val&0xff00)>>8;
+ *bytes = val&0xff;
+}
+
+/***********************************************\
+* The reverse of lto3b *
+\***********************************************/
+_3btol(bytes)
+u_char *bytes;
+{
+ int rc;
+ rc = (*bytes++ << 16);
+ rc += (*bytes++ << 8);
+ rc += *bytes;
+ return(rc);
+}
+
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
new file mode 100644
index 0000000..c36efde
--- /dev/null
+++ b/sys/scsi/scsiconf.h
@@ -0,0 +1,113 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ *
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+/***********************************************\
+* these calls are called by the high-end *
+* drivers to get services from whatever low-end *
+* drivers they are attached to *
+\***********************************************/
+struct scsi_switch
+{
+ int (*scsi_cmd)();
+ void (*scsi_minphys)();
+ int (*open_target_lu)();
+ int (*close_target_lu)();
+ long int (*adapter_info)(); /* see definitions below */
+ u_long spare[3];
+};
+#define AD_INF_MAX_CMDS 0x000000FF /* maximum number of entries
+ queuable to a device by
+ the adapter */
+/* 24 bits of other adapter charcteristics go here */
+
+/***********************************************\
+* The scsi debug control bits *
+\***********************************************/
+extern int scsi_debug;
+#define PRINTROUTINES 0x01
+#define TRACEOPENS 0x02
+#define TRACEINTERRUPTS 0x04
+#define SHOWREQUESTS 0x08
+#define SHOWSCATGATH 0x10
+#define SHOWINQUIRY 0x20
+#define SHOWCOMMANDS 0x40
+
+
+/********************************/
+/* return values for scsi_cmd() */
+/********************************/
+#define SUCCESSFULLY_QUEUED 0
+#define TRY_AGAIN_LATER 1
+#define COMPLETE 2
+#define HAD_ERROR 3
+
+struct scsi_xfer
+{
+ struct scsi_xfer *next; /* when free */
+ int flags;
+ u_char adapter;
+ u_char targ;
+ u_char lu;
+ u_char retries; /* the number of times to retry */
+ long int timeout; /* in miliseconds */
+ struct scsi_generic *cmd;
+ int cmdlen;
+ u_char *data; /* either the dma address OR a uio address */
+ int datalen; /* data len (blank if uio) */
+ int resid;
+ int (*when_done)();
+ int done_arg;
+ int done_arg2;
+ int error;
+ struct buf *bp;
+ struct scsi_sense_data sense;
+};
+/********************************/
+/* Flag values */
+/********************************/
+#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */
+#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */
+#define SCSI_NOSTART 0x04 /* left over from ancient history */
+#define ITSDONE 0x10 /* the transfer is as done as it gets */
+#define INUSE 0x20 /* The scsi_xfer block is in use */
+#define SCSI_SILENT 0x40 /* Don't report errors to console */
+#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */
+#define SCSI_RESET 0x100 /* Reset the device in question */
+#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */
+#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */
+#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */
+#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */
+/********************************/
+/* Error values */
+/********************************/
+#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */
+#define XS_SENSE 0x1 /* Check the returned sense for the error */
+#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */
+#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */
+#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */
+#define XS_BUSY 0x08 /* The device busy, try again later? */
+
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
new file mode 100644
index 0000000..af8ae79
--- /dev/null
+++ b/sys/scsi/sd.c
@@ -0,0 +1,1466 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 2 00149
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * 20 Apr 93 Julian Elischer Fixed error reporting
+ *
+ */
+
+static char rev[] = "$Revision: 1.3 $";
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+#define SPLSD splbio
+#define ESUCCESS 0
+#include <sd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+
+long int sdstrats,sdqueues;
+
+
+#include <ddb.h>
+#if NDDB > 0
+int Debugger();
+#else NDDB > 0
+#define Debugger()
+#endif NDDB > 0
+
+
+#define PAGESIZ 4096
+#define SECSIZE 512
+#define PDLOCATION 29
+#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
+#define SDOUTSTANDING 2
+#define SDQSIZE 4
+#define SD_RETRIES 4
+
+#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part)))
+#define UNITSHIFT 3
+#define PARTITION(z) (minor(z) & 0x07)
+#define RAW_PART 3
+#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
+
+#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART )
+
+struct buf sd_buf_queue[NSD];
+int sd_done();
+int sdstrategy();
+
+int sd_debug = 0;
+
+struct scsi_xfer *sd_free_xfer[NSD];
+int sd_xfer_block_wait[NSD];
+
+struct sd_data
+{
+ int flags;
+#define SDVALID 0x02 /* PARAMS LOADED */
+#define SDINIT 0x04 /* device has been init'd */
+#define SDWAIT 0x08 /* device has someone waiting */
+#define SDHAVELABEL 0x10 /* have read the label */
+#define SDDOSPART 0x20 /* Have read the DOS partition table */
+#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W)*/
+ struct scsi_switch *sc_sw; /* address of scsi low level switch */
+ int ctlr; /* so they know which one we want */
+ int targ; /* our scsi target ID */
+ int lu; /* out scsi lu */
+ long int ad_info; /* info about the adapter */
+ int cmdscount; /* cmds allowed outstanding by board*/
+ int wlabel; /* label is writable */
+ struct disk_parms
+ {
+ u_char heads; /* Number of heads */
+ u_short cyls; /* Number of cylinders */
+ u_char sectors;/*dubious*/ /* Number of sectors/track */
+ u_short secsiz; /* Number of bytes/sector */
+ u_long disksize; /* total number sectors */
+ }params;
+ struct disklabel disklabel;
+ struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
+ int partflags[MAXPARTITIONS]; /* per partition flags */
+#define SDOPEN 0x01
+ int openparts; /* one bit for each open partition */
+ unsigned int sd_start_of_unix; /* unix vs dos partitions */
+}sd_data[NSD];
+
+
+static int next_sd_unit = 0;
+/***********************************************************************\
+* The routine called by the low level scsi routine when it discovers *
+* A device suitable for this driver *
+\***********************************************************************/
+
+int sdattach(ctlr,targ,lu,scsi_switch)
+struct scsi_switch *scsi_switch;
+{
+ int unit,i;
+ unsigned char *tbl;
+ struct sd_data *sd;
+ struct disk_parms *dp;
+ long int ad_info;
+ struct scsi_xfer *sd_scsi_xfer;
+
+ unit = next_sd_unit++;
+ sd = sd_data + unit;
+ dp = &(sd->params);
+ if(scsi_debug & PRINTROUTINES) printf("sdattach: ");
+ /*******************************************************\
+ * Check we have the resources for another drive *
+ \*******************************************************/
+ if( unit >= NSD)
+ {
+ printf("Too many scsi disks..(%d > %d) reconfigure kernel",(unit + 1),NSD);
+ return(0);
+ }
+ /*******************************************************\
+ * Store information needed to contact our base driver *
+ \*******************************************************/
+ sd->sc_sw = scsi_switch;
+ sd->ctlr = ctlr;
+ sd->targ = targ;
+ sd->lu = lu;
+ if(sd->sc_sw->adapter_info)
+ {
+ sd->ad_info = ( (*(sd->sc_sw->adapter_info))(ctlr));
+ sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
+ if(sd->cmdscount > SDOUTSTANDING)
+ {
+ sd->cmdscount = SDOUTSTANDING;
+ }
+ }
+ else
+ {
+ sd->ad_info = 1;
+ sd->cmdscount = 1;
+ }
+
+ i = sd->cmdscount;
+ sd_scsi_xfer = (struct scsi_xfer *)malloc(sizeof(struct scsi_xfer) * i
+ ,M_TEMP, M_NOWAIT);
+ while(i-- )
+ {
+ sd_scsi_xfer->next = sd_free_xfer[unit];
+ sd_free_xfer[unit] = sd_scsi_xfer;
+ sd_scsi_xfer++;
+ }
+ /*******************************************************\
+ * Use the subdriver to request information regarding *
+ * the drive. We cannot use interrupts yet, so the *
+ * request must specify this. *
+ \*******************************************************/
+ sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ printf(" sd%d: %dMB, cyls %d, heads %d, secs %d, bytes/sec %d\n",
+ unit,
+ ( dp->cyls
+ * dp->heads
+ * dp->sectors
+ * dp->secsiz
+ )
+ / (1024 * 1024),
+ dp->cyls,
+ dp->heads,
+ dp->sectors,
+ dp->secsiz);
+ /*******************************************************\
+ * Set up the bufs for this device *
+ \*******************************************************/
+ sd->flags |= SDINIT;
+ return;
+
+}
+
+
+
+/*******************************************************\
+* open the device. Make sure the partition info *
+* is a up-to-date as can be. *
+\*******************************************************/
+sdopen(dev)
+{
+ int errcode = 0;
+ int unit, part;
+ struct disk_parms disk_parms;
+ struct sd_data *sd ;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = sd_data + unit;
+ if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
+ printf("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
+ , dev, unit, NSD, part);
+ /*******************************************************\
+ * Check the unit is legal *
+ \*******************************************************/
+ if ( unit >= NSD )
+ {
+ return(ENXIO);
+ }
+ /*******************************************************\
+ * Make sure the disk has been initialised *
+ * At some point in the future, get the scsi driver *
+ * to look for a new device if we are not initted *
+ \*******************************************************/
+ if (! (sd->flags & SDINIT))
+ {
+ return(ENXIO);
+ }
+
+ /*******************************************************\
+ * If it's been invalidated, and not everybody has *
+ * closed it then forbid re-entry. *
+ \*******************************************************/
+ if ((! (sd->flags & SDVALID))
+ && ( sd->openparts))
+ return(ENXIO);
+ /*******************************************************\
+ * Check that it is still responding and ok. *
+ * "unit attention errors should occur here if the drive *
+ * has been restarted or the pack changed *
+ \*******************************************************/
+
+ if(scsi_debug & TRACEOPENS)
+ printf("device is ");
+ if (sd_test_unit_ready(unit,0))
+ {
+ if(scsi_debug & TRACEOPENS) printf("not reponding\n");
+ return(ENXIO);
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("ok\n");
+ /*******************************************************\
+ * In case it is a funny one, tell it to start *
+ * not needed for most hard drives (ignore failure) *
+ \*******************************************************/
+ sd_start_unit(unit,SCSI_ERR_OK|SCSI_SILENT);
+ if(scsi_debug & TRACEOPENS)
+ printf("started ");
+ /*******************************************************\
+ * Load the physical device parameters *
+ \*******************************************************/
+ sd_get_parms(unit, 0); /* sets SDVALID */
+ if (sd->params.secsiz != SECSIZE)
+ {
+ printf("sd%d: Can't deal with %d bytes logical blocks\n"
+ ,unit, sd->params.secsiz);
+ Debugger();
+ return(ENXIO);
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("Params loaded ");
+ /*******************************************************\
+ * Load the partition info if not already loaded *
+ \*******************************************************/
+ sd_prevent(unit,PR_PREVENT,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
+ if((errcode = sdgetdisklabel(unit)) && (part != RAW_PART))
+ {
+ sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
+ return(errcode);
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("Disklabel loaded ");
+ /*******************************************************\
+ * Check the partition is legal *
+ \*******************************************************/
+ if ( part >= MAXPARTITIONS ) {
+ sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
+ return(ENXIO);
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("ok");
+ /*******************************************************\
+ * Check that the partition exists *
+ \*******************************************************/
+ if (( sd->disklabel.d_partitions[part].p_size == 0 )
+ && (part != RAW_PART))
+ {
+ sd_prevent(unit,PR_ALLOW,SCSI_ERR_OK|SCSI_SILENT); /* who cares if it fails? */
+ return(ENXIO);
+ }
+ sd->partflags[part] |= SDOPEN;
+ sd->openparts |= (1 << part);
+ if(scsi_debug & TRACEOPENS)
+ printf("open %d %d\n",sdstrats,sdqueues);
+ return(0);
+}
+
+/*******************************************************\
+* Get ownership of a scsi_xfer *
+* If need be, sleep on it, until it comes free *
+\*******************************************************/
+struct scsi_xfer *sd_get_xs(unit,flags)
+int flags;
+int unit;
+{
+ struct scsi_xfer *xs;
+ int s;
+
+ if(flags & (SCSI_NOSLEEP | SCSI_NOMASK))
+ {
+ if (xs = sd_free_xfer[unit])
+ {
+ sd_free_xfer[unit] = xs->next;
+ xs->flags = 0;
+ }
+ }
+ else
+ {
+ s = SPLSD();
+ while (!(xs = sd_free_xfer[unit]))
+ {
+ sd_xfer_block_wait[unit]++; /* someone waiting! */
+ sleep((caddr_t)&sd_free_xfer[unit], PRIBIO+1);
+ sd_xfer_block_wait[unit]--;
+ }
+ sd_free_xfer[unit] = xs->next;
+ splx(s);
+ xs->flags = 0;
+ }
+ return(xs);
+}
+
+/*******************************************************\
+* Free a scsi_xfer, wake processes waiting for it *
+\*******************************************************/
+sd_free_xs(unit,xs,flags)
+struct scsi_xfer *xs;
+int unit;
+int flags;
+{
+ int s;
+
+ if(flags & SCSI_NOMASK)
+ {
+ if (sd_xfer_block_wait[unit])
+ {
+ printf("doing a wakeup from NOMASK mode\n");
+ wakeup((caddr_t)&sd_free_xfer[unit]);
+ }
+ xs->next = sd_free_xfer[unit];
+ sd_free_xfer[unit] = xs;
+ }
+ else
+ {
+ s = SPLSD();
+ if (sd_xfer_block_wait[unit])
+ wakeup((caddr_t)&sd_free_xfer[unit]);
+ xs->next = sd_free_xfer[unit];
+ sd_free_xfer[unit] = xs;
+ splx(s);
+ }
+}
+
+/*******************************************************\
+* trim the size of the transfer if needed, *
+* called by physio *
+* basically the smaller of our max and the scsi driver's*
+* minphys (note we have no max) *
+\*******************************************************/
+/* Trim buffer length if buffer-size is bigger than page size */
+void sdminphys(bp)
+struct buf *bp;
+{
+ (*(sd_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp);
+}
+
+/*******************************************************\
+* Actually translate the requested transfer into *
+* one the physical driver can understand *
+* The transfer is described by a buf and will include *
+* only one physical transfer. *
+\*******************************************************/
+
+int sdstrategy(bp)
+struct buf *bp;
+{
+ struct buf *dp;
+ unsigned int opri;
+ struct sd_data *sd ;
+ int unit;
+
+ sdstrats++;
+ unit = UNIT((bp->b_dev));
+ sd = sd_data + unit;
+ if(scsi_debug & PRINTROUTINES) printf("\nsdstrategy ");
+ if(scsi_debug & SHOWREQUESTS) printf("sd%d: %d bytes @ blk%d\n",
+ unit,bp->b_bcount,bp->b_blkno);
+ sdminphys(bp);
+ /*******************************************************\
+ * If the device has been made invalid, error out *
+ \*******************************************************/
+ if(!(sd->flags & SDVALID))
+ {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*******************************************************\
+ * "soft" write protect check *
+ \*******************************************************/
+ if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+ /*******************************************************\
+ * If it's a null transfer, return immediatly *
+ \*******************************************************/
+ if (bp->b_bcount == 0)
+ {
+ goto done;
+ }
+
+ /*******************************************************\
+ * Decide which unit and partition we are talking about *
+ * only raw is ok if no label *
+ \*******************************************************/
+ if(PARTITION(bp->b_dev) != RAW_PART)
+ {
+ if (!(sd->flags & SDHAVELABEL))
+ {
+ bp->b_error = EIO;
+ goto bad;
+ }
+
+ /*
+ * do bounds checking, adjust transfer. if error, process.
+ * if end of partition, just return
+ */
+ if (bounds_check_with_label(bp,&sd->disklabel,sd->wlabel) <= 0)
+ goto done;
+ /* otherwise, process transfer request */
+ }
+
+ opri = SPLSD();
+ dp = &sd_buf_queue[unit];
+
+ /*******************************************************\
+ * Place it in the queue of disk activities for this disk*
+ \*******************************************************/
+ disksort(dp, bp);
+
+ /*******************************************************\
+ * Tell the device to get going on the transfer if it's *
+ * not doing anything, otherwise just wait for completion*
+ \*******************************************************/
+ sdstart(unit);
+
+ splx(opri);
+ return;
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+
+ /*******************************************************\
+ * Correctly set the buf to indicate a completed xfer *
+ \*******************************************************/
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return;
+}
+
+/***************************************************************\
+* sdstart looks to see if there is a buf waiting for the device *
+* and that the device is not already busy. If both are true, *
+* It deques the buf and creates a scsi command to perform the *
+* transfer in the buf. The transfer request will call sd_done *
+* on completion, which will in turn call this routine again *
+* so that the next queued transfer is performed. *
+* The bufs are queued by the strategy routine (sdstrategy) *
+* *
+* This routine is also called after other non-queued requests *
+* have been made of the scsi driver, to ensure that the queue *
+* continues to be drained. *
+* *
+* must be called at the correct (highish) spl level *
+\***************************************************************/
+/* sdstart() is called at SPLSD from sdstrategy and sd_done*/
+sdstart(unit)
+int unit;
+{
+ int drivecount;
+ register struct buf *bp = 0;
+ register struct buf *dp;
+ struct scsi_xfer *xs;
+ struct scsi_rw_big cmd;
+ int blkno, nblk;
+ struct sd_data *sd = sd_data + unit;
+ struct partition *p ;
+
+ if(scsi_debug & PRINTROUTINES) printf("sdstart%d ",unit);
+ /*******************************************************\
+ * See if there is a buf to do and we are not already *
+ * doing one *
+ \*******************************************************/
+ if(!sd_free_xfer[unit])
+ {
+ return; /* none for us, unit already underway */
+ }
+
+ if(sd_xfer_block_wait[unit]) /* there is one, but a special waits */
+ {
+ return; /* give the special that's waiting a chance to run */
+ }
+
+
+ dp = &sd_buf_queue[unit];
+ if ((bp = dp->b_actf) != NULL) /* yes, an assign */
+ {
+ dp->b_actf = bp->av_forw;
+ }
+ else
+ {
+ return;
+ }
+
+ xs=sd_get_xs(unit,0); /* ok we can grab it */
+ xs->flags = INUSE; /* Now ours */
+ /*******************************************************\
+ * If the device has become invalid, abort all the *
+ * reads and writes until all files have been closed and *
+ * re-openned *
+ \*******************************************************/
+ if(!(sd->flags & SDVALID))
+ {
+ xs->error = XS_DRIVER_STUFFUP;
+ sd_done(unit,xs); /* clean up (calls sdstart) */
+ return ;
+ }
+ /*******************************************************\
+ * We have a buf, now we should move the data into *
+ * a scsi_xfer definition and try start it *
+ \*******************************************************/
+ /*******************************************************\
+ * First, translate the block to absolute *
+ \*******************************************************/
+ p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
+ blkno = bp->b_blkno + p->p_offset;
+ nblk = (bp->b_bcount + 511) >> 9;
+
+ /*******************************************************\
+ * Fill out the scsi command *
+ \*******************************************************/
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = (bp->b_flags & B_READ)
+ ? READ_BIG : WRITE_BIG;
+ cmd.addr_3 = (blkno & 0xff000000) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ * Note: we cannot sleep as we may be an interrupt *
+ \*******************************************************/
+ xs->flags |= SCSI_NOSLEEP;
+ xs->adapter = sd->ctlr;
+ xs->targ = sd->targ;
+ xs->lu = sd->lu;
+ xs->retries = SD_RETRIES;
+ xs->timeout = 10000;/* 10000 millisecs for a disk !*/
+ xs->cmd = (struct scsi_generic *)&cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->resid = bp->b_bcount;
+ xs->when_done = sd_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+ xs->error = XS_NOERROR;
+ xs->bp = bp;
+ xs->data = (u_char *)bp->b_un.b_addr;
+ xs->datalen = bp->b_bcount;
+ /*******************************************************\
+ * Pass all this info to the scsi driver. *
+ \*******************************************************/
+
+
+
+ if ( (*(sd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
+ {
+ printf("sd%d: oops not queued",unit);
+ xs->error = XS_DRIVER_STUFFUP;
+ sd_done(unit,xs); /* clean up (calls sdstart) */
+ }
+ sdqueues++;
+}
+
+/*******************************************************\
+* This routine is called by the scsi interrupt when *
+* the transfer is complete.
+\*******************************************************/
+int sd_done(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct buf *bp;
+ int retval;
+ int retries = 0;
+
+ if(scsi_debug & PRINTROUTINES) printf("sd_done%d ",unit);
+ if (! (xs->flags & INUSE))
+ panic("scsi_xfer not in use!");
+ if(bp = xs->bp)
+ {
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ break;
+
+ case XS_SENSE:
+ retval = (sd_interpret_sense(unit,xs));
+ if(retval)
+ {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = retval;
+ }
+ break;
+
+ case XS_TIMEOUT:
+ printf("sd%d timeout\n",unit);
+
+ case XS_BUSY: /* should retry */ /* how? */
+ /************************************************/
+ /* SHOULD put buf back at head of queue */
+ /* and decrement retry count in (*xs) */
+ /* HOWEVER, this should work as a kludge */
+ /************************************************/
+ if(xs->retries--)
+ {
+ xs->error = XS_NOERROR;
+ xs->flags &= ~ITSDONE;
+ if ( (*(sd_data[unit].sc_sw->scsi_cmd))(xs)
+ == SUCCESSFULLY_QUEUED)
+ { /* don't wake the job, ok? */
+ return;
+ }
+ xs->flags |= ITSDONE;
+ } /* fall through */
+
+ case XS_DRIVER_STUFFUP:
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ break;
+ default:
+ printf("sd%d: unknown error category from scsi driver\n"
+ ,unit);
+ }
+ biodone(bp);
+ sd_free_xs(unit,xs,0);
+ sdstart(unit); /* If there's anything waiting.. do it */
+ }
+ else /* special has finished */
+ {
+ wakeup(xs);
+ }
+}
+/*******************************************************\
+* Perform special action on behalf of the user *
+* Knows about the internals of this device *
+\*******************************************************/
+sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ /* struct sd_cmd_buf *args;*/
+ int error = 0;
+ unsigned int opri;
+ unsigned char unit, part;
+ register struct sd_data *sd;
+
+
+ /*******************************************************\
+ * Find the device that the user is talking about *
+ \*******************************************************/
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = &sd_data[unit];
+ if(scsi_debug & PRINTROUTINES) printf("sdioctl%d ",unit);
+
+ /*******************************************************\
+ * If the device is not valid.. abandon ship *
+ \*******************************************************/
+ if (!(sd_data[unit].flags & SDVALID))
+ return(EIO);
+ switch(cmd)
+ {
+
+ case DIOCSBAD:
+ error = EINVAL;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)addr = sd->disklabel;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *)addr)->disklab = &sd->disklabel;
+ ((struct partinfo *)addr)->part =
+ &sd->disklabel.d_partitions[PARTITION(dev)];
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&sd->disklabel,
+ (struct disklabel *)addr,
+ /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */0,
+ sd->dosparts);
+ if (error == 0) {
+ sd->flags |= SDHAVELABEL;
+ }
+ break;
+
+ case DIOCWLABEL:
+ sd->flags &= ~SDWRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ sd->wlabel = *(int *)addr;
+ break;
+
+ case DIOCWDINFO:
+ sd->flags &= ~SDWRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ {
+ if ((error = setdisklabel(&sd->disklabel
+ , (struct disklabel *)addr
+ , /*(sd->flags & SDHAVELABEL) ? sd->openparts :*/ 0
+ , sd->dosparts)) == 0)
+ {
+ int wlab;
+
+ sd->flags |= SDHAVELABEL; /* ok write will succeed */
+
+ /* simulate opening partition 0 so write succeeds */
+ sd->openparts |= (1 << 0); /* XXX */
+ wlab = sd->wlabel;
+ sd->wlabel = 1;
+ error = writedisklabel(dev, sdstrategy,
+ &sd->disklabel, sd->dosparts);
+ sd->wlabel = wlab;
+ }
+ }
+ break;
+
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+
+/*******************************************************\
+* Load the label information on the named device *
+\*******************************************************/
+int sdgetdisklabel(unit)
+unsigned char unit;
+{
+ /*unsigned int n, m;*/
+ char *errstring;
+ struct dos_partition *dos_partition_p;
+ struct sd_data *sd = sd_data + unit;
+
+ /*******************************************************\
+ * If the inflo is already loaded, use it *
+ \*******************************************************/
+ if(sd->flags & SDHAVELABEL) return(ESUCCESS);
+
+ bzero(&sd->disklabel,sizeof(struct disklabel));
+ /*******************************************************\
+ * make partition 3 the whole disk in case of failure *
+ * then get pdinfo *
+ \*******************************************************/
+ sd->disklabel.d_partitions[0].p_offset = 0;
+ sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
+ sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
+ sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
+ sd->disklabel.d_npartitions = MAXPARTITIONS;
+ sd->disklabel.d_secsize = 512; /* as long as it's not 0 */
+ sd->disklabel.d_ntracks = sd->params.heads;
+ sd->disklabel.d_nsectors = sd->params.sectors;
+ sd->disklabel.d_ncylinders = sd->params.cyls;
+ sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
+ if (sd->disklabel.d_secpercyl == 0)
+ {
+ sd->disklabel.d_secpercyl = 100;
+ /* as long as it's not 0 */
+ /* readdisklabel divides by it */
+ }
+
+ /*******************************************************\
+ * all the generic bisklabel extraction routine *
+ \*******************************************************/
+ if(errstring = readdisklabel(makedev(0 ,(unit<<UNITSHIFT )+3)
+ , sdstrategy
+ , &sd->disklabel
+ , sd->dosparts
+ , 0
+ , 0))
+ {
+ printf("sd%d: %s\n",unit, errstring);
+ return(ENXIO);
+ }
+ /*******************************************************\
+ * leave partition 2 "open" for raw I/O *
+ \*******************************************************/
+
+ sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
+ return(ESUCCESS);
+}
+
+/*******************************************************\
+* Find out from the device what it's capacity is *
+\*******************************************************/
+sd_size(unit, flags)
+{
+ struct scsi_read_cap_data rdcap;
+ struct scsi_read_capacity scsi_cmd;
+ int size;
+
+ /*******************************************************\
+ * make up a scsi command and ask the scsi driver to do *
+ * it for you. *
+ \*******************************************************/
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CAPACITY;
+
+ /*******************************************************\
+ * If the command works, interpret the result as a 4 byte*
+ * number of blocks *
+ \*******************************************************/
+ if (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &rdcap,
+ sizeof(rdcap),
+ 2000,
+ flags) != 0)
+ {
+ printf("could not get size of unit %d\n", unit);
+ return(0);
+ } else {
+ size = rdcap.addr_0 + 1 ;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ }
+ return(size);
+}
+
+/*******************************************************\
+* Get scsi driver to send a "are you ready?" command *
+\*******************************************************/
+sd_test_unit_ready(unit,flags)
+int unit,flags;
+{
+ struct scsi_test_unit_ready scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = TEST_UNIT_READY;
+
+ return (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 100000,
+ flags));
+}
+
+/*******************************************************\
+* Prevent or allow the user to remove the tape *
+\*******************************************************/
+sd_prevent(unit,type,flags)
+int unit,type,flags;
+{
+ struct scsi_prevent scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PREVENT_ALLOW;
+ scsi_cmd.prevent=type;
+ return (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 5000,
+ flags) );
+}
+/*******************************************************\
+* Get scsi driver to send a "start up" command *
+\*******************************************************/
+sd_start_unit(unit,flags)
+int unit,flags;
+{
+ struct scsi_start_stop scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = START_STOP;
+ scsi_cmd.start = 1;
+
+ return (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2000,
+ flags));
+}
+
+/*******************************************************\
+* Tell the device to map out a defective block *
+\*******************************************************/
+sd_reassign_blocks(unit,block)
+{
+ struct scsi_reassign_blocks scsi_cmd;
+ struct scsi_reassign_blocks_data rbdata;
+
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(&rbdata, sizeof(rbdata));
+ scsi_cmd.op_code = REASSIGN_BLOCKS;
+
+ rbdata.length_msb = 0;
+ rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
+ rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_0 = ((block ) & 0xff);
+
+ return(sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &rbdata,
+ sizeof(rbdata),
+ 5000,
+ 0));
+}
+
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+
+/*******************************************************\
+* Get the scsi driver to send a full inquiry to the *
+* device and use the results to fill out the disk *
+* parameter structure. *
+\*******************************************************/
+
+int sd_get_parms(unit, flags)
+{
+ struct sd_data *sd = sd_data + unit;
+ struct disk_parms *disk_parms = &sd->params;
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_mode_sense_data
+ {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ union disk_pages pages;
+ }scsi_sense;
+ int sectors;
+
+ /*******************************************************\
+ * First check if we have it all loaded *
+ \*******************************************************/
+ if(sd->flags & SDVALID) return(0);
+ /*******************************************************\
+ * First do a mode sense page 3 *
+ \*******************************************************/
+ if (sd_debug)
+ {
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.page_code = 3;
+ scsi_cmd.length = 0x24;
+ /*******************************************************\
+ * do the command, but we don't need the results *
+ * just print them for our interest's sake *
+ \*******************************************************/
+ if (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &scsi_sense,
+ sizeof(scsi_sense),
+ 2000,
+ flags) != 0)
+ {
+ printf("could not mode sense (3) for unit %d\n", unit);
+ return(ENXIO);
+ }
+ printf("unit %d: %d trk/zone, %d alt_sec/zone, %d alt_trk/zone, %d alt_trk/lun\n",
+ unit,
+ b2tol(scsi_sense.pages.disk_format.trk_z),
+ b2tol(scsi_sense.pages.disk_format.alt_sec),
+ b2tol(scsi_sense.pages.disk_format.alt_trk_z),
+ b2tol(scsi_sense.pages.disk_format.alt_trk_v));
+ printf(" %d sec/trk, %d bytes/sec, %d interleave, %d %d bytes/log_blk\n",
+ b2tol(scsi_sense.pages.disk_format.ph_sec_t),
+ b2tol(scsi_sense.pages.disk_format.bytes_s),
+ b2tol(scsi_sense.pages.disk_format.interleave),
+ sd_size(unit, flags),
+ _3btol(scsi_sense.blk_desc.blklen));
+ }
+
+
+ /*******************************************************\
+ * do a "mode sense page 4" *
+ \*******************************************************/
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.page_code = 4;
+ scsi_cmd.length = 0x20;
+ /*******************************************************\
+ * If the command worked, use the results to fill out *
+ * the parameter structure *
+ \*******************************************************/
+ if (sd_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &scsi_sense,
+ sizeof(scsi_sense),
+ 2000,
+ flags) != 0)
+ {
+ printf("could not mode sense (4) for unit %d\n", unit);
+ printf(" using ficticious geometry\n");
+ /* use adaptec standard ficticious geometry */
+ sectors = sd_size(unit, flags);
+ disk_parms->heads = 64;
+ disk_parms->sectors = 32;
+ disk_parms->cyls = sectors/(64 * 32);
+ disk_parms->secsiz = SECSIZE;
+ }
+ else
+ {
+
+ if (sd_debug)
+ {
+ printf(" %d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
+ _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
+ scsi_sense.pages.rigid_geometry.nheads,
+ b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
+ b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
+ b2tol(scsi_sense.pages.rigid_geometry.land_zone));
+ }
+
+ /*******************************************************\
+ * KLUDGE!!(for zone recorded disks) *
+ * give a number of sectors so that sec * trks * cyls *
+ * is <= disk_size *
+ \*******************************************************/
+ disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
+ disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
+ disk_parms->secsiz = _3btol(&scsi_sense.blk_desc.blklen);
+
+ sectors = sd_size(unit, flags);
+ sectors /= disk_parms->cyls;
+ sectors /= disk_parms->heads;
+ disk_parms->sectors = sectors; /* dubious on SCSI*/
+ }
+
+ sd->flags |= SDVALID;
+ return(0);
+}
+
+/*******************************************************\
+* close the device.. only called if we are the LAST *
+* occurence of an open device *
+\*******************************************************/
+sdclose(dev)
+dev_t dev;
+{
+ unsigned char unit, part;
+ unsigned int old_priority;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd_data[unit].partflags[part] &= ~SDOPEN;
+ sd_data[unit].openparts &= ~(1 << part);
+ if(sd_data[unit].openparts == 0) /* if all partitions closed */
+ {
+ sd_prevent(unit,PR_ALLOW,SCSI_SILENT|SCSI_ERR_OK);
+ }
+ return(0);
+}
+
+/*******************************************************\
+* ask the scsi driver to perform a command for us. *
+* Call it through the switch table, and tell it which *
+* sub-unit we want, and what target and lu we wish to *
+* talk to. Also tell it where to find the command *
+* how long int is. *
+* Also tell it where to read/write the data, and how *
+* long the data is supposed to be *
+\*******************************************************/
+int sd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
+
+int unit,flags;
+struct scsi_generic *scsi_cmd;
+int cmdlen;
+int timeout;
+u_char *data_addr;
+int datalen;
+{
+ struct scsi_xfer *xs;
+ int retval;
+ int s;
+ struct sd_data *sd = sd_data + unit;
+
+ if(scsi_debug & PRINTROUTINES) printf("\nsd_scsi_cmd%d ",unit);
+ if(sd->sc_sw) /* If we have a scsi driver */
+ {
+ xs = sd_get_xs(unit,flags); /* should wait unless booting */
+ if(!xs)
+ {
+ printf("sd_scsi_cmd%d: controller busy"
+ " (this should never happen)\n",unit);
+ return(EBUSY);
+ }
+ xs->flags |= INUSE;
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ \*******************************************************/
+ xs->flags |= flags;
+ xs->adapter = sd->ctlr;
+ xs->targ = sd->targ;
+ xs->lu = sd->lu;
+ xs->retries = SD_RETRIES;
+ xs->timeout = timeout;
+ xs->cmd = scsi_cmd;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->resid = datalen;
+ xs->when_done = (flags & SCSI_NOMASK)
+ ?(int (*)())0
+ :sd_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+retry: xs->error = XS_NOERROR;
+ xs->bp = 0;
+ retval = (*(sd->sc_sw->scsi_cmd))(xs);
+ switch(retval)
+ {
+ case SUCCESSFULLY_QUEUED:
+ s = splbio();
+ while(!(xs->flags & ITSDONE))
+ sleep(xs,PRIBIO+1);
+ splx(s);
+
+ case HAD_ERROR:
+ /*printf("err = %d ",xs->error);*/
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ retval = ESUCCESS;
+ break;
+ case XS_SENSE:
+ retval = (sd_interpret_sense(unit,xs));
+ break;
+ case XS_DRIVER_STUFFUP:
+ retval = EIO;
+ break;
+ case XS_TIMEOUT:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ case XS_BUSY:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ printf("sd%d: unknown error category from scsi driver\n"
+ ,unit);
+ }
+ break;
+ case COMPLETE:
+ retval = ESUCCESS;
+ break;
+ case TRY_AGAIN_LATER:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ }
+ sd_free_xs(unit,xs,flags);
+ sdstart(unit); /* check if anything is waiting fr the xs */
+ }
+ else
+ {
+ printf("sd%d: not set up\n",unit);
+ return(EINVAL);
+ }
+ return(retval);
+}
+/***************************************************************\
+* Look at the returned sense and act on the error and detirmine *
+* The unix error number to pass back... (0 = report no error) *
+\***************************************************************/
+
+int sd_interpret_sense(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *sense;
+ int key;
+ int silent;
+
+ /***************************************************************\
+ * If the flags say errs are ok, then always return ok. *
+ \***************************************************************/
+ if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
+ silent = (xs->flags & SCSI_SILENT);
+
+ sense = &(xs->sense);
+ switch(sense->error_class)
+ {
+ case 7:
+ {
+ key=sense->ext.extended.sense_key;
+ switch(key)
+ {
+ case 0x0:
+ return(ESUCCESS);
+ case 0x1:
+ if(!silent)
+ {
+ printf("sd%d: soft error(corrected) ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(ESUCCESS);
+ case 0x2:
+ if(!silent)printf("sd%d: not ready\n ",
+ unit);
+ return(ENODEV);
+ case 0x3:
+ if(!silent)
+ {
+ printf("sd%d: medium error ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0x4:
+ if(!silent)printf("sd%d: non-media hardware failure\n ",
+ unit);
+ return(EIO);
+ case 0x5:
+ if(!silent)printf("sd%d: illegal request\n ",
+ unit);
+ return(EINVAL);
+ case 0x6:
+ /***********************************************\
+ * If we are not open, then this is not an error *
+ * as we don't have state yet. Either way, make *
+ * sure that we don't have any residual state *
+ \***********************************************/
+ if(!silent)printf("sd%d: Unit attention.\n ", unit);
+ sd_data[unit].flags &= ~(SDVALID | SDHAVELABEL);
+ if (sd_data[unit].openparts)
+ {
+ return(EIO);
+ }
+ return(ESUCCESS); /* not an error if nothing's open */
+ case 0x7:
+ if(!silent)
+ {
+ printf("sd%d: attempted protection violation ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EACCES);
+ case 0x8:
+ if(!silent)
+ {
+ printf("sd%d: block wrong state (worm)\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0x9:
+ if(!silent)printf("sd%d: vendor unique\n",
+ unit);
+ return(EIO);
+ case 0xa:
+ if(!silent)printf("sd%d: copy aborted\n ",
+ unit);
+ return(EIO);
+ case 0xb:
+ if(!silent)printf("sd%d: command aborted\n ",
+ unit);
+ return(EIO);
+ case 0xc:
+ if(!silent)
+ {
+ printf("sd%d: search returned\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(ESUCCESS);
+ case 0xd:
+ if(!silent)printf("sd%d: volume overflow\n ",
+ unit);
+ return(ENOSPC);
+ case 0xe:
+ if(!silent)
+ {
+ printf("sd%d: verify miscompare\n ",
+ unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ printf("\n");
+ }
+ return(EIO);
+ case 0xf:
+ if(!silent)printf("sd%d: unknown error key\n ",
+ unit);
+ return(EIO);
+ }
+ break;
+ }
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ {
+ if(!silent)printf("sd%d: error class %d code %d\n",
+ unit,
+ sense->error_class,
+ sense->error_code);
+ if(sense->valid)
+ if(!silent)printf("block no. %d (decimal)\n",
+ (sense->ext.unextended.blockhi <<16)
+ + (sense->ext.unextended.blockmed <<8)
+ + (sense->ext.unextended.blocklow ));
+ }
+ return(EIO);
+ }
+}
+
+
+
+
+int
+sdsize(dev_t dev)
+{
+ int unit = UNIT(dev), part = PARTITION(dev), val;
+ struct sd_data *sd;
+
+ if (unit >= NSD)
+ return(-1);
+
+ sd = &sd_data[unit];
+ if((sd->flags & SDINIT) == 0) return(-1);
+ if (sd == 0 || (sd->flags & SDHAVELABEL) == 0)
+ val = sdopen (MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
+ if ( val != 0 || sd->flags & SDWRITEPROT)
+ return (-1);
+
+ return((int)sd->disklabel.d_partitions[part].p_size);
+}
+
+sddump()
+{
+ printf("sddump() -- not implemented\n");
+ return(-1);
+}
+
+
+
+
+
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
new file mode 100644
index 0000000..e896902
--- /dev/null
+++ b/sys/scsi/st.c
@@ -0,0 +1,1774 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+
+/*
+ * To do:
+ * work out some better way of guessing what a good timeout is going
+ * to be depending on whether we expect to retension or not.
+ *
+ */
+
+#include <sys/types.h>
+#include <st.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/mtio.h>
+
+#if defined(OSF)
+#define SECSIZE 512
+#endif /* defined(OSF) */
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_tape.h>
+#include <scsi/scsiconf.h>
+
+
+long int ststrats,stqueues;
+
+
+#define PAGESIZ 4096
+#define STQSIZE 4
+#define ST_RETRIES 4
+
+
+#define MODE(z) ( (minor(z) & 0x03) )
+#define DSTY(z) ( ((minor(z) >> 2) & 0x03) )
+#define UNIT(z) ( (minor(z) >> 4) )
+
+#define DSTY_QIC120 3
+#define DSTY_QIC150 2
+#define DSTY_QIC525 1
+
+#define QIC120 0x0f
+#define QIC150 0x10
+#define QIC525 0x11
+
+
+
+
+#ifndef __386BSD__
+struct buf stbuf[NST][STQSIZE]; /* buffer for raw io (one per device) */
+struct buf *stbuf_free[NST]; /* queue of free buffers for raw io */
+#endif __386BSD__
+struct buf st_buf_queue[NST];
+int ststrategy();
+void stminphys();
+struct scsi_xfer st_scsi_xfer[NST];
+int st_xfer_block_wait[NST];
+
+#if defined(OSF)
+caddr_t st_window[NST];
+#endif /* defined(OSF) */
+#ifndef MACH
+#define ESUCCESS 0
+#endif MACH
+
+int st_info_valid[NST]; /* the info about the device is valid */
+int st_initialized[NST] ;
+int st_debug = 0;
+
+int stattach();
+int st_done();
+struct st_data
+{
+ int flags;
+ struct scsi_switch *sc_sw; /* address of scsi low level switch */
+ int ctlr; /* so they know which one we want */
+ int targ; /* our scsi target ID */
+ int lu; /* out scsi lu */
+ int blkmin; /* min blk size */
+ int blkmax; /* max blk size */
+ int numblks; /* nominal blocks capacity */
+ int blksiz; /* nominal block size */
+}st_data[NST];
+#define ST_OPEN 0x01
+#define ST_NOREWIND 0x02
+#define ST_WRITTEN 0x04
+#define ST_FIXEDBLOCKS 0x10
+#define ST_AT_FILEMARK 0x20
+#define ST_AT_EOM 0x40
+
+#define ST_PER_ACTION (ST_AT_FILEMARK | ST_AT_EOM)
+#define ST_PER_OPEN (ST_OPEN | ST_NOREWIND | ST_WRITTEN | ST_PER_ACTION)
+#define ST_PER_MEDIA ST_FIXEDBLOCKS
+
+static int next_st_unit = 0;
+/***********************************************************************\
+* The routine called by the low level scsi routine when it discovers *
+* A device suitable for this driver *
+\***********************************************************************/
+
+int stattach(ctlr,targ,lu,scsi_switch)
+struct scsi_switch *scsi_switch;
+{
+ int unit,i;
+ unsigned char *tbl;
+ struct st_data *st;
+
+ if(scsi_debug & PRINTROUTINES) printf("stattach: ");
+ /*******************************************************\
+ * Check we have the resources for another drive *
+ \*******************************************************/
+ unit = next_st_unit++;
+ if( unit >= NST)
+ {
+ printf("Too many scsi tapes..(%d > %d) reconfigure kernel",(unit + 1),NST);
+ return(0);
+ }
+ st = st_data + unit;
+ /*******************************************************\
+ * Store information needed to contact our base driver *
+ \*******************************************************/
+ st->sc_sw = scsi_switch;
+ st->ctlr = ctlr;
+ st->targ = targ;
+ st->lu = lu;
+
+ /*******************************************************\
+ * Use the subdriver to request information regarding *
+ * the drive. We cannot use interrupts yet, so the *
+ * request must specify this. *
+ \*******************************************************/
+ if((st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)))
+ {
+ printf(" st%d: scsi tape drive, %d blocks of %d bytes\n",
+ unit, st->numblks, st->blksiz);
+ }
+ else
+ {
+ printf(" st%d: scsi tape drive :- offline\n", unit);
+ }
+ /*******************************************************\
+ * Set up the bufs for this device *
+ \*******************************************************/
+#ifndef __386BSD__
+ stbuf_free[unit] = (struct buf *)0;
+ for (i = 1; i < STQSIZE; i++)
+ {
+ stbuf[unit][i].b_forw = stbuf_free[unit];
+ stbuf_free[unit]=&stbuf[unit][i];
+ }
+#endif __386BSD__
+ st_buf_queue[unit].b_active = 0;
+ st_buf_queue[unit].b_actf = st_buf_queue[unit].b_actl = 0;
+ st_initialized[unit] = 1;
+
+#if defined(OSF)
+ st_window[unit] = (caddr_t)alloc_kva(SECSIZE*256+PAGESIZ);
+#endif /* defined(OSF) */
+
+ return;
+
+}
+
+
+
+/*******************************************************\
+* open the device. *
+\*******************************************************/
+stopen(dev)
+{
+ int errcode = 0;
+ int unit,mode,dsty;
+ int dsty_code;
+ struct st_data *st;
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ dsty = DSTY(dev);
+ st = st_data + unit;
+
+ /*******************************************************\
+ * Check the unit is legal *
+ \*******************************************************/
+ if ( unit >= NST )
+ {
+ errcode = ENXIO;
+ return(errcode);
+ }
+ /*******************************************************\
+ * Only allow one at a time *
+ \*******************************************************/
+ if(st->flags & ST_OPEN)
+ {
+ errcode = ENXIO;
+ goto bad;
+ }
+ /*******************************************************\
+ * Set up the mode flags according to the minor number *
+ * ensure all open flags are in a known state *
+ \*******************************************************/
+ st->flags &= ~ST_PER_OPEN;
+ switch(mode)
+ {
+ case 2:
+ case 0:
+ st->flags &= ~ST_NOREWIND;
+ break;
+ case 3:
+ case 1:
+ st->flags |= ST_NOREWIND;
+ break;
+ default:
+ printf("st%d: Bad mode (minor number)%d\n",unit,mode);
+ return(EINVAL);
+ }
+ /*******************************************************\
+ * Check density code: 0 is drive default *
+ \*******************************************************/
+ switch(dsty)
+ {
+ case 0: dsty_code = 0; break;
+ case DSTY_QIC120: dsty_code = QIC120; break;
+ case DSTY_QIC150: dsty_code = QIC150; break;
+ case DSTY_QIC525: dsty_code = QIC525; break;
+ default:
+ printf("st%d: Bad density (minor number)%d\n",unit,dsty);
+ return(EINVAL);
+ }
+ if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
+ printf("stopen: dev=0x%x (unit %d (of %d))\n"
+ , dev, unit, NST);
+ /*******************************************************\
+ * Make sure the device has been initialised *
+ \*******************************************************/
+
+ if (!st_initialized[unit])
+ return(ENXIO);
+ /*******************************************************\
+ * Check that it is still responding and ok. *
+ \*******************************************************/
+
+ if(scsi_debug & TRACEOPENS)
+ printf("device is ");
+ if (!(st_req_sense(unit, 0)))
+ {
+ errcode = ENXIO;
+ if(scsi_debug & TRACEOPENS)
+ printf("not responding\n");
+ goto bad;
+ }
+ if(scsi_debug & TRACEOPENS)
+ printf("ok\n");
+
+ if(!(st_test_ready(unit,0)))
+ {
+ printf("st%d not ready\n",unit);
+ return(EIO);
+ }
+
+ if(!st_info_valid[unit]) /* is media new? */
+ if(!st_load(unit,LD_LOAD,0))
+ {
+ return(EIO);
+ }
+
+ if(!st_rd_blk_lim(unit,0))
+ {
+ return(EIO);
+ }
+
+ if(!st_mode_sense(unit,0))
+ {
+ return(EIO);
+ }
+
+ if(!st_mode_select(unit,0,dsty_code))
+ {
+ return(EIO);
+ }
+
+ st_info_valid[unit] = TRUE;
+
+ st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */
+
+ /*******************************************************\
+ * Load the physical device parameters *
+ \*******************************************************/
+ if(scsi_debug & TRACEOPENS)
+ printf("Params loaded ");
+
+
+ st->flags |= ST_OPEN;
+
+bad:
+ return(errcode);
+}
+
+/*******************************************************\
+* close the device.. only called if we are the LAST *
+* occurence of an open device *
+\*******************************************************/
+stclose(dev)
+{
+ unsigned char unit,mode;
+ struct st_data *st;
+
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ st = st_data + unit;
+
+ if(scsi_debug & TRACEOPENS)
+ printf("Closing device");
+ if(st->flags & ST_WRITTEN)
+ {
+ st_write_filemarks(unit,1,0);
+ }
+ st->flags &= ~ST_WRITTEN;
+ switch(mode)
+ {
+ case 0:
+ st_rewind(unit,FALSE,SCSI_SILENT);
+ st_prevent(unit,PR_ALLOW,SCSI_SILENT);
+ break;
+ case 1:
+ st_prevent(unit,PR_ALLOW,SCSI_SILENT);
+ break;
+ case 2:
+ st_rewind(unit,FALSE,SCSI_SILENT);
+ st_prevent(unit,PR_ALLOW,SCSI_SILENT);
+ st_load(unit,LD_UNLOAD,SCSI_SILENT);
+ break;
+ case 3:
+ st_prevent(unit,PR_ALLOW,SCSI_SILENT);
+ st_load(unit,LD_UNLOAD,SCSI_SILENT);
+ break;
+ default:
+ printf("st%d:close: Bad mode (minor number)%d how's it open?\n"
+ ,unit,mode);
+ return(EINVAL);
+ }
+ st->flags &= ~ST_PER_OPEN;
+ return(0);
+}
+
+#ifndef __386BSD__
+/*******************************************************\
+* Get ownership of this unit's buf *
+* If need be, sleep on it, until it comes free *
+\*******************************************************/
+struct buf *
+st_get_buf(unit) {
+ struct buf *rc;
+
+ while (!(rc = stbuf_free[unit]))
+ sleep((caddr_t)&stbuf_free[unit], PRIBIO+1);
+ stbuf_free[unit] = stbuf_free[unit]->b_forw;
+ rc->b_error = 0;
+ rc->b_resid = 0;
+ rc->b_flags = 0;
+ return(rc);
+}
+
+/*******************************************************\
+* Free this unit's buf, wake processes waiting for it *
+\*******************************************************/
+st_free_buf(unit,bp)
+struct buf *bp;
+{
+ if (!stbuf_free[unit])
+ wakeup((caddr_t)&stbuf_free[unit]);
+ bp->b_forw = stbuf_free[unit];
+ stbuf_free[unit] = bp;
+}
+
+
+/*******************************************************\
+* Get the buf for this unit and use physio to do it *
+\*******************************************************/
+stread(dev,uio)
+register short dev;
+struct uio *uio;
+{
+ int unit = UNIT(dev);
+ struct buf *bp = st_get_buf(unit);
+ int rc;
+ rc = physio(ststrategy, bp, dev, B_READ, stminphys, uio);
+ st_free_buf(unit,bp);
+ return(rc);
+}
+
+/*******************************************************\
+* Get the buf for this unit and use physio to do it *
+\*******************************************************/
+stwrite(dev,uio)
+dev_t dev;
+struct uio *uio;
+{
+ int unit = UNIT(dev);
+ struct buf *bp = st_get_buf(unit);
+ int rc;
+
+ rc = physio(ststrategy, bp, dev, B_WRITE, stminphys, uio);
+ st_free_buf(unit,bp);
+ return(rc);
+}
+
+
+#endif __386BSD__
+/*******************************************************\
+* trim the size of the transfer if needed, *
+* called by physio *
+* basically the smaller of our min and the scsi driver's*
+* minphys *
+\*******************************************************/
+void stminphys(bp)
+struct buf *bp;
+{
+ (*(st_data[UNIT(bp->b_dev)].sc_sw->scsi_minphys))(bp);
+}
+
+/*******************************************************\
+* Actually translate the requested transfer into *
+* one the physical driver can understand *
+* The transfer is described by a buf and will include *
+* only one physical transfer. *
+\*******************************************************/
+
+int ststrategy(bp)
+struct buf *bp;
+{
+ struct buf *dp;
+ unsigned char unit;
+ unsigned int opri;
+
+ ststrats++;
+ unit = UNIT((bp->b_dev));
+ if(scsi_debug & PRINTROUTINES) printf("\nststrategy ");
+ if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n",
+ unit,bp->b_bcount,bp->b_blkno);
+ /*******************************************************\
+ * If it's a null transfer, return immediatly *
+ \*******************************************************/
+ if (bp->b_bcount == 0) {
+ goto done;
+ }
+
+ /*******************************************************\
+ * Odd sized request on fixed drives are verboten *
+ \*******************************************************/
+ if((st_data[unit].flags & ST_FIXEDBLOCKS)
+ && bp->b_bcount % st_data[unit].blkmin)
+ {
+ printf("st%d: bad request, must be multiple of %d\n",
+ unit, st_data[unit].blkmin);
+ bp->b_error = EIO;
+ goto bad;
+ }
+
+#ifdef __386BSD__
+ stminphys(bp);
+#endif __386BSD__
+ opri = splbio();
+ dp = &st_buf_queue[unit];
+
+ /*******************************************************\
+ * Place it in the queue of disk activities for this tape*
+ * at the end *
+ \*******************************************************/
+ while ( dp->b_actf)
+ {
+ dp = dp->b_actf;
+ }
+ dp->b_actf = bp;
+ bp->b_actf = NULL;
+
+ /*******************************************************\
+ * Tell the device to get going on the transfer if it's *
+ * not doing anything, otherwise just wait for completion*
+ \*******************************************************/
+ ststart(unit);
+
+ splx(opri);
+ return;
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ /*******************************************************\
+ * Correctly set the buf to indicate a completed xfer *
+ \*******************************************************/
+ iodone(bp);
+ return;
+}
+
+
+/***************************************************************\
+* ststart looks to see if there is a buf waiting for the device *
+* and that the device is not already busy. If both are true, *
+* It deques the buf and creates a scsi command to perform the *
+* transfer in the buf. The transfer request will call st_done *
+* on completion, which will in turn call this routine again *
+* so that the next queued transfer is performed. *
+* The bufs are queued by the strategy routine (ststrategy) *
+* *
+* This routine is also called after other non-queued requests *
+* have been made of the scsi driver, to ensure that the queue *
+* continues to be drained. *
+\***************************************************************/
+/* ststart() is called at splbio */
+ststart(unit)
+{
+ int drivecount;
+ register struct buf *bp = 0;
+ register struct buf *dp;
+ struct scsi_xfer *xs;
+ struct scsi_rw_tape cmd;
+ int blkno, nblk;
+ struct st_data *st;
+
+
+ st = st_data + unit;
+
+ if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit);
+ /*******************************************************\
+ * See if there is a buf to do and we are not already *
+ * doing one *
+ \*******************************************************/
+ xs=&st_scsi_xfer[unit];
+ if(xs->flags & INUSE)
+ {
+ return; /* unit already underway */
+ }
+trynext:
+ if(st_xfer_block_wait[unit]) /* a special awaits, let it proceed first */
+ {
+ wakeup(&st_xfer_block_wait[unit]);
+ return;
+ }
+
+ dp = &st_buf_queue[unit];
+ if ((bp = dp->b_actf) != NULL)
+ {
+ dp->b_actf = bp->b_actf;
+ }
+ else /* no work to do */
+ {
+ return;
+ }
+ xs->flags = INUSE; /* Now ours */
+
+
+ /*******************************************************\
+ * We have a buf, now we should move the data into *
+ * a scsi_xfer definition and try start it *
+ \*******************************************************/
+
+ /*******************************************************\
+ * If we are at a filemark but have not reported it yet *
+ * then we should report it now *
+ \*******************************************************/
+ if(st->flags & ST_AT_FILEMARK)
+ {
+ bp->b_error = 0;
+ bp->b_flags |= B_ERROR; /* EOF*/
+ st->flags &= ~ST_AT_FILEMARK;
+ biodone(bp);
+ xs->flags = 0; /* won't need it now */
+ goto trynext;
+ }
+ /*******************************************************\
+ * If we are at EOM but have not reported it yet *
+ * then we should report it now *
+ \*******************************************************/
+ if(st->flags & ST_AT_EOM)
+ {
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ st->flags &= ~ST_AT_EOM;
+ biodone(bp);
+ xs->flags = 0; /* won't need it now */
+ goto trynext;
+ }
+ /*******************************************************\
+ * Fill out the scsi command *
+ \*******************************************************/
+ bzero(&cmd, sizeof(cmd));
+ if((bp->b_flags & B_READ) == B_WRITE)
+ {
+ st->flags |= ST_WRITTEN;
+ xs->flags |= SCSI_DATA_OUT;
+ }
+ else
+ {
+ xs->flags |= SCSI_DATA_IN;
+ }
+ cmd.op_code = (bp->b_flags & B_READ)
+ ? READ_COMMAND_TAPE
+ : WRITE_COMMAND_TAPE;
+
+ /*******************************************************\
+ * Handle "fixed-block-mode" tape drives by using the *
+ * block count instead of the length. *
+ \*******************************************************/
+ if(st->flags & ST_FIXEDBLOCKS)
+ {
+ cmd.fixed = 1;
+ lto3b(bp->b_bcount/st->blkmin,cmd.len);
+ }
+ else
+ {
+ lto3b(bp->b_bcount,cmd.len);
+ }
+
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ * Note: we cannot sleep as we may be an interrupt *
+ \*******************************************************/
+ xs->flags |= SCSI_NOSLEEP;
+ xs->adapter = st->ctlr;
+ xs->targ = st->targ;
+ xs->lu = st->lu;
+ xs->retries = 1; /* can't retry on tape*/
+ xs->timeout = 100000; /* allow 100 secs for retension */
+ xs->cmd = (struct scsi_generic *)&cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->data = (u_char *)bp->b_un.b_addr;
+ xs->datalen = bp->b_bcount;
+ xs->resid = bp->b_bcount;
+ xs->when_done = st_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+ xs->error = XS_NOERROR;
+ xs->bp = bp;
+ /*******************************************************\
+ * Pass all this info to the scsi driver. *
+ \*******************************************************/
+
+
+#if defined(OSF)||defined(FIX_ME)
+ if (bp->b_flags & B_PHYS) {
+ xs->data = (u_char*)map_pva_kva(bp->b_proc, bp->b_un.b_addr,
+ bp->b_bcount, st_window[unit],
+ (bp->b_flags&B_READ)?B_WRITE:B_READ);
+ } else {
+ xs->data = (u_char*)bp->b_un.b_addr;
+ }
+#endif /* defined(OSF) */
+
+ if ( (*(st->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
+ {
+ printf("st%d: oops not queued",unit);
+ xs->error = XS_DRIVER_STUFFUP;
+ st_done(unit,xs);
+ }
+ stqueues++;
+}
+
+/*******************************************************\
+* This routine is called by the scsi interrupt when *
+* the transfer is complete.
+\*******************************************************/
+int st_done(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct buf *bp;
+ int retval;
+
+ if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit);
+ if (! (xs->flags & INUSE))
+ panic("scsi_xfer not in use!");
+ if(bp = xs->bp)
+ {
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ bp->b_flags &= ~B_ERROR;
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ break;
+ case XS_SENSE:
+ retval = (st_interpret_sense(unit,xs));
+ if(retval)
+ {
+ /***************************************\
+ * We have a real error, the bit should *
+ * be set to indicate this. The return *
+ * value will contain the unix error code*
+ * that the error interpretation routine *
+ * thought was suitable, so pass this *
+ * value back in the buf structure. *
+ * Furthermore we return information *
+ * saying that no data was transferred *
+ \***************************************/
+ bp->b_flags |= B_ERROR;
+ bp->b_error = retval;
+ bp->b_resid = bp->b_bcount;
+ st_data[unit].flags
+ &= ~(ST_AT_FILEMARK|ST_AT_EOM);
+ }
+ else
+ {
+ /***********************************************\
+ * The error interpretation code has declared *
+ * that it wasn't a real error, or at least that *
+ * we should be ignoring it if it was. *
+ \***********************************************/
+ if(xs->resid && ( xs->resid != xs->datalen ))
+ {
+ /***************************************\
+ * Here we have the tricky part.. *
+ * We successfully read less data than *
+ * we requested. (but not 0) *
+ *------for variable blocksize tapes:----*
+ * UNDER 386BSD: *
+ * We should legitimatly have the error *
+ * bit set, with the error value set to *
+ * zero.. This is to indicate to the *
+ * physio code that while we didn't get *
+ * as much information as was requested, *
+ * we did reach the end of the record *
+ * and so physio should not call us *
+ * again for more data... we have it all *
+ * SO SET THE ERROR BIT! *
+ * *
+ * UNDER MACH:(CMU) *
+ * To indicate the same as above, we *
+ * need only have a non 0 resid that is *
+ * less than the b_bcount, but the *
+ * ERROR BIT MUST BE CLEAR! (sigh) *
+ * *
+ * UNDER OSF1: *
+ * To indicate the same as above, we *
+ * need to have a non 0 resid that is *
+ * less than the b_bcount, but the *
+ * ERROR BIT MUST BE SET! (gasp)(sigh) *
+ * *
+ *-------for fixed blocksize device------*
+ * We could have read some successful *
+ * records before hitting *
+ * the EOF or EOT. These must be passed *
+ * to the user, before we report the *
+ * EOx. Only if there is no data for the *
+ * user do we report it now. (via an EIO *
+ * for EOM and resid == count for EOF). *
+ * We will report the EOx NEXT time.. *
+ \***************************************/
+#ifdef MACH /*osf and cmu varieties */
+#ifdef OSF
+ bp->b_flags |= B_ERROR;
+#else OSF
+ bp->b_flags &= ~B_ERROR;
+#endif OSF
+#endif MACH
+#ifdef __386BSD__
+ bp->b_flags |= B_ERROR;
+#endif __386BSD__
+ bp->b_error = 0;
+ bp->b_resid = xs->resid;
+ if((st_data[unit].flags & ST_FIXEDBLOCKS))
+ {
+ bp->b_resid *= st_data[unit].blkmin;
+ if( (st_data[unit].flags & ST_AT_EOM)
+ && (bp->b_resid == bp->b_bcount))
+ {
+ bp->b_error = EIO;
+ st_data[unit].flags
+ &= ~ST_AT_EOM;
+ }
+ }
+ xs->error = XS_NOERROR;
+ break;
+ }
+ else
+ {
+ /***************************************\
+ * We have come out of the error handler *
+ * with no error code.. we have also *
+ * not had an ili (would have gone to *
+ * the previous clause). Now we need to *
+ * distiguish between succesful read of *
+ * no data (EOF or EOM) and successfull *
+ * read of all requested data. *
+ * At least all o/s agree that: *
+ * 0 bytes read with no error is EOF *
+ * 0 bytes read with an EIO is EOM *
+ \***************************************/
+
+ bp->b_resid = bp->b_bcount;
+ if(st_data[unit].flags & ST_AT_FILEMARK)
+ {
+ st_data[unit].flags &= ~ST_AT_FILEMARK;
+ bp->b_flags &= ~B_ERROR;
+ bp->b_error = 0;
+ break;
+ }
+ if(st_data[unit].flags & ST_AT_EOM)
+ {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ st_data[unit].flags &= ~ST_AT_EOM;
+ break;
+ }
+ printf("st%d:error ignored\n" ,unit);
+ }
+ }
+ break;
+
+ case XS_TIMEOUT:
+ printf("st%d timeout\n",unit);
+ break;
+
+ case XS_BUSY: /* should retry */ /* how? */
+ /************************************************/
+ /* SHOULD put buf back at head of queue */
+ /* and decrement retry count in (*xs) */
+ /* HOWEVER, this should work as a kludge */
+ /************************************************/
+ if(xs->retries--)
+ {
+ xs->flags &= ~ITSDONE;
+ xs->error = XS_NOERROR;
+ if ( (*(st_data[unit].sc_sw->scsi_cmd))(xs)
+ == SUCCESSFULLY_QUEUED)
+ { /* don't wake the job, ok? */
+ return;
+ }
+ printf("device busy");
+ xs->flags |= ITSDONE;
+ }
+
+ case XS_DRIVER_STUFFUP:
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ break;
+ default:
+ printf("st%d: unknown error category from scsi driver\n"
+ ,unit);
+ }
+ biodone(bp);
+ xs->flags = 0; /* no longer in use */
+ ststart(unit); /* If there's another waiting.. do it */
+ }
+ else
+ {
+ wakeup(xs);
+ }
+}
+/*******************************************************\
+* Perform special action on behalf of the user *
+* Knows about the internals of this device *
+\*******************************************************/
+stioctl(dev, cmd, arg, mode)
+dev_t dev;
+int cmd;
+caddr_t arg;
+{
+ register i,j;
+ unsigned int opri;
+ int errcode = 0;
+ unsigned char unit;
+ int number,flags,ret;
+
+ /*******************************************************\
+ * Find the device that the user is talking about *
+ \*******************************************************/
+ flags = 0; /* give error messages, act on errors etc. */
+ unit = UNIT(dev);
+
+ switch(cmd)
+ {
+
+ case MTIOCGET:
+ {
+ struct mtget *g = (struct mtget *) arg;
+
+ bzero(g, sizeof(struct mtget));
+ g->mt_type = 0x7; /* Ultrix compat */ /*?*/
+ ret=TRUE;
+ break;
+ }
+
+
+ case MTIOCTOP:
+ {
+ struct mtop *mt = (struct mtop *) arg;
+
+ if (st_debug)
+ printf("[sctape_sstatus: %x %x]\n",
+ mt->mt_op, mt->mt_count);
+
+
+
+ /* compat: in U*x it is a short */
+ number = mt->mt_count;
+ switch ((short)(mt->mt_op))
+ {
+ case MTWEOF: /* write an end-of-file record */
+ ret = st_write_filemarks(unit,number,flags);
+ st_data[unit].flags &= ~ST_WRITTEN;
+ break;
+ case MTFSF: /* forward space file */
+ ret = st_space(unit,number,SP_FILEMARKS,flags);
+ break;
+ case MTBSF: /* backward space file */
+ ret = st_space(unit,-number,SP_FILEMARKS,flags);
+ break;
+ case MTFSR: /* forward space record */
+ ret = st_space(unit,number,SP_BLKS,flags);
+ break;
+ case MTBSR: /* backward space record */
+ ret = st_space(unit,-number,SP_BLKS,flags);
+ break;
+ case MTREW: /* rewind */
+ ret = st_rewind(unit,FALSE,flags);
+ break;
+ case MTOFFL: /* rewind and put the drive offline */
+ if((ret = st_rewind(unit,FALSE,flags)))
+ {
+ st_prevent(unit,PR_ALLOW,0);
+ ret = st_load(unit,LD_UNLOAD,flags);
+ }
+ else
+ {
+ printf("rewind failed, unit still loaded\n");
+ }
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ ret = TRUE;;
+ break;
+ default:
+ return EINVAL;
+ }
+ break;
+ }
+ case MTIOCIEOT:
+ case MTIOCEEOT:
+ ret=TRUE;
+ break;
+ }
+
+ return(ret?ESUCCESS:EIO);
+}
+
+
+/*******************************************************\
+* Check with the device that it is ok, (via scsi driver)*
+\*******************************************************/
+st_req_sense(unit, flags)
+int flags;
+{
+ struct scsi_sense_data sense;
+ struct scsi_sense scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = REQUEST_SENSE;
+ scsi_cmd.length = sizeof(sense);
+
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &sense,
+ sizeof(sense),
+ 100000,
+ flags | SCSI_DATA_IN) != 0)
+ {
+ return(FALSE);
+ }
+ else
+ return(TRUE);
+}
+
+/*******************************************************\
+* Get scsi driver to send a "are you ready" command *
+\*******************************************************/
+st_test_ready(unit,flags)
+int unit,flags;
+{
+ struct scsi_test_unit_ready scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = TEST_UNIT_READY;
+
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 100000,
+ flags) != 0) {
+ return(FALSE);
+ } else
+ return(TRUE);
+}
+
+
+#ifdef __STDC__
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+#else
+#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
+#endif
+
+/*******************************************************\
+* Ask the drive what it's min and max blk sizes are. *
+\*******************************************************/
+st_rd_blk_lim(unit, flags)
+int unit,flags;
+{
+ struct scsi_blk_limits scsi_cmd;
+ struct scsi_blk_limits_data scsi_blkl;
+ struct st_data *st = st_data + unit;
+ /*******************************************************\
+ * First check if we have it all loaded *
+ \*******************************************************/
+ if (st_info_valid[unit]) goto done;
+
+ /*******************************************************\
+ * do a 'Read Block Limits' *
+ \*******************************************************/
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_BLK_LIMITS;
+
+ /*******************************************************\
+ * do the command, update the global values *
+ \*******************************************************/
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &scsi_blkl,
+ sizeof(scsi_blkl),
+ 5000,
+ flags | SCSI_DATA_IN) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not get blk limits for unit %d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ if (st_debug)
+ {
+ printf(" (%d <= blksiz <= %d\n) ",
+ b2tol(scsi_blkl.min_length),
+ _3btol(&scsi_blkl.max_length_2));
+ }
+ st->blkmin = b2tol(scsi_blkl.min_length);
+ st->blkmax = _3btol(&scsi_blkl.max_length_2);
+
+done:
+ if(st->blkmin && (st->blkmin == st->blkmax))
+ {
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* Get the scsi driver to send a full inquiry to the *
+* device and use the results to fill out the global *
+* parameter structure. *
+\*******************************************************/
+st_mode_sense(unit, flags)
+int unit,flags;
+{
+ struct scsi_mode_sense scsi_cmd;
+ struct
+ {
+ struct scsi_mode_header_tape header;
+ struct blk_desc blk_desc;
+ }scsi_sense;
+ struct st_data *st = st_data + unit;
+
+ /*******************************************************\
+ * First check if we have it all loaded *
+ \*******************************************************/
+ if (st_info_valid[unit]) return(TRUE);
+ /*******************************************************\
+ * First do a mode sense *
+ \*******************************************************/
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.length = sizeof(scsi_sense);
+ /*******************************************************\
+ * do the command, but we don't need the results *
+ * just print them for our interest's sake *
+ \*******************************************************/
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &scsi_sense,
+ sizeof(scsi_sense),
+ 5000,
+ flags | SCSI_DATA_IN) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not mode sense for unit %d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ if (st_debug)
+ {
+ printf("unit %d: %d blocks of %d bytes, write %s, %sbuffered",
+ unit,
+ _3btol(&scsi_sense.blk_desc.nblocks),
+ _3btol(&scsi_sense.blk_desc.blklen),
+ (scsi_sense.header.write_protected ?
+ "protected" : "enabled"),
+ (scsi_sense.header.buf_mode ?
+ "" : "un")
+ );
+ }
+ st->numblks = _3btol(&scsi_sense.blk_desc.nblocks);
+ st->blksiz = _3btol(&scsi_sense.blk_desc.blklen);
+ return(TRUE);
+}
+
+/*******************************************************\
+* Get the scsi driver to send a full inquiry to the *
+* device and use the results to fill out the global *
+* parameter structure. *
+\*******************************************************/
+st_mode_select(unit, flags, dsty_code)
+int unit,flags,dsty_code;
+{
+ struct scsi_mode_select scsi_cmd;
+ struct
+ {
+ struct scsi_mode_header_tape header;
+ struct blk_desc blk_desc;
+ }dat;
+ struct st_data *st = st_data + unit;
+
+ /*******************************************************\
+ * Set up for a mode select *
+ \*******************************************************/
+ bzero(&dat, sizeof(dat));
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SELECT;
+ scsi_cmd.length = sizeof(dat);
+ dat.header.blk_desc_len = sizeof(struct blk_desc);
+ dat.header.buf_mode = 1;
+ dat.blk_desc.density = dsty_code;
+ if(st->flags & ST_FIXEDBLOCKS)
+ {
+ lto3b( st->blkmin , dat.blk_desc.blklen);
+ }
+/* lto3b( st->numblks , dat.blk_desc.nblocks); use defaults!!!!
+ lto3b( st->blksiz , dat.blk_desc.blklen);
+*/
+ /*******************************************************\
+ * do the command *
+ \*******************************************************/
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ &dat,
+ sizeof(dat),
+ 5000,
+ flags | SCSI_DATA_OUT) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not mode select for unit %d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+
+/*******************************************************\
+* skip N blocks/filemarks/seq filemarks/eom *
+\*******************************************************/
+st_space(unit,number,what,flags)
+int unit,number,what,flags;
+{
+ struct scsi_space scsi_cmd;
+
+ /* if we are at a filemark now, we soon won't be*/
+ st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM);
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = SPACE;
+ scsi_cmd.code = what;
+ lto3b(number,scsi_cmd.number);
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 600000, /* 10 mins enough? */
+ flags) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not space st%d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* write N filemarks *
+\*******************************************************/
+st_write_filemarks(unit,number,flags)
+int unit,number,flags;
+{
+ struct scsi_write_filemarks scsi_cmd;
+
+ st_data[unit].flags &= ~(ST_AT_FILEMARK);
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = WRITE_FILEMARKS;
+ lto3b(number,scsi_cmd.number);
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 100000, /* 10 secs.. (may need to repos head )*/
+ flags) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not write_filemarks st%d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* load /unload (with retension if true) *
+\*******************************************************/
+st_load(unit,type,flags)
+int unit,type,flags;
+{
+ struct scsi_load scsi_cmd;
+
+ st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM);
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = LOAD_UNLOAD;
+ scsi_cmd.load=type;
+ if (type == LD_LOAD)
+ {
+ /*scsi_cmd.reten=TRUE;*/
+ scsi_cmd.reten=FALSE;
+ }
+ else
+ {
+ scsi_cmd.reten=FALSE;
+ }
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 30000, /* 30 secs */
+ flags) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("cannot load/unload st%d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* Prevent or allow the user to remove the tape *
+\*******************************************************/
+st_prevent(unit,type,flags)
+int unit,type,flags;
+{
+ struct scsi_prevent scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PREVENT_ALLOW;
+ scsi_cmd.prevent=type;
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 5000,
+ flags) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("cannot prevent/allow on st%d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* Rewind the device *
+\*******************************************************/
+st_rewind(unit,immed,flags)
+int unit,immed,flags;
+{
+ struct scsi_rewind scsi_cmd;
+
+ st_data[unit].flags &= ~(ST_AT_FILEMARK | ST_AT_EOM);
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = REWIND;
+ scsi_cmd.immed=immed;
+ if (st_scsi_cmd(unit,
+ &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ immed?5000:300000, /* 5 sec or 5 min */
+ flags) != 0)
+ {
+ if(!(flags & SCSI_SILENT))
+ printf("could not rewind st%d\n", unit);
+ st_info_valid[unit] = FALSE;
+ return(FALSE);
+ }
+ return(TRUE);
+}
+/*******************************************************\
+* ask the scsi driver to perform a command for us. *
+* Call it through the switch table, and tell it which *
+* sub-unit we want, and what target and lu we wish to *
+* talk to. Also tell it where to find the command *
+* how long int is. *
+* Also tell it where to read/write the data, and how *
+* long the data is supposed to be *
+\*******************************************************/
+int st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
+
+int unit,flags;
+struct scsi_generic *scsi_cmd;
+int cmdlen;
+int timeout;
+u_char *data_addr;
+int datalen;
+{
+ struct scsi_xfer *xs;
+ int retval;
+ int s;
+ struct st_data *st = st_data + unit;
+
+ if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit);
+ if(st->sc_sw) /* If we have a scsi driver */
+ {
+
+ xs = &(st_scsi_xfer[unit]);
+ if(!(flags & SCSI_NOMASK))
+ s = splbio();
+ st_xfer_block_wait[unit]++; /* there is someone waiting */
+ while (xs->flags & INUSE)
+ {
+ sleep(&st_xfer_block_wait[unit],PRIBIO+1);
+ }
+ st_xfer_block_wait[unit]--;
+ xs->flags = INUSE;
+ if(!(flags & SCSI_NOMASK))
+ splx(s);
+
+ /*******************************************************\
+ * Fill out the scsi_xfer structure *
+ \*******************************************************/
+ xs->flags |= flags;
+ xs->adapter = st->ctlr;
+ xs->targ = st->targ;
+ xs->lu = st->lu;
+ xs->retries = ST_RETRIES;
+ xs->timeout = timeout;
+ xs->cmd = scsi_cmd;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->resid = datalen;
+ xs->when_done = (flags & SCSI_NOMASK)
+ ?(int (*)())0
+ :st_done;
+ xs->done_arg = unit;
+ xs->done_arg2 = (int)xs;
+retry: xs->error = XS_NOERROR;
+ xs->bp = 0;
+ retval = (*(st->sc_sw->scsi_cmd))(xs);
+ switch(retval)
+ {
+ case SUCCESSFULLY_QUEUED:
+ s = splbio();
+ while(!(xs->flags & ITSDONE))
+ sleep(xs,PRIBIO+1);
+ splx(s);
+
+ case HAD_ERROR:
+ case COMPLETE:
+ switch(xs->error)
+ {
+ case XS_NOERROR:
+ retval = ESUCCESS;
+ break;
+ case XS_SENSE:
+ retval = (st_interpret_sense(unit,xs));
+ /* only useful for reads */
+ if (retval)
+ { /* error... don't care about filemarks */
+ st->flags &= ~(ST_AT_FILEMARK
+ | ST_AT_EOM);
+ }
+ else
+ {
+ xs->error = XS_NOERROR;
+ retval = ESUCCESS;
+ }
+ break;
+ case XS_DRIVER_STUFFUP:
+ retval = EIO;
+ break;
+ case XS_TIMEOUT:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ case XS_BUSY:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ printf("st%d: unknown error category from scsi driver\n"
+ ,unit);
+ break;
+ }
+ break;
+ case TRY_AGAIN_LATER:
+ if(xs->retries-- )
+ {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ }
+ xs->flags = 0; /* it's free! */
+ ststart(unit);
+ }
+ else
+ {
+ printf("st%d: not set up\n",unit);
+ return(EINVAL);
+ }
+ return(retval);
+}
+/***************************************************************\
+* Look at the returned sense and act on the error and detirmine *
+* The unix error number to pass back... (0 = report no error) *
+\***************************************************************/
+
+int st_interpret_sense(unit,xs)
+int unit;
+struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *sense;
+ int key;
+ int silent = xs->flags & SCSI_SILENT;
+
+ /***************************************************************\
+ * If errors are ok, report a success *
+ \***************************************************************/
+ if(xs->flags & SCSI_ERR_OK) return(ESUCCESS);
+
+ /***************************************************************\
+ * Get the sense fields and work out what CLASS *
+ \***************************************************************/
+ sense = &(xs->sense);
+ if(st_debug)
+ {
+ int count = 0;
+ printf("code%x class%x valid%x\n"
+ ,sense->error_code
+ ,sense->error_class
+ ,sense->valid);
+ printf("seg%x key%x ili%x eom%x fmark%x\n"
+ ,sense->ext.extended.segment
+ ,sense->ext.extended.sense_key
+ ,sense->ext.extended.ili
+ ,sense->ext.extended.eom
+ ,sense->ext.extended.filemark);
+ printf("info: %x %x %x %x followed by %d extra bytes\n"
+ ,sense->ext.extended.info[0]
+ ,sense->ext.extended.info[1]
+ ,sense->ext.extended.info[2]
+ ,sense->ext.extended.info[3]
+ ,sense->ext.extended.extra_len);
+ printf("extra: ");
+ while(count < sense->ext.extended.extra_len)
+ {
+ printf ("%x ",sense->ext.extended.extra_bytes[count++]);
+ }
+ printf("\n");
+ }
+ switch(sense->error_class)
+ {
+ /***************************************************************\
+ * If it's class 7, use the extended stuff and interpret the key *
+ \***************************************************************/
+ case 7:
+ {
+ if(sense->ext.extended.eom)
+ {
+ st_data[unit].flags |= ST_AT_EOM;
+ }
+
+ if(sense->ext.extended.filemark)
+ {
+ st_data[unit].flags |= ST_AT_FILEMARK;
+ }
+
+ if(sense->ext.extended.ili)
+ {
+ if(sense->valid)
+ {
+ /*******************************\
+ * In all ili cases, note that *
+ * the resid is non-0 AND not *
+ * unchanged. *
+ \*******************************/
+ xs->resid
+ = ntohl(*((long *)sense->ext.extended.info));
+ if(xs->bp)
+ {
+ if(xs->resid < 0)
+ { /* never on block devices */
+ /***********************\
+ * it's only really bad *
+ * if we have lost data *
+ * (the record was *
+ * bigger than the read) *
+ \***********************/
+ return(EIO);
+ }
+ }
+ }
+ else
+ { /* makes no sense.. complain */
+ printf("BAD length error?");
+ }
+ }/* there may be some other error. check the rest */
+
+ key=sense->ext.extended.sense_key;
+ switch(key)
+ {
+ case 0x0:
+ return(ESUCCESS);
+ case 0x1:
+ if(!silent)
+ {
+ printf("st%d: soft error(corrected) ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(ESUCCESS);
+ case 0x2:
+ if(!silent) printf("st%d: not ready\n ", unit);
+ return(ENODEV);
+ case 0x3:
+ if(!silent)
+ {
+ printf("st%d: medium error ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(EIO);
+ case 0x4:
+ if(!silent) printf("st%d: non-media hardware failure\n ",
+ unit);
+ return(EIO);
+ case 0x5:
+ if(!silent) printf("st%d: illegal request\n ", unit);
+ return(EINVAL);
+ case 0x6:
+ if(!silent) printf("st%d: Unit attention.\n ", unit);
+ st_data[unit].flags &= ~(ST_AT_FILEMARK|ST_AT_EOM);
+ st_info_valid[unit] = FALSE;
+ if (st_data[unit].flags & ST_OPEN) /* TEMP!!!! */
+ return(EIO);
+ else
+ return(ESUCCESS);
+ case 0x7:
+ if(!silent)
+ {
+ printf("st%d: attempted protection violation "
+ , unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(EACCES);
+ case 0x8:
+ if(!silent)
+ {
+ printf("st%d: block wrong state (worm)\n "
+ , unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(EIO);
+ case 0x9:
+ if(!silent) printf("st%d: vendor unique\n",
+ unit);
+ return(EIO);
+ case 0xa:
+ if(!silent) printf("st%d: copy aborted\n ",
+ unit);
+ return(EIO);
+ case 0xb:
+ if(!silent) printf("st%d: command aborted\n ",
+ unit);
+ return(EIO);
+ case 0xc:
+ if(!silent)
+ {
+ printf("st%d: search returned\n ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(ESUCCESS);
+ case 0xd:
+ if(!silent) printf("st%d: volume overflow\n ",
+ unit);
+ return(ENOSPC);
+ case 0xe:
+ if(!silent)
+ {
+ printf("st%d: verify miscompare\n ", unit);
+ if(sense->valid)
+ {
+ printf("block no. %d (decimal)\n",
+ (sense->ext.extended.info[0] <<24)|
+ (sense->ext.extended.info[1] <<16)|
+ (sense->ext.extended.info[2] <<8)|
+ (sense->ext.extended.info[3] ));
+ }
+ else
+ {
+ printf("\n");
+ }
+ }
+ return(EIO);
+ case 0xf:
+ if(!silent) printf("st%d: unknown error key\n ",
+ unit);
+ return(EIO);
+ }
+ break;
+ }
+ /***************************************************************\
+ * If it's NOT class 7, just report it. *
+ \***************************************************************/
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ {
+ if(!silent) printf("st%d: error class %d code %d\n",
+ unit,
+ sense->error_class,
+ sense->error_code);
+ if(sense->valid)
+ if(!silent) printf("block no. %d (decimal)\n",
+ (sense->ext.unextended.blockhi <<16),
+ + (sense->ext.unextended.blockmed <<8),
+ + (sense->ext.unextended.blocklow ));
+ }
+ return(EIO);
+ }
+}
+
+#if defined(OSF)
+
+stsize(dev_t dev)
+{
+ printf("stsize() -- not implemented\n");
+ return(0);
+}
+
+stdump()
+{
+ printf("stdump() -- not implemented\n");
+ return(-1);
+}
+
+#endif /* defined(OSF) */
+
diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h
new file mode 100644
index 0000000..0bd4ea7
--- /dev/null
+++ b/sys/sys/cdio.h
@@ -0,0 +1,149 @@
+/*
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ */
+/* Shared between kernel & process */
+
+struct cd_toc_entry {
+ u_char :8;
+ u_char control:4;
+ u_char addr_type:4;
+ u_char track;
+ u_char :8;
+ u_char addr[4];
+};
+
+struct cd_sub_channel_header {
+ u_char :8;
+ u_char audio_status;
+#define CD_AS_AUDIO_INVALID 0x00
+#define CD_AS_PLAY_IN_PROGRESS 0x11
+#define CD_AS_PLAY_PAUSED 0x12
+#define CD_AS_PLAY_COMPLETED 0x13
+#define CD_AS_PLAY_ERROR 0x14
+#define CD_AS_NO_STATUS 0x15
+ u_char data_len[2];
+};
+
+struct cd_sub_channel_position_data {
+ u_char data_format;
+ u_char control:4;
+ u_char addr_type:4;
+ u_char track_number;
+ u_char index_number;
+ u_char absaddr[4];
+ u_char reladdr[4];
+};
+
+struct cd_sub_channel_media_catalog {
+ u_char data_format;
+ u_char :8;
+ u_char :8;
+ u_char :8;
+ u_char :7;
+ u_char mc_valid:1;
+ u_char mc_number[15];
+};
+
+struct cd_sub_channel_track_info {
+ u_char data_format;
+ u_char :8;
+ u_char track_number;
+ u_char :8;
+ u_char :7;
+ u_char ti_valid:1;
+ u_char ti_number[15];
+};
+
+struct cd_sub_channel_info {
+ struct cd_sub_channel_header header;
+ union {
+ struct cd_sub_channel_position_data position;
+ struct cd_sub_channel_media_catalog media_catalog;
+ struct cd_sub_channel_track_info track_info;
+ } what;
+};
+
+/***************************************************************\
+* Ioctls for the CD drive *
+\***************************************************************/
+struct ioc_play_track
+{
+ u_char start_track;
+ u_char start_index;
+ u_char end_track;
+ u_char end_index;
+};
+
+#define CDIOCPLAYTRACKS _IOW('c',1,struct ioc_play_track)
+struct ioc_play_blocks
+{
+ int blk;
+ int len;
+};
+#define CDIOCPLAYBLOCKS _IOW('c',2,struct ioc_play_blocks)
+
+struct ioc_read_subchannel {
+ u_char address_format;
+#define CD_LBA_FORMAT 1
+#define CD_MSF_FORMAT 2
+ u_char data_format;
+#define CD_SUBQ_DATA 0
+#define CD_CURRENT_POSITION 1
+#define CD_MEDIA_CATALOG 2
+#define CD_TRACK_INFO 3
+ u_char track;
+ int data_len;
+ struct cd_sub_channel_info *data;
+};
+#define CDIOCREADSUBCHANNEL _IOWR('c', 3 , struct ioc_read_subchannel )
+
+
+struct ioc_toc_header {
+ u_short len;
+ u_char starting_track;
+ u_char ending_track;
+};
+
+#define CDIOREADTOCHEADER _IOR('c',4,struct ioc_toc_header)
+
+struct ioc_read_toc_entry {
+ u_char address_format;
+ u_char starting_track;
+ u_short data_len;
+ struct cd_toc_entry *data;
+};
+#define CDIOREADTOCENTRYS _IOWR('c',5,struct ioc_read_toc_entry)
+
+struct ioc_patch
+{
+ u_char patch[4]; /* one for each channel */
+};
+#define CDIOCSETPATCH _IOW('c',9,struct ioc_patch)
+struct ioc_vol
+{
+ u_char vol[4]; /* one for each channel */
+};
+#define CDIOCGETVOL _IOR('c',10,struct ioc_vol)
+#define CDIOCSETVOL _IOW('c',11,struct ioc_vol)
+#define CDIOCSETMONO _IO('c',12)
+#define CDIOCSETSTERIO _IO('c',13)
+#define CDIOCSETMUTE _IO('c',14)
+#define CDIOCSETLEFT _IO('c',15)
+#define CDIOCSETRIGHT _IO('c',16)
+#define CDIOCSETDEBUG _IO('c',17)
+#define CDIOCCLRDEBUG _IO('c',18)
+#define CDIOCPAUSE _IO('c',19)
+#define CDIOCRESUME _IO('c',20)
+#define CDIOCRESET _IO('c',21)
+#define CDIOCSTART _IO('c',22)
+#define CDIOCSTOP _IO('c',23)
+#define CDIOCEJECT _IO('c',24)
+
+
+
diff --git a/sys/sys/cons.h b/sys/sys/cons.h
new file mode 100644
index 0000000..b3c7064
--- /dev/null
+++ b/sys/sys/cons.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cons.h 7.2 (Berkeley) 5/9/91
+ */
+
+
+struct consdev {
+ int (*cn_probe)(); /* probe hardware and fill in consdev info */
+ int (*cn_init)(); /* turn on as console */
+ int (*cn_getc)(); /* kernel getchar interface */
+ int (*cn_putc)(); /* kernel putchar interface */
+ struct tty *cn_tp; /* tty structure for console device */
+ dev_t cn_dev; /* major/minor of device */
+ short cn_pri; /* pecking order; the higher the better */
+};
+
+/* values for cn_pri - reflect our policy for console selection */
+#define CN_DEAD 0 /* device doesn't exist */
+#define CN_NORMAL 1 /* device exists but is nothing special */
+#define CN_INTERNAL 2 /* "internal" bit-mapped display */
+#define CN_REMOTE 3 /* serial interface with remote bit set */
+
+/* XXX */
+#define CONSMAJOR 0
+
+#ifdef KERNEL
+extern struct consdev constab[];
+extern struct consdev *cn_tab;
+extern struct tty *cn_tty;
+#endif
diff --git a/sys/sys/rlist.h b/sys/sys/rlist.h
new file mode 100644
index 0000000..bd468b1
--- /dev/null
+++ b/sys/sys/rlist.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1992 William Jolitz. All rights reserved.
+ * Written by William Jolitz 1/92
+ *
+ * Redistribution and use in source and binary forms are freely permitted
+ * provided that the above copyright notice and attribution and date of work
+ * and this paragraph are duplicated in all such forms.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Resource lists.
+ *
+ * Usage:
+ * rlist_free(&swapmap, 100, 200); add space to swapmap
+ * rlist_alloc(&swapmap, 100, &loc); obtain 100 sectors from swap
+ * $Header: /usr/bill/working/sys/sys/RCS/rlist.h,v 1.2 92/01/21 21:23:48 william Exp $
+ */
+
+/* A resource list element. */
+struct rlist {
+ unsigned rl_start; /* boundaries of extent - inclusive */
+ unsigned rl_end; /* boundaries of extent - inclusive */
+ struct rlist *rl_next; /* next list entry, if present */
+};
+
+/* Functions to manipulate resource lists. */
+extern rlist_free __P((struct rlist **, unsigned, unsigned));
+int rlist_alloc __P((struct rlist **, unsigned, unsigned *));
+extern rlist_destroy __P((struct rlist **));
+
+
+/* heads of lists */
+struct rlist *swapmap;
OpenPOWER on IntegriCloud