summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarcus <marcus>2003-09-15 18:09:45 +0000
committermarcus <marcus>2003-09-15 18:09:45 +0000
commit4a72493526b593401a268664f0b4447703c0dc6e (patch)
treec2abaa934c0e0f6a20a41a0257a1f16b296027cf
parente5dc11cd069435b21476c9074ab8e1ade5be941f (diff)
doc/
Add more info on exec wortel/ Make more generic.
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac6
-rw-r--r--doc/posix.tex121
-rw-r--r--libhurd-cap/cap-move.c5
-rw-r--r--libhurd-cap/cap-user.c48
-rw-r--r--libhurd-cap/cap.c13
-rw-r--r--libhurd-cap/cap.h33
-rw-r--r--wortel/ia32-cmain.c44
-rw-r--r--wortel/loader.c10
-rw-r--r--wortel/loader.h4
-rw-r--r--wortel/wortel.c108
-rw-r--r--wortel/wortel.h54
12 files changed, 307 insertions, 143 deletions
diff --git a/Makefile.am b/Makefile.am
index f923a78..46f1882 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1 +1,3 @@
-SUBDIRS = libl4 libc-parts laden wortel physmem libhurd-slab libhurd-ihash
+SUBDIRS = libl4 libhurd-ihash libhurd-slab libhurd-cap \
+ libc-parts laden wortel physmem \
+ doc
diff --git a/configure.ac b/configure.ac
index 204f4df..c06a7b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,7 @@ esac
m4_include([libl4/headers.m4])
m4_include([libhurd-ihash/headers.m4])
m4_include([libhurd-slab/headers.m4])
+m4_include([libhurd-cap/headers.m4])
if test "x$missing_progs" != "x"; then
AC_MSG_ERROR([The following programs were not found:$missing_progs])
@@ -94,10 +95,11 @@ fi
AC_CONFIG_FILES([Makefile
libl4/ia32/Makefile libl4/Makefile
libc-parts/Makefile
+ libhurd-ihash/Makefile
+ libhurd-slab/Makefile
+ libhurd-cap/Makefile
laden/Makefile
wortel/Makefile
physmem/Makefile
- libhurd-slab/Makefile
- libhurd-ihash/Makefile
doc/Makefile])
AC_OUTPUT
diff --git a/doc/posix.tex b/doc/posix.tex
index 708bde1..7ac28b6 100644
--- a/doc/posix.tex
+++ b/doc/posix.tex
@@ -248,26 +248,26 @@ and \texttt{auth} capability of a running task, etc).
To be written.
-\subsection{The \texttt{exec()} function}
+\subsection{The \texttt{exec} functions}
\label{exec}
-The \texttt{exec()} operation will be done locally in a task.
-Traditionally, \texttt{exec()} overlays the same task with a new
+The \texttt{exec} operation will be done locally in a task.
+Traditionally, \texttt{exec} overlays the same task with a new
process image, because creating a new task and transferring the
associated state is expensive. In L4, only the threads and virtual
memory mappings are actually kernel state associated with a task, and
-exactly those have to be destroyed by \texttt{exec()} anyway. There
+exactly those have to be destroyed by \texttt{exec} anyway. There
is a lot of Hurd specific state associated with a task (capabilities,
for example), but it is difficult to preserve that. There are
security concerns, because POSIX programs do not know about Hurd
features like capabilities, so inheriting all capabilities across
-\texttt{exec()} unconditionally seems dangerous.
+\texttt{exec} unconditionally seems dangerous.
\begin{comment}
One could think that if a program is not Hurd-aware, then it will
not make any use of capabilities except through the normal POSIX
API, and thus there are no capabilities except those that the GNU C
- library uses itself, which \texttt{exec()} can take care of.
+ library uses itself, which \texttt{exec} can take care of.
However, this is only true if code that is not Hurd-aware is never
mixed with Hurd specific code, even libraries (unless the library
intimately cooperates with the GNU C library). This would be a high
@@ -280,9 +280,9 @@ features like capabilities, so inheriting all capabilities across
executable.
For \verb/posix_spawn()/, this is straight-forward. For
- \texttt{exec()}, it is not. either specific capabilities could be
- markes as ``do not close on \texttt{exec()}'', or variants of the
- \texttt{exec()} function could be provided which take further
+ \texttt{exec}, it is not. either specific capabilities could be
+ markes as ``do not close on \texttt{exec}'', or variants of the
+ \texttt{exec} function could be provided which take further
arguments.
\end{comment}
@@ -294,16 +294,16 @@ binary image is installed and used (not to speak of the actual program
snippet that runs during the transition).
So the decision was made to always create a new task with
-\texttt{exec()}, and copy the desired state from the current task to
-the new task. This is a clean solution, because a new task will
-always start out without any capabilities in servers, etc, and thus
-there is no need for the old task to try to destroy all unneeded
-capabilities and other local state before \texttt{exec()}. Also, in
-case the exec fails, the old program can continue to run, even if the
-exec fails at a very late point (there is no ``point of no return''
-until the new task is actually up and running).
-
-For suid and sgid applications, the actual \texttt{exec()} has to be
+\texttt{exec}, and copy the desired state from the current task to the
+new task. This is a clean solution, because a new task will always
+start out without any capabilities in servers, etc, and thus there is
+no need for the old task to try to destroy all unneeded capabilities
+and other local state before \texttt{exec}. Also, in case the
+\texttt{exec} fails, the old program can continue to run, even if the
+\texttt{exec} fails at a very late point (there is no ``point of no
+return'' until the new task is actually up and running).
+
+For suid and sgid applications, the actual \texttt{exec} has to be
done by the filesystem. However, the filesystem can not be bothered
to also transfer all the user state into the new task. It can not
even do that, because it can not accept capabilities implemented by
@@ -313,7 +313,7 @@ necessarily trust the code, if is is owned by an untrusted user.
\begin{enumerate}
\item The user creates a new task and a container with a single
- physical page, and makes the \texttt{exec()} call to the file
+ physical page, and makes the \texttt{exec} call to the file
capability, providing the task control capability. Before that, it
creates a task info capability from it for its own use.
\item The filesystem checks permission and then revokes all other
@@ -354,6 +354,63 @@ This is a coarse and incomplete description, but it shows the general
idea. The details will depend a lot on the actual implementation.
+\subsubsection{The startup information}
+
+The following information is passed to the new task by the parent (the
+filesystem in the suid case). Every item is a machine word.
+
+\begin{enumerate}
+\item \texttt{magic}
+
+ The first four bytes are \texttt{E}, \texttt{X}, \texttt{E},
+ \texttt{C}.
+
+\item \texttt{program header location}
+\item \texttt{program header size}
+
+ The location and size of the program header. The meaning of this
+ field depends on the binary format.
+
+\item \texttt{feature flags}
+
+ This bit-field indicates which of the following information is
+ present. If the information is not present, the corresponding
+ machine words are undefined. This provides simple version control.
+
+ \begin{comment}
+ They could also be undefined.
+ \end{comment}
+
+\item \texttt{wortel thread ID}
+\item \texttt{wortel control cap ID}
+
+ The thread ID of the \texttt{wortel} rootserver, and the local ID of
+ the \texttt{wortel} control cap. The \texttt{wortel} control cap
+ allows the user to make privileged system calls. This field is only
+ present if the user has this capability. Usually, this is only the
+ case for some initial servers at bootstrap.
+
+\item \texttt{physmem thread ID}
+\item \texttt{physmem control cap ID}
+
+ The thread ID physical memory server, and the local ID of the
+ \texttt{physmem} control cap. This cap can be used to manage the
+ physical memory of this task.
+
+\item \texttt{physmem startup page container cap ID}
+
+ The container cap ID for the startup code, containing this
+ information, the initial pager, and other startup code. This
+ container is mapped into the address space of the task outside of
+ the actual program, and can be unmapped by the program after it has
+ used this information and installed its own pager, by destroying
+ this container, to reclaim the virtual address space and physical
+ memory it occupies.
+
+\item (More to come.)
+\end{enumerate}
+
+
\section{Unix Domain Sockets}
\label{unixdomainsockets}
@@ -489,18 +546,18 @@ root directory capability in exchange).
\end{comment}
The actual creation of the child filesystem can be performed much like
-a suid exec, just without any client to follow up with further
-capabilities and startup info. The only problem that remains is how
-the parent filesystem can know which thread in the child filesystem
-implements the initial handshake protocol for the clients to use. The
-only safe way here seems to be that the parent filesystem requires the
-child to use the main thread for that, or that the parent filesystem
-creates a second thread in the child at startup (passing its thread ID
-in the startup data), requiring that this second thread is used. In
-either case the parent filesystem will know the thread ID in advance
-because it created the thread in the first place. This looks a bit
-ugly, and violates good taste, so we might try to look for alternative
-solutions.
+a suid \texttt{exec}, just without any client to follow up with
+further capabilities and startup info. The only problem that remains
+is how the parent filesystem can know which thread in the child
+filesystem implements the initial handshake protocol for the clients
+to use. The only safe way here seems to be that the parent filesystem
+requires the child to use the main thread for that, or that the parent
+filesystem creates a second thread in the child at startup (passing
+its thread ID in the startup data), requiring that this second thread
+is used. In either case the parent filesystem will know the thread ID
+in advance because it created the thread in the first place. This
+looks a bit ugly, and violates good taste, so we might try to look for
+alternative solutions.
\subsection{Reparenting}
diff --git a/libhurd-cap/cap-move.c b/libhurd-cap/cap-move.c
index aacd2bc..df829fe 100644
--- a/libhurd-cap/cap-move.c
+++ b/libhurd-cap/cap-move.c
@@ -19,6 +19,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
/* FIXME: This is only some pseudo code to get the hang of it. */
/* Sender side. */
diff --git a/libhurd-cap/cap-user.c b/libhurd-cap/cap-user.c
index a760ac0..aeecd86 100644
--- a/libhurd-cap/cap-user.c
+++ b/libhurd-cap/cap-user.c
@@ -19,10 +19,15 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
+#include <stdint.h>
#include <hurd/cap.h>
@@ -69,15 +74,15 @@ _hurd_cap_sconn_dealloc (hurd_cap_sconn_t sconn)
}
/* Now we can remove the object. */
- hurd_ihash_remove (&server_to_sconn, sconn->server_thread);
+ hurd_ihash_remove (&server_to_sconn, sconn->server_thread.raw);
pthread_mutex_unlock (&server_to_sconn_lock);
/* Finally, we can destroy it. */
pthread_mutex_unlock (&sconn->lock);
pthread_mutex_destroy (&sconn->lock);
hurd_ihash_destroy (&sconn->id_to_cap);
- if (sconn->server_task_id)
- hurd_cap_deallocate (sconn->server_task_id);
+ if (sconn->server_task_info)
+ hurd_cap_deallocate (sconn->server_task_info);
free (sconn);
}
@@ -86,10 +91,11 @@ _hurd_cap_sconn_dealloc (hurd_cap_sconn_t sconn)
connection SCONN. SCONN is locked. Afterwards, SCONN is
unlocked. */
void
-_hurd_cap_sconn_remove (sconn, scid)
+_hurd_cap_sconn_remove (hurd_cap_sconn_t sconn, l4_word_t scid)
{
/* Remove the capability object pointer, which is now invalid. */
hurd_ihash_remove (&sconn->id_to_cap, scid);
+
/* FIXME: The following should be some low level RPC to deallocate
the capability on the server side. If it fails, then what can we
do at this point? */
@@ -100,7 +106,7 @@ _hurd_cap_sconn_remove (sconn, scid)
/* Enter a new send capability provided by the server SERVER_THREAD
- (with the task ID reference SERVER_TASK_ID) and the cap ID SCID.
+ (with the task ID reference SERVER_TASK_INFO) and the cap ID SCID.
SCONN is the server connection for SERVER_THREAD, if known. It
should be unlocked. If SCONN is NULL, then SERVER_TASK_INFO should
be the task info capability for the server SERVER_THREAD, otherwise
@@ -118,12 +124,12 @@ _hurd_cap_sconn_enter (hurd_cap_sconn_t sconn_provided,
int sconn_created = 0;
if (sconn)
- assert (sconn->server_thread == server_thread);
+ assert (l4_is_thread_equal (sconn->server_thread, server_thread));
else
{
/* It might have become available by now. */
pthread_mutex_lock (&server_to_sconn_lock);
- sconn = hurd_ihash_find (&server_to_sconn, server_thread);
+ sconn = hurd_ihash_find (&server_to_sconn, server_thread.raw);
if (sconn)
hurd_cap_deallocate (server_task_info);
else
@@ -146,20 +152,20 @@ _hurd_cap_sconn_enter (hurd_cap_sconn_t sconn_provided,
return errno;
}
- hurd_ihash_init (&sconn->id_to_cap);
+ hurd_ihash_init (&sconn->id_to_cap, HURD_IHASH_NO_LOCP);
sconn->server_thread = server_thread;
- sconn->server_task_id = server_task_info;
+ sconn->server_task_info = server_task_info;
sconn->refs = 0;
/* Enter the new server connection object. */
- err = hurd_ihash_add (&server_to_sconn, server_thread, sconn);
+ err = hurd_ihash_add (&server_to_sconn, server_thread.raw, sconn);
if (err)
{
pthread_mutex_destroy (&sconn->lock);
hurd_ihash_destroy (&sconn->id_to_cap);
free (sconn);
pthread_mutex_unlock (&server_to_sconn_lock);
- hurd_cap_deallocate (server_task_id);
+ hurd_cap_deallocate (server_task_info);
return errno;
}
}
@@ -167,30 +173,32 @@ _hurd_cap_sconn_enter (hurd_cap_sconn_t sconn_provided,
pthread_mutex_lock (&sconn->lock);
pthread_mutex_unlock (&server_to_sconn_lock);
- cap = hurd_ihash_find (&sconn->id_to_cap, scid);
+ (*cap) = hurd_ihash_find (&sconn->id_to_cap, scid);
if (!cap)
{
- error_t err = hurd_slab_alloc (cap_space, &cap);
+ error_t err = hurd_slab_alloc (cap_space, cap);
if (err)
{
_hurd_cap_sconn_dealloc (sconn);
return err;
}
- cap->sconn = sconn;
- cap->scid = scid;
- cap->dead_cb = NULL;
+ (*cap)->sconn = sconn;
+ (*cap)->scid = scid;
+#if 0
+ (*cap)->dead_cb = NULL;
+#endif
- err = hurd_ihash_add (&sconn->id_to_cap, scid, cap);
+ err = hurd_ihash_add (&sconn->id_to_cap, scid, *cap);
if (err)
{
_hurd_cap_sconn_dealloc (sconn);
- hurd_slab_dealloc (cap_space, cap);
+ hurd_slab_dealloc (cap_space, *cap);
return err;
}
}
- pthread_mutex_lock (&cap->lock);
- cap->srefs++;
+ pthread_mutex_lock (&(*cap)->lock);
+ (*cap)->srefs++;
/* We have to add a reference for the capability we have added,
unless we are consuming the reference that was provided. */
if (!sconn_provided)
diff --git a/libhurd-cap/cap.c b/libhurd-cap/cap.c
index 38f0abf..d7a992e 100644
--- a/libhurd-cap/cap.c
+++ b/libhurd-cap/cap.c
@@ -18,9 +18,14 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
+#include <stdint.h>
#include <pthread.h>
@@ -71,7 +76,7 @@ error_t
hurd_cap_init (void)
{
return hurd_slab_create (sizeof (struct hurd_cap),
- cap_constructor, cap_deconstructor, &cap_space);
+ cap_constructor, cap_destructor, &cap_space);
}
@@ -190,7 +195,7 @@ hurd_cap_obj_mod_refs (hurd_cap_t cap, int delta)
get a temporary reference and acquire the user list lock while
the capability is temporarily unlocked. Then we can check if we
still have to deallocate the capabilty. */
- ulist = cap->ulist;
+ ulist = cap->ouser;
cap->orefs = 1;
pthread_mutex_unlock (&cap->lock);
@@ -200,7 +205,7 @@ hurd_cap_obj_mod_refs (hurd_cap_t cap, int delta)
pthread_mutex_lock (&ulist->lock);
pthread_mutex_lock (&cap->lock);
- assert (cap->ulist == ulist);
+ assert (cap->ouser == ulist);
assert (cap->orefs != 0);
cap->orefs--;
if (cap->orefs != 0)
@@ -208,7 +213,7 @@ hurd_cap_obj_mod_refs (hurd_cap_t cap, int delta)
/* Someone else came in and got a reference to the almost dead
capability object. Give up. */
pthread_mutex_unlock (&cap->lock);
- pthread_mutex_unlock (&sconn->lock);
+ pthread_mutex_unlock (&ulist->lock);
return 0;
}
diff --git a/libhurd-cap/cap.h b/libhurd-cap/cap.h
index 38a9a2c..7d2b012 100644
--- a/libhurd-cap/cap.h
+++ b/libhurd-cap/cap.h
@@ -25,6 +25,7 @@
#include <hurd/slab.h>
#include <l4/types.h>
+typedef l4_word_t hurd_task_info_t;
/* Initialize the capability system. */
error_t hurd_cap_init (void);
@@ -38,7 +39,7 @@ struct hurd_cap_sconn
/* A reference for the servers task ID to prevent reuse. This is 0
if this is the connection to the task server itself. */
- task_id_t server_task_id;
+ hurd_task_info_t server_task_info;
/* The lock protecting the variable members of the server connection
object. */
@@ -50,6 +51,7 @@ struct hurd_cap_sconn
/* A hash mapping the capability IDs to capability objects. */
struct hurd_ihash id_to_cap;
};
+typedef struct hurd_cap_sconn *hurd_cap_sconn_t;
/* User capabilities. */
@@ -57,10 +59,10 @@ struct hurd_cap_sconn
/* The task-specific ID for this capability. */
typedef l4_word_t hurd_cap_scid_t;
-
-/* Remove the entry for the capability CAP from the user list ULIST.
- ULIST (and the capability CAP) are locked. */
-void _hurd_cap_ulist_remove (ulist, cap);
+
+/* Forward reference. */
+struct hurd_cap_ulist;
+typedef struct hurd_cap_ulist *hurd_cap_ulist_t;
/* The capability structure. */
@@ -88,8 +90,9 @@ struct hurd_cap
/* A callback for the user of the capability, invoked when the
capability is destroyed. */
+#if 0
hurd_cap_dead_t dead_cb;
-
+#endif
/* Information for local capabilities. */
@@ -104,10 +107,26 @@ struct hurd_cap
hurd_cap_ulist_t ouser;
/* A callback invoked when the capability is destroyed. */
+#if 0
hurd_cap_odead_cb_t odead_cb;
+#endif
/* A callback to be invoked when the capability has no more
senders. */
+#if 0
hurd_cap_no_sender_cb_t no_sender_cb;
+#endif
+};
+typedef struct hurd_cap *hurd_cap_t;
+
+
+struct hurd_cap_ulist
+{
+ /* The lock protecting the variable members of the object. */
+ pthread_mutex_t lock;
};
-typedef struct hurd_cap hurd_cap_t;
+
+
+/* Remove the entry for the capability CAP from the user list ULIST.
+ ULIST (and the capability CAP) are locked. */
+void _hurd_cap_ulist_remove (hurd_cap_ulist_t ulist, hurd_cap_t cap);
diff --git a/wortel/ia32-cmain.c b/wortel/ia32-cmain.c
index a8b58e6..a8ebf2c 100644
--- a/wortel/ia32-cmain.c
+++ b/wortel/ia32-cmain.c
@@ -52,20 +52,6 @@ cmain (void)
mbi = (multiboot_info_t *) l4_boot_info ();
debug ("Multiboot Info: 0x%x\n", mbi);
-#if 0
- if (CHECK_FLAG (mbi->flags, 3))
- {
- module_t *mod = (module_t *) mbi->mods_addr;
- int nr;
-
- /* FIXME: Should add all modules that we need to start up to the
- global, architecture independent module list. */
- for (nr = 0; nr < mbi->mods_count; nr++)
- debug ("Module %i: Start 0x%x, End 0x%x, Cmd %s\n",
- nr + 1, mod[nr].mod_start, mod[nr].mod_end, mod[nr].string);
- }
-#endif
-
if (CHECK_FLAG (mbi->flags, 3) && mbi->mods_count > 0)
{
/* A command line is available. */
@@ -141,31 +127,31 @@ find_components (void)
l4_word_t start;
l4_word_t end;
-#if 0
- debug_dump ();
-#endif
-
/* Load the module information. */
if (CHECK_FLAG (mbi->flags, 3))
{
module_t *mod = (module_t *) mbi->mods_addr;
-
- if (mbi->mods_count > 0)
- {
- /* Skip the entry for the rootserver. */
- mod++;
- }
+ unsigned int nr_mods;
+ unsigned int i;
+
+ mods_count = mbi->mods_count - 1;
+ if (mods_count > MOD_NUMBER)
+ mods_count = MOD_NUMBER;
+ /* Skip the entry for the rootserver. */
+ mod++;
- if (mbi->mods_count > 1)
+ for (i = 0; i < nr_mods; i++)
{
- physmem.low = mod->mod_start;
- physmem.high = mod->mod_end;
+ mods[i].name = mod_names[i];
+ mods[i].start = mod[i].mod_start;
+ mods[i].end = mod[i].mod_end;
+ mods[i].args = (char *) mod[i].string;
mod++;
}
}
- /* Now protect ourselves and the mulitboot info (at least the module
- configuration. */
+ /* Now protect ourselves and the multiboot info (at least the module
+ configuration). */
loader_add_region (program_name, (l4_word_t) &_start, (l4_word_t) &_end);
start = (l4_word_t) mbi;
diff --git a/wortel/loader.c b/wortel/loader.c
index 697a8df..32a0f7e 100644
--- a/wortel/loader.c
+++ b/wortel/loader.c
@@ -82,7 +82,7 @@ mem_check (const char *name, unsigned long start, unsigned long end)
static struct
{
- char *name;
+ const char *name;
l4_word_t start;
l4_word_t end;
} used_regions[MAX_REGIONS];
@@ -93,7 +93,7 @@ static int nr_regions;
/* Check that the region with the name NAME from START to END does not
overlap with an existing region. */
static void
-check_region (char *name, l4_word_t start, l4_word_t end)
+check_region (const char *name, l4_word_t start, l4_word_t end)
{
int i;
@@ -115,7 +115,7 @@ check_region (char *name, l4_word_t start, l4_word_t end)
regions to check against. Before doing that, check for overlaps
with existing regions. */
void
-loader_add_region (char *name, l4_word_t start, l4_word_t end)
+loader_add_region (const char *name, l4_word_t start, l4_word_t end)
{
debug ("Protected Region: %s (0x%x - 0x%x)\n", name, start, end);
@@ -142,7 +142,7 @@ loader_remove_region (const char *name)
break;
if (i == nr_regions)
- panic ("Assertion failure: Could not find region %s for removal");
+ panic ("Assertion failure: Could not find region %s for removal", name);
while (i < nr_regions - 1)
{
@@ -159,7 +159,7 @@ loader_remove_region (const char *name)
program in NEW_START_P and NEW_END_P, and the entry point in
ENTRY. */
void
-loader_elf_load (char *name, l4_word_t start, l4_word_t end,
+loader_elf_load (const char *name, l4_word_t start, l4_word_t end,
l4_word_t *new_start_p, l4_word_t *new_end_p,
l4_word_t *entry)
{
diff --git a/wortel/loader.h b/wortel/loader.h
index 855b169..d9c310b 100644
--- a/wortel/loader.h
+++ b/wortel/loader.h
@@ -38,7 +38,7 @@ l4_memory_desc_t loader_get_memory_desc (l4_word_t nr);
/* Add the region with the name NAME from START to END to the table of
regions to check against. Before doing that, check for overlaps
with existing regions. */
-void loader_add_region (char *name, l4_word_t start, l4_word_t end);
+void loader_add_region (const char *name, l4_word_t start, l4_word_t end);
/* Remove the region with the name NAME from the table. */
void loader_remove_region (const char *name);
@@ -48,7 +48,7 @@ void loader_remove_region (const char *name);
program). Return the lowest and highest address used by the
program in NEW_START_P and NEW_END_P, and the entry point in
ENTRY. */
-void loader_elf_load (char *name, l4_word_t start, l4_word_t end,
+void loader_elf_load (const char *name, l4_word_t start, l4_word_t end,
l4_word_t *new_start_p, l4_word_t *new_end_p,
l4_word_t *entry);
diff --git a/wortel/wortel.c b/wortel/wortel.c
index 2004b46..7d8e4b6 100644
--- a/wortel/wortel.c
+++ b/wortel/wortel.c
@@ -29,7 +29,14 @@
/* The program name. */
char *program_name = "wortel";
-rootserver_t physmem;
+const char *mod_names[] = { "physmem-mod", "task-mod", "root-fs-mod" };
+
+/* For the boot components, find_components() must fill in the start
+ and end address of the ELF images in memory. The end address is
+ one more than the last byte in the image. */
+struct wortel_module mods[MOD_NUMBER];
+
+unsigned int mods_count;
/* Return the number of memory descriptors. */
@@ -52,16 +59,61 @@ loader_get_memory_desc (l4_word_t nr)
static void
load_components (void)
{
- if (!physmem.low)
+ unsigned int i;
+
+ for (i = 0; i < mods_count; i++)
+ loader_add_region (mods[i].name, mods[i].start, mods[i].end);
+
+ if (!mods[MOD_PHYSMEM].start)
panic ("No physical memory server found");
- loader_add_region ("physmem-mod", physmem.low, physmem.high);
- loader_elf_load ("physmem-server", physmem.low, physmem.high,
- &physmem.low, &physmem.high, &physmem.ip);
+ loader_elf_load ("physmem-server", mods[MOD_PHYSMEM].start,
+ mods[MOD_PHYSMEM].end,
+ &mods[MOD_PHYSMEM].start, &mods[MOD_PHYSMEM].end,
+ &mods[MOD_PHYSMEM].ip);
loader_remove_region ("physmem-mod");
}
+/* The maximum number of fpages required to cover a page aligned range
+ of memory. This is k if the maximum memory range size to cover is
+ 2^(k + min_page_size_log2), which can be easily proved by
+ induction. The minimum page size in L4 is at least 2^10. */
+#define MAX_FPAGES (sizeof (l4_word_t) * 8 - 10)
+
+
+/* Determine the fpages required to cover the bytes from START to END,
+ which must be aligned to the minimal page size supported by the
+ system. Returns the number of fpages required to cover the range,
+ and returns that many fpages (with maximum accessibility) in
+ FPAGES. At most MAX_FPAGES fpages will be returned. */
+unsigned int
+make_fpages (l4_word_t start, l4_word_t size, l4_fpage_t *fpages)
+{
+ l4_word_t min_page_size = getpagesize ();
+ l4_word_t end = (start + size + min_page_size - 1) & ~(min_page_size - 1);
+ unsigned int nr_fpages = 0;
+
+ if (!size)
+ return 0;
+
+ if (start & ~(min_page_size - 1))
+ panic ("make_fpages: START is not aligned to minimum page size");
+ if (end & ~(min_page_size - 1))
+ panic ("make_fpages: START is not aligned to minimum page size");
+
+ /* END is at least one MIN_PAGE_SIZE larger than START. */
+ nr_fpages = 0;
+ while (start < end)
+ {
+ fpages[nr_fpages] = l4_fpage (start, end - start);
+ start += l4_size (fpages[nr_fpages]);
+ nr_fpages++;
+ }
+ return nr_fpages;
+}
+
+
static void
start_components (void)
{
@@ -71,18 +123,18 @@ start_components (void)
l4_msg_t msg;
l4_msg_tag_t msg_tag;
- if (physmem.low & (min_page_size - 1))
+ if (mods[MOD_PHYSMEM].start & (min_page_size - 1))
panic ("physmem is not page aligned on this architecture");
- if (physmem.low > physmem.high)
+ if (mods[MOD_PHYSMEM].start > mods[MOD_PHYSMEM].end)
panic ("physmem has invalid memory range");
- if (physmem.ip < physmem.low || physmem.ip > physmem.high)
+ if (mods[MOD_PHYSMEM].ip < mods[MOD_PHYSMEM].start
+ || mods[MOD_PHYSMEM].ip > mods[MOD_PHYSMEM].end)
panic ("physmem has invalid IP");
/* Thread nr is next available after rootserver thread nr,
version part is 2 (rootserver is 1). */
l4_thread_id_t physmem_server
- = l4_global_id (l4_thread_no (l4_myself ()) + 2,
- 2);
+ = l4_global_id (l4_thread_no (l4_myself ()) + 2, 2);
/* The UTCB location below is only a hack. We also need a way to
specify the maximum number of threads (ie the size of the UTCB
area), for example via ELF symbols, or via the command line.
@@ -109,7 +161,7 @@ start_components (void)
l4_msg_clear (&msg);
l4_set_msg_label (&msg, 0);
- l4_msg_append_word (&msg, physmem.ip);
+ l4_msg_append_word (&msg, mods[MOD_PHYSMEM].ip);
l4_msg_append_word (&msg, 0);
l4_msg_load (&msg);
msg_tag = l4_send (physmem_server);
@@ -118,36 +170,18 @@ start_components (void)
l4_error_code ());
{
- l4_fpage_t *fpages;
- unsigned int nr_fpages = 0;
- l4_word_t start = physmem.low;
- l4_word_t end = (physmem.high + min_page_size) & ~(min_page_size - 1);
- l4_word_t region;
+ l4_fpage_t fpages[MAX_FPAGES];
+ unsigned int nr_fpages;
+ l4_word_t start = mods[MOD_PHYSMEM].start;
+ l4_word_t size = (mods[MOD_PHYSMEM].end - start + min_page_size)
+ & ~(min_page_size - 1);
/* We want to grant all the memory for the physmem binary image
with the first page fault, but we might have to send several
fpages. So we first create a list of all fpages we need, then
we serve one after another, providing the one containing the
fault address last. */
-
- /* A page-aligned region of size up to 2^k * min_page_size can be
- covered by k fpages at most (proof by induction). At this
- point, END is at least one MIN_PAGE_SIZE larger than START. */
- region = (end - start) / min_page_size;
- while (region > 0)
- {
- nr_fpages++;
- region >>= 1;
- }
- fpages = alloca (sizeof (l4_fpage_t) * nr_fpages);
-
- nr_fpages = 0;
- while (start < end)
- {
- fpages[nr_fpages] = l4_fpage (start, end - start);
- start += l4_size (fpages[nr_fpages]);
- nr_fpages++;
- }
+ nr_fpages = make_fpages (start, size, fpages);
/* Now serve page requests. */
while (nr_fpages)
@@ -167,9 +201,9 @@ start_components (void)
if (l4_untyped_words (msg_tag) != 2 || l4_typed_words (msg_tag) != 0)
panic ("Invalid format of page fault message");
addr = l4_msg_word (&msg, 0);
- if (addr != physmem.ip)
+ if (addr != mods[MOD_PHYSMEM].ip)
panic ("Page fault at unexpected address 0x%x (expected 0x%x)",
- addr, physmem.ip);
+ addr, mods[MOD_PHYSMEM].ip);
if (nr_fpages == 1)
i = 0;
diff --git a/wortel/wortel.h b/wortel/wortel.h
index 6e1c47b..c01947c 100644
--- a/wortel/wortel.h
+++ b/wortel/wortel.h
@@ -24,6 +24,8 @@
#include <string.h>
+#include <hurd/cap.h>
+
#include <l4.h>
#include "output.h"
@@ -37,15 +39,59 @@ extern char *program_name;
#define BUG_ADDRESS "<bug-hurd@gnu.org>"
-typedef __l4_rootserver_t rootserver_t;
+struct wortel_module
+{
+ const char *name;
+
+ /* Low and high address of the module. */
+ l4_word_t start;
+ l4_word_t end;
+
+ /* The command line, in raw, uninterpreted form. */
+ char *args;
+
+ /* The container capability in the physical memory server for this
+ module. Valid for all modules except for the physical memory
+ server itself. */
+ hurd_cap_scid_t mem_cont;
+
+ /* The following informartion is only valid if a task will be
+ created from the module. */
+
+ /* The entry point of the executable. */
+ l4_word_t ip;
+
+ /* The task control capability for this module. Only valid if this
+ is not the task server task itself. */
+ hurd_cap_scid_t task_ctrl;
+
+ /* Main thread of the task made from this module. */
+ l4_thread_id_t main_thread;
+
+ /* Server thread of the task made from this module. */
+ l4_thread_id_t server_thread;
+};
+
+
+enum wortel_module_type
+ {
+ MOD_PHYSMEM = 0,
+ MOD_TASK,
+ MOD_ROOT_FS,
+ MOD_NUMBER
+ };
+
+
+extern const char *mod_names[MOD_NUMBER];
/* For the boot components, find_components() must fill in the start
and end address of the ELF images in memory. The end address is
one more than the last byte in the image. */
-extern rootserver_t physmem;
+extern struct wortel_module mods[MOD_NUMBER];
+
+extern unsigned int mods_count;
-/* Find the kernel, the initial servers and the other information
- required for booting. */
+/* Find the module information required for booting (start, end, args). */
void find_components (void);
int main (int argc, char *argv[]);