diff options
author | Marcus Brinkmann <marcus@gnu.org> | 2002-06-12 14:38:39 +0000 |
---|---|---|
committer | Marcus Brinkmann <marcus@gnu.org> | 2002-06-12 14:38:39 +0000 |
commit | 693eb63d90f9036680e538bc84275a32f707f926 (patch) | |
tree | e4f6e1890526dee1e6a40c824dc1725480979479 /console | |
parent | 609a7d4a162f97ff3ea6d59cb7326fbaaa960fd4 (diff) |
2002-06-12 Marcus Brinkmann <marcus@gnu.org>
* console.c: Include <argz.h>. Do not include "console.h", but
inline it. New macro DEFAULT_ENCODING.
(struct cons): De-const-ify member ENCODING.
(mycons, cons): Remove global variables.
(vcons_lookup): Use default encoding if CONS->encoding is not set.
(new_node): Access CONS through VCONS. Adjust size of display
node.
(netfs_attempt_read): Truncate length to read before reading.
(netfs_S_io_map): New function.
(options): New global variable.
(parse_opt): New function.
(netfs_append_args): New function.
(main): New variable CONS to hold console structure. Rediddle
initialization to allocate memory for it, parse arguments, and
create the root node in correct order. Also call display_init.
* console.h: Rewritten with new meaning. It now describes the
public interface of the console.
* display.c: Include <assert.h>, <error.h>, <hurd.h>,
<hurd/pager.h> and "console.h".
(struct screen): Removed.
(struct cursor): Remove members X, Y and status.
(struct user_pager_info): New struct.
(struct display): Remove member SCREEN, add new members USER, UPI,
MEMOBJ and MEMOBJ_SIZE.
(pager_bucket): New global variable.
(display_get_filemap): New function.
(pager_clear_user_data): Likewise.
(pager_read_page): Likewise.
(pager_write_page): Likewise.
(pager_unlock_page): Likewise.
(pager_report_extent): Likewise.
(pager_dropweak): Likewise.
(service_paging_requests): Likewise.
(screen_init): Renamed to ...
(user_create): ... this new function and changed to allocate
memory object and map it for USER data in display structure.
(screen_deinit): Renamed to ...
(user_destroy): ... this new function and rewrote it.
(MATRIX_POS): New macro.
(screen_fill): Take DISPLAY argument instead SCREEN. Use
MATRIX_POS.
(screen_scroll_up): Likewise.
(screen_scroll_down): Likewise.
(screen_scroll_left): Likewise.
(screen_scroll_right): Likewise.
(handle_esc_bracket_hl): Take DISPLAY argument instead CURSOR.
(handle_esc_bracket): Access screen and cursor fields correctly.
(display_output_one): Likewise.
(display_getsize): Likewise.
(display_init): New function.
(display_create): New variables width, height, lines. Call
user_create, not screen_init. Call user_destroy, not
screen_deinit.
(display_destroy): Call user_destroy, not
screen_deinit.
(display_read): Reimplement using memory mapping.
* display.h: New prototypes for display_init and display_get_filemap.
Diffstat (limited to 'console')
-rw-r--r-- | console/ChangeLog | 60 | ||||
-rw-r--r-- | console/console.c | 213 | ||||
-rw-r--r-- | console/console.h | 57 | ||||
-rw-r--r-- | console/display.c | 515 | ||||
-rw-r--r-- | console/display.h | 4 |
5 files changed, 601 insertions, 248 deletions
diff --git a/console/ChangeLog b/console/ChangeLog index 332a70ba..53fa34a8 100644 --- a/console/ChangeLog +++ b/console/ChangeLog @@ -1,3 +1,63 @@ +2002-06-12 Marcus Brinkmann <marcus@gnu.org> + + * console.c: Include <argz.h>. Do not include "console.h", but + inline it. New macro DEFAULT_ENCODING. + (struct cons): De-const-ify member ENCODING. + (mycons, cons): Remove global variables. + (vcons_lookup): Use default encoding if CONS->encoding is not set. + (new_node): Access CONS through VCONS. Adjust size of display + node. + (netfs_attempt_read): Truncate length to read before reading. + (netfs_S_io_map): New function. + (options): New global variable. + (parse_opt): New function. + (netfs_append_args): New function. + (main): New variable CONS to hold console structure. Rediddle + initialization to allocate memory for it, parse arguments, and + create the root node in correct order. Also call display_init. + * console.h: Rewritten with new meaning. It now describes the + public interface of the console. + * display.c: Include <assert.h>, <error.h>, <hurd.h>, + <hurd/pager.h> and "console.h". + (struct screen): Removed. + (struct cursor): Remove members X, Y and status. + (struct user_pager_info): New struct. + (struct display): Remove member SCREEN, add new members USER, UPI, + MEMOBJ and MEMOBJ_SIZE. + (pager_bucket): New global variable. + (display_get_filemap): New function. + (pager_clear_user_data): Likewise. + (pager_read_page): Likewise. + (pager_write_page): Likewise. + (pager_unlock_page): Likewise. + (pager_report_extent): Likewise. + (pager_dropweak): Likewise. + (service_paging_requests): Likewise. + (screen_init): Renamed to ... + (user_create): ... this new function and changed to allocate + memory object and map it for USER data in display structure. + (screen_deinit): Renamed to ... + (user_destroy): ... this new function and rewrote it. + (MATRIX_POS): New macro. + (screen_fill): Take DISPLAY argument instead SCREEN. Use + MATRIX_POS. + (screen_scroll_up): Likewise. + (screen_scroll_down): Likewise. + (screen_scroll_left): Likewise. + (screen_scroll_right): Likewise. + (handle_esc_bracket_hl): Take DISPLAY argument instead CURSOR. + (handle_esc_bracket): Access screen and cursor fields correctly. + (display_output_one): Likewise. + (display_getsize): Likewise. + (display_init): New function. + (display_create): New variables width, height, lines. Call + user_create, not screen_init. Call user_destroy, not + screen_deinit. + (display_destroy): Call user_destroy, not + screen_deinit. + (display_read): Reimplement using memory mapping. + * display.h: New prototypes for display_init and display_get_filemap. + 2002-06-09 Marcus Brinkmann <marcus@gnu.org> * display.c (struct cursor): Change type of all members from int diff --git a/console/console.c b/console/console.c index c0dbf4f5..3c1c5ce2 100644 --- a/console/console.c +++ b/console/console.c @@ -16,25 +16,27 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <hurd/netfs.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> #include <unistd.h> #include <argp.h> +#include <argz.h> #include <error.h> #include <string.h> #include <fcntl.h> #include <dirent.h> #include <sys/mman.h> #include <sys/stat.h> +#include <rwlock.h> +#include <maptime.h> #include <cthreads.h> -#include <mcheck.h> #include <version.h> -#include "console.h" +#include <hurd/netfs.h> + #include "display.h" #include "input.h" @@ -44,6 +46,11 @@ char *netfs_server_name = "console"; char *netfs_server_version = HURD_VERSION; int netfs_maxsymlinks = 16; /* Arbitrary. */ +/* Handy source of time. */ +volatile struct mapped_time_value *console_maptime; + +#define DEFAULT_ENCODING "ISO-8859-1" + struct vcons { @@ -68,24 +75,28 @@ struct vcons struct node *disp_node; struct node *inpt_node; }; +/* A handle for a virtual console device. */ +typedef struct vcons *vcons_t; struct cons { /* The lock protects the console, all virtual consoles contained in - it and the reference counters. It also locks the - configuration. */ + it and the reference counters. It also locks the configuration + parameters. */ struct mutex lock; vcons_t vcons_list; /* The encoding. */ - const char *encoding; + char *encoding; struct node *node; mach_port_t underlying; /* A template for the stat information of all nodes. */ struct stat stat_template; -} mycons; -cons_t cons = &mycons; +}; +/* A handle for a console device. */ +typedef struct cons *cons_t; + /* Lookup the virtual console with number ID in the console CONS, acquire a reference for it, and return it in R_VCONS. If CREATE is true, the virtual console will be created if it doesn't exist yet. @@ -150,7 +161,7 @@ vcons_lookup (cons_t cons, int id, int create, vcons_t *r_vcons) /* XXX Error checking. */ mutex_init (&vcons->lock); - err = display_create (&vcons->display, cons->encoding); + err = display_create (&vcons->display, cons->encoding ?: DEFAULT_ENCODING); if (err) { free (vcons->name); @@ -159,7 +170,7 @@ vcons_lookup (cons_t cons, int id, int create, vcons_t *r_vcons) return err; } - err = input_create (&vcons->input, cons->encoding); + err = input_create (&vcons->input, cons->encoding ?: DEFAULT_ENCODING); if (err) { display_destroy (vcons->display); @@ -268,7 +279,7 @@ new_node (struct node **np, vcons_t vcons, vcons_node_type type) free (nn); return ENOMEM; } - (*np)->nn_stat = cons->stat_template; + (*np)->nn_stat = vcons->cons->stat_template; (*np)->nn_translated = 0; switch (type) @@ -288,7 +299,7 @@ new_node (struct node **np, vcons_t vcons, vcons_node_type type) (*np)->nn_stat.st_ino = (vcons->id << 2) + 2; (*np)->nn_stat.st_mode |= S_IFREG; (*np)->nn_stat.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); - (*np)->nn_stat.st_size = 2008 * sizeof (wchar_t); /* XXX */ + (*np)->nn_stat.st_size = 2011 * sizeof (wchar_t); /* XXX */ break; case VCONS_NODE_INPUT: (*np)->nn_stat.st_ino = (vcons->id << 2) + 3; @@ -300,14 +311,14 @@ new_node (struct node **np, vcons_t vcons, vcons_node_type type) /* If the underlying node isn't a directory, propagate read permission to execute permission since we need that for lookups. */ - if (! S_ISDIR (cons->stat_template.st_mode) + if (! S_ISDIR (vcons->cons->stat_template.st_mode) && S_ISDIR ((*np)->nn_stat.st_mode)) { - if (cons->stat_template.st_mode & S_IRUSR) + if (vcons->cons->stat_template.st_mode & S_IRUSR) (*np)->nn_stat.st_mode |= S_IXUSR; - if (cons->stat_template.st_mode & S_IRGRP) + if (vcons->cons->stat_template.st_mode & S_IRGRP) (*np)->nn_stat.st_mode |= S_IXGRP; - if (cons->stat_template.st_mode & S_IROTH) + if (vcons->cons->stat_template.st_mode & S_IROTH) (*np)->nn_stat.st_mode |= S_IXOTH; } @@ -1037,11 +1048,14 @@ netfs_attempt_read (struct iouser *cred, struct node *np, else { /* Pass display content to caller. */ - ssize_t amt; + ssize_t amt = *len; assert (np == vcons->disp_node); - amt = display_read (vcons->display, - /* cred->po->openstat & O_NONBLOCK */ 0, - offset, data, *len); + + if (amt > np->nn_stat.st_size) + amt = np->nn_stat.st_size; + amt = display_read (vcons->display, + /* cred->po->openstat & O_NONBLOCK */ 0, + offset, data, amt); if (amt == -1) err = errno; else @@ -1094,44 +1108,175 @@ netfs_attempt_write (struct iouser *cred, struct node *np, } +/* Implement io_map as described in <hurd/io.defs>. */ +kern_return_t +netfs_S_io_map (struct protid *cred, + memory_object_t *rdobj, + mach_msg_type_name_t *rdtype, + memory_object_t *wrobj, + mach_msg_type_name_t *wrtype) +{ + int flags; + struct node *np; + vcons_t vcons; + + if (!cred) + return EOPNOTSUPP; + + np = cred->po->np; + vcons = np->nn->vcons; + if (!vcons || np != vcons->disp_node) + return EOPNOTSUPP; + + *wrobj = *rdobj = MACH_PORT_NULL; + + flags = cred->po->openstat & (O_READ | O_WRITE); + + mutex_lock (&np->lock); + switch (flags) + { + case O_READ | O_WRITE: + *wrobj = *rdobj = display_get_filemap (vcons->display, + VM_PROT_READ | VM_PROT_WRITE); + if (*wrobj == MACH_PORT_NULL) + goto error; + mach_port_mod_refs (mach_task_self (), *rdobj, MACH_PORT_RIGHT_SEND, 1); + break; + case O_READ: + *rdobj = display_get_filemap (vcons->display, VM_PROT_READ); + if (*rdobj == MACH_PORT_NULL) + goto error; + break; + case O_WRITE: + *wrobj = display_get_filemap (vcons->display, VM_PROT_WRITE); + if (*wrobj == MACH_PORT_NULL) + goto error; + break; + } + mutex_unlock (&np->lock); + + *rdtype = MACH_MSG_TYPE_MOVE_SEND; + *wrtype = MACH_MSG_TYPE_MOVE_SEND; + + return 0; + + error: + mutex_unlock (&np->lock); + return errno; +} + + +static const struct argp_option options[] = +{ + {"encoding", 'e', "NAME", 0, "Set encoding of virtual consoles to" + " NAME (default `" DEFAULT_ENCODING "')" }, + {0} +}; + +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + cons_t cons = state->input; + + switch (opt) + { + default: + return ARGP_ERR_UNKNOWN; + case ARGP_KEY_SUCCESS: + case ARGP_KEY_ERROR: + break; + + case ARGP_KEY_INIT: + mutex_lock (&cons->lock); + break; + + case ARGP_KEY_FINI: + mutex_unlock (&cons->lock); + break; + + case 'e': + /* XXX Check validity of encoding. Can we perform all necessary + conversions? */ + { + char *new = strdup (arg); + if (!new) + return ENOMEM; + if (cons->encoding) + free (cons->encoding); + cons->encoding = new; + } + break; + } + return 0; +} + +/* Return an argz string describing the current options. Fill *ARGZ + with a pointer to newly malloced storage holding the list and *LEN + to the length of that storage. */ +error_t +netfs_append_args (char **argz, size_t *argz_len) +{ + error_t err = 0; + cons_t cons = netfs_root_node->nn->cons; + + if (cons->encoding && strcmp (cons->encoding, DEFAULT_ENCODING)) + { + char *buf; + asprintf (&buf, "--encoding=%s", cons->encoding); + if (buf) + err = argz_add (argz, argz_len, buf); + else + err = errno; + } + return err; +} + + int main (int argc, char **argv) { error_t err; mach_port_t bootstrap; struct stat ul_stat; - struct netnode root_nn = { cons: cons, vcons: 0 }; + cons_t cons; + struct netnode root_nn = { vcons: 0 }; + struct argp argp = { options, parse_opt, NULL, + "A translator that provides virtual consoles." }; - mtrace(); - struct argp argp - = { NULL, NULL, NULL, - "A translator that provides virtual console displays." }; + cons = malloc (sizeof (struct cons)); + if (!malloc) + error (1, ENOMEM, "Cannot create console structure"); + mutex_init (&cons->lock); + cons->encoding = NULL; + cons->vcons_list = NULL; + root_nn.cons = cons; /* Parse our command line arguments (all none of them). */ - argp_parse (&argp, argc, argv, 0, 0, 0); + argp_parse (&argp, argc, argv, 0, 0, cons); task_get_bootstrap_port (mach_task_self (), &bootstrap); + netfs_init (); + display_init (); + /* Create the root node (some attributes initialized below). */ netfs_root_node = netfs_make_node (&root_nn); if (! netfs_root_node) - error (5, ENOMEM, "Cannot create root node"); + error (2, ENOMEM, "Cannot create root node"); err = maptime_map (0, 0, &console_maptime); if (err) - error (6, err, "Cannot map time"); + error (3, err, "Cannot map time"); - mutex_init (&cons->lock); - cons->encoding = "ISO-8859-1"; cons->node = netfs_root_node; cons->underlying = netfs_startup (bootstrap, O_READ); if (cons->underlying == MACH_PORT_NULL) - error (5, err, "Cannot get underlying node"); + error (4, err, "Cannot get underlying node"); err = io_stat (cons->underlying, &ul_stat); if (err) - error (6, err, "Cannot stat underlying node"); + error (5, err, "Cannot stat underlying node"); /* CONS.stat_template contains some fields that are inherited by all nodes we create. */ @@ -1164,8 +1309,8 @@ main (int argc, char **argv) fshelp_touch (&netfs_root_node->nn_stat, TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME, console_maptime); - netfs_server_loop (); /* Never returns. */ - + netfs_server_loop (); + /*NOTREACHED*/ return 0; } diff --git a/console/console.h b/console/console.h index 3642bfe4..27996955 100644 --- a/console/console.h +++ b/console/console.h @@ -1,4 +1,4 @@ -/* console.h -- Interfaces for the console server. +/* console.h -- Public interface to the console server. Copyright (C) 2002 Free Software Foundation, Inc. Written by Marcus Brinkmann. @@ -16,20 +16,51 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef CONSOLE_H -#define CONSOLE_H +#ifndef _HURD_CONSOLE_H +#define _HURD_CONSOLE_H -#include <hurd/netfs.h> -#include <rwlock.h> -#include <maptime.h> +#include <sys/types.h> -/* Handy source of time. */ -volatile struct mapped_time_value *console_maptime; +struct cons_display +{ +#define CONS_MAGIC 0x48555244 /* Hex for "HURD". */ + u_int32_t magic; /* CONS_MAGIC, use to detect + endianess. */ +#define CONS_VERSION_MAJ 0x0 +#define CONS_VERSION_MAJ_SHIFT 16 +#define CONS_VERSION_AGE 0x0 + u_int32_t version; /* Version of interface. Lower 16 + bits define the age, upper 16 bits + the major version. */ + struct + { + u_int32_t width; /* Width of screen matrix. */ + u_int32_t lines; /* Length of whole matrix. */ + u_int32_t cur_line; /* Beginning of visible area. */ + u_int32_t scr_lines;/* Number of lines in scrollback buffer + preceeding CUR_LINE. */ + u_int32_t height; /* Number of lines in visible area following + (and including) CUR_LINE. */ + u_int32_t matrix; /* Index (in wchar_t) of the beginning of + screen matrix in this structure. */ + } screen; -/* A handle for a console device. */ -typedef struct cons *cons_t; + struct + { + u_int32_t col; /* Current column (x-position) of cursor. */ + u_int32_t row; /* Current row (y-position) of cursor. */ -/* A handle for a virtual console device. */ -typedef struct vcons *vcons_t; +#define CONS_CURSOR_INVISIBLE 0 +#define CONS_CURSOR_NORMAL 1 +#define CONS_CURSOR_VERY_VISIBLE 2 + u_int32_t status; /* Visibility status of cursor. */ + } cursor; -#endif /* CONSOLE_H */ + /* Don't use this, use ((wchar_t *) cons_display + + cons_display.screen.matrix) instead. This will make your client + upward compatible with future versions of this interface. */ + wchar_t _matrix[0]; +}; + + +#endif /* _HURD_CONSOLE_H */ diff --git a/console/display.c b/console/display.c index 0fffba24..9c33b933 100644 --- a/console/display.c +++ b/console/display.c @@ -25,47 +25,27 @@ #include <iconv.h> #include <argp.h> #include <string.h> +#include <assert.h> +#include <error.h> #include <sys/io.h> -#include <sys/mman.h> #include <sys/fcntl.h> +#include <sys/mman.h> #include <cthreads.h> +#include <hurd.h> +#include <hurd/pager.h> + #ifndef __STDC_ISO_10646__ #error It is required that wchar_t is UCS-4. #endif +#include "console.h" #include "display.h" -struct screen -{ - /* A screen matrix, including the scroll back buffer. */ - wchar_t *matrix; - - /* The size of the screen, in lines. */ - int lines; - - /* The top most line of the screen in the video buffer. */ - int current_line; - - /* Maximum number of lines scrolled back. */ - int scrolling_max; - - int width; - int height; -}; -typedef struct screen *screen_t; - struct cursor { - /* The visibility of the cursor. */ - u_int32_t status; -#define CURSOR_INVISIBLE 1 -#define CURSOR_STANDOUT 2 - - u_int32_t x; - u_int32_t y; u_int32_t saved_x; u_int32_t saved_y; }; @@ -128,107 +108,251 @@ struct attr }; typedef struct attr *attr_t; +struct user_pager_info +{ + display_t display; + struct pager *p; +}; + struct display { /* The lock for the virtual console display structure. */ struct mutex lock; - struct screen screen; - struct cursor cursor; - struct output output; - struct attr attr; - /* Indicates if OWNER_ID is initialized. */ int has_owner; /* Specifies the ID of the process that should receive the WINCH signal for this virtual console. */ int owner_id; + + struct cursor cursor; + struct output output; + struct attr attr; + struct cons_display *user; + + struct user_pager_info *upi; + memory_object_t memobj; + size_t memobj_size; }; + +/* We need a separate bucket for the pager ports. */ +struct port_bucket *pager_bucket; + +mach_port_t +display_get_filemap (display_t display, vm_prot_t prot) +{ + error_t err; + + /* Add a reference for each call, the caller will deallocate it. */ + err = mach_port_mod_refs (mach_task_self (), display->memobj, + MACH_PORT_RIGHT_SEND, +1); + assert_perror (err); + + return display->memobj; +} + +/* Implement the pager_clear_user_data callback from the pager library. */ +void +pager_clear_user_data (struct user_pager_info *upi) +{ + free (upi); +} + +/* XXX This is not good enough. We actually need to provide a backing + store. */ +error_t +pager_read_page (struct user_pager_info *pager, vm_offset_t page, + vm_address_t *buf, int *writelock) +{ + /* This is a read-only medium */ + *writelock = 1; + + *buf = (vm_address_t) mmap (0, vm_page_size, PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + return 0; +} +error_t +pager_write_page (struct user_pager_info *pager, + vm_offset_t page, + vm_address_t buf) +{ + /* XXX Implement me. */ + assert (0); +} + +error_t +pager_unlock_page (struct user_pager_info *pager, + vm_offset_t address) +{ + return 0; +} + +/* Tell how big the file is. */ +error_t +pager_report_extent (struct user_pager_info *upi, + vm_address_t *offset, + vm_size_t *size) +{ + display_t display = upi->display; + *offset = 0; + *size = display->memobj_size; + return 0; +} + +void +pager_dropweak (struct user_pager_info *upi) +{ +} + +/* A top-level function for the paging thread that just services paging + requests. */ +static void +service_paging_requests (any_t arg) +{ + struct port_bucket *pager_bucket = arg; + for (;;) + ports_manage_port_operations_multithread (pager_bucket, + pager_demuxer, + 1000 * 60 * 2, + 1000 * 60 * 10, 0); +} + + static error_t -screen_init (screen_t screen) +user_create (display_t display, u_int32_t width, u_int32_t height, + u_int32_t lines) { - screen->width = 80; - screen->height = 25; - screen->lines = 25; /* XXX For now. */ - screen->current_line = 0; - screen->matrix = calloc (screen->lines * screen->width, sizeof (wchar_t)); - if (!screen->matrix) - return ENOMEM; + error_t err; + struct cons_display *user; + display->memobj_size = round_page (sizeof (struct cons_display) + + sizeof (u_int32_t) * width * lines); + + display->upi = malloc (sizeof (struct user_pager_info)); + if (!display->upi) + return MACH_PORT_NULL; + display->upi->display = display; + /* 1 & MOCD correct? */ + display->upi->p = pager_create (display->upi, pager_bucket, + 1, MEMORY_OBJECT_COPY_DELAY); + if (display->upi->p == 0) + { + free (display->upi); + return errno; + } + display->memobj = pager_get_port (display->upi->p); + ports_port_deref (display->upi->p); + + mach_port_insert_right (mach_task_self (), display->memobj, display->memobj, + MACH_MSG_TYPE_MAKE_SEND); + + err = vm_map (mach_task_self (), + (vm_address_t *) &user, (vm_size_t) display->memobj_size, + (vm_address_t) 0, + 1 /* ! (flags & MAP_FIXED) */, + display->memobj, 0 /* (vm_offset_t) offset */, + 0 /* ! (flags & MAP_SHARED) */, + VM_PROT_READ | VM_PROT_WRITE, + VM_PROT_READ | VM_PROT_WRITE, + VM_INHERIT_NONE); + if (err) + { + /* UPI will be cleaned up by libpager. */ + mach_port_deallocate (mach_task_self (), display->memobj); + return err; + } + + user->magic = CONS_MAGIC; + user->version = CONS_VERSION_MAJ << 16 | CONS_VERSION_AGE; + user->screen.width = width; + user->screen.height = height; + user->screen.lines = lines; + user->screen.cur_line = 0; + user->screen.scr_lines = 0; + user->screen.matrix = sizeof (struct cons_display) / sizeof (u_int32_t); + user->cursor.col = 0; + user->cursor.row = 0; + user->cursor.status = CONS_CURSOR_NORMAL; + wmemset (user->_matrix, L' ', user->screen.width * user->screen.lines); - wmemset (screen->matrix, L' ', screen->height * screen->width); /* XXX Set attribute flags. */ + display->user = user; return 0; } static void -screen_deinit (screen_t screen) +user_destroy (display_t display) { - free (screen->matrix); + /* The pager will be deallocated by libpager. */ + mach_port_deallocate (mach_task_self (), display->memobj); } + +#define MATRIX_POS(user,x,y) ((user)->_matrix \ + + (((user)->screen.cur_line + (y)) % (user)->screen.height) \ + * (user)->screen.width + (x)) + static void -screen_fill (screen_t screen, size_t x, size_t y, size_t w, size_t h, +screen_fill (display_t display, size_t x, size_t y, size_t w, size_t h, wchar_t chr, char attr) { - wchar_t *matrixp = screen->matrix - + ((screen->current_line + y) % screen->height) * screen->width + x; + struct cons_display *user = display->user; + wchar_t *matrixp = MATRIX_POS (user, x, y); while (h--) { /* XXX Set attribute flags. */ wmemset (matrixp, L' ', w); - matrixp += screen->width; + matrixp += user->screen.width; } - /* XXX Flag screen change, but here? */ + /* XXX Flag screen change, but here or where else? */ } static void -screen_scroll_up (screen_t screen, size_t x, size_t y, size_t w, size_t h, +screen_scroll_up (display_t display, size_t x, size_t y, size_t w, size_t h, int amt, wchar_t chr, char attr) { - wchar_t *matrixp = screen->matrix - + ((screen->current_line + y) % screen->height) * screen->width + x; + struct cons_display *user = display->user; + wchar_t *matrixp = MATRIX_POS (user, x, y); if (amt < 0) return; while (h-- > amt) { - wmemcpy (matrixp, matrixp + amt * screen->width, w); - matrixp += screen->width; + wmemcpy (matrixp, matrixp + amt * user->screen.width, w); + matrixp += user->screen.width; } - screen_fill (screen, x, y, w, h, chr, attr); + screen_fill (display, x, y, w, h, chr, attr); } static void -screen_scroll_down (screen_t screen, size_t x, size_t y, size_t w, size_t h, +screen_scroll_down (display_t display, size_t x, size_t y, size_t w, size_t h, int amt, wchar_t chr, char attr) { - wchar_t *matrixp = screen->matrix - + ((screen->current_line + y + h - 1) % screen->height) - * screen->width + x; + struct cons_display *user = display->user; + wchar_t *matrixp = MATRIX_POS (user, x, y + h - 1); if (amt < 0) return; while (h-- > amt) { - wmemcpy (matrixp, matrixp - amt * screen->width, w); - matrixp -= screen->width; + wmemcpy (matrixp, matrixp - amt * user->screen.width, w); + matrixp -= user->screen.width; } - screen_fill (screen, x, y, w, h, chr, attr); + screen_fill (display, x, y, w, h, chr, attr); } static void -screen_scroll_left (screen_t screen, size_t x, size_t y, size_t w, size_t h, +screen_scroll_left (display_t display, size_t x, size_t y, size_t w, size_t h, int amt, wchar_t chr, char attr) { + struct cons_display *user = display->user; + wchar_t *matrixp = MATRIX_POS (user, x, y); int i; - wchar_t *matrixp = screen->matrix - + ((screen->current_line + y) % screen->height) * screen->width + x; if (amt < 0) return; @@ -238,18 +362,18 @@ screen_scroll_left (screen_t screen, size_t x, size_t y, size_t w, size_t h, for (i = 0; i < y + h; i++) { wmemmove (matrixp, matrixp + amt, w - amt); - matrixp += screen->width; + matrixp += user->screen.width; } - screen_fill (screen, x + w - amt, y, amt, h, chr, attr); + screen_fill (display, x + w - amt, y, amt, h, chr, attr); } static void -screen_scroll_right (screen_t screen, size_t x, size_t y, size_t w, size_t h, +screen_scroll_right (display_t display, size_t x, size_t y, size_t w, size_t h, int amt, wchar_t chr, char attr) { + struct cons_display *user = display->user; + wchar_t *matrixp = MATRIX_POS (user, x, y); int i; - wchar_t *matrixp = screen->matrix - + ((screen->current_line + y) % screen->height) * screen->width + x; if (amt < 0) return; @@ -259,9 +383,9 @@ screen_scroll_right (screen_t screen, size_t x, size_t y, size_t w, size_t h, for (i = 0; i < y + h; i++) { wmemmove (matrixp + amt, matrixp, w - amt); - matrixp += screen->width; + matrixp += user->screen.width; } - screen_fill (screen, x, y, amt, h, chr, attr); + screen_fill (display, x, y, amt, h, chr, attr); } @@ -289,16 +413,16 @@ output_deinit (output_t output) static void -handle_esc_bracket_hl (cursor_t cursor, int code, int flag) +handle_esc_bracket_hl (display_t display, int code, int flag) { switch (code) { case 34: /* Cursor standout: <cnorm>, <cvvis>. */ if (flag) - cursor->status |= CURSOR_STANDOUT; + display->user->cursor.status = CONS_CURSOR_VERY_VISIBLE; else - cursor->status &= ~CURSOR_STANDOUT; + display->user->cursor.status = CONS_CURSOR_NORMAL; /* XXX Flag cursor status change. */ break; } @@ -390,20 +514,21 @@ handle_esc_bracket_m (attr_t attr, int code) static void handle_esc_bracket (display_t display, char op) { + struct cons_display *user = display->user; parse_t parse = &display->output.parse; int i; static void limit_cursor (void) { - if (display->cursor.x >= display->screen.width) - display->cursor.x = display->screen.width - 1; - else if (display->cursor.x < 0) - display->cursor.x = 0; + if (user->cursor.col >= user->screen.width) + user->cursor.col = user->screen.width - 1; + else if (user->cursor.col < 0) + user->cursor.col = 0; - if (display->cursor.y >= display->screen.height) - display->cursor.y = display->screen.height - 1; - else if (display->cursor.y < 0) - display->cursor.y = 0; + if (user->cursor.row >= user->screen.height) + user->cursor.row = user->screen.height - 1; + else if (user->cursor.row < 0) + user->cursor.row = 0; /* XXX Flag cursor change. */ } @@ -413,64 +538,64 @@ handle_esc_bracket (display_t display, char op) case 'H': case 'f': /* Cursor position: <cup>. */ - display->cursor.x = parse->params[1] - 1; - display->cursor.y = parse->params[0] - 1; + user->cursor.col = parse->params[1] - 1; + user->cursor.row = parse->params[0] - 1; limit_cursor (); break; case 'G': /* Horizontal position: <hpa>. */ - display->cursor.x = parse->params[0] - 1; + user->cursor.col = parse->params[0] - 1; limit_cursor (); break; case 'F': /* Beginning of previous line. */ - display->cursor.x = 0; + user->cursor.col = 0; /* fall through */ case 'A': /* Cursor up: <cuu>, <cuu1>. */ - display->cursor.y -= (parse->params[0] ?: 1); + user->cursor.row -= (parse->params[0] ?: 1); limit_cursor (); break; case 'E': /* Beginning of next line. */ - display->cursor.x = 0; + user->cursor.col = 0; /* Fall through. */ case 'B': /* Cursor down: <cud1>, <cud>. */ - display->cursor.y += (parse->params[0] ?: 1); + user->cursor.row += (parse->params[0] ?: 1); limit_cursor (); break; case 'C': /* Cursor right: <cuf1>, <cuf>. */ - display->cursor.x += (parse->params[0] ?: 1); + user->cursor.col += (parse->params[0] ?: 1); limit_cursor (); break; case 'D': /* Cursor left: <cub>, <cub1>. */ - display->cursor.x -= (parse->params[0] ?: 1); + user->cursor.col -= (parse->params[0] ?: 1); limit_cursor (); break; case 's': /* Save cursor position: <sc>. */ - display->cursor.saved_x = display->cursor.x; - display->cursor.saved_y = display->cursor.y; + display->cursor.saved_x = user->cursor.col; + display->cursor.saved_y = user->cursor.row; break; case 'u': /* Restore cursor position: <rc>. */ - display->cursor.x = display->cursor.saved_x; - display->cursor.y = display->cursor.saved_y; + user->cursor.col = display->cursor.saved_x; + user->cursor.row = display->cursor.saved_y; /* In case the screen was larger before: */ limit_cursor (); break; case 'h': /* Reset mode. */ for (i = 0; i < parse->nparams; i++) - handle_esc_bracket_hl (&display->cursor, parse->params[i], 0); + handle_esc_bracket_hl (display, parse->params[i], 0); break; case 'l': /* Set mode. */ for (i = 0; i < parse->nparams; i++) - handle_esc_bracket_hl (&display->cursor, parse->params[i], 1); + handle_esc_bracket_hl (display, parse->params[i], 1); break; case 'm': for (i = 0; i < parse->nparams; i++) @@ -481,27 +606,27 @@ handle_esc_bracket (display_t display, char op) { case 0: /* Clear to end of screen: <ed>. */ - screen_fill (&display->screen, display->cursor.x, display->cursor.y, - display->screen.width - display->cursor.x, 1, L' ', + screen_fill (display, user->cursor.col, user->cursor.row, + user->screen.width - user->cursor.col, 1, L' ', display->attr.current); - screen_fill (&display->screen, 0, display->cursor.y + 1, - display->screen.width, - display->screen.height - display->cursor.y, + screen_fill (display, 0, user->cursor.row + 1, + user->screen.width, + user->screen.height - user->cursor.row, L' ', display->attr.current); break; case 1: /* Clear to beginning of screen. */ - screen_fill (&display->screen, 0, 0, - display->screen.width, display->cursor.y, + screen_fill (display, 0, 0, + user->screen.width, user->cursor.row, L' ', display->attr.current); - screen_fill (&display->screen, 0, display->cursor.y, - display->cursor.x + 1, 1, + screen_fill (display, 0, user->cursor.row, + user->cursor.col + 1, 1, L' ', display->attr.current); break; case 2: /* Clear entire screen. */ - screen_fill (&display->screen, 0, 0, - display->screen.width, display->screen.height, + screen_fill (display, 0, 0, + user->screen.width, user->screen.height, L' ', display->attr.current); break; } @@ -511,73 +636,73 @@ handle_esc_bracket (display_t display, char op) { case 0: /* Clear to end of line: <el>. */ - screen_fill (&display->screen, display->cursor.x, display->cursor.y, - display->screen.width - display->cursor.x, 1, + screen_fill (display, user->cursor.col, user->cursor.row, + user->screen.width - user->cursor.col, 1, L' ', display->attr.current); break; case 1: /* Clear to beginning of line: <el1>. */ - screen_fill (&display->screen, 0, display->cursor.y, - display->cursor.x + 1, 1, + screen_fill (display, 0, user->cursor.row, + user->cursor.col + 1, 1, L' ', display->attr.current); break; case 2: /* Clear entire line. */ - screen_fill (&display->screen, 0, display->cursor.y, - display->screen.width, 1, + screen_fill (display, 0, user->cursor.row, + user->screen.width, 1, L' ', display->attr.current); break; } break; case 'L': /* Insert line(s): <il1>, <il>. */ - screen_scroll_down (&display->screen, 0, display->cursor.y, - display->screen.width, - display->screen.height - display->cursor.y, + screen_scroll_down (display, 0, user->cursor.row, + user->screen.width, + user->screen.height - user->cursor.row, parse->params[0] ?: 1, L' ', display->attr.current); break; case 'M': /* Delete line(s): <dl1>, <dl>. */ - screen_scroll_up (&display->screen, 0, display->cursor.y, - display->screen.width, - display->screen.height - display->cursor.y, + screen_scroll_up (display, 0, user->cursor.row, + user->screen.width, + user->screen.height - user->cursor.row, parse->params[0] ?: 1, L' ', display->attr.current); break; case '@': /* Insert character(s): <ich1>, <ich>. */ - screen_scroll_right (&display->screen, display->cursor.x, - display->cursor.y, - display->screen.width - display->cursor.x, 1, + screen_scroll_right (display, user->cursor.col, + user->cursor.row, + user->screen.width - user->cursor.col, 1, parse->params[0] ?: 1, L' ', display->attr.current); break; case 'P': /* Delete character(s): <dch1>, <dch>. */ - screen_scroll_left (&display->screen, display->cursor.x, - display->cursor.y, - display->screen.width - display->cursor.x, 1, + screen_scroll_left (display, user->cursor.col, + user->cursor.row, + user->screen.width - user->cursor.col, 1, parse->params[0] ?: 1, L' ', display->attr.current); break; case 'S': /* Scroll up: <ind>, <indn>. */ - screen_scroll_up (&display->screen, 0, 0, - display->screen.width, display->screen.height, + screen_scroll_up (display, 0, 0, + user->screen.width, user->screen.height, parse->params[0] ?: 1, L' ', display->attr.current); break; case 'T': /* Scroll down: <ri>, <rin>. */ - screen_scroll_down (&display->screen, 0, 0, - display->screen.width, display->screen.height, + screen_scroll_down (display, 0, 0, + user->screen.width, user->screen.height, parse->params[0] ?: 1, L' ', display->attr.current); break; case 'X': /* Erase character(s): <ech>. */ - screen_fill (&display->screen, display->cursor.x, display->cursor.y, + screen_fill (display, user->cursor.col, user->cursor.row, parse->params[0] ?: 1, 1, L' ', display->attr.current); break; @@ -592,9 +717,9 @@ handle_esc_bracket_question_hl (display_t display, int code, int flag) case 25: /* Cursor invisibility: <civis>, <cnorm>. */ if (flag) - display->cursor.status |= CURSOR_INVISIBLE; + display->user->cursor.status = CONS_CURSOR_INVISIBLE; else - display->cursor.status &= ~CURSOR_INVISIBLE; + display->user->cursor.status = CONS_CURSOR_NORMAL; /* XXX Flag cursor status change. */ break; } @@ -626,26 +751,27 @@ handle_esc_bracket_question (display_t display, char op) static void display_output_one (display_t display, wchar_t chr) { + struct cons_display *user = display->user; parse_t parse = &display->output.parse; void newline (void) { - if (display->cursor.y < display->screen.height - 1) + if (user->cursor.row < user->screen.height - 1) { - display->cursor.y++; + user->cursor.row++; /* XXX Flag cursor update. */ } else { - display->screen.current_line++; - display->screen.current_line %= display->screen.lines; + user->screen.cur_line++; + user->screen.cur_line %= user->screen.lines; /* XXX Set attribute flags. */ - screen_fill (&display->screen, 0, display->screen.height - 1, - display->screen.width, 1, L' ', display->screen.width); - if (display->screen.scrolling_max < - display->screen.lines - display->screen.height) - display->screen.scrolling_max++; + screen_fill (display, 0, user->screen.height - 1, + user->screen.width, 1, L' ', user->screen.width); + if (user->screen.scr_lines < + user->screen.lines - user->screen.height) + user->screen.scr_lines++; /* XXX Flag current line change. */ /* XXX Flag change of last line. */ /* XXX Possibly flag change of length of scroll back buffer. */ @@ -659,9 +785,9 @@ display_output_one (display_t display, wchar_t chr) { case L'\r': /* Carriage return: <cr>. */ - if (display->cursor.x) + if (user->cursor.col) { - display->cursor.x = 0; + user->cursor.col = 0; /* XXX Flag cursor update. */ } break; @@ -671,26 +797,26 @@ display_output_one (display_t display, wchar_t chr) break; case L'\b': /* Cursor backward: <cub1>. */ - if (display->cursor.x > 0 || display->cursor.y > 0) + if (user->cursor.col > 0 || user->cursor.row > 0) { - if (display->cursor.x > 0) - display->cursor.x--; + if (user->cursor.col > 0) + user->cursor.col--; else { /* XXX This implements the <bw> functionality. The alternative is to cut off and set x to 0. */ - display->cursor.x = display->screen.width - 1; - display->cursor.y--; + user->cursor.col = user->screen.width - 1; + user->cursor.row--; } /* XXX Flag cursor update. */ } break; case L'\t': /* Horizontal tab: <ht> */ - display->cursor.x = (display->cursor.x | 7) + 1; - if (display->cursor.x >= display->screen.width) + user->cursor.col = (user->cursor.col | 7) + 1; + if (user->cursor.col >= user->screen.width) { - display->cursor.x = 0; + user->cursor.col = 0; newline (); } /* XXX Flag cursor update. */ @@ -703,17 +829,17 @@ display_output_one (display_t display, wchar_t chr) break; default: { - int line = (display->screen.current_line + display->cursor.y) - % display->screen.lines; + int line = (user->screen.cur_line + user->cursor.row) + % user->screen.lines; /* XXX Set attribute flags. */ - display->screen.matrix[line * display->screen.width - + display->cursor.x] = chr; + user->_matrix[line * user->screen.width + + user->cursor.col] = chr; - display->cursor.x++; - if (display->cursor.x == display->screen.width) + user->cursor.col++; + if (user->cursor.col == user->screen.width) { - display->cursor.x = 0; + user->cursor.col = 0; newline (); } } @@ -729,10 +855,10 @@ display_output_one (display_t display, wchar_t chr) break; case L'c': /* Clear screen and home cursor: <clear>. */ - screen_fill (&display->screen, 0, 0, - display->screen.width, display->screen.height, + screen_fill (display, 0, 0, + user->screen.width, user->screen.height, L' ', display->attr.current); - display->cursor.x = display->cursor.y = 0; + user->cursor.col = user->cursor.row = 0; /* XXX Flag cursor change. */ parse->state = STATE_NORMAL; break; @@ -818,6 +944,19 @@ display_output_some (display_t display, char **buffer, size_t *length) return err; } +void +display_init (void) +{ + /* Create the pager bucket, and start to serve paging requests. */ + pager_bucket = ports_create_bucket (); + if (! pager_bucket) + error (5, errno, "Cannot create pager bucket"); + + /* Make a thread to service paging requests. */ + cthread_detach (cthread_fork ((cthread_fn_t) service_paging_requests, + (any_t)pager_bucket)); +} + /* Create a new virtual console display, with the system encoding being ENCODING. */ error_t @@ -825,6 +964,9 @@ display_create (display_t *r_display, const char *encoding) { error_t err = 0; display_t display; + int width = 80; + int height = 25; + int lines = 25; /* XXX For now. */ *r_display = NULL; display = calloc (1, sizeof *display); @@ -832,7 +974,7 @@ display_create (display_t *r_display, const char *encoding) return ENOMEM; mutex_init (&display->lock); - err = screen_init (&display->screen); + err = user_create (display, width, height, lines); if (err) { free (display); @@ -842,7 +984,7 @@ display_create (display_t *r_display, const char *encoding) err = output_init (&display->output, encoding); if (err) { - screen_deinit (&display->screen); + user_destroy (display); free (display); } *r_display = display; @@ -855,7 +997,7 @@ void display_destroy (display_t display) { output_deinit (&display->output); - screen_deinit (&display->screen); + user_destroy (display); free (display); } @@ -865,8 +1007,8 @@ void display_getsize (display_t display, struct winsize *winsize) { mutex_lock (&display->lock); - winsize->ws_row = display->screen.height; - winsize->ws_col = display->screen.width; + winsize->ws_row = display->user->screen.height; + winsize->ws_col = display->user->screen.width; winsize->ws_xpixel = 0; winsize->ws_ypixel = 0; mutex_unlock (&display->lock); @@ -1003,43 +1145,14 @@ display_output (display_t display, int nonblock, char *data, size_t datalen) return amount; } -ssize_t display_read (display_t display, int nonblock, off_t off, - char *data, size_t len) +ssize_t +display_read (display_t display, int nonblock, off_t off, + char *data, size_t len) { - u_int32_t metadata[8]; - size_t metadatalen = sizeof (metadata); - ssize_t written = 0; - mutex_lock (&display->lock); - metadata[0] = display->screen.width; - metadata[1] = display->screen.height; - metadata[2] = display->screen.lines; - metadata[3] = display->screen.current_line; - metadata[4] = display->screen.scrolling_max; - metadata[5] = display->cursor.x; - metadata[6] = display->cursor.y; - metadata[7] = display->cursor.status; - - if (off >= 0 && off < metadatalen) - { - int part_len = len; - - if (part_len > metadatalen) - part_len = metadatalen; - memcpy (data, (char *) metadata + off, part_len); - data += part_len; - len -= part_len; - written += part_len; - } - off -= metadatalen; - if (off < 0) - off = 0; - - if (off + len > 2000 * sizeof(wchar_t)) - len = 2000 * sizeof(wchar_t) - off; - memcpy (data, (char *) display->screen.matrix + off, len); + memcpy (data, ((char *) display->user) + off, len); mutex_unlock (&display->lock); - return written + len; + return len; } /* Resume the output on the display DISPLAY. */ diff --git a/console/display.h b/console/display.h index 6762e1b7..c48aec99 100644 --- a/console/display.h +++ b/console/display.h @@ -26,6 +26,8 @@ struct display; typedef struct display *display_t; +void display_init (void); + /* Create a new virtual console display, with the system encoding being ENCODING. */ error_t display_create (display_t *r_display, const char *encoding); @@ -53,6 +55,8 @@ error_t display_get_owner (display_t display, pid_t *pid); ssize_t display_output (display_t display, int nonblock, char *data, size_t datalen); +mach_port_t display_get_filemap (display_t display, vm_prot_t prot); + ssize_t display_read (display_t display, int nonblock, off_t off, char *data, size_t len); |