diff options
Diffstat (limited to 'boot')
-rw-r--r-- | boot/ChangeLog | 722 | ||||
-rw-r--r-- | boot/Makefile | 54 | ||||
-rw-r--r-- | boot/boot.c | 1964 | ||||
-rw-r--r-- | boot/boot_script.c | 822 | ||||
-rw-r--r-- | boot/boot_script.h | 90 | ||||
-rw-r--r-- | boot/frank1.ld | 94 | ||||
-rw-r--r-- | boot/frankemul.ld | 107 | ||||
-rw-r--r-- | boot/mach-crt0.c | 158 | ||||
-rw-r--r-- | boot/sigvec.S | 23 | ||||
-rw-r--r-- | boot/syscall.S | 35 | ||||
-rw-r--r-- | boot/tcattr.c | 592 | ||||
-rw-r--r-- | boot/ux.c | 303 | ||||
-rw-r--r-- | boot/ux.h | 114 |
13 files changed, 5078 insertions, 0 deletions
diff --git a/boot/ChangeLog b/boot/ChangeLog new file mode 100644 index 00000000..ddafdd82 --- /dev/null +++ b/boot/ChangeLog @@ -0,0 +1,722 @@ +1999-09-13 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c: Reverted changes related to io_map_segment. + +1999-09-07 Thomas Bushnell, BSG <tb@mit.edu> + + * boot.c (S_io_map_segment): New function. + +1999-07-11 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (ds_device_read, S_io_read): Fix sloppy bugs in last change. + +1999-07-06 Thomas Bushnell, BSG <tb@mit.edu> + + * boot.c (load_image): Use mmap instead of vm_allocate, when + allocating in mach_task_self (). + (boot_script_exec_cmd): Likewise. + (set_mach_stack_args): Likewise. + (read_reply): Likewise. + (S_io_read): Likewise. + +1999-07-10 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c: Add #include <sys/mman.h> for munmap decl. + +Mon Jul 5 20:04:06 1999 Thomas Bushnell, BSG <tb@mit.edu> + + * boot.c (load_image): Fix typo in cast. Reported by Yamashita + TAKAO <jargon@lares.dti.ne.jp>. + +1999-07-03 Thomas Bushnell, BSG <tb@mit.edu> + + * boot.c (load_image): Use munmap instead of vm_deallocate when + it's from our own task. + (boot_script_read_file): Likewise. + (boot_script_exec_cmd): Likewise. + (set_mach_stack_args): Likewise. + (ds_device_read_inband): Likewise. + +1999-03-20 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (S_term_get_peername): New function. + +1999-03-14 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c: Fix typo in last change. + +1999-03-10 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (main): Only use real device name if root_store is for an + enforced single run starting at the beginning of the device. + +1999-03-09 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (main): Add newline to error msg. + Patch by Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>. + +1999-02-16 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (S_io_revoke): Add reply, replyPoly args. + +Tue Feb 16 05:06:12 1999 Thomas Bushnell, BSG <tb@mit.edu> + + * boot.c (S_io_revoke): New (unsupported) routine. + +1998-12-26 Roland McGrath <roland@baalperazim.frob.com> + + * boot.c (isig): New variable. + (init_termstate): If it's set, set ISIG flag in c_lflag. + (options): New option -I/--isig. + (parse_opt): Make -I set `isig'. + (boot_script_exec_cmd): Print out args as well as file name. + +1998-09-04 Roland McGrath <roland@baalperazim.frob.com> + + * boot_script.c: Include <string.h> instead of declaring memset here. + Include <stdlib.h> instead of declaring malloc, free here. + +1997-07-08 Miles Bader <miles@gnu.ai.mit.edu> + + * boot_script.c (prompt_resume_task): Pass more than a single + character buffer to safe_gets. + +Mon Jul 7 16:25:49 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * boot.c: Include <fcntl.h> instead of <fcntlbits.h>. Suggested + by Marcus G. Daniels (marcus@cathcart.sysc.pdx.edu). + +1997-06-20 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (bootscript): Made global. + (parse_opt): New function. + (options, doc, args_doc): New variables. + (bootscript_args): Now an array. + (ds_device_open, ds_device_close, ds_device_write, + ds_device_write_inband, ds_device_read, ds_device_read_inband, + ds_device_get_status, ds_device_set_status, ds_device_map, + ds_xxx_device_set_filter, ds_xxx_device_get_status, + ds_xxx_device_set_status, ds_device_set_filter): + Handle "pseudo-root" device. + (pseudo_root, root_store): New variables. + (main): Use argp to parse args, and implement the pseudo-root device. + Include <argp.h> & <hurd/store.h> + * Makefile (HURDLIBS): Include libstore & libshouldbeinlibc. + +Thu Apr 10 11:53:57 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * boot.c: Don't include varargs.h. + (set_mach_stack_args): Use stdarg instead of vararg. + +Mon Mar 17 13:12:45 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * boot_script.c (boot_script_parse_line): Don't print gratuitous + output noise. + +Thu Sep 12 16:28:47 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * Makefile (HURDLIBS): New variable. + (boot): Delete special depedencies. + +Tue Aug 13 16:57:22 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * Makefile (device.defs): Rule removed. + (ourdevice.defs): Fix rule to work with Makeconf-generated device.defs. + +Tue Aug 13 15:09:45 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * Makefile (ourdevice.defs): Depend on local device.defs. + (device.defs): New rule. + +Mon Aug 12 11:11:08 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * Makefile (ourdevice.defs): Find device.defs under + install_includedir now. + + * Makefile (all): No longer build uxboot by default. + +Thu Aug 1 14:38:38 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * boot_script.h (safe_gets): Declare second parm as type `int'. + * boot.c (safe_gets): Likewise. + +Sun Jul 7 21:10:08 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * boot.c (S_io_reauthenticate): Don't use unsafe MOVE_SEND in + auth_server_authenticate. + +Fri May 10 16:11:49 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (S_io_identity): Typo. + +Fri May 10 09:18:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * boot.c (S_io_identity): New function. + +Thu May 9 18:57:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * boot.c (S_io_select): No longer has TAG parm. + + * boot.c (S_io_reauthenticate): Use new interface. + +Sun Apr 28 22:50:38 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (main): Use select instead of SIGIO. + +Mon Apr 15 12:57:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * Makefile (uxboot): Permit errors because people might not have + the a.out-mach3 target installed, and that's OK for many users. + + * Makefile (uxboot.0): Find frank1.ld in #(srcdir). + + * boot_script.h (safe_gets): Add decl. + * boot_script.c: Include <stdio.h>. + +Wed Apr 3 18:54:22 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * ux.c (printf): Add %d. + +Wed Mar 27 11:30:29 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c [notanymore] (S_tioctl_tiocgeta, S_tioctl_tiocseta, + S_tioctl_tiocsetaf, term_modes, term_ccs, term_speeds): + Functions & variables removed. + * Makefile (COMMON-OBJS): Remove tcattr.o. + (SRCS): Remove tcattr.c. + +Thu Mar 14 10:10:20 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu> + + * Makefile (boot): Depend on libthreads.so, nothing wrong with shared + libs. + (uxboot.0, uxboot.1): Use automatic vars in cmds instead of gratuitous + redundancy. + (LDFLAGS-uxboot.0): Remove useless indirection through variable. + +Wed Feb 14 16:50:05 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c [!UX] + (orig_tty_state): New variable. + (init_termstate, restore_termstate): New hurd versions of these funcs. + * ux.c (init_termstate, restore_termstate, term_sgb, localbits): + Moved here from boot.c + +Tue Feb 13 18:49:26 1996 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (load_image, boot_script_read_file, main): Use O_RDONLY, + not 0 (kind of ironic, this...). + (load_image): Give the filename with the error message (and a newline). + + * ux.h (O_RDONLY, O_WRONLY, O_RDWR): New macros. + + * ux.c, ux.h: New files. + * boot.c: Move all the ux-specific grot into ux.c & ux.h. + If UX is defined, include "ux.h", else define hurdish stuff. + (main): Use get_privileged_ports instead of task_by_pid. + (load_image, boot_script_read_file, main, do_mach_notify_no_senders, + do_mach_notify_dead_name): Use host_exit instead of uxexit. + (boot_script_read_file): Use host_stat instead of uxstat. + (init_termstate, S_tioctl_tiocseta): Use sg_flags fld in struct sgttyb. + + * Makefile (all): Depend on `boot' and `uxboot'. + (COMMON-OBJS, UX-OBJS): New macros. + (OBJS): Inherit most names from $(COMMON-OBJS). + (LCLHDRS): Add ux.h. + (LDFLAGS): Use target-specific value. + (uxboot.0-LDFLAGS): New macro (with contents from old LDFLAGS). + (uxboot.o, uxboot.0): New targets. + (uxboot): Target renamed from boot.a. + +Sun Dec 10 18:05:14 1995 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (read_reply): Don't call clear_should_read(), just do + things ourselves. + (should_read_lock): Variable deleted. + (service_sigio): Function deleted. + (main): Use read_reply to service SIGIO again, not service_sigio. + + * boot.c (service_sigio): New function, replacing set_should_read. + Calls read_reply() itself too. + (unlock_readlock): New function. + (ds_device_read, ds_device_read_inband, S_io_read): Call + unlock_readlock instead of directly unlocking READLOCK. + (request_server, main): Don't call read_reply() anymore. + + * boot.c (should_read): New variable. + (main): SIGIO uses set_should_read instead of read_reply. + Call read_reply() after sigpause() returns. + (read_reply): Call clear_should_read(), and don't do anything if + SHOULD_READ wasn't set. + (set_should_read): New function. + (clear_should_read): New function. + (request_server): Call read_reply() before returning. + +Sat Dec 9 19:01:10 1995 Miles Bader <miles@gnu.ai.mit.edu> + + * boot.c (S_io_read, ds_device_read_inband, ds_device_read): Don't + block SIGIO. + (main): Don't trap SIGMSG & SIGEMSG. + +Mon Dec 4 23:54:18 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (main): Request no-senders notification on + pseudo_master_device_port. + Deallocate our send right to it when we no longer need it. + (do_mach_notify_no_senders): Exit only when both pseudo_console and + pseudo_master_device_port have no senders. + (ds_device_read_inband): Unlock readlock properly. + +Thu Nov 30 15:58:47 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> + + * boot.c (readlock): New variable. + (read_reply): Check FIONREAD before dequeueing QR so that we don't + abandon requests. Lock READLOCK around FIONREAD/read pair. + (ds_device_read): Lock READLOCK around FIONREAD/read pair. + (ds_device_read_inband): Likewise. + (S_io_read): Likewise. + +Nov 22 16:25:01 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (request_server): Don't call exec_server. + (S_exec_*): Functions removed. + (boot_script_task_port): Variable removed. + (boot_script_task_*, boot_script_port_*): Functions removed. + +Tue Nov 14 12:07:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (OBJS): Remove execServer.o. + +Thu Sep 28 14:47:46 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot_script.c (read_file): Pass CMD->path for file name. + (CHECK_CMDLINE_LEN): Update ARGV pointers after reallocating the line + buffer. + +Wed Sep 27 14:01:03 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (struct uxstat): New type. + (uxfstat): Renamed from fstat; use struct uxstat * for arg. + (boot_script_read_file): Use those. + Return the memory object port, not zero. + + * boot.c (fstat): New syscall function. + + * boot_script.c (read_file): New function. + (builtin_symbols): Add $(read-file) builtin. + * boot_script.h (boot_script_read_file): Declare it. + * boot.c (close): New syscall function. + (defpager): New variable. + (main): Set it up. + (boot_script_read_file): New function. + (useropen_dir): New variable. + (useropen): New function. + (load_image): Call it instead of open. + (main): Grok -D arg to set useropen_dir. + +Sat Sep 23 00:53:51 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * syscall.S: Restore entry SP before return. + + * boot.c (main): Use static const for constant strings. + On boot script error, write script line with error msg. + + * boot_script.c (boot_script_parse_line): Ignore line beginning + with #. + + * boot.c (S_io_pathconf): New function. + + * Makefile (LDFLAGS): Add -static. + +Fri Sep 22 14:14:23 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * mach-crt0.c (__data_start): New variable. + +Tue Aug 29 10:41:29 1995 Michael I. Bushnell, p/BSG <mib@duality.gnu.ai.mit.edu> + + * boot.c (mig_dealloc_reply_port): Remove __ from call to + mach_port_mod_refs. + (main): Look for -d in bootstrap_args, not (nonexistent) + boot_args. Remove `const' keyword from decl of MSG. + + * boot.c (sigblock, sigsetmask): New functions. + (sigmask): New macro. + (ds_device_read): Block SIGIO around critical section. + (ds_device_read_inband): Likewise. + (S_io_read): Likewise. + +Mon Aug 28 17:16:48 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot_script.h, boot_script.c: Updated by Shantanu Goel, to + accept action keywords only inside $(...) and only variable values + inside ${...}. + * boot.c: Updated for changes in boot_script.h protocol by + Shantanu Goel. + (main): Use boot_script_set_variable instead of magic variables. + Under -d, pause between parsing bootscript and executing it. + +Wed Aug 23 16:08:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + New script-driven boot mechanism, mostly implemented by Shantanu Goel. + * Makefile (SRCS): Add boot_script.c. + (OBJS): Add boot_script.o. + (LCLHDRS): New variable. + (HURDLIBS): Variable removed. + (boot): Depend on ../libthreads/libthreads.a. + * boot_script.c, boot_script.h: New files. + * boot.c (boot_like_kernel, boot_like_cmudef, boot_like_hurd): + Variables removed. + (main): Don't interpret switches. Instead of servers, take + command line argument of boot script file name. Read the file and + use boot_script functions to parse and execute its directives. + (boot_script_*): New variables and functions for boot_script callbacks. + +Sun Jul 30 23:50:53 1995 Michael I. Bushnell, p/BSG <mib@geech.gnu.ai.mit.edu> + + * Makefile: DISTFILES -> DIST_FILES. + +Sat Jul 8 11:37:32 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> + + * boot.c (free_reply_ports, free_reply_ports_lock): New variables. + (__mig_get_reply_port, __mig_put_reply_port, __mig_dealloc_reply_port, + mig_get_reply_port, mig_put_reply_port, mig_dealloc_reply_port): + Provide better versions of these routines that won't leak reply ports. + +Fri Jul 7 15:55:18 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> + + * mach-crt0.c: New file, from mach4-i386/libmach/standalone. + * boot.c (mach_init_routine): New variable, wanted by mach-crt0.o. + (__mig_get_reply_port, __mig_dealloc_reply_port, __mig_put_reply_port): + New functions, to avoid using hurdish versions. + * Makefile (OBJS): Add mach-crt0.o. + (SRCS): Add mach-crt0.c. + (LDFLAGS): Add -nostartfiles (as we now use mach-crt0.o). + +Thu Jul 6 15:30:18 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * Makefile (boot.1, boot.a): Use $(LD) and $(OBJCOPY) instead of + explicit names. + + * boot.c: Include <mach/mig_support.h>. + (S_io_reauthenticate): Cast first arg to mig_deallocate. + (load_image): Cast second arg to read. + * tcattr.c: Undo last change; add private decl of ioctl. + + * boot.c (bootdevice): Initialize to hard-coded `sd0a' instead of + DEFAULT_BOOTDEVICE. + + * Makefile (all): Depend on boot.a too. + + * Makefile: Removed dependencies that are now automatically + generated. + +Wed May 31 10:02:11 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (DISTFILES): New variable; include frank1.ld and + frankemul.ld. + (CPPFLAGS): Variable removed. + (LDFLAGS): Append -T frank1.ld. + (boot.1, boot.a): New targets. + + * syscall.S: Omit .globl decl for errno; it caused some as + complaint. + +Mon May 22 11:48:58 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> + + * sigvec.S: Remove copyright notice. + +Wed May 17 13:10:27 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> + + * boot.c (load_image): Make sure we actually allocate enough + memory to read into, including the offset into the buffer at which + the segment is read. + + * sigvec.S (sigreturn, _sigreturn, sigvec): Remove the explicit + underscore prefixes from these names, now that we're using elf. + Instead we use the various macros from <i386/asm.h>. Also, return + errors correctly. [Also added a copyright notice] + +Sat May 13 03:37:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (load_image): Fixed alignment calculation in ELF segment + loading. + + * syscall.S: Include i386/asm.h and use ENTRY and EXT macros, + instead of explicit _s. + +Fri May 12 18:36:39 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (load_image): Grok ELF executables as well as a.out. + (main): Load multiple servers. Suspend all but the first. + The first gets an extra arg, its name for the task port of the + second. + +Wed Apr 12 09:18:50 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> + + * Makefile: Don't try and install boot in /usr/local/bin. + +Wed Apr 5 17:25:19 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c: Don't include <errno.h>. Define `errno' variable. + * Makefile (SRCS): Add syscall.S. + (OBJS): Add syscall.o. + * syscall.S: Check for errors. + +Thu Jan 19 01:21:24 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (S_io_select): Updated to new io_select protocol. + +Fri Dec 9 01:23:22 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c: Use mach_msg_type_number_t in place of unsigned int and + int. + +Fri Nov 11 14:05:43 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu> + + * boot.c (main): Always set `f' flag (signifying "fake" because we + aren't a real native bootstrap). + +Thu Nov 3 17:26:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * Makefile (boot.o): Depend on bootstrap_S.h. + +Fri Oct 28 17:08:12 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * boot.c (main): Create the thread before setting it up. + (bootstrap_compat): Make a send right for psuedo_master_device_port. + (main): Explicitly clear NEWTASK's bootstrap port for boot_like_kernel. + (main): Format strings for port names for boot_like_kernel. + +Fri Oct 28 15:26:48 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu> + + * boot.c (boot_like_kernel, boot_like_cmudef, boot_like_hurd): New + global vars. + (set_mach_stack_args): New function. + (main): If the -k flag is given, set BOOT_LIKE_KERNEL. + If the -p flag is given, set BOOT_LIKE_CMUDEF. If neither is + given, set BOOT_LIKE_HURD. + Only set a bootstrap port if BOOT_LIKE_CMUDEF or BOOT_LIKE_HURD. + If BOOT_LIKE_KERNEL or BOOT_LIKE_CMUDEF, set up the stack the + Mach way using set_mach_stack_args. + (request_server): Declare and call bootstrap_server. + (do_bootstrap_priveleged_ports, bootstrap_compat): New functions. + * Makefile (OBJS): Require bootstrapServer.o. + * bootstrap.defs: New file. + +Tue Aug 30 11:41:33 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * boot.c (S_io_reauthenticate): Use new authentication protocol. + +Mon Aug 22 13:43:32 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * boot.c: Include <cthreads.h>. + (main): Run msg_thread fork; don't call + mach_msg_server_timeout here. Use sigpause instead of getpid. + (msg_thread): New function. + (queuelock): New variable. + (queue_read): Acquire queuelock. + (read_reply): Acquire queuelock. + * Makefile (HURDLIBS): New var to get threads. + +Thu Aug 18 18:04:36 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * boot.c (restore_termstate): New function. + (do_mach_notify_no_senders): Call restore_termstate before exiting. + + * boot.c (main): New var `usagemsg'; print it if args are wrong. + Allow flags and disk device to be given on command line. + New var `bootfile'. + (bootdevice, bootstrap_args): New vars. + (load_image): Exit nicely if the startup file can't be found. + (S_exec_startup): Use `bootdevice' instead of hardcoded name. + Use `bootstrap_args' instead of hardcoded "-x". + (main): Only do `pausing' hack if -d was provided. + + * Makefile (CPPFLAGS): Define DEFAULT_BOOTDEVICE. + + * Makefile (/usr/local/bin/boot): Depend on boot. + + * boot.c (S_termctty_open_terminal): New "function". + (S_io_select): Added `rettype' arg. + +Sat Jul 23 02:58:05 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> + + * Makefile (io-MIGSFLAGS): Renamed from ioMIGSFLAGS. + +Fri Jul 22 15:10:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * boot.c (request_server): Remove S_ from io_server and + term_server. + +Thu Jul 21 19:00:36 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * Makefile: Rewritten to use new scheme. + * boot.c: Include io_reply_U.h and device_reply_U.h instead + of io_repl.h and device_reply.h. + +Wed Jul 20 13:19:45 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> + + * boot.c: Comment out bits relating to tioctl interface. + * Makefile: Likewise. + +Tue Jul 19 12:41:46 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * Makefile (boot): Don't use variable $(link) anymore. + +Tue Jul 5 14:19:36 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * Makefile (SRCS): New variable. + +Sun Jul 3 17:20:07 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * tcattr.c: New file. + * boot.c (S_tioctl_tiocgeta): Call tcgetattr. + (S_tioctl_tiocseta): Call tcsetattr. + * Makefile (OBJS): Add tcattr.o. + (DIST_FILES): Add tcattr.c. + +Fri Jul 1 11:16:27 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * boot.c (init_termstate): Enter raw mode here. + +Fri Jun 24 14:27:56 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * boot.c (S_term_open_ctty): Renamed from term_become_ctty. + Deleted SIGPT arg. Add msg type arg for NEWTTY. + +Fri Jun 17 13:46:07 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * boot.c (request_server): Remove S_ prefix from exec_server + and notify_server. + +Fri Jun 17 00:12:16 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Makefile (boot.o): Depend on term_S.h. + +Tue Jun 14 01:28:10 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * boot.c (request_server): Add S_ prefix to demuxer functions. + +Wed Jun 8 18:02:19 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * boot.c (S_tioctl_tiocseta): Turn off ECHO. + (S_io_select): Implement. + +Tue Jun 7 04:33:42 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Makefile (tioctlServer.o): Depend on ../hurd/ioctl_types.h. + +Mon Jun 6 20:33:39 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * boot.c (authserver): New variable. + (S_io_reauthenticate): Do auth_server_authenticate and throw away + the returned info. + (S_exec_init): Set authserver to the passed port. + +Sat Jun 4 02:32:03 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * boot.c: Include term_S.h and tioctl_S.h. + (S_term_getctty): New function. + (S_term_*): Stub functions. + (request_server): Use S_term_server. + + * Makefile (termServer.c term_S.h): New rule. + (OBJS): Add termServer.o. + + * boot.c (S_exec_setexecdata, S_exec_exec): Fix prototypes. + +Tue May 17 18:44:29 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * boot.c (ds_device_write): DATA arg is char *; don't dereference + it in call to write. + +Mon May 16 14:34:15 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * boot.c (fsname): New variable. + (main): Set fsname to argv[1]. + (S_exec_startup): Include fsname in child's argv[0]. + + * boot.c (init_termstate): Add forward declaration. + (struct sigvec): Make SV_HANDLER member void (*)(). + (sigvec): Add declaration to avoid warning. + +Tue May 10 18:14:39 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * boot.c (tioctl_tiocseta, tioctl_tiocsetw, tioctl_tiocsetf, + tioctl_tiocgeta, init_termstate): New functions. + (term_modes, term_ccs, term_speeds, term_sgb, localbits): Nev + vars. + Also added new bits from ioctl.h. + (main): Call init_termstate. + (request_server): Call tioctl_server. + * Makefile (tioctlServer.c tioctl_S.h): New targets. + (OBJS): Include tioctlServer.o. + (boot.o): Depend on tioctl_S.h + +Fri May 6 13:56:58 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * boot.c (main): Restore braindamage of yesterday relating to + signals; that is, restore declaration of VEC and calls to sigvec. + * Makefile (DIST_FILES): Add sigvec.S. + +Thu May 5 13:16:42 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * Makefile (device_replyUser.c): Mention that this build + device_reply.h as well. + (boot.o): Add dependency on device_reply.h and io_repl.h. + + * boot.c: Include <stdlib.h> for malloc and free prototypes. + Include <string.h> for bcopy and bzero prototypes. + Include <stdio.h> for sprintf prototype. + Include "device_reply.h" for its prototypes. + Include "io_reply.h" for its prototypes. + Declare return type for all the server functions that were lacking + such. + (sigpause): Declare type of MASK. + (ioctl): Declare third arg to be generic pointer, not char *. + (request_server): Declare MiG functions we call. + (load_image): Delete unused variable STACKADDR. + (main): Comment out declaration of VEC. + Comment out calls to sigvec. + Cast STARTPC in call to __mach_setup_thread. + Delete unused variable TIMEOUT. + (read_reply): Cast BUF correctly in call to ds_device_read_reply. + (S_exec_startup): Delete unused variable DTABLE. + (ds_device_write): Double cast arg to write to avoid warning. + (S_io_read): Order args to vm_allocate properly; cast DATA arg. + Check *datalen properly for unsigned type. + + * boot.c: Renamed _exit to uxexit to avoid library name clash. + (do_mach_notify_dead_name, do_mach_notify_no_senders): + Call uxexit instead of _exit. + + * boot.c (S_io_async, S_io_get_icky_async_id, S_io_map_cntl): + Expect new type arg for returned port. + (S_io_prenotify, S_io_postnotify): START and END args are now + vm_offset_t. + + * boot.c: Change error_t to kern_return_t because error_t + is now unsigned and conflicts with MiG's use of kern_return_t. + + * Makefile (io_S.h, ioServer.c): Punt mungio hack; use + -DREPLY_PORTS. + * boot.c: Changed all io server stubs to expect reply ports. + + * mungio: removed file. + * Makefile (DIST_FILES): Removed mungio. + + * boot.c (load_image): Only read from the image file the actual + amount being read, not that amount rounded to the nearest page. + Otherwise, the first bit of the BSS will not be zero, but will be + whatever is in the front of the symbol section of the a.out. + +Thu May 5 07:43:06 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Makefile: Change uses of $(headers) to $(includedir). + +Mon May 2 16:47:49 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * boot.c (S_io_readable): Implement io_readable fully. + +Fri Apr 1 17:55:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Makefile (OBJS): Remove boot_machdep.o. diff --git a/boot/Makefile b/boot/Makefile new file mode 100644 index 00000000..37593f68 --- /dev/null +++ b/boot/Makefile @@ -0,0 +1,54 @@ +# Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the GNU Hurd; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +dir := boot +makemode := utility + +SRCS = mach-crt0.c boot.c ux.c sigvec.S syscall.S boot_script.c +COMMON-OBJS = notifyServer.o ourdeviceServer.o \ + ioServer.o io_replyUser.o device_replyUser.o \ + termServer.o bootstrapServer.o boot_script.o +OBJS = boot.o $(COMMON-OBJS) +UX-OBJS = mach-crt0.o uxboot.o sigvec.o syscall.o ux.o $(COMMON-OBJS) +LCLHDRS = boot_script.h ux.h +target = boot +io-MIGSFLAGS=-DREPLY_PORTS +DIST_FILES=frank1.ld frankemul.ld +HURDLIBS=store shouldbeinlibc threads + +include ../Makeconf + +#install: /usr/local/bin/uxboot +# +#/usr/local/bin/uxboot: uxboot +# cp $< $@ + +all: boot # uxboot + +ourdevice.defs: device.defs + $(CPP) $(CPPFLAGS) -x c $< | sed -e '/out device : device_t/s/device_t/mach_port_send_t/' > $@ + + +uxboot.o: boot.c + $(COMPILE.c) -DUX $< -o $@ + +uxboot.0: $(UX-OBJS) ../libthreads/libthreads.a + $(LINK.o) -o $@ -static -nostartfiles -Wl,-T -Wl,$(srcdir)/frank1.ld $^ +uxboot.1: frankemul.ld uxboot.0 + $(LD) -o $@ -T $^ +uxboot: uxboot.1 + -$(OBJCOPY) -S --remove-section=.comment -O a.out-mach3 $< $@ diff --git a/boot/boot.c b/boot/boot.c new file mode 100644 index 00000000..859dae25 --- /dev/null +++ b/boot/boot.c @@ -0,0 +1,1964 @@ +/* Load a task using the single server, and then run it + as if we were the kernel. + Copyright (C) 1993,94,95,96,97,98,99 Free Software Foundation, Inc. + +This file is part of the GNU Hurd. + +The GNU Hurd is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU Hurd is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by Michael I. Bushnell. */ + +#include <mach.h> +#include <mach/notify.h> +#include <device/device.h> +#include <a.out.h> +#include <mach/message.h> +#include <mach/mig_errors.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <cthreads.h> +#include <fcntl.h> +#include <elf.h> +#include <mach/mig_support.h> +#include <mach/default_pager.h> +#include <argp.h> +#include <hurd/store.h> +#include <sys/mman.h> + +#include "notify_S.h" +#include "exec_S.h" +#include "ourdevice_S.h" +#include "io_S.h" +#include "device_reply_U.h" +#include "io_reply_U.h" +#include "term_S.h" +#include "bootstrap_S.h" +/* #include "tioctl_S.h" */ + +#include "boot_script.h" + +#include <hurd/auth.h> + +#ifdef UX +#undef STORE /* We can't use libstore when under UX. */ +#else +#define STORE +#endif + +#ifdef UX + +#include "ux.h" + +#else /* !UX */ + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <termios.h> +#include <error.h> +#include <hurd.h> + +static struct termios orig_tty_state; +static int isig; + +static void +init_termstate () +{ + struct termios tty_state; + + if (tcgetattr (0, &tty_state) < 0) + error (10, errno, "tcgetattr"); + + orig_tty_state = tty_state; + cfmakeraw (&tty_state); + if (isig) + tty_state.c_lflag |= ISIG; + + if (tcsetattr (0, 0, &tty_state) < 0) + error (11, errno, "tcsetattr"); +} + +static void +restore_termstate () +{ + tcsetattr (0, 0, &orig_tty_state); +} + +#define host_fstat fstat +typedef struct stat host_stat_t; +#define host_exit exit + +#endif /* UX */ + +mach_port_t privileged_host_port, master_device_port, defpager; +mach_port_t pseudo_master_device_port; +mach_port_t receive_set; +mach_port_t pseudo_console, pseudo_root; +auth_t authserver; + +struct store *root_store; + +spin_lock_t queuelock = SPIN_LOCK_INITIALIZER; +spin_lock_t readlock = SPIN_LOCK_INITIALIZER; + +mach_port_t php_child_name, psmdp_child_name, taskname; + +task_t child_task; +mach_port_t bootport; + +int console_mscount; + +vm_address_t fs_stack_base; +vm_size_t fs_stack_size; + +void init_termstate (); +void restore_termstate (); + +char *fsname; + +char bootstrap_args[100] = "-"; +char *bootdevice = 0; +char *bootscript = 0; + +void set_mach_stack_args (task_t, thread_t, char *, ...); + +void safe_gets (char *buf, int buf_len) +{ + fgets (buf, buf_len, stdin); +} + +char *useropen_dir; + +int +useropen (const char *name, int flags, int mode) +{ + if (useropen_dir) + { + static int dlen; + if (!dlen) dlen = strlen (useropen_dir); + { + int len = strlen (name); + char try[dlen + 1 + len + 1]; + int fd; + memcpy (try, useropen_dir, dlen); + try[dlen] = '/'; + memcpy (&try[dlen + 1], name, len + 1); + fd = open (try, flags, mode); + if (fd >= 0) + return fd; + } + } + return open (name, flags, mode); +} + +int +request_server (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + extern int io_server (mach_msg_header_t *, mach_msg_header_t *); + extern int device_server (mach_msg_header_t *, mach_msg_header_t *); + extern int notify_server (mach_msg_header_t *, mach_msg_header_t *); + extern int term_server (mach_msg_header_t *, mach_msg_header_t *); +/* extern int tioctl_server (mach_msg_header_t *, mach_msg_header_t *); */ + extern int bootstrap_server (mach_msg_header_t *, mach_msg_header_t *); + extern void bootstrap_compat (); + +#if 0 + if (inp->msgh_local_port == bootport && boot_like_cmudef) + { + if (inp->msgh_id == 999999) + { + bootstrap_compat (inp, outp); + return 1; + } + else + return bootstrap_server (inp, outp); + } + else +#endif + return (io_server (inp, outp) + || device_server (inp, outp) + || notify_server (inp, outp) + || term_server (inp, outp) + /* || tioctl_server (inp, outp) */); +} + +vm_address_t +load_image (task_t t, + char *file) +{ + int fd; + union + { + struct exec a; + Elf32_Ehdr e; + } hdr; + char msg[] = ": cannot open bootstrap file\n"; + + fd = useropen (file, O_RDONLY, 0); + + if (fd == -1) + { + write (2, file, strlen (file)); + write (2, msg, sizeof msg - 1); + task_terminate (t); + host_exit (1); + } + + read (fd, &hdr, sizeof hdr); + if (*(Elf32_Word *) hdr.e.e_ident == *(Elf32_Word *) "\177ELF") + { + Elf32_Phdr phdrs[hdr.e.e_phnum], *ph; + lseek (fd, hdr.e.e_phoff, SEEK_SET); + read (fd, phdrs, sizeof phdrs); + for (ph = phdrs; ph < &phdrs[sizeof phdrs/sizeof phdrs[0]]; ++ph) + if (ph->p_type == PT_LOAD) + { + vm_address_t buf; + vm_size_t offs = ph->p_offset & (ph->p_align - 1); + vm_size_t bufsz = round_page (ph->p_filesz + offs); + + buf = (vm_address_t) mmap (0, bufsz, + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + + lseek (fd, ph->p_offset, SEEK_SET); + read (fd, (void *)(buf + offs), ph->p_filesz); + + ph->p_memsz = ((ph->p_vaddr + ph->p_memsz + ph->p_align - 1) + & ~(ph->p_align - 1)); + ph->p_vaddr &= ~(ph->p_align - 1); + ph->p_memsz -= ph->p_vaddr; + + vm_allocate (t, (vm_address_t*)&ph->p_vaddr, ph->p_memsz, 0); + vm_write (t, ph->p_vaddr, buf, bufsz); + munmap ((caddr_t) buf, bufsz); + vm_protect (t, ph->p_vaddr, ph->p_memsz, 0, + ((ph->p_flags & PF_R) ? VM_PROT_READ : 0) | + ((ph->p_flags & PF_W) ? VM_PROT_WRITE : 0) | + ((ph->p_flags & PF_X) ? VM_PROT_EXECUTE : 0)); + } + return hdr.e.e_entry; + } + else + { + /* a.out */ + int magic = N_MAGIC (hdr.a); + int headercruft; + vm_address_t base = 0x10000; + int rndamount, amount; + vm_address_t bsspagestart, bssstart; + char *buf; + + headercruft = sizeof (struct exec) * (magic == ZMAGIC); + + amount = headercruft + hdr.a.a_text + hdr.a.a_data; + rndamount = round_page (amount); + buf = mmap (0, rndamount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + lseek (fd, sizeof hdr.a - headercruft, SEEK_SET); + read (fd, buf, amount); + vm_allocate (t, &base, rndamount, 0); + vm_write (t, base, (u_int) buf, rndamount); + if (magic != OMAGIC) + vm_protect (t, base, trunc_page (headercruft + hdr.a.a_text), + 0, VM_PROT_READ | VM_PROT_EXECUTE); + munmap ((caddr_t) buf, rndamount); + + bssstart = base + hdr.a.a_text + hdr.a.a_data + headercruft; + bsspagestart = round_page (bssstart); + vm_allocate (t, &bsspagestart, + hdr.a.a_bss - (bsspagestart - bssstart), 0); + + return hdr.a.a_entry; + } +} + + +void read_reply (); +void msg_thread (); + +/* Callbacks for boot_script.c; see boot_script.h. */ + +void * +boot_script_malloc (int size) +{ + return malloc (size); +} + +void +boot_script_free (void *ptr, int size) +{ + free (ptr); +} + +mach_port_t +boot_script_read_file (const char *filename) +{ + static const char msg[] = ": cannot open\n"; + int fd = useropen (filename, O_RDONLY, 0); + host_stat_t st; + error_t err; + mach_port_t memobj; + vm_address_t region; + + write (2, filename, strlen (filename)); + if (fd < 0) + { + write (2, msg, sizeof msg - 1); + host_exit (1); + } + else + write (2, msg + sizeof msg - 2, 1); + + host_fstat (fd, &st); + + err = default_pager_object_create (defpager, &memobj, + round_page (st.st_size)); + if (err) + { + static const char msg[] = "cannot create default-pager object\n"; + write (2, msg, sizeof msg - 1); + host_exit (1); + } + + region = 0; + vm_map (mach_task_self (), ®ion, round_page (st.st_size), + 0, 1, memobj, 0, 0, VM_PROT_ALL, VM_PROT_ALL, VM_INHERIT_NONE); + read (fd, (char *) region, st.st_size); + munmap ((caddr_t) region, round_page (st.st_size)); + + close (fd); + return memobj; +} + +int +boot_script_exec_cmd (mach_port_t task, char *path, int argc, + char **argv, char *strings, int stringlen) +{ + char *args, *p; + int arg_len, i; + unsigned reg_size; + void *arg_pos; + vm_offset_t stack_start, stack_end; + vm_address_t startpc, str_start; + thread_t thread; + struct i386_thread_state regs; + + write (2, path, strlen (path)); + for (i = 1; i < argc; ++i) + { + write (2, " ", 1); + write (2, argv[i], strlen (argv[i])); + } + write (2, "\r\n", 2); + + startpc = load_image (task, path); + thread_create (task, &thread); + arg_len = stringlen + (argc + 2) * sizeof (char *) + sizeof (integer_t); + arg_len += 5 * sizeof (int); + stack_end = VM_MAX_ADDRESS; + stack_start = VM_MAX_ADDRESS - 16 * 1024 * 1024; + vm_allocate (task, &stack_start, stack_end - stack_start, FALSE); + reg_size = i386_THREAD_STATE_COUNT; + thread_get_state (thread, i386_THREAD_STATE, + (thread_state_t) ®s, ®_size); + regs.eip = (int) startpc; + regs.uesp = (int) ((stack_end - arg_len) & ~(sizeof (int) - 1)); + thread_set_state (thread, i386_THREAD_STATE, + (thread_state_t) ®s, reg_size); + arg_pos = (void *) regs.uesp; + args = mmap (0, stack_end - trunc_page ((vm_offset_t) arg_pos), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + str_start = ((vm_address_t) arg_pos + + (argc + 2) * sizeof (char *) + sizeof (integer_t)); + p = args + ((vm_address_t) arg_pos & (vm_page_size - 1)); + *((int *) p)++ = argc; + for (i = 0; i < argc; i++) + *((char **) p)++ = argv[i] - strings + (char *) str_start; + *((char **) p)++ = 0; + *((char **) p)++ = 0; + memcpy (p, strings, stringlen); + bzero (args, (vm_offset_t) arg_pos & (vm_page_size - 1)); + vm_write (task, trunc_page ((vm_offset_t) arg_pos), (vm_address_t) args, + stack_end - trunc_page ((vm_offset_t) arg_pos)); + munmap ((caddr_t) args, + stack_end - trunc_page ((vm_offset_t) arg_pos)); + thread_resume (thread); + mach_port_deallocate (mach_task_self (), thread); + return 0; +} + +static struct argp_option options[] = +{ + { "boot-root", 'D', "DIR", 0, + "Root of a directory tree in which to find files specified in BOOT-SCRIPT" }, + { "single-user", 's', 0, 0, + "Boot in single user mode" }, + { "pause" , 'd', 0, 0, + "Pause for user confirmation at various times during booting" }, + { "isig", 'I', 0, 0, + "Do not disable terminal signals, so you can suspend and interrupt boot."}, + { 0 } +}; +static char args_doc[] = "BOOT-SCRIPT"; +static char doc[] = "Boot a second hurd"; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + size_t len; + + case 'D': useropen_dir = arg; break; + + case 'I': isig = 1; break; + + case 's': case 'd': + len = strlen (bootstrap_args); + if (len >= sizeof bootstrap_args - 1) + argp_error (state, "Too many bootstrap args"); + bootstrap_args[len++] = key; + bootstrap_args[len] = '\0'; + break; + + case ARGP_KEY_ARG: + if (state->arg_num == 0) + bootscript = arg; + else + return ARGP_ERR_UNKNOWN; + break; + + case ARGP_KEY_INIT: + state->child_inputs[0] = state->input; break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +int +main (int argc, char **argv, char **envp) +{ + error_t err; + mach_port_t foo; + char *buf = 0; + int i, len; + char *root_store_name; + const struct argp_child kids[] = { { &store_argp }, { 0 }}; + struct argp argp = { options, parse_opt, args_doc, doc, kids }; + struct store_argp_params store_argp_params = { 0 }; + + argp_parse (&argp, argc, argv, 0, 0, &store_argp_params); + err = store_parsed_name (store_argp_params.result, &root_store_name); + if (err) + error (2, err, "store_parsed_name"); + + err = store_parsed_open (store_argp_params.result, 0, &root_store); + if (err) + error (4, err, "%s", root_store_name); + + get_privileged_ports (&privileged_host_port, &master_device_port); + + defpager = MACH_PORT_NULL; + vm_set_default_memory_manager (privileged_host_port, &defpager); + + strcat (bootstrap_args, "f"); + + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET, + &receive_set); + + if (root_store->class == &store_device_class && root_store->name + && (root_store->flags & STORE_ENFORCED) + && root_store->num_runs == 1 && root_store->runs[0].start == 0) + /* Let known device nodes pass through directly. */ + bootdevice = root_store->name; + else + /* Pass a magic value that we can use to do I/O to ROOT_STORE. */ + { + bootdevice = "pseudo-root"; + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + &pseudo_root); + mach_port_move_member (mach_task_self (), pseudo_root, receive_set); + } + + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + &pseudo_master_device_port); + mach_port_insert_right (mach_task_self (), + pseudo_master_device_port, + pseudo_master_device_port, + MACH_MSG_TYPE_MAKE_SEND); + mach_port_move_member (mach_task_self (), pseudo_master_device_port, + receive_set); + mach_port_request_notification (mach_task_self (), pseudo_master_device_port, + MACH_NOTIFY_NO_SENDERS, 1, + pseudo_master_device_port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo); + if (foo != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), foo); + + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, + &pseudo_console); + mach_port_move_member (mach_task_self (), pseudo_console, receive_set); + mach_port_request_notification (mach_task_self (), pseudo_console, + MACH_NOTIFY_NO_SENDERS, 1, pseudo_console, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo); + if (foo != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), foo); + + /* Initialize boot script variables. */ + if (boot_script_set_variable ("host-port", VAL_PORT, + (int) privileged_host_port) + || boot_script_set_variable ("device-port", VAL_PORT, + (int) pseudo_master_device_port) + || boot_script_set_variable ("root-device", VAL_STR, (int) bootdevice) + || boot_script_set_variable ("boot-args", VAL_STR, (int) bootstrap_args)) + { + static const char msg[] = "error setting variable"; + + write (2, msg, strlen (msg)); + host_exit (1); + } + + /* Parse the boot script. */ + { + char *p, *line; + static const char filemsg[] = "Can't open boot script\n"; + int amt, fd, err; + + fd = open (bootscript, O_RDONLY, 0); + if (fd < 0) + { + write (2, filemsg, sizeof (filemsg)); + host_exit (1); + } + p = buf = malloc (500); + len = 500; + amt = 0; + while (1) + { + i = read (fd, p, len - (p - buf)); + if (i <= 0) + break; + p += i; + amt += i; + if (p == buf + len) + { + char *newbuf; + + len += 500; + newbuf = realloc (buf, len); + p = newbuf + (p - buf); + buf = newbuf; + } + } + line = p = buf; + while (1) + { + while (p < buf + amt && *p != '\n') + p++; + *p = '\0'; + err = boot_script_parse_line (line); + if (err) + { + char *str; + int i; + + str = boot_script_error_string (err); + i = strlen (str); + write (2, str, i); + write (2, " in `", 5); + write (2, line, strlen (line)); + write (2, "'\n", 2); + host_exit (1); + } + if (p == buf + amt) + break; + line = ++p; + } + } + + if (index (bootstrap_args, 'd')) + { + static const char msg[] = "Pausing. . ."; + char c; + write (2, msg, sizeof (msg) - 1); + read (0, &c, 1); + } + + init_termstate (); + + /* The boot script has now been parsed into internal data structures. + Now execute its directives. */ + { + int err; + + err = boot_script_exec (); + if (err) + { + char *str = boot_script_error_string (err); + int i = strlen (str); + + write (2, str, i); + host_exit (1); + } + free (buf); + } + + mach_port_deallocate (mach_task_self (), pseudo_master_device_port); + + cthread_detach (cthread_fork ((cthread_fn_t) msg_thread, (any_t) 0)); + + for (;;) + { + fd_set rmask; + FD_ZERO (&rmask); + FD_SET (0, &rmask); + if (select (1, &rmask, 0, 0, 0) == 1) + read_reply (); + else + { /* We hosed */ + perror ("select"); + exit (5); + } + } + +/* mach_msg_server (request_server, __vm_page_size * 2, receive_set); */ +} + +/* Set up stack args the Mach way */ +void +set_mach_stack_args (task_t user_task, + thread_t user_thread, + char *startpc, ...) +{ + /* This code is lifted from .../mk/bootstrap/load.c. */ + va_list argv_ptr; + char * arg_ptr; + + int arg_len; + int arg_count; + char * arg_pos; + unsigned int arg_item_len; + + /* + * Calculate the size of the argument list. + */ + va_start(argv_ptr, startpc); + arg_len = 0; + arg_count = 0; + for (;;) { + arg_ptr = va_arg(argv_ptr, char *); + if (arg_ptr == (char *)0) + break; + arg_count++; + arg_len += strlen(arg_ptr) + 1; /* space for '\0' */ + } + va_end(argv_ptr); + /* + * Add space for: + * arg_count + * pointers to arguments + * trailing 0 pointer + * dummy 0 pointer to environment variables + * and align to integer boundary + */ + arg_len += sizeof(integer_t) + (2 + arg_count) * sizeof(char *); + arg_len = (arg_len + (sizeof(integer_t) - 1)) & ~(sizeof(integer_t)-1); + + + /* This small piece is from .../mk/bootstrap/i386/exec.c. */ + { + vm_offset_t stack_start; + vm_offset_t stack_end; + struct i386_thread_state regs; + unsigned int reg_size; + +#define STACK_SIZE (1024 * 1024 * 16) + + /* + * Add space for 5 ints to arguments, for + * PS program. XXX + */ + arg_len += 5 * sizeof(int); + + /* + * Allocate stack. + */ + stack_end = VM_MAX_ADDRESS; + stack_start = VM_MAX_ADDRESS - STACK_SIZE; + (void)vm_allocate(user_task, + &stack_start, + (vm_size_t)(stack_end - stack_start), + FALSE); + + reg_size = i386_THREAD_STATE_COUNT; + (void)thread_get_state(user_thread, + i386_THREAD_STATE, + (thread_state_t)®s, + ®_size); + + regs.eip = (int) startpc; + regs.uesp = (int)((stack_end - arg_len) & ~(sizeof(int)-1)); + + (void)thread_set_state(user_thread, + i386_THREAD_STATE, + (thread_state_t)®s, + reg_size); + + arg_pos = (void *) regs.uesp; + } + + /* + * Copy out the arguments. + */ + { + vm_offset_t u_arg_start; + /* user start of argument list block */ + vm_offset_t k_arg_start; + /* kernel start of argument list block */ + vm_offset_t u_arg_page_start; + /* user start of args, page-aligned */ + vm_size_t arg_page_size; + /* page_aligned size of args */ + vm_offset_t k_arg_page_start; + /* kernel start of args, page-aligned */ + + register + char ** k_ap; /* kernel arglist address */ + char * u_cp; /* user argument string address */ + register + char * k_cp; /* kernel argument string address */ + register + int i; + + /* + * Get address of argument list in user space + */ + u_arg_start = (vm_offset_t)arg_pos; + + /* + * Round to page boundaries, and allocate kernel copy + */ + u_arg_page_start = trunc_page(u_arg_start); + arg_page_size = (vm_size_t)(round_page(u_arg_start + arg_len) + - u_arg_page_start); + + k_arg_page_start = (vm_address_t) mmap (0, arg_page_size, + PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + + /* + * Set up addresses corresponding to user pointers + * in the kernel block + */ + k_arg_start = k_arg_page_start + (u_arg_start - u_arg_page_start); + + k_ap = (char **)k_arg_start; + + /* + * Start the strings after the arg-count and pointers + */ + u_cp = (char *)u_arg_start + arg_count * sizeof(char *) + + 2 * sizeof(char *) + + sizeof(integer_t); + k_cp = (char *)k_arg_start + arg_count * sizeof(char *) + + 2 * sizeof(char *) + + sizeof(integer_t); + + /* + * first the argument count + */ + *k_ap++ = (char *)(natural_t)arg_count; + + /* + * Then the strings and string pointers for each argument + */ + va_start(argv_ptr, startpc); + for (i = 0; i < arg_count; i++) { + arg_ptr = va_arg(argv_ptr, char *); + arg_item_len = strlen(arg_ptr) + 1; /* include trailing 0 */ + + /* set string pointer */ + *k_ap++ = u_cp; + + /* copy string */ + bcopy(arg_ptr, k_cp, arg_item_len); + k_cp += arg_item_len; + u_cp += arg_item_len; + } + va_end(argv_ptr); + + /* + * last, the trailing 0 argument and a null environment pointer. + */ + *k_ap++ = (char *)0; + *k_ap = (char *)0; + + /* + * Now write all of this to user space. + */ + (void) vm_write(user_task, + u_arg_page_start, + k_arg_page_start, + arg_page_size); + + (void) munmap ((caddr_t) k_arg_page_start, + arg_page_size); + } +} + + +void +msg_thread() +{ + while (1) + mach_msg_server (request_server, 0, receive_set); +} + + +enum read_type +{ + DEV_READ, + DEV_READI, + IO_READ, +}; +struct qr +{ + enum read_type type; + mach_port_t reply_port; + mach_msg_type_name_t reply_type; + int amount; + struct qr *next; +}; +struct qr *qrhead, *qrtail; + +/* Queue a read for later reply. */ +void +queue_read (enum read_type type, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int amount) +{ + struct qr *qr; + + spin_lock (&queuelock); + + qr = malloc (sizeof (struct qr)); + qr->type = type; + qr->reply_port = reply_port; + qr->reply_type = reply_type; + qr->amount = amount; + qr->next = 0; + if (qrtail) + qrtail->next = qr; + else + qrhead = qrtail = qr; + + spin_unlock (&queuelock); +} + +/* TRUE if there's data available on stdin, which should be used to satisfy + console read requests. */ +static int should_read = 0; + +/* Reply to a queued read. */ +void +read_reply () +{ + int avail; + struct qr *qr; + char * buf; + int amtread; + + /* By forcing SHOULD_READ to true before trying the lock, we ensure that + either we get the lock ourselves or that whoever currently holds the + lock will service this read when he unlocks it. */ + should_read = 1; + if (! spin_try_lock (&readlock)) + return; + + /* Since we're commited to servicing the read, no one else need do so. */ + should_read = 0; + + ioctl (0, FIONREAD, &avail); + if (!avail) + { + spin_unlock (&readlock); + return; + } + + spin_lock (&queuelock); + + if (!qrhead) + { + spin_unlock (&queuelock); + spin_unlock (&readlock); + return; + } + + qr = qrhead; + qrhead = qr->next; + if (qr == qrtail) + qrtail = 0; + + spin_unlock (&queuelock); + + if (qr->type == DEV_READ) + buf = mmap (0, qr->amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + else + buf = alloca (qr->amount); + amtread = read (0, buf, qr->amount); + + spin_unlock (&readlock); + + switch (qr->type) + { + case DEV_READ: + if (amtread >= 0) + ds_device_read_reply (qr->reply_port, qr->reply_type, 0, + (io_buf_ptr_t) buf, amtread); + else + ds_device_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0); + break; + + case DEV_READI: + if (amtread >= 0) + ds_device_read_reply_inband (qr->reply_port, qr->reply_type, 0, + buf, amtread); + else + ds_device_read_reply_inband (qr->reply_port, qr->reply_type, errno, + 0, 0); + break; + + case IO_READ: + if (amtread >= 0) + io_read_reply (qr->reply_port, qr->reply_type, 0, + buf, amtread); + else + io_read_reply (qr->reply_port, qr->reply_type, errno, 0, 0); + break; + } + + free (qr); +} + +/* Unlock READLOCK, and also service any new read requests that it was + blocking. */ +static void +unlock_readlock () +{ + spin_unlock (&readlock); + while (should_read) + read_reply (); +} + +/* + * Handle bootstrap requests. + */ +/* These two functions from .../mk/bootstrap/default_pager.c. */ + +kern_return_t +do_bootstrap_privileged_ports(bootstrap, hostp, devicep) + mach_port_t bootstrap; + mach_port_t *hostp, *devicep; +{ + *hostp = privileged_host_port; + *devicep = pseudo_master_device_port; + return KERN_SUCCESS; +} + +void +bootstrap_compat(in, out) + mach_msg_header_t *in, *out; +{ + mig_reply_header_t *reply = (mig_reply_header_t *) out; + mach_msg_return_t mr; + + struct imsg { + mach_msg_header_t hdr; + mach_msg_type_t port_desc_1; + mach_port_t port_1; + mach_msg_type_t port_desc_2; + mach_port_t port_2; + } imsg; + + /* + * Send back the host and device ports. + */ + + imsg.hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | + MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(in->msgh_bits), 0); + /* msgh_size doesn't need to be initialized */ + imsg.hdr.msgh_remote_port = in->msgh_remote_port; + imsg.hdr.msgh_local_port = MACH_PORT_NULL; + /* msgh_seqno doesn't need to be initialized */ + imsg.hdr.msgh_id = in->msgh_id + 100; /* this is a reply msg */ + + imsg.port_desc_1.msgt_name = MACH_MSG_TYPE_COPY_SEND; + imsg.port_desc_1.msgt_size = (sizeof(mach_port_t) * 8); + imsg.port_desc_1.msgt_number = 1; + imsg.port_desc_1.msgt_inline = TRUE; + imsg.port_desc_1.msgt_longform = FALSE; + imsg.port_desc_1.msgt_deallocate = FALSE; + imsg.port_desc_1.msgt_unused = 0; + + imsg.port_1 = privileged_host_port; + + imsg.port_desc_2 = imsg.port_desc_1; + + imsg.port_desc_2.msgt_name = MACH_MSG_TYPE_MAKE_SEND; + imsg.port_2 = pseudo_master_device_port; + + /* + * Send the reply message. + * (mach_msg_server can not do this, because the reply + * is not in standard format.) + */ + + mr = mach_msg(&imsg.hdr, MACH_SEND_MSG, + sizeof imsg, 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (mr != MACH_MSG_SUCCESS) + (void) mach_port_deallocate(mach_task_self (), + imsg.hdr.msgh_remote_port); + + /* + * Tell mach_msg_server to do nothing. + */ + + reply->RetCode = MIG_NO_REPLY; +} + +/* Implementation of device interface */ + +kern_return_t +ds_device_open (mach_port_t master_port, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + dev_mode_t mode, + dev_name_t name, + mach_port_t *device, + mach_msg_type_name_t *devicetype) +{ + if (master_port != pseudo_master_device_port) + return D_INVALID_OPERATION; + + if (!strcmp (name, "console")) + { +#if 0 + mach_port_insert_right (mach_task_self (), pseudo_console, + pseudo_console, MACH_MSG_TYPE_MAKE_SEND); + console_send_rights++; +#endif + console_mscount++; + *device = pseudo_console; + *devicetype = MACH_MSG_TYPE_MAKE_SEND; + return 0; + } + else if (strcmp (name, "pseudo-root") == 0) + /* Magic root device. */ + { + *device = pseudo_root; + *devicetype = MACH_MSG_TYPE_MAKE_SEND; + return 0; + } + + *devicetype = MACH_MSG_TYPE_MOVE_SEND; + return device_open (master_device_port, mode, name, device); +} + +kern_return_t +ds_device_close (device_t device) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return 0; +} + +kern_return_t +ds_device_write (device_t device, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + dev_mode_t mode, + recnum_t recnum, + io_buf_ptr_t data, + unsigned int datalen, + int *bytes_written) +{ + if (device == pseudo_console) + { +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + *bytes_written = write (1, data, datalen); + + return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS); + } + else if (device == pseudo_root) + return + (store_write (root_store, recnum, data, datalen, bytes_written) == 0 + ? D_SUCCESS + : D_IO_ERROR); + else + return D_NO_SUCH_DEVICE; +} + +kern_return_t +ds_device_write_inband (device_t device, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + dev_mode_t mode, + recnum_t recnum, + io_buf_ptr_inband_t data, + unsigned int datalen, + int *bytes_written) +{ + if (device == pseudo_console) + { +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + *bytes_written = write (1, data, datalen); + + return (*bytes_written == -1 ? D_IO_ERROR : D_SUCCESS); + } + else if (device == pseudo_root) + return + (store_write (root_store, recnum, data, datalen, bytes_written) == 0 + ? D_SUCCESS + : D_IO_ERROR); + else + return D_NO_SUCH_DEVICE; +} + +kern_return_t +ds_device_read (device_t device, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + dev_mode_t mode, + recnum_t recnum, + int bytes_wanted, + io_buf_ptr_t *data, + unsigned int *datalen) +{ + if (device == pseudo_console) + { + int avail; + +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + spin_lock (&readlock); + ioctl (0, FIONREAD, &avail); + if (avail) + { + *data = mmap (0, bytes_wanted, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + *datalen = read (0, *data, bytes_wanted); + unlock_readlock (); + return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS); + } + else + { + unlock_readlock (); + queue_read (DEV_READ, reply_port, reply_type, bytes_wanted); + return MIG_NO_REPLY; + } + } + else if (device == pseudo_root) + { + *datalen = 0; + return + (store_read (root_store, recnum, bytes_wanted, (void **)data, datalen) == 0 + ? D_SUCCESS + : D_IO_ERROR); + } + else + return D_NO_SUCH_DEVICE; +} + +kern_return_t +ds_device_read_inband (device_t device, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + dev_mode_t mode, + recnum_t recnum, + int bytes_wanted, + io_buf_ptr_inband_t data, + unsigned int *datalen) +{ + if (device == pseudo_console) + { + int avail; + +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + spin_lock (&readlock); + ioctl (0, FIONREAD, &avail); + if (avail) + { + *datalen = read (0, data, bytes_wanted); + unlock_readlock (); + return (*datalen == -1 ? D_IO_ERROR : D_SUCCESS); + } + else + { + unlock_readlock (); + queue_read (DEV_READI, reply_port, reply_type, bytes_wanted); + return MIG_NO_REPLY; + } + } + else if (device == pseudo_root) + { + error_t err; + void *returned = data; + + *datalen = bytes_wanted; + err = + store_read (root_store, recnum, bytes_wanted, (void **)&returned, datalen); + + if (! err) + { + if (returned != data) + { + bcopy (returned, (void *)data, *datalen); + munmap ((caddr_t) returned, *datalen); + } + return D_SUCCESS; + } + else + return D_IO_ERROR; + } + else + return D_NO_SUCH_DEVICE; +} + +kern_return_t +ds_xxx_device_set_status (device_t device, + dev_flavor_t flavor, + dev_status_t status, + u_int statu_cnt) +{ + if (device != pseudo_console) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + +kern_return_t +ds_xxx_device_get_status (device_t device, + dev_flavor_t flavor, + dev_status_t status, + u_int *statuscnt) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + +kern_return_t +ds_xxx_device_set_filter (device_t device, + mach_port_t rec, + int pri, + filter_array_t filt, + unsigned int len) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + +kern_return_t +ds_device_map (device_t device, + vm_prot_t prot, + vm_offset_t offset, + vm_size_t size, + memory_object_t *pager, + int unmap) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + +kern_return_t +ds_device_set_status (device_t device, + dev_flavor_t flavor, + dev_status_t status, + unsigned int statuslen) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + +kern_return_t +ds_device_get_status (device_t device, + dev_flavor_t flavor, + dev_status_t status, + unsigned int *statuslen) +{ + if (device == pseudo_console) + return D_INVALID_OPERATION; + else if (device == pseudo_root) + if (flavor == DEV_GET_SIZE) + if (*statuslen != DEV_GET_SIZE_COUNT) + return D_INVALID_SIZE; + else + { + status[DEV_GET_SIZE_DEVICE_SIZE] = root_store->size; + status[DEV_GET_SIZE_RECORD_SIZE] = root_store->block_size; + return D_SUCCESS; + } + else + return D_INVALID_OPERATION; + else + return D_NO_SUCH_DEVICE; +} + +kern_return_t +ds_device_set_filter (device_t device, + mach_port_t receive_port, + int priority, + filter_array_t filter, + unsigned int filterlen) +{ + if (device != pseudo_console && device != pseudo_root) + return D_NO_SUCH_DEVICE; + return D_INVALID_OPERATION; +} + + +/* Implementation of notify interface */ +kern_return_t +do_mach_notify_port_deleted (mach_port_t notify, + mach_port_t name) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_msg_accepted (mach_port_t notify, + mach_port_t name) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_port_destroyed (mach_port_t notify, + mach_port_t port) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_no_senders (mach_port_t notify, + mach_port_mscount_t mscount) +{ + static int no_console; + mach_port_t foo; + if (notify == pseudo_master_device_port) + { + if (no_console) + goto bye; + pseudo_master_device_port = MACH_PORT_NULL; + return 0; + } + if (notify == pseudo_console) + { + if (mscount == console_mscount && + pseudo_master_device_port == MACH_PORT_NULL) + { + bye: + restore_termstate (); + write (2, "bye\n", 4); + host_exit (0); + } + else + { + no_console = (mscount == console_mscount); + + mach_port_request_notification (mach_task_self (), pseudo_console, + MACH_NOTIFY_NO_SENDERS, + console_mscount == mscount + ? mscount + 1 + : console_mscount, + pseudo_console, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo); + if (foo != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), foo); + } + } + + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_send_once (mach_port_t notify) +{ + return EOPNOTSUPP; +} + +kern_return_t +do_mach_notify_dead_name (mach_port_t notify, + mach_port_t name) +{ +#if 0 + if (name == child_task && notify == bootport) + host_exit (0); +#endif + return EOPNOTSUPP; +} + + +/* Implementation of the Hurd I/O interface, which + we support for the console port only. */ + +kern_return_t +S_io_write (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + char *data, + mach_msg_type_number_t datalen, + off_t offset, + mach_msg_type_number_t *amtwritten) +{ + if (object != pseudo_console) + return EOPNOTSUPP; + +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + *amtwritten = write (1, data, datalen); + return *amtwritten == -1 ? errno : 0; +} + +kern_return_t +S_io_read (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + char **data, + mach_msg_type_number_t *datalen, + off_t offset, + mach_msg_type_number_t amount) +{ + mach_msg_type_number_t avail; + + if (object != pseudo_console) + return EOPNOTSUPP; + +#if 0 + if (console_send_rights) + { + mach_port_mod_refs (mach_task_self (), pseudo_console, + MACH_PORT_TYPE_SEND, -console_send_rights); + console_send_rights = 0; + } +#endif + + spin_lock (&readlock); + ioctl (0, FIONREAD, &avail); + if (avail) + { + if (amount > *datalen) + *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + *datalen = read (0, *data, amount); + unlock_readlock (); + return *datalen == -1 ? errno : 0; + } + else + { + unlock_readlock (); + queue_read (IO_READ, reply_port, reply_type, amount); + return MIG_NO_REPLY; + } +} + +kern_return_t +S_io_seek (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + off_t offset, + int whence, + off_t *newp) +{ + return object == pseudo_console ? ESPIPE : EOPNOTSUPP; +} + +kern_return_t +S_io_readable (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_msg_type_number_t *amt) +{ + if (object != pseudo_console) + return EOPNOTSUPP; + ioctl (0, FIONREAD, amt); + return 0; +} + +kern_return_t +S_io_set_all_openmodes (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int bits) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_get_openmodes (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int *modes) +{ + *modes = O_READ | O_WRITE; + return object == pseudo_console ? 0 : EOPNOTSUPP; +} + +kern_return_t +S_io_set_some_openmodes (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int bits) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_clear_some_openmodes (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int bits) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_async (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t notify, + mach_port_t *id, + mach_msg_type_name_t *idtype) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_mod_owner (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + pid_t owner) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_get_owner (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + pid_t *owner) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_get_icky_async_id (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t *id, + mach_msg_type_name_t *idtype) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_select (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int *type) +{ + fd_set r, w, x; + int n; + + if (object != pseudo_console) + return EOPNOTSUPP; + + FD_ZERO (&r); + FD_ZERO (&w); + FD_ZERO (&x); + FD_SET (0, &r); + FD_SET (0, &w); + FD_SET (0, &x); + + n = select (1, + (*type & SELECT_READ) ? &r : 0, + (*type & SELECT_WRITE) ? &w : 0, + (*type & SELECT_URG) ? &x : 0, + 0); + if (n < 0) + return errno; + + if (! FD_ISSET (0, &r)) + *type &= ~SELECT_READ; + if (! FD_ISSET (0, &w)) + *type &= ~SELECT_WRITE; + if (! FD_ISSET (0, &x)) + *type &= ~SELECT_URG; + + return 0; +} + +kern_return_t +S_io_stat (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + struct stat *st) +{ + if (object != pseudo_console) + return EOPNOTSUPP; + + bzero (st, sizeof (struct stat)); + st->st_blksize = 1024; + return 0; +} + +kern_return_t +S_io_reauthenticate (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t rend) +{ + uid_t *gu, *au; + gid_t *gg, *ag; + unsigned int gulen = 0, aulen = 0, gglen = 0, aglen = 0; + + if (! auth_server_authenticate (authserver, + rend, MACH_MSG_TYPE_COPY_SEND, + object, MACH_MSG_TYPE_MAKE_SEND, + &gu, &gulen, + &au, &aulen, + &gg, &gglen, + &ag, &aglen)) + { + mig_deallocate ((vm_address_t) gu, gulen * sizeof *gu); + mig_deallocate ((vm_address_t) au, aulen * sizeof *gu); + mig_deallocate ((vm_address_t) gg, gglen * sizeof *gu); + mig_deallocate ((vm_address_t) au, aulen * sizeof *gu); + } + mach_port_deallocate (mach_task_self (), rend); + + return 0; +} + +kern_return_t +S_io_restrict_auth (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t *newobject, + mach_msg_type_name_t *newobjtype, + uid_t *uids, + u_int nuids, + uid_t *gids, + u_int ngids) +{ + if (object != pseudo_console) + return EOPNOTSUPP; + *newobject = pseudo_console; + *newobjtype = MACH_MSG_TYPE_MAKE_SEND; + console_mscount++; + return 0; +} + +kern_return_t +S_io_duplicate (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t *newobj, + mach_msg_type_name_t *newobjtype) +{ + if (object != pseudo_console) + return EOPNOTSUPP; + *newobj = pseudo_console; + *newobjtype = MACH_MSG_TYPE_MAKE_SEND; + console_mscount++; + return 0; +} + +kern_return_t +S_io_server_version (mach_port_t object, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + char *name, + int *maj, + int *min, + int *edit) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_map (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t *rd, + mach_msg_type_name_t *rdtype, + mach_port_t *wr, + mach_msg_type_name_t *wrtype) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_map_cntl (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + mach_port_t *mem, + mach_msg_type_name_t *memtype) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_get_conch (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_release_conch (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_eofnotify (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) + +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_prenotify (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + vm_offset_t start, + vm_offset_t end) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_postnotify (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + vm_offset_t start, + vm_offset_t end) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_readsleep (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_readnotify (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) +{ + return EOPNOTSUPP; +} + + +kern_return_t +S_io_sigio (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type) +{ + return EOPNOTSUPP; +} + + +kern_return_t +S_io_pathconf (mach_port_t obj, + mach_port_t reply_port, + mach_msg_type_name_t reply_type, + int name, int *value) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_identity (mach_port_t obj, + mach_port_t reply, + mach_msg_type_name_t replytype, + mach_port_t *id, + mach_msg_type_name_t *idtype, + mach_port_t *fsid, + mach_msg_type_name_t *fsidtype, + int *fileno) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_io_revoke (mach_port_t obj, + mach_port_t reply, mach_msg_type_name_t replyPoly) +{ + return EOPNOTSUPP; +} + + + +/* Implementation of the Hurd terminal driver interface, which we only + support on the console device. */ + +kern_return_t +S_termctty_open_terminal (mach_port_t object, + int flags, + mach_port_t *result, + mach_msg_type_name_t *restype) +{ + return EOPNOTSUPP; +} + +kern_return_t +S_term_getctty (mach_port_t object, + mach_port_t *cttyid, mach_msg_type_name_t *cttyPoly) +{ + static mach_port_t id = MACH_PORT_NULL; + + if (object != pseudo_console) + return EOPNOTSUPP; + + if (id == MACH_PORT_NULL) + mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_DEAD_NAME, &id); + + *cttyid = id; + *cttyPoly = MACH_MSG_TYPE_COPY_SEND; + return 0; +} + + +kern_return_t S_term_open_ctty +( + io_t terminal, + pid_t pid, + pid_t pgrp, + mach_port_t *newtty, + mach_msg_type_name_t *newttytype +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_set_nodename +( + io_t terminal, + string_t name +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_get_nodename +( + io_t terminal, + string_t name +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_get_peername +( + io_t terminal, + string_t name +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_set_filenode +( + io_t terminal, + file_t filenode +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_get_bottom_type +( + io_t terminal, + int *ttype +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_on_machdev +( + io_t terminal, + mach_port_t machdev +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_on_hurddev +( + io_t terminal, + io_t hurddev +) +{ return EOPNOTSUPP; } + +kern_return_t S_term_on_pty +( + io_t terminal, + io_t *ptymaster +) +{ return EOPNOTSUPP; } diff --git a/boot/boot_script.c b/boot/boot_script.c new file mode 100644 index 00000000..04ede101 --- /dev/null +++ b/boot/boot_script.c @@ -0,0 +1,822 @@ +/* Boot script parser for Mach. */ + +/* Written by Shantanu Goel (goel@cs.columbia.edu). */ + +#include <mach.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "boot_script.h" + + +/* This structure describes a symbol. */ +struct sym +{ + /* Symbol name. */ + const char *name; + + /* Type of value returned by function. */ + int type; + + /* Symbol value. */ + int val; + + /* For function symbols; type of value returned by function. */ + int ret_type; + + /* For function symbols; if set, execute function at the time + of command execution, not during parsing. A function with + this field set must also have `no_arg' set. Also, the function's + `val' argument will always be NULL. */ + int run_on_exec; +}; + +/* Additional values symbols can take. + These are only used internally. */ +#define VAL_SYM 3 /* symbol table entry */ +#define VAL_FUNC 4 /* function pointer */ + +/* This structure describes an argument. */ +struct arg +{ + /* Argument text copied verbatim. 0 if none. */ + char *text; + + /* Type of value assigned. 0 if none. */ + int type; + + /* Argument value. */ + int val; +}; + +/* List of commands. */ +static struct cmd **cmds = 0; + +/* Amount allocated for `cmds'. */ +static int cmds_alloc = 0; + +/* Next available slot in `cmds'. */ +static int cmds_index = 0; + +/* Symbol table. */ +static struct sym **symtab = 0; + +/* Amount allocated for `symtab'. */ +static int symtab_alloc = 0; + +/* Next available slot in `symtab'. */ +static int symtab_index = 0; + +/* Create a task. */ +static int +create_task (struct cmd *cmd, int *val) +{ + if (task_create (mach_task_self (), 0, (task_t *) &cmd->task) || + task_suspend (cmd->task)) + { + printf ("(bootstrap): %s: Cannot create task\n", cmd->path); + return BOOT_SCRIPT_MACH_ERROR; + } + *val = (int) cmd->task; + return 0; +} + +/* Resume a task. */ +static int +resume_task (struct cmd *cmd, int *val) +{ + if (task_resume (cmd->task)) + { + printf ("(bootstrap): %s: Cannot resume task\n", cmd->path); + return BOOT_SCRIPT_MACH_ERROR; + } + return 0; +} + +/* Resume a task when the user hits return. */ +static int +prompt_resume_task (struct cmd *cmd, int *val) +{ + char xx[5]; + + printf ("Hit return to resume %s...", cmd->path); + safe_gets (xx, sizeof xx); + + if (task_resume (cmd->task)) + { + printf ("(bootstrap): %s: Cannot resume task\n", cmd->path); + return BOOT_SCRIPT_MACH_ERROR; + } + + return 0; +} + +static int +read_file (struct cmd *cmd, int *val) +{ + *val = boot_script_read_file (cmd->path); + if (*val == 0) + { + printf ("(bootstrap): %s: Cannot read boot script\n", cmd->path); + return BOOT_SCRIPT_MACH_ERROR; + } + return 0; +} + +/* List of builtin symbols. */ +static struct sym builtin_symbols[] = +{ + { "task-create", VAL_FUNC, (int) create_task, VAL_PORT, 0 }, + { "task-resume", VAL_FUNC, (int) resume_task, VAL_NONE, 1 }, + { "prompt-task-resume", VAL_FUNC, (int) prompt_resume_task, VAL_NONE, 1 }, + { "read-file", VAL_FUNC, (int) read_file, VAL_PORT, 0 }, +}; +#define NUM_BUILTIN (sizeof (builtin_symbols) / sizeof (builtin_symbols[0])) + +/* Free CMD and all storage associated with it. + If ABORTING is set, terminate the task associated with CMD, + otherwise just deallocate the send right. */ +static void +free_cmd (struct cmd *cmd, int aborting) +{ + if (cmd->task) + { + if (aborting) + task_terminate (cmd->task); + else + mach_port_deallocate (mach_task_self (), cmd->task); + } + if (cmd->args) + { + int i; + + for (i = 0; i < cmd->args_index; i++) + free (cmd->args[i]); + free (cmd->args); + } + if (cmd->exec_funcs) + free (cmd->exec_funcs); + free (cmd); +} + +/* Free all storage allocated by the parser. + If ABORTING is set, terminate all tasks. */ +static void +cleanup (int aborting) +{ + int i; + + for (i = 0; i < cmds_index; i++) + free_cmd (cmds[i], aborting); + free (cmds); + cmds = 0; + cmds_index = cmds_alloc = 0; + + for (i = 0; i < symtab_index; i++) + free (symtab[i]); + free (symtab); + symtab = 0; + symtab_index = symtab_alloc = 0; +} + +/* Add PTR to the list of pointers PTR_LIST, which + currently has ALLOC amount of space allocated to it, and + whose next available slot is INDEX. If more space + needs to to allocated, INCR is the amount by which + to increase it. Return 0 on success, non-zero otherwise. */ +static int +add_list (void *ptr, void ***ptr_list, int *alloc, int *index, int incr) +{ + if (*index == *alloc) + { + void **p; + + *alloc += incr; + p = malloc (*alloc * sizeof (void *)); + if (! p) + { + *alloc -= incr; + return 1; + } + if (*ptr_list) + { + memcpy (p, *ptr_list, *index * sizeof (void *)); + free (*ptr_list); + } + *ptr_list = p; + } + *(*ptr_list + *index) = ptr; + *index += 1; + return 0; +} + +/* Create an argument with TEXT, value type TYPE, and value VAL. + Add the argument to the argument list of CMD. */ +static struct arg * +add_arg (struct cmd *cmd, char *text, int type, int val) +{ + struct arg *arg; + + arg = malloc (sizeof (struct arg)); + if (arg) + { + arg->text = text; + arg->type = type; + arg->val = val; + if (add_list (arg, (void ***) &cmd->args, + &cmd->args_alloc, &cmd->args_index, 5)) + { + free (arg); + return 0; + } + } + return arg; +} + +/* Search for the symbol NAME in the symbol table. */ +static struct sym * +sym_lookup (const char *name) +{ + int i; + + for (i = 0; i < symtab_index; i++) + if (! strcmp (name, symtab[i]->name)) + return symtab[i]; + return 0; +} + +/* Create an entry for symbol NAME in the symbol table. */ +static struct sym * +sym_enter (const char *name) +{ + struct sym *sym; + + sym = malloc (sizeof (struct sym)); + if (sym) + { + memset (sym, 0, sizeof (struct sym)); + sym->name = name; + if (add_list (sym, (void ***) &symtab, &symtab_alloc, &symtab_index, 20)) + { + free (sym); + return 0; + } + } + return sym; +} + +/* Parse the command line CMDLINE. */ +int +boot_script_parse_line (char *cmdline) +{ + char *p, *q; + int error; + struct cmd *cmd; + struct arg *arg; + + /* Extract command name. Ignore line if it lacks a command. */ + for (p = cmdline; *p == ' ' || *p == '\t'; p++) + ; + if (*p == '#') + /* Ignore comment line. */ + return 0; + +#if 0 + if (*p && *p != ' ' && *p != '\t' && *p != '\n') + { + printf ("(bootstrap): %s\n", cmdline); + } +#endif + + for (q = p; *q && *q != ' ' && *q != '\t' && *q != '\n'; q++) + ; + if (p == q) + return 0; + + *q = '\0'; + + /* Allocate a command structure. */ + cmd = malloc (sizeof (struct cmd)); + if (! cmd) + return BOOT_SCRIPT_NOMEM; + memset (cmd, 0, sizeof (struct cmd)); + cmd->path = p; + p = q + 1; + + for (arg = 0;;) + { + if (! arg) + { + /* Skip whitespace. */ + while (*p == ' ' || *p == '\t') + p++; + + /* End of command line. */ + if (! *p || *p == '\n') + { + /* Add command to list. */ + if (add_list (cmd, (void ***) &cmds, + &cmds_alloc, &cmds_index, 10)) + { + error = BOOT_SCRIPT_NOMEM; + goto bad; + } + return 0; + } + } + + /* Look for a symbol. */ + if (arg || (*p == '$' && (*(p + 1) == '{' || *(p + 1) == '('))) + { + char end_char = (*(p + 1) == '{') ? '}' : ')'; + struct sym *sym = 0; + + for (p += 2;;) + { + char c; + int i, val, type; + struct sym *s; + + /* Parse symbol name. */ + for (q = p; *q && *q != '\n' && *q != end_char && *q != '='; q++) + ; + if (p == q || ! *q || *q == '\n' + || (end_char == '}' && *q != '}')) + { + error = BOOT_SCRIPT_SYNTAX_ERROR; + goto bad; + } + c = *q; + *q = '\0'; + + /* See if this is a builtin symbol. */ + for (i = 0; i < NUM_BUILTIN; i++) + if (! strcmp (p, builtin_symbols[i].name)) + break; + + if (i < NUM_BUILTIN) + s = &builtin_symbols[i]; + else + { + /* Look up symbol in symbol table. + If no entry exists, create one. */ + s = sym_lookup (p); + if (! s) + { + s = sym_enter (p); + if (! s) + { + error = BOOT_SCRIPT_NOMEM; + goto bad; + } + } + } + + /* Only values are allowed in ${...} constructs. */ + if (end_char == '}' && s->type == VAL_FUNC) + return BOOT_SCRIPT_INVALID_SYM; + + /* Check that assignment is valid. */ + if (c == '=' && s->type == VAL_FUNC) + { + error = BOOT_SCRIPT_INVALID_ASG; + goto bad; + } + + /* For function symbols, execute the function. */ + if (s->type == VAL_FUNC) + { + if (! s->run_on_exec) + { + (error + = ((*((int (*) (struct cmd *, int *)) s->val)) + (cmd, &val))); + if (error) + goto bad; + type = s->ret_type; + } + else + { + if (add_list (s, (void ***) &cmd->exec_funcs, + &cmd->exec_funcs_alloc, + &cmd->exec_funcs_index, 5)) + { + error = BOOT_SCRIPT_NOMEM; + goto bad; + } + type = VAL_NONE; + goto out; + } + } + else if (s->type == VAL_NONE) + { + type = VAL_SYM; + val = (int) s; + } + else + { + type = s->type; + val = s->val; + } + + if (sym) + { + sym->type = type; + sym->val = val; + } + else if (arg) + { + arg->type = type; + arg->val = val; + } + + out: + p = q + 1; + if (c == end_char) + { + /* Create an argument if necessary. + We create an argument if the symbol appears + in the expression by itself. + + NOTE: This is temporary till the boot filesystem + servers support arguments. When that happens, + symbol values will only be printed if they're + associated with an argument. */ + if (! arg && end_char == '}') + { + if (! add_arg (cmd, 0, type, val)) + { + error = BOOT_SCRIPT_NOMEM; + goto bad; + } + } + arg = 0; + break; + } + if (s->type != VAL_FUNC) + sym = s; + } + } + else + { + char c; + + /* Command argument; just copy the text. */ + for (q = p;; q++) + { + if (! *q || *q == ' ' || *q == '\t' || *q == '\n') + break; + if (*q == '$' && *(q + 1) == '{') + break; + } + c = *q; + *q = '\0'; + + /* Add argument to list. */ + arg = add_arg (cmd, p, VAL_NONE, 0); + if (! arg) + { + error = BOOT_SCRIPT_NOMEM; + goto bad; + } + if (c == '$') + p = q; + else + { + if (c) + p = q + 1; + else + p = q; + arg = 0; + } + } + } + + + bad: + free_cmd (cmd, 1); + cleanup (1); + return error; +} + +/* Ensure that the command line buffer can accommodate LEN bytes of space. */ +#define CHECK_CMDLINE_LEN(len) \ +{ \ + if (cmdline_alloc - cmdline_index < len) \ + { \ + char *ptr; \ + int alloc, i; \ + alloc = cmdline_alloc + len - (cmdline_alloc - cmdline_index) + 100; \ + ptr = malloc (alloc); \ + if (! ptr) \ + { \ + error = BOOT_SCRIPT_NOMEM; \ + goto done; \ + } \ + memcpy (ptr, cmdline, cmdline_index); \ + for (i = 0; i < argc; ++i) \ + argv[i] = ptr + (argv[i] - cmdline); \ + free (cmdline); \ + cmdline = ptr; \ + cmdline_alloc = alloc; \ + } \ +} + +/* Execute commands previously parsed. */ +int +boot_script_exec () +{ + int cmd_index; + + for (cmd_index = 0; cmd_index < cmds_index; cmd_index++) + { + char **argv, *cmdline; + int i, argc, cmdline_alloc; + int cmdline_index, error, arg_index; + struct cmd *cmd = cmds[cmd_index]; + + /* Skip command if it doesn't have an associated task. */ + if (cmd->task == 0) + continue; + + /* Allocate a command line and copy command name. */ + cmdline_index = strlen (cmd->path) + 1; + cmdline_alloc = cmdline_index + 100; + cmdline = malloc (cmdline_alloc); + if (! cmdline) + { + cleanup (1); + return BOOT_SCRIPT_NOMEM; + } + memcpy (cmdline, cmd->path, cmdline_index); + + /* Allocate argument vector. */ + argv = malloc (sizeof (char *) * (cmd->args_index + 2)); + if (! argv) + { + free (cmdline); + cleanup (1); + return BOOT_SCRIPT_NOMEM; + } + argv[0] = cmdline; + argc = 1; + + /* Build arguments. */ + for (arg_index = 0; arg_index < cmd->args_index; arg_index++) + { + struct arg *arg = cmd->args[arg_index]; + + /* Copy argument text. */ + if (arg->text) + { + int len = strlen (arg->text); + + if (arg->type == VAL_NONE) + len++; + CHECK_CMDLINE_LEN (len); + memcpy (cmdline + cmdline_index, arg->text, len); + argv[argc++] = &cmdline[cmdline_index]; + cmdline_index += len; + } + + /* Add value of any symbol associated with this argument. */ + if (arg->type != VAL_NONE) + { + char *p, buf[50]; + int len; + + if (arg->type == VAL_SYM) + { + struct sym *sym = (struct sym *) arg->val; + + /* Resolve symbol value. */ + while (sym->type == VAL_SYM) + sym = (struct sym *) sym->val; + if (sym->type == VAL_NONE) + { + error = BOOT_SCRIPT_UNDEF_SYM; + goto done; + } + arg->type = sym->type; + arg->val = sym->val; + } + + /* Print argument value. */ + switch (arg->type) + { + case VAL_STR: + p = (char *) arg->val; + len = strlen (p); + break; + + case VAL_PORT: + /* Insert send right. */ + if ((mach_port_insert_right + (cmd->task, (mach_port_t) arg->val, + (mach_port_t) arg->val, MACH_MSG_TYPE_COPY_SEND))) + { + printf ("(bootstrap): %s: Cannot insert port right %d\n", + cmd->path, arg->val); + error = BOOT_SCRIPT_MACH_ERROR; + goto done; + } + + i = arg->val; + p = buf + sizeof (buf); + len = 0; + do + { + *--p = i % 10 + '0'; + len++; + } + while (i /= 10); + break; + + default: + error = BOOT_SCRIPT_BAD_TYPE; + goto done; + } + len++; + CHECK_CMDLINE_LEN (len); + memcpy (cmdline + cmdline_index, p, len - 1); + *(cmdline + cmdline_index + len - 1) = '\0'; + if (! arg->text) + argv[argc++] = &cmdline[cmdline_index]; + cmdline_index += len; + } + } + + /* Terminate argument vector. */ + argv[argc] = 0; + + /* Execute the command. */ + if (boot_script_exec_cmd (cmd->task, cmd->path, + argc, argv, cmdline, cmdline_index)) + { + error = BOOT_SCRIPT_EXEC_ERROR; + goto done; + } + + error = 0; + + done: + free (cmdline); + free (argv); + if (error) + { + cleanup (1); + return error; + } + } + + for (cmd_index = 0; cmd_index < cmds_index; cmd_index++) + { + int i; + struct cmd *cmd = cmds[cmd_index]; + + /* Execute functions that want to be run on exec. */ + for (i = 0; i < cmd->exec_funcs_index; i++) + { + struct sym *sym = cmd->exec_funcs[i]; + int error = ((*((int (*) (struct cmd *, int *)) sym->val)) + (cmd, 0)); + if (error) + { + cleanup (1); + return error; + } + } + } + + cleanup (0); + return 0; +} + +/* Create an entry for the variable NAME with TYPE and value VAL, + in the symbol table. */ +int +boot_script_set_variable (const char *name, int type, int val) +{ + struct sym *sym = sym_enter (name); + + if (sym) + { + sym->type = type; + sym->val = val; + } + return sym ? 0 : 1; +} + + +/* Define the function NAME, which will return type RET_TYPE. */ +int +boot_script_define_function (const char *name, int ret_type, + int (*func) (const struct cmd *cmd, int *val)) +{ + struct sym *sym = sym_enter (name); + + if (sym) + { + sym->type = VAL_FUNC; + sym->val = (int) func; + sym->ret_type = ret_type; + sym->run_on_exec = ret_type == VAL_NONE; + } + return sym ? 0 : 1; +} + + +/* Return a string describing ERR. */ +char * +boot_script_error_string (int err) +{ + switch (err) + { + case BOOT_SCRIPT_NOMEM: + return "no memory"; + + case BOOT_SCRIPT_SYNTAX_ERROR: + return "syntax error"; + + case BOOT_SCRIPT_INVALID_ASG: + return "invalid variable in assignment"; + + case BOOT_SCRIPT_MACH_ERROR: + return "mach error"; + + case BOOT_SCRIPT_UNDEF_SYM: + return "undefined symbol"; + + case BOOT_SCRIPT_EXEC_ERROR: + return "exec error"; + + case BOOT_SCRIPT_INVALID_SYM: + return "invalid variable in expression"; + + case BOOT_SCRIPT_BAD_TYPE: + return "invalid value type"; + } + return 0; +} + +#ifdef BOOT_SCRIPT_TEST +#include <stdio.h> + +int +boot_script_exec_cmd (mach_port_t task, char *path, int argc, + char **argv, char *strings, int stringlen) +{ + int i; + + printf ("port = %d: ", (int) task); + for (i = 0; i < argc; i++) + printf ("%s ", argv[i]); + printf ("\n"); + return 0; +} + +void +main (int argc, char **argv) +{ + char buf[500], *p; + int len; + FILE *fp; + mach_port_t host_port, device_port; + + if (argc < 2) + { + fprintf (stderr, "Usage: %s <script>\n", argv[0]); + exit (1); + } + fp = fopen (argv[1], "r"); + if (! fp) + { + fprintf (stderr, "Can't open %s\n", argv[1]); + exit (1); + } + host_port = 1; + device_port = 2; + boot_script_set_variable ("host-port", VAL_PORT, (int) host_port); + boot_script_set_variable ("device-port", VAL_PORT, (int) device_port); + boot_script_set_variable ("root-device", VAL_STR, (int) "hd0a"); + boot_script_set_variable ("boot-args", VAL_STR, (int) "-ad"); + p = buf; + len = sizeof (buf); + while (fgets (p, len, fp)) + { + int i, err; + + i = strlen (p) + 1; + err = boot_script_parse_line (p); + if (err) + { + fprintf (stderr, "error %s\n", boot_script_error_string (err)); + exit (1); + } + p += i; + len -= i; + } + boot_script_exec (); + exit (0); +} +#endif /* BOOT_SCRIPT_TEST */ diff --git a/boot/boot_script.h b/boot/boot_script.h new file mode 100644 index 00000000..d2db1a14 --- /dev/null +++ b/boot/boot_script.h @@ -0,0 +1,90 @@ +/* Definitions for boot script parser for Mach. */ + +/* Written by Shantanu Goel (goel@cs.columbia.edu). */ + +/* Error codes returned by boot_script_parse_line() + and boot_script_exec_cmd(). */ +#define BOOT_SCRIPT_NOMEM 1 +#define BOOT_SCRIPT_SYNTAX_ERROR 2 +#define BOOT_SCRIPT_INVALID_ASG 3 +#define BOOT_SCRIPT_MACH_ERROR 4 +#define BOOT_SCRIPT_UNDEF_SYM 5 +#define BOOT_SCRIPT_EXEC_ERROR 6 +#define BOOT_SCRIPT_INVALID_SYM 7 +#define BOOT_SCRIPT_BAD_TYPE 8 + +/* Legal values for argument `type' to function + boot_script_set_variable and boot_script_define_function. */ +#define VAL_NONE 0 /* none -- function runs at exec time */ +#define VAL_STR 1 /* string */ +#define VAL_PORT 2 /* port */ + +/* This structure describes a command. */ +struct cmd +{ + /* Path of executable. */ + char *path; + + /* Task port. */ + mach_port_t task; + + /* Argument list. */ + struct arg **args; + + /* Amount allocated for `args'. */ + int args_alloc; + + /* Next available slot in `args'. */ + int args_index; + + /* List of functions that want to be run on command execution. */ + struct sym **exec_funcs; + + /* Amount allocated for `exec_funcs'. */ + int exec_funcs_alloc; + + /* Next available slot in `exec_funcs'. */ + int exec_funcs_index; +}; + + +/* The user must define this function. Load the image of the + executable specified by PATH in TASK. Create a thread + in TASK and point it at the executable's entry point. Initialize + TASK's stack with argument vector ARGV of length ARGC whose + strings are STRINGS. STRINGS has length STRINGLEN. + Return 0 for success, non-zero otherwise. */ +int boot_script_exec_cmd (mach_port_t task, char *path, int argc, + char **argv, char *strings, int stringlen); + +/* The user must define this function. Load the contents of FILE + into a fresh anonymous memory object and return the memory object port. */ +mach_port_t boot_script_read_file (const char *file); + +/* Parse the command line LINE. This causes the command line to be + converted into an internal format. Returns 0 for success, non-zero + otherwise. + + NOTE: The parser writes into the line so it must not be a string constant. + It is also the responsibility of the caller not to deallocate the line + across calls to the parser. */ +int boot_script_parse_line (char *cmdline); + +/* Execute the command lines prevously parsed. + Returns 0 for success, non-zero otherwise. */ +int boot_script_exec (void); + +/* Create an entry in the symbol table for variable NAME, + whose type is TYPE and value is VAL. Returns 0 on success, + non-zero otherwise. */ +int boot_script_set_variable (const char *name, int type, int val); + +/* Define the function NAME, which will return type RET_TYPE. */ +int boot_script_define_function (const char *name, int ret_type, + int (*func) (const struct cmd *cmd, int *val)); + +/* Returns a string describing the error ERR. */ +char *boot_script_error_string (int err); + + +void safe_gets (char *, int); diff --git a/boot/frank1.ld b/boot/frank1.ld new file mode 100644 index 00000000..9de827ae --- /dev/null +++ b/boot/frank1.ld @@ -0,0 +1,94 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + SEARCH_DIR(/usr/local/i386-gnuelf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x10020; + .text : + { + *(.text) + *(.interp) + *(.hash) + *(.dynsym) + *(.dynstr) + *(.rel.text) + *(.rela.text) + *(.rel.data) + *(.rela.data) + *(.rel.rodata) + *(.rela.rodata) + *(.rel.got) + *(.rela.got) + *(.rel.ctors) + *(.rela.ctors) + *(.rel.dtors) + *(.rela.dtors) + *(.rel.init) + *(.rela.init) + *(.rel.fini) + *(.rela.fini) + *(.rel.bss) + *(.rela.bss) + *(.rel.plt) + *(.rela.plt) + *(.init) + *(.plt) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.fini) + *(.rodata) + *(.rodata1) + _etext = .; + PROVIDE (etext = .); + . = ALIGN(0x1000); + } =0x9090 + . = ALIGN(0x1000); + .data : + { + *(.data) + CONSTRUCTORS + + *(.data1) + *(.ctors) + *(.dtors) + *(.got.plt) *(.got) + *(.dynamic) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata) + _edata = .; + PROVIDE (edata = .); + . = ALIGN(0x10); +} + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + _end = ALIGN(4) ; + PROVIDE (end = ALIGN(4)); + } + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ +} diff --git a/boot/frankemul.ld b/boot/frankemul.ld new file mode 100644 index 00000000..413953ef --- /dev/null +++ b/boot/frankemul.ld @@ -0,0 +1,107 @@ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + SEARCH_DIR(/usr/local/i386-gnuelf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x10020; + .text : + { + *(.text) + *(.interp) + *(.hash) + *(.dynsym) + *(.dynstr) + *(.rel.text) + *(.rela.text) + *(.rel.data) + *(.rela.data) + *(.rel.rodata) + *(.rela.rodata) + *(.rel.got) + *(.rela.got) + *(.rel.ctors) + *(.rela.ctors) + *(.rel.dtors) + *(.rela.dtors) + *(.rel.init) + *(.rela.init) + *(.rel.fini) + *(.rela.fini) + *(.rel.bss) + *(.rela.bss) + *(.rel.plt) + *(.rela.plt) + *(.init) + *(.plt) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.fini) + *(.rodata) + *(.rodata1) +*(_hurd_ioctl_handler_lists) +*(_hurd_pgrp_changed_hook) +*(_hurd_fork_locks) +*(_hurd_subinit) +*(__libc_atexit) +*(_hurd_fd_subinit) +*(_hurd_preinit_hook) +*(_hurd_fork_child_hook) +*(_hurd_fork_parent_hook) +*(_hurd_fork_prepare_hook) +*(_hurd_reauth_hook) +*(_hurd_proc_subinit) +*(__libc_subinit) + _etext = .; + PROVIDE (etext = .); + . = ALIGN(0x1000); + } =0x9090 + . = ALIGN(0x1000); + .data : + { + *(.data) + CONSTRUCTORS + + *(.data1) + *(.ctors) + *(.dtors) + *(.got.plt) *(.got) + *(.dynamic) + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + *(.sdata) + _edata = .; + PROVIDE (edata = .); + . = ALIGN(0x10); +} + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + _end = ALIGN(4) ; + PROVIDE (end = ALIGN(4)); + } + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ +} diff --git a/boot/mach-crt0.c b/boot/mach-crt0.c new file mode 100644 index 00000000..0469424e --- /dev/null +++ b/boot/mach-crt0.c @@ -0,0 +1,158 @@ +/* + * 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. + */ +/* + * 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 are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by the University of California, Berkeley and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)crt0.c 5.2 (Berkeley) 5/14/90"; +#endif /* not lint */ + +/* + * C start up routine. + * Robert Henry, UCB, 20 Oct 81 + * + * We make the following (true) assumptions: + * 1) when the kernel calls start, it does a jump to location 2, + * and thus avoids the register save mask. We are NOT called + * with a calls! see sys1.c:setregs(). + * 2) The only register variable that we can trust is sp, + * which points to the base of the kernel calling frame. + * Do NOT believe the documentation in exec(2) regarding the + * values of fp and ap. + * 3) We can allocate as many register variables as we want, + * and don't have to save them for anybody. + * 4) Because of the ways that asm's work, we can't have + * any automatic variables allocated on the stack, because + * we must catch the value of sp before any automatics are + * allocated. + */ + +#include <mach/machine/asm.h> + +int __data_start = 0; +char **environ = (char **)0; +#ifdef paranoid +static int fd; +#endif paranoid + +int (*mach_init_routine)(); +int (*_cthread_init_routine)(); +int (*_cthread_exit_routine)(); +int (*_monstartup_routine)(); +int (*_StrongBox_init_routine)(); +int errno = 0; +int exit(); + +extern int main(); + +extern unsigned char etext; +int _start() +{ + __label__ eprol; + struct kframe { + int kargc; + char *kargv[1]; /* size depends on kargc */ + char kargstr[1]; /* size varies */ + char kenvstr[1]; /* size varies */ + }; + /* + * ALL REGISTER VARIABLES!!! + */ + register struct kframe *kfp; /* r10 */ + register char **targv; + register char **argv; + +#ifdef lint + kfp = 0; + initcode = initcode = 0; +#else not lint +#define Entry_sp() \ +({ int _spl__, _tmp1__; \ + asm volatile("leal 4(%%ebp), %0" : "=r" (_spl__) : "r" (_tmp1__)); \ + _spl__; }) + + kfp = (struct kframe *)Entry_sp(); +#endif not lint + for (argv = targv = &kfp->kargv[0]; *targv++; /* void */) + /* void */ ; + if (targv >= (char **)(*argv)) + --targv; + environ = targv; + if (mach_init_routine) + (void) mach_init_routine(); + + eprol: +#ifdef paranoid + /* + * The standard I/O library assumes that file descriptors 0, 1, and 2 + * are open. If one of these descriptors is closed prior to the start + * of the process, I/O gets very confused. To avoid this problem, we + * insure that the first three file descriptors are open before calling + * main(). Normally this is undefined, as it adds two unnecessary + * system calls. + */ + do { + fd = open("/dev/null", 2); + } while (fd >= 0 && fd < 3); + close(fd); +#endif paranoid + + + if (_cthread_init_routine) { + int new_sp; + new_sp = (*_cthread_init_routine)(); + if (new_sp) { + asm volatile("movl %0, %%esp" : : "g" (new_sp) ); + } + } + if (_StrongBox_init_routine) (*_StrongBox_init_routine)(); + + if (_monstartup_routine) { + _monstartup_routine(&&eprol, &etext); + } + + (* (_cthread_exit_routine ? _cthread_exit_routine : exit)) + (main(kfp->kargc, argv, targv)); +} diff --git a/boot/sigvec.S b/boot/sigvec.S new file mode 100644 index 00000000..cc7bb94e --- /dev/null +++ b/boot/sigvec.S @@ -0,0 +1,23 @@ +#include <i386/asm.h> + +.text +ENTRY(sigreturn) + movl $0x67,%eax + lcall $0x7,$0x0 + jb error + ret +ENTRY(_sigreturn) + addl $0xc,%esp + call EXT(sigreturn) + ret +ENTRY(sigvec) + movl $0x6c,%eax + movl $EXT(_sigreturn),%edx + orl $0x80000000,%edx + lcall $0x7,$0x0 + jb error + ret +error: + movl %eax,EXT(errno) + movl $-1,%eax + ret diff --git a/boot/syscall.S b/boot/syscall.S new file mode 100644 index 00000000..a04ab28d --- /dev/null +++ b/boot/syscall.S @@ -0,0 +1,35 @@ +/* Temporary.... + Copyright (C) 1993, 1995 Free Software Foundation + +This file is part of the GNU Hurd. + +The GNU Hurd is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +The GNU Hurd is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with the GNU Hurd; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <i386/asm.h> + +/* .globl EXT(errno)*/ +.text +ENTRY(syscall) + pop %ecx + pop %eax + push %ecx + lcall $7, $0 + push %ecx /* Restore stack position. */ + jb error + ret +error: + movl %eax,EXT(errno) + movl $-1,%eax + ret diff --git a/boot/tcattr.c b/boot/tcattr.c new file mode 100644 index 00000000..fcd3293e --- /dev/null +++ b/boot/tcattr.c @@ -0,0 +1,592 @@ +/* Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <stddef.h> +#include <termios.h> + +#undef B0 +#undef B50 +#undef B75 +#undef B110 +#undef B134 +#undef B150 +#undef B200 +#undef B300 +#undef B600 +#undef B1200 +#undef B1800 +#undef B2400 +#undef B4800 +#undef B9600 +#undef B19200 +#undef B38400 +#undef EXTA +#undef EXTB +#undef ECHO +#undef TOSTOP +#undef NOFLSH +#undef MDMBUF +#undef FLUSHO +#undef PENDIN +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS +#undef CERASE +#undef CKILL +#undef CINTR +#undef CQUIT +#undef CSTART +#undef CSTOP +#undef CEOF +#undef CEOT +#undef CBRK +#undef CSUSP +#undef CDSUSP +#undef CRPRNT +#undef CFLUSH +#undef CWERASE +#undef CLNEXT +#undef CSTATUS + +#define IOCPARM_MASK 0x7f +#define IOC_OUT 0x40000000 +#define IOC_IN 0x80000000 +#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define FIONREAD _IOR('f', 127, int) +#define FIOASYNC _IOW('f', 125, int) +#define TIOCGETP _IOR('t', 8, struct sgttyb) +#define TIOCLGET _IOR('t', 124, int) +#define TIOCLSET _IOW('t', 125, int) +#define TIOCSETN _IOW('t', 10, struct sgttyb) +#define TIOCSETP _IOW('t', 9,struct sgttyb)/* set parameters -- stty */ +#define TIOCFLUSH _IOW('t', 16, int) /* flush buffers */ +#define TIOCSETC _IOW('t',17,struct tchars)/* set special characters */ +#define TIOCGETC _IOR('t',18,struct tchars)/* get special characters */ +#define TANDEM 0x00000001 /* send stopc on out q full */ +#define CBREAK 0x00000002 /* half-cooked mode */ +#define LCASE 0x00000004 /* simulate lower case */ +#define ECHO 0x00000008 /* echo input */ +#define CRMOD 0x00000010 /* map \r to \r\n on output */ +#define RAW 0x00000020 /* no i/o processing */ +#define ODDP 0x00000040 /* get/send odd parity */ +#define EVENP 0x00000080 /* get/send even parity */ +#define ANYP 0x000000c0 /* get any parity/send none */ +#define PRTERA 0x00020000 /* \ ... / erase */ +#define CRTERA 0x00040000 /* " \b " to wipe out char */ +#define TILDE 0x00080000 /* hazeltine tilde kludge */ +#define MDMBUF 0x00100000 /* start/stop output on carrier intr */ +#define LITOUT 0x00200000 /* literal output */ +#define TOSTOP 0x00400000 /* SIGSTOP on background output */ +#define FLUSHO 0x00800000 /* flush output to terminal */ +#define NOHANG 0x01000000 /* no SIGHUP on carrier drop */ +#define L001000 0x02000000 +#define CRTKIL 0x04000000 /* kill line with " \b " */ +#define PASS8 0x08000000 +#define CTLECH 0x10000000 /* echo control chars as ^X */ +#define PENDIN 0x20000000 /* tp->t_rawq needs reread */ +#define DECCTQ 0x40000000 /* only ^Q starts after ^S */ +#define NOFLSH 0x80000000 /* no output flush on signal */ +#define TIOCLSET _IOW('t', 125, int) /* set entire local mode word */ +#define TIOCLGET _IOR('t', 124, int) /* get local modes */ +#define LCRTBS (CRTBS>>16) +#define LPRTERA (PRTERA>>16) +#define LCRTERA (CRTERA>>16) +#define LTILDE (TILDE>>16) +#define LMDMBUF (MDMBUF>>16) +#define LLITOUT (LITOUT>>16) +#define LTOSTOP (TOSTOP>>16) +#define LFLUSHO (FLUSHO>>16) +#define LNOHANG (NOHANG>>16) +#define LCRTKIL (CRTKIL>>16) +#define LPASS8 (PASS8>>16) +#define LCTLECH (CTLECH>>16) +#define LPENDIN (PENDIN>>16) +#define LDECCTQ (DECCTQ>>16) +#define LNOFLSH (NOFLSH>>16) +#define TIOCSLTC _IOW('t',117,struct ltchars)/* set local special chars */ +#define TIOCGLTC _IOR('t',116,struct ltchars)/* get local special chars */ + + +#if defined(TIOCGETC) || defined(TIOCSETC) +/* Type of ARG for TIOCGETC and TIOCSETC requests. */ +struct tchars +{ + char t_intrc; /* Interrupt character. */ + char t_quitc; /* Quit character. */ + char t_startc; /* Start-output character. */ + char t_stopc; /* Stop-output character. */ + char t_eofc; /* End-of-file character. */ + char t_brkc; /* Input delimiter character. */ +}; + +#define _IOT_tchars /* Hurd ioctl type field. */ \ + _IOT (_IOTS (char), 6, 0, 0, 0, 0) +#endif + +#if defined(TIOCGLTC) || defined(TIOCSLTC) +/* Type of ARG for TIOCGLTC and TIOCSLTC requests. */ +struct ltchars +{ + char t_suspc; /* Suspend character. */ + char t_dsuspc; /* Delayed suspend character. */ + char t_rprntc; /* Reprint-line character. */ + char t_flushc; /* Flush-output character. */ + char t_werasc; /* Word-erase character. */ + char t_lnextc; /* Literal-next character. */ +}; + +#define _IOT_ltchars /* Hurd ioctl type field. */ \ + _IOT (_IOTS (char), 6, 0, 0, 0, 0) +#endif + +/* Type of ARG for TIOCGETP and TIOCSETP requests (and gtty and stty). */ +struct sgttyb +{ + char sg_ispeed; /* Input speed. */ + char sg_ospeed; /* Output speed. */ + char sg_erase; /* Erase character. */ + char sg_kill; /* Kill character. */ + short int sg_flags; /* Mode flags. */ +}; + + + + +const speed_t __bsd_speeds[] = + { + 0, + 50, + 75, + 110, + 134, + 150, + 200, + 300, + 600, + 1200, + 1800, + 2400, + 4800, + 9600, + 19200, + 38400, + }; + +extern int ioctl (); + +/* Set the state of FD to *TERMIOS_P. */ +int +tcsetattr (int fd, int optional_actions, const struct termios *termios_p) +{ + struct sgttyb buf; + struct tchars tchars; + struct ltchars ltchars; + int local; +#ifdef TIOCGETX + int extra; +#endif + size_t i; + + if (ioctl(fd, TIOCGETP, &buf) < 0 || + ioctl(fd, TIOCGETC, &tchars) < 0 || + ioctl(fd, TIOCGLTC, <chars) < 0 || +#ifdef TIOCGETX + ioctl(fd, TIOCGETX, &extra) < 0 || +#endif + ioctl(fd, TIOCLGET, &local) < 0) + return -1; + + if (termios_p == NULL) + { + errno = EINVAL; + return -1; + } + + buf.sg_ispeed = buf.sg_ospeed = -1; + for (i = 0; i <= sizeof (__bsd_speeds) / sizeof (__bsd_speeds[0]); ++i) + { + if (__bsd_speeds[i] == termios_p->__ispeed) + buf.sg_ispeed = i; + if (__bsd_speeds[i] == termios_p->__ospeed) + buf.sg_ospeed = i; + } + if (buf.sg_ispeed == -1 || buf.sg_ospeed == -1) + { + errno = EINVAL; + return -1; + } + + buf.sg_flags &= ~(CBREAK|RAW); + if (!(termios_p->c_lflag & ICANON)) + buf.sg_flags |= (termios_p->c_cflag & ISIG) ? CBREAK : RAW; +#ifdef LPASS8 + if (termios_p->c_oflag & CS8) + local |= LPASS8; + else + local &= ~LPASS8; +#endif + if (termios_p->c_lflag & _NOFLSH) + local |= LNOFLSH; + else + local &= ~LNOFLSH; + if (termios_p->c_oflag & OPOST) + local &= ~LLITOUT; + else + local |= LLITOUT; +#ifdef TIOCGETX + if (termios_p->c_lflag & ISIG) + extra &= ~NOISIG; + else + extra |= NOISIG; + if (termios_p->c_cflag & CSTOPB) + extra |= STOPB; + else + extra &= ~STOPB; +#endif + if (termios_p->c_iflag & ICRNL) + buf.sg_flags |= CRMOD; + else + buf.sg_flags &= ~CRMOD; + if (termios_p->c_iflag & IXOFF) + buf.sg_flags |= TANDEM; + else + buf.sg_flags &= ~TANDEM; + + buf.sg_flags &= ~(ODDP|EVENP); + if (!(termios_p->c_cflag & PARENB)) + buf.sg_flags |= ODDP | EVENP; + else if (termios_p->c_cflag & PARODD) + buf.sg_flags |= ODDP; + else + buf.sg_flags |= EVENP; + + if (termios_p->c_lflag & _ECHO) + buf.sg_flags |= ECHO; + else + buf.sg_flags &= ~ECHO; + if (termios_p->c_lflag & ECHOE) + local |= LCRTERA; + else + local &= ~LCRTERA; + if (termios_p->c_lflag & ECHOK) + local |= LCRTKIL; + else + local &= ~LCRTKIL; + if (termios_p->c_lflag & _TOSTOP) + local |= LTOSTOP; + else + local &= ~LTOSTOP; + + buf.sg_erase = termios_p->c_cc[VERASE]; + buf.sg_kill = termios_p->c_cc[VKILL]; + tchars.t_eofc = termios_p->c_cc[VEOF]; + tchars.t_intrc = termios_p->c_cc[VINTR]; + tchars.t_quitc = termios_p->c_cc[VQUIT]; + ltchars.t_suspc = termios_p->c_cc[VSUSP]; + tchars.t_startc = termios_p->c_cc[VSTART]; + tchars.t_stopc = termios_p->c_cc[VSTOP]; + + if (ioctl(fd, TIOCSETP, &buf) < 0 || + ioctl(fd, TIOCSETC, &tchars) < 0 || + ioctl(fd, TIOCSLTC, <chars) < 0 || +#ifdef TIOCGETX + ioctl(fd, TIOCSETX, &extra) < 0 || +#endif + ioctl(fd, TIOCLSET, &local) < 0) + return -1; + return 0; +} + + +#undef tcgetattr + +/* Put the state of FD into *TERMIOS_P. */ +int +tcgetattr (int fd, struct termios *termios_p) +{ + struct sgttyb buf; + struct tchars tchars; + struct ltchars ltchars; + int local; +#ifdef TIOCGETX + int extra; +#endif + + if (termios_p == NULL) + { + errno = EINVAL; + return -1; + } + + if (ioctl(fd, TIOCGETP, &buf) < 0 || + ioctl(fd, TIOCGETC, &tchars) < 0 || + ioctl(fd, TIOCGLTC, <chars) < 0 || +#ifdef TIOCGETX + ioctl(fd, TIOCGETX, &extra) < 0 || +#endif + ioctl(fd, TIOCLGET, &local) < 0) + return -1; + + termios_p->__ispeed = __bsd_speeds[(unsigned char) buf.sg_ispeed]; + termios_p->__ospeed = __bsd_speeds[(unsigned char) buf.sg_ospeed]; + + termios_p->c_iflag = 0; + termios_p->c_oflag = 0; + termios_p->c_cflag = 0; + termios_p->c_lflag = 0; + termios_p->c_oflag |= CREAD | HUPCL; +#ifdef LPASS8 + if (local & LPASS8) + termios_p->c_oflag |= CS8; + else +#endif + termios_p->c_oflag |= CS7; + if (!(buf.sg_flags & RAW)) + { + termios_p->c_iflag |= IXON; + termios_p->c_cflag |= OPOST; +#ifndef NOISIG + termios_p->c_lflag |= ISIG; +#endif + } + if ((buf.sg_flags & (CBREAK|RAW)) == 0) + termios_p->c_lflag |= ICANON; + if (!(buf.sg_flags & RAW) && !(local & LLITOUT)) + termios_p->c_oflag |= OPOST; + if (buf.sg_flags & CRMOD) + termios_p->c_iflag |= ICRNL; + if (buf.sg_flags & TANDEM) + termios_p->c_iflag |= IXOFF; +#ifdef TIOCGETX + if (!(extra & NOISIG)) + termios_p->c_lflag |= ISIG; + if (extra & STOPB) + termios_p->c_cflag |= CSTOPB; +#endif + + switch (buf.sg_flags & (EVENP|ODDP)) + { + case EVENP|ODDP: + break; + case ODDP: + termios_p->c_cflag |= PARODD; + default: + termios_p->c_cflag |= PARENB; + termios_p->c_iflag |= IGNPAR | INPCK; + break; + } + if (buf.sg_flags & ECHO) + termios_p->c_lflag |= _ECHO; + if (local & LCRTERA) + termios_p->c_lflag |= ECHOE; + if (local & LCRTKIL) + termios_p->c_lflag |= ECHOK; + if (local & LTOSTOP) + termios_p->c_lflag |= _TOSTOP; + if (local & LNOFLSH) + termios_p->c_lflag |= _NOFLSH; + + termios_p->c_cc[VEOF] = tchars.t_eofc; + termios_p->c_cc[VEOL] = '\n'; + termios_p->c_cc[VERASE] = buf.sg_erase; + termios_p->c_cc[VKILL] = buf.sg_kill; + termios_p->c_cc[VINTR] = tchars.t_intrc; + termios_p->c_cc[VQUIT] = tchars.t_quitc; + termios_p->c_cc[VSTART] = tchars.t_startc; + termios_p->c_cc[VSTOP] = tchars.t_stopc; + termios_p->c_cc[VSUSP] = ltchars.t_suspc; + termios_p->c_cc[VMIN] = -1; + termios_p->c_cc[VTIME] = -1; + + return 0; +} diff --git a/boot/ux.c b/boot/ux.c new file mode 100644 index 00000000..b532f19e --- /dev/null +++ b/boot/ux.c @@ -0,0 +1,303 @@ +/* Hacks to make boot work under UX + + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <mach.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <cthreads.h> + +#include "ux.h" + +#if 0 +static int (* const _sc)(int, ...) = &syscall; +int _sc_print = 1; + +#define syscall(num, args...) \ + ({ int _rv, _num = (num), _pr = _sc_print; \ + _sc_print = 0; \ + if (_pr) printf ("syscall (%d) start\r\n", _num); \ + _rv = (*_sc) (_num , ##args); \ + if (_pr) printf ("syscall (%d) end\r\n", _num); \ + _sc_print = _pr; \ + _rv; \ + }) +#endif + +extern void __mach_init (); +void (*mach_init_routine)() = __mach_init; + +/* These will prevent the Hurd-ish versions from being used */ + +struct free_reply_port +{ + mach_port_t port; + struct free_reply_port *next; +}; +static struct free_reply_port *free_reply_ports = NULL; +static spin_lock_t free_reply_ports_lock = SPIN_LOCK_INITIALIZER; + +mach_port_t __mig_get_reply_port () +{ + spin_lock (&free_reply_ports_lock); + if (free_reply_ports == NULL) + { + spin_unlock (&free_reply_ports_lock); + return __mach_reply_port (); + } + else + { + struct free_reply_port *frp = free_reply_ports; + mach_port_t reply_port = frp->port; + free_reply_ports = free_reply_ports->next; + spin_unlock (&free_reply_ports_lock); + free (frp); + return reply_port; + } +} +mach_port_t mig_get_reply_port () +{ + return __mig_get_reply_port (); +} +void __mig_put_reply_port (mach_port_t port) +{ + struct free_reply_port *frp = malloc (sizeof (struct free_reply_port)); + frp->port = port; + spin_lock (&free_reply_ports_lock); + frp->next = free_reply_ports; + free_reply_ports = frp; + spin_unlock (&free_reply_ports_lock); +} +void mig_put_reply_port (mach_port_t port) +{ + __mig_put_reply_port (port); +} +void __mig_dealloc_reply_port (mach_port_t port) +{ + mach_port_mod_refs (__mach_task_self (), port, + MACH_PORT_RIGHT_RECEIVE, -1); +} +void mig_dealloc_reply_port (mach_port_t port) +{ + __mig_dealloc_reply_port (port); +} +void __mig_init (void *stack) {} +void mig_init (void *stack) {} + +int +task_by_pid (int pid) +{ + return syscall (-33, pid); +} + +int +write (int fd, + const void *buf, + int buflen) +{ + return syscall (4, fd, buf, buflen); +} + +int +read (int fd, + void *buf, + int buflen) +{ + return syscall (3, fd, buf, buflen); +} + +int +open (const char *name, + int flags, + int mode) +{ + return syscall (5, name, flags, mode); +} + +int +uxfstat (int fd, struct uxstat *buf) +{ + return syscall (62, fd, buf); +} + +int +close (int fd) +{ + return syscall (6, fd); +} + +int +lseek (int fd, + int off, + int whence) +{ + return syscall (19, fd, off, whence); +} + +int +uxexit (int code) +{ + return syscall (1, code); +} + +int +getpid () +{ + return syscall (20); +} + +int +ioctl (int fd, int code, void *buf) +{ + return syscall (54, fd, code, buf); +} + +int +sigblock (int mask) +{ + return syscall (109, mask); +} + +int +sigsetmask (int mask) +{ + return syscall (110, mask); +} + +int +sigpause (int mask) +{ + return syscall (111, mask); +} + + +#if 0 +void +sigreturn () +{ + asm volatile ("movl $0x67,%eax\n" + "lcall $0x7, $0x0\n" + "ret"); +} + +void +_sigreturn () +{ + asm volatile ("addl $0xc, %%esp\n" + "call %0\n" + "ret"::"m" (sigreturn)); +} + +int +sigvec (int sig, struct sigvec *vec, struct sigvec *ovec) +{ + asm volatile ("movl $0x6c,%%eax\n" + "movl %0, %%edx\n" + "orl $0x80000000, %%edx\n" + "lcall $0x7,$0x0\n" + "ret"::"g" (_sigreturn)); +} +#else +int sigvec (); +#endif + +void get_privileged_ports (mach_port_t *host_port, mach_port_t *device_port) +{ + *host_port = task_by_pid (-1); + *device_port = task_by_pid (-2); +} + +/* A *really* stupid printf that only understands %s & %d. */ +int +printf (const char *fmt, ...) +{ + va_list ap; + const char *p = fmt, *q = p; + + void flush (const char *new) + { + if (p > q) + write (1, q, p - q); + q = p = new; + } + + va_start (ap, fmt); + while (*p) + if (*p == '%' && p[1] == 's') + { + char *str = va_arg (ap, char *); + flush (p + 2); + write (1, str, strlen (str)); + } + else if (*p == '%' && p[1] == 'd') + { + int i = va_arg (ap, int); + char rbuf[20], *e = rbuf + sizeof (rbuf), *b = e; + + if (i == 0) + *--b = '0'; + else + while (i) + { + *--b = i % 10 + '0'; + i /= 10; + } + + flush (p + 2); + write (1, b, e - b); + } + else + p++; + va_end (ap); + + flush (0); + + return 0; +} + +static struct sgttyb term_sgb; +static int localbits; + +void +init_termstate () +{ + struct sgttyb sgb; + int bits; + ioctl (0, TIOCGETP, &term_sgb); + ioctl (0, TIOCLGET, &localbits); + /* Enter raw made. Rather than try and interpret these bits, + we just do what emacs does in .../emacs/src/sysdep.c for + an old style terminal driver. */ + bits = localbits | LDECCTQ | LLITOUT | LPASS8 | LNOFLSH; + ioctl (0, TIOCLSET, &bits); + sgb = term_sgb; + sgb.sg_flags &= ~ECHO; + sgb.sg_flags |= RAW | ANYP; + ioctl (0, TIOCSETN, &sgb); +} + +void +restore_termstate () +{ + ioctl (0, TIOCLSET, &localbits); + ioctl (0, TIOCSETN, &term_sgb); +} diff --git a/boot/ux.h b/boot/ux.h new file mode 100644 index 00000000..d3787c54 --- /dev/null +++ b/boot/ux.h @@ -0,0 +1,114 @@ +/* Hacks to make boot work under UX + + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define sigmask(m) (1 << ((m)-1)) + +#define IOCPARM_MASK 0x7f +#define IOC_OUT 0x40000000 +#define IOC_IN 0x80000000 +#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define FIONREAD _IOR('f', 127, int) +#define FIOASYNC _IOW('f', 125, int) +#define TIOCGETP _IOR('t', 8, struct sgttyb) +#define TIOCLGET _IOR('t', 124, int) +#define TIOCLSET _IOW('t', 125, int) +#define TIOCSETN _IOW('t', 10, struct sgttyb) +#define LDECCTQ 0x4000 +#define LLITOUT 0x0020 +#define LPASS8 0x0800 +#define LNOFLSH 0x8000 +#define RAW 0x0020 +#define ANYP 0x00c0 +#define ECHO 8 + + +struct sgttyb +{ + char unused[4]; + short sg_flags; +}; + +#define SIGIO 23 + +struct sigvec +{ + void (*sv_handler)(); + int sv_mask; + int sv_flags; +}; + +struct uxstat + { + short int st_dev; /* Device containing the file. */ + __ino_t st_ino; /* File serial number. */ + unsigned short int st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + unsigned short int st_uid; /* User ID of the file's owner. */ + unsigned short int st_gid; /* Group ID of the file's group.*/ + short int st_rdev; /* Device number, if device. */ + __off_t st_size; /* Size of file, in bytes. */ + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atime_usec; + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtime_usec; + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctime_usec; + unsigned long int st_blksize; /* Optimal block size for I/O. */ + unsigned long int st_blocks; /* Number of 512-byte blocks allocated. */ + long int st_spare[2]; + }; + +void get_privileged_ports (mach_port_t *host_port, mach_port_t *device_port); + +/* We can't include <unistd.h> for this, because that will fight witho + our definitions of syscalls below. */ +int syscall (int, ...); + +int open (const char *name, int flags, int mode); +int write (int fd, const void *buf, int len); +int read (int fd, void *buf, int len); +int uxfstat (int fd, struct uxstat *buf); +int close (int fd); +int lseek (int fd, int off, int whence); +int uxexit (int code); +int getpid (); +int ioctl (int fd, int code, void *buf); +int sigblock (int mask); +int sigsetmask (int mask); +int sigpause (int mask); +int sigvec (int sig, struct sigvec *vec, struct sigvec *ovec); + +#undef O_RDONLY +#undef O_WRONLY +#undef O_RDWR +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 + +#define host_exit(c) uxexit(c) + +typedef struct uxstat host_stat_t; +#define host_fstat(fd, st) uxfstat (fd, st) + +void init_stdio (); + +#undef errno +int errno; |