2005-04-21 16:53:53 +02:00
|
|
|
/* This task handles the interface between the kernel and user-level servers.
|
|
|
|
* System services can be accessed by doing a system call. System calls are
|
|
|
|
* transformed into request messages, which are handled by this task. By
|
|
|
|
* convention, a sys_call() is transformed in a SYS_CALL request message that
|
|
|
|
* is handled in a function named do_call().
|
|
|
|
*
|
|
|
|
* A private call vector is used to map all system calls to the functions that
|
|
|
|
* handle them. The actual handler functions are contained in separate files
|
|
|
|
* to keep this file clean. The call vector is used in the system task's main
|
|
|
|
* loop to handle all incoming requests.
|
|
|
|
*
|
|
|
|
* In addition to the main sys_task() entry point, which starts the main loop,
|
|
|
|
* there are several other minor entry points:
|
2005-07-26 14:48:34 +02:00
|
|
|
* get_priv: assign privilege structure to user or system process
|
2009-07-02 18:25:31 +02:00
|
|
|
* set_sendto_bit: allow a process to send messages to a new target
|
|
|
|
* unset_sendto_bit: disallow a process from sending messages to a target
|
2005-07-21 20:36:40 +02:00
|
|
|
* send_sig: send a signal directly to a system process
|
2005-07-19 14:21:36 +02:00
|
|
|
* cause_sig: take action to cause a signal to occur via PM
|
2005-04-21 16:53:53 +02:00
|
|
|
* umap_bios: map virtual address in BIOS_SEG to physical
|
2005-06-03 15:55:06 +02:00
|
|
|
* get_randomness: accumulate randomness in a buffer
|
2006-03-15 13:01:59 +01:00
|
|
|
* clear_endpoint: remove a process' ability to send and receive messages
|
2005-04-21 16:53:53 +02:00
|
|
|
*
|
|
|
|
* Changes:
|
2005-10-14 11:13:52 +02:00
|
|
|
* Aug 04, 2005 check if system call is allowed (Jorrit N. Herder)
|
2005-08-04 11:26:36 +02:00
|
|
|
* Jul 20, 2005 send signal to services with message (Jorrit N. Herder)
|
|
|
|
* Jan 15, 2005 new, generalized virtual copy function (Jorrit N. Herder)
|
2005-04-21 16:53:53 +02:00
|
|
|
* Oct 10, 2004 dispatch system calls from call vector (Jorrit N. Herder)
|
|
|
|
* Sep 30, 2004 source code documentation updated (Jorrit N. Herder)
|
|
|
|
*/
|
|
|
|
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
#include "debug.h"
|
2005-04-21 16:53:53 +02:00
|
|
|
#include "kernel.h"
|
|
|
|
#include "system.h"
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
#include "proc.h"
|
2008-11-19 13:26:10 +01:00
|
|
|
#include "vm.h"
|
2005-04-21 16:53:53 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <string.h>
|
2005-04-21 16:53:53 +02:00
|
|
|
#include <sys/sigcontext.h>
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
#include <minix/endpoint.h>
|
2006-06-20 11:58:58 +02:00
|
|
|
#include <minix/safecopies.h>
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
#include <minix/portio.h>
|
2008-02-22 13:38:22 +01:00
|
|
|
#include <minix/u64.h>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <sys/vm_i386.h>
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2005-04-29 17:36:43 +02:00
|
|
|
/* Declaration of the call vector that defines the mapping of system calls
|
|
|
|
* to handler functions. The vector is initialized in sys_init() with map(),
|
|
|
|
* which makes sure the system call numbers are ok. No space is allocated,
|
|
|
|
* because the dummy is declared extern. If an illegal call is given, the
|
|
|
|
* array size will be negative and this won't compile.
|
2005-04-21 16:53:53 +02:00
|
|
|
*/
|
2005-04-29 17:36:43 +02:00
|
|
|
PUBLIC int (*call_vec[NR_SYS_CALLS])(message *m_ptr);
|
2008-11-19 13:26:10 +01:00
|
|
|
char *callnames[NR_SYS_CALLS];
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2005-04-29 17:36:43 +02:00
|
|
|
#define map(call_nr, handler) \
|
2005-07-26 16:54:49 +02:00
|
|
|
{extern int dummy[NR_SYS_CALLS>(unsigned)(call_nr-KERNEL_CALL) ? 1:-1];} \
|
2008-11-19 13:26:10 +01:00
|
|
|
callnames[(call_nr-KERNEL_CALL)] = #call_nr; \
|
2005-07-26 16:54:49 +02:00
|
|
|
call_vec[(call_nr-KERNEL_CALL)] = (handler)
|
2005-04-29 17:36:43 +02:00
|
|
|
|
|
|
|
FORWARD _PROTOTYPE( void initialize, (void));
|
2008-11-19 13:26:10 +01:00
|
|
|
FORWARD _PROTOTYPE( struct proc *vmrestart_check, (message *));
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* sys_task *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void sys_task()
|
|
|
|
{
|
|
|
|
/* Main entry point of sys_task. Get the message and dispatch on type. */
|
2005-04-29 17:36:43 +02:00
|
|
|
static message m;
|
2005-06-24 18:24:40 +02:00
|
|
|
register int result;
|
2005-08-04 21:23:03 +02:00
|
|
|
register struct proc *caller_ptr;
|
|
|
|
int s;
|
2006-06-20 11:58:58 +02:00
|
|
|
int call_nr;
|
2008-11-19 13:26:10 +01:00
|
|
|
int n = 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Initialize the system task. */
|
|
|
|
initialize();
|
|
|
|
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
while (TRUE) {
|
2008-11-19 13:26:10 +01:00
|
|
|
struct proc *restarting;
|
|
|
|
|
|
|
|
restarting = vmrestart_check(&m);
|
|
|
|
|
|
|
|
if(!restarting) {
|
|
|
|
int r;
|
|
|
|
/* Get work. Block and wait until a request message arrives. */
|
|
|
|
if((r=receive(ANY, &m)) != OK)
|
|
|
|
minix_panic("receive() failed", r);
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2006-06-20 11:58:58 +02:00
|
|
|
sys_call_code = (unsigned) m.m_type;
|
|
|
|
call_nr = sys_call_code - KERNEL_CALL;
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
who_e = m.m_source;
|
|
|
|
okendpt(who_e, &who_p);
|
|
|
|
caller_ptr = proc_addr(who_p);
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2005-08-04 21:23:03 +02:00
|
|
|
/* See if the caller made a valid request and try to handle it. */
|
2006-08-10 12:56:16 +02:00
|
|
|
if (call_nr < 0 || call_nr >= NR_SYS_CALLS) { /* check call number */
|
2006-06-20 11:58:58 +02:00
|
|
|
kprintf("SYSTEM: illegal request %d from %d.\n",
|
|
|
|
call_nr,m.m_source);
|
2005-04-21 16:53:53 +02:00
|
|
|
result = EBADREQUEST; /* illegal message type */
|
2005-08-04 21:23:03 +02:00
|
|
|
}
|
2006-08-10 12:56:16 +02:00
|
|
|
else if (!GET_BIT(priv(caller_ptr)->s_k_call_mask, call_nr)) {
|
|
|
|
result = ECALLDENIED; /* illegal message type */
|
|
|
|
}
|
2005-08-04 21:23:03 +02:00
|
|
|
else {
|
2006-06-20 11:58:58 +02:00
|
|
|
result = (*call_vec[call_nr])(&m); /* handle the system call */
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
if(result == VMSUSPEND) {
|
|
|
|
/* Special case: message has to be saved for handling
|
|
|
|
* until VM tells us it's allowed. VM has been notified
|
|
|
|
* and we must wait for its reply to restart the call.
|
|
|
|
*/
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
vmassert(RTS_ISSET(caller_ptr, VMREQUEST));
|
|
|
|
vmassert(caller_ptr->p_vmrequest.type == VMSTYPE_KERNELCALL);
|
2008-11-19 13:26:10 +01:00
|
|
|
memcpy(&caller_ptr->p_vmrequest.saved.reqmsg, &m, sizeof(m));
|
|
|
|
} else if (result != EDONTREPLY) {
|
|
|
|
/* Send a reply, unless inhibited by a handler function.
|
|
|
|
* Use the kernel function lock_send() to prevent a system
|
|
|
|
* call trap.
|
|
|
|
*/
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
if(restarting) {
|
|
|
|
vmassert(!RTS_ISSET(restarting, VMREQUEST));
|
|
|
|
#if 0
|
|
|
|
vmassert(!RTS_ISSET(restarting, VMREQTARGET));
|
|
|
|
#endif
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
m.m_type = result; /* report status of call */
|
|
|
|
if(WILLRECEIVE(caller_ptr, SYSTEM)) {
|
|
|
|
if (OK != (s=lock_send(m.m_source, &m))) {
|
|
|
|
kprintf("SYSTEM, reply to %d failed: %d\n",
|
|
|
|
m.m_source, s);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
kprintf("SYSTEM: not replying to %d; not ready\n",
|
|
|
|
caller_ptr->p_endpoint);
|
|
|
|
}
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
2005-09-11 18:44:06 +02:00
|
|
|
* initialize *
|
2005-04-21 16:53:53 +02:00
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void initialize(void)
|
|
|
|
{
|
2005-07-14 17:12:12 +02:00
|
|
|
register struct priv *sp;
|
2005-04-21 16:53:53 +02:00
|
|
|
int i;
|
|
|
|
|
2005-05-02 16:30:04 +02:00
|
|
|
/* Initialize IRQ handler hooks. Mark all hooks available. */
|
|
|
|
for (i=0; i<NR_IRQ_HOOKS; i++) {
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
irq_hooks[i].proc_nr_e = NONE;
|
2005-05-02 16:30:04 +02:00
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Initialize all alarm timers for all processes. */
|
2005-07-14 17:12:12 +02:00
|
|
|
for (sp=BEG_PRIV_ADDR; sp < END_PRIV_ADDR; sp++) {
|
|
|
|
tmr_inittimer(&(sp->s_alarm_timer));
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-04-29 17:36:43 +02:00
|
|
|
|
|
|
|
/* Initialize the call vector to a safe default handler. Some system calls
|
|
|
|
* may be disabled or nonexistant. Then explicitely map known calls to their
|
|
|
|
* handler functions. This is done with a macro that gives a compile error
|
|
|
|
* if an illegal call number is used. The ordering is not important here.
|
|
|
|
*/
|
|
|
|
for (i=0; i<NR_SYS_CALLS; i++) {
|
|
|
|
call_vec[i] = do_unused;
|
2008-11-19 13:26:10 +01:00
|
|
|
callnames[i] = "unused";
|
2005-04-29 17:36:43 +02:00
|
|
|
}
|
|
|
|
|
2005-08-04 11:26:36 +02:00
|
|
|
/* Process management. */
|
2005-07-14 17:12:12 +02:00
|
|
|
map(SYS_FORK, do_fork); /* a process forked a new process */
|
|
|
|
map(SYS_EXEC, do_exec); /* update process after execute */
|
|
|
|
map(SYS_EXIT, do_exit); /* clean up after process exit */
|
2005-07-19 14:21:36 +02:00
|
|
|
map(SYS_NICE, do_nice); /* set scheduling priority */
|
2005-08-04 11:26:36 +02:00
|
|
|
map(SYS_PRIVCTL, do_privctl); /* system privileges control */
|
2005-07-14 17:12:12 +02:00
|
|
|
map(SYS_TRACE, do_trace); /* request a trace operation */
|
2006-06-23 17:35:05 +02:00
|
|
|
map(SYS_SETGRANT, do_setgrant); /* get/set own parameters */
|
2005-04-29 17:36:43 +02:00
|
|
|
|
|
|
|
/* Signal handling. */
|
|
|
|
map(SYS_KILL, do_kill); /* cause a process to be signaled */
|
2005-07-14 17:12:12 +02:00
|
|
|
map(SYS_GETKSIG, do_getksig); /* PM checks for pending signals */
|
|
|
|
map(SYS_ENDKSIG, do_endksig); /* PM finished processing signal */
|
2005-04-29 17:36:43 +02:00
|
|
|
map(SYS_SIGSEND, do_sigsend); /* start POSIX-style signal */
|
|
|
|
map(SYS_SIGRETURN, do_sigreturn); /* return from POSIX-style signal */
|
|
|
|
|
|
|
|
/* Device I/O. */
|
|
|
|
map(SYS_IRQCTL, do_irqctl); /* interrupt control operations */
|
|
|
|
map(SYS_DEVIO, do_devio); /* inb, inw, inl, outb, outw, outl */
|
|
|
|
map(SYS_VDEVIO, do_vdevio); /* vector with devio requests */
|
|
|
|
|
2005-08-04 11:26:36 +02:00
|
|
|
/* Memory management. */
|
|
|
|
map(SYS_NEWMAP, do_newmap); /* set up a process memory map */
|
2005-04-29 17:36:43 +02:00
|
|
|
map(SYS_SEGCTL, do_segctl); /* add segment and get selector */
|
2005-08-04 11:26:36 +02:00
|
|
|
map(SYS_MEMSET, do_memset); /* write char to memory area */
|
2008-11-19 13:26:10 +01:00
|
|
|
map(SYS_VMCTL, do_vmctl); /* various VM process settings */
|
2005-04-29 17:36:43 +02:00
|
|
|
|
|
|
|
/* Copying. */
|
|
|
|
map(SYS_UMAP, do_umap); /* map virtual to physical address */
|
2005-05-02 16:30:04 +02:00
|
|
|
map(SYS_VIRCOPY, do_vircopy); /* use pure virtual addressing */
|
2008-11-19 13:26:10 +01:00
|
|
|
map(SYS_PHYSCOPY, do_copy); /* use physical addressing */
|
2005-04-29 17:36:43 +02:00
|
|
|
map(SYS_VIRVCOPY, do_virvcopy); /* vector with copy requests */
|
2008-11-19 13:26:10 +01:00
|
|
|
map(SYS_PHYSVCOPY, do_vcopy); /* vector with copy requests */
|
2006-06-20 11:58:58 +02:00
|
|
|
map(SYS_SAFECOPYFROM, do_safecopy); /* copy with pre-granted permission */
|
|
|
|
map(SYS_SAFECOPYTO, do_safecopy); /* copy with pre-granted permission */
|
2006-06-23 13:54:03 +02:00
|
|
|
map(SYS_VSAFECOPY, do_vsafecopy); /* vectored safecopy */
|
2005-08-04 11:26:36 +02:00
|
|
|
|
|
|
|
/* Clock functionality. */
|
|
|
|
map(SYS_TIMES, do_times); /* get uptime and process times */
|
|
|
|
map(SYS_SETALARM, do_setalarm); /* schedule a synchronous alarm */
|
2007-08-07 14:21:40 +02:00
|
|
|
map(SYS_STIME, do_stime); /* set the boottime */
|
2009-08-15 23:37:26 +02:00
|
|
|
map(SYS_VTIMER, do_vtimer); /* set or retrieve a virtual timer */
|
2005-08-04 11:26:36 +02:00
|
|
|
|
|
|
|
/* System control. */
|
|
|
|
map(SYS_ABORT, do_abort); /* abort MINIX */
|
|
|
|
map(SYS_GETINFO, do_getinfo); /* request system information */
|
2009-01-26 18:43:59 +01:00
|
|
|
map(SYS_SYSCTL, do_sysctl); /* misc system manipulation */
|
2006-10-30 16:53:38 +01:00
|
|
|
|
|
|
|
/* Profiling. */
|
|
|
|
map(SYS_SPROF, do_sprofile); /* start/stop statistical profiling */
|
|
|
|
map(SYS_CPROF, do_cprofile); /* get/reset call profiling data */
|
|
|
|
map(SYS_PROFBUF, do_profbuf); /* announce locations to kernel */
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
|
|
|
|
/* i386-specific. */
|
|
|
|
#if _MINIX_CHIP == _CHIP_INTEL
|
|
|
|
map(SYS_INT86, do_int86); /* real-mode BIOS calls */
|
|
|
|
map(SYS_READBIOS, do_readbios); /* read from BIOS locations */
|
|
|
|
map(SYS_IOPENABLE, do_iopenable); /* Enable I/O */
|
|
|
|
map(SYS_SDEVIO, do_sdevio); /* phys_insb, _insw, _outsb, _outsw */
|
2008-02-22 13:38:22 +01:00
|
|
|
map(SYS_MAPDMA, do_mapdma);
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
#endif
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2005-07-14 17:12:12 +02:00
|
|
|
/*===========================================================================*
|
2005-09-11 18:44:06 +02:00
|
|
|
* get_priv *
|
2005-07-14 17:12:12 +02:00
|
|
|
*===========================================================================*/
|
2005-07-26 14:48:34 +02:00
|
|
|
PUBLIC int get_priv(rc, proc_type)
|
2005-07-20 17:25:38 +02:00
|
|
|
register struct proc *rc; /* new (child) process pointer */
|
2005-07-21 20:36:40 +02:00
|
|
|
int proc_type; /* system or user process flag */
|
2005-07-14 17:12:12 +02:00
|
|
|
{
|
2005-07-21 20:36:40 +02:00
|
|
|
/* Get a privilege structure. All user processes share the same privilege
|
|
|
|
* structure. System processes get their own privilege structure.
|
|
|
|
*/
|
|
|
|
register struct priv *sp; /* privilege structure */
|
|
|
|
|
|
|
|
if (proc_type == SYS_PROC) { /* find a new slot */
|
|
|
|
for (sp = BEG_PRIV_ADDR; sp < END_PRIV_ADDR; ++sp)
|
|
|
|
if (sp->s_proc_nr == NONE && sp->s_id != USER_PRIV_ID) break;
|
2007-04-23 16:23:37 +02:00
|
|
|
if (sp >= END_PRIV_ADDR) return(ENOSPC);
|
2005-07-21 20:36:40 +02:00
|
|
|
rc->p_priv = sp; /* assign new slot */
|
|
|
|
rc->p_priv->s_proc_nr = proc_nr(rc); /* set association */
|
2005-07-29 17:26:23 +02:00
|
|
|
rc->p_priv->s_flags = SYS_PROC; /* mark as privileged */
|
2007-04-23 16:23:37 +02:00
|
|
|
|
|
|
|
/* Clear some fields */
|
|
|
|
sp->s_asyntab= -1;
|
|
|
|
sp->s_asynsize= 0;
|
2005-07-21 20:36:40 +02:00
|
|
|
} else {
|
|
|
|
rc->p_priv = &priv[USER_PRIV_ID]; /* use shared slot */
|
|
|
|
rc->p_priv->s_proc_nr = INIT_PROC_NR; /* set association */
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
|
|
|
|
/* s_flags of this shared structure are to be once at system startup. */
|
2005-05-30 13:05:42 +02:00
|
|
|
}
|
2005-07-21 20:36:40 +02:00
|
|
|
return(OK);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2009-07-02 18:25:31 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* set_sendto_bit *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void set_sendto_bit(struct proc *rp, int id)
|
|
|
|
{
|
|
|
|
/* Allow a process to send messages to the process(es) associated with the
|
|
|
|
* system privilege structure with the given ID.
|
|
|
|
*/
|
|
|
|
struct proc *rrp; /* receiver process */
|
|
|
|
|
|
|
|
/* Disallow the process from sending to a system privilege structure with no
|
|
|
|
* associated process, and disallow the process from sending to itself.
|
|
|
|
*/
|
|
|
|
if (id_to_nr(id) == NONE || priv_id(rp) == id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
set_sys_bit(priv(rp)->s_ipc_to, id);
|
|
|
|
|
|
|
|
/* The process that this process can now send to, must be able to reply.
|
|
|
|
* Therefore, its send mask should be updated as well.
|
|
|
|
*/
|
|
|
|
rrp = proc_addr(id_to_nr(id));
|
|
|
|
if (!iskernelp(rrp))
|
|
|
|
set_sys_bit(priv(rrp)->s_ipc_to, priv_id(rp));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* unset_sendto_bit *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void unset_sendto_bit(struct proc *rp, int id)
|
|
|
|
{
|
|
|
|
/* Prevent a process from sending to another process. Retain the send mask
|
|
|
|
* symmetry by also unsetting the bit for the other direction.
|
|
|
|
*/
|
|
|
|
|
|
|
|
unset_sys_bit(priv(rp)->s_ipc_to, id);
|
|
|
|
|
|
|
|
unset_sys_bit(priv_addr(id)->s_ipc_to, priv_id(rp));
|
|
|
|
}
|
|
|
|
|
2005-07-19 14:21:36 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* send_sig *
|
|
|
|
*===========================================================================*/
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
PUBLIC void send_sig(int proc_nr, int sig_nr)
|
2005-07-19 14:21:36 +02:00
|
|
|
{
|
|
|
|
/* Notify a system process about a signal. This is straightforward. Simply
|
|
|
|
* set the signal that is to be delivered in the pending signals map and
|
|
|
|
* send a notification with source SYSTEM.
|
|
|
|
*/
|
|
|
|
register struct proc *rp;
|
'proc number' is process slot, 'endpoint' are generation-aware process
instance numbers, encoded and decoded using macros in <minix/endpoint.h>.
proc number -> endpoint migration
. proc_nr in the interrupt hook is now an endpoint, proc_nr_e.
. m_source for messages and notifies is now an endpoint, instead of
proc number.
. isokendpt() converts an endpoint to a process number, returns
success (but fails if the process number is out of range, the
process slot is not a living process, or the given endpoint
number does not match the endpoint number in the process slot,
indicating an old process).
. okendpt() is the same as isokendpt(), but panic()s if the conversion
fails. This is mainly used for decoding message.m_source endpoints,
and other endpoint numbers in kernel data structures, which should
always be correct.
. if DEBUG_ENABLE_IPC_WARNINGS is enabled, isokendpt() and okendpt()
get passed the __FILE__ and __LINE__ of the calling lines, and
print messages about what is wrong with the endpoint number
(out of range proc, empty proc, or inconsistent endpoint number),
with the caller, making finding where the conversion failed easy
without having to include code for every call to print where things
went wrong. Sometimes this is harmless (wrong arg to a kernel call),
sometimes it's a fatal internal inconsistency (bogus m_source).
. some process table fields have been appended an _e to indicate it's
become and endpoint.
. process endpoint is stored in p_endpoint, without generation number.
it turns out the kernel never needs the generation number, except
when fork()ing, so it's decoded then.
. kernel calls all take endpoints as arguments, not proc numbers.
the one exception is sys_fork(), which needs to know in which slot
to put the child.
2006-03-03 11:00:02 +01:00
|
|
|
static int n;
|
|
|
|
|
2006-03-09 15:02:56 +01:00
|
|
|
if(!isokprocn(proc_nr) || isemptyn(proc_nr))
|
2008-11-19 13:26:10 +01:00
|
|
|
minix_panic("send_sig to empty process", proc_nr);
|
2005-07-19 14:21:36 +02:00
|
|
|
|
|
|
|
rp = proc_addr(proc_nr);
|
|
|
|
sigaddset(&priv(rp)->s_sig_pending, sig_nr);
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
if(!intr_disabled()) {
|
|
|
|
lock_notify(SYSTEM, rp->p_endpoint);
|
|
|
|
} else {
|
|
|
|
mini_notify(proc_addr(SYSTEM), rp->p_endpoint);
|
|
|
|
}
|
2005-07-19 14:21:36 +02:00
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* cause_sig *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void cause_sig(proc_nr, sig_nr)
|
|
|
|
int proc_nr; /* process to be signalled */
|
|
|
|
int sig_nr; /* signal to be sent, 1 to _NSIG */
|
|
|
|
{
|
2005-06-17 11:09:54 +02:00
|
|
|
/* A system process wants to send a signal to a process. Examples are:
|
2005-07-14 17:12:12 +02:00
|
|
|
* - HARDWARE wanting to cause a SIGSEGV after a CPU exception
|
|
|
|
* - TTY wanting to cause SIGINT upon getting a DEL
|
|
|
|
* - FS wanting to cause SIGPIPE for a broken pipe
|
2005-06-17 11:09:54 +02:00
|
|
|
* Signals are handled by sending a message to PM. This function handles the
|
2005-04-29 17:36:43 +02:00
|
|
|
* signals and makes sure the PM gets them by sending a notification. The
|
|
|
|
* process being signaled is blocked while PM has not finished all signals
|
2005-06-24 18:24:40 +02:00
|
|
|
* for it.
|
2005-07-19 14:21:36 +02:00
|
|
|
* Race conditions between calls to this function and the system calls that
|
|
|
|
* process pending kernel signals cannot exist. Signal related functions are
|
|
|
|
* only called when a user process causes a CPU exception and from the kernel
|
|
|
|
* process level, which runs to completion.
|
2005-04-21 16:53:53 +02:00
|
|
|
*/
|
2005-06-21 12:47:46 +02:00
|
|
|
register struct proc *rp;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2007-04-23 16:23:37 +02:00
|
|
|
if (proc_nr == PM_PROC_NR)
|
2008-11-19 13:26:10 +01:00
|
|
|
minix_panic("cause_sig: PM gets signal", NO_NUM);
|
2007-04-23 16:23:37 +02:00
|
|
|
|
2005-06-24 18:24:40 +02:00
|
|
|
/* Check if the signal is already pending. Process it otherwise. */
|
2005-04-21 16:53:53 +02:00
|
|
|
rp = proc_addr(proc_nr);
|
2005-06-24 18:24:40 +02:00
|
|
|
if (! sigismember(&rp->p_pending, sig_nr)) {
|
|
|
|
sigaddset(&rp->p_pending, sig_nr);
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
if (! (RTS_ISSET(rp, SIGNALED))) { /* other pending */
|
|
|
|
RTS_LOCK_SET(rp, SIGNALED | SIG_PENDING);
|
2005-07-19 14:21:36 +02:00
|
|
|
send_sig(PM_PROC_NR, SIGKSIG);
|
2005-06-30 17:55:19 +02:00
|
|
|
}
|
2005-06-24 18:24:40 +02:00
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
#if _MINIX_CHIP == _CHIP_INTEL
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*===========================================================================*
|
2005-05-24 12:06:17 +02:00
|
|
|
* umap_bios *
|
2005-04-21 16:53:53 +02:00
|
|
|
*===========================================================================*/
|
2008-11-19 13:26:10 +01:00
|
|
|
PUBLIC phys_bytes umap_bios(vir_addr, bytes)
|
2005-04-21 16:53:53 +02:00
|
|
|
vir_bytes vir_addr; /* virtual address in BIOS segment */
|
|
|
|
vir_bytes bytes; /* # of bytes to be copied */
|
|
|
|
{
|
2005-04-29 17:36:43 +02:00
|
|
|
/* Calculate the physical memory address at the BIOS. Note: currently, BIOS
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
* address zero (the first BIOS interrupt vector) is not considered as an
|
2005-04-29 17:36:43 +02:00
|
|
|
* error here, but since the physical address will be zero as well, the
|
|
|
|
* calling function will think an error occurred. This is not a problem,
|
|
|
|
* since no one uses the first BIOS interrupt vector.
|
|
|
|
*/
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2005-04-29 17:36:43 +02:00
|
|
|
/* Check all acceptable ranges. */
|
|
|
|
if (vir_addr >= BIOS_MEM_BEGIN && vir_addr + bytes <= BIOS_MEM_END)
|
|
|
|
return (phys_bytes) vir_addr;
|
2005-07-21 20:36:40 +02:00
|
|
|
else if (vir_addr >= BASE_MEM_TOP && vir_addr + bytes <= UPPER_MEM_END)
|
2005-04-29 17:36:43 +02:00
|
|
|
return (phys_bytes) vir_addr;
|
2005-07-21 20:36:40 +02:00
|
|
|
|
2005-04-29 17:36:43 +02:00
|
|
|
kprintf("Warning, error in umap_bios, virtual address 0x%x\n", vir_addr);
|
|
|
|
return 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* umap_grant *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC phys_bytes umap_grant(rp, grant, bytes)
|
|
|
|
struct proc *rp; /* pointer to proc table entry for process */
|
|
|
|
cp_grant_id_t grant; /* grant no. */
|
|
|
|
vir_bytes bytes; /* size */
|
|
|
|
{
|
|
|
|
int proc_nr;
|
2008-11-19 13:26:10 +01:00
|
|
|
vir_bytes offset, ret;
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
endpoint_t granter;
|
2008-11-19 13:26:10 +01:00
|
|
|
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
/* See if the grant in that process is sensible, and
|
|
|
|
* find out the virtual address and (optionally) new
|
|
|
|
* process for that address.
|
|
|
|
*
|
|
|
|
* Then convert that process to a slot number.
|
|
|
|
*/
|
|
|
|
if(verify_grant(rp->p_endpoint, ANY, grant, bytes, 0, 0,
|
|
|
|
&offset, &granter) != OK) {
|
2008-11-19 13:26:10 +01:00
|
|
|
kprintf("SYSTEM: umap_grant: verify_grant failed\n");
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!isokendpt(granter, &proc_nr)) {
|
2008-11-19 13:26:10 +01:00
|
|
|
kprintf("SYSTEM: umap_grant: isokendpt failed\n");
|
Split of architecture-dependent and -independent functions for i386,
mainly in the kernel and headers. This split based on work by
Ingmar Alting <iaalting@cs.vu.nl> done for his Minix PowerPC architecture
port.
. kernel does not program the interrupt controller directly, do any
other architecture-dependent operations, or contain assembly any more,
but uses architecture-dependent functions in arch/$(ARCH)/.
. architecture-dependent constants and types defined in arch/$(ARCH)/include.
. <ibm/portio.h> moved to <minix/portio.h>, as they have become, for now,
architecture-independent functions.
. int86, sdevio, readbios, and iopenable are now i386-specific kernel calls
and live in arch/i386/do_* now.
. i386 arch now supports even less 86 code; e.g. mpx86.s and klib86.s have
gone, and 'machine.protected' is gone (and always taken to be 1 in i386).
If 86 support is to return, it should be a new architecture.
. prototypes for the architecture-dependent functions defined in
kernel/arch/$(ARCH)/*.c but used in kernel/ are in kernel/proto.h
. /etc/make.conf included in makefiles and shell scripts that need to
know the building architecture; it defines ARCH=<arch>, currently only
i386.
. some basic per-architecture build support outside of the kernel (lib)
. in clock.c, only dequeue a process if it was ready
. fixes for new include files
files deleted:
. mpx/klib.s - only for choosing between mpx/klib86 and -386
. klib86.s - only for 86
i386-specific files files moved (or arch-dependent stuff moved) to arch/i386/:
. mpx386.s (entry point)
. klib386.s
. sconst.h
. exception.c
. protect.c
. protect.h
. i8269.c
2006-12-22 16:22:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the mapping from virtual to physical. */
|
2008-11-19 13:26:10 +01:00
|
|
|
ret = umap_virtual(proc_addr(proc_nr), D, offset, bytes);
|
|
|
|
if(!ret) {
|
|
|
|
kprintf("SYSTEM:umap_grant:umap_virtual failed; grant %s:%d -> %s: vir 0x%lx\n",
|
|
|
|
rp->p_name, grant,
|
|
|
|
proc_addr(proc_nr)->p_name, offset);
|
|
|
|
}
|
|
|
|
return ret;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2006-03-15 13:01:59 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* clear_endpoint *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void clear_endpoint(rc)
|
|
|
|
register struct proc *rc; /* slot of process to clean up */
|
|
|
|
{
|
|
|
|
register struct proc *rp; /* iterate over process table */
|
|
|
|
register struct proc **xpp; /* iterate over caller queue */
|
2008-11-19 13:26:10 +01:00
|
|
|
struct proc *np;
|
2006-03-15 13:01:59 +01:00
|
|
|
|
2009-01-14 09:52:50 +01:00
|
|
|
if(isemptyp(rc)) minix_panic("clear_proc: empty process", rc->p_endpoint);
|
2008-11-19 13:26:10 +01:00
|
|
|
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
if(rc->p_endpoint == PM_PROC_NR || rc->p_endpoint == VFS_PROC_NR ||
|
|
|
|
rc->p_endpoint == VM_PROC_NR)
|
|
|
|
{
|
2008-11-19 13:26:10 +01:00
|
|
|
/* This test is great for debugging system processes dying,
|
|
|
|
* but as this happens normally on reboot, not good permanent code.
|
|
|
|
*/
|
|
|
|
kprintf("process %s / %d died; stack: ", rc->p_name, rc->p_endpoint);
|
|
|
|
proc_stacktrace(rc);
|
|
|
|
kprintf("kernel trace: ");
|
|
|
|
util_stacktrace();
|
|
|
|
minix_panic("clear_proc: system process died", rc->p_endpoint);
|
|
|
|
}
|
2006-03-15 13:01:59 +01:00
|
|
|
|
|
|
|
/* Make sure that the exiting process is no longer scheduled. */
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
RTS_LOCK_SET(rc, NO_ENDPOINT);
|
2007-04-23 16:23:37 +02:00
|
|
|
if (priv(rc)->s_flags & SYS_PROC)
|
|
|
|
{
|
2008-12-21 04:46:42 +01:00
|
|
|
if (priv(rc)->s_asynsize) {
|
|
|
|
kprintf("clear_endpoint: clearing s_asynsize of %s / %d\n",
|
|
|
|
rc->p_name, rc->p_endpoint);
|
|
|
|
proc_stacktrace(rc);
|
|
|
|
}
|
2007-04-23 16:23:37 +02:00
|
|
|
priv(rc)->s_asynsize= 0;
|
|
|
|
}
|
2006-03-15 13:01:59 +01:00
|
|
|
|
|
|
|
/* If the process happens to be queued trying to send a
|
|
|
|
* message, then it must be removed from the message queues.
|
|
|
|
*/
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
if (RTS_ISSET(rc, SENDING)) {
|
2006-03-15 13:01:59 +01:00
|
|
|
int target_proc;
|
|
|
|
|
|
|
|
okendpt(rc->p_sendto_e, &target_proc);
|
|
|
|
xpp = &proc_addr(target_proc)->p_caller_q; /* destination's queue */
|
|
|
|
while (*xpp != NIL_PROC) { /* check entire queue */
|
|
|
|
if (*xpp == rc) { /* process is on the queue */
|
|
|
|
*xpp = (*xpp)->p_q_link; /* replace by next process */
|
|
|
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
2009-01-14 09:52:50 +01:00
|
|
|
kprintf("endpoint %d / %s removed from queue at %d\n",
|
|
|
|
rc->p_endpoint, rc->p_name, rc->p_sendto_e);
|
2006-03-15 13:01:59 +01:00
|
|
|
#endif
|
|
|
|
break; /* can only be queued once */
|
|
|
|
}
|
|
|
|
xpp = &(*xpp)->p_q_link; /* proceed to next queued */
|
|
|
|
}
|
|
|
|
rc->p_rts_flags &= ~SENDING;
|
|
|
|
}
|
|
|
|
rc->p_rts_flags &= ~RECEIVING;
|
|
|
|
|
|
|
|
/* Likewise, if another process was sending or receive a message to or from
|
|
|
|
* the exiting process, it must be alerted that process no longer is alive.
|
|
|
|
* Check all processes.
|
|
|
|
*/
|
|
|
|
for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; rp++) {
|
|
|
|
if(isemptyp(rp))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Unset pending notification bits. */
|
|
|
|
unset_sys_bit(priv(rp)->s_notify_pending, priv(rc)->s_id);
|
|
|
|
|
|
|
|
/* Check if process is receiving from exiting process. */
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
if (RTS_ISSET(rp, RECEIVING) && rp->p_getfrom_e == rc->p_endpoint) {
|
2006-03-15 13:01:59 +01:00
|
|
|
rp->p_reg.retreg = ESRCDIED; /* report source died */
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
RTS_LOCK_UNSET(rp, RECEIVING); /* no longer receiving */
|
2006-03-15 13:01:59 +01:00
|
|
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
2009-01-14 09:52:50 +01:00
|
|
|
kprintf("endpoint %d / %s receiving from dead src ep %d / %s\n",
|
|
|
|
rp->p_endpoint, rp->p_name, rc->p_endpoint, rc->p_name);
|
2006-03-15 13:01:59 +01:00
|
|
|
#endif
|
|
|
|
}
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
if (RTS_ISSET(rp, SENDING) &&
|
|
|
|
rp->p_sendto_e == rc->p_endpoint) {
|
2006-03-15 13:01:59 +01:00
|
|
|
rp->p_reg.retreg = EDSTDIED; /* report destination died */
|
Mostly bugfixes of bugs triggered by the test set.
bugfixes:
SYSTEM:
. removed
rc->p_priv->s_flags = 0;
for the priv struct shared by all user processes in get_priv(). this
should only be done once. doing a SYS_PRIV_USER in sys_privctl()
caused the flags of all user processes to be reset, so they were no
longer PREEMPTIBLE. this happened when RS executed a policy script.
(this broke test1 in the test set)
VFS/MFS:
. chown can change the mode of a file, and chmod arguments are only
part of the full file mode so the full filemode is slightly magic.
changed these calls so that the final modes are returned to VFS, so
that the vnode can be kept up-to-date.
(this broke test11 in the test set)
MFS:
. lookup() checked for sizeof(string) instead of sizeof(user_path),
truncating long path names
(caught by test 23)
. truncate functions neglected to update ctime
(this broke test16)
VFS:
. corner case of an empty filename lookup caused fields of a request
not to be filled in in the lookup functions, not making it clear
that the lookup had failed, causing messages to garbage processes,
causing strange failures.
(caught by test 30)
. trust v_size in vnode when doing reads or writes on non-special
files, truncating i/o where necessary; this is necessary for pipes,
as MFS can't tell when a pipe has been truncated without it being
told explicitly each time.
when the last reader/writer on a pipe closes, tell FS about
the new size using truncate_vn().
(this broke test 25, among others)
. permission check for chdir() had disappeared; added a
forbidden() call
(caught by test 23)
new code, shouldn't change anything:
. introduced RTS_SET, RTS_UNSET, and RTS_ISSET macro's, and their
LOCK variants. These macros set and clear the p_rts_flags field,
causing a lot of duplicated logic like
old_flags = rp->p_rts_flags; /* save value of the flags */
rp->p_rts_flags &= ~NO_PRIV;
if (old_flags != 0 && rp->p_rts_flags == 0) lock_enqueue(rp);
to change into the simpler
RTS_LOCK_UNSET(rp, NO_PRIV);
so the macros take care of calling dequeue() and enqueue() (or lock_*()),
as the case may be). This makes the code a bit more readable and a
bit less fragile.
. removed return code from do_clocktick in CLOCK as it currently
never replies
. removed some debug code from VFS
. fixed grant debug message in device.c
preemptive checks, tests, changes:
. added return code checks of receive() to SYSTEM and CLOCK
. O_TRUNC should never arrive at MFS (added sanity check and removed
O_TRUNC code)
. user_path declared with PATH_MAX+1 to let it be null-terminated
. checks in MFS to see if strings passed by VFS are null-terminated
IS:
. static irq name table thrown out
2007-02-01 18:50:02 +01:00
|
|
|
RTS_LOCK_UNSET(rp, SENDING);
|
2006-03-15 13:01:59 +01:00
|
|
|
#if DEBUG_ENABLE_IPC_WARNINGS
|
2009-01-14 09:52:50 +01:00
|
|
|
kprintf("endpoint %d / %s send to dying dst ep %d (%s)\n",
|
|
|
|
rp->p_endpoint, rp->p_name, rc->p_endpoint, rc->p_name);
|
2006-03-15 13:01:59 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* umap_verify_grant *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC phys_bytes umap_verify_grant(rp, grantee, grant, offset, bytes, access)
|
|
|
|
struct proc *rp; /* pointer to proc table entry for process */
|
|
|
|
endpoint_t grantee; /* who wants to do this */
|
|
|
|
cp_grant_id_t grant; /* grant no. */
|
|
|
|
vir_bytes offset; /* offset into grant */
|
|
|
|
vir_bytes bytes; /* size */
|
|
|
|
int access; /* does grantee want to CPF_READ or _WRITE? */
|
|
|
|
{
|
|
|
|
int proc_nr;
|
|
|
|
vir_bytes v_offset;
|
|
|
|
endpoint_t granter;
|
|
|
|
|
|
|
|
/* See if the grant in that process is sensible, and
|
|
|
|
* find out the virtual address and (optionally) new
|
|
|
|
* process for that address.
|
|
|
|
*
|
|
|
|
* Then convert that process to a slot number.
|
|
|
|
*/
|
|
|
|
if(verify_grant(rp->p_endpoint, grantee, grant, bytes, access, offset,
|
|
|
|
&v_offset, &granter) != OK
|
|
|
|
|| !isokendpt(granter, &proc_nr)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do the mapping from virtual to physical. */
|
|
|
|
return umap_virtual(proc_addr(proc_nr), D, v_offset, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* vmrestart_check *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE struct proc *vmrestart_check(message *m)
|
|
|
|
{
|
|
|
|
int type, r;
|
|
|
|
struct proc *restarting;
|
|
|
|
|
|
|
|
/* Anyone waiting to be vm-restarted? */
|
|
|
|
|
|
|
|
if(!(restarting = vmrestart))
|
|
|
|
return NULL;
|
|
|
|
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
vmassert(!RTS_ISSET(restarting, SLOT_FREE));
|
|
|
|
vmassert(RTS_ISSET(restarting, VMREQUEST));
|
2008-11-19 13:26:10 +01:00
|
|
|
|
|
|
|
type = restarting->p_vmrequest.type;
|
|
|
|
restarting->p_vmrequest.type = VMSTYPE_SYS_NONE;
|
|
|
|
vmrestart = restarting->p_vmrequest.nextrestart;
|
|
|
|
|
|
|
|
switch(type) {
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
case VMSTYPE_KERNELCALL:
|
2008-11-19 13:26:10 +01:00
|
|
|
memcpy(m, &restarting->p_vmrequest.saved.reqmsg, sizeof(*m));
|
Primary goal for these changes is:
- no longer have kernel have its own page table that is loaded
on every kernel entry (trap, interrupt, exception). the primary
purpose is to reduce the number of required reloads.
Result:
- kernel can only access memory of process that was running when
kernel was entered
- kernel must be mapped into every process page table, so traps to
kernel keep working
Problem:
- kernel must often access memory of arbitrary processes (e.g. send
arbitrary processes messages); this can't happen directly any more;
usually because that process' page table isn't loaded at all, sometimes
because that memory isn't mapped in at all, sometimes because it isn't
mapped in read-write.
So:
- kernel must be able to map in memory of any process, in its own
address space.
Implementation:
- VM and kernel share a range of memory in which addresses of
all page tables of all processes are available. This has two purposes:
. Kernel has to know what data to copy in order to map in a range
. Kernel has to know where to write the data in order to map it in
That last point is because kernel has to write in the currently loaded
page table.
- Processes and kernel are separated through segments; kernel segments
haven't changed.
- The kernel keeps the process whose page table is currently loaded
in 'ptproc.'
- If it wants to map in a range of memory, it writes the value of the
page directory entry for that range into the page directory entry
in the currently loaded map. There is a slot reserved for such
purposes. The kernel can then access this memory directly.
- In order to do this, its segment has been increased (and the
segments of processes start where it ends).
- In the pagefault handler, detect if the kernel is doing
'trappable' memory access (i.e. a pagefault isn't a fatal
error) and if so,
- set the saved instruction pointer to phys_copy_fault,
breaking out of phys_copy
- set the saved eax register to the address of the page
fault, both for sanity checking and for checking in
which of the two ranges that phys_copy was called
with the fault occured
- Some boot-time processes do not have their own page table,
and are mapped in with the kernel, and separated with
segments. The kernel detects this using HASPT. If such a
process has to be scheduled, any page table will work and
no page table switch is done.
Major changes in kernel are
- When accessing user processes memory, kernel no longer
explicitly checks before it does so if that memory is OK.
It simply makes the mapping (if necessary), tries to do the
operation, and traps the pagefault if that memory isn't present;
if that happens, the copy function returns EFAULT.
So all of the CHECKRANGE_OR_SUSPEND macros are gone.
- Kernel no longer has to copy/read and parse page tables.
- A message copying optimisation: when messages are copied, and
the recipient isn't mapped in, they are copied into a buffer
in the kernel. This is done in QueueMess. The next time
the recipient is scheduled, this message is copied into
its memory. This happens in schedcheck().
This eliminates the mapping/copying step for messages, and makes
it easier to deliver messages. This eliminates soft_notify.
- Kernel no longer creates a page table at all, so the vm_setbuf
and pagetable writing in memory.c is gone.
Minor changes in kernel are
- ipc_stats thrown out, wasn't used
- misc flags all renamed to MF_*
- NOREC_* macros to enter and leave functions that should not
be called recursively; just sanity checks really
- code to fully decode segment selectors and descriptors
to print on exceptions
- lots of vmassert()s added, only executed if DEBUG_VMASSERT is 1
2009-09-21 16:31:52 +02:00
|
|
|
restarting->p_vmrequest.saved.reqmsg.m_source = NONE;
|
|
|
|
vmassert(m->m_source == restarting->p_endpoint);
|
2008-11-19 13:26:10 +01:00
|
|
|
/* Original caller could've disappeared in the meantime. */
|
|
|
|
if(!isokendpt(m->m_source, &who_p)) {
|
|
|
|
kprintf("SYSTEM: ignoring call %d from dead %d\n",
|
|
|
|
m->m_type, m->m_source);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
{ int i;
|
|
|
|
i = m->m_type - KERNEL_CALL;
|
|
|
|
if(i >= 0 && i < NR_SYS_CALLS) {
|
|
|
|
#if 0
|
|
|
|
kprintf("SYSTEM: restart %s from %d\n",
|
|
|
|
callnames[i], m->m_source);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
minix_panic("call number out of range", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return restarting;
|
|
|
|
default:
|
|
|
|
minix_panic("strange restart type", type);
|
|
|
|
}
|
|
|
|
minix_panic("fell out of switch", NO_NUM);
|
2006-03-15 13:01:59 +01:00
|
|
|
}
|