Do some fairly major include file cleanups to further separate kernelland
[dragonfly.git] / usr.bin / doscmd / doscmd.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
16 * Design, Inc.
17 *
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * BSDI doscmd.c,v 2.3 1996/04/08 19:32:30 bostic Exp
1de703da
MD
31 *
32 * $FreeBSD: src/usr.bin/doscmd/doscmd.c,v 1.13.2.6 2002/04/25 11:04:51 tg Exp $
05220613 33 * $DragonFly: src/usr.bin/doscmd/doscmd.c,v 1.3 2003/11/21 22:46:14 dillon Exp $
984263bc
MD
34 */
35
984263bc
MD
36#include <sys/types.h>
37#include <sys/param.h>
38#include <sys/mman.h>
39#include <sys/time.h>
40
41#include <ctype.h>
42#include <err.h>
43#include <errno.h>
44#include <limits.h>
45#include <paths.h>
46#include <pwd.h>
47#include <signal.h>
48#include <unistd.h>
49
50#include <machine/param.h>
51#include <machine/vmparam.h>
52
984263bc
MD
53#include <machine/sysarch.h>
54#include <machine/vm86.h>
55
56#include "doscmd.h"
57#include "cwd.h"
58#include "trap.h"
59#include "tty.h"
60#include "video.h"
61
62/* exports */
63int capture_fd = -1;
64int dead = 0;
65int xmode = 0;
66int booting = 0;
67int raw_kbd = 0;
68int timer_disable = 0;
69struct timeval boot_time;
70unsigned long *ivec = (unsigned long *)0;
71
72#ifndef USE_VM86
73#define PRB_V86_FORMAT 0x4242
74
75struct vconnect_area vconnect_area = {
76 0, /* Interrupt state */
77 PRB_V86_FORMAT, /* Magic number */
78 { 0, }, /* Pass through ints */
79 { 0x00000000, 0x00000000 } /* Magic iret location */
80};
81#endif
82
83/* local prototypes */
84static void setup_boot(regcontext_t *REGS);
85static int try_boot(int);
86static void setup_command(int argc, char *argv[], regcontext_t *REGS);
87static FILE *find_doscmdrc(void);
88static int do_args(int argc, char *argv[]);
89static void usage(void);
90static int open_name(char *name, char *ext);
91
92/* Local option flags &c. */
93static int zflag = 0;
94
95/* DOS environment emulation */
96static unsigned ecnt = 0;
97static char *envs[256];
98
99/* Search path and command name */
100static char *dos_path = 0;
101char cmdname[256]; /* referenced from dos.c */
102
103static struct vm86_init_args kargs;
104
105/* lobotomise */
106int
107main(int argc, char **argv)
108{
109#ifndef USE_VM86
110 ucontext_t uc;
111#else
112 struct vm86_struct vm86s;
113#define sc vm86s.substr.regs.vmsc
114#endif
115 regcontext_t *REGS = (regcontext_t *)&uc.uc_mcontext;
116 int fd;
117 int i;
118 sigset_t sigset;
119
120 sigemptyset(&sigset);
121 sigaddset(&sigset, SIGIO);
122 sigaddset(&sigset, SIGALRM);
123 sigprocmask(SIG_BLOCK, &sigset, 0);
124
125 init_ints();
126
127 debugf = stderr;
128 /* XXX should only be for tty mode */
129 fd = open (_PATH_DEVNULL, O_RDWR);
130 if (fd != 3)
131 dup2 (fd, 3); /* stdaux */
132 if (fd != 4)
133 dup2 (fd, 4); /* stdprt */
134 if (fd != 3 && fd != 4)
135 close (fd);
136 fd = -1;
137
138 debug_set(0); /* debug any D_TRAPS without intnum */
139
140 /* perform option argument processing */
141 do_args(argc, argv);
142 argc -= optind;
143 argv += optind;
144
145 if (vflag && debugf == stderr) {
146 debugf = stdout;
147 setbuf (stdout, NULL);
148 }
149
150 initHMA();
151
152 /* This needs to happen before the executable is loaded */
153 mem_init();
154
155#ifdef USE_VM86
156 memset(&vm86s, 0, sizeof(vm86s));
157#endif
158
159 /*
160 * With no other arguments we will assume we must boot DOS
161 */
162 if (argc <= 0)
163 booting = 1;
164
165#if 1
166 /*
167 * Nominate interrupts to handle here when the kernel is
168 * performing interrupt handling.
169 *
170 * I would like to let INT 2F pass through as well, but I
171 * need to get my hands on INT 2F:11 to do file redirection.
172 */
173 for (i = 0; i <= 0xff; ++i) {
174 switch (i) {
175 case 0x2f:
176 case 0xff:
177#if 1
178 kargs.int_map[i >> 3] |= (1 << (i & 7));
179#ifndef USE_VM86
180 vconnect_area.passthru[i >> 5] &= ~(1 << (i & 0x1f));
181#else
182 vm86s.int_byuser[i >> 3] |= (1 << (i & 0x07));
183#endif
184#endif
185 break;
186 default:
187#if 1
188 kargs.int_map[i >> 3] &= ~(1 << (i & 7));
189#ifndef USE_VM86
190 vconnect_area.passthru[i >> 5] |= (1 << (i & 0x1f));
191#else
192 vm86s.int_byuser[i >> 3] |= (1 << (i & 0x07));
193#endif
194#endif
195 break;
196 }
197 }
198#endif
199
200 if (booting) { /* are we booting? */
201 setup_boot(REGS);
202 } else { /* no, load a command */
203 setup_command(argc, argv, REGS);
204 }
205
206 /* install signal handlers */
207 setsignal(SIGFPE, sigfpe); /* */
208 setsignal(SIGALRM, sigalrm); /* */
209 setsignal(SIGILL, sigill); /* */
210 setsignal(SIGTRAP, sigtrap); /* */
211 setsignal(SIGUSR2, sigtrace); /* */
212 setsignal(SIGINFO, sigtrace); /* */
213#ifdef USE_VM86
214 setsignal(SIGURG, sigurg); /* entry from NetBSD vm86 */
215#else
216 setsignal(SIGBUS, sigbus); /* entry from FreeBSD, BSD/OS vm86 */
217#endif
218
219 /* Call init functions */
220 if (raw_kbd)
221 console_init();
222 init_io_port_handlers();
223 bios_init();
224 cpu_init();
225 kbd_init();
226 kbd_bios_init();
227 video_init();
228 if (xmode)
229 mouse_init();
230 video_bios_init();
231 disk_bios_init();
232 cmos_init();
233 xms_init();
234 dos_init();
235 net_init();
236 speaker_init();
237 timer_init();
238 /* iomap_init(); */
239
240 gettimeofday(&boot_time, 0);
241
242 if (zflag) for (;;) pause(); /* spin if requested */
243
244 if (raw_kbd) {
245 /*
246 * If we have a raw keyboard, and hence, video,
247 * sneak in a call to the video BIOS to reinit the
248 * the video display.
249 */
250 u_long video_vector;
251 static u_char video_trampoline[] = {
252 0x60, /* pusha */
253 0xB8, 0x03, 0x00, /* mov ax,00003h */
254 0xCD, 0x10, /* int 010h */
255 0x61, /* popa */
256 0xCF, /* iret */
257 };
258
259 video_vector = insert_generic_trampoline(
260 sizeof(video_trampoline), video_trampoline);
261
262 PUSH(R_FLAGS, REGS);
263 PUSH(R_CS, REGS);
264 PUSH(R_IP, REGS);
265 PUTVEC(R_CS, R_IP, video_vector);
266 }
267
268 sigemptyset(&uc.uc_sigmask);
269 sigaltstack(NULL, &uc.uc_stack);
270 uc.uc_mcontext.mc_onstack = 0;
271
272 if (tmode)
273 tracetrap(REGS);
274
275#ifndef USE_VM86
276 R_EAX = (booting || raw_kbd) ? (int)&vconnect_area : -1;
277 R_EFLAGS |= PSL_VM | PSL_VIF; /* request VM86 mode */
278
279 i386_vm86(VM86_INIT, &kargs);
280
281 sigreturn(&uc);
282 debug(D_ALWAYS,"sigreturn failed : %s\n", strerror(errno));
283#else
284 vm86s.cpu_type = VCPU_586;
285 i386_vm86(&vm86s);
286#endif
287
288 /* shouldn't get here */
289 if (vflag) dump_regs(REGS);
290 fatal ("vm86 returned (no kernel support?)\n");
291#undef sc
292 /* quiet -Wall */
293 return 0;
294}
295
296/*
297** setup_boot
298**
299** Setup to boot DOS
300*/
301static void
302setup_boot(regcontext_t *REGS)
303{
304 FILE *fp; /* doscmdrc handle */
305 int fd; /* don't close this! */
306
307 fp = find_doscmdrc(); /* get doscmdrc */
308 if (!fp) {
309 fprintf(stderr, "You must have a doscmdrc to boot\n");
310 quit(1);
311 }
312
313 booting = read_config(fp); /* where to boot from? */
314 fclose(fp);
315 if (booting < 0) { /* not specified */
316 if ((fd = try_boot(booting = 0)) < 0) /* try A: */
317 fd = try_boot(booting = 2); /* try C: */
318 } else {
319 fd = try_boot(booting); /* do like the man says */
320 }
321
322 if (fd < 0)
323 errx(1, "Failed to boot");
324
325 /* initialise registers for entry to bootblock */
326 R_EFLAGS = 0x20202;
327 R_CS = 0x0000;
328 R_IP = 0x7c00;
329 R_SS = 0x9800;
330 R_SP = 0x8000 - 2;
331 R_DS = 0x0000;
332 R_ES = 0x0000;
333
334 R_AX = R_BX = R_CX = R_DX = R_SI = R_DI = R_BP = 0;
335
336#if defined(__FreeBSD__) || defined(__NetBSD__)
337 /*
338 ** init a few other context registers
339 */
340 R_FS = 0x0000;
341 R_GS = 0x0000;
342#endif
343}
344
345/*
346** try_boot
347**
348** try to read the boot sector from the specified disk
349*/
350static int
351try_boot(int bootdrv)
352{
353 int fd;
354
355 fd = disk_fd(bootdrv);
356 if (fd < 0) { /* can we boot it? */
357 debug(D_DISK, "Cannot boot from %c\n", drntol(bootdrv));
358 return -1;
359 }
360
361 /* read bootblock */
362 if (read(fd, (char *)0x7c00, 512) != 512) {
363 debug(D_DISK, "Short read on boot block from %c:\n", drntol(bootdrv));
364 return -1;
365 }
366
367 return fd;
368}
369
370/*
371** setup_command
372**
373** Setup to run a single command and emulate DOS
374*/
375static void
376setup_command(int argc, char *argv[], regcontext_t *REGS)
377{
378 FILE *fp;
379 u_short param[7] = {0, 0, 0, 0, 0, 0, 0};
380 const char *p;
381 char prog[1024];
382 char buffer[PATH_MAX];
383 unsigned i;
384 int fd;
385
386 fp = find_doscmdrc(); /* dig up a doscmdrc */
387 if (fp) {
388 read_config(fp); /* load config for non-boot mode */
389 fclose(fp);
390 }
391
392 if (argc <= 0) /* need some arguments */
393 usage();
394
395 /* look for a working directory XXX ??? */
396 if (dos_getcwd(drlton('C')) == NULL) {
397
398 /* try to get our current directory, use '/' if desperate */
399 p = getcwd(buffer, sizeof(buffer));
400 if (!p || !*p) p = getenv("PWD");
401 if (!p || !*p) p = "/";
402 init_path(drlton('C'), "/", p);
403
404 /* look for PATH= already set, learn from it if possible */
405 for (i = 0; i < ecnt; ++i) {
406 if (!strncmp(envs[i], "PATH=", 5)) {
407 dos_path = envs[i] + 5;
408 break;
409 }
410 }
411 /* no PATH in DOS environment? put current directory there*/
412 if (i >= ecnt) {
413 static char path[256];
414 snprintf(path, sizeof(path), "PATH=C:%s", dos_getcwd(drlton('C')));
415 put_dosenv(path);
416 dos_path = envs[ecnt-1] + 5;
417 }
418 }
419
420 /* add a COMSPEC if required */
421 for (i = 0; i < ecnt; ++i) {
422 if (!strncmp(envs[i], "COMSPEC=", 8))
423 break;
424 }
425 if (i >= ecnt)
426 put_dosenv("COMSPEC=C:\\COMMAND.COM");
427
428 /* look for PATH already set, learn from it if possible */
429 for (i = 0; i < ecnt; ++i) {
430 if (!strncmp(envs[i], "PATH=", 5)) {
431 dos_path = envs[i] + 5;
432 break;
433 }
434 }
435 /* No PATH, default to c:\ */
436 if (i >= ecnt) {
437 put_dosenv("PATH=C:\\");
438 dos_path = envs[ecnt-1] + 5;
439 }
440
441 /* if no PROMPT, default to 'DOS>' */
442 for (i = 0; i < ecnt; ++i) {
443 if (!strncmp(envs[i], "PROMPT=", 7))
444 break;
445 }
446 if (i >= ecnt)
447 put_dosenv("PROMPT=DOS> ");
448
449 /* terminate environment */
450 envs[ecnt] = 0;
451
452 /* XXX ??? */
453 if (dos_getcwd(drlton('R')) == NULL)
454 init_path(drlton('R'), "/", 0);
455
456 /* get program name */
457 strncpy(prog, *argv++, sizeof(prog) -1);
458 prog[sizeof(prog) -1] = '\0';
459
460 /* try to open program */
461 if ((fd = open_prog(prog)) < 0) {
462 fprintf (stderr, "%s: command not found\n", prog);
463 quit(1);
464 }
465
466 /* load program */
467 load_command(REGS, 1, fd, cmdname, param, argv, envs);
468 close(fd);
469}
470
471/*
472** find_doscmdrc
473**
474** Try to find a doscmdrc file
475*/
476static FILE *
477find_doscmdrc(void)
478{
479 FILE *fp;
480 char buffer[4096];
481
482 if ((fp = fopen(".doscmdrc", "r")) == NULL) {
483 struct passwd *pwd = getpwuid(geteuid());
484 if (pwd) {
485 snprintf(buffer, sizeof(buffer), "%s/.doscmdrc", pwd->pw_dir);
486 fp = fopen(buffer, "r");
487 }
488 if (!fp) {
489 char *home = getenv("HOME");
490 if (home) {
491 snprintf(buffer, sizeof(buffer), "%s/.doscmdrc", home);
492 fp = fopen(buffer, "r");
493 }
494 }
495 if (!fp)
496 fp = fopen("/etc/doscmdrc", "r");
497 }
498 return(fp);
499}
500
501/*
502** do_args
503**
504** commandline argument processing
505*/
506static int
507do_args(int argc, char *argv[])
508{
509 int i,c,p;
510 FILE *fp;
511 char *col;
512
513 while ((c = getopt(argc, argv, "234AbCc:Dd:EGHIi:kLMOo:Pp:RrS:TtU:vVxXYz")) != -1) {
514 switch (c) {
515 case '2':
516 debug_flags |= D_TRAPS2;
517 break;
518 case '3':
519 debug_flags |= D_TRAPS3;
520 break;
521 case '4':
522 debug_flags |= D_DEBUGIN;
523 break;
524 case 'A':
525 debug_flags |= D_TRAPS | D_ITRAPS;
526 for (c = 0; c < 256; ++c)
527 debug_set(c);
528 break;
529 case 'b':
530 booting = 1;
531 break;
532 case 'C':
533 debug_flags |= D_DOSCALL;
534 break;
535 case 'c':
536 if ((capture_fd = creat(optarg, 0666)) < 0) {
537 perror(optarg);
538 quit(1);
539 }
540 break;
541 case 'D':
542 debug_flags |= D_DISK | D_FILE_OPS;
543 break;
544 case 'd':
545 if ((fp = fopen(optarg, "w")) != 0) {
546 debugf = fp;
547 setbuf (fp, NULL);
548 } else
549 perror(optarg);
550 break;
551 case 'E':
552 debug_flags |= D_EXEC;
553 break;
554 case 'G':
555 debug_flags |= D_VIDEO;
556 break;
557 case 'H':
558 debug_flags |= D_HALF;
559 break;
560 case 'I':
561 debug_flags |= D_ITRAPS;
562 for (c = 0; c < 256; ++c)
563 debug_set(c);
564 break;
565 case 'i':
566 i = 1;
567 if ((col = strchr(optarg, ':')) != 0) {
568 *col++ = 0;
569 i = strtol(col, 0, 0);
570 }
571 p = strtol(optarg, 0, 0);
572 iomap_port(p, i);
573
574 while (i-- > 0)
575 define_input_port_handler(p++, inb_traceport);
576 break;
577 case 'k':
578 kargs.debug = 1;
579 break;
580 case 'L':
581 debug_flags |= D_PRINTER;
582 break;
583 case 'M':
584 debug_flags |= D_MEMORY;
585 break;
586 case 'O':
587 debugf = stdout;
588 setbuf (stdout, NULL);
589 break;
590 case 'o':
591 i = 1;
592 if ((col = strchr(optarg, ':')) != 0) {
593 *col++ = 0;
594 i = strtol(col, 0, 0);
595 }
596 p = strtol(optarg, 0, 0);
597 iomap_port(p, i);
598
599 while (i-- > 0)
600 define_output_port_handler(p++, outb_traceport);
601 break;
602 case 'P':
603 debug_flags |= D_PORT;
604 break;
605 case 'p':
606 i = 1;
607 if ((col = strchr(optarg, ':')) != 0) {
608 *col++ = 0;
609 i = strtol(col, 0, 0);
610 }
611 p = strtol(optarg, 0, 0);
612 iomap_port(p, i);
613
614 while (i-- > 0) {
615 define_input_port_handler(p++, inb_port);
616 define_output_port_handler(p++, outb_port);
617 }
618 break;
619 case 'R':
620 debug_flags |= D_REDIR;
621 break;
622 case 'r':
623 raw_kbd = 1;
624 break;
625 case 'S':
626 debug_flags |= D_TRAPS | D_ITRAPS;
627 debug_set(strtol(optarg, 0, 0));
628 break;
629 case 'T':
630 timer_disable = 1;
631 break;
632 case 't':
633 tmode = 1;
634 break;
635 case 'U':
636 debug_unset(strtol(optarg, 0, 0));
637 break;
638 case 'V':
639 vflag = 1;
640 break;
641 case 'v':
642 debug_flags |= D_TRAPS | D_ITRAPS | D_HALF | 0xff;
643 break;
644 case 'X':
645 debug_flags |= D_XMS;
646 break;
647 case 'x':
648#ifdef NO_X
649 fatal("X11 support not compiled in.\n");
650#endif
651 xmode = 1;
652 break;
653 case 'Y':
654 debug_flags |= D_EMS;
655 break;
656 case 'z':
657 zflag = 1;
658 break;
659 default:
660 usage ();
661 }
662 }
663 return(optind);
664}
665
666/*
667** Very helpful 8(
668*/
669void
670usage (void)
671{
672 fprintf (stderr, "usage: doscmd cmd args...\n");
673 quit (1);
674}
675
676/*
677** look up a DOS command name
678**
679** XXX ordering is wrong!
680*/
681static int
682open_name(char *name, char *ext)
683{
684 int fd;
685 char *p = name + strlen(name);
686 char *q;
687
688 *ext = 0;
689
690 q = strrchr(name, '/');
691 if (q)
692 q++;
693 else
694 q = name;
695
696 if (!strchr(q, '.')) {
697 strcpy(ext, ".exe");
698 strcpy(p, ".exe");
699
700 if ((fd = open (name, O_RDONLY)) >= 0)
701 return (fd);
702
703 strcpy(ext, ".com");
704 strcpy(p, ".com");
705
706 if ((fd = open (name, O_RDONLY)) >= 0)
707 return (fd);
708 } else {
709 if ((fd = open (name, O_RDONLY)) >= 0)
710 return (fd);
711 }
712
713 return (-1);
714}
715
716/*
717** look up a DOS command, search the path as well.
718*/
719int
720open_prog(char *name)
721{
722 int fd;
723 char fullname[1024], tmppath[1024];
724 char *p;
725 char *e;
726 char ext[5];
727 int error;
728 int drive;
729 char *path;
730
731 if (strpbrk(name, ":/\\")) {
732 error = translate_filename(name, fullname, &drive);
733 if (error)
734 return (-1);
735
736 fd = open_name(fullname, ext);
737
738 strcpy(cmdname, name);
739 if (*ext)
740 strcat(cmdname, ext);
741 return (fd);
742 }
743
744 path = dos_path;
745
746 while (*path) {
747 p = path;
748 while (*p && *p != ';')
749 ++p;
750
751 memcpy(tmppath, path, p - path);
752 e = tmppath + (p - path);
753 *e++ = '\\';
754 strcpy(e, name);
755
756 path = *p ? p + 1 : p;
757
758 error = translate_filename(tmppath, fullname, &drive);
759 if (error)
760 continue;
761
762 fd = open_name(fullname, ext);
763
764 if (fd >= 0) {
765 strcpy(cmdname, tmppath);
766 if (*ext)
767 strcat(cmdname, ext);
768 return (fd);
769 }
770 }
771
772 return (-1);
773}
774
775/*
776** append a value to the DOS environment
777*/
778void
779put_dosenv(const char *value)
780{
781 if (ecnt < sizeof(envs)/sizeof(envs[0])) {
782 if ((envs[ecnt++] = strdup(value)) == NULL) {
783 perror("put_dosenv");
784 quit(1);
785 }
786 } else {
787 fprintf(stderr, "Environment full, ignoring %s\n", value);
788 }
789}
790
791/*
792** replicate a fd up at the top of the range
793*/
794int
795squirrel_fd(int fd)
796{
797 int sfd = sysconf(_SC_OPEN_MAX);
798 struct stat sb;
799
800 do {
801 errno = 0;
802 fstat(--sfd, &sb);
803 } while (sfd > 0 && errno != EBADF);
804
805 if (errno == EBADF && dup2(fd, sfd) >= 0) {
806 close(fd);
807 return(sfd);
808 }
809 return(fd);
810}
811
812/*
813** Exit-time stuff
814*/
815
816/*
817** Going away time
818**
819** XXX belongs somewhere else perhaps
820*/
821void
822done(regcontext_t *REGS, int val)
823{
824 if (curpsp < 2) {
825 if (xmode) {
826 const char *m;
827
828 tty_move(24, 0);
829 for (m = "END OF PROGRAM"; *m; ++m)
830 tty_write(*m, 0x8400);
831
832 for (m = "(PRESS <CTRL-ALT> ANY MOUSE BUTTON TO exit)"; *m; ++m)
833 tty_write(*m, 0x0900);
834 tty_move(-1, -1);
835 for (;;)
836 tty_pause();
837 } else {
838 quit(val);
839 }
840 }
841 exec_return(REGS, val);
842}
843
844typedef struct COQ {
845 void (*func)(void *);
846 void *arg;
847 struct COQ *next;
848} COQ;
849
850COQ *coq = 0;
851
852void
853quit(int status)
854{
855 while (coq) {
856 COQ *c = coq;
857 coq = coq->next;
858 c->func(c->arg);
859 }
860 if (!xmode) /* XXX not for bootmode */
861 puts("\n");
862 exit(status);
863}
864
865void
866call_on_quit(void (*func)(void *), void *arg)
867{
868 COQ *c = (COQ *)malloc(sizeof(COQ));
869 if (!c) {
870 perror("call_on_quit");
871 quit(1);
872 }
873 c->func = func;
874 c->arg = arg;
875 c->next = coq;
876 coq = c;
877}
878
879struct io_range {
880 u_int start;
881 u_int length;
882 int enable;
883};
884
885/* This is commented out as it is never called. Turn it back on if needed.
886 */
887#if COMMENTED_OUT
888static void
889iomap_init(void)
890{
891 int i;
892 struct io_range io[] = {
893#if 0
894 { 0x200, 0x200, 1 }, /* 0x200 - 0x400 */
895 { 0x1c80, 2, 1 }, /* 0x1c80 - 0x1c81 */
896 { 0x2c80, 2, 1 }, /* 0x2c80 - 0x2c81 */
897 { 0x3c80, 2, 1 }, /* 0x3c80 - 0x3c81 */
898 { 0x378, 8, 1 }, /* 0x378 - 0x37F */
899 { 0x3c4, 2, 1 }, /* 0x3c4 - 0x3c5 */
900 { 0x3c5, 2, 1 }, /* 0x3ce - 0x3cf */
901#else
902 { 0x0, 0x10000, 1 }, /* entire i/o space */
903#endif
904 { 0, 0, 0 }
905 };
906
907 for (i = 0; io[i].length; i++)
908 if (i386_set_ioperm(io[i].start, io[i].length, io[i].enable) < 0)
909 err(1, "i386_set_ioperm");
910}
911#endif
912
913/* This is used to map in only the specified port range, instead of all
914 the ports or only certain port ranges.
915 */
916void
917iomap_port(int port, int count)
918{
919 if (i386_set_ioperm(port, count, 1) < 0)
920 err(1, "i386_set_ioperm");
921
922 debug(D_PORT,"mapped I/O port: port=%#x count=%d\n", port, count);
923}