Basic VM and other minor improvements.

Not complete, probably not fully debugged or optimized.
This commit is contained in:
Ben Gras
2008-11-19 12:26:10 +00:00
parent c888305e21
commit c078ec0331
273 changed files with 10814 additions and 4305 deletions

View File

@@ -8,17 +8,19 @@ ARCHAR=$(ARCH).a
# the HEAD variable is passed as an argument to this Makefile
# by an upper level Makefile.
OBJS=$(ARCHAR)(exception.o) \
$(ARCHAR)(i8259.o) \
$(ARCHAR)(memory.o) \
$(ARCHAR)(protect.o) \
$(ARCHAR)(system.o) \
$(ARCHAR)(clock.o) \
$(ARCHAR)(klib386.o) \
$(ARCHAR)(do_readbios.o) \
$(ARCHAR)(do_int86.o) \
$(ARCHAR)(do_sdevio.o) \
$(ARCHAR)(do_iopenable.o)
OBJS= arch_do_vmctl.o \
clock.o \
do_int86.o \
do_iopenable.o \
do_readbios.o \
do_sdevio.o \
exception.o \
i8259.o \
klib386.o \
memory.o \
mpx386.o \
protect.o \
system.o
CPPFLAGS=-Iinclude
CFLAGS=$(CPPFLAGS) -Wall
@@ -56,6 +58,9 @@ $(ARCHAR)(do_int86.o): do_int86.c
$(ARCHAR)(do_iopenable.o): do_iopenable.c
$(CC) $(CFLAGS) -c $<
$(ARCHAR)(arch_do_vmctl.o): arch_do_vmctl.c
$(CC) $(CFLAGS) -c $<
$(ARCHAR)(do_readbios.o): do_readbios.c
$(CC) $(CFLAGS) -c $<

View File

@@ -0,0 +1,56 @@
/* The kernel call implemented in this file:
* m_type: SYS_VMCTL
*
* The parameters for this kernel call are:
* SVMCTL_WHO which process
* SVMCTL_PARAM set this setting (VMCTL_*)
* SVMCTL_VALUE to this value
*/
#include "../../system.h"
#include <minix/type.h>
extern u32_t kernel_cr3;
/*===========================================================================*
* arch_do_vmctl *
*===========================================================================*/
PUBLIC int arch_do_vmctl(m_ptr, p)
register message *m_ptr; /* pointer to request message */
struct proc *p;
{
switch(m_ptr->SVMCTL_PARAM) {
case VMCTL_I386_GETCR3:
/* Get process CR3. */
m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3;
return OK;
case VMCTL_I386_SETCR3:
/* Set process CR3. */
if(m_ptr->SVMCTL_VALUE) {
p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE;
p->p_misc_flags |= MF_FULLVM;
} else {
p->p_seg.p_cr3 = kernel_cr3;
p->p_misc_flags &= ~MF_FULLVM;
}
RTS_LOCK_UNSET(p, VMINHIBIT);
return OK;
case VMCTL_GET_PAGEFAULT:
{
struct proc *rp;
if(!(rp=pagefaults))
return ESRCH;
pagefaults = rp->p_nextpagefault;
if(!RTS_ISSET(rp, PAGEFAULT))
minix_panic("non-PAGEFAULT process on pagefault chain",
rp->p_endpoint);
m_ptr->SVMCTL_PF_WHO = rp->p_endpoint;
m_ptr->SVMCTL_PF_I386_CR2 = rp->p_pagefault.pf_virtual;
m_ptr->SVMCTL_PF_I386_ERR = rp->p_pagefault.pf_flags;
return OK;
}
}
kprintf("arch_do_vmctl: strange param %d\n", m_ptr->SVMCTL_PARAM);
return EINVAL;
}

View File

@@ -21,28 +21,23 @@ struct reg86u reg86;
PUBLIC int do_int86(m_ptr)
register message *m_ptr; /* pointer to request message */
{
vir_bytes caller_vir;
phys_bytes caller_phys, kernel_phys;
caller_vir = (vir_bytes) m_ptr->INT86_REG86;
caller_phys = umap_local(proc_addr(who_p), D, caller_vir, sizeof(reg86));
if (0 == caller_phys) return(EFAULT);
kernel_phys = vir2phys(&reg86);
phys_copy(caller_phys, kernel_phys, (phys_bytes) sizeof(reg86));
data_copy(who_e, (vir_bytes) m_ptr->INT86_REG86,
SYSTEM, (vir_bytes) &reg86, sizeof(reg86));
level0(int86);
/* Copy results back to the caller */
phys_copy(kernel_phys, caller_phys, (phys_bytes) sizeof(reg86));
data_copy(SYSTEM, (vir_bytes) &reg86,
who_e, (vir_bytes) m_ptr->INT86_REG86, sizeof(reg86));
/* The BIOS call eats interrupts. Call get_randomness to generate some
* entropy. Normally, get_randomness is called from an interrupt handler.
* Figuring out the exact source is too complicated. CLOCK_IRQ is normally
* not very random.
*/
lock(0, "do_int86");
lock;
get_randomness(CLOCK_IRQ);
unlock(0);
unlock;
return(OK);
}

View File

@@ -16,24 +16,14 @@
PUBLIC int do_readbios(m_ptr)
register message *m_ptr; /* pointer to request message */
{
int proc_nr;
struct proc *p;
phys_bytes address, phys_buf, phys_bios;
vir_bytes buf;
size_t size;
struct vir_addr src, dst;
src.segment = BIOS_SEG;
dst.segment = D;
src.offset = m_ptr->RDB_ADDR;
dst.offset = (vir_bytes) m_ptr->RDB_BUF;
src.proc_nr_e = NONE;
dst.proc_nr_e = m_ptr->m_source;
address = m_ptr->RDB_ADDR;
buf = (vir_bytes)m_ptr->RDB_BUF;
size = m_ptr->RDB_SIZE;
okendpt(m_ptr->m_source, &proc_nr);
p = proc_addr(proc_nr);
phys_buf = umap_local(p, D, buf, size);
if (phys_buf == 0)
return EFAULT;
phys_bios = umap_bios(p, address, size);
if (phys_bios == 0)
return EPERM;
phys_copy(phys_bios, phys_buf, size);
return 0;
return virtual_copy_vmcheck(&src, &dst, m_ptr->RDB_SIZE);
}

View File

@@ -77,7 +77,7 @@ register message *m_ptr; /* pointer to request message */
return EPERM;
}
/* Get and check physical address. */
if ((phys_buf = numap_local(proc_nr,
if ((phys_buf = umap_virtual(proc_addr(proc_nr), D,
(vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
return(EFAULT);
}

View File

@@ -6,8 +6,66 @@
#include "../../kernel.h"
#include "proto.h"
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <minix/sysutil.h>
#include "../../proc.h"
extern int vm_copy_in_progress;
extern struct proc *vm_copy_from, *vm_copy_to;
extern u32_t vm_copy_from_v, vm_copy_to_v;
extern u32_t vm_copy_from_p, vm_copy_to_p, vm_copy_cr3;
u32_t pagefault_cr2, pagefault_count = 0;
void pagefault(struct proc *pr, int trap_errno)
{
int s;
vir_bytes ph;
u32_t pte;
if(pagefault_count != 1)
minix_panic("recursive pagefault", pagefault_count);
/* Don't schedule this process until pagefault is handled. */
if(RTS_ISSET(pr, PAGEFAULT))
minix_panic("PAGEFAULT set", pr->p_endpoint);
RTS_LOCK_SET(pr, PAGEFAULT);
if(pr->p_endpoint <= INIT_PROC_NR) {
/* Page fault we can't / don't want to
* handle.
*/
kprintf("pagefault for process %d ('%s'), pc = 0x%x\n",
pr->p_endpoint, pr->p_name, pr->p_reg.pc);
proc_stacktrace(pr);
minix_panic("page fault in system process", pr->p_endpoint);
return;
}
/* Save pagefault details, suspend process,
* add process to pagefault chain,
* and tell VM there is a pagefault to be
* handled.
*/
pr->p_pagefault.pf_virtual = pagefault_cr2;
pr->p_pagefault.pf_flags = trap_errno;
pr->p_nextpagefault = pagefaults;
pagefaults = pr;
lock_notify(HARDWARE, VM_PROC_NR);
pagefault_count = 0;
#if 0
kprintf("pagefault for process %d ('%s'), pc = 0x%x\n",
pr->p_endpoint, pr->p_name, pr->p_reg.pc);
proc_stacktrace(pr);
#endif
return;
}
/*===========================================================================*
* exception *
*===========================================================================*/
@@ -62,8 +120,13 @@ u32_t old_eflags;
* k_reenter larger than zero.
*/
if (k_reenter == 0 && ! iskernelp(saved_proc)) {
#if 0
{
switch(vec_nr) {
case PAGE_FAULT_VECTOR:
pagefault(saved_proc, trap_errno);
return;
}
kprintf(
"exception for process %d, endpoint %d ('%s'), pc = 0x%x:0x%x, sp = 0x%x:0x%x\n",
proc_nr(saved_proc), saved_proc->p_endpoint,
@@ -75,12 +138,11 @@ u32_t old_eflags;
vec_nr, (unsigned long)trap_errno,
(unsigned long)old_eip, old_cs,
(unsigned long)old_eflags);
#if DEBUG_STACKTRACE
stacktrace(saved_proc);
#endif
proc_stacktrace(saved_proc);
}
#endif
kprintf("kernel: cause_sig %d for %d\n",
ep->signum, saved_proc->p_endpoint);
cause_sig(proc_nr(saved_proc), ep->signum);
return;
}
@@ -92,43 +154,45 @@ u32_t old_eflags;
kprintf("\n%s\n", ep->msg);
kprintf("k_reenter = %d ", k_reenter);
kprintf("process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name);
kprintf("pc = %u:0x%x", (unsigned) saved_proc->p_reg.cs,
(unsigned) saved_proc->p_reg.pc);
kprintf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs,
(unsigned) saved_proc->p_reg.pc);
kprintf(
"vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n",
vec_nr, (unsigned long)trap_errno,
(unsigned long)old_eip, old_cs, (unsigned long)old_eflags);
proc_stacktrace(saved_proc);
panic("exception in a kernel task", NO_NUM);
minix_panic("exception in a kernel task", saved_proc->p_endpoint);
}
#if DEBUG_STACKTRACE
/*===========================================================================*
* stacktrace *
*===========================================================================*/
PUBLIC void stacktrace(struct proc *proc)
PUBLIC void proc_stacktrace(struct proc *proc)
{
reg_t bp, v_bp, v_pc, v_hbp;
v_bp = proc->p_reg.fp;
kprintf("stacktrace: ");
kprintf("ep %d pc 0x%lx stack ", proc->p_endpoint, proc->p_reg.pc);
while(v_bp) {
phys_bytes p;
if(!(p = umap_local(proc, D, v_bp, sizeof(v_bp)))) {
kprintf("(bad bp %lx)", v_bp);
if(data_copy(proc->p_endpoint, v_bp,
SYSTEM, (vir_bytes) &v_hbp, sizeof(v_hbp)) != OK) {
kprintf("(v_bp 0x%lx ?)", v_bp);
break;
}
if(data_copy(proc->p_endpoint, v_bp + sizeof(v_pc),
SYSTEM, (vir_bytes) &v_pc, sizeof(v_pc)) != OK) {
kprintf("(v_pc 0x%lx ?)", v_pc);
break;
}
phys_copy(p+sizeof(v_pc), vir2phys(&v_pc), sizeof(v_pc));
phys_copy(p, vir2phys(&v_hbp), sizeof(v_hbp));
kprintf("0x%lx ", (unsigned long) v_pc);
if(v_hbp != 0 && v_hbp <= v_bp) {
kprintf("(bad hbp %lx)", v_hbp);
kprintf("(hbp %lx ?)", v_hbp);
break;
}
v_bp = v_hbp;
}
kprintf("\n");
}
#endif

View File

@@ -135,12 +135,6 @@
#define IF_MASK 0x00000200
#define IOPL_MASK 0x003000
/* Sizes of memory tables. The boot monitor distinguishes three memory areas,
* namely low mem below 1M, 1M-16M, and mem after 16M. More chunks are needed
* for DOS MINIX.
*/
#define NR_MEMS 8
#define vir2phys(vir) (kinfo.data_base + (vir_bytes) (vir))
#endif /* _I386_ACONST_H */

View File

@@ -55,8 +55,18 @@ struct segdesc_s { /* segment descriptor for protected mode */
typedef struct segframe {
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
reg_t p_cr3; /* page table root */
struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote */
} segframe_t;
/* Page fault event. Stored in process table. Only valid if PAGEFAULT
* set in p_rts_flags.
*/
struct pagefault
{
u32_t pf_virtual; /* Address causing fault (CR2). */
u32_t pf_flags; /* Pagefault flags on stack. */
};
#endif /* #ifndef _I386_TYPES_H */

View File

@@ -8,6 +8,7 @@
#include <ibm/interrupt.h>
#include <archconst.h>
#include "../../const.h"
#include "vm.h"
#include "sconst.h"
! This file contains a number of assembly code utility routines needed by the
@@ -15,7 +16,7 @@
.define _monitor ! exit Minix and return to the monitor
.define _int86 ! let the monitor make an 8086 interrupt call
.define _cp_mess ! copies messages from source to destination
!.define _cp_mess ! copies messages from source to destination
.define _exit ! dummy for library routines
.define __exit ! dummy for library routines
.define ___exit ! dummy for library routines
@@ -34,8 +35,11 @@
.define _level0 ! call a function at level 0
.define _read_cpu_flags ! read the cpu flags
.define _read_cr0 ! read cr0
.define _write_cr3 ! write cr3
.define _last_cr3
.define _write_cr0 ! write a value in cr0
.define _write_cr3 ! write a value in cr3 (root of the page table)
.define _kernel_cr3
! The routines only guarantee to preserve the registers the C compiler
! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
@@ -162,42 +166,42 @@ csinit: mov eax, DS_SELECTOR
! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
! correctly. Changing the definition of message in the type file and not
! changing it here will lead to total disaster.
CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
! es ds edi esi eip proc scl sof dcl dof
.align 16
_cp_mess:
cld
push esi
push edi
push ds
push es
mov eax, FLAT_DS_SELECTOR
mov ds, ax
mov es, ax
mov esi, CM_ARGS+4(esp) ! src clicks
shl esi, CLICK_SHIFT
add esi, CM_ARGS+4+4(esp) ! src offset
mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
shl edi, CLICK_SHIFT
add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
mov eax, CM_ARGS(esp) ! process number of sender
stos ! copy number of sender to dest message
add esi, 4 ! do not copy first word
mov ecx, Msize - 1 ! remember, first word does not count
rep
movs ! copy the message
pop es
pop ds
pop edi
pop esi
ret ! that is all folks!
!
!CM_ARGS = 4 + 4 + 4 + 4 + 4 ! 4 + 4 + 4 + 4 + 4
!! es ds edi esi eip proc scl sof dcl dof
!
! .align 16
!_cp_mess:
! cld
! push esi
! push edi
! push ds
! push es
!
! mov eax, FLAT_DS_SELECTOR
! mov ds, ax
! mov es, ax
!
! mov esi, CM_ARGS+4(esp) ! src clicks
! shl esi, CLICK_SHIFT
! add esi, CM_ARGS+4+4(esp) ! src offset
! mov edi, CM_ARGS+4+4+4(esp) ! dst clicks
! shl edi, CLICK_SHIFT
! add edi, CM_ARGS+4+4+4+4(esp) ! dst offset
!
! mov eax, CM_ARGS(esp) ! process number of sender
! stos ! copy number of sender to dest message
! add esi, 4 ! do not copy first word
! mov ecx, Msize - 1 ! remember, first word does not count
! rep
! movs ! copy the message
!
! pop es
! pop ds
! pop edi
! pop esi
! ret ! that is all folks!
!
!*===========================================================================*
!* exit *
@@ -229,6 +233,9 @@ _phys_insw:
cld
push edi
push es
LOADKERNELCR3
mov ecx, FLAT_DS_SELECTOR
mov es, cx
mov edx, 8(ebp) ! port to read from
@@ -254,6 +261,9 @@ _phys_insb:
cld
push edi
push es
LOADKERNELCR3
mov ecx, FLAT_DS_SELECTOR
mov es, cx
mov edx, 8(ebp) ! port to read from
@@ -280,6 +290,9 @@ _phys_outsw:
cld
push esi
push ds
LOADKERNELCR3
mov ecx, FLAT_DS_SELECTOR
mov ds, cx
mov edx, 8(ebp) ! port to write to
@@ -306,6 +319,9 @@ _phys_outsb:
cld
push esi
push ds
LOADKERNELCR3
mov ecx, FLAT_DS_SELECTOR
mov ds, cx
mov edx, 8(ebp) ! port to write to
@@ -412,6 +428,8 @@ _phys_copy:
push edi
push es
LOADKERNELCR3
mov eax, FLAT_DS_SELECTOR
mov es, ax
@@ -456,6 +474,9 @@ _phys_memset:
push esi
push ebx
push ds
LOADKERNELCR3
mov esi, 8(ebp)
mov eax, 16(ebp)
mov ebx, FLAT_DS_SELECTOR
@@ -485,6 +506,7 @@ fill_done:
pop esi
pop ebp
ret
!*===========================================================================*
!* mem_rdw *
@@ -585,14 +607,13 @@ _write_cr0:
ret
!*===========================================================================*
!* write_cr3 *
!* write_cr3 *
!*===========================================================================*
! PUBLIC void write_cr3(unsigned long value);
_write_cr3:
push ebp
mov ebp, esp
mov eax, 8(ebp)
mov cr3, eax
pop ebp
push ebp
mov ebp, esp
LOADCR3WITHEAX(0x22, 8(ebp))
pop ebp
ret

View File

@@ -1,20 +1,26 @@
#include "../../kernel.h"
#include "../../proc.h"
#include "../../vm.h"
#include <minix/type.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <string.h>
#include <sys/vm.h>
#include <sys/vm_i386.h>
#include <minix/portio.h>
#include "proto.h"
#include "../../proto.h"
#include "../../debug.h"
/* VM functions and data. */
PRIVATE int vm_needs_init= 1;
PRIVATE u32_t vm_cr3;
PUBLIC u32_t kernel_cr3;
extern u32_t cswitch;
u32_t last_cr3 = 0;
FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) );
FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) );
@@ -22,6 +28,13 @@ FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) );
FORWARD _PROTOTYPE( void set_cr3, (void) );
FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
#if DEBUG_VMASSERT
#define vmassert(t) { \
if(!(t)) { minix_panic("vm: assert " #t " failed\n", __LINE__); } }
#else
#define vmassert(t) { }
#endif
/* *** Internal VM Functions *** */
PUBLIC void vm_init(void)
@@ -31,31 +44,35 @@ PUBLIC void vm_init(void)
phys_bytes vm_dir_base, vm_pt_base, phys_mem;
u32_t entry;
unsigned pages;
struct proc* rp;
if (!vm_size)
panic("i386_vm_init: no space for page tables", NO_NUM);
minix_panic("i386_vm_init: no space for page tables", NO_NUM);
if(vm_running)
return;
/* Align page directory */
o= (vm_base % PAGE_SIZE);
o= (vm_base % I386_PAGE_SIZE);
if (o != 0)
o= PAGE_SIZE-o;
o= I386_PAGE_SIZE-o;
vm_dir_base= vm_base+o;
/* Page tables start after the page directory */
vm_pt_base= vm_dir_base+PAGE_SIZE;
vm_pt_base= vm_dir_base+I386_PAGE_SIZE;
pt_size= (vm_base+vm_size)-vm_pt_base;
pt_size -= (pt_size % PAGE_SIZE);
pt_size -= (pt_size % I386_PAGE_SIZE);
/* Compute the number of pages based on vm_mem_high */
pages= (vm_mem_high-1)/PAGE_SIZE + 1;
pages= (vm_mem_high-1)/I386_PAGE_SIZE + 1;
if (pages * I386_VM_PT_ENT_SIZE > pt_size)
panic("i386_vm_init: page table too small", NO_NUM);
minix_panic("i386_vm_init: page table too small", NO_NUM);
for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++)
{
phys_mem= p*PAGE_SIZE;
phys_mem= p*I386_PAGE_SIZE;
entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
I386_VM_PRESENT;
if (phys_mem >= vm_mem_high)
@@ -65,15 +82,33 @@ PUBLIC void vm_init(void)
for (p= 0; p < I386_VM_DIR_ENTRIES; p++)
{
phys_mem= vm_pt_base + p*PAGE_SIZE;
phys_mem= vm_pt_base + p*I386_PAGE_SIZE;
entry= phys_mem | I386_VM_USER | I386_VM_WRITE |
I386_VM_PRESENT;
if (phys_mem >= vm_pt_base + pt_size)
entry= 0;
phys_put32(vm_dir_base + p*I386_VM_PT_ENT_SIZE, entry);
}
/* Set this cr3 in all currently running processes for
* future context switches.
*/
for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
u32_t mycr3;
if(isemptyp(rp)) continue;
rp->p_seg.p_cr3 = vm_dir_base;
}
kernel_cr3 = vm_dir_base;
/* Set this cr3 now (not active until paging enabled). */
vm_set_cr3(vm_dir_base);
/* Actually enable paging (activating cr3 load above). */
level0(vm_enable_paging);
/* Don't do this init in the future. */
vm_running = 1;
}
PRIVATE void phys_put32(addr, value)
@@ -113,50 +148,6 @@ PRIVATE void vm_enable_paging(void)
write_cr0(cr0 | I386_CR0_PG);
}
PUBLIC void vm_map_range(base, size, offset)
u32_t base;
u32_t size;
u32_t offset;
{
u32_t curr_pt, curr_pt_addr, entry;
int dir_ent, pt_ent;
if (base % PAGE_SIZE != 0)
panic("map_range: bad base", base);
if (size % PAGE_SIZE != 0)
panic("map_range: bad size", size);
if (offset % PAGE_SIZE != 0)
panic("map_range: bad offset", offset);
curr_pt= -1;
curr_pt_addr= 0;
while (size != 0)
{
dir_ent= (base >> I386_VM_DIR_ENT_SHIFT);
pt_ent= (base >> I386_VM_PT_ENT_SHIFT) & I386_VM_PT_ENT_MASK;
if (dir_ent != curr_pt)
{
/* Get address of page table */
curr_pt= dir_ent;
curr_pt_addr= phys_get32(vm_cr3 +
dir_ent * I386_VM_PT_ENT_SIZE);
curr_pt_addr &= I386_VM_ADDR_MASK;
}
entry= offset | I386_VM_USER | I386_VM_WRITE |
I386_VM_PRESENT;
#if 0 /* Do we need this for memory mapped I/O? */
entry |= I386_VM_PCD | I386_VM_PWT;
#endif
phys_put32(curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE, entry);
offset += PAGE_SIZE;
base += PAGE_SIZE;
size -= PAGE_SIZE;
}
/* reload root of page table. */
vm_set_cr3(vm_cr3);
}
PUBLIC vir_bytes alloc_remote_segment(u32_t *selector,
segframe_t *segments, int index, phys_bytes phys, vir_bytes size,
int priv)
@@ -188,6 +179,10 @@ PUBLIC phys_bytes umap_remote(struct proc* rp, int seg,
/* Calculate the physical memory address for a given virtual address. */
struct far_mem *fm;
#if 0
if(rp->p_misc_flags & MF_FULLVM) return 0;
#endif
if (bytes <= 0) return( (phys_bytes) 0);
if (seg < 0 || seg >= NR_REMOTE_SEGS) return( (phys_bytes) 0);
@@ -212,6 +207,9 @@ vir_bytes bytes; /* # of bytes to be copied */
phys_bytes pa; /* intermediate variables as phys_bytes */
phys_bytes seg_base;
if(seg != T && seg != D && seg != S)
minix_panic("umap_local: wrong seg", seg);
if (bytes <= 0) return( (phys_bytes) 0);
if (vir_addr + bytes <= vir_addr) return 0; /* overflow */
vc = (vir_addr + bytes - 1) >> CLICK_SHIFT; /* last click of data */
@@ -232,3 +230,569 @@ vir_bytes bytes; /* # of bytes to be copied */
return(seg_base + pa);
}
/*===========================================================================*
* umap_virtual *
*===========================================================================*/
PUBLIC phys_bytes umap_virtual(rp, seg, vir_addr, bytes)
register struct proc *rp; /* pointer to proc table entry for process */
int seg; /* T, D, or S segment */
vir_bytes vir_addr; /* virtual address in bytes within the seg */
vir_bytes bytes; /* # of bytes to be copied */
{
vir_bytes linear;
u32_t phys = 0;
if(seg == MEM_GRANT) {
phys = umap_grant(rp, vir_addr, bytes);
} else {
if(!(linear = umap_local(rp, seg, vir_addr, bytes))) {
kprintf("SYSTEM:umap_virtual: umap_local failed\n");
phys = 0;
} else {
if(vm_lookup(rp, linear, &phys, NULL) != OK) {
kprintf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%lx: 0x%lx failed\n", rp->p_name, seg, vir_addr);
phys = 0;
}
if(phys == 0)
minix_panic("vm_lookup returned phys", phys);
}
}
if(phys == 0) {
kprintf("SYSTEM:umap_virtual: lookup failed\n");
return 0;
}
/* Now make sure addresses are contiguous in physical memory
* so that the umap makes sense.
*/
if(bytes > 0 && !vm_contiguous(rp, linear, bytes)) {
kprintf("umap_virtual: %s: %d at 0x%lx (vir 0x%lx) not contiguous\n",
rp->p_name, bytes, linear, vir_addr);
return 0;
}
/* phys must be larger than 0 (or the caller will think the call
* failed), and address must not cross a page boundary.
*/
vmassert(phys);
return phys;
}
/*===========================================================================*
* vm_lookup *
*===========================================================================*/
PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical, u32_t *ptent)
{
u32_t *root, *pt;
int pde, pte;
u32_t pde_v, pte_v;
vmassert(proc);
vmassert(physical);
vmassert(!(proc->p_rts_flags & SLOT_FREE));
/* Retrieve page directory entry. */
root = (u32_t *) proc->p_seg.p_cr3;
vmassert(!((u32_t) root % I386_PAGE_SIZE));
pde = I386_VM_PDE(virtual);
vmassert(pde >= 0 && pde < I386_VM_DIR_ENTRIES);
pde_v = phys_get32((u32_t) (root + pde));
if(!(pde_v & I386_VM_PRESENT)) {
#if 0
kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pde %d not present\n",
proc->p_endpoint, proc->p_name, virtual, root, pde);
kprintf("kernel stack: ");
util_stacktrace();
#endif
return EFAULT;
}
/* Retrieve page table entry. */
pt = (u32_t *) I386_VM_PFA(pde_v);
vmassert(!((u32_t) pt % I386_PAGE_SIZE));
pte = I386_VM_PTE(virtual);
vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES);
pte_v = phys_get32((u32_t) (pt + pte));
if(!(pte_v & I386_VM_PRESENT)) {
#if 0
kprintf("vm_lookup: %d:%s:0x%lx: cr3 %lx: pde %d: pte %d not present\n",
proc->p_endpoint, proc->p_name, virtual, root, pde, pte);
kprintf("kernel stack: ");
util_stacktrace();
#endif
return EFAULT;
}
if(ptent) *ptent = pte_v;
/* Actual address now known; retrieve it and add page offset. */
*physical = I386_VM_PFA(pte_v);
*physical += virtual % I386_PAGE_SIZE;
return OK;
}
/* From virtual address v in process p,
* lookup physical address and assign it to d.
* If p is NULL, assume it's already a physical address.
*/
#define LOOKUP(d, p, v, flagsp) { \
int r; \
if(!(p)) { (d) = (v); } \
else { \
if((r=vm_lookup((p), (v), &(d), flagsp)) != OK) { \
kprintf("vm_copy: lookup failed of 0x%lx in %d (%s)\n"\
"kernel stacktrace: ", (v), (p)->p_endpoint, \
(p)->p_name); \
util_stacktrace(); \
return r; \
} } }
/*===========================================================================*
* vm_copy *
*===========================================================================*/
int vm_copy(vir_bytes src, struct proc *srcproc,
vir_bytes dst, struct proc *dstproc, phys_bytes bytes)
{
#define WRAPS(v) (ULONG_MAX - (v) <= bytes)
if(WRAPS(src) || WRAPS(dst))
minix_panic("vm_copy: linear address wraps", NO_NUM);
while(bytes > 0) {
u32_t n, flags;
phys_bytes p_src, p_dst;
#define PAGEREMAIN(v) (I386_PAGE_SIZE - ((v) % I386_PAGE_SIZE))
/* We can copy this number of bytes without
* crossing a page boundary, but don't copy more
* than asked.
*/
n = MIN(PAGEREMAIN(src), PAGEREMAIN(dst));
n = MIN(n, bytes);
vmassert(n > 0);
vmassert(n <= I386_PAGE_SIZE);
/* Convert both virtual addresses to physical and do
* copy.
*/
LOOKUP(p_src, srcproc, src, NULL);
LOOKUP(p_dst, dstproc, dst, &flags);
if(!(flags & I386_VM_WRITE)) {
kprintf("vm_copy: copying to nonwritable page\n");
kprintf("kernel stack: ");
util_stacktrace();
return EFAULT;
}
phys_copy(p_src, p_dst, n);
/* Book number of bytes copied. */
vmassert(bytes >= n);
bytes -= n;
src += n;
dst += n;
}
return OK;
}
/*===========================================================================*
* vm_contiguous *
*===========================================================================*/
PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes)
{
int first = 1, r, boundaries = 0;
u32_t prev_phys, po;
u32_t prev_vir;
vmassert(targetproc);
vmassert(bytes > 0);
vmassert(vm_running);
/* Start and end at page boundary to make logic simpler. */
po = vir_buf % I386_PAGE_SIZE;
if(po > 0) {
bytes += po;
vir_buf -= po;
}
po = (vir_buf + bytes) % I386_PAGE_SIZE;
if(po > 0)
bytes += I386_PAGE_SIZE - po;
/* Keep going as long as we cross a page boundary. */
while(bytes > 0) {
u32_t phys;
if((r=vm_lookup(targetproc, vir_buf, &phys, NULL)) != OK) {
kprintf("vm_contiguous: vm_lookup failed, %d\n", r);
kprintf("kernel stack: ");
util_stacktrace();
return 0;
}
if(!first) {
if(prev_phys+I386_PAGE_SIZE != phys) {
kprintf("vm_contiguous: no (0x%lx, 0x%lx)\n",
prev_phys, phys);
kprintf("kernel stack: ");
util_stacktrace();
return 0;
}
}
first = 0;
prev_phys = phys;
prev_vir = vir_buf;
vir_buf += I386_PAGE_SIZE;
bytes -= I386_PAGE_SIZE;
boundaries++;
}
if(verbose_vm)
kprintf("vm_contiguous: yes (%d boundaries tested)\n",
boundaries);
return 1;
}
int vm_checkrange_verbose = 0;
/*===========================================================================*
* vm_checkrange *
*===========================================================================*/
PUBLIC int vm_checkrange(struct proc *caller, struct proc *target,
vir_bytes vir, vir_bytes bytes, int wrfl, int checkonly)
{
u32_t flags, po, v;
int r;
vmassert(vm_running);
/* If caller has had a reply to this request, return it. */
if(RTS_ISSET(caller, VMREQUEST)) {
if(caller->p_vmrequest.who == target->p_endpoint) {
if(caller->p_vmrequest.vmresult == VMSUSPEND)
minix_panic("check sees VMSUSPEND?", NO_NUM);
RTS_LOCK_UNSET(caller, VMREQUEST);
#if 0
kprintf("SYSTEM: vm_checkrange: returning vmresult %d\n",
caller->p_vmrequest.vmresult);
#endif
return caller->p_vmrequest.vmresult;
} else {
#if 0
kprintf("SYSTEM: vm_checkrange: caller has a request for %d, "
"but our target is %d\n",
caller->p_vmrequest.who, target->p_endpoint);
#endif
}
}
po = vir % I386_PAGE_SIZE;
if(po > 0) {
vir -= po;
bytes += po;
}
vmassert(target);
vmassert(bytes > 0);
for(v = vir; v < vir + bytes; v+= I386_PAGE_SIZE) {
u32_t phys;
/* If page exists and it's writable if desired, we're OK
* for this page.
*/
if(vm_lookup(target, v, &phys, &flags) == OK &&
!(wrfl && !(flags & I386_VM_WRITE))) {
if(vm_checkrange_verbose) {
#if 0
kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, OK\n",
target->p_name, target->p_endpoint, v, wrfl, flags, phys);
#endif
}
continue;
}
if(vm_checkrange_verbose) {
kprintf("SYSTEM: checkrange:%s:%d: 0x%lx: write 0x%lx, flags 0x%lx, phys 0x%lx, NOT OK\n",
target->p_name, target->p_endpoint, v, wrfl, flags, phys);
}
if(checkonly)
return VMSUSPEND;
/* This range is not OK for this process. Set parameters
* of the request and notify VM about the pending request.
*/
if(RTS_ISSET(caller, VMREQUEST))
minix_panic("VMREQUEST already set", caller->p_endpoint);
RTS_LOCK_SET(caller, VMREQUEST);
/* Set parameters in caller. */
caller->p_vmrequest.writeflag = wrfl;
caller->p_vmrequest.start = vir;
caller->p_vmrequest.length = bytes;
caller->p_vmrequest.who = target->p_endpoint;
/* Set caller in target. */
target->p_vmrequest.requestor = caller;
/* Connect caller on vmrequest wait queue. */
caller->p_vmrequest.nextrequestor = vmrequest;
vmrequest = caller;
soft_notify(VM_PROC_NR);
#if 0
kprintf("SYSTEM: vm_checkrange: range bad for "
"target %s:0x%lx-0x%lx, caller %s\n",
target->p_name, vir, vir+bytes, caller->p_name);
kprintf("vm_checkrange kernel trace: ");
util_stacktrace();
kprintf("target trace: ");
proc_stacktrace(target);
#endif
if(target->p_endpoint == VM_PROC_NR) {
kprintf("caller trace: ");
proc_stacktrace(caller);
kprintf("target trace: ");
proc_stacktrace(target);
minix_panic("VM ranges should be OK", NO_NUM);
}
return VMSUSPEND;
}
return OK;
}
char *flagstr(u32_t e, int dir)
{
static char str[80];
strcpy(str, "");
#define FLAG(v) do { if(e & (v)) { strcat(str, #v " "); } } while(0)
FLAG(I386_VM_PRESENT);
FLAG(I386_VM_WRITE);
FLAG(I386_VM_USER);
FLAG(I386_VM_PWT);
FLAG(I386_VM_PCD);
if(dir)
FLAG(I386_VM_BIGPAGE); /* Page directory entry only */
else
FLAG(I386_VM_DIRTY); /* Page table entry only */
return str;
}
void vm_pt_print(u32_t *pagetable, u32_t v)
{
int pte, l = 0;
int col = 0;
vmassert(!((u32_t) pagetable % I386_PAGE_SIZE));
for(pte = 0; pte < I386_VM_PT_ENTRIES; pte++) {
u32_t pte_v, pfa;
pte_v = phys_get32((u32_t) (pagetable + pte));
if(!(pte_v & I386_VM_PRESENT))
continue;
pfa = I386_VM_PFA(pte_v);
kprintf("%4d:%08lx:%08lx ",
pte, v + I386_PAGE_SIZE*pte, pfa);
col++;
if(col == 3) { kprintf("\n"); col = 0; }
}
if(col > 0) kprintf("\n");
return;
}
/*===========================================================================*
* vm_print *
*===========================================================================*/
void vm_print(u32_t *root)
{
int pde;
vmassert(!((u32_t) root % I386_PAGE_SIZE));
for(pde = 0; pde < I386_VM_DIR_ENTRIES; pde++) {
u32_t pde_v;
u32_t *pte_a;
pde_v = phys_get32((u32_t) (root + pde));
if(!(pde_v & I386_VM_PRESENT))
continue;
pte_a = (u32_t *) I386_VM_PFA(pde_v);
kprintf("%4d: pt %08lx %s\n",
pde, pte_a, flagstr(pde_v, 1));
vm_pt_print(pte_a, pde * I386_VM_PT_ENTRIES * I386_PAGE_SIZE);
}
return;
}
/*===========================================================================*
* virtual_copy_f *
*===========================================================================*/
PUBLIC int virtual_copy_f(src_addr, dst_addr, bytes, vmcheck)
struct vir_addr *src_addr; /* source virtual address */
struct vir_addr *dst_addr; /* destination virtual address */
vir_bytes bytes; /* # of bytes to copy */
int vmcheck; /* if nonzero, can return VMSUSPEND */
{
/* Copy bytes from virtual address src_addr to virtual address dst_addr.
* Virtual addresses can be in ABS, LOCAL_SEG, REMOTE_SEG, or BIOS_SEG.
*/
struct vir_addr *vir_addr[2]; /* virtual source and destination address */
phys_bytes phys_addr[2]; /* absolute source and destination */
int seg_index;
int i, r;
struct proc *procs[2];
/* Check copy count. */
if (bytes <= 0) return(EDOM);
/* Do some more checks and map virtual addresses to physical addresses. */
vir_addr[_SRC_] = src_addr;
vir_addr[_DST_] = dst_addr;
for (i=_SRC_; i<=_DST_; i++) {
int proc_nr, type;
struct proc *p;
type = vir_addr[i]->segment & SEGMENT_TYPE;
if((type != PHYS_SEG && type != BIOS_SEG) &&
isokendpt(vir_addr[i]->proc_nr_e, &proc_nr))
p = proc_addr(proc_nr);
else
p = NULL;
procs[i] = p;
/* Get physical address. */
switch(type) {
case LOCAL_SEG:
case LOCAL_VM_SEG:
if(!p) return EDEADSRCDST;
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
if(type == LOCAL_SEG)
phys_addr[i] = umap_local(p, seg_index, vir_addr[i]->offset,
bytes);
else
phys_addr[i] = umap_virtual(p, seg_index, vir_addr[i]->offset,
bytes);
if(phys_addr[i] == 0) {
kprintf("virtual_copy: map 0x%x failed for %s seg %d, "
"offset %lx, len %d, i %d\n",
type, p->p_name, seg_index, vir_addr[i]->offset,
bytes, i);
}
break;
case REMOTE_SEG:
if(!p) return EDEADSRCDST;
seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
phys_addr[i] = umap_remote(p, seg_index, vir_addr[i]->offset, bytes);
break;
#if _MINIX_CHIP == _CHIP_INTEL
case BIOS_SEG:
phys_addr[i] = umap_bios(vir_addr[i]->offset, bytes );
break;
#endif
case PHYS_SEG:
phys_addr[i] = vir_addr[i]->offset;
break;
case GRANT_SEG:
phys_addr[i] = umap_grant(p, vir_addr[i]->offset, bytes);
break;
default:
kprintf("virtual_copy: strange type 0x%x\n", type);
return(EINVAL);
}
/* Check if mapping succeeded. */
if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) {
kprintf("virtual_copy EFAULT\n");
return(EFAULT);
}
}
if(vmcheck && procs[_SRC_])
CHECKRANGE_OR_SUSPEND(procs[_SRC_], phys_addr[_SRC_], bytes, 0);
if(vmcheck && procs[_DST_])
CHECKRANGE_OR_SUSPEND(procs[_DST_], phys_addr[_DST_], bytes, 1);
/* Now copy bytes between physical addresseses. */
if(!vm_running || (procs[_SRC_] == NULL && procs[_DST_] == NULL)) {
/* Without vm, address ranges actually are physical. */
phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes);
r = OK;
} else {
/* With vm, addresses need further interpretation. */
r = vm_copy(phys_addr[_SRC_], procs[_SRC_],
phys_addr[_DST_], procs[_DST_], (phys_bytes) bytes);
if(r != OK) {
kprintf("vm_copy: %lx to %lx failed\n",
phys_addr[_SRC_],phys_addr[_DST_]);
}
}
return(r);
}
/*===========================================================================*
* data_copy *
*===========================================================================*/
PUBLIC int data_copy(
endpoint_t from_proc, vir_bytes from_addr,
endpoint_t to_proc, vir_bytes to_addr,
size_t bytes)
{
struct vir_addr src, dst;
src.segment = dst.segment = D;
src.offset = from_addr;
dst.offset = to_addr;
src.proc_nr_e = from_proc;
dst.proc_nr_e = to_proc;
return virtual_copy(&src, &dst, bytes);
}
/*===========================================================================*
* arch_pre_exec *
*===========================================================================*/
PUBLIC int arch_pre_exec(struct proc *pr, u32_t ip, u32_t sp)
{
/* wipe extra LDT entries, set program counter, and stack pointer. */
memset(pr->p_seg.p_ldt + EXTRA_LDT_INDEX, 0,
sizeof(pr->p_seg.p_ldt[0]) * (LDT_SIZE - EXTRA_LDT_INDEX));
pr->p_reg.pc = ip;
pr->p_reg.sp = sp;
}
/*===========================================================================*
* arch_umap *
*===========================================================================*/
PUBLIC int arch_umap(struct proc *pr, vir_bytes offset, vir_bytes count,
int seg, phys_bytes *addr)
{
switch(seg) {
case BIOS_SEG:
*addr = umap_bios(offset, count);
return OK;
}
/* This must be EINVAL; the umap fallback function in
* lib/syslib/alloc_util.c depends on it to detect an
* older kernel (as opposed to mapping error).
*/
return EINVAL;
}

View File

@@ -1,4 +1,4 @@
#
#
! This file, mpx386.s, is included by mpx.s when Minix is compiled for
! 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs.
@@ -58,6 +58,7 @@ begbss:
#include <ibm/interrupt.h>
#include <archconst.h>
#include "../../const.h"
#include "vm.h"
#include "sconst.h"
/* Selected 386 tss offsets. */
@@ -71,6 +72,13 @@ begbss:
.define _restart
.define save
.define _kernel_cr3
.define _pagefault_cr2
.define _pagefault_count
.define errexception
.define exception1
.define exception
.define _divide_error
.define _single_step_exception
@@ -88,6 +96,9 @@ begbss:
.define _general_protection
.define _page_fault
.define _copr_error
.define _params_size
.define _params_offset
.define _mon_ds
.define _hwint00 ! handlers for hardware interrupts
.define _hwint01
@@ -173,6 +184,11 @@ copygdt:
mov ss, ax
mov esp, k_stktop ! set sp to point to the top of kernel stack
! Save boot parameters into these global variables for i386 code
mov (_params_size), edx
mov (_params_offset), ebx
mov (_mon_ds), SS_SELECTOR
! Call C startup code to set up a proper environment to run main().
push edx
push ebx
@@ -216,6 +232,7 @@ csinit:
#define hwint_master(irq) \
call save /* save interrupted process state */;\
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
pop ecx ;\
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
@@ -267,6 +284,7 @@ _hwint07: ! Interrupt routine for irq 7 (printer)
#define hwint_slave(irq) \
call save /* save interrupted process state */;\
push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\
LOADCR3WITHEAX(irq, (_kernel_cr3)) /* switch to kernel page table */;\
call _intr_handle /* intr_handle(irq_handlers[irq]) */;\
pop ecx ;\
cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\
@@ -358,6 +376,7 @@ _p_s_call:
o16 push es
o16 push fs
o16 push gs
mov si, ss ! ss is kernel data segment
mov ds, si ! load rest of kernel segments
mov es, si ! kernel does not use fs, gs
@@ -371,6 +390,9 @@ _p_s_call:
push ebx ! pointer to user message
push eax ! source / destination
push ecx ! call number (ipc primitive to use)
! LOADCR3WITHEAX(0x20, (_kernel_cr3))
call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
! caller is now explicitly in proc_ptr
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
@@ -391,6 +413,7 @@ _restart:
mov (_next_ptr), 0
0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
lldt P_LDT_SEL(esp) ! enable process' segment descriptors
LOADCR3WITHEAX(0x21, P_CR3(esp)) ! switch to process page table
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
mov (_tss+TSS3_S_SP0), eax ! to save state in process table
restart1:
@@ -464,6 +487,11 @@ _general_protection:
_page_fault:
push PAGE_FAULT_VECTOR
push eax
mov eax, cr2
sseg mov (_pagefault_cr2), eax
sseg inc (_pagefault_count)
pop eax
jmp errexception
_copr_error:
@@ -492,12 +520,16 @@ errexception:
sseg pop (trap_errno)
exception1: ! Common for all exceptions.
push eax ! eax is scratch register
mov eax, 0+4(esp) ! old eip
sseg mov (old_eip), eax
movzx eax, 4+4(esp) ! old cs
sseg mov (old_cs), eax
mov eax, 8+4(esp) ! old eflags
sseg mov (old_eflags), eax
LOADCR3WITHEAX(0x24, (_kernel_cr3))
pop eax
call save
push (old_eflags)
@@ -517,6 +549,15 @@ _level0_call:
call save
jmp (_level0_func)
!*===========================================================================*
!* load_kernel_cr3 *
!*===========================================================================*
.align 16
_load_kernel_cr3:
mov eax, (_kernel_cr3)
mov cr3, eax
ret
!*===========================================================================*
!* data *
!*===========================================================================*
@@ -533,3 +574,4 @@ k_stktop: ! top of kernel stack
.comm old_eip, 4
.comm old_cs, 4
.comm old_eflags, 4

View File

@@ -307,7 +307,10 @@ PUBLIC void alloc_segments(register struct proc *rp)
code_bytes = data_bytes; /* common I&D, poor protect */
else
code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
privilege = (iskernelp(rp)) ? TASK_PRIVILEGE : USER_PRIVILEGE;
if( (iskernelp(rp)))
privilege = TASK_PRIVILEGE;
else
privilege = USER_PRIVILEGE;
init_codeseg(&rp->p_seg.p_ldt[CS_LDT_INDEX],
(phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT,
code_bytes, privilege);

View File

@@ -44,10 +44,16 @@ _PROTOTYPE( void trp, (void) );
_PROTOTYPE( void s_call, (void) ), _PROTOTYPE( p_s_call, (void) );
_PROTOTYPE( void level0_call, (void) );
/* memory.c */
_PROTOTYPE( void vir_insb, (u16_t port, struct proc *proc, u32_t vir, size_t count));
_PROTOTYPE( void vir_outsb, (u16_t port, struct proc *proc, u32_t vir, size_t count));
_PROTOTYPE( void vir_insw, (u16_t port, struct proc *proc, u32_t vir, size_t count));
_PROTOTYPE( void vir_outsw, (u16_t port, struct proc *proc, u32_t vir, size_t count));
/* exception.c */
_PROTOTYPE( void exception, (unsigned vec_nr, u32_t trap_errno,
u32_t old_eip, U16_t old_cs, u32_t old_eflags) );
_PROTOTYPE( void stacktrace, (struct proc *proc) );
/* klib386.s */
_PROTOTYPE( void level0, (void (*func)(void)) );
@@ -62,6 +68,7 @@ _PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) );
_PROTOTYPE( void i386_invlpg, (U32_t addr) );
/* protect.c */
_PROTOTYPE( void prot_init, (void) );

View File

@@ -23,5 +23,6 @@ SPREG = PSWREG + W
SSREG = SPREG + W
P_STACKTOP = SSREG + W
P_LDT_SEL = P_STACKTOP
P_LDT = P_LDT_SEL + W
P_CR3 = P_LDT_SEL + W
P_LDT = P_CR3 + W
Msize = 9 ! size of a message in 32-bit words

View File

@@ -3,10 +3,14 @@
#include "../../kernel.h"
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <ibm/cmos.h>
#include <ibm/bios.h>
#include <minix/portio.h>
#include <minix/u64.h>
#include <minix/sysutil.h>
#include <a.out.h>
#include "proto.h"
#include "../../proc.h"
@@ -31,7 +35,39 @@ PUBLIC void arch_shutdown(int how)
* the program if not already done.
*/
if (how != RBT_MONITOR)
phys_copy(vir2phys(""), kinfo.params_base, 1);
arch_set_params("", 1);
if(minix_panicing) {
int source, dest;
static char mybuffer[sizeof(params_buffer)];
char *lead = "echo \\n*** kernel messages:\\n";
int leadlen = strlen(lead);
strcpy(mybuffer, lead);
#define DECSOURCE source = (source - 1 + _KMESS_BUF_SIZE) % _KMESS_BUF_SIZE
dest = sizeof(mybuffer)-1;
mybuffer[dest--] = '\0';
source = kmess.km_next;
DECSOURCE;
while(dest >= leadlen) {
char c = kmess.km_buf[source];
if(c == '\n') {
mybuffer[dest--] = 'n';
mybuffer[dest] = '\\';
} else if(isprint(c) &&
c != '\'' && c != '"' &&
c != '\\' && c != ';') {
mybuffer[dest] = c;
} else mybuffer[dest] = '|';
DECSOURCE;
dest--;
}
arch_set_params(mybuffer, strlen(mybuffer)+1);
}
level0(monitor);
} else {
/* Reset the system by forcing a processor shutdown. First stop
@@ -44,6 +80,17 @@ PUBLIC void arch_shutdown(int how)
}
}
/* address of a.out headers, set in mpx386.s */
phys_bytes aout;
PUBLIC void arch_get_aout_headers(int i, struct exec *h)
{
/* The bootstrap loader created an array of the a.out headers at
* absolute address 'aout'. Get one element to h.
*/
phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR);
}
PUBLIC void system_init(void)
{
prot_init();
@@ -122,7 +169,7 @@ PUBLIC void ser_dump_proc()
pp->p_priority, pp->p_max_priority,
pp->p_user_time, pp->p_sys_time,
pp->p_reg.pc);
stacktrace(pp);
proc_stacktrace(pp);
}
}
@@ -219,3 +266,23 @@ PUBLIC void cons_seth(int pos, int n)
else
cons_setc(pos, 'A'+(n-10));
}
/* Saved by mpx386.s into these variables. */
u32_t params_size, params_offset, mon_ds;
PUBLIC int arch_get_params(char *params, int maxsize)
{
phys_copy(seg2phys(mon_ds) + params_offset, vir2phys(params),
MIN(maxsize, params_size));
params[maxsize-1] = '\0';
return OK;
}
PUBLIC int arch_set_params(char *params, int size)
{
if(size > params_size)
return E2BIG;
phys_copy(vir2phys(params), seg2phys(mon_ds) + params_offset, size);
return OK;
}

27
kernel/arch/i386/vm.h Normal file
View File

@@ -0,0 +1,27 @@
.define _load_kernel_cr3
.define _last_cr3
#define LOADKERNELCR3 ;\
inc (_cr3switch) ;\
mov eax, (_kernel_cr3) ;\
cmp (_last_cr3), eax ;\
jz 9f ;\
push _load_kernel_cr3 ;\
call _level0 ;\
pop eax ;\
mov eax, (_kernel_cr3) ;\
mov (_last_cr3), eax ;\
inc (_cr3reload) ;\
9:
#define LOADCR3WITHEAX(type, newcr3) ;\
sseg inc (_cr3switch) ;\
sseg mov eax, newcr3 ;\
sseg cmp (_last_cr3), eax ;\
jz 8f ;\
mov cr3, eax ;\
sseg inc (_cr3reload) ;\
sseg mov (_last_cr3), eax ;\
8: