diff --git a/kernel/glo.h b/kernel/glo.h index bbc3e8383..e37b7a4d4 100755 --- a/kernel/glo.h +++ b/kernel/glo.h @@ -44,6 +44,12 @@ EXTERN int irq_use; /* map of all in-use irq's */ /* Miscellaneous. */ EXTERN reg_t mon_ss, mon_sp; /* boot monitor stack */ EXTERN int mon_return; /* true if we can return to monitor */ +EXTERN int do_serial_debug; + +/* VM */ +EXTERN phys_bytes vm_base; +EXTERN phys_bytes vm_size; +EXTERN phys_bytes vm_mem_high; /* Variables that are initialized elsewhere are just extern here. */ extern struct boot_image image[]; /* system image processes */ diff --git a/kernel/klib386.s b/kernel/klib386.s index e258e6644..d8c90a11b 100755 --- a/kernel/klib386.s +++ b/kernel/klib386.s @@ -33,6 +33,9 @@ .define _level0 ! call a function at level 0 .define _read_tsc ! read the cycle counter (Pentium and up) .define _read_cpu_flags ! read the cpu flags +.define _read_cr0 ! read cr0 +.define _write_cr0 ! write a value in cr0 +.define _write_cr3 ! write a value in cr3 (root of the page table) ! The routines only guarantee to preserve the registers the C compiler ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and @@ -572,3 +575,41 @@ _read_cpu_flags: popf ret + +!*===========================================================================* +!* read_cr0 * +!*===========================================================================* +! PUBLIC unsigned long read_cr0(void); +_read_cr0: + push ebp + mov ebp, esp + mov eax, cr0 + pop ebp + ret + +!*===========================================================================* +!* write_cr0 * +!*===========================================================================* +! PUBLIC void write_cr0(unsigned long value); +_write_cr0: + push ebp + mov ebp, esp + mov eax, 8(ebp) + mov cr0, eax + jmp 0f ! A jump is required for some flags +0: + pop ebp + ret + +!*===========================================================================* +!* 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 + ret + diff --git a/kernel/proc.h b/kernel/proc.h index 5e4a1f07e..7f6a32780 100755 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -30,6 +30,8 @@ struct proc { struct priv *p_priv; /* system privileges structure */ char p_rts_flags; /* SENDING, RECEIVING, etc. */ + char p_misc_flags; /* Flags that do suspend the process */ + char p_priority; /* current scheduling priority */ char p_max_priority; /* maximum scheduling priority */ char p_ticks_left; /* number of scheduling ticks left */ @@ -66,6 +68,9 @@ struct proc { #define P_STOP 0x40 /* set when process is being traced */ #define NO_PRIV 0x80 /* keep forked system process from running */ +/* Misc flags */ +#define MF_VM 0x01 /* Process uses VM */ + /* Scheduling priorities for p_priority. Values must start at zero (highest * priority) and increment. Priorities of the processes in the boot image * can be set in table.c. IDLE must have a queue for itself, to prevent low diff --git a/kernel/proto.h b/kernel/proto.h index f2530549d..1d69a9519 100755 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -82,6 +82,9 @@ _PROTOTYPE( void reset, (void) ); _PROTOTYPE( void level0, (void (*func)(void)) ); _PROTOTYPE( void monitor, (void) ); _PROTOTYPE( void read_tsc, (unsigned long *high, unsigned long *low) ); +_PROTOTYPE( unsigned long read_cr0, (void) ); +_PROTOTYPE( void write_cr0, (unsigned long value) ); +_PROTOTYPE( void write_cr3, (unsigned long value) ); _PROTOTYPE( unsigned long read_cpu_flags, (void) ); /* mpx*.s */ @@ -142,6 +145,9 @@ _PROTOTYPE( void phys2seg, (u16_t *seg, vir_bytes *off, phys_bytes phys)); _PROTOTYPE( void enable_iop, (struct proc *pp) ); _PROTOTYPE( void alloc_segments, (struct proc *rp) ); +/* system/do_vm.c */ +_PROTOTYPE( void vm_map_default, (struct proc *pp) ); + #endif /* (CHIP == INTEL) */ #if (CHIP == M68000) diff --git a/kernel/system.c b/kernel/system.c index 5019dd94e..59f79b4a0 100755 --- a/kernel/system.c +++ b/kernel/system.c @@ -75,7 +75,8 @@ PUBLIC void sys_task() caller_ptr = proc_addr(m.m_source); /* See if the caller made a valid request and try to handle it. */ - if (! (priv(caller_ptr)->s_call_mask & (1<s_call_mask & (1<= NR_SYS_CALLS) { /* check call number */ @@ -152,6 +153,8 @@ PRIVATE void initialize(void) map(SYS_NEWMAP, do_newmap); /* set up a process memory map */ map(SYS_SEGCTL, do_segctl); /* add segment and get selector */ map(SYS_MEMSET, do_memset); /* write char to memory area */ + map(SYS_VM_SETBUF, do_vm_setbuf); /* PM passes buffer for page tables */ + map(SYS_VM_MAP, do_vm_map); /* Map/unmap physical (device) memory */ /* Copying. */ map(SYS_UMAP, do_umap); /* map virtual to physical address */ @@ -167,6 +170,7 @@ PRIVATE void initialize(void) /* System control. */ map(SYS_ABORT, do_abort); /* abort MINIX */ map(SYS_GETINFO, do_getinfo); /* request system information */ + map(SYS_IOPENABLE, do_iopenable); /* Enable I/O */ } /*===========================================================================* diff --git a/kernel/system.h b/kernel/system.h index 64dcad145..c2a25035d 100644 --- a/kernel/system.h +++ b/kernel/system.h @@ -92,6 +92,9 @@ _PROTOTYPE( int do_memset, (message *m_ptr) ); #define do_memset do_unused #endif +_PROTOTYPE( int do_vm_setbuf, (message *m_ptr) ); +_PROTOTYPE( int do_vm_map, (message *m_ptr) ); + _PROTOTYPE( int do_abort, (message *m_ptr) ); #if ! USE_ABORT #define do_abort do_unused @@ -169,5 +172,7 @@ _PROTOTYPE( int do_setalarm, (message *m_ptr) ); #define do_setalarm do_unused #endif +_PROTOTYPE( int do_iopenable, (message *m_ptr) ); + #endif /* SYSTEM_H */ diff --git a/kernel/system/Makefile b/kernel/system/Makefile index f852ae666..8d18fbefa 100644 --- a/kernel/system/Makefile +++ b/kernel/system/Makefile @@ -44,6 +44,9 @@ OBJECTS = \ $(SYSTEM)(do_sigreturn.o) \ $(SYSTEM)(do_abort.o) \ $(SYSTEM)(do_getinfo.o) \ + $(SYSTEM)(do_iopenable.o) \ + $(SYSTEM)(do_vm.o) \ + $(SYSTEM)(do_vm_setbuf.o) \ $(SYSTEM): $(OBJECTS) aal cr $@ *.o @@ -138,3 +141,13 @@ $(SYSTEM)(do_privctl.o): do_privctl.c $(SYSTEM)(do_segctl.o): do_segctl.c $(CC) do_segctl.c + +$(SYSTEM)(do_iopenable.o): do_iopenable.c + $(CC) do_iopenable.c + +$(SYSTEM)(do_vm.o): do_vm.o +do_vm.o: do_vm.c + $(CC) do_vm.c + +$(SYSTEM)(do_vm_setbuf.o): do_vm_setbuf.c + $(CC) do_vm_setbuf.c diff --git a/kernel/system/do_exit.c b/kernel/system/do_exit.c index c76ecfa9a..982bd6626 100644 --- a/kernel/system/do_exit.c +++ b/kernel/system/do_exit.c @@ -84,6 +84,10 @@ register struct proc *rc; /* slot of process to clean up */ } } + /* Clean up virtual memory */ + if (rc->p_misc_flags & MF_VM) + vm_map_default(rc); + /* Now it is safe to release the process table slot. If this is a system * process, also release its privilege structure. Further cleanup is not * needed at this point. All important fields are reinitialized when the diff --git a/kernel/system/do_iopenable.c b/kernel/system/do_iopenable.c new file mode 100644 index 000000000..71b33caf5 --- /dev/null +++ b/kernel/system/do_iopenable.c @@ -0,0 +1,33 @@ +/* The system call implemented in this file: + * m_type: SYS_IOPENABLE + * + * The parameters for this system call are: + * m2_i2: PROC_NR (process to give I/O Protection Level bits) + * + * Author: + * Jorrit N. Herder + */ + +#include "../kernel.h" +#include "../system.h" + +/*===========================================================================* + * do_iopenable * + *===========================================================================*/ +PUBLIC int do_iopenable(m_ptr) +register message *m_ptr; /* pointer to request message */ +{ + int proc_nr; + +#if 1 /* ENABLE_USERPRIV && ENABLE_USERIOPL */ + proc_nr= m_ptr->PROC_NR; + if (proc_nr == SELF) + proc_nr = m_ptr->m_source; + enable_iop(proc_addr(proc_nr)); + return(OK); +#else + return(EPERM); +#endif +} + + diff --git a/kernel/system/do_vm.c b/kernel/system/do_vm.c new file mode 100644 index 000000000..f1114fae7 --- /dev/null +++ b/kernel/system/do_vm.c @@ -0,0 +1,245 @@ +/* The system call implemented in this file: + * m_type: SYS_VM_MAP + * + * The parameters for this system call are: + * m4_l1: Process that requests map + * m4_l2: Map (TRUE) or unmap (FALSE) + * m4_l3: Base address + * m4_l4: Size + * m4_l5: Memory address + */ +#include "../system.h" + +#include + +PRIVATE int vm_needs_init= 1; +PRIVATE u32_t vm_cr3; + +FORWARD _PROTOTYPE( void vm_init, (void) ); +FORWARD _PROTOTYPE( void phys_put32, (phys_bytes addr, u32_t value) ); +FORWARD _PROTOTYPE( u32_t phys_get32, (phys_bytes addr) ); +FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) ); +FORWARD _PROTOTYPE( void set_cr3, (void) ); +FORWARD _PROTOTYPE( void vm_enable_paging, (void) ); +FORWARD _PROTOTYPE( void map_range, (u32_t base, u32_t size, + u32_t offset) ); + +/*===========================================================================* + * do_vm_setbuf * + *===========================================================================*/ +PUBLIC int do_vm_map(m_ptr) +message *m_ptr; /* pointer to request message */ +{ + int proc_nr, do_map; + phys_bytes base, size, offset, p_phys; + struct proc *pp; + + /* do_serial_debug= 1; */ + + kprintf("in do_vm_map\n"); + + if (vm_needs_init) + { + vm_needs_init= 0; + vm_init(); + } + + proc_nr= m_ptr->m4_l1; + do_map= m_ptr->m4_l2; + base= m_ptr->m4_l3; + size= m_ptr->m4_l4; + offset= m_ptr->m4_l5; + + pp= proc_addr(proc_nr); + p_phys= umap_local(pp, D, base, size); + if (p_phys == 0) + return EFAULT; + kprintf("got 0x%x for 0x%x [D].mem_start = 0x%x\n", + p_phys, base, pp->p_memmap[D].mem_phys); + + if (do_map) + { + kprintf( + "do_vm_map: mapping 0x%x @ 0x%x to 0x%x @ proc %d\n", + size, offset, base, proc_nr); + pp->p_misc_flags |= MF_VM; + + map_range(p_phys, size, offset); + } + else + { + map_range(p_phys, size, p_phys); + } + vm_set_cr3(vm_cr3); + + return OK; +} + +/*===========================================================================* + * vm_map_default * + *===========================================================================*/ +PUBLIC void vm_map_default(pp) +struct proc *pp; +{ + phys_bytes base_clicks, size_clicks; + + if (vm_needs_init) + panic("vm_map_default: VM not initialized?", NO_NUM); + pp->p_misc_flags &= ~MF_VM; + base_clicks= pp->p_memmap[D].mem_phys; + size_clicks= pp->p_memmap[S].mem_phys+pp->p_memmap[S].mem_len - + base_clicks; + map_range(base_clicks << CLICK_SHIFT, size_clicks << CLICK_SHIFT, + base_clicks << CLICK_SHIFT); + vm_set_cr3(vm_cr3); +} + +PRIVATE void vm_init(void) +{ + int o; + phys_bytes p, pt_size; + phys_bytes vm_dir_base, vm_pt_base, phys_mem; + u32_t entry; + unsigned pages; + + kprintf("in vm_init\n"); + +kprintf("%s, %d\n", __FILE__, __LINE__); + if (!vm_size) + panic("vm_init: no space for page tables", NO_NUM); + + /* Align page directory */ + o= (vm_base % PAGE_SIZE); + if (o != 0) + o= PAGE_SIZE-o; + vm_dir_base= vm_base+o; + + /* Page tables start after the page directory */ + vm_pt_base= vm_dir_base+PAGE_SIZE; + + pt_size= (vm_base+vm_size)-vm_pt_base; + pt_size -= (pt_size % PAGE_SIZE); + + /* Compute the number of pages based on vm_mem_high */ + pages= (vm_mem_high-1)/PAGE_SIZE + 1; + + if (pages * I386_VM_PT_ENT_SIZE > pt_size) + panic("vm_init: page table too small", NO_NUM); + +kprintf("%s, %d\n", __FILE__, __LINE__); + + for (p= 0; p*I386_VM_PT_ENT_SIZE < pt_size; p++) + { + phys_mem= p*PAGE_SIZE; + entry= phys_mem | I386_VM_USER | I386_VM_WRITE | + I386_VM_PRESENT; + if (phys_mem >= vm_mem_high) + entry= 0; + phys_put32(vm_pt_base + p*I386_VM_PT_ENT_SIZE, entry); + } + + for (p= 0; p < I386_VM_DIR_ENTRIES; p++) + { + phys_mem= vm_pt_base + p*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); + } + +kprintf("%s, %d\n", __FILE__, __LINE__); + vm_set_cr3(vm_dir_base); + level0(vm_enable_paging); +} + +PRIVATE void phys_put32(addr, value) +phys_bytes addr; +u32_t value; +{ +#if 0 +kprintf("%s, %d: %d bytes from 0x%x to 0x%x\n", __FILE__, __LINE__, + sizeof(value), vir2phys((vir_bytes)&value), addr); +#endif + + phys_copy(vir2phys((vir_bytes)&value), addr, sizeof(value)); +} + +PRIVATE u32_t phys_get32(addr) +phys_bytes addr; +{ + u32_t value; + + phys_copy(addr, vir2phys((vir_bytes)&value), sizeof(value)); + + return value; +} + +PRIVATE void vm_set_cr3(value) +u32_t value; +{ +kprintf("%s, %d\n", __FILE__, __LINE__); + vm_cr3= value; +kprintf("%s, %d\n", __FILE__, __LINE__); + level0(set_cr3); +kprintf("%s, %d\n", __FILE__, __LINE__); +} + +PRIVATE void set_cr3() +{ + write_cr3(vm_cr3); +} + +PRIVATE void vm_enable_paging(void) +{ + u32_t cr0; + + cr0= read_cr0(); + write_cr0(cr0 | I386_CR0_PG); +} + +PRIVATE void 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; + kprintf("got address 0x%x for page table 0x%x\n", + curr_pt_addr, curr_pt); + } + entry= offset | I386_VM_USER | I386_VM_WRITE | + I386_VM_PRESENT; +#if 0 + kprintf( + "putting 0x%x at dir_ent 0x%x, pt_ent 0x%x (addr 0x%x)\n", + entry, dir_ent, pt_ent, + curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE); +#endif + phys_put32(curr_pt_addr + pt_ent * I386_VM_PT_ENT_SIZE, entry); + offset += PAGE_SIZE; + base += PAGE_SIZE; + size -= PAGE_SIZE; + } +} diff --git a/kernel/system/do_vm_setbuf.c b/kernel/system/do_vm_setbuf.c new file mode 100644 index 000000000..75c9af71f --- /dev/null +++ b/kernel/system/do_vm_setbuf.c @@ -0,0 +1,25 @@ +/* The system call implemented in this file: + * m_type: SYS_VM_SETBUF + * + * The parameters for this system call are: + * m4_l1: Start of the buffer + * m4_l2: Length of the buffer + * m4_l3: End of main memory + */ +#include "../system.h" + +/*===========================================================================* + * do_vm_setbuf * + *===========================================================================*/ +PUBLIC int do_vm_setbuf(m_ptr) +message *m_ptr; /* pointer to request message */ +{ + vm_base= m_ptr->m4_l1; + vm_size= m_ptr->m4_l2; + vm_mem_high= m_ptr->m4_l3; + + kprintf("do_vm_setbuf: got 0x%x @ 0x%x for 0x%x\n", + vm_size, vm_base, vm_mem_high); + + return OK; +} diff --git a/kernel/table.c b/kernel/table.c index 0f55f32b2..9c9687af7 100755 --- a/kernel/table.c +++ b/kernel/table.c @@ -66,9 +66,9 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)]; * structure 0 is shared by user processes. */ #define s(n) (1 << s_nr_to_id(n)) -#define SRV_M (~0) -#define SYS_M (~0) -#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR)) +#define SRV_M (~0) +#define SYS_M (~0) +#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR) | s(SYSTEM)) #define DRV_M (USR_M | s(SYSTEM) | s(CLOCK) | s(LOG_PROC_NR) | s(TTY_PROC_NR)) /* Define kernel calls that processes are allowed to make. This is not looking @@ -84,7 +84,7 @@ PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)]; | c(SYS_GETINFO) | c(SYS_EXIT) | c(SYS_TIMES) | c(SYS_SETALARM)) #define DRV_C (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) \ | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO)) -#define MEM_C (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY)) +#define MEM_C (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY) | c(SYS_VM_MAP)) /* The system image table lists all programs that are part of the boot image. * The order of the entries here MUST agree with the order of the programs diff --git a/kernel/utility.c b/kernel/utility.c index fe7ee3607..47fcbb460 100755 --- a/kernel/utility.c +++ b/kernel/utility.c @@ -23,6 +23,7 @@ #define END_OF_KMESS -1 FORWARD _PROTOTYPE(void kputc, (int c)); +FORWARD _PROTOTYPE( void ser_putc, (char c)); /*===========================================================================* * panic * @@ -130,6 +131,8 @@ int c; /* character to append */ * the to output driver if an END_OF_KMESS is encountered. */ if (c != END_OF_KMESS) { + if (do_serial_debug) + ser_putc(c); kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */ if (kmess.km_size < KMESS_BUF_SIZE) kmess.km_size += 1; @@ -139,3 +142,24 @@ int c; /* character to append */ } } +#define COM1_BASE 0x3F8 +#define COM1_THR (COM1_BASE + 0) +#define LSR_THRE 0x20 +#define COM1_LSR (COM1_BASE + 5) + +PRIVATE void ser_putc(char c) +{ + int i; + int lsr, thr; + + return; + + lsr= COM1_LSR; + thr= COM1_THR; + for (i= 0; i<100000; i++) + { + if (inb(lsr) & LSR_THRE) + break; + } + outb(thr, c); +}