intr ipcrm ipcs irdpd isoread join kill last \
less loadkeys loadramdisk logger look lp \
lpd ls lspci mail MAKEDEV \
- mdb mesg mined mkfifo mknod \
+ mesg mined mkfifo mknod \
mkproto mount mt netconf nice acknm nohup \
nonamed od paste patch pax \
ping postinstall poweroff pr prep printf printroot \
*===========================================================================*/
static void complete_bars(void)
{
- int i, j, r, bar_nr, reg;
+ int i, j, bar_nr, reg;
u32_t memgap_low, memgap_high, iogap_low, iogap_high, io_high,
base, size, v32, diff1, diff2;
- char *cp, *next;
- char memstr[256];
+ kinfo_t kinfo;
- r= env_get_param("memory", memstr, sizeof(memstr));
- if (r != OK)
- panic("env_get_param failed: %d", r);
-
- /* Set memgap_low to just above physical memory */
- memgap_low= 0;
- cp= memstr;
- while (*cp != '\0')
- {
- base= strtoul(cp, &next, 16);
- if (!(*next) || next == cp || *next != ':')
- goto bad_mem_string;
- cp= next+1;
- size= strtoul(cp, &next, 16);
- if (next == cp || (*next != ',' && *next != '\0'))
- if (!*next)
- goto bad_mem_string;
- if (base+size > memgap_low)
- memgap_low= base+size;
-
- if (*next)
- cp= next+1;
- else
- break;
- }
+ if(OK != sys_getkinfo(&kinfo))
+ panic("can't get kinfo");
+ /* Set memgap_low to just above physical memory */
+ memgap_low= kinfo.mem_high_phys;
memgap_high= 0xfe000000; /* Leave space for the CPU (APIC) */
if (debug)
}
}
return;
-
-bad_mem_string:
- printf("PCI: bad memory environment string '%s'\n", memstr);
- panic(NULL);
}
/*===========================================================================*
if(font_memory == MAP_FAILED)
panic("Console couldn't map font memory");
-
vid_size >>= 1; /* word count */
vid_mask = vid_size - 1;
if (nr_cons > NR_CONS) nr_cons = NR_CONS;
if (nr_cons > 1) wrap = 0;
+ if (nr_cons < 1) panic("no consoles");
page_size = vid_size / nr_cons;
}
u8_t access; /* |P|DL|1|X|E|R|A| */
u8_t granularity; /* |G|X|0|A|LIMT| */
u8_t base_high;
-};
+} __attribute__((packed));
-#define LDT_SIZE 2 /* CS and DS */
-
-/* Fixed local descriptors. */
-#define CS_LDT_INDEX 0 /* process CS */
-#define DS_LDT_INDEX 1 /* process DS=ES=FS=GS=SS */
+struct desctableptr_s {
+ u16_t limit;
+ u32_t base;
+} __attribute__((packed));
typedef struct segframe {
- reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
reg_t p_cr3; /* page table root */
u32_t *p_cr3_v;
char *fpu_state;
- struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */
} segframe_t;
-#define INMEMORY(p) (!p->p_seg.p_cr3 || get_cpulocal_var(ptproc) == p)
-
typedef u32_t atomic_t; /* access to an aligned 32bit value is atomic on i386 */
#endif /* #ifndef _I386_TYPES_H */
/* Magic numbers for interrupt controller. */
#define END_OF_INT 0x20 /* code used to re-enable after an interrupt */
+#define IRQ0_VECTOR 0x50 /* nice vectors to relocate IRQ0-7 to */
+#define IRQ8_VECTOR 0x70 /* no need to move IRQ8-15 */
+
/* Interrupt vectors defined/reserved by processor. */
#define DIVIDE_VECTOR 0 /* divide error */
#define DEBUG_VECTOR 1 /* single step (trace) */
#define KERN_CALL_VECTOR 32 /* system calls are made with int SYSVEC */
#define IPC_VECTOR 33 /* interrupt vector for ipc */
-/* Suitable irq bases for hardware interrupts. Reprogram the 8259(s) from
- * the PC BIOS defaults since the BIOS doesn't respect all the processor's
- * reserved vectors (0 to 31).
- */
-#define BIOS_IRQ0_VEC 0x08 /* base of IRQ0-7 vectors used by BIOS */
-#define BIOS_IRQ8_VEC 0x70 /* base of IRQ8-15 vectors used by BIOS */
-#define IRQ0_VECTOR 0x50 /* nice vectors to relocate IRQ0-7 to */
-#define IRQ8_VECTOR 0x70 /* no need to move IRQ8-15 */
-
/* Hardware interrupt numbers. */
#ifndef USE_APIC
#define NR_IRQ_VECTORS 16
#define AT_WINI_0_IRQ 14 /* at winchester controller 0 */
#define AT_WINI_1_IRQ 15 /* at winchester controller 1 */
-/* Interrupt number to hardware vector. */
-#define BIOS_VECTOR(irq) \
- (((irq) < 8 ? BIOS_IRQ0_VEC : BIOS_IRQ8_VEC) + ((irq) & 0x07))
-#define VECTOR(irq) \
- (((irq) < 8 ? IRQ0_VECTOR : IRQ8_VECTOR) + ((irq) & 0x07))
+#define VECTOR(irq) \
+ (((irq) < 8 ? IRQ0_VECTOR : IRQ8_VECTOR) + ((irq) & 0x07))
#endif /* (CHIP == INTEL) */
#define MULTIBOOT_AOUT_KLUDGE 0x00010000
-#define MULTIBOOT_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
-
/* consts used for Multiboot pre-init */
#define MULTIBOOT_VIDEO_MODE_EGA 1
#define MULTIBOOT_CONSOLE_LINES 25
#define MULTIBOOT_CONSOLE_COLS 80
+#define MULTIBOOT_VIDEO_BUFFER_BYTES \
+ (MULTIBOOT_CONSOLE_LINES*MULTIBOOT_CONSOLE_COLS*2)
#define MULTIBOOT_STACK_SIZE 4096
#define MULTIBOOT_PARAM_BUF_SIZE 1024
+#define MULTIBOOT_MAX_MODS 20
+
/* Flags to be set in the ’flags’ member of the multiboot info structure. */
#define MULTIBOOT_INFO_MEMORY 0x00000001
+#define MULTIBOOT_INFO_MEM_MAP 0x00000040
/* Is there a boot device set? */
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
/* Are there modules to do something with? */
#define MULTIBOOT_INFO_MODS 0x00000008
+#define MULTIBOOT_HIGH_MEM_BASE 0x100000
+
#ifndef __ASSEMBLY__
#include <minix/types.h>
/* Multiboot info version number */
u32_t flags;
/* Available memory from BIOS */
- u32_t mem_lower;
- u32_t mem_upper;
+ u32_t mem_lower_unused; /* minix uses memmap instead */
+ u32_t mem_upper_unused;
/* "root" partition */
u32_t boot_device;
/* Kernel command line */
};
typedef struct multiboot_mod_list multiboot_module_t;
-/* Buffer for multiboot parameters */
-extern char multiboot_param_buf[];
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+struct multiboot_mmap_entry
+{
+ u32_t size;
+ u64_t addr;
+ u64_t len;
+#define MULTIBOOT_MEMORY_AVAILABLE 1
+#define MULTIBOOT_MEMORY_RESERVED 2
+ u32_t type;
+} __attribute__((packed));
+typedef struct multiboot_mmap_entry multiboot_memory_map_t;
#endif /* __ASSEMBLY__ */
#endif /* __MULTIBOOT_H__ */
#define PAGE_SIZE (1 << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
-/* As visible from the user space process, where is the top of the
- * stack (first non-stack byte), when in paged mode?
- */
-#define VM_STACKTOP 0x80000000
-
#endif /* _I386_VMPARAM_H_ */
#define ROOT_SYS_PROC_NR RS_PROC_NR
#define ROOT_USR_PROC_NR INIT_PROC_NR
-/* Number of processes contained in the system image. */
-#define NR_BOOT_PROCS (NR_TASKS + LAST_SPECIAL_PROC_NR + 1)
-
/*===========================================================================*
* Kernel notification types *
*===========================================================================*/
# define SYS_SIGSEND (KERNEL_CALL + 9) /* sys_sigsend() */
# define SYS_SIGRETURN (KERNEL_CALL + 10) /* sys_sigreturn() */
-# define SYS_NEWMAP (KERNEL_CALL + 11) /* sys_newmap() */
# define SYS_MEMSET (KERNEL_CALL + 13) /* sys_memset() */
# define SYS_UMAP (KERNEL_CALL + 14) /* sys_umap() */
#define SIG_MAP m2_l1 /* used by kernel to pass signal bit map */
#define SIG_CTXT_PTR m2_p1 /* pointer to info to restore signal context */
-/* Field names for SYS_FORK, _EXEC, _EXIT, _NEWMAP, GETMCONTEXT, SETMCONTEXT.*/
+/* Field names for SYS_FORK, _EXEC, _EXIT, GETMCONTEXT, SETMCONTEXT.*/
#define PR_ENDPT m1_i1 /* indicates a process */
#define PR_PRIORITY m1_i2 /* process priority */
#define PR_SLOT m1_i2 /* indicates a process slot */
#define PR_STACK_PTR m1_p1 /* used for stack ptr in sys_exec, sys_getsp */
#define PR_NAME_PTR m1_p2 /* tells where program name is for dmp */
#define PR_IP_PTR m1_p3 /* initial value for ip after exec */
-#define PR_MEM_PTR m1_p1 /* tells where memory map is for sys_newmap
- * and sys_fork
- */
#define PR_FORK_FLAGS m1_i3 /* optional flags for fork operation */
#define PR_FORK_MSGADDR m1_p1 /* reply message address of forked child */
#define PR_CTX_PTR m1_p1 /* pointer to mcontext_t structure */
#define VMCTL_I386_GETCR3 13
#define VMCTL_MEMREQ_GET 14
#define VMCTL_MEMREQ_REPLY 15
-#define VMCTL_INCSP 16
#define VMCTL_NOPAGEZERO 18
#define VMCTL_I386_KERNELLIMIT 19
-#define VMCTL_I386_FREEPDE 23
-#define VMCTL_ENABLE_PAGING 24
#define VMCTL_I386_INVLPG 25
#define VMCTL_FLUSHTLB 26
#define VMCTL_KERN_PHYSMAP 27
#define VMCTL_SETADDRSPACE 29
#define VMCTL_VMINHIBIT_SET 30
#define VMCTL_VMINHIBIT_CLEAR 31
+#define VMCTL_CLEARMAPCACHE 32
/* Codes and field names for SYS_SYSCTL. */
#define SYSCTL_CODE m1_i1 /* SYSCTL_CODE_* below */
/* Parameters for the EXEC_NEWMEM call */
#define EXC_NM_PROC m1_i1 /* process that needs new map */
-#define EXC_NM_PTR m1_p1 /* parameters in struct exec_newmem */
+#define EXC_NM_PTR m1_p1 /* parameters in struct exec_info */
/* Results:
* the status will be in m_type.
* the top of the stack will be in m1_i1.
#define SEGMENT_TYPE 0xFF00 /* bit mask to get segment type */
#define SEGMENT_INDEX 0x00FF /* bit mask to get segment index */
-#define LOCAL_SEG 0x0000 /* flags indicating local memory segment */
-#define NR_LOCAL_SEGS 3 /* # local segments per process (fixed) */
-#define T 0 /* proc[i].mem_map[T] is for text */
-#define D 1 /* proc[i].mem_map[D] is for data */
-#define S 2 /* proc[i].mem_map[S] is for stack */
+#define D_OBSOLETE 1 /* proc[i].mem_map[D] is for data */
#define PHYS_SEG 0x0400 /* flag indicating entire physical memory */
#define LOCAL_VM_SEG 0x1000 /* same as LOCAL_SEG, but with vm lookup */
-#define VM_D (LOCAL_VM_SEG | D)
-#define VM_T (LOCAL_VM_SEG | T)
#define MEM_GRANT 3
+#define VIR_ADDR 1
+#define VM_D (LOCAL_VM_SEG | VIR_ADDR)
#define VM_GRANT (LOCAL_VM_SEG | MEM_GRANT)
/* Labels used to disable code sections for different reasons. */
#define FUTURE_CODE 0 /* new code to be activated + tested later */
#define TEMP_CODE 1 /* active code to be removed later */
+/* Number of processes contained in the system image. */
+#define NR_BOOT_PROCS (NR_TASKS + LAST_SPECIAL_PROC_NR + 1)
+
/* Process name length in the PM process table, including '\0'. */
#define PROC_NAME_LEN 16
#define SERVARNAME "cttyline"
#define SERBAUDVARNAME "cttybaud"
-/* Bits for the system property flags in boot image processes. */
-#define PROC_FULLVM 0x100 /* VM sets and manages full pagetable */
-
/* Bits for s_flags in the privilege structure. */
#define PREEMPTIBLE 0x002 /* kernel tasks are not preemptible */
#define BILLABLE 0x004 /* some processes are not billable */
struct sprof_proc {
endpoint_t proc;
- char name[8];
+ char name[PROC_NAME_LEN];
};
#include <minix/types.h>
int sys_enable_iop(endpoint_t proc_ep);
int sys_exec(endpoint_t proc_ep, char *ptr, char *aout, vir_bytes
initpc);
-int sys_fork(endpoint_t parent, endpoint_t child, endpoint_t *, struct
- mem_map *ptr, u32_t vm, vir_bytes *);
-int sys_newmap(endpoint_t proc_ep, struct mem_map *ptr);
+int sys_fork(endpoint_t parent, endpoint_t child, endpoint_t *,
+ u32_t vm, vir_bytes *);
int sys_clear(endpoint_t proc_ep);
int sys_exit(void);
int sys_trace(int req, endpoint_t proc_ep, long addr, long *data_p);
#ifndef _TYPE_H
#define _TYPE_H
+#include <machine/multiboot.h>
#ifndef _MINIX_SYS_CONFIG_H
#include <minix/sys_config.h>
#include <minix/types.h>
#endif
+#include <minix/const.h>
+#include <minix/com.h>
+
#include <stdint.h>
/* Type definitions. */
typedef unsigned long phys_bytes; /* physical addr/length in bytes */
typedef unsigned int phys_clicks; /* physical addr/length in clicks */
typedef int endpoint_t; /* process identifier */
-
typedef int32_t cp_grant_id_t; /* A grant ID. */
-
-#if (_MINIX_CHIP == _CHIP_INTEL)
typedef long unsigned int vir_bytes; /* virtual addresses/lengths in bytes */
-#endif
-
-#if (_MINIX_CHIP == _CHIP_M68000)
-typedef unsigned long vir_bytes;/* virtual addresses and lengths in bytes */
-#endif
-
-#if (_MINIX_CHIP == _CHIP_SPARC)
-typedef unsigned long vir_bytes;/* virtual addresses and lengths in bytes */
-#endif
-
-/* Memory map for local text, stack, data segments. */
-struct mem_map {
- vir_clicks mem_vir; /* virtual address */
- phys_clicks mem_phys; /* physical address */
- vir_clicks mem_len; /* length */
-};
-
-/* Memory map for remote memory areas, e.g., for the RAM disk. */
-struct far_mem {
- int in_use; /* entry in use, unless zero */
- phys_clicks mem_phys; /* physical address */
- vir_clicks mem_len; /* length */
-};
/* Structure for virtual copying by means of a vector with requests. */
struct vir_addr {
- endpoint_t proc_nr_e;
- int segment;
+ endpoint_t proc_nr_e; /* NONE for phys, otherwise process endpoint */
vir_bytes offset;
};
vir_bytes sm_stkptr; /* user stack pointer */
};
-/* This is used to obtain system information through SYS_GETINFO. */
-struct kinfo {
- phys_bytes code_base; /* base of kernel code */
- phys_bytes code_size;
- phys_bytes data_base; /* base of kernel data */
- phys_bytes data_size;
- vir_bytes proc_addr; /* virtual address of process table */
- phys_bytes _kmem_base; /* kernel memory layout (/dev/kmem) */
- phys_bytes _kmem_size;
- phys_bytes bootdev_base; /* boot device from boot image (/dev/boot) */
- phys_bytes bootdev_size;
- phys_bytes ramdev_base; /* boot device from boot image (/dev/boot) */
- phys_bytes ramdev_size;
- phys_bytes _params_base; /* parameters passed by boot monitor */
- phys_bytes _params_size;
- int nr_procs; /* number of user processes */
- int nr_tasks; /* number of kernel tasks */
- char release[6]; /* kernel release number */
- char version[6]; /* kernel version number */
-};
-
/* Load data accounted every this no. of seconds. */
#define _LOAD_UNIT_SECS 6 /* Changing this breaks ABI. */
phys_bytes mr_limit; /* Highest memory address in range */
};
+/* List of boot-time processes set in kernel/table.c. */
+struct boot_image {
+ int proc_nr; /* process number to use */
+ char proc_name[PROC_NAME_LEN]; /* name in process table */
+ endpoint_t endpoint; /* endpoint number when started */
+ phys_bytes start_addr; /* Where it's in memory */
+ phys_bytes len;
+};
+
/* Memory chunks. */
struct memory {
phys_bytes base;
phys_bytes size;
};
+/* This is used to obtain system information through SYS_GETINFO. */
+#define MAXMEMMAP 40
+typedef struct kinfo {
+ /* Straight multiboot-provided info */
+ multiboot_info_t mbi;
+ multiboot_module_t module_list[MULTIBOOT_MAX_MODS];
+ multiboot_memory_map_t memmap[MAXMEMMAP]; /* free mem list */
+ phys_bytes mem_high_phys;
+ int mmap_size;
+
+ /* Multiboot-derived */
+ int mods_with_kernel; /* no. of mods incl kernel */
+ int kern_mod; /* which one is kernel */
+
+ /* Minix stuff, started at bootstrap phase */
+ int freepde_start; /* lowest pde unused kernel pde */
+ char param_buf[MULTIBOOT_PARAM_BUF_SIZE];
+
+ /* Minix stuff */
+ struct kmessages *kmess;
+ int do_serial_debug; /* system serial output */
+ int serial_debug_baud; /* serial baud rate */
+ int minix_panicing; /* are we panicing? */
+ vir_bytes user_sp; /* where does kernel want stack set */
+ vir_bytes user_end; /* upper proc limit */
+ vir_bytes vir_kern_start; /* kernel addrspace starts */
+ vir_bytes bootstrap_start, bootstrap_len;
+ struct boot_image boot_procs[NR_BOOT_PROCS];
+ int nr_procs; /* number of user processes */
+ int nr_tasks; /* number of kernel tasks */
+ char release[6]; /* kernel release number */
+ char version[6]; /* kernel version number */
+} kinfo_t;
+
#define STATICINIT(v, n) \
if(!(v)) { \
if(!((v) = alloc_contig(sizeof(*(v)) * (n), 0, NULL))) { \
int km_next; /* next index to write */
int km_size; /* current size in buffer */
char km_buf[_KMESS_BUF_SIZE]; /* buffer for messages */
+ char kmess_buf[80*25]; /* printable copy of message buffer */
+ int blpos; /* kmess_buf position */
};
#include <minix/config.h>
};
struct vm_region_info {
- int vri_seg; /* segment of virtual region (T or D) */
vir_bytes vri_addr; /* base address of region */
vir_bytes vri_length; /* length of region */
int vri_prot; /* protection flags (PROT_) */
.include "arch/${MACHINE_ARCH}/Makefile.inc"
-SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c start.c system.c \
+SRCS+= clock.c cpulocals.c interrupt.c main.c proc.c system.c \
table.c utility.c
-DPADD+= ${LIBTIMERS} ${LIBSYS} ${LIBEXEC}
+LINKERSCRIPT=${.CURDIR}/arch/${ARCH}/kernel.lds
+
+DPADD+= ${LIBTIMERS} ${LIBSYS} ${LIBEXEC} $(LINKERSCRIPT)
LDADD+= -ltimers -lsys -lexec
-CFLAGS += -D__kernel__
+CFLAGS += -D__kernel__
CPPFLAGS+= -fno-stack-protector -D_NETBSD_SOURCE
-LDFLAGS+= -T ${.CURDIR}/arch/${MACHINE_ARCH}/kernel.lds
+LDFLAGS+= -T $(LINKERSCRIPT)
LDFLAGS+= -nostdlib -L${DESTDIR}/${LIBDIR}
LDADD+= -lminlib
DPADD+= ${LIBMINLIB}
clean:
rm -f extracted-errno.h extracted-mfield.h extracted-mtype.h
+
+
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
+
+# objects we want unpaged from -lminlib, -lminc
+MINLIB_OBJS_UNPAGED=_cpufeature.o _cpuid.o get_bp.o
+MINC_OBJS_UNPAGED=strcat.o strlen.o memcpy.o strcpy.o strncmp.o memset.o \
+ memmove.o strcmp.o atoi.o ctype_.o _stdfile.o strtol.o _errno.o errno.o
+SYS_OBJS_UNPAGED=kprintf.o vprintf.o assert.o stacktrace.o
+
+# some object files we give a symbol prefix (or namespace) of __k_unpaged_
+# that must live in their own unique namespace.
+#
+.for UNPAGED_OBJ in head.o pre_init.o direct_tty_utils.o io_outb.o \
+ io_inb.o pg_utils.o klib.o utility.o arch_reset.o \
+ $(MINLIB_OBJS_UNPAGED) $(MINC_OBJS_UNPAGED) $(SYS_OBJS_UNPAGED)
+unpaged_${UNPAGED_OBJ}: ${UNPAGED_OBJ}
+ objcopy --prefix-symbols=__k_unpaged_ ${UNPAGED_OBJ} unpaged_${UNPAGED_OBJ}
+UNPAGED_OBJS += unpaged_${UNPAGED_OBJ}
+.endfor
+
+# we have to extract some object files from libminc.a and libminlib.a
+$(MINLIB_OBJS_UNPAGED) $(MINC_OBJS_UNPAGED) $(SYS_OBJS_UNPAGED): $(LIBMINLIB) $(LIBMINC) $(LIBSYS)
+ ar x $(LIBMINLIB) $(MINLIB_OBJS_UNPAGED)
+ ar x $(LIBMINC) $(MINC_OBJS_UNPAGED)
+ ar x $(LIBSYS) $(SYS_OBJS_UNPAGED)
+
SRCS+= mpx.S arch_clock.c arch_do_vmctl.c arch_system.c \
do_iopenable.c do_readbios.c do_sdevio.c exception.c i8259.c io_inb.S \
- io_inl.S io_intr.S io_inw.S io_outb.S io_outl.S io_outw.S klib.S klib16.S memory.c multiboot.S \
- oxpcie.c pre_init.c protect.c
+ io_inl.S io_intr.S io_inw.S io_outb.S io_outl.S io_outw.S klib.S klib16.S memory.c \
+ oxpcie.c protect.c direct_tty_utils.c arch_reset.c \
+ pg_utils.c
+
+OBJS.kernel+= ${UNPAGED_OBJS}
.if ${USE_ACPI} != "no"
SRCS+= acpi.c
CPPFLAGS+= -DUSE_WATCHDOG
.endif
-apic_asm.d klib.d mpx.d: procoffsets.h
+apic_asm.d klib.d mpx.d head.d: procoffsets.h
# It's OK to hardcode the arch as i386 here as this and procoffsets.cf
# are i386-specific.
apic_idt_init(TRUE); /* reset */
idt_reload();
-
- intr_init(INTS_ORIG, 0); /* no auto eoi */
}
static void ioapic_disable_irq(unsigned irq)
* update it
*/
addr = (msr_lo >> 12) | ((msr_hi & 0xf) << 20);
- if (phys2vir(addr) != (lapic_addr >> 12)) {
+ if (addr != (lapic_addr >> 12)) {
if (msr_hi & 0xf) {
printf("ERROR : APIC address needs more then 32 bits\n");
return 0;
}
- lapic_addr = phys2vir(msr_lo & ~((1 << 12) - 1));
+ lapic_addr = msr_lo & ~((1 << 12) - 1);
}
#endif
handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
for(; handler < &lapic_intr_dummy_handles_end;
handler += LAPIC_INTR_DUMMY_HANDLER_SIZE) {
- int_gate(vect++, (vir_bytes) handler,
+ int_gate_idt(vect++, (vir_bytes) handler,
PRESENT | INT_GATE_TYPE |
(INTR_PRIVILEGE << DPL_SHIFT));
}
/* Set up idt tables for smp mode.
*/
- int is_bsp = is_boot_apic(apicid());
+ int is_bsp;
if (reset) {
- idt_copy_vectors(gate_table_pic);
+ idt_copy_vectors_pic();
idt_copy_vectors(gate_table_common);
return;
}
+ is_bsp = is_boot_apic(apicid());
+
#ifdef APIC_DEBUG
if (is_bsp)
printf("APIC debugging is enabled\n");
if (ioapic_enabled)
idt_copy_vectors(gate_table_ioapic);
else
- idt_copy_vectors(gate_table_pic);
+ idt_copy_vectors_pic();
idt_copy_vectors(gate_table_common);
if (is_bsp) {
BOOT_VERBOSE(printf("Initiating APIC timer handler\n"));
/* register the timer interrupt handler for this CPU */
- int_gate(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler,
+ int_gate_idt(APIC_TIMER_INT_VECTOR, (vir_bytes) lapic_timer_int_handler,
PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
}
break;
ioa[n].id = acpi_ioa->id;
- ioa[n].addr = phys2vir(acpi_ioa->address);
+ ioa[n].addr = acpi_ioa->address;
ioa[n].paddr = (phys_bytes) acpi_ioa->address;
ioa[n].gsi_base = acpi_ioa->global_int_base;
ioa[n].pins = ((ioapic_read(ioa[n].addr,
{
int status;
- if (machine.acpi_rsdp)
+ if (machine.acpi_rsdp) {
status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
- else
+ } else {
status = 0;
+ }
if (!status) {
/* try something different like MPS */
}
+
return status;
}
if (!cpu_feature_apic_on_chip())
return 0;
- lapic_addr = phys2vir(LOCAL_APIC_DEF_ADDR);
+ lapic_addr = LOCAL_APIC_DEF_ADDR;
ioapic_enabled = 0;
if (!lapic_enable(0)) {
* master and slave. */
outb(0x22, 0x70);
outb(0x23, 0x00);
-
- intr_init(INTS_ORIG, 0); /* no auto eoi */
}
static void irq_lapic_status(int irq)
*/
#include "kernel/system.h"
+#include <assert.h>
#include <minix/type.h>
#include "arch_proto.h"
+extern phys_bytes video_mem_vaddr;
+
+extern char *video_mem;
+
+static void setcr3(struct proc *p, u32_t cr3, u32_t *v)
+{
+ /* Set process CR3. */
+ p->p_seg.p_cr3 = cr3;
+ assert(p->p_seg.p_cr3);
+ p->p_seg.p_cr3_v = v;
+ if(p == get_cpulocal_var(ptproc)) {
+ write_cr3(p->p_seg.p_cr3);
+ }
+ if(p->p_nr == VM_PROC_NR) {
+ if (arch_enable_paging(p) != OK)
+ panic("arch_enable_paging failed");
+ }
+ RTS_UNSET(p, RTS_VMINHIBIT);
+}
+
/*===========================================================================*
* arch_do_vmctl *
*===========================================================================*/
m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3;
return OK;
case VMCTL_SETADDRSPACE:
- /* Set process CR3. */
- if(m_ptr->SVMCTL_PTROOT) {
- p->p_seg.p_cr3 = m_ptr->SVMCTL_PTROOT;
- p->p_seg.p_cr3_v = (u32_t *) m_ptr->SVMCTL_PTROOT_V;
- p->p_misc_flags |= MF_FULLVM;
- if(p == get_cpulocal_var(ptproc)) {
- write_cr3(p->p_seg.p_cr3);
- }
- } else {
- p->p_seg.p_cr3 = 0;
- p->p_seg.p_cr3_v = NULL;
- p->p_misc_flags &= ~MF_FULLVM;
- }
- RTS_UNSET(p, RTS_VMINHIBIT);
+ setcr3(p, m_ptr->SVMCTL_PTROOT, (u32_t *) m_ptr->SVMCTL_PTROOT_V);
return OK;
- case VMCTL_INCSP:
- /* Increase process SP. */
- p->p_reg.sp += m_ptr->SVMCTL_VALUE;
- return OK;
- case VMCTL_I386_KERNELLIMIT:
- {
- int r;
- /* VM wants kernel to increase its segment. */
- r = prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
- return r;
- }
- case VMCTL_I386_FREEPDE:
- {
- i386_freepde(m_ptr->SVMCTL_VALUE);
- return OK;
- }
case VMCTL_FLUSHTLB:
{
reload_cr3();
i386_invlpg(m_ptr->SVMCTL_VALUE);
return OK;
}
-
}
--- /dev/null
+
+#include "kernel/kernel.h"
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <machine/cmos.h>
+#include <machine/bios.h>
+#include <machine/cpu.h>
+#include <minix/portio.h>
+#include <minix/cpufeature.h>
+#include <assert.h>
+#include <signal.h>
+#include <machine/vm.h>
+
+#include <minix/u64.h>
+
+#include "archconst.h"
+#include "arch_proto.h"
+#include "serial.h"
+#include "oxpcie.h"
+#include "kernel/proc.h"
+#include "kernel/debug.h"
+#include "direct_utils.h"
+#include <machine/multiboot.h>
+
+#define KBCMDP 4 /* kbd controller port (O) */
+#define KBC_PULSE0 0xfe /* pulse output bit 0 */
+#define IO_KBD 0x060 /* 8042 Keyboard */
+
+int cpu_has_tsc;
+
+void
+reset(void)
+{
+ uint8_t b;
+ /*
+ * The keyboard controller has 4 random output pins, one of which is
+ * connected to the RESET pin on the CPU in many PCs. We tell the
+ * keyboard controller to pulse this line a couple of times.
+ */
+ outb(IO_KBD + KBCMDP, KBC_PULSE0);
+ busy_delay_ms(100);
+ outb(IO_KBD + KBCMDP, KBC_PULSE0);
+ busy_delay_ms(100);
+
+ /*
+ * Attempt to force a reset via the Reset Control register at
+ * I/O port 0xcf9. Bit 2 forces a system reset when it
+ * transitions from 0 to 1. Bit 1 selects the type of reset
+ * to attempt: 0 selects a "soft" reset, and 1 selects a
+ * "hard" reset. We try a "hard" reset. The first write sets
+ * bit 1 to select a "hard" reset and clears bit 2. The
+ * second write forces a 0 -> 1 transition in bit 2 to trigger
+ * a reset.
+ */
+ outb(0xcf9, 0x2);
+ outb(0xcf9, 0x6);
+ busy_delay_ms(500); /* wait 0.5 sec to see if that did it */
+
+ /*
+ * Attempt to force a reset via the Fast A20 and Init register
+ * at I/O port 0x92. Bit 1 serves as an alternate A20 gate.
+ * Bit 0 asserts INIT# when set to 1. We are careful to only
+ * preserve bit 1 while setting bit 0. We also must clear bit
+ * 0 before setting it if it isn't already clear.
+ */
+ b = inb(0x92);
+ if (b != 0xff) {
+ if ((b & 0x1) != 0)
+ outb(0x92, b & 0xfe);
+ outb(0x92, b | 0x1);
+ busy_delay_ms(500); /* wait 0.5 sec to see if that did it */
+ }
+
+ /* Triple fault */
+ x86_triplefault();
+
+ /* Give up on resetting */
+ while(1) {
+ ;
+ }
+}
+
+__dead void arch_shutdown(int how)
+{
+ unsigned char unused_ch;
+ /* Mask all interrupts, including the clock. */
+ outb( INT_CTLMASK, ~0);
+
+ /* Empty buffer */
+ while(direct_read_char(&unused_ch))
+ ;
+
+ if(kinfo.minix_panicing) {
+ /* Printing is done synchronously over serial. */
+ if (kinfo.do_serial_debug)
+ reset();
+
+ /* Print accumulated diagnostics buffer and reset. */
+ direct_cls();
+ direct_print("Minix panic. System diagnostics buffer:\n\n");
+ direct_print(kmess.kmess_buf);
+ direct_print("\nSystem has panicked, press any key to reboot");
+ while (!direct_read_char(&unused_ch))
+ ;
+ reset();
+ }
+
+ if (how == RBT_DEFAULT) {
+ how = RBT_RESET;
+ }
+
+ switch (how) {
+ case RBT_HALT:
+ /* Stop */
+ for (; ; ) halt_cpu();
+ NOT_REACHABLE;
+
+ default:
+ case RBT_REBOOT:
+ case RBT_RESET:
+ /* Reset the system by forcing a processor shutdown.
+ * First stop the BIOS memory test by setting a soft
+ * reset flag.
+ */
+ reset();
+ NOT_REACHABLE;
+ }
+
+ NOT_REACHABLE;
+}
+
+#ifdef DEBUG_SERIAL
+void ser_putc(char c)
+{
+ int i;
+ int lsr, thr;
+
+#if CONFIG_OXPCIE
+ oxpcie_putc(c);
+#else
+ lsr= COM1_LSR;
+ thr= COM1_THR;
+ for (i= 0; i<100000; i++)
+ {
+ if (inb( lsr) & LSR_THRE)
+ break;
+ }
+ outb( thr, c);
+#endif
+}
+
+#endif
* 16-bit mode
*/
extern volatile u32_t __ap_id;
-extern volatile struct segdesc_s __ap_gdt, __ap_idt;
+extern volatile struct desctableptr_s __ap_gdt, __ap_idt;
extern void * __trampoline_end;
extern u32_t busclock[CONFIG_MAX_CPUS];
return tramp_base;
}
+extern struct desctableptr_s gdt_desc, idt_desc;
+
static void smp_start_aps(void)
{
/*
outb(RTC_IO, 0xA);
/* prepare gdt and idt for the new cpus */
- __ap_gdt = gdt[GDT_INDEX];
- __ap_idt = gdt[IDT_INDEX];
+ __ap_gdt = gdt_desc;
+ __ap_idt = idt_desc;
if (!(trampoline_base = copy_trampoline())) {
printf("Copying trampoline code failed, cannot boot SMP\n");
}
__ap_id = cpu;
- phys_copy(vir2phys(__ap_id), __ap_id_phys, sizeof(__ap_id));
+ phys_copy(vir2phys((void *) &__ap_id),
+ __ap_id_phys, sizeof(__ap_id));
mfence();
if (apic_send_init_ipi(cpu, trampoline_base) ||
apic_send_startup_ipi(cpu, trampoline_base)) {
/* inform the world of our presence. */
ap_cpu_ready = cpu;
- while(!i386_paging_enabled)
+ while(!bootstrap_pagetable_done)
arch_pause();
/*
* we must load some page tables befre we turn paging on. As VM is
* always present we use those
*/
- segmentation2paging(proc_addr(VM_PROC_NR));
+ pg_load(); /* load bootstrap pagetable built by BSP */
+ vm_enable_paging();
printf("CPU %d paging is on\n", cpu);
goto uniproc_fallback;
}
- lapic_addr = phys2vir(LOCAL_APIC_DEF_ADDR);
+ lapic_addr = LOCAL_APIC_DEF_ADDR;
ioapic_enabled = 0;
tss_init_all();
apic_idt_init(1); /* Reset to PIC idt ! */
idt_reload();
smp_reinit_vars (); /* revert to a single proc system. */
- intr_init (INTS_MINIX, 0); /* no auto eoi */
+ intr_init(0); /* no auto eoi */
printf("WARNING : SMP initialization failed\n");
}
#include "oxpcie.h"
#include "kernel/proc.h"
#include "kernel/debug.h"
-#include "mb_utils.h"
+#include "direct_utils.h"
#include <machine/multiboot.h>
#include "glo.h"
static int osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
-extern __dead void poweroff_jmp();
-extern void poweroff16();
-extern void poweroff16_end();
-
/* set MP and NE flags to handle FPU exceptions in native mode. */
#define CR0_MP_NE 0x0022
/* set CR4.OSFXSR[bit 9] if FXSR is supported. */
static void ser_init(void);
#endif
-#define KBCMDP 4 /* kbd controller port (O) */
-#define KBC_PULSE0 0xfe /* pulse output bit 0 */
-#define IO_KBD 0x060 /* 8042 Keyboard */
-
-void
-reset(void)
-{
- uint8_t b;
- /*
- * The keyboard controller has 4 random output pins, one of which is
- * connected to the RESET pin on the CPU in many PCs. We tell the
- * keyboard controller to pulse this line a couple of times.
- */
- outb(IO_KBD + KBCMDP, KBC_PULSE0);
- busy_delay_ms(100);
- outb(IO_KBD + KBCMDP, KBC_PULSE0);
- busy_delay_ms(100);
-
- /*
- * Attempt to force a reset via the Reset Control register at
- * I/O port 0xcf9. Bit 2 forces a system reset when it
- * transitions from 0 to 1. Bit 1 selects the type of reset
- * to attempt: 0 selects a "soft" reset, and 1 selects a
- * "hard" reset. We try a "hard" reset. The first write sets
- * bit 1 to select a "hard" reset and clears bit 2. The
- * second write forces a 0 -> 1 transition in bit 2 to trigger
- * a reset.
- */
- outb(0xcf9, 0x2);
- outb(0xcf9, 0x6);
- busy_delay_ms(500); /* wait 0.5 sec to see if that did it */
-
- /*
- * Attempt to force a reset via the Fast A20 and Init register
- * at I/O port 0x92. Bit 1 serves as an alternate A20 gate.
- * Bit 0 asserts INIT# when set to 1. We are careful to only
- * preserve bit 1 while setting bit 0. We also must clear bit
- * 0 before setting it if it isn't already clear.
- */
- b = inb(0x92);
- if (b != 0xff) {
- if ((b & 0x1) != 0)
- outb(0x92, b & 0xfe);
- outb(0x92, b | 0x1);
- busy_delay_ms(500); /* wait 0.5 sec to see if that did it */
- }
-
- /* Triple fault */
- x86_triplefault();
-
- /* Give up on resetting */
- while(1) {
- ;
- }
-}
-
-static __dead void arch_bios_poweroff(void)
-{
- u32_t cr0;
-
- /* Disable paging */
- cr0 = read_cr0();
- cr0 &= ~I386_CR0_PG;
- write_cr0(cr0);
- /* Copy 16-bit poweroff code to below 1M */
- phys_copy(
- (u32_t)&poweroff16,
- BIOS_POWEROFF_ENTRY,
- (u32_t)&poweroff16_end-(u32_t)&poweroff16);
- poweroff_jmp();
-}
-
-int cpu_has_tsc;
-
-__dead void arch_shutdown(int how)
-{
- vm_stop();
-
- /* Mask all interrupts, including the clock. */
- outb( INT_CTLMASK, ~0);
-
- if(minix_panicing) {
- unsigned char unused_ch;
- /* We're panicing? Then retrieve and decode currently
- * loaded segment selectors.
- */
- printseg("cs: ", 1, get_cpulocal_var(proc_ptr), read_cs());
- printseg("ds: ", 0, get_cpulocal_var(proc_ptr), read_ds());
- if(read_ds() != read_ss()) {
- printseg("ss: ", 0, NULL, read_ss());
- }
-
- /* Printing is done synchronously over serial. */
- if (do_serial_debug)
- reset();
-
- /* Print accumulated diagnostics buffer and reset. */
- mb_cls();
- mb_print("Minix panic. System diagnostics buffer:\n\n");
- mb_print(kmess_buf);
- mb_print("\nSystem has panicked, press any key to reboot");
- while (!mb_read_char(&unused_ch))
- ;
- reset();
- }
-
- if (how == RBT_DEFAULT) {
- how = RBT_RESET;
- }
-
- switch (how) {
-
- case RBT_HALT:
- /* Poweroff without boot monitor */
- arch_bios_poweroff();
- NOT_REACHABLE;
-
- case RBT_PANIC:
- /* Allow user to read panic message */
- for (; ; ) halt_cpu();
- NOT_REACHABLE;
-
- default:
- case RBT_REBOOT:
- case RBT_RESET:
- /* Reset the system by forcing a processor shutdown.
- * First stop the BIOS memory test by setting a soft
- * reset flag.
- */
- reset();
- NOT_REACHABLE;
- }
-
- NOT_REACHABLE;
-}
-
void fpu_init(void)
{
unsigned short cw, sw;
*/
static char fpu_state[NR_PROCS][FPU_XFP_SIZE] __aligned(FPUALIGN);
-void arch_proc_init(int nr, struct proc *pr)
+void arch_proc_reset(struct proc *pr)
{
- if(nr < 0) return;
- char *v;
+ char *v = NULL;
- assert(nr < NR_PROCS);
+ assert(pr->p_nr < NR_PROCS);
- v = fpu_state[nr];
+ if(pr->p_nr >= 0) {
+ v = fpu_state[pr->p_nr];
+ /* verify alignment */
+ assert(!((vir_bytes)v % FPUALIGN));
+ /* initialize state */
+ memset(v, 0, FPU_XFP_SIZE);
+ }
+
+ /* Clear process state. */
+ memset(&pr->p_reg, 0, sizeof(pr->p_reg));
+ if(iskerneln(pr->p_nr))
+ pr->p_reg.psw = INIT_TASK_PSW;
+ else
+ pr->p_reg.psw = INIT_PSW;
- /* verify alignment */
- assert(!((vir_bytes)v % FPUALIGN));
-
pr->p_seg.fpu_state = v;
+
+ /* Initialize the fundamentals that are (initially) the same for all
+ * processes - the segment selectors it gets to use.
+ */
+ pr->p_reg.cs = USER_CS_SELECTOR;
+ pr->p_reg.gs =
+ pr->p_reg.fs =
+ pr->p_reg.ss =
+ pr->p_reg.es =
+ pr->p_reg.ds = USER_DS_SELECTOR;
}
int restore_fpu(struct proc *pr)
void arch_init(void)
{
-#ifdef USE_APIC
- /*
- * this is setting kernel segments to cover most of the phys memory. The
- * value is high enough to reach local APIC nad IOAPICs before paging is
- * turned on.
- */
- prot_set_kern_seg_limit(0xfff00000);
- reload_ds();
-#endif
-
- idt_init();
-
/* FIXME stupid a.out
* align the stacks in the stack are to the K_STACK_SIZE which is a
* power of 2
BOOT_VERBOSE(printf("APIC not present, using legacy PIC\n"));
}
#endif
-}
-#ifdef DEBUG_SERIAL
-void ser_putc(char c)
-{
- int i;
- int lsr, thr;
-
-#if CONFIG_OXPCIE
- oxpcie_putc(c);
-#else
- lsr= COM1_LSR;
- thr= COM1_THR;
- for (i= 0; i<100000; i++)
- {
- if (inb( lsr) & LSR_THRE)
- break;
- }
- outb( thr, c);
-#endif
+ /* Reserve some BIOS ranges */
+ cut_memmap(&kinfo, BIOS_MEM_BEGIN, BIOS_MEM_END);
+ cut_memmap(&kinfo, BASE_MEM_TOP, UPPER_MEM_END);
}
-
/*===========================================================================*
* do_ser_debug *
*===========================================================================*/
#endif
}
-static void ser_dump_segs(void)
-{
- struct proc *pp;
- for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++)
- {
- if (isemptyp(pp))
- continue;
- printf("%d: %s ep %d\n", proc_nr(pp), pp->p_name, pp->p_endpoint);
- printseg("cs: ", 1, pp, pp->p_reg.cs);
- printseg("ds: ", 0, pp, pp->p_reg.ds);
- if(pp->p_reg.ss != pp->p_reg.ds) {
- printseg("ss: ", 0, pp, pp->p_reg.ss);
- }
- }
-}
-
#ifdef CONFIG_SMP
static void dump_bkl_usage(void)
{
case '2':
ser_dump_queues();
break;
- case '3':
- ser_dump_segs();
- break;
#ifdef CONFIG_SMP
case '4':
ser_dump_proc_cpu();
serial_debug_active = 0;
}
+#if DEBUG_SERIAL
void ser_dump_proc()
{
struct proc *pp;
#endif
-/* Saved by mpx386.s into these variables. */
-u32_t params_size, params_offset, mon_ds;
-
-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;
-}
-
-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;
-}
-
void arch_do_syscall(struct proc *proc)
{
/* do_ipc assumes that it's running because of the current process */
/* set pointer to the process to run on the stack */
p = get_cpulocal_var(proc_ptr);
*((reg_t *)stk) = (reg_t) p;
+
+ /* make sure IF is on in FLAGS so that interrupts won't be disabled
+ * once p's context is restored. this should not be possible.
+ */
+ assert(p->p_reg.psw & (1L << 9));
+
return p;
}
unsigned divisor;
/* keep BIOS settings if cttybaud is not set */
- if (serial_debug_baud <= 0) return;
+ if (kinfo.serial_debug_baud <= 0) return;
/* set DLAB to make baud accessible */
lcr = LCR_8BIT | LCR_1STOP | LCR_NPAR;
outb(COM1_LCR, lcr | LCR_DLAB);
/* set baud rate */
- divisor = UART_BASE_FREQ / serial_debug_baud;
+ divisor = UART_BASE_FREQ / kinfo.serial_debug_baud;
if (divisor < 1) divisor = 1;
if (divisor > 65535) divisor = 65535;
--- /dev/null
+
+#include "kernel.h"
+#include <minix/minlib.h>
+#include <minix/const.h>
+#include <minix/cpufeature.h>
+#include <minix/types.h>
+#include <minix/type.h>
+#include <minix/com.h>
+#include <sys/param.h>
+#include <machine/partition.h>
+#include <libexec.h>
+#include "string.h"
+#include "arch_proto.h"
+#include "libexec.h"
+#include "direct_utils.h"
+#include "serial.h"
+#include "glo.h"
+#include <machine/multiboot.h>
+
+/* Give non-zero values to avoid them in BSS */
+static int print_line = 1, print_col = 1;
+
+#include <sys/video.h>
+
+extern char *video_mem;
+#define VIDOFFSET(line, col) ((line) * MULTIBOOT_CONSOLE_COLS * 2 + (col) * 2)
+#define VIDSIZE VIDOFFSET(MULTIBOOT_CONSOLE_LINES-1,MULTIBOOT_CONSOLE_COLS-1)
+
+void direct_put_char(char c, int line, int col)
+{
+ int offset = VIDOFFSET(line, col);
+ video_mem[offset] = c;
+ video_mem[offset+1] = 0x07; /* grey-on-black */
+}
+
+static char direct_get_char(int line, int col)
+{
+ return video_mem[VIDOFFSET(line, col)];
+}
+
+void direct_cls(void)
+{
+ /* Clear screen */
+ int i,j;
+
+ for(i = 0; i < MULTIBOOT_CONSOLE_COLS; i++)
+ for(j = 0; j < MULTIBOOT_CONSOLE_LINES; j++)
+ direct_put_char(' ', j, i);
+
+ print_line = print_col = 0;
+
+ /* Tell video hardware origin is 0. */
+ outb(C_6845+INDEX, VID_ORG);
+ outb(C_6845+DATA, 0);
+ outb(C_6845+INDEX, VID_ORG+1);
+ outb(C_6845+DATA, 0);
+}
+
+static void direct_scroll_up(int lines)
+{
+ int i, j;
+ for (i = 0; i < MULTIBOOT_CONSOLE_LINES; i++ ) {
+ for (j = 0; j < MULTIBOOT_CONSOLE_COLS; j++ ) {
+ char c = 0;
+ if(i < MULTIBOOT_CONSOLE_LINES-lines)
+ c = direct_get_char(i + lines, j);
+ direct_put_char(c, i, j);
+ }
+ }
+ print_line-= lines;
+}
+
+void direct_print_char(char c)
+{
+ while (print_line >= MULTIBOOT_CONSOLE_LINES)
+ direct_scroll_up(1);
+
+#define TABWIDTH 8
+ if(c == '\t') {
+ if(print_col >= MULTIBOOT_CONSOLE_COLS - TABWIDTH) {
+ c = '\n';
+ } else {
+ do {
+ direct_put_char(' ', print_line, print_col++);
+ } while(print_col % TABWIDTH);
+ return;
+ }
+ }
+
+ if (c == '\n') {
+ while (print_col < MULTIBOOT_CONSOLE_COLS)
+ direct_put_char(' ', print_line, print_col++);
+ print_line++;
+ print_col = 0;
+ return;
+ }
+
+ direct_put_char(c, print_line, print_col++);
+
+ if (print_col >= MULTIBOOT_CONSOLE_COLS) {
+ print_line++;
+ print_col = 0;
+ }
+
+ while (print_line >= MULTIBOOT_CONSOLE_LINES)
+ direct_scroll_up(1);
+}
+
+void direct_print(const char *str)
+{
+ while (*str) {
+ direct_print_char(*str);
+ str++;
+ }
+}
+
+/* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
+#define KEYBD 0x60 /* I/O port for keyboard data */
+#define KB_STATUS 0x64 /* I/O port for status on AT */
+#define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
+#define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
+
+int direct_read_char(unsigned char *ch)
+{
+ unsigned long b, sb;
+
+ sb = inb(KB_STATUS);
+
+ if (!(sb & KB_OUT_FULL)) {
+ return 0;
+ }
+
+ b = inb(KEYBD);
+
+ if (!(sb & KB_AUX_BYTE))
+ return 1;
+
+ return 0;
+}
+
struct vir_addr src, dst;
vir_bytes len = m_ptr->RDB_SIZE, limit;
- src.segment = PHYS_SEG;
- dst.segment = D;
src.offset = m_ptr->RDB_ADDR;
dst.offset = (vir_bytes) m_ptr->RDB_BUF;
src.proc_nr_e = NONE;
endpoint_t proc_nr_e = m_ptr->DIO_VEC_ENDPT;
vir_bytes count = m_ptr->DIO_VEC_SIZE;
long port = m_ptr->DIO_PORT;
- phys_bytes phys_buf;
+ phys_bytes vir_buf;
int i, req_type, req_dir, size, nr_io_range;
struct priv *privp;
struct io_range *iorp;
if(!isokendpt(newep, &proc_nr))
return(EINVAL);
destproc = proc_addr(proc_nr);
- if ((phys_buf = umap_local(destproc, D,
- (vir_bytes) newoffset, count)) == 0) {
- printf("do_sdevio: umap_local failed\n");
- return(EFAULT);
- }
+ vir_buf = newoffset;
} else {
if(proc_nr != _ENDPOINT_P(caller->p_endpoint))
{
return EPERM;
}
/* Get and check physical address. */
- if ((phys_buf = umap_local(proc_addr(proc_nr), D,
- (vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
- return(EFAULT);
+ vir_buf = (phys_bytes) m_ptr->DIO_VEC_ADDR;
destproc = proc_addr(proc_nr);
}
/* current process must be target for phys_* to be OK */
/* Perform device I/O for bytes and words. Longs are not supported. */
if (req_dir == _DIO_INPUT) {
switch (req_type) {
- case _DIO_BYTE: phys_insb(port, phys_buf, count); break;
- case _DIO_WORD: phys_insw(port, phys_buf, count); break;
+ case _DIO_BYTE: phys_insb(port, vir_buf, count); break;
+ case _DIO_WORD: phys_insw(port, vir_buf, count); break;
default:
retval = EINVAL;
goto return_error;
}
} else if (req_dir == _DIO_OUTPUT) {
switch (req_type) {
- case _DIO_BYTE: phys_outsb(port, phys_buf, count); break;
- case _DIO_WORD: phys_outsw(port, phys_buf, count); break;
+ case _DIO_BYTE: phys_outsb(port, vir_buf, count); break;
+ case _DIO_WORD: phys_outsw(port, vir_buf, count); break;
default:
retval = EINVAL;
goto return_error;
inkernel_disaster(pr, frame, NULL, is_nested);
}
- /* System processes that don't have their own page table can't
- * have page faults. VM does have its own page table but also
- * can't have page faults (because VM has to handle them).
- */
- if((pr->p_endpoint <= INIT_PROC_NR &&
- !(pr->p_misc_flags & MF_FULLVM)) || pr->p_endpoint == VM_PROC_NR) {
+ /* VM can't handle page faults. */
+ if(pr->p_endpoint == VM_PROC_NR) {
/* Page fault we can't / don't want to
* handle.
*/
- printf("pagefault for process %d ('%s') on CPU %d, "
+ printf("pagefault for VM on CPU %d, "
"pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
- pr->p_endpoint, pr->p_name, cpuid, pr->p_reg.pc,
- pagefaultcr2, frame->errcode, is_nested);
- if(!is_nested) {
- printf("process vir addr of pagefault is 0x%lx\n",
- pagefaultcr2 -
- (pr->p_memmap[D].mem_phys << CLICK_SHIFT));
- }
+ cpuid, pr->p_reg.pc, pagefaultcr2, frame->errcode,
+ is_nested);
proc_stacktrace(pr);
printf("pc of pagefault: 0x%lx\n", frame->eip);
- cause_sig(proc_nr(pr), SIGSEGV);
+ panic("pagefault in VM");
return;
}
proc_stacktrace_execute(proc_addr(SYSTEM), k_ebp, frame->eip);
}
- printseg("ker cs: ", 1, NULL, frame->cs);
- printseg("ker ds: ", 0, NULL, DS_SELECTOR);
-
if (saved_proc) {
printf("scheduled was: process %d (%s), ", saved_proc->p_endpoint, saved_proc->p_name);
- printf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs,
- (unsigned) saved_proc->p_reg.pc);
+ printf("pc = 0x%x\n", (unsigned) saved_proc->p_reg.pc);
proc_stacktrace(saved_proc);
panic("Unhandled kernel exception");
--- /dev/null
+#include "kernel/kernel.h" /* configures the kernel */
+
+/* sections */
+
+#include <machine/vm.h>
+#include "../../kernel.h"
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/com.h>
+#include <machine/asm.h>
+#include <machine/interrupt.h>
+#include "archconst.h"
+#include "kernel/const.h"
+#include "kernel/proc.h"
+#include "sconst.h"
+#include <machine/multiboot.h>
+
+#include "arch_proto.h" /* K_STACK_SIZE */
+
+#ifdef CONFIG_SMP
+#include "kernel/smp.h"
+#endif
+
+/* Selected 386 tss offsets. */
+#define TSS3_S_SP0 4
+
+IMPORT(copr_not_available_handler)
+IMPORT(params_size)
+IMPORT(params_offset)
+IMPORT(mon_ds)
+IMPORT(switch_to_user)
+IMPORT(multiboot_init)
+
+.text
+/*===========================================================================*/
+/* MINIX */
+/*===========================================================================*/
+.global MINIX
+MINIX:
+/* this is the entry point for the MINIX kernel */
+ jmp multiboot_init
+
+/* Multiboot header here*/
+
+.balign 8
+
+#define MULTIBOOT_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
+
+multiboot_magic:
+ .long MULTIBOOT_HEADER_MAGIC
+multiboot_flags:
+ .long MULTIBOOT_FLAGS
+multiboot_checksum:
+ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_FLAGS)
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+/* Video mode */
+multiboot_mode_type:
+ .long MULTIBOOT_VIDEO_MODE_EGA
+multiboot_width:
+ .long MULTIBOOT_CONSOLE_COLS
+multiboot_height:
+ .long MULTIBOOT_CONSOLE_LINES
+multiboot_depth:
+ .long 0
+
+multiboot_init:
+ mov $load_stack_start, %esp /* make usable stack */
+ mov $0, %ebp
+ push $0 /* set flags to known good state */
+ popf /* esp, clear nested task and int enable */
+ push $0
+
+ push %ebx /* multiboot information struct */
+ push %eax /* multiboot magic number */
+ call _C_LABEL(pre_init)
+
+ /* Kernel is mapped high now and ready to go, with
+ * the boot info pointer returnd in %eax. Set the
+ * highly mapped stack, initialize it, push the boot
+ * info pointer and jump to the highly mapped kernel.
+ */
+ mov $k_initial_stktop, %esp
+ push $0 /* Terminate stack */
+ push %eax
+ call _C_LABEL(kmain)
+
+ /* not reached */
+hang:
+ jmp hang
+
+.data
+load_stack:
+ .space 4096
+load_stack_start:
/*===========================================================================*
* intr_init *
*===========================================================================*/
-int intr_init(const int mine, const int auto_eoi)
+int intr_init(const int auto_eoi)
{
-/* Initialize the 8259s, finishing with all interrupts disabled. This is
- * only done in protected mode, in real mode we don't touch the 8259s, but
- * use the BIOS locations instead. The flag "mine" is set if the 8259s are
- * to be programmed for MINIX, or to be reset to what the BIOS expects.
- */
-
- /* The AT and newer PS/2 have two interrupt controllers, one master,
- * one slaved at IRQ 2. (We don't have to deal with the PC that
- * has just one controller, because it must run in real mode.)
- */
+/* Initialize the 8259s, finishing with all interrupts disabled. */
outb( INT_CTL, ICW1_AT);
- outb( INT_CTLMASK, mine == INTS_MINIX ? IRQ0_VECTOR : BIOS_IRQ0_VEC);
+ outb( INT_CTLMASK, IRQ0_VECTOR);
/* ICW2 for master */
outb( INT_CTLMASK, (1 << CASCADE_IRQ));
/* ICW3 tells slaves */
outb( INT_CTLMASK, ICW4_AT_MASTER);
outb( INT_CTLMASK, ~(1 << CASCADE_IRQ)); /* IRQ 0-7 mask */
outb( INT2_CTL, ICW1_AT);
- outb( INT2_CTLMASK, mine == INTS_MINIX ? IRQ8_VECTOR : BIOS_IRQ8_VEC);
+ outb( INT2_CTLMASK, IRQ8_VECTOR);
/* ICW2 for slave */
outb( INT2_CTLMASK, CASCADE_IRQ); /* ICW3 is slave nr */
if (auto_eoi)
outb( INT2_CTLMASK, ICW4_AT_SLAVE);
outb( INT2_CTLMASK, ~0); /* IRQ 8-15 mask */
- /* Copy the BIOS vectors from the BIOS to the Minix location, so we
- * can still make BIOS calls without reprogramming the i8259s.
- */
-#if IRQ0_VECTOR != BIOS_IRQ0_VEC
- phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
-#endif
-#if IRQ8_VECTOR != BIOS_IRQ8_VEC
- phys_copy(BIOS_VECTOR(8) * 4L, VECTOR(8) * 4L, 8 * 4L);
-#endif
-
return OK;
}
void kernel_call_entry(void);
void level0_call(void);
-/* memory.c */
-void segmentation2paging(struct proc * current);
-void i386_freepde(int pde);
-void getcr3val(void);
-
-
/* exception.c */
struct exception_frame {
reg_t vector; /* which interrupt vector was triggered */
void write_cr4(unsigned long value);
void write_cr3(unsigned long value);
unsigned long read_cpu_flags(void);
+phys_bytes vir2phys(void *);
void phys_insb(u16_t port, phys_bytes buf, size_t count);
void phys_insw(u16_t port, phys_bytes buf, size_t count);
void phys_outsb(u16_t port, phys_bytes buf, size_t count);
int __frstor_failure(void *);
unsigned short fnstsw(void);
void fnstcw(unsigned short* cw);
+void x86_lgdt(void *);
+void x86_lldt(u32_t);
+void x86_ltr(u32_t);
+void x86_lidt(void *);
+void x86_load_kerncs(void);
+void x86_load_ds(u32_t);
+void x86_load_ss(u32_t);
+void x86_load_es(u32_t);
+void x86_load_fs(u32_t);
+void x86_load_gs(u32_t);
+
void switch_k_stack(void * esp, void (* continuation)(void));
u16_t trap;
u16_t iobase;
/* u8_t iomap[0]; */
-};
+} __attribute__((packed));
-void prot_init(void);
-void idt_init(void);
-void init_dataseg(struct segdesc_s *segdp, phys_bytes base, vir_bytes
- size, int privilege);
void enable_iop(struct proc *pp);
-int prot_set_kern_seg_limit(vir_bytes limit);
-void printseg(char *banner, int iscs, struct proc *pr, u32_t selector);
u32_t read_cs(void);
u32_t read_ds(void);
u32_t read_ss(void);
+void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len);
+void vm_enable_paging(void);
+void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end);
+phys_bytes pg_roundup(phys_bytes b);
+void pg_info(reg_t *, u32_t **);
+void pg_clear(void);
+void pg_identity(void);
+phys_bytes pg_load(void);
+void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end, kinfo_t *cbi);
+int pg_mapkernel(void);
+void pg_mapproc(struct proc *p, struct boot_image *ip, kinfo_t *cbi);
+
/* prototype of an interrupt vector table entry */
struct gate_table_s {
void(*gate) (void);
unsigned char privilege;
};
-extern struct gate_table_s gate_table_pic[];
-
/* copies an array of vectors to the IDT. The last vector must be zero filled */
void idt_copy_vectors(struct gate_table_s * first);
+void idt_copy_vectors_pic(void);
void idt_reload(void);
-EXTERN void * k_boot_stktop;
EXTERN void * k_stacks_start;
extern void * k_stacks;
/*
* sets up TSS for a cpu and assigns kernel stack and cpu id
*/
-void tss_init(unsigned cpu, void * kernel_stack);
+int tss_init(unsigned cpu, void * kernel_stack);
-void int_gate(unsigned vec_nr, vir_bytes offset, unsigned dpl_type);
+void int_gate_idt(unsigned vec_nr, vir_bytes offset, unsigned dpl_type);
void __copy_msg_from_user_end(void);
void __copy_msg_to_user_end(void);
cmp_f)(void *)));
/* breakpoints.c */
+int breakpoint_set(phys_bytes linaddr, int bp, const int flags);
#define BREAKPOINT_COUNT 4
#define BREAKPOINT_FLAG_RW_MASK (3 << 0)
#define BREAKPOINT_FLAG_RW_EXEC (0 << 0)
int i386_watchdog_start(void);
-#define nmi_in_kernel(f) ((f)->cs == CS_SELECTOR)
+#define nmi_in_kernel(f) ((f)->cs == KERN_CS_SELECTOR)
#endif /* __I386_WATCHDOG_H__ */
/* Constants for protected mode. */
/* Table sizes. */
-#define GDT_SIZE (FIRST_LDT_INDEX + NR_TASKS + NR_PROCS)
- /* spec. and LDT's */
#define IDT_SIZE 256 /* the table is set to it's maximal size */
-/* Fixed global descriptors. 1 to 7 are prescribed by the BIOS. */
-#define GDT_INDEX 1 /* GDT descriptor */
-#define IDT_INDEX 2 /* IDT descriptor */
-#define DS_INDEX 3 /* kernel DS */
-#define ES_INDEX 4 /* kernel ES (386: flag 4 Gb at startup) */
-#define SS_INDEX 5 /* kernel SS (386: monitor SS at startup) */
-#define CS_INDEX 6 /* kernel CS */
-#define MON_CS_INDEX 7 /* temp for BIOS (386: monitor CS at startup) */
-#define TSS_INDEX_FIRST 8 /* first kernel TSS */
-#define TSS_INDEX_BOOT TSS_INDEX_FIRST
-#define TSS_INDEX(cpu) (TSS_INDEX_FIRST + (cpu)) /* per cpu kernel tss */
-#define FIRST_LDT_INDEX TSS_INDEX(CONFIG_MAX_CPUS) /* rest of descriptors are LDT's */
-
-/* Descriptor structure offsets. */
-#define DESC_BASE 2 /* to base_low */
-#define DESC_BASE_MIDDLE 4 /* to base_middle */
-#define DESC_ACCESS 5 /* to access byte */
-#define DESC_SIZE 8 /* sizeof (struct segdesc_s) */
-
-/*
- * WARNING no () around the macros, be careful. This is because of ACK assembler
- * and will be fixed after switching to GAS
- */
-#define GDT_SELECTOR GDT_INDEX * DESC_SIZE
-#define IDT_SELECTOR IDT_INDEX * DESC_SIZE
-#define DS_SELECTOR DS_INDEX * DESC_SIZE
-#define ES_SELECTOR ES_INDEX * DESC_SIZE
-/* flat DS is less privileged ES */
-#define FLAT_DS_SELECTOR ES_SELECTOR
-#define SS_SELECTOR SS_INDEX * DESC_SIZE
-#define CS_SELECTOR CS_INDEX * DESC_SIZE
-#define MON_CS_SELECTOR MON_CS_INDEX * DESC_SIZE
-#define TSS_SELECTOR(cpu) (TSS_INDEX(cpu) * DESC_SIZE)
-#define TSS_SELECTOR_BOOT (TSS_INDEX_BOOT * DESC_SIZE)
+/* GDT layout (SYSENTER/SYSEXIT compliant) */
+#define KERN_CS_INDEX 1
+#define KERN_DS_INDEX 2
+#define USER_CS_INDEX 3
+#define USER_DS_INDEX 4
+#define LDT_INDEX 5
+#define TSS_INDEX_FIRST 6
+#define TSS_INDEX(cpu) (TSS_INDEX_FIRST + (cpu)) /* per cpu kernel tss */
+#define GDT_SIZE (TSS_INDEX(CONFIG_MAX_CPUS)) /* LDT descriptor */
+
+#define SEG_SELECTOR(i) ((i)*8)
+#define KERN_CS_SELECTOR SEG_SELECTOR(KERN_CS_INDEX)
+#define KERN_DS_SELECTOR SEG_SELECTOR(KERN_DS_INDEX)
+#define USER_CS_SELECTOR (SEG_SELECTOR(USER_CS_INDEX) | USER_PRIVILEGE)
+#define USER_DS_SELECTOR (SEG_SELECTOR(USER_DS_INDEX) | USER_PRIVILEGE)
+#define LDT_SELECTOR SEG_SELECTOR(LDT_INDEX)
+#define TSS_SELECTOR(cpu) SEG_SELECTOR(TSS_INDEX(cpu))
/* Privileges. */
#define INTR_PRIVILEGE 0 /* kernel and interrupt handlers */
#define IF_MASK 0x00000200
#define IOPL_MASK 0x003000
-#define vir2phys(vir) ((phys_bytes)((kinfo.data_base + (vir_bytes) (vir))))
-#define phys2vir(ph) ((vir_bytes)((vir_bytes) (ph) - kinfo.data_base))
-
#define INTEL_CPUID_GEN_EBX 0x756e6547 /* ASCII value of "Genu" */
#define INTEL_CPUID_GEN_EDX 0x49656e69 /* ASCII value of "ineI" */
#define INTEL_CPUID_GEN_ECX 0x6c65746e /* ASCII value of "ntel" */
*/
#define X86_STACK_TOP_RESERVED (2 * sizeof(reg_t))
+#define PG_ALLOCATEME ((phys_bytes)-1)
+
#endif /* _I386_ACONST_H */
--- /dev/null
+#ifndef MB_UTILS_H
+#define MB_UTILS_H
+
+#include "kernel/kernel.h"
+
+void direct_cls(void);
+void direct_print(const char*);
+void direct_print_char(char);
+int direct_read_char(unsigned char*);
+
+#endif
OUTPUT_ARCH("i386")
-ENTRY(MINIX)
+ENTRY(__k_unpaged_MINIX)
+
+_kern_phys_base = 0x00400000; /* phys 4MB aligned for convenient remapping */
+_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */
+_kern_offset = (_kern_vir_base - _kern_phys_base);
+
+__k_unpaged__kern_offset = _kern_offset;
+__k_unpaged__kern_vir_base = _kern_vir_base;
+__k_unpaged__kern_phys_base = _kern_phys_base;
+
SECTIONS
{
- . = 0x200000 + SIZEOF_HEADERS;
- .text . : AT (ADDR(.text) - 0x0000) {
- *(.text)
- *(.text.*)
- }
- _etext = .;
- etext = .;
- . = ALIGN(4096);
+ . = _kern_phys_base;
+ __k_unpaged__kern_unpaged_start = .;
- .data . : AT (ADDR(.data) - 0x0000) {
- _rodata = .;
- /* kernel data starts with this magic number */
- SHORT(0x526f);
- *(.rodata)
- *(.rodata.*)
- _erodata = .;
- *(.data)
- *(.data.*)
- . = ALIGN(4096);
- }
- _edata = .;
+ .unpaged_text : { unpaged_*.o(.text) }
+ .unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) }
+ .unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) }
+ __k_unpaged__kern_unpaged_end = .;
- .bss . : AT (ADDR(.bss) - 0x0000) {
- *(.bss)
- *(.bss.*)
- *(COMMON)
- }
- _end = .;
- end = .;
+ . += _kern_offset;
- /DISCARD/ :
- {
- *(.eh_frame)
- *(.comment)
- *(.comment.*)
- *(.note)
- *(.note.*)
- *(.ident)
+ .text : AT(ADDR(.text) - _kern_offset) { *(.text*) }
+ .data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) }
+ .bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON)
+ __k_unpaged__kern_size = . - _kern_vir_base;
+ _kern_size = __k_unpaged__kern_size;
}
}
mov %esp, %ebp
cld
push %edi
- push %es
- mov $FLAT_DS_SELECTOR, %ecx
- mov %cx, %es
mov 8(%ebp), %edx /* port to read from */
mov 12(%ebp), %edi /* destination addr */
mov 16(%ebp), %ecx /* byte count */
shr $1, %ecx /* word count */
rep insw /* input many words */
- pop %es
pop %edi
pop %ebp
ret
mov %esp, %ebp
cld
push %edi
- push %es
- mov $FLAT_DS_SELECTOR, %ecx
- mov %cx, %es
mov 8(%ebp), %edx /* port to read from */
mov 12(%ebp), %edi /* destination addr */
mov 16(%ebp), %ecx /* byte count */
rep insb /* input many bytes */
- pop %es
pop %edi
pop %ebp
ret
mov %esp, %ebp
cld
push %esi
- push %ds
- mov $FLAT_DS_SELECTOR, %ecx
- mov %cx, %ds
mov 8(%ebp), %edx /* port to write to */
mov 12(%ebp), %esi /* source addr */
mov 16(%ebp), %ecx /* byte count */
shr $1, %ecx /* word count */
rep outsw /* output many words */
- pop %ds
pop %esi
pop %ebp
ret
mov %esp, %ebp
cld
push %esi
- push %ds
- mov $FLAT_DS_SELECTOR, %ecx
- mov %cx, %ds
mov 8(%ebp), %edx /* port to write to */
mov 12(%ebp), %esi /* source addr */
mov 16(%ebp), %ecx /* byte count */
rep outsb /* output many bytes */
- pop %ds
pop %esi
pop %ebp
ret
* phys_bytes bytecount);
* Copy a block of data from anywhere to anywhere in physical memory.
*/
- PC_ARGS = 4+4+4+4 /* 4 + 4 + 4 */
/* es edi esi eip src dst len */
ENTRY(phys_copy)
+ push %ebp
+ mov %esp, %ebp
+
cld
push %esi
push %edi
- push %es
- mov $FLAT_DS_SELECTOR, %eax
- mov %ax, %es
-
- mov PC_ARGS(%esp), %esi
- mov PC_ARGS+4(%esp), %edi
- mov PC_ARGS+4+4(%esp), %eax
+ mov 8(%ebp), %esi
+ mov 12(%ebp), %edi
+ mov 16(%ebp), %eax
cmp $10, %eax /* avoid align overhead for small counts */
jb pc_small
and $3, %ecx /* count for alignment */
sub %ecx, %eax
- rep movsb %es:(%esi), %es:(%edi)
+ rep movsb (%esi), (%edi)
mov %eax, %ecx
shr $2, %ecx /* count of dwords */
- rep movsl %es:(%esi), %es:(%edi)
+ rep movsl (%esi), (%edi)
and $3, %eax
pc_small:
xchg %eax, %ecx /* remainder */
- rep movsb %es:(%esi), %es:(%edi)
+ rep movsb (%esi), (%edi)
mov $0, %eax /* 0 means: no fault */
LABEL(phys_copy_fault) /* kernel can send us here */
- pop %es
pop %edi
pop %esi
+ pop %ebp
ret
LABEL(phys_copy_fault_in_kernel) /* kernel can send us here */
- pop %es
pop %edi
pop %esi
+ pop %ebp
mov %cr2, %eax
ret
+
/*===========================================================================*/
/* copy_msg_from_user */
/*===========================================================================*/
/*
- * int copy_msg_from_user(struct proc * p, message * user_mbuf, message * dst);
+ * int copy_msg_from_user(message * user_mbuf, message * dst);
*
* Copies a message of 36 bytes from user process space to a kernel buffer. This
- * function assumes that the process address space is installed (cr3 loaded) and
- * the local descriptor table of this process is loaded too.
- *
- * The %gs segment register is used to access the userspace memory. We load the
- * process' data segment in this register.
+ * function assumes that the process address space is installed (cr3 loaded).
*
* This function from the callers point of view either succeeds or returns an
* error which gives the caller a chance to respond accordingly. In fact it
* userspace as if wrong values or request were passed to the kernel
*/
ENTRY(copy_msg_from_user)
- push %gs
-
- mov 8(%esp), %eax
- movw DSREG(%eax), %gs
-
/* load the source pointer */
- mov 12(%esp), %ecx
+ mov 4(%esp), %ecx
/* load the destination pointer */
- mov 16(%esp), %edx
+ mov 8(%esp), %edx
- mov %gs:0*4(%ecx), %eax
- mov %eax, 0*4(%edx)
- mov %gs:1*4(%ecx), %eax
+/* mov 0*4(%ecx), %eax
+ mov %eax, 0*4(%edx) */
+ mov 1*4(%ecx), %eax
mov %eax, 1*4(%edx)
- mov %gs:2*4(%ecx), %eax
+ mov 2*4(%ecx), %eax
mov %eax, 2*4(%edx)
- mov %gs:3*4(%ecx), %eax
+ mov 3*4(%ecx), %eax
mov %eax, 3*4(%edx)
- mov %gs:4*4(%ecx), %eax
+ mov 4*4(%ecx), %eax
mov %eax, 4*4(%edx)
- mov %gs:5*4(%ecx), %eax
+ mov 5*4(%ecx), %eax
mov %eax, 5*4(%edx)
- mov %gs:6*4(%ecx), %eax
+ mov 6*4(%ecx), %eax
mov %eax, 6*4(%edx)
- mov %gs:7*4(%ecx), %eax
+ mov 7*4(%ecx), %eax
mov %eax, 7*4(%edx)
- mov %gs:8*4(%ecx), %eax
+ mov 8*4(%ecx), %eax
mov %eax, 8*4(%edx)
LABEL(__copy_msg_from_user_end)
-
- pop %gs
-
movl $0, %eax
ret
/* copy_msg_to_user */
/*===========================================================================*/
/*
- * void copy_msg_to_user(struct proc * p, message * src, message * user_mbuf);
+ * void copy_msg_to_user(message * src, message * user_mbuf);
*
- * Copies a message of 36 bytes to user process space from a kernel buffer. This
- * function assumes that the process address space is installed (cr3 loaded) and
- * the local descriptor table of this process is loaded too.
+ * Copies a message of 36 bytes to user process space from a kernel buffer.
*
* All the other copy_msg_from_user() comments apply here as well!
*/
ENTRY(copy_msg_to_user)
- push %gs
-
- mov 8(%esp), %eax
- movw DSREG(%eax), %gs
-
/* load the source pointer */
- mov 12(%esp), %ecx
+ mov 4(%esp), %ecx
/* load the destination pointer */
- mov 16(%esp), %edx
+ mov 8(%esp), %edx
mov 0*4(%ecx), %eax
- mov %eax, %gs:0*4(%edx)
+ mov %eax, 0*4(%edx)
mov 1*4(%ecx), %eax
- mov %eax, %gs:1*4(%edx)
+ mov %eax, 1*4(%edx)
mov 2*4(%ecx), %eax
- mov %eax, %gs:2*4(%edx)
+ mov %eax, 2*4(%edx)
mov 3*4(%ecx), %eax
- mov %eax, %gs:3*4(%edx)
+ mov %eax, 3*4(%edx)
mov 4*4(%ecx), %eax
- mov %eax, %gs:4*4(%edx)
+ mov %eax, 4*4(%edx)
mov 5*4(%ecx), %eax
- mov %eax, %gs:5*4(%edx)
+ mov %eax, 5*4(%edx)
mov 6*4(%ecx), %eax
- mov %eax, %gs:6*4(%edx)
+ mov %eax, 6*4(%edx)
mov 7*4(%ecx), %eax
- mov %eax, %gs:7*4(%edx)
+ mov %eax, 7*4(%edx)
mov 8*4(%ecx), %eax
- mov %eax, %gs:8*4(%edx)
+ mov %eax, 8*4(%edx)
LABEL(__copy_msg_to_user_end)
-
- pop %gs
-
movl $0, %eax
ret
* here to continue, clean up and report the error
*/
ENTRY(__user_copy_msg_pointer_failure)
- pop %gs
-
movl $-1, %eax
ret
mov %esp, %ebp
push %esi
push %ebx
- push %ds
mov 8(%ebp), %esi
mov 16(%ebp), %eax
- mov $FLAT_DS_SELECTOR, %ebx
- mov %bx, %ds
mov 12(%ebp), %ebx
shr $2, %eax
fill_start:
fill_done:
LABEL(memset_fault) /* kernel can send us here */
mov $0, %eax /* 0 means: no fault */
- pop %ds
pop %ebx
pop %esi
pop %ebp
ret
LABEL(memset_fault_in_kernel) /* kernel can send us here */
- pop %ds
pop %ebx
pop %esi
pop %ebp
mov %cr2, %eax
ret
-
-/*===========================================================================*/
-/* mem_rdw */
-/*===========================================================================*/
-/*
- * PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
- * Load and return word at far pointer segment:offset.
- */
-ENTRY(mem_rdw)
- mov %ds, %cx
- mov 4(%esp), %ds
- mov 4+4(%esp), %eax /* offset */
- movzwl (%eax), %eax /* word to return */
- mov %cx, %ds
- ret
-
-
/*===========================================================================*/
/* x86_triplefault */
/*===========================================================================*/
/* invlpg */
ARG_EAX_ACTION(i386_invlpg, invlpg (%eax));
-/*===========================================================================*/
-/* getcr3val */
-/*===========================================================================*/
-/* PUBLIC unsigned long getcr3val(void); */
-ENTRY(getcr3val)
- mov %cr3, %eax
+ENTRY(x86_load_kerncs)
+ push %ebp
+ mov %esp, %ebp
+ mov 8(%ebp), %eax
+ jmp $KERN_CS_SELECTOR, $newcs
+newcs:
+ pop %ebp
ret
/*
pop %ebp
ret
-/*===========================================================================*/
-/* idt_reload */
-/*===========================================================================*/
-/* PUBLIC void idt_reload (void); */
-/* reload idt when returning to monitor. */
-ENTRY(idt_reload)
- lidt _C_LABEL(gdt)+IDT_SELECTOR /* reload interrupt descriptor table */
- ret
-
-/*
- * void reload_segment_regs(void)
- */
-
-#define RELOAD_SEG_REG(reg) \
- mov reg, %ax ;\
- mov %ax, reg ;
-
-ENTRY(reload_ds)
- RELOAD_SEG_REG(%ds)
- ret
-
/*===========================================================================*/
/* __switch_address_space */
/*===========================================================================*/
ENTRY(__switch_address_space)
/* read the process pointer */
mov 4(%esp), %edx
- /* enable process' segment descriptors */
- lldt P_LDT_SEL(%edx)
/* get the new cr3 value */
movl P_CR3(%edx), %eax
/* test if the new cr3 != NULL */
0:
ret
-/*===========================================================================*/
-/* poweroff */
-/*===========================================================================*/
-/* PUBLIC void poweroff(); */
-/* Jump to 16-bit poweroff code */
-ENTRY(poweroff_jmp)
- cli
- /* Make real mode descriptor */
- mov $(_C_LABEL(gdt) + SS_SELECTOR), %edi
- mov $0x100, %eax
- movw %ax, 2(%edi)
- shr $16, %eax
- movb %al, 4(%edi)
- and $0xff00, %ax
- andw $0xff, 6(%edi)
- or %ax, 6(%edi)
- mov $0xffff, %eax
- movw %ax, (%edi)
- shr $16, %eax
- and $0xf, %ax
- andb $0xf0, 6(%edi)
- or %ax, 6(%edi)
-
- /* Flush TLB */
- xor %eax, %eax
- mov %eax, %cr3
-
- xor %esp, %esp /* clear esp for real mode*/
-
- /* Reset IDTR */
- lidt idt_ptr
-
- mov $SS_SELECTOR, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
-
- /* Save real mode cr0 in eax */
- mov %cr0, %eax
- andl $~I386_CR0_PE, %eax
-
- /* Jump to 16-bit code that is copied to below 1MB */
- ljmp $MON_CS_SELECTOR, $0
-
/* acknowledge just the master PIC */
ENTRY(eoi_8259_master)
movb $END_OF_INT, %al
idt_ptr:
.short 0x3ff
.long 0x0
+
+ldtsel:
+ .long LDT_SELECTOR
+++ /dev/null
-#ifndef MB_UTILS_H
-#define MB_UTILS_H
-
-#include "kernel/kernel.h"
-
-void mb_cls(void);
-void mb_print(char*);
-void mb_print_char(char);
-int mb_read_char(unsigned char*);
-
-
-#endif
#endif
#endif
-int i386_paging_enabled = 0;
-
-static int psok = 0;
-
-#define MAX_FREEPDES 2
-static int nfreepdes = 0, freepdes[MAX_FREEPDES];
+phys_bytes video_mem_vaddr = 0;
#define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
+static int nfreepdes = 0;
+#define MAXFREEPDES 2
+static int freepdes[MAXFREEPDES];
static u32_t phys_get32(phys_bytes v);
-static void vm_enable_paging(void);
-
-void segmentation2paging(struct proc * current)
+void mem_clear_mapcache(void)
{
- /* switch to the current process page tables before turning paging on */
- switch_address_space(current);
- vm_enable_paging();
+ int i;
+ for(i = 0; i < nfreepdes; i++) {
+ struct proc *ptproc = get_cpulocal_var(ptproc);
+ int pde = freepdes[i];
+ u32_t *ptv;
+ assert(ptproc);
+ ptv = ptproc->p_seg.p_cr3_v;
+ assert(ptv);
+ ptv[pde] = 0;
+ }
}
/* This function sets up a mapping from within the kernel's address
*
* The logical number supplied by the caller is translated into an actual
* pde number to be used, and a pointer to it (linear address) is returned
- * for actual use by phys_copy or phys_memset.
+ * for actual use by phys_copy or memset.
*/
static phys_bytes createpde(
const struct proc *pr, /* Requested process, NULL for physical. */
pde = freepdes[free_pde_idx];
assert(pde >= 0 && pde < 1024);
- if(pr && ((pr == get_cpulocal_var(ptproc)) || !HASPT(pr))) {
+ if(pr && ((pr == get_cpulocal_var(ptproc)) || iskernelp(pr))) {
/* Process memory is requested, and
* it's a process that is already in current page table, or
- * a process that is in every page table.
+ * the kernel, which is always there.
* Therefore linaddr is valid directly, with the requested
* size.
*/
u32_t addr;
proc_nr_t procslot;
- assert(vm_running);
- assert(nfreepdes >= MAX_FREEPDES);
-
assert(get_cpulocal_var(ptproc));
assert(get_cpulocal_var(proc_ptr));
assert(read_cr3() == get_cpulocal_var(ptproc)->p_seg.p_cr3);
const u32_t v;
int r;
- if(!vm_running) {
- phys_copy(addr, vir2phys(&v), sizeof(v));
- return v;
- }
-
if((r=lin_lin_copy(NULL, addr,
- proc_addr(SYSTEM), vir2phys(&v), sizeof(v))) != OK) {
+ proc_addr(SYSTEM), (phys_bytes) &v, sizeof(v))) != OK) {
panic("lin_lin_copy for phys_get32 failed: %d", r);
}
}
#endif
-void vm_stop(void)
-{
- write_cr0(read_cr0() & ~I386_CR0_PG);
-}
-
-static void vm_enable_paging(void)
-{
- u32_t cr0, cr4;
- int pgeok;
-
- psok = _cpufeature(_CPUF_I386_PSE);
- pgeok = _cpufeature(_CPUF_I386_PGE);
-
- cr0= read_cr0();
- cr4= read_cr4();
-
- /* First clear PG and PGE flag, as PGE must be enabled after PG. */
- write_cr0(cr0 & ~I386_CR0_PG);
- write_cr4(cr4 & ~(I386_CR4_PGE | I386_CR4_PSE));
-
- cr0= read_cr0();
- cr4= read_cr4();
-
- /* Our first page table contains 4MB entries. */
- if(psok)
- cr4 |= I386_CR4_PSE;
-
- write_cr4(cr4);
-
- /* First enable paging, then enable global page flag. */
- cr0 |= I386_CR0_PG;
- write_cr0(cr0 );
- cr0 |= I386_CR0_WP;
- write_cr0(cr0);
-
- /* May we enable these features? */
- if(pgeok)
- cr4 |= I386_CR4_PGE;
-
- write_cr4(cr4);
-}
-
-/*===========================================================================*
- * umap_local *
- *===========================================================================*/
-phys_bytes umap_local(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 */
-{
-/* Calculate the physical memory address for a given virtual address. */
- vir_clicks vc; /* the virtual address in clicks */
- phys_bytes pa; /* intermediate variables as phys_bytes */
- phys_bytes seg_base;
-
- if(seg != T && seg != D && seg != S)
- panic("umap_local: wrong seg: %d", 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 */
-
- if (seg != T)
- seg = (vc < rp->p_memmap[D].mem_vir + rp->p_memmap[D].mem_len ? D : S);
- else if (rp->p_memmap[T].mem_len == 0) /* common I&D? */
- seg = D; /* ptrace needs this */
-
- if ((vir_addr>>CLICK_SHIFT) >= rp->p_memmap[seg].mem_vir +
- rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
-
- if (vc >= rp->p_memmap[seg].mem_vir +
- rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
-
- seg_base = (phys_bytes) rp->p_memmap[seg].mem_phys;
- seg_base = seg_base << CLICK_SHIFT; /* segment origin in bytes */
- pa = (phys_bytes) vir_addr;
- pa -= rp->p_memmap[seg].mem_vir << CLICK_SHIFT;
- return(seg_base + pa);
-}
-
/*===========================================================================*
* umap_virtual *
*===========================================================================*/
vir_bytes vir_addr; /* virtual address in bytes within the seg */
vir_bytes bytes; /* # of bytes to be copied */
{
- vir_bytes linear;
phys_bytes phys = 0;
- if(!(linear = umap_local(rp, seg, vir_addr, bytes))) {
- printf("SYSTEM:umap_virtual: umap_local failed\n");
- phys = 0;
- } else {
- if(vm_lookup(rp, linear, &phys, NULL) != OK) {
- printf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%x: 0x%lx failed\n", rp->p_name, seg, vir_addr);
- phys = 0;
- } else {
- if(phys == 0)
- panic("vm_lookup returned phys: %d", phys);
- }
- }
-
+ if(vm_lookup(rp, vir_addr, &phys, NULL) != OK) {
+ printf("SYSTEM:umap_virtual: vm_lookup of %s: seg 0x%x: 0x%lx failed\n", rp->p_name, seg, vir_addr);
+ phys = 0;
+ } else {
+ if(phys == 0)
+ panic("vm_lookup returned phys: %d", phys);
+ }
if(phys == 0) {
printf("SYSTEM:umap_virtual: lookup failed\n");
/* Now make sure addresses are contiguous in physical memory
* so that the umap makes sense.
*/
- if(bytes > 0 && vm_lookup_range(rp, linear, NULL, bytes) != bytes) {
+ if(bytes > 0 && vm_lookup_range(rp, vir_addr, NULL, bytes) != bytes) {
printf("umap_virtual: %s: %lu at 0x%lx (vir 0x%lx) not contiguous\n",
- rp->p_name, bytes, linear, vir_addr);
+ rp->p_name, bytes, vir_addr, vir_addr);
return 0;
}
assert(proc);
assert(physical);
assert(!isemptyp(proc));
-
- if(!HASPT(proc)) {
- *physical = virtual;
- return OK;
- }
+ assert(HASPT(proc));
/* Retrieve page directory entry. */
root = (u32_t *) proc->p_seg.p_cr3;
assert(proc);
assert(bytes > 0);
-
- if (!HASPT(proc))
- return bytes;
+ assert(HASPT(proc));
/* Look up the first page. */
if (vm_lookup(proc, vir_addr, &phys, NULL) != OK)
*/
int r;
- if (!vm_running)
- return EFAULT;
-
if ((caller->p_misc_flags & MF_KCALL_RESUME) &&
(r = caller->p_vmrequest.vmresult) != OK)
return r;
assert(rp->p_misc_flags & MF_DELIVERMSG);
assert(rp->p_delivermsg.m_source != NONE);
- if (copy_msg_to_user(rp, &rp->p_delivermsg,
+ if (copy_msg_to_user(&rp->p_delivermsg,
(message *) rp->p_delivermsg_vir)) {
printf("WARNING wrong user pointer 0x%08lx from "
"process %s / %d\n",
/* NONE for physical, otherwise virtual */
if(who != NONE) {
int n;
- vir_bytes lin;
- assert(vm_running);
if(!isokendpt(who, &n)) return ESRCH;
whoptr = proc_addr(n);
- if(!(lin = umap_local(whoptr, D, ph, bytes))) return EFAULT;
- ph = lin;
}
p = c | (c << 8) | (c << 16) | (c << 24);
- if(!vm_running) {
- if(who != NONE) panic("can't vm_memset without vm running");
- phys_memset(ph, p, bytes);
- return OK;
- }
-
- assert(nfreepdes >= MAX_FREEPDES);
-
assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v);
assert(!catch_pagefaults);
{
/* Copy bytes from virtual address src_addr to virtual address dst_addr. */
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;
+ int i, r;
struct proc *procs[2];
assert((vmcheck && caller) || (!vmcheck && !caller));
vir_addr[_DST_] = dst_addr;
for (i=_SRC_; i<=_DST_; i++) {
- int proc_nr, type;
+ endpoint_t proc_e = vir_addr[i]->proc_nr_e;
+ int proc_nr;
struct proc *p;
- type = vir_addr[i]->segment & SEGMENT_TYPE;
- if((type != PHYS_SEG) && isokendpt(vir_addr[i]->proc_nr_e, &proc_nr))
- p = proc_addr(proc_nr);
- else
+ if(proc_e == NONE) {
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) {
- printf("virtual_copy: map 0x%x failed for %s seg %d, "
- "offset %lx, len %lu, i %d\n",
- type, p->p_name, seg_index, vir_addr[i]->offset,
- bytes, i);
- }
- break;
- case PHYS_SEG:
- phys_addr[i] = vir_addr[i]->offset;
- break;
- default:
- printf("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) {
- printf("virtual_copy EFAULT\n");
- return EFAULT;
- }
- }
-
- if(vm_running) {
- int r;
-
- if(caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
- assert(caller->p_vmrequest.vmresult != VMSUSPEND);
- if(caller->p_vmrequest.vmresult != OK) {
- return caller->p_vmrequest.vmresult;
- }
- }
-
- if((r=lin_lin_copy(procs[_SRC_], phys_addr[_SRC_],
- procs[_DST_], phys_addr[_DST_], bytes)) != OK) {
- struct proc *target = NULL;
- phys_bytes lin;
- if(r != EFAULT_SRC && r != EFAULT_DST)
- panic("lin_lin_copy failed: %d", r);
- if(!vmcheck || !caller) {
- return r;
- }
-
- if(r == EFAULT_SRC) {
- lin = phys_addr[_SRC_];
- target = procs[_SRC_];
- } else if(r == EFAULT_DST) {
- lin = phys_addr[_DST_];
- target = procs[_DST_];
- } else {
- panic("r strange: %d", r);
+ } else {
+ if(!isokendpt(proc_e, &proc_nr)) {
+ printf("virtual_copy: no reasonable endpoint\n");
+ return ESRCH;
}
-
- assert(caller);
- assert(target);
-
- vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL);
- return VMSUSPEND;
+ p = proc_addr(proc_nr);
}
- return OK;
+ procs[i] = p;
}
- assert(!vm_running);
+ if(caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
+ assert(caller->p_vmrequest.vmresult != VMSUSPEND);
+ if(caller->p_vmrequest.vmresult != OK) {
+ return caller->p_vmrequest.vmresult;
+ }
+ }
- /* can't copy to/from process with PT without VM */
-#define NOPT(p) (!(p) || !HASPT(p))
- if(!NOPT(procs[_SRC_])) {
- printf("ignoring page table src: %s / %d at 0x%x\n",
- procs[_SRC_]->p_name, procs[_SRC_]->p_endpoint, procs[_SRC_]->p_seg.p_cr3);
-}
- if(!NOPT(procs[_DST_])) {
- printf("ignoring page table dst: %s / %d at 0x%x\n",
- procs[_DST_]->p_name, procs[_DST_]->p_endpoint,
- procs[_DST_]->p_seg.p_cr3);
+ if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
+ procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {
+ struct proc *target = NULL;
+ phys_bytes lin;
+ if(r != EFAULT_SRC && r != EFAULT_DST)
+ panic("lin_lin_copy failed: %d", r);
+ if(!vmcheck || !caller) {
+ return r;
+ }
+
+ if(r == EFAULT_SRC) {
+ lin = vir_addr[_SRC_]->offset;
+ target = procs[_SRC_];
+ } else if(r == EFAULT_DST) {
+ lin = vir_addr[_DST_]->offset;
+ target = procs[_DST_];
+ } else {
+ panic("r strange: %d", r);
+ }
+
+ assert(caller);
+ assert(target);
+
+ vm_suspend(caller, target, lin, bytes, VMSTYPE_KERNELCALL);
+ return VMSUSPEND;
}
- /* Now copy bytes between physical addresseses. */
- if(phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes))
- return EFAULT;
-
return OK;
}
{
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;
+ assert(src.proc_nr_e != NONE);
+ assert(dst.proc_nr_e != NONE);
return virtual_copy(&src, &dst, 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;
+ assert(src.proc_nr_e != NONE);
+ assert(dst.proc_nr_e != NONE);
return virtual_copy_vmcheck(caller, &src, &dst, bytes);
}
+void memory_init(void)
+{
+ assert(nfreepdes == 0);
+
+ freepdes[nfreepdes++] = kinfo.freepde_start++;
+ freepdes[nfreepdes++] = kinfo.freepde_start++;
+
+ assert(kinfo.freepde_start < I386_VM_DIR_ENTRIES);
+ assert(nfreepdes == 2);
+ assert(nfreepdes <= MAXFREEPDES);
+}
+
/*===========================================================================*
- * arch_pre_exec *
+ * arch_proc_init *
*===========================================================================*/
-void arch_pre_exec(struct proc *pr, const u32_t ip, const u32_t sp)
+void arch_proc_init(struct proc *pr, const u32_t ip, const u32_t sp, char *name)
{
-/* set program counter and stack pointer. */
+ arch_proc_reset(pr);
+ strcpy(pr->p_name, name);
+
+ /* set custom state we know */
pr->p_reg.pc = ip;
pr->p_reg.sp = sp;
}
-/* VM reports page directory slot we're allowed to use freely. */
-void i386_freepde(const int pde)
-{
- if(nfreepdes >= MAX_FREEPDES)
- return;
- freepdes[nfreepdes++] = pde;
-}
-
static int oxpcie_mapping_index = -1,
lapic_mapping_index = -1,
ioapic_first_index = -1,
- ioapic_last_index = -1;
+ ioapic_last_index = -1,
+ video_mem_mapping_index = -1;
+
+extern char *video_mem;
int arch_phys_map(const int index,
phys_bytes *addr,
static char *ser_var = NULL;
if(first) {
+ video_mem_mapping_index = freeidx++;
+
#ifdef USE_APIC
if(lapic_addr)
lapic_mapping_index = freeidx++;
}
}
#endif
+
first = 0;
}
#ifdef USE_APIC
- /* map the local APIC if enabled */
- if (index == lapic_mapping_index) {
+ if (index == video_mem_mapping_index) {
+ /* map video memory in so we can print panic messages */
+ *addr = MULTIBOOT_VIDEO_BUFFER;
+ *len = I386_PAGE_SIZE;
+ *flags = 0;
+ return OK;
+ }
+ else if (index == lapic_mapping_index) {
+ /* map the local APIC if enabled */
if (!lapic_addr)
return EINVAL;
- *addr = vir2phys(lapic_addr);
+ *addr = lapic_addr;
*len = 4 << 10 /* 4kB */;
*flags = VMMF_UNCACHED;
return OK;
}
- else if (ioapic_enabled && index <= nioapics) {
+ else if (ioapic_enabled && index <= ioapic_last_index) {
*addr = io_apic[index - 1].paddr;
*len = 4 << 10 /* 4kB */;
*flags = VMMF_UNCACHED;
}
else if (ioapic_enabled && index >= ioapic_first_index &&
index <= ioapic_last_index) {
- io_apic[index - ioapic_first_index].vaddr = addr;
+ int i = index - ioapic_first_index;
+ io_apic[i].vaddr = addr;
return OK;
}
#endif
return OK;
}
#endif
+ if (index == video_mem_mapping_index) {
+ video_mem_vaddr = addr;
+ return OK;
+ }
return EINVAL;
}
-int arch_enable_paging(struct proc * caller, const message * m_ptr)
+int arch_enable_paging(struct proc * caller)
{
- struct vm_ep_data ep_data;
- int r;
-
- /* switch_address_space() checks what is in cr3, and do nothing if it's
- * the same as the cr3 of its argument, newptproc. If MINIX was
- * previously booted, this could very well be the case.
- *
- * The first time switch_address_space() is called, we want to
- * force it to do something (load cr3 and set newptproc), so we
- * zero cr3, and force paging off to make that a safe thing to do.
- *
- * After that, segmentation2paging() enables paging with the page table
- * of caller loaded.
- */
-
- vm_stop();
- write_cr3(0);
+ assert(caller->p_seg.p_cr3);
- /* switch from segmentation only to paging */
- segmentation2paging(caller);
+ /* load caller's page table */
+ switch_address_space(caller);
- vm_running = 1;
-
- /*
- * copy the extra data associated with the call from userspace
- */
- if((r=data_copy(caller->p_endpoint, (vir_bytes)m_ptr->SVMCTL_VALUE,
- KERNEL, (vir_bytes) &ep_data, sizeof(ep_data))) != OK) {
- printf("vmctl_enable_paging: data_copy failed! (%d)\n", r);
- return r;
- }
-
- /*
- * when turning paging on i386 we also change the segment limits to make
- * the special mappings requested by the kernel reachable
- */
- if ((r = prot_set_kern_seg_limit(ep_data.data_seg_limit)) != OK)
- return r;
-
- /*
- * install the new map provided by the call
- */
- if (newmap(caller, caller, ep_data.mem_map) != OK)
- panic("arch_enable_paging: newmap failed");
+ video_mem = (char *) video_mem_vaddr;
#ifdef USE_APIC
/* start using the virtual addresses */
#if CONFIG_SMP
barrier();
- i386_paging_enabled = 1;
-
wait_for_APs_to_finish_booting();
#endif
#endif
phys_bytes addr;
for (addr = start; addr < end; addr += increment) {
- phys_copy (addr, vir2phys(buff), size);
+ phys_copy (addr, (phys_bytes) buff, size);
if (cmp_f(buff)) {
if (phys_addr)
*phys_addr = addr;
IMPORT(copr_not_available_handler)
IMPORT(params_size)
IMPORT(params_offset)
-IMPORT(mon_ds)
IMPORT(switch_to_user)
IMPORT(multiboot_init)
.text
-/*===========================================================================*/
-/* MINIX */
-/*===========================================================================*/
-.global MINIX
-MINIX:
-/* this is the entry point for the MINIX kernel */
-
- jmp _C_LABEL(multiboot_init)
-
-/* Multiboot header here*/
-
-.balign 8
-
-multiboot_magic:
- .long MULTIBOOT_HEADER_MAGIC
-multiboot_flags:
- .long MULTIBOOT_FLAGS
-multiboot_checksum:
- .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_FLAGS)
- .long 0
- .long 0
- .long 0
- .long 0
- .long 0
-/* Video mode */
-multiboot_mode_type:
- .long MULTIBOOT_VIDEO_MODE_EGA
-multiboot_width:
- .long MULTIBOOT_CONSOLE_COLS
-multiboot_height:
- .long MULTIBOOT_CONSOLE_LINES
-multiboot_depth:
- .long 0
-
-.globl kernel_init
-kernel_init: /* after pre-init*/
- push %ebp
- mov %esp, %ebp
- push %esi
- push %edi
-/* Copy the monitor global descriptor table to the address space of kernel and */
-/* switch over to it. Prot_init() can then update it with immediate effect. */
-
- sgdt _C_LABEL(gdt)+GDT_SELECTOR /* get the monitor gdtr */
- movl _C_LABEL(gdt)+GDT_SELECTOR+2, %esi /* absolute address of GDT */
- mov $_C_LABEL(gdt), %ebx /* address of kernel GDT */
- mov $8*8, %ecx /* copying eight descriptors */
-copygdt:
- movb %es:(%esi), %al
- movb %al, (%ebx)
- inc %esi
- inc %ebx
- loop copygdt
- movl _C_LABEL(gdt)+DS_SELECTOR+2, %eax /* base of kernel data */
- and $0x00FFFFFF, %eax /* only 24 bits */
- add $_C_LABEL(gdt), %eax /* eax = vir2phys(gdt) */
- movl %eax, _C_LABEL(gdt)+GDT_SELECTOR+2 /* set base of GDT */
- lgdt _C_LABEL(gdt)+GDT_SELECTOR /* switch over to kernel GDT */
-
-/* Locate boot parameters, set up kernel segment registers and stack. */
- mov 8(%ebp), %ebx /* boot parameters offset */
- mov 12(%ebp), %edx /* boot parameters length */
- mov 16(%ebp), %eax /* address of a.out headers */
- mov %ds, %ax /* kernel data */
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
- mov $_C_LABEL(k_boot_stktop) - 4, %esp /* set sp to point to the top of kernel stack */
-
-/* Save boot parameters into these global variables for i386 code */
- movl %edx, _C_LABEL(params_size)
- movl %ebx, _C_LABEL(params_offset)
- movl $SS_SELECTOR, _C_LABEL(mon_ds)
-
-/* Call C startup code to set up a proper environment to run main(). */
- push %edx
- push %ebx
- push $SS_SELECTOR
- push $DS_SELECTOR
- push $CS_SELECTOR
- call _C_LABEL(cstart) /* cstart(cs, ds, mds, parmoff, parmlen) */
- add $5*4, %esp
-
-/* Reload gdtr, idtr and the segment registers to global descriptor table set */
-/* up by prot_init(). */
-
- lgdt _C_LABEL(gdt)+GDT_SELECTOR
- lidt _C_LABEL(gdt)+IDT_SELECTOR
-
- ljmp $CS_SELECTOR, $csinit
-csinit:
- movw $DS_SELECTOR, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
- movw $TSS_SELECTOR_BOOT, %ax /* no other TSS is used */
- ltr %ax
- push $0 /* set flags to known good state */
- popf /* esp, clear nested task and int enable */
- jmp _C_LABEL(main) /* main() */
-
-
/*===========================================================================*/
/* interrupt handlers */
/* interrupt handlers for 386 32-bit protected mode */
mov 4(%esp), %ebp /* will assume P_STACKBASE == 0 */
/* reconstruct the stack for iret */
- movl SSREG(%ebp), %eax
- push %eax
+ push $USER_DS_SELECTOR /* ss */
movl SPREG(%ebp), %eax
push %eax
movl PSWREG(%ebp), %eax
push %eax
- movl CSREG(%ebp), %eax
- push %eax
+ push $USER_CS_SELECTOR /* cs */
movl PCREG(%ebp), %eax
push %eax
- RESTORE_GP_REGS(%ebp)
+ /* Restore segments as the user should see them. */
+ movw $USER_DS_SELECTOR, %si
+ movw %si, %ds
+ movw %si, %es
+ movw %si, %fs
+ movw %si, %gs
- RESTORE_SEGS(%ebp)
+ /* Same for general-purpose registers. */
+ RESTORE_GP_REGS(%ebp)
- movl %ss:BPREG(%ebp), %ebp
+ movl BPREG(%ebp), %ebp
iret /* continue process */
* we are in protected mode now, %cs is correct and we need to set the
* data descriptors before we can touch anything
*/
- movw $DS_SELECTOR, %ax
+ movw $KERN_DS_SELECTOR, %ax
mov %ax, %ds
mov %ax, %ss
mov %ax, %es
.data
.short 0x526F /* this must be the first data entry (magic #) */
.bss
+k_initial_stack:
+.space K_STACK_SIZE
+LABEL(__k_unpaged_k_initial_stktop)
+
/*
* the kernel stack
*/
+++ /dev/null
-#include "kernel/kernel.h" /* configures the kernel */
-#include <minix/config.h>
-#include <minix/const.h>
-#include <minix/com.h>
-#include <machine/asm.h>
-#include <machine/interrupt.h>
-#include "archconst.h"
-#include "kernel/const.h"
-#include "kernel/proc.h"
-#include "sconst.h"
-#include <machine/multiboot.h>
-
-#define GDT_SET_ENTRY(selector, base, limit) \
- mov %ebp, %edi; \
- add $(_C_LABEL(gdt) + selector), %edi; \
- mov base, %eax; \
- movw %ax, 2(%edi); \
- shr $16, %eax; \
- movb %al, 4(%edi); \
- and $0xff00, %ax; \
- andw $0xff, 6(%edi); \
- or %ax, 6(%edi); \
- mov limit, %eax; \
- movw %ax, (%edi); \
- shr $16, %eax; \
- and $0xf, %ax; \
- andb $0xf0, 6(%edi); \
- or %ax, 6(%edi); \
-
-IMPORT(pre_init)
-.extern kernel_init
-
-ENTRY(multiboot_init)
- mov $(GDT_SIZE*DESC_SIZE), %eax
- mov $(_C_LABEL(gdt) + GDT_SELECTOR), %edi
- mov %ax, (%edi)
- mov $_C_LABEL(gdt), %eax
- mov %eax, 2(%edi)
- lgdt (%edi)
- ljmp $(CS_SELECTOR), $reload_cs
-
-reload_cs:
- mov $DS_SELECTOR, %eax
- mov %eax, %ds
- mov %eax, %ss
- mov %eax, %es
- mov %eax, %fs
- mov %eax, %gs
-
- mov $(multiboot_stack + MULTIBOOT_STACK_SIZE), %esp
-
- push %ebx
- call _C_LABEL(pre_init)
-
- add $4, %esp
-
- /* return to old boot code of kernel */
- push %eax
- push $MULTIBOOT_PARAM_BUF_SIZE
- push $_C_LABEL(multiboot_param_buf)
- push $0
-
- mov $ES_SELECTOR, %eax
- mov %eax, %es
-
- jmp kernel_init
-
-.data
-LABEL(multiboot_param_buf)
- .space MULTIBOOT_PARAM_BUF_SIZE
-
-multiboot_stack:
-.space MULTIBOOT_STACK_SIZE + 4
--- /dev/null
+
+#include <minix/cpufeature.h>
+
+#include <minix/type.h>
+#include <libexec.h>
+#include <assert.h>
+#include "kernel.h"
+#include "arch_proto.h"
+
+#include <string.h>
+#include <libexec.h>
+#include <minix/type.h>
+
+/* These are set/computed in kernel.lds. */
+extern char _kern_vir_base, _kern_phys_base, _kern_size;
+
+/* Retrieve the absolute values to something we can use. */
+static phys_bytes kern_vir_start = (phys_bytes) &_kern_vir_base;
+static phys_bytes kern_phys_start = (phys_bytes) &_kern_phys_base;
+static phys_bytes kern_kernlen = (phys_bytes) &_kern_size;
+
+/* page directory we can use to map things */
+static u32_t pagedir[1024] __aligned(4096);
+
+void cut_memmap(kinfo_t *cbi, phys_bytes start, phys_bytes end)
+{
+ int m;
+ phys_bytes o;
+
+ if((o=start % I386_PAGE_SIZE))
+ start -= o;
+ if((o=end % I386_PAGE_SIZE))
+ end += I386_PAGE_SIZE - o;
+
+ for(m = 0; m < cbi->mmap_size; m++) {
+ phys_bytes substart = start, subend = end;
+ phys_bytes memaddr = cbi->memmap[m].addr,
+ memend = cbi->memmap[m].addr + cbi->memmap[m].len;
+
+ /* adjust cut range to be a subset of the free memory */
+ if(substart < memaddr) substart = memaddr;
+ if(subend > memend) subend = memend;
+ if(substart >= subend) continue;
+
+ /* if there is any overlap, forget this one and add
+ * 1-2 subranges back
+ */
+ cbi->memmap[m].addr = cbi->memmap[m].len = 0;
+ if(substart > memaddr)
+ add_memmap(cbi, memaddr, substart-memaddr);
+ if(subend < memend)
+ add_memmap(cbi, subend, memend-subend);
+ }
+}
+
+void add_memmap(kinfo_t *cbi, u64_t addr, u64_t len)
+{
+ int m;
+ phys_bytes highmark;
+#define LIMIT 0xFFFFF000
+ /* Truncate available memory at 4GB as the rest of minix
+ * currently can't deal with any bigger.
+ */
+ if(addr > LIMIT) return;
+ if(addr + len > LIMIT) {
+ len -= (addr + len - LIMIT);
+ }
+ assert(cbi->mmap_size < MAXMEMMAP);
+ if(len == 0) return;
+ addr = roundup(addr, I386_PAGE_SIZE);
+ len = rounddown(len, I386_PAGE_SIZE);
+ for(m = 0; m < MAXMEMMAP; m++) {
+ if(cbi->memmap[m].len) continue;
+ cbi->memmap[m].addr = addr;
+ cbi->memmap[m].len = len;
+ cbi->memmap[m].type = MULTIBOOT_MEMORY_AVAILABLE;
+ if(m >= cbi->mmap_size)
+ cbi->mmap_size = m+1;
+ return;
+ }
+
+ highmark = addr + len;
+ if(highmark > cbi->mem_high_phys)
+ cbi->mem_high_phys = highmark;
+
+ panic("no available memmap slot");
+}
+
+u32_t *alloc_pagetable(phys_bytes *ph)
+{
+ u32_t *ret;
+#define PG_PAGETABLES 3
+ static u32_t pagetables[PG_PAGETABLES][1024] __aligned(4096);
+ static int pt_inuse = 0;
+ if(pt_inuse >= PG_PAGETABLES) panic("no more pagetables");
+ assert(sizeof(pagetables[pt_inuse]) == I386_PAGE_SIZE);
+ ret = pagetables[pt_inuse++];
+ *ph = vir2phys(ret);
+ return ret;
+}
+
+#define PAGE_KB (I386_PAGE_SIZE / 1024)
+
+phys_bytes pg_alloc_page(kinfo_t *cbi)
+{
+ int m;
+ multiboot_memory_map_t *mmap;
+ for(m = cbi->mmap_size-1; m >= 0; m--) {
+ mmap = &cbi->memmap[m];
+ if(!mmap->len) continue;
+ assert(mmap->len > 0);
+ assert(!(mmap->len % I386_PAGE_SIZE));
+ assert(!(mmap->addr % I386_PAGE_SIZE));
+
+ mmap->len -= I386_PAGE_SIZE;
+
+ return mmap->addr + mmap->len;
+ }
+
+ panic("can't find free memory");
+}
+
+void pg_identity(void)
+{
+ int i;
+ phys_bytes phys;
+
+ /* Set up an identity mapping page directory */
+ for(i = 0; i < I386_VM_DIR_ENTRIES; i++) {
+ phys = i * I386_BIG_PAGE_SIZE;
+ pagedir[i] = phys | I386_VM_PRESENT | I386_VM_BIGPAGE |
+ I386_VM_USER | I386_VM_WRITE;
+ }
+}
+
+int pg_mapkernel(void)
+{
+ int pde;
+ u32_t mapped = 0, kern_phys = kern_phys_start;
+
+ assert(!(kern_vir_start % I386_BIG_PAGE_SIZE));
+ assert(!(kern_phys % I386_BIG_PAGE_SIZE));
+ pde = kern_vir_start / I386_BIG_PAGE_SIZE; /* start pde */
+ while(mapped < kern_kernlen) {
+ pagedir[pde] = kern_phys | I386_VM_PRESENT |
+ I386_VM_BIGPAGE | I386_VM_WRITE;
+ mapped += I386_BIG_PAGE_SIZE;
+ kern_phys += I386_BIG_PAGE_SIZE;
+ pde++;
+ }
+ return pde; /* free pde */
+}
+
+void vm_enable_paging(void)
+{
+ u32_t cr0, cr4;
+ int pgeok;
+
+ pgeok = _cpufeature(_CPUF_I386_PGE);
+
+ cr0= read_cr0();
+ cr4= read_cr4();
+
+ /* The boot loader should have put us in protected mode. */
+ assert(cr0 & I386_CR0_PE);
+
+ /* First clear PG and PGE flag, as PGE must be enabled after PG. */
+ write_cr0(cr0 & ~I386_CR0_PG);
+ write_cr4(cr4 & ~(I386_CR4_PGE | I386_CR4_PSE));
+
+ cr0= read_cr0();
+ cr4= read_cr4();
+
+ /* Our page table contains 4MB entries. */
+ cr4 |= I386_CR4_PSE;
+
+ write_cr4(cr4);
+
+ /* First enable paging, then enable global page flag. */
+ cr0 |= I386_CR0_PG;
+ write_cr0(cr0);
+ cr0 |= I386_CR0_WP;
+ write_cr0(cr0);
+
+ /* May we enable these features? */
+ if(pgeok)
+ cr4 |= I386_CR4_PGE;
+
+ write_cr4(cr4);
+}
+
+phys_bytes pg_load()
+{
+ phys_bytes phpagedir = vir2phys(pagedir);
+ write_cr3(phpagedir);
+ return phpagedir;
+}
+
+void pg_clear(void)
+{
+ memset(pagedir, 0, sizeof(pagedir));
+}
+
+phys_bytes pg_rounddown(phys_bytes b)
+{
+ phys_bytes o;
+ if(!(o = b % I386_PAGE_SIZE))
+ return b;
+ return b - o;
+}
+
+void pg_map(phys_bytes phys, vir_bytes vaddr, vir_bytes vaddr_end,
+ kinfo_t *cbi)
+{
+ static int mapped_pde = -1;
+ static u32_t *pt = NULL;
+ int pde, pte;
+
+ if(phys == PG_ALLOCATEME) {
+ assert(!(vaddr % I386_PAGE_SIZE));
+ } else {
+ assert((vaddr % I386_PAGE_SIZE) == (phys % I386_PAGE_SIZE));
+ vaddr = pg_rounddown(vaddr);
+ phys = pg_rounddown(phys);
+ }
+ assert(vaddr < kern_vir_start);
+
+ while(vaddr < vaddr_end) {
+ phys_bytes source = phys;
+ assert(!(vaddr % I386_PAGE_SIZE));
+ if(phys == PG_ALLOCATEME) {
+ source = pg_alloc_page(cbi);
+ } else {
+ assert(!(phys % I386_PAGE_SIZE));
+ }
+ assert(!(source % I386_PAGE_SIZE));
+ pde = I386_VM_PDE(vaddr);
+ pte = I386_VM_PTE(vaddr);
+ if(mapped_pde < pde) {
+ phys_bytes ph;
+ pt = alloc_pagetable(&ph);
+ pagedir[pde] = (ph & I386_VM_ADDR_MASK)
+ | I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE;
+ mapped_pde = pde;
+ }
+ assert(pt);
+ pt[pte] = (source & I386_VM_ADDR_MASK) |
+ I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE;
+ vaddr += I386_PAGE_SIZE;
+ if(phys != PG_ALLOCATEME)
+ phys += I386_PAGE_SIZE;
+ }
+}
+
+void pg_info(reg_t *pagedir_ph, u32_t **pagedir_v)
+{
+ *pagedir_ph = vir2phys(pagedir);
+ *pagedir_v = pagedir;
+}
+
-#include "kernel/kernel.h"
+
+#define UNPAGED 1 /* for proper kmain() prototype */
+
+#include "kernel.h"
+#include <assert.h>
+#include <stdlib.h>
#include <minix/minlib.h>
#include <minix/const.h>
-/*
- * == IMPORTANT ==
- * Routines in this file can not use any variable in kernel BSS,
- * since before image is extracted, no BSS is allocated.
- * So pay attention to any external call (including library call).
- *
- * */
#include <minix/types.h>
#include <minix/type.h>
#include <minix/com.h>
#include <sys/param.h>
+#include <sys/reboot.h>
#include <machine/partition.h>
#include "string.h"
#include "arch_proto.h"
#include "libexec.h"
-#include "mb_utils.h"
+#include "direct_utils.h"
#include "serial.h"
+#include "glo.h"
#include <machine/multiboot.h>
#if USE_SYSDEBUG
#define MULTIBOOT_VERBOSE 1
#endif
-/* FIXME: Share this define with kernel linker script */
-#define MULTIBOOT_KERNEL_ADDR 0x00200000UL
+/* to-be-built kinfo struct, diagnostics buffer */
+kinfo_t kinfo;
+struct kmessages kmess;
-/* Granularity used in image file and copying */
-#define GRAN 512
-#define SECT_CEIL(x) ((((x) - 1) / GRAN + 1) * GRAN)
+/* pg_utils.c uses this; in this phase, there is a 1:1 mapping. */
+phys_bytes vir2phys(void *addr) { return (phys_bytes) addr; }
+
+/* mb_utils.c uses this; we can reach it directly */
+char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
/* String length used for mb_itoa */
#define ITOA_BUFFER_SIZE 20
-#define mb_load_phymem(buf, phy, len) \
- phys_copy((phy), (u32_t)(buf), (len))
-
-#define mb_save_phymem(buf, phy, len) \
- phys_copy((u32_t)(buf), (phy), (len))
-
-#define mb_clear_memrange(start, end) \
- phys_memset((start), 0, (end)-(start))
-
-static void mb_itoa(u32_t val, char * out)
-{
- char ret[ITOA_BUFFER_SIZE];
- int i = ITOA_BUFFER_SIZE - 2;
- /* Although there's a library version of itoa(int n),
- * we can't use it since that implementation relies on BSS segment
- */
- ret[ITOA_BUFFER_SIZE - 2] = '0';
- if (val) {
- for (; i >= 0; i--) {
- char c;
- if (val == 0) break;
- c = val % 10;
- val = val / 10;
- c += '0';
- ret[i] = c;
- }
- }
- else
- i--;
- ret[ITOA_BUFFER_SIZE - 1] = 0;
- strcpy(out, ret + i + 1);
-}
-
-static void mb_itox(u32_t val, char *out)
-{
- char ret[9];
- int i = 7;
- /* Convert a number to hex string */
- ret[7] = '0';
- if (val) {
- for (; i >= 0; i--) {
- char c;
- if (val == 0) break;
- c = val & 0xF;
- val = val >> 4;
- if (c > 9)
- c += 'A' - 10;
- else
- c += '0';
- ret[i] = c;
- }
- }
- else
- i--;
- ret[8] = 0;
- strcpy(out, ret + i + 1);
-}
-
-static void mb_put_char(char c, int line, int col)
+static int mb_set_param(char *bigbuf, char *name, char *value, kinfo_t *cbi)
{
- /* Write a char to vga display buffer. */
- if (line<MULTIBOOT_CONSOLE_LINES&&col<MULTIBOOT_CONSOLE_COLS)
- mb_save_phymem(
- &c,
- MULTIBOOT_VIDEO_BUFFER
- + line * MULTIBOOT_CONSOLE_COLS * 2
- + col * 2,
- 1);
-}
-
-static char mb_get_char(int line, int col)
-{
- char c;
- /* Read a char to from display buffer. */
- if (line < MULTIBOOT_CONSOLE_LINES && col < MULTIBOOT_CONSOLE_COLS)
- mb_load_phymem(
- &c,
- MULTIBOOT_VIDEO_BUFFER
- + line * MULTIBOOT_CONSOLE_COLS * 2
- + col * 2,
- 1);
- return c;
-}
-
-/* Give non-zero values to avoid them in BSS */
-static int print_line = 1, print_col = 1;
-
-#include <sys/video.h>
-
-void mb_cls(void)
-{
- int i, j;
- /* Clear screen */
- for (i = 0; i < MULTIBOOT_CONSOLE_LINES; i++ )
- for (j = 0; j < MULTIBOOT_CONSOLE_COLS; j++ )
- mb_put_char(0, i, j);
- print_line = print_col = 0;
-
- /* Tell video hardware origin is 0. */
- outb(C_6845+INDEX, VID_ORG);
- outb(C_6845+DATA, 0);
- outb(C_6845+INDEX, VID_ORG+1);
- outb(C_6845+DATA, 0);
-}
-
-static void mb_scroll_up(int lines)
-{
- int i, j;
- for (i = 0; i < MULTIBOOT_CONSOLE_LINES; i++ ) {
- for (j = 0; j < MULTIBOOT_CONSOLE_COLS; j++ ) {
- char c = 0;
- if(i < MULTIBOOT_CONSOLE_LINES-lines)
- c = mb_get_char(i + lines, j);
- mb_put_char(c, i, j);
- }
- }
- print_line-= lines;
-}
-
-void mb_print_char(char c)
-{
- while (print_line >= MULTIBOOT_CONSOLE_LINES)
- mb_scroll_up(1);
-
- if (c == '\n') {
- while (print_col < MULTIBOOT_CONSOLE_COLS)
- mb_put_char(' ', print_line, print_col++);
- print_line++;
- print_col = 0;
- return;
- }
-
- mb_put_char(c, print_line, print_col++);
-
- if (print_col >= MULTIBOOT_CONSOLE_COLS) {
- print_line++;
- print_col = 0;
- }
-
- while (print_line >= MULTIBOOT_CONSOLE_LINES)
- mb_scroll_up(1);
-}
-
-void mb_print(char *str)
-{
- while (*str) {
- mb_print_char(*str);
- str++;
- }
-}
-
-/* Standard and AT keyboard. (PS/2 MCA implies AT throughout.) */
-#define KEYBD 0x60 /* I/O port for keyboard data */
-#define KB_STATUS 0x64 /* I/O port for status on AT */
-#define KB_OUT_FULL 0x01 /* status bit set when keypress char pending */
-#define KB_AUX_BYTE 0x20 /* Auxiliary Device Output Buffer Full */
-
-int mb_read_char(unsigned char *ch)
-{
- unsigned long b, sb;
-#ifdef DEBUG_SERIAL
- u8_t c, lsr;
-
- if (do_serial_debug) {
- lsr= inb(COM1_LSR);
- if (!(lsr & LSR_DR))
- return 0;
- c = inb(COM1_RBR);
- return 1;
- }
-#endif /* DEBUG_SERIAL */
-
- sb = inb(KB_STATUS);
-
- if (!(sb & KB_OUT_FULL)) {
- return 0;
- }
-
- b = inb(KEYBD);
-
- if (!(sb & KB_AUX_BYTE))
- return 1;
-
- return 0;
-}
-
-static void mb_print_hex(u32_t value)
-{
- int i;
- char c;
- char out[9] = "00000000";
- /* Print a hex value */
- for (i = 7; i >= 0; i--) {
- c = value % 0x10;
- value /= 0x10;
- if (c < 10)
- c += '0';
- else
- c += 'A'-10;
- out[i] = c;
- }
- mb_print(out);
-}
-
-static int mb_set_param(char *name, char *value)
-{
- char *p = multiboot_param_buf;
+ char *p = bigbuf;
+ char *bufend = bigbuf + MULTIBOOT_PARAM_BUF_SIZE;
char *q;
int namelen = strlen(name);
int valuelen = strlen(value);
-
+
+ /* Some variables we recognize */
+ if(!strcmp(name, SERVARNAME)) { cbi->do_serial_debug = 1; return 0; }
+ if(!strcmp(name, SERBAUDVARNAME)) { cbi->serial_debug_baud = atoi(value); return 0; }
+
/* Delete the item if already exists */
while (*p) {
if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
q = p;
while (*q) q++;
- for (q++;
- q < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE;
- q++, p++)
+ for (q++; q < bufend; q++, p++)
*p = *q;
break;
}
p++;
}
- for (p = multiboot_param_buf;
- p < multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE
- && (*p || *(p + 1));
- p++)
+ for (p = bigbuf; p < bufend && (*p || *(p + 1)); p++)
;
- if (p > multiboot_param_buf) p++;
+ if (p > bigbuf) p++;
/* Make sure there's enough space for the new parameter */
- if (p + namelen + valuelen + 3
- > multiboot_param_buf + MULTIBOOT_PARAM_BUF_SIZE)
+ if (p + namelen + valuelen + 3 > bufend)
return -1;
strcpy(p, name);
return 0;
}
-static void get_parameters(multiboot_info_t *mbi)
+int overlaps(multiboot_module_t *mod, int n, int cmp_mod)
{
- char mem_value[40], temp[ITOA_BUFFER_SIZE];
- int i;
- int dev;
- int ctrlr;
- int disk, prim, sub;
- int var_i,value_i;
- char *p;
- const static int dev_cNd0[] = { 0x0300, 0x0800, 0x0A00, 0x0C00, 0x1000 };
- static char mb_cmd_buff[GRAN] = "add some value to avoid me in BSS";
- static char var[GRAN] = "add some value to avoid me in BSS";
- static char value[GRAN] = "add some value to avoid me in BSS";
- for (i = 0; i < MULTIBOOT_PARAM_BUF_SIZE; i++)
- multiboot_param_buf[i] = 0;
-
- if (mbi->flags & MULTIBOOT_INFO_BOOTDEV) {
- disk = ((mbi->boot_device&0xff000000) >> 24)-0x80;
- prim = (mbi->boot_device & 0xff0000) >> 16;
- if (prim == 0xff)
- prim = 0;
- sub = (mbi->boot_device & 0xff00) >> 8;
- if (sub == 0xff)
- sub = 0;
- ctrlr = 0;
- dev = dev_cNd0[ctrlr];
-
- /* Determine the value of rootdev */
- dev += 0x80
- + (disk * NR_PARTITIONS + prim) * NR_PARTITIONS + sub;
-
- mb_itoa(dev, temp);
- mb_set_param("rootdev", temp);
- mb_set_param("ramimagedev", temp);
+ multiboot_module_t *cmp = &mod[cmp_mod];
+ int m;
+
+#define INRANGE(mod, v) ((v) >= mod->mod_start && (v) <= thismod->mod_end)
+#define OVERLAP(mod1, mod2) (INRANGE(mod1, mod2->mod_start) || \
+ INRANGE(mod1, mod2->mod_end))
+ for(m = 0; m < n; m++) {
+ multiboot_module_t *thismod = &mod[m];
+ if(m == cmp_mod) continue;
+ if(OVERLAP(thismod, cmp))
+ return 1;
}
- mb_set_param("hz", "60");
-
- if (mbi->flags & MULTIBOOT_INFO_MEMORY)
- {
- strcpy(mem_value, "800:");
- mb_itox(
- mbi->mem_lower * 1024 > MULTIBOOT_LOWER_MEM_MAX ?
- MULTIBOOT_LOWER_MEM_MAX : mbi->mem_lower * 1024,
- temp);
- strcat(mem_value, temp);
- strcat(mem_value, ",100000:");
- mb_itox(mbi->mem_upper * 1024, temp);
- strcat(mem_value, temp);
- mb_set_param("memory", mem_value);
+ return 0;
+}
+
+void print_memmap(kinfo_t *cbi)
+{
+ int m;
+ assert(cbi->mmap_size < MAXMEMMAP);
+ for(m = 0; m < cbi->mmap_size; m++) {
+ printf("%08lx-%08lx ",cbi->memmap[m].addr, cbi->memmap[m].addr + cbi->memmap[m].len);
}
-
+ printf("\nsize %08lx\n", cbi->mmap_size);
+}
+
+void get_parameters(u32_t ebx, kinfo_t *cbi)
+{
+ multiboot_memory_map_t *mmap;
+ multiboot_info_t *mbi = &cbi->mbi;
+ int var_i,value_i, m, k;
+ char *p;
+ extern char _kern_phys_base, _kern_vir_base, _kern_size,
+ _kern_unpaged_start, _kern_unpaged_end;
+ phys_bytes kernbase = (phys_bytes) &_kern_phys_base,
+ kernsize = (phys_bytes) &_kern_size;
+#define BUF 1024
+ static char cmdline[BUF];
+
+ /* get our own copy of the multiboot info struct and module list */
+ memcpy((void *) mbi, (void *) ebx, sizeof(*mbi));
+
+ /* Set various bits of info for the higher-level kernel. */
+ cbi->mem_high_phys = 0;
+ cbi->user_sp = (vir_bytes) &_kern_vir_base;
+ cbi->vir_kern_start = (vir_bytes) &_kern_vir_base;
+ cbi->bootstrap_start = (vir_bytes) &_kern_unpaged_start;
+ cbi->bootstrap_len = (vir_bytes) &_kern_unpaged_end -
+ cbi->bootstrap_start;
+ cbi->kmess = &kmess;
+
+ /* set some configurable defaults */
+ cbi->do_serial_debug = 0;
+ cbi->serial_debug_baud = 115200;
+
+ /* parse boot command line */
if (mbi->flags&MULTIBOOT_INFO_CMDLINE) {
+ static char var[BUF];
+ static char value[BUF];
+
/* Override values with cmdline argument */
- p = mb_cmd_buff;
- mb_load_phymem(mb_cmd_buff, mbi->cmdline, GRAN);
+ memcpy(cmdline, (void *) mbi->cmdline, BUF);
+ p = cmdline;
while (*p) {
var_i = 0;
value_i = 0;
while (*p == ' ') p++;
if (!*p) break;
- while (*p && *p != '=' && *p != ' ' && var_i < GRAN - 1)
+ while (*p && *p != '=' && *p != ' ' && var_i < BUF - 1)
var[var_i++] = *p++ ;
var[var_i] = 0;
if (*p++ != '=') continue; /* skip if not name=value */
- while (*p && *p != ' ' && value_i < GRAN - 1)
+ while (*p && *p != ' ' && value_i < BUF - 1)
value[value_i++] = *p++ ;
value[value_i] = 0;
- mb_set_param(var, value);
+ mb_set_param(cbi->param_buf, var, value, cbi);
}
}
-}
-
-static void mb_extract_image(multiboot_info_t mbi)
-{
- phys_bytes start_paddr = 0x5000000;
- multiboot_module_t *mb_module_info;
- multiboot_module_t *module;
- u32_t mods_count = mbi.mods_count;
- int r, i;
- vir_bytes text_vaddr, text_filebytes, text_membytes;
- vir_bytes data_vaddr, data_filebytes, data_membytes;
- phys_bytes text_paddr, data_paddr;
- vir_bytes stack_bytes;
- vir_bytes pc;
- off_t text_offset, data_offset;
- /* Save memory map for kernel tasks */
- r = read_header_elf((char *) MULTIBOOT_KERNEL_ADDR,
- 4096, /* everything is there */
- &text_vaddr, &text_paddr,
- &text_filebytes, &text_membytes,
- &data_vaddr, &data_paddr,
- &data_filebytes, &data_membytes,
- &pc, &text_offset, &data_offset);
-
- for (i = 0; i < NR_TASKS; ++i) {
- image[i].memmap.text_vaddr = trunc_page(text_vaddr);
- image[i].memmap.text_paddr = trunc_page(text_paddr);
- image[i].memmap.text_bytes = text_membytes;
- image[i].memmap.data_vaddr = trunc_page(data_vaddr);
- image[i].memmap.data_paddr = trunc_page(data_paddr);
- image[i].memmap.data_bytes = data_membytes;
- image[i].memmap.stack_bytes = 0;
- image[i].memmap.entry = pc;
+ /* round user stack down to leave a gap to catch kernel
+ * stack overflow; and to distinguish kernel and user addresses
+ * at a glance (0xf.. vs 0xe..)
+ */
+ cbi->user_sp &= 0xF0000000;
+ cbi->user_end = cbi->user_sp;
+
+ assert(!(cbi->bootstrap_start % I386_PAGE_SIZE));
+ cbi->bootstrap_len = rounddown(cbi->bootstrap_len, I386_PAGE_SIZE);
+ assert(mbi->flags & MULTIBOOT_INFO_MODS);
+ assert(mbi->mods_count < MULTIBOOT_MAX_MODS);
+ assert(mbi->mods_count > 0);
+ memcpy(&cbi->module_list, (void *) mbi->mods_addr,
+ mbi->mods_count * sizeof(multiboot_module_t));
+
+ memset(cbi->memmap, 0, sizeof(cbi->memmap));
+ /* mem_map has a variable layout */
+ if(mbi->flags & MULTIBOOT_INFO_MEM_MAP) {
+ cbi->mmap_size = 0;
+ for (mmap = (multiboot_memory_map_t *) mbi->mmap_addr;
+ (unsigned long) mmap < mbi->mmap_addr + mbi->mmap_length;
+ mmap = (multiboot_memory_map_t *)
+ ((unsigned long) mmap + mmap->size + sizeof(mmap->size))) {
+ if(mmap->type != MULTIBOOT_MEMORY_AVAILABLE) continue;
+ add_memmap(cbi, mmap->addr, mmap->len);
+ }
+ } else {
+ assert(mbi->flags & MULTIBOOT_INFO_MEMORY);
+ add_memmap(cbi, 0, mbi->mem_lower_unused*1024);
+ add_memmap(cbi, 0x100000, mbi->mem_upper_unused*1024);
}
-#ifdef MULTIBOOT_VERBOSE
- mb_print("\nKernel: ");
- mb_print_hex(trunc_page(text_paddr));
- mb_print("-");
- mb_print_hex(trunc_page(data_paddr) + data_membytes);
- mb_print(" Entry: ");
- mb_print_hex(pc);
-#endif
-
- mb_module_info = ((multiboot_module_t *)mbi.mods_addr);
- module = &mb_module_info[0];
-
- /* Load boot image services into memory and save memory map */
- for (i = 0; module < &mb_module_info[mods_count]; ++module, ++i) {
- r = read_header_elf((char *) module->mod_start,
- module->mod_end - module->mod_start + 1,
- &text_vaddr, &text_paddr,
- &text_filebytes, &text_membytes,
- &data_vaddr, &data_paddr,
- &data_filebytes, &data_membytes,
- &pc, &text_offset, &data_offset);
- if (r) {
- mb_print("fatal: ELF parse failure\n");
- /* Spin here */
- while (1)
- ;
- }
-
- stack_bytes = image[NR_TASKS+i].stack_kbytes * 1024;
-
- text_paddr = start_paddr + (text_vaddr & PAGE_MASK);
-
- /* Load text segment */
- phys_copy(module->mod_start+text_offset, text_paddr,
- text_filebytes);
- mb_clear_memrange(text_paddr+text_filebytes,
- round_page(text_paddr) + text_membytes);
-
- data_paddr = round_page((text_paddr + text_membytes));
- data_paddr += data_vaddr & PAGE_MASK;
- /* start of next module */
- start_paddr = round_page(data_paddr + data_membytes + stack_bytes);
-
- /* Load data and stack segments */
- phys_copy(module->mod_start+data_offset, data_paddr, data_filebytes);
- mb_clear_memrange(data_paddr+data_filebytes, start_paddr);
-
- /* Save memmap for non-kernel tasks, so subscript past kernel
- tasks. */
- image[NR_TASKS+i].memmap.text_vaddr = trunc_page(text_vaddr);
- image[NR_TASKS+i].memmap.text_paddr = trunc_page(text_paddr);
- image[NR_TASKS+i].memmap.text_bytes = text_membytes;
- image[NR_TASKS+i].memmap.data_vaddr = trunc_page(data_vaddr);
- image[NR_TASKS+i].memmap.data_paddr = trunc_page(data_paddr);
- image[NR_TASKS+i].memmap.data_bytes = data_membytes;
- image[NR_TASKS+i].memmap.stack_bytes = stack_bytes;
- image[NR_TASKS+i].memmap.entry = pc;
-
-#ifdef MULTIBOOT_VERBOSE
- mb_print("\n");
- mb_print_hex(i);
- mb_print(": ");
- mb_print_hex(trunc_page(text_paddr));
- mb_print("-");
- mb_print_hex(trunc_page(data_paddr) + data_membytes + stack_bytes);
- mb_print(" Entry: ");
- mb_print_hex(pc);
- mb_print(" Stack: ");
- mb_print_hex(stack_bytes);
- mb_print(" ");
- mb_print((char *)module->cmdline);
+ /* Sanity check: the kernel nor any of the modules may overlap
+ * with each other. Pretend the kernel is an extra module for a
+ * second.
+ */
+ k = mbi->mods_count;
+ assert(k < MULTIBOOT_MAX_MODS);
+ cbi->module_list[k].mod_start = kernbase;
+ cbi->module_list[k].mod_end = kernbase + kernsize;
+ cbi->mods_with_kernel = mbi->mods_count+1;
+ cbi->kern_mod = k;
+
+ for(m = 0; m < cbi->mods_with_kernel; m++) {
+#if 0
+ printf("checking overlap of module %08lx-%08lx\n",
+ cbi->module_list[m].mod_start, cbi->module_list[m].mod_end);
#endif
+ if(overlaps(cbi->module_list, cbi->mods_with_kernel, m))
+ panic("overlapping boot modules/kernel");
+ /* We cut out the bits of memory that we know are
+ * occupied by the kernel and boot modules.
+ */
+ cut_memmap(cbi,
+ cbi->module_list[m].mod_start,
+ cbi->module_list[m].mod_end);
}
-
- return;
}
-phys_bytes pre_init(u32_t ebx)
+kinfo_t *pre_init(u32_t magic, u32_t ebx)
{
- multiboot_info_t mbi;
-
- /* Do pre-initialization for multiboot, returning physical address of
- * of multiboot module info
- */
- mb_cls();
- mb_print("\nMINIX booting... ");
- mb_load_phymem(&mbi, ebx, sizeof(mbi));
- get_parameters(&mbi);
- mb_print("\nLoading image... ");
- mb_extract_image(mbi);
- return mbi.mods_addr;
+ /* Get our own copy boot params pointed to by ebx.
+ * Here we find out whether we should do serial output.
+ */
+ get_parameters(ebx, &kinfo);
+
+ /* Say hello. */
+ printf("MINIX loading\n");
+
+ assert(magic == MULTIBOOT_BOOTLOADER_MAGIC);
+
+ /* Make and load a pagetable that will map the kernel
+ * to where it should be; but first a 1:1 mapping so
+ * this code stays where it should be.
+ */
+ pg_clear();
+ pg_identity();
+ kinfo.freepde_start = pg_mapkernel();
+ pg_load();
+ vm_enable_paging();
+
+ /* Done, return boot info so it can be passed to kmain(). */
+ return &kinfo;
}
+
+int send_sig(endpoint_t proc_nr, int sig_nr) { return 0; }
+void minix_shutdown(timer_t *t) { arch_shutdown(RBT_PANIC); }
+void busy_delay_ms(int x) { }
include "proc.h"
struct proc
-member GSREG p_reg.gs
-member FSREG p_reg.fs
-member ESREG p_reg.es
-member DSREG p_reg.ds
member DIREG p_reg.di
member SIREG p_reg.si
member BPREG p_reg.fp
member CSREG p_reg.cs
member PSWREG p_reg.psw
member SPREG p_reg.sp
-member SSREG p_reg.ss
-member P_LDT_SEL p_seg.p_ldt_sel
member P_CR3 p_seg.p_cr3
-member P_CR3_V p_seg.p_cr3_v
-member P_LDT p_seg.p_ldt
-
* for local descriptors in the process table.
*/
+#include <string.h>
+#include <assert.h>
+#include <machine/multiboot.h>
+
#include "kernel/kernel.h"
#include "kernel/proc.h"
#include "archconst.h"
#include "arch_proto.h"
+#include <libexec.h>
+
#define INT_GATE_TYPE (INT_286_GATE | DESC_386_BIT)
#define TSS_TYPE (AVL_286_TSS | DESC_386_BIT)
-struct desctableptr_s {
- char limit[sizeof(u16_t)];
- char base[sizeof(u32_t)]; /* really u24_t + pad for 286 */
-};
+/* This is OK initially, when the 1:1 mapping is still there. */
+char *video_mem = (char *) MULTIBOOT_VIDEO_BUFFER;
struct gatedesc_s {
u16_t offset_low;
u8_t pad; /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
u8_t p_dpl_type; /* |P|DL|0|TYPE| */
u16_t offset_high;
-};
+} __attribute__((packed));
+/* Storage for gdt, idt and tss. */
+static struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE);
+struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE);
+struct tss_s tss[CONFIG_MAX_CPUS];
-/* used in klib.s and mpx.s */
-struct segdesc_s gdt[GDT_SIZE] __aligned(DESC_SIZE) =
-{ {0},
- {0,0,0,0}, /* GDT descriptor */
- {0,0,0,0}, /* IDT descriptor */
- {0xffff,0,0,0x93,0xcf,0}, /* kernel DS */
- {0xffff,0,0,0x93,0xcf,0}, /* kernel ES (386: flag 4 Gb at startup) */
- {0xffff,0,0,0x93,0xcf,0}, /* kernel SS (386: monitor SS at startup) */
- {0xffff,0,0,0x9b,0xcf,0}, /* kernel CS */
- {0xffff,0,0,0x9b,0xcf,0}, /* temp for BIOS (386: monitor CS at startup) */
-};
-
-/* zero-init so none present */
-static struct gatedesc_s idt[IDT_SIZE] __aligned(DESC_SIZE);
-struct tss_s tss[CONFIG_MAX_CPUS]; /* zero init */
-
-static void sdesc(struct segdesc_s *segdp, phys_bytes base, vir_bytes
- size);
+phys_bytes vir2phys(void *vir)
+{
+ extern char _kern_vir_base, _kern_phys_base; /* in kernel.lds */
+ u32_t offset = (vir_bytes) &_kern_vir_base -
+ (vir_bytes) &_kern_phys_base;
+ return (phys_bytes)vir - offset;
+}
/*===========================================================================*
* enable_iop *
pp->p_reg.psw |= 0x3000;
}
+
/*===========================================================================*
- * seg2phys *
+ * sdesc *
*===========================================================================*/
-phys_bytes seg2phys(const u16_t seg)
+ void sdesc(struct segdesc_s *segdp, phys_bytes base, vir_bytes size)
{
-/* Return the base address of a segment, with seg being a
- * register, or a 286/386 segment selector.
- */
- phys_bytes base;
- struct segdesc_s *segdp;
-
- segdp = &gdt[seg >> 3];
- base = ((u32_t) segdp->base_low << 0)
- | ((u32_t) segdp->base_middle << 16)
- | ((u32_t) segdp->base_high << 24);
- return base;
+/* Fill in the size fields (base, limit and granularity) of a descriptor. */
+ segdp->base_low = base;
+ segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
+ segdp->base_high = base >> BASE_HIGH_SHIFT;
+
+ --size; /* convert to a limit, 0 size means 4G */
+ if (size > BYTE_GRAN_MAX) {
+ segdp->limit_low = size >> PAGE_GRAN_SHIFT;
+ segdp->granularity = GRANULAR | (size >>
+ (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
+ } else {
+ segdp->limit_low = size;
+ segdp->granularity = size >> GRANULARITY_SHIFT;
+ }
+ segdp->granularity |= DEFAULT; /* means BIG for data seg */
}
/*===========================================================================*
* init_dataseg *
*===========================================================================*/
-void init_dataseg(register struct segdesc_s *segdp,
+void init_param_dataseg(register struct segdesc_s *segdp,
phys_bytes base, vir_bytes size, const int privilege)
{
/* Build descriptor for a data segment. */
sdesc(segdp, base, size);
segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT |
- WRITEABLE);
+ WRITEABLE | ACCESSED);
/* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
}
+void init_dataseg(int index, const int privilege)
+{
+ init_param_dataseg(&gdt[index], 0, 0xFFFFFFFF, privilege);
+}
+
/*===========================================================================*
* init_codeseg *
*===========================================================================*/
-static void init_codeseg(register struct segdesc_s *segdp, phys_bytes base,
- vir_bytes size, int privilege)
+static void init_codeseg(int index, int privilege)
{
/* Build descriptor for a code segment. */
- sdesc(segdp, base, size);
- segdp->access = (privilege << DPL_SHIFT)
+ sdesc(&gdt[index], 0, 0xFFFFFFFF);
+ gdt[index].access = (privilege << DPL_SHIFT)
| (PRESENT | SEGMENT | EXECUTABLE | READABLE);
/* CONFORMING = 0, ACCESSED = 0 */
}
-struct gate_table_s gate_table_pic[] = {
+static struct gate_table_s gate_table_pic[] = {
{ hwint00, VECTOR( 0), INTR_PRIVILEGE },
{ hwint01, VECTOR( 1), INTR_PRIVILEGE },
{ hwint02, VECTOR( 2), INTR_PRIVILEGE },
{ NULL, 0, 0}
};
-void tss_init(unsigned cpu, void * kernel_stack)
+static struct gate_table_s gate_table_exceptions[] = {
+ { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE },
+ { single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE },
+ { nmi, NMI_VECTOR, INTR_PRIVILEGE },
+ { breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE },
+ { overflow, OVERFLOW_VECTOR, USER_PRIVILEGE },
+ { bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE },
+ { inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE },
+ { copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE },
+ { double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE },
+ { copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE },
+ { inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE },
+ { segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE },
+ { stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE },
+ { general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE },
+ { page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE },
+ { copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE },
+ { alignment_check, ALIGNMENT_CHECK_VECTOR, INTR_PRIVILEGE },
+ { machine_check, MACHINE_CHECK_VECTOR, INTR_PRIVILEGE },
+ { simd_exception, SIMD_EXCEPTION_VECTOR, INTR_PRIVILEGE },
+ { ipc_entry, IPC_VECTOR, USER_PRIVILEGE },
+ { kernel_call_entry, KERN_CALL_VECTOR, USER_PRIVILEGE },
+ { NULL, 0, 0}
+};
+
+int tss_init(unsigned cpu, void * kernel_stack)
{
struct tss_s * t = &tss[cpu];
+ int index = TSS_INDEX(cpu);
+ struct segdesc_s *tssgdt;
+
+ tssgdt = &gdt[index];
- t->ss0 = DS_SELECTOR;
- init_dataseg(&gdt[TSS_INDEX(cpu)], vir2phys(t),
+ init_param_dataseg(tssgdt, (phys_bytes) t,
sizeof(struct tss_s), INTR_PRIVILEGE);
- gdt[TSS_INDEX(cpu)].access = PRESENT |
- (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
+ tssgdt->access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
- /* Complete building of main TSS. */
+ /* Build TSS. */
+ memset(t, 0, sizeof(*t));
+ t->ds = t->es = t->fs = t->gs = t->ss0 = KERN_DS_SELECTOR;
+ t->cs = KERN_CS_SELECTOR;
t->iobase = sizeof(struct tss_s); /* empty i/o permissions map */
/*
* this stak in use when we trap to kernel
*/
*((reg_t *)(t->sp0 + 1 * sizeof(reg_t))) = cpu;
+
+ return SEG_SELECTOR(index);
}
-/*===========================================================================*
- * prot_init *
- *===========================================================================*/
-void prot_init(void)
+phys_bytes init_segdesc(int gdt_index, void *base, int size)
{
-/* Set up tables for protected mode.
- * All GDT slots are allocated at compile time.
- */
- struct desctableptr_s *dtp;
- unsigned ldt_index;
- register struct proc *rp;
-
- /* Click-round kernel. */
- if(kinfo.data_base % CLICK_SIZE)
- panic("kinfo.data_base not aligned");
- kinfo.data_size = (phys_bytes) (CLICK_CEIL(kinfo.data_size));
-
- /* Build gdt and idt pointers in GDT where the BIOS expects them. */
- dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
- * (u16_t *) dtp->limit = (sizeof gdt) - 1;
- * (u32_t *) dtp->base = vir2phys(gdt);
-
- dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
- * (u16_t *) dtp->limit = (sizeof idt) - 1;
- * (u32_t *) dtp->base = vir2phys(idt);
-
- /* Build segment descriptors for tasks and interrupt handlers. */
- init_codeseg(&gdt[CS_INDEX],
- kinfo.code_base, kinfo.code_size, INTR_PRIVILEGE);
- init_dataseg(&gdt[DS_INDEX],
- kinfo.data_base, kinfo.data_size, INTR_PRIVILEGE);
- init_dataseg(&gdt[ES_INDEX], 0L, 0, INTR_PRIVILEGE);
-
- /* Build local descriptors in GDT for LDT's in process table.
- * The LDT's are allocated at compile time in the process table, and
- * initialized whenever a process' map is initialized or changed.
- */
- for (rp = BEG_PROC_ADDR, ldt_index = FIRST_LDT_INDEX;
- rp < END_PROC_ADDR; ++rp, ldt_index++) {
- init_dataseg(&gdt[ldt_index], vir2phys(rp->p_seg.p_ldt),
- sizeof(rp->p_seg.p_ldt), INTR_PRIVILEGE);
- gdt[ldt_index].access = PRESENT | LDT;
- rp->p_seg.p_ldt_sel = ldt_index * DESC_SIZE;
- }
+ struct desctableptr_s *dtp = (struct desctableptr_s *) &gdt[gdt_index];
+ dtp->limit = size - 1;
+ dtp->base = (phys_bytes) base;
+
+ return (phys_bytes) dtp;
+}
+
+void int_gate(struct gatedesc_s *tab,
+ unsigned vec_nr, vir_bytes offset, unsigned dpl_type)
+{
+/* Build descriptor for an interrupt gate. */
+ register struct gatedesc_s *idp;
+
+ idp = &tab[vec_nr];
+ idp->offset_low = offset;
+ idp->selector = KERN_CS_SELECTOR;
+ idp->p_dpl_type = dpl_type;
+ idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
+}
- /* Build boot TSS */
- tss_init(0, &k_boot_stktop);
+void int_gate_idt(unsigned vec_nr, vir_bytes offset, unsigned dpl_type)
+{
+ int_gate(idt, vec_nr, offset, dpl_type);
}
void idt_copy_vectors(struct gate_table_s * first)
{
struct gate_table_s *gtp;
for (gtp = first; gtp->gate; gtp++) {
- int_gate(gtp->vec_nr, (vir_bytes) gtp->gate,
+ int_gate(idt, gtp->vec_nr, (vir_bytes) gtp->gate,
PRESENT | INT_GATE_TYPE |
(gtp->privilege << DPL_SHIFT));
}
}
-/* Build descriptors for interrupt gates in IDT. */
-void idt_init(void)
+void idt_copy_vectors_pic(void)
{
- struct gate_table_s gate_table[] = {
- { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE },
- { single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE },
- { nmi, NMI_VECTOR, INTR_PRIVILEGE },
- { breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE },
- { overflow, OVERFLOW_VECTOR, USER_PRIVILEGE },
- { bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE },
- { inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE },
- { copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE },
- { double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE },
- { copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE },
- { inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE },
- { segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE },
- { stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE },
- { general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE },
- { page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE },
- { copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE },
- { alignment_check, ALIGNMENT_CHECK_VECTOR, INTR_PRIVILEGE },
- { machine_check, MACHINE_CHECK_VECTOR, INTR_PRIVILEGE },
- { simd_exception, SIMD_EXCEPTION_VECTOR, INTR_PRIVILEGE },
- { ipc_entry, IPC_VECTOR, USER_PRIVILEGE },
- { kernel_call_entry, KERN_CALL_VECTOR, USER_PRIVILEGE },
- { NULL, 0, 0}
- };
-
- idt_copy_vectors(gate_table);
idt_copy_vectors(gate_table_pic);
}
-
-/*===========================================================================*
- * sdesc *
- *===========================================================================*/
-static void sdesc(segdp, base, size)
-register struct segdesc_s *segdp;
-phys_bytes base;
-vir_bytes size;
+void idt_init(void)
{
-/* Fill in the size fields (base, limit and granularity) of a descriptor. */
- segdp->base_low = base;
- segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
- segdp->base_high = base >> BASE_HIGH_SHIFT;
-
- --size; /* convert to a limit, 0 size means 4G */
- if (size > BYTE_GRAN_MAX) {
- segdp->limit_low = size >> PAGE_GRAN_SHIFT;
- segdp->granularity = GRANULAR | (size >>
- (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
- } else {
- segdp->limit_low = size;
- segdp->granularity = size >> GRANULARITY_SHIFT;
- }
- segdp->granularity |= DEFAULT; /* means BIG for data seg */
+ idt_copy_vectors_pic();
+ idt_copy_vectors(gate_table_exceptions);
}
-/*===========================================================================*
- * int_gate *
- *===========================================================================*/
-void int_gate(unsigned vec_nr, vir_bytes offset, unsigned dpl_type)
-{
-/* Build descriptor for an interrupt gate. */
- register struct gatedesc_s *idp;
+struct desctableptr_s gdt_desc, idt_desc;
- idp = &idt[vec_nr];
- idp->offset_low = offset;
- idp->selector = CS_SELECTOR;
- idp->p_dpl_type = dpl_type;
- idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
-}
-
-/*===========================================================================*
- * alloc_segments *
- *===========================================================================*/
-void alloc_segments(register struct proc *rp)
+void idt_reload(void)
{
-/* This is called at system initialization from main() and by do_newmap().
- * The code has a separate function because of all hardware-dependencies.
- */
- phys_bytes code_bytes;
- phys_bytes data_bytes;
- phys_bytes text_vaddr, data_vaddr;
- phys_bytes text_segbase, data_segbase;
- int privilege;
-
- data_bytes = (phys_bytes) (rp->p_memmap[S].mem_vir +
- rp->p_memmap[S].mem_len) << CLICK_SHIFT;
- if (rp->p_memmap[T].mem_len == 0)
- code_bytes = data_bytes; /* common I&D, poor protect */
- else
- code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
- privilege = USER_PRIVILEGE;
-
- text_vaddr = rp->p_memmap[T].mem_vir << CLICK_SHIFT;
- data_vaddr = rp->p_memmap[D].mem_vir << CLICK_SHIFT;
- text_segbase = (rp->p_memmap[T].mem_phys -
- rp->p_memmap[T].mem_vir) << CLICK_SHIFT;
- data_segbase = (rp->p_memmap[D].mem_phys -
- rp->p_memmap[D].mem_vir) << CLICK_SHIFT;
-
- init_codeseg(&rp->p_seg.p_ldt[CS_LDT_INDEX],
- text_segbase,
- text_vaddr + code_bytes, privilege);
- init_dataseg(&rp->p_seg.p_ldt[DS_LDT_INDEX],
- data_segbase,
- data_vaddr + data_bytes, privilege);
- rp->p_reg.cs = (CS_LDT_INDEX * DESC_SIZE) | TI | privilege;
- rp->p_reg.gs =
- rp->p_reg.fs =
- rp->p_reg.ss =
- rp->p_reg.es =
- rp->p_reg.ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
+ x86_lidt(&idt_desc);
}
-#if 0
-/*===========================================================================*
- * check_segments *
- *===========================================================================*/
-static void check_segments(char *File, int line)
+multiboot_module_t *bootmod(int pnr)
{
- int checked = 0;
-int fail = 0;
-struct proc *rp;
-for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
-
- int privilege;
- int cs, ds;
-
- if (isemptyp(rp))
- continue;
+ int i;
- privilege = USER_PRIVILEGE;
+ assert(pnr >= 0);
- cs = (CS_LDT_INDEX*DESC_SIZE) | TI | privilege;
- ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
-
-#define CHECK(s1, s2) if(s1 != s2) { \
- printf("%s:%d: " #s1 " != " #s2 " for ep %d\n", \
- File, line, rp->p_endpoint); fail++; } checked++;
-
- CHECK(rp->p_reg.cs, cs);
- CHECK(rp->p_reg.gs, ds);
- CHECK(rp->p_reg.fs, ds);
- CHECK(rp->p_reg.ss, ds);
- if(rp->p_endpoint != SYSTEM) {
- CHECK(rp->p_reg.es, ds);
+ /* Search for desired process in boot process
+ * list. The first NR_TASKS ones do not correspond
+ * to a module, however, so we don't search those.
+ */
+ for(i = NR_TASKS; i < NR_BOOT_PROCS; i++) {
+ int p;
+ p = i - NR_TASKS;
+ if(image[i].proc_nr == pnr) {
+ assert(p < MULTIBOOT_MAX_MODS);
+ assert(p < kinfo.mbi.mods_count);
+ return &kinfo.module_list[p];
+ }
}
- CHECK(rp->p_reg.ds, ds);
- }
- if(fail) {
- printf("%d/%d checks failed\n", fail, checked);
- panic("wrong: %d", fail);
- }
+
+ panic("boot module %d not found", pnr);
}
-#endif
/*===========================================================================*
- * printseg *
+ * prot_init *
*===========================================================================*/
-void printseg(char *banner, const int iscs, struct proc *pr,
- const u32_t selector)
+void prot_init()
{
-#if USE_SYSDEBUG
- u32_t base, limit, index, dpl;
- struct segdesc_s *desc;
-
- if(banner) { printf("%s", banner); }
-
- index = selector >> 3;
-
- printf("RPL %d, ind %d of ",
- (selector & RPL_MASK), index);
-
- if(selector & TI) {
- printf("LDT");
- if(index >= LDT_SIZE) {
- printf("invalid index in ldt\n");
- return;
- }
- if(!pr) {
- printf("local selector but unknown process\n");
- return;
- }
- desc = &pr->p_seg.p_ldt[index];
- } else {
- printf("GDT");
- if(index >= GDT_SIZE) {
- printf("invalid index in gdt\n");
- return;
- }
- desc = &gdt[index];
- }
-
- limit = desc->limit_low |
- (((u32_t) desc->granularity & LIMIT_HIGH) << GRANULARITY_SHIFT);
-
- if(desc->granularity & GRANULAR) {
- limit = (limit << PAGE_GRAN_SHIFT) + 0xfff;
- }
-
- base = desc->base_low |
- ((u32_t) desc->base_middle << BASE_MIDDLE_SHIFT) |
- ((u32_t) desc->base_high << BASE_HIGH_SHIFT);
-
- printf(" -> base 0x%08lx size 0x%08lx ", base, limit+1);
-
- if(iscs) {
- if(!(desc->granularity & BIG))
- printf("16bit ");
- } else {
- if(!(desc->granularity & BIG))
- printf("not big ");
- }
-
- if(desc->granularity & 0x20) { /* reserved */
- panic("granularity reserved field set");
- }
-
- if(!(desc->access & PRESENT))
- printf("notpresent ");
-
- if(!(desc->access & SEGMENT))
- printf("system ");
-
- if(desc->access & EXECUTABLE) {
- printf(" exec ");
- if(desc->access & CONFORMING) printf("conforming ");
- if(!(desc->access & READABLE)) printf("non-readable ");
- } else {
- printf("nonexec ");
- if(desc->access & EXPAND_DOWN) printf("non-expand-down ");
- if(!(desc->access & WRITEABLE)) printf("non-writable ");
- }
-
- if(!(desc->access & ACCESSED)) {
- printf("nonacc ");
- }
+ int sel_tss;
+ extern char k_boot_stktop;
+
+ memset(gdt, 0, sizeof(gdt));
+ memset(idt, 0, sizeof(idt));
+
+ /* Build GDT, IDT, IDT descriptors. */
+ gdt_desc.base = (u32_t) gdt;
+ gdt_desc.limit = sizeof(gdt)-1;
+ idt_desc.base = (u32_t) idt;
+ idt_desc.limit = sizeof(idt)-1;
+ sel_tss = tss_init(0, &k_boot_stktop);
+
+ /* Build GDT */
+ init_param_dataseg(&gdt[LDT_INDEX],
+ (phys_bytes) 0, 0, INTR_PRIVILEGE); /* unusable LDT */
+ gdt[LDT_INDEX].access = PRESENT | LDT;
+ init_codeseg(KERN_CS_INDEX, INTR_PRIVILEGE);
+ init_dataseg(KERN_DS_INDEX, INTR_PRIVILEGE);
+ init_codeseg(USER_CS_INDEX, USER_PRIVILEGE);
+ init_dataseg(USER_DS_INDEX, USER_PRIVILEGE);
+
+ x86_lgdt(&gdt_desc); /* Load gdt */
+ idt_init();
+ idt_reload();
+ x86_lldt(LDT_SELECTOR); /* Load bogus ldt */
+ x86_ltr(sel_tss); /* Load global TSS */
+
+ /* Currently the multiboot segments are loaded; which is fine, but
+ * let's replace them with the ones from our own GDT so we test
+ * right away whether they work as expected.
+ */
+ x86_load_kerncs();
+ x86_load_ds(KERN_DS_SELECTOR);
+ x86_load_es(KERN_DS_SELECTOR);
+ x86_load_fs(KERN_DS_SELECTOR);
+ x86_load_gs(KERN_DS_SELECTOR);
+ x86_load_ss(KERN_DS_SELECTOR);
+
+ /* Set up a new post-relocate bootstrap pagetable so that
+ * we can map in VM, and we no longer rely on pre-relocated
+ * data.
+ */
- dpl = ((u32_t) desc->access & DPL) >> DPL_SHIFT;
+ pg_clear();
+ pg_identity(); /* Still need 1:1 for lapic and video mem and such. */
+ pg_mapkernel();
+ pg_load();
+ bootstrap_pagetable_done = 1; /* secondary CPU's can use it too */
+}
- printf("DPL %d\n", dpl);
+void arch_post_init(void)
+{
+ /* Let memory mapping code know what's going on at bootstrap time */
+ struct proc *vm;
+ vm = proc_addr(VM_PROC_NR);
+ get_cpulocal_var(ptproc) = vm;
+ pg_info(&vm->p_seg.p_cr3, &vm->p_seg.p_cr3_v);
+}
- return;
-#endif /* USE_SYSDEBUG */
+int libexec_pg_alloc(struct exec_info *execi, off_t vaddr, size_t len)
+{
+ pg_map(PG_ALLOCATEME, vaddr, vaddr+len, &kinfo);
+ pg_load();
+ memset((char *) vaddr, 0, len);
+ return OK;
}
-/*===========================================================================*
- * prot_set_kern_seg_limit *
- *===========================================================================*/
-int prot_set_kern_seg_limit(const vir_bytes limit)
+void arch_boot_proc(struct boot_image *ip, struct proc *rp)
{
- struct proc *rp;
- int orig_click;
- int incr_clicks;
+ multiboot_module_t *mod;
- if(limit <= kinfo.data_base) {
- printf("prot_set_kern_seg_limit: limit bogus\n");
- return EINVAL;
- }
+ if(rp->p_nr < 0) return;
- /* Do actual increase. */
- orig_click = kinfo.data_size / CLICK_SIZE;
- kinfo.data_size = limit - kinfo.data_base;
- incr_clicks = kinfo.data_size / CLICK_SIZE - orig_click;
+ mod = bootmod(rp->p_nr);
- prot_init();
+ /* Important special case: we put VM in the bootstrap pagetable
+ * so it can run.
+ */
- /* Increase kernel processes too. */
- for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
- if (isemptyp(rp) || !iskernelp(rp))
- continue;
- rp->p_memmap[S].mem_len += incr_clicks;
- alloc_segments(rp);
- rp->p_memmap[S].mem_len -= incr_clicks;
+ if(rp->p_nr == VM_PROC_NR) {
+ struct exec_info execi;
+
+ memset(&execi, 0, sizeof(execi));
+
+ /* exec parameters */
+ execi.stack_high = kinfo.user_sp;
+ execi.stack_size = 16 * 1024; /* not too crazy as it must be preallocated */
+ execi.proc_e = ip->endpoint;
+ execi.hdr = (char *) mod->mod_start; /* phys mem direct */
+ execi.hdr_len = mod->mod_end - mod->mod_start;
+ strcpy(execi.progname, ip->proc_name);
+ execi.frame_len = 0;
+
+ /* callbacks for use in the kernel */
+ execi.copymem = libexec_copy_memcpy;
+ execi.clearmem = libexec_clear_memset;
+ execi.allocmem_prealloc = libexec_pg_alloc;
+ execi.allocmem_ondemand = libexec_pg_alloc;
+ execi.clearproc = NULL;
+
+ /* parse VM ELF binary and alloc/map it into bootstrap pagetable */
+ libexec_load_elf(&execi);
+
+ /* Initialize the server stack pointer. Take it down three words
+ * to give startup code something to use as "argc", "argv" and "envp".
+ */
+ arch_proc_init(rp, execi.pc, kinfo.user_sp - 3*4, ip->proc_name);
+
+ /* Free VM blob that was just copied into existence. */
+ cut_memmap(&kinfo, mod->mod_start, mod->mod_end);
}
-
- return OK;
}
* zeroed
*/
#define TEST_INT_IN_KERNEL(displ, label) \
- cmpl $CS_SELECTOR, displ(%esp) ;\
+ cmpl $KERN_CS_SELECTOR, displ(%esp) ;\
je label ;
/*
movl tmp, PSWREG(pptr) ;\
movl (12 + displ)(%esp), tmp ;\
movl tmp, SPREG(pptr) ;\
- movl tmp, STREG(pptr) ;\
- movl (16 + displ)(%esp), tmp ;\
- movl tmp, SSREG(pptr) ;
-
-#define SAVE_SEGS(pptr) \
- mov %ds, %ss:DSREG(pptr) ;\
- mov %es, %ss:ESREG(pptr) ;\
- mov %fs, %ss:FSREG(pptr) ;\
- mov %gs, %ss:GSREG(pptr) ;
-
-#define RESTORE_SEGS(pptr) \
- movw %ss:DSREG(pptr), %ds ;\
- movw %ss:ESREG(pptr), %es ;\
- movw %ss:FSREG(pptr), %fs ;\
- movw %ss:GSREG(pptr), %gs ;
+ movl tmp, STREG(pptr)
/*
- * restore kernel segments, %ss is kernnel data segment, %cs is aready set and
- * %fs, %gs are not used
- */
+ * restore kernel segments. %cs is aready set and %fs, %gs are not used */
#define RESTORE_KERNEL_SEGS \
- mov %ss, %si ;\
+ mov $KERN_DS_SELECTOR, %si ;\
mov %si, %ds ;\
mov %si, %es ;\
movw $0, %si ;\
mov %si, %fs ;
#define SAVE_GP_REGS(pptr) \
- mov %eax, %ss:AXREG(pptr) ;\
- mov %ecx, %ss:CXREG(pptr) ;\
- mov %edx, %ss:DXREG(pptr) ;\
- mov %ebx, %ss:BXREG(pptr) ;\
- mov %esi, %ss:SIREG(pptr) ;\
- mov %edi, %ss:DIREG(pptr) ;
+ mov %eax, AXREG(pptr) ;\
+ mov %ecx, CXREG(pptr) ;\
+ mov %edx, DXREG(pptr) ;\
+ mov %ebx, BXREG(pptr) ;\
+ mov %esi, SIREG(pptr) ;\
+ mov %edi, DIREG(pptr) ;
#define RESTORE_GP_REGS(pptr) \
- movl %ss:AXREG(pptr), %eax ;\
- movl %ss:CXREG(pptr), %ecx ;\
- movl %ss:DXREG(pptr), %edx ;\
- movl %ss:BXREG(pptr), %ebx ;\
- movl %ss:SIREG(pptr), %esi ;\
- movl %ss:DIREG(pptr), %edi ;
+ movl AXREG(pptr), %eax ;\
+ movl CXREG(pptr), %ecx ;\
+ movl DXREG(pptr), %edx ;\
+ movl BXREG(pptr), %ebx ;\
+ movl SIREG(pptr), %esi ;\
+ movl DIREG(pptr), %edi ;
/*
* save the context of the interrupted process to the structure in the process
;\
movl (CURR_PROC_PTR + 4 + displ)(%esp), %ebp ;\
\
- /* save the segment registers */ \
- SAVE_SEGS(%ebp) ;\
- \
SAVE_GP_REGS(%ebp) ;\
pop %esi /* get the orig %ebp and save it */ ;\
- mov %esi, %ss:BPREG(%ebp) ;\
+ mov %esi, BPREG(%ebp) ;\
\
RESTORE_KERNEL_SEGS ;\
SAVE_TRAP_CTX(displ, %ebp, %esi) ;
orb $1, %al
mov %eax, %cr0
- ljmpl $CS_SELECTOR, $_C_LABEL(startup_ap_32)
+ ljmpl $KERN_CS_SELECTOR, $_C_LABEL(startup_ap_32)
.balign 4
LABEL(__ap_id)
}
#ifdef DEBUG_SERIAL
- if (do_serial_debug)
+ if (kinfo.do_serial_debug)
do_ser_debug();
#endif
#define USE_MEMSET 1 /* write char to a given memory area */
#define USE_RUNCTL 1 /* control stop flags of a process */
-/* Length of program names stored in the process table. This is only used
- * for the debugging dumps that can be generated with the IS server. The PM
- * server keeps its own copy of the program name.
- */
-#define P_NAME_LEN 8
-
/* This section contains defines for valuable system resources that are used
* by device drivers. The number of elements of the vectors is determined by
* the maximum needed by any given driver. The number of interrupt hooks may
#define unset_sys_bit(map,bit) \
( MAP_CHUNK((map).chunk,bit) &= ~(1 << CHUNK_OFFSET(bit) ))
-/* args to intr_init() */
-#define INTS_ORIG 0 /* restore interrupts */
-#define INTS_MINIX 1 /* initialize interrupts for minix */
-
/* for kputc() */
#define END_OF_KMESS 0
str[0] = '\0';
FLAG(MF_REPLY_PEND);
- FLAG(MF_FULLVM);
FLAG(MF_DELIVERMSG);
FLAG(MF_KCALL_RESUME);
EXTERN struct kinfo kinfo; /* kernel information for users */
EXTERN struct machine machine; /* machine information for users */
EXTERN struct kmessages kmess; /* diagnostic messages in kernel */
-EXTERN char kmess_buf[80*25]; /* printable copy of message buffer */
EXTERN struct k_randomness krandom; /* gather kernel random information */
EXTERN struct loadinfo kloadinfo; /* status of load average */
EXTERN u32_t system_hz; /* HZ value */
/* Miscellaneous. */
-EXTERN int do_serial_debug;
-EXTERN int serial_debug_baud;
EXTERN time_t boottime;
-EXTERN char params_buffer[512]; /* boot monitor parameters */
-EXTERN int minix_panicing;
EXTERN int verboseboot; /* verbose boot, init'ed in cstart */
-#define MAGICTEST 0xC0FFEE23
-EXTERN u32_t magictest; /* global magic number */
#if DEBUG_TRACE
EXTERN int verboseflags;
#ifdef CONFIG_SMP
EXTERN int config_no_smp; /* optionaly turn off SMP */
#endif
+EXTERN int bootstrap_pagetable_done;
/* VM */
EXTERN int vm_running;
EXTERN int catch_pagefaults;
/* Variables that are initialized elsewhere are just extern here. */
-extern struct boot_image image[]; /* system image processes */
-extern struct segdesc_s gdt[]; /* global descriptor table */
+extern struct boot_image image[NR_BOOT_PROCS]; /* system image processes */
EXTERN volatile int serial_debug_active;
EXTERN unsigned bkl_tries[CONFIG_MAX_CPUS];
EXTERN unsigned bkl_succ[CONFIG_MAX_CPUS];
+/* Feature flags */
+EXTERN int minix_feature_flags;
+
#endif /* GLO_H */
*/
#include "kernel.h"
#include <string.h>
+#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
+#include <libexec.h>
#include <a.out.h>
#include <minix/com.h>
#include <minix/endpoint.h>
+#include <machine/vmparam.h>
#include <minix/u64.h>
+#include <minix/type.h>
#include "proc.h"
#include "debug.h"
#include "clock.h"
machine.processors_count = 1;
machine.bsp_id = 0;
#endif
-
+
switch_to_user();
NOT_REACHABLE;
}
/*===========================================================================*
- * main *
+ * kmain *
*===========================================================================*/
-int main(void)
+void kmain(kinfo_t *local_cbi)
{
/* Start the ball rolling. */
struct boot_image *ip; /* boot image pointer */
register struct proc *rp; /* process pointer */
register int i, j;
- size_t argsz; /* size of arguments passed to crtso on stack */
+
+ /* save a global copy of the boot parameters */
+ memcpy(&kinfo, local_cbi, sizeof(kinfo));
+ memcpy(&kmess, kinfo.kmess, sizeof(kmess));
+
+ /* We can talk now */
+ printf("MINIX booting\n");
+
+ assert(sizeof(kinfo.boot_procs) == sizeof(image));
+ memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
+
+ cstart();
BKL_LOCK();
- /* Global value to test segment sanity. */
- magictest = MAGICTEST;
DEBUGEXTRA(("main()\n"));
proc_init();
- /* Set up proc table entries for processes in boot image. The stacks
- * of the servers have been added to the data segment by the monitor, so
- * the stack pointer is set to the end of the data segment.
- */
-
+ /* Set up proc table entries for processes in boot image. */
for (i=0; i < NR_BOOT_PROCS; ++i) {
int schedulable_proc;
proc_nr_t proc_nr;
rp = proc_addr(ip->proc_nr); /* get process pointer */
ip->endpoint = rp->p_endpoint; /* ipc endpoint */
make_zero64(rp->p_cpu_time_left);
- strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */
+
+ if(i >= NR_TASKS) {
+ /* Remember this so it can be passed to VM */
+ multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS];
+ ip->start_addr = mb_mod->mod_start;
+ ip->len = mb_mod->mod_end - mb_mod->mod_start;
+ }
reset_proc_accounting(rp);
* process has set their privileges.
*/
proc_nr = proc_nr(rp);
- schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr));
+ schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) ||
+ proc_nr == VM_PROC_NR);
if(schedulable_proc) {
/* Assign privilege structure. Force a static privilege id. */
(void) get_priv(rp, static_priv_id(proc_nr));
/* Priviliges for kernel tasks. */
- if(iskerneln(proc_nr)) {
+ if(proc_nr == VM_PROC_NR) {
+ priv(rp)->s_flags = VM_F;
+ priv(rp)->s_trap_mask = SRV_T;
+ ipc_to_m = SRV_M;
+ kcalls = SRV_KC;
+ priv(rp)->s_sig_mgr = SELF;
+ rp->p_priority = SRV_Q;
+ rp->p_quantum_size_ms = SRV_QT;
+ }
+ else if(iskerneln(proc_nr)) {
/* Privilege flags. */
priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
/* Allowed traps. */
/* Don't let the process run for now. */
RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
}
- rp->p_memmap[T].mem_vir = ABS2CLICK(ip->memmap.text_vaddr);
- rp->p_memmap[T].mem_phys = ABS2CLICK(ip->memmap.text_paddr);
- rp->p_memmap[T].mem_len = ABS2CLICK(ip->memmap.text_bytes);
- rp->p_memmap[D].mem_vir = ABS2CLICK(ip->memmap.data_vaddr);
- rp->p_memmap[D].mem_phys = ABS2CLICK(ip->memmap.data_paddr);
- rp->p_memmap[D].mem_len = ABS2CLICK(ip->memmap.data_bytes);
- rp->p_memmap[S].mem_phys = ABS2CLICK(ip->memmap.data_paddr +
- ip->memmap.data_bytes +
- ip->memmap.stack_bytes);
- rp->p_memmap[S].mem_vir = ABS2CLICK(ip->memmap.data_vaddr +
- ip->memmap.data_bytes +
- ip->memmap.stack_bytes);
- rp->p_memmap[S].mem_len = 0;
-
- /* Set initial register values. The processor status word for tasks
- * is different from that of other processes because tasks can
- * access I/O; this is not allowed to less-privileged processes
- */
- rp->p_reg.pc = ip->memmap.entry;
- rp->p_reg.psw = (iskerneln(proc_nr)) ? INIT_TASK_PSW : INIT_PSW;
- /* Initialize the server stack pointer. Take it down three words
- * to give crtso.s something to use as "argc", "argv" and "envp".
- */
- if (isusern(proc_nr)) { /* user-space process? */
- rp->p_reg.sp = (rp->p_memmap[S].mem_vir +
- rp->p_memmap[S].mem_len) << CLICK_SHIFT;
- argsz = 3 * sizeof(reg_t);
- rp->p_reg.sp -= argsz;
- phys_memset(rp->p_reg.sp -
- (rp->p_memmap[S].mem_vir << CLICK_SHIFT) +
- (rp->p_memmap[S].mem_phys << CLICK_SHIFT),
- 0, argsz);
- }
+ /* Arch-specific state initialization. */
+ arch_boot_proc(ip, rp);
/* scheduling functions depend on proc_ptr pointing somewhere. */
if(!get_cpulocal_var(proc_ptr))
get_cpulocal_var(proc_ptr) = rp;
- /* If this process has its own page table, VM will set the
- * PT up and manage it. VM will signal the kernel when it has
- * done this; until then, don't let it run.
- */
- if(ip->flags & PROC_FULLVM)
+ /* Process isn't scheduled until VM has set up a pagetable for it. */
+ if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0)
rp->p_rts_flags |= RTS_VMINHIBIT;
rp->p_rts_flags |= RTS_PROC_STOP;
rp->p_rts_flags &= ~RTS_SLOT_FREE;
- alloc_segments(rp);
DEBUGEXTRA(("done\n"));
}
+ /* update boot procs info for VM */
+ memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
+
#define IPCNAME(n) { \
assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
assert(!ipc_call_names[n]); \
ipc_call_names[n] = #n; \
}
+ arch_post_init();
+
IPCNAME(SEND);
IPCNAME(RECEIVE);
IPCNAME(SENDREC);
IPCNAME(SENDNB);
IPCNAME(SENDA);
- /* Architecture-dependent initialization. */
- DEBUGEXTRA(("arch_init()... "));
- arch_init();
- DEBUGEXTRA(("done\n"));
-
/* System and processes initialization */
+ memory_init();
DEBUGEXTRA(("system_init()... "));
system_init();
DEBUGEXTRA(("done\n"));
+ /* The bootstrap phase is over, so we can add the physical
+ * memory used for it to the free list.
+ */
+ add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len);
+
#ifdef CONFIG_SMP
if (config_no_apic) {
BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n"));
#endif
NOT_REACHABLE;
- return 1;
}
/*===========================================================================*
#endif
hw_intr_disable_all();
stop_local_timer();
- intr_init(INTS_ORIG, 0);
arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC);
}
+/*===========================================================================*
+ * cstart *
+ *===========================================================================*/
+void cstart()
+{
+/* Perform system initializations prior to calling main(). Most settings are
+ * determined with help of the environment strings passed by MINIX' loader.
+ */
+ register char *value; /* value in key=value pair */
+ int h;
+
+ /* low-level initialization */
+ prot_init();
+
+ /* determine verbosity */
+ if ((value = env_get(VERBOSEBOOTVARNAME)))
+ verboseboot = atoi(value);
+
+ /* Get clock tick frequency. */
+ value = env_get("hz");
+ if(value)
+ system_hz = atoi(value);
+ if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */
+ system_hz = DEFAULT_HZ;
+
+ DEBUGEXTRA(("cstart\n"));
+
+ /* Record miscellaneous information for user-space servers. */
+ kinfo.nr_procs = NR_PROCS;
+ kinfo.nr_tasks = NR_TASKS;
+ strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
+ kinfo.release[sizeof(kinfo.release)-1] = '\0';
+ strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
+ kinfo.version[sizeof(kinfo.version)-1] = '\0';
+
+ /* Load average data initialization. */
+ kloadinfo.proc_last_slot = 0;
+ for(h = 0; h < _LOAD_HISTORY; h++)
+ kloadinfo.proc_load_history[h] = 0;
+
+#ifdef USE_APIC
+ value = env_get("no_apic");
+ if(value)
+ config_no_apic = atoi(value);
+ else
+ config_no_apic = 1;
+ value = env_get("apic_timer_x");
+ if(value)
+ config_apic_timer_x = atoi(value);
+ else
+ config_apic_timer_x = 1;
+#endif
+
+#ifdef USE_WATCHDOG
+ value = env_get("watchdog");
+ if (value)
+ watchdog_enabled = atoi(value);
+#endif
+
+#ifdef CONFIG_SMP
+ if (config_no_apic)
+ config_no_smp = 1;
+ value = env_get("no_smp");
+ if(value)
+ config_no_smp = atoi(value);
+ else
+ config_no_smp = 0;
+#endif
+ DEBUGEXTRA(("intr_init(0)\n"));
+
+ intr_init(0);
+
+ arch_init();
+}
+
+/*===========================================================================*
+ * get_value *
+ *===========================================================================*/
+
+char *get_value(
+ const char *params, /* boot monitor parameters */
+ const char *name /* key to look up */
+)
+{
+/* Get environment value - kernel version of getenv to avoid setting up the
+ * usual environment array.
+ */
+ register const char *namep;
+ register char *envp;
+
+ for (envp = (char *) params; *envp != 0;) {
+ for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
+ ;
+ if (*namep == '\0' && *envp == '=') return(envp + 1);
+ while (*envp++ != 0)
+ ;
+ }
+ return(NULL);
+}
+
+/*===========================================================================*
+ * env_get *
+ *===========================================================================*/
+char *env_get(const char *name)
+{
+ return get_value(kinfo.param_buf, name);
+}
+
+void cpu_print_freq(unsigned cpu)
+{
+ u64_t freq;
+
+ freq = cpu_get_freq(cpu);
+ printf("CPU %d freq %lu MHz\n", cpu, div64u(freq, 1000000));
+}
+
+int is_fpu(void)
+{
+ return get_cpulocal_var(fpu_presence);
+}
+
/* Enable copy-on-write optimization for safecopy. */
#define PERF_USE_COW_SAFECOPY 0
-/* Use a private page table for critical system processes. */
-#ifdef CONFIG_SMP
-#define PERF_SYS_CORE_FULLVM 1
-#else
-#define PERF_SYS_CORE_FULLVM 0
-#endif
-
#endif /* PERF_H */
{
int i, c;
int p_z = 0;
- /*
- * P_NAME_LEN limits us to 3 characters for the idle task numer. 999
- * should be enough though.
- */
+
if (n > 999)
n = 999;
rp->p_quantum_size_ms = 0; /* no quantum size */
/* arch-specific initialization */
- arch_proc_init(i, rp);
+ arch_proc_reset(rp);
}
for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) {
sp->s_proc_nr = NONE; /* initialize as free */
*/
p->p_misc_flags &= ~MF_CONTEXT_SET;
- assert(!(p->p_misc_flags & MF_FULLVM) || p->p_seg.p_cr3 != 0);
+ assert(p->p_seg.p_cr3 != 0);
#ifdef CONFIG_SMP
if (p->p_misc_flags & MF_FLUSH_TLB) {
if (tlb_must_refresh)
assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));
if (!(flags & FROM_KERNEL)) {
- if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg))
+ if(copy_msg_from_user(m_ptr, &dst_ptr->p_delivermsg))
return EFAULT;
} else {
dst_ptr->p_delivermsg = *m_ptr;
/* Destination is not waiting. Block and dequeue caller. */
if (!(flags & FROM_KERNEL)) {
- if(copy_msg_from_user(caller_ptr, m_ptr, &caller_ptr->p_sendmsg))
+ if(copy_msg_from_user(m_ptr, &caller_ptr->p_sendmsg))
return EFAULT;
} else {
caller_ptr->p_sendmsg = *m_ptr;
unsigned long preempted;
} p_accounting;
- struct mem_map p_memmap[NR_LOCAL_SEGS]; /* memory map (T, D, S) */
-
clock_t p_user_time; /* user time in ticks */
clock_t p_sys_time; /* sys time in ticks */
sigset_t p_pending; /* bit map for pending kernel signals */
- char p_name[P_NAME_LEN]; /* name of the process, including \0 */
+ char p_name[PROC_NAME_LEN]; /* name of the process, including \0 */
endpoint_t p_endpoint; /* endpoint number, generation-aware */
We need to resume the kernel call execution
now
*/
-#define MF_FULLVM 0x020
#define MF_DELIVERMSG 0x040 /* Copy message for him before running */
#define MF_SIG_DELAY 0x080 /* Send signal when no longer sending */
#define MF_SC_ACTIVE 0x100 /* Syscall tracing: in a system call now */
s = (struct sprof_proc *) (sprof_sample_buffer + sprof_info.mem_used);
s->proc = p->p_endpoint;
- memcpy(&s->name, p->p_name, P_NAME_LEN);
+ strcpy(s->name, p->p_name);
sprof_info.mem_used += sizeof(struct sprof_proc);
}
sigcontext *sc);
/* main.c */
-int main(void);
+#ifndef UNPAGED
+#define kmain __k_unpaged_kmain
+#endif
+void kmain(kinfo_t *cbi);
void prepare_shutdown(int how);
__dead void minix_shutdown(struct timer *tp);
void bsp_finish_booting(void);
void enqueue(struct proc *rp);
void dequeue(struct proc *rp);
void switch_to_user(void);
-void arch_proc_init(int nr, struct proc *rp);
+void arch_proc_reset(struct proc *rp);
struct proc * arch_finish_switch_to_user(void);
struct proc *endpoint_lookup(endpoint_t ep);
#if DEBUG_ENABLE_IPC_WARNINGS
size);
/* start.c */
-void cstart(u16_t cs, u16_t ds, u16_t mds, u16_t parmoff, u16_t
- parmsize);
+void cstart();
char *env_get(const char *key);
/* system.c */
void sig_delay_done(struct proc *rp);
void kernel_call(message *m_user, struct proc * caller);
void system_init(void);
-#define numap_local(proc_nr, vir_addr, bytes) \
- umap_local(proc_addr(proc_nr), D, (vir_addr), (bytes))
void clear_endpoint(struct proc *rc);
void clear_ipc_refs(struct proc *rc, int caller_ret);
void kernel_call_resume(struct proc *p);
int sched_proc(struct proc *rp, int priority, int quantum, int cpu);
-/* system/do_newmap.c */
-int newmap(struct proc * caller, struct proc *rp, struct mem_map
- *map_ptr);
-
/* system/do_vtimer.c */
void vtimer_check(struct proc *rp);
#endif
/* functions defined in architecture-dependent files. */
-void prot_init(void);
+void prot_init();
+void arch_post_init();
phys_bytes phys_copy(phys_bytes source, phys_bytes dest, phys_bytes
count);
void phys_copy_fault(void);
vir_bytes to_addr, size_t bytes);
int data_copy_vmcheck(struct proc *, endpoint_t from, vir_bytes
from_addr, endpoint_t to, vir_bytes to_addr, size_t bytes);
-void alloc_segments(struct proc *rp);
-void vm_stop(void);
-phys_bytes umap_local(register struct proc *rp, int seg, vir_bytes
- vir_addr, vir_bytes bytes);
phys_bytes umap_virtual(struct proc* rp, int seg, vir_bytes vir_addr,
vir_bytes bytes);
phys_bytes seg2phys(u16_t);
int vm_memset(endpoint_t who,
phys_bytes source, u8_t pattern, phys_bytes count);
-int intr_init(int, int);
+int intr_init(int);
void halt_cpu(void);
void arch_init(void);
+void arch_boot_proc(struct boot_image *b, struct proc *p);
void cpu_identify(void);
/* arch dependent FPU initialization per CPU */
void fpu_init(void);
void arch_ack_profile_clock(void);
void do_ser_debug(void);
int arch_get_params(char *parm, int max);
-int arch_set_params(char *parm, int max);
-void arch_pre_exec(struct proc *pr, u32_t, u32_t);
+void memory_init(void);
+void mem_clear_mapcache(void);
+void arch_proc_init(struct proc *pr, u32_t, u32_t, char *);
int arch_do_vmctl(message *m_ptr, struct proc *p);
int vm_contiguous(const struct proc *targetproc, vir_bytes vir_buf,
size_t count);
int arch_phys_map(int index, phys_bytes *addr, phys_bytes *len, int
*flags);
int arch_phys_map_reply(int index, vir_bytes addr);
-int arch_enable_paging(struct proc * caller, const message * m_ptr);
+int arch_enable_paging(struct proc * caller);
int vm_check_range(struct proc *caller,
struct proc *target, vir_bytes vir_addr, size_t bytes);
-int copy_msg_from_user(struct proc * p, message * user_mbuf, message *
- dst);
-int copy_msg_to_user(struct proc * p, message * src, message *
- user_mbuf);
+int copy_msg_from_user(message * user_mbuf, message * dst);
+int copy_msg_to_user(message * src, message * user_mbuf);
void switch_address_space(struct proc * p);
void release_address_space(struct proc *pr);
+++ /dev/null
-
-/* First C file used by the kernel. */
-
-#include "kernel.h"
-#include "proc.h"
-#include <stdlib.h>
-#include <string.h>
-#include "proto.h"
-
-#ifdef USE_WATCHDOG
-#include "watchdog.h"
-#endif
-
-/*===========================================================================*
- * cstart *
- *===========================================================================*/
-void cstart(
- u16_t cs, /* kernel code segment */
- u16_t ds, /* kernel data segment */
- u16_t mds, /* monitor data segment */
- u16_t parmoff, /* boot parameters offset */
- u16_t parmsize /* boot parameters length */
-)
-{
-/* Perform system initializations prior to calling main(). Most settings are
- * determined with help of the environment strings passed by MINIX' loader.
- */
- register char *value; /* value in key=value pair */
- extern int etext, end;
- int h;
-
- /* Record where the kernel and the monitor are. */
- kinfo.code_base = seg2phys(cs);
- kinfo.code_size = (phys_bytes) &etext; /* size of code segment */
- kinfo.data_base = seg2phys(ds);
- kinfo.data_size = (phys_bytes) &end; /* size of data segment */
-
- /* protection initialization */
- prot_init();
-
- /* Copy the boot parameters to the local buffer. */
- arch_get_params(params_buffer, sizeof(params_buffer));
-
- /* determine verbosity */
- if ((value = env_get(VERBOSEBOOTVARNAME)))
- verboseboot = atoi(value);
-
- /* Get clock tick frequency. */
- value = env_get("hz");
- if(value)
- system_hz = atoi(value);
- if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */
- system_hz = DEFAULT_HZ;
-
-#ifdef DEBUG_SERIAL
- /* Intitialize serial debugging */
- value = env_get(SERVARNAME);
- if(value && atoi(value) == 0) {
- do_serial_debug=1;
-
- value = env_get(SERBAUDVARNAME);
- if (value) serial_debug_baud = atoi(value);
- }
-#endif
-
- DEBUGEXTRA(("cstart\n"));
-
- /* Record miscellaneous information for user-space servers. */
- kinfo.nr_procs = NR_PROCS;
- kinfo.nr_tasks = NR_TASKS;
- strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
- kinfo.release[sizeof(kinfo.release)-1] = '\0';
- strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
- kinfo.version[sizeof(kinfo.version)-1] = '\0';
- kinfo.proc_addr = (vir_bytes) proc;
-
- /* Load average data initialization. */
- kloadinfo.proc_last_slot = 0;
- for(h = 0; h < _LOAD_HISTORY; h++)
- kloadinfo.proc_load_history[h] = 0;
-
-#ifdef USE_APIC
- value = env_get("no_apic");
- if(value)
- config_no_apic = atoi(value);
- else
- config_no_apic = 1;
- value = env_get("apic_timer_x");
- if(value)
- config_apic_timer_x = atoi(value);
- else
- config_apic_timer_x = 1;
-#endif
-
-#ifdef USE_WATCHDOG
- value = env_get("watchdog");
- if (value)
- watchdog_enabled = atoi(value);
-#endif
-
-#ifdef CONFIG_SMP
- if (config_no_apic)
- config_no_smp = 1;
- value = env_get("no_smp");
- if(value)
- config_no_smp = atoi(value);
- else
- config_no_smp = 0;
-#endif
-
- /* Return to assembler code to switch to protected mode (if 286),
- * reload selectors and call main().
- */
-
- DEBUGEXTRA(("intr_init(%d, 0)\n", INTS_MINIX));
- intr_init(INTS_MINIX, 0);
-}
-
-/*===========================================================================*
- * get_value *
- *===========================================================================*/
-
-char *get_value(
- const char *params, /* boot monitor parameters */
- const char *name /* key to look up */
-)
-{
-/* Get environment value - kernel version of getenv to avoid setting up the
- * usual environment array.
- */
- register const char *namep;
- register char *envp;
-
- for (envp = (char *) params; *envp != 0;) {
- for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
- ;
- if (*namep == '\0' && *envp == '=') return(envp + 1);
- while (*envp++ != 0)
- ;
- }
- return(NULL);
-}
-
-/*===========================================================================*
- * env_get *
- *===========================================================================*/
-char *env_get(const char *name)
-{
- return get_value(params_buffer, name);
-}
-
#if DEBUG_IPC_HOOK
hook_ipc_msgkresult(msg, caller);
#endif
- if (copy_msg_to_user(caller, msg,
- (message *)caller->p_delivermsg_vir)) {
+ if (copy_msg_to_user(msg, (message *)caller->p_delivermsg_vir)) {
printf("WARNING wrong user pointer 0x%08x from "
"process %s / %d\n",
caller->p_delivermsg_vir,
* into the kernel or was already set in switch_to_user() before we resume
* execution of an interrupted kernel call
*/
- if (copy_msg_from_user(caller, m_user, &msg) == 0) {
+ if (copy_msg_from_user(m_user, &msg) == 0) {
msg.m_source = caller->p_endpoint;
result = kernel_call_dispatch(caller, &msg);
}
map(SYS_VDEVIO, do_vdevio); /* vector with devio requests */
/* Memory management. */
- map(SYS_NEWMAP, do_newmap); /* set up a process memory map */
map(SYS_MEMSET, do_memset); /* write char to memory area */
map(SYS_VMCTL, do_vmctl); /* various VM process settings */
* send a notification with source SYSTEM.
*/
register struct proc *rp;
+ struct priv *priv;
int proc_nr;
if(!isokendpt(ep, &proc_nr) || isemptyn(proc_nr))
return EINVAL;
rp = proc_addr(proc_nr);
- sigaddset(&priv(rp)->s_sig_pending, sig_nr);
+ priv = priv(rp);
+ if(!priv) return ENOENT;
+ sigaddset(&priv->s_sig_pending, sig_nr);
mini_notify(proc_addr(SYSTEM), rp->p_endpoint);
return OK;
#define do_fork NULL
#endif
-int do_newmap(struct proc * caller, message *m_ptr);
-#if ! USE_NEWMAP
-#define do_newmap NULL
-#endif
-
int do_clear(struct proc * caller, message *m_ptr);
#if ! USE_CLEAR
#define do_clear NULL
SRCS+= \
do_fork.c \
do_exec.c \
- do_newmap.c \
do_clear.c \
do_exit.c \
do_trace.c \
return p;
}
paramsbuffer[len] = '\0';
-
- /* Parameters seem ok, copy them and prepare shutting down. */
- if((p = arch_set_params(paramsbuffer, len+1)) != OK)
- return p;
}
/* Now prepare to shutdown MINIX. */
struct vir_addr vir_addr[2]; /* virtual source and destination address */
phys_bytes bytes; /* number of bytes to copy */
int i;
- endpoint_t pe;
#if 0
if (caller->p_endpoint != PM_PROC_NR && caller->p_endpoint != VFS_PROC_NR &&
#endif
/* Dismember the command message. */
- pe = vir_addr[_SRC_].proc_nr_e = m_ptr->CP_SRC_ENDPT;
- vir_addr[_SRC_].segment = (pe == NONE ? PHYS_SEG : D);
+ vir_addr[_SRC_].proc_nr_e = m_ptr->CP_SRC_ENDPT;
+ vir_addr[_DST_].proc_nr_e = m_ptr->CP_DST_ENDPT;
+
vir_addr[_SRC_].offset = (vir_bytes) m_ptr->CP_SRC_ADDR;
- pe = vir_addr[_DST_].proc_nr_e = m_ptr->CP_DST_ENDPT;
- vir_addr[_DST_].segment = (pe == NONE ? PHYS_SEG : D);
vir_addr[_DST_].offset = (vir_bytes) m_ptr->CP_DST_ADDR;
bytes = (phys_bytes) m_ptr->CP_NR_BYTES;
/* Check if process number was given implictly with SELF and is valid. */
if (vir_addr[i].proc_nr_e == SELF)
vir_addr[i].proc_nr_e = caller->p_endpoint;
- if (vir_addr[i].segment != PHYS_SEG) {
+ if (vir_addr[i].proc_nr_e != NONE) {
if(! isokendpt(vir_addr[i].proc_nr_e, &p)) {
- printf("do_copy: %d: seg 0x%x, %d not ok endpoint\n",
- i, vir_addr[i].segment, vir_addr[i].proc_nr_e);
+ printf("do_copy: %d: %d not ok endpoint\n", i, vir_addr[i].proc_nr_e);
return(EINVAL);
}
}
/* Handle sys_exec(). A process has done a successful EXEC. Patch it up. */
register struct proc *rp;
int proc_nr;
+ char name[PROC_NAME_LEN];
if(!isokendpt(m_ptr->PR_ENDPT, &proc_nr))
return EINVAL;
/* Save command name for debugging, ps(1) output, etc. */
if(data_copy(caller->p_endpoint, (vir_bytes) m_ptr->PR_NAME_PTR,
- KERNEL, (vir_bytes) rp->p_name, (phys_bytes) P_NAME_LEN - 1) != OK)
- strncpy(rp->p_name, "<unset>", P_NAME_LEN);
+ KERNEL, (vir_bytes) name,
+ (phys_bytes) sizeof(name) - 1) != OK)
+ strncpy(name, "<unset>", PROC_NAME_LEN);
- /* Do architecture-specific exec() stuff. */
- arch_pre_exec(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR);
+ name[sizeof(name)-1] = '\0';
+
+ /* Set process state. */
+ arch_proc_init(rp, (u32_t) m_ptr->PR_IP_PTR, (u32_t) m_ptr->PR_STACK_PTR, name);
/* No reply to EXEC call */
RTS_UNSET(rp, RTS_RECEIVING);
{
/* Handle sys_fork(). PR_ENDPT has forked. The child is PR_SLOT. */
#if (_MINIX_CHIP == _CHIP_INTEL)
- reg_t old_ldt_sel;
char *old_fpu_save_area_p;
#endif
register struct proc *rpc; /* child process pointer */
struct proc *rpp; /* parent process pointer */
- struct mem_map *map_ptr; /* virtual address of map inside caller (PM) */
- int gen, r;
+ int gen;
int p_proc;
int namelen;
return EINVAL;
}
- map_ptr= (struct mem_map *) m_ptr->PR_MEM_PTR;
-
/* make sure that the FPU context is saved in parent before copy */
save_fpu(rpp);
/* Copy parent 'proc' struct to child. And reinitialize some fields. */
gen = _ENDPOINT_G(rpc->p_endpoint);
#if (_MINIX_CHIP == _CHIP_INTEL)
- old_ldt_sel = rpc->p_seg.p_ldt_sel; /* backup local descriptors */
old_fpu_save_area_p = rpc->p_seg.fpu_state;
#endif
*rpc = *rpp; /* copy 'proc' struct */
#if (_MINIX_CHIP == _CHIP_INTEL)
- rpc->p_seg.p_ldt_sel = old_ldt_sel; /* restore descriptors */
rpc->p_seg.fpu_state = old_fpu_save_area_p;
if(proc_used_fpu(rpp))
memcpy(rpc->p_seg.fpu_state, rpp->p_seg.fpu_state, FPU_XFP_SIZE);
m_ptr->PR_ENDPT = rpc->p_endpoint;
m_ptr->PR_FORK_MSGADDR = (char *) rpp->p_delivermsg_vir;
- /* Install new map */
- r = newmap(caller, rpc, map_ptr);
-
/* Don't schedule process in VM mode until it has a new pagetable. */
if(m_ptr->PR_FORK_FLAGS & PFF_VMINHIBIT) {
RTS_SET(rpc, RTS_VMINHIBIT);
rpc->p_seg.p_cr3 = 0;
rpc->p_seg.p_cr3_v = NULL;
- return r;
+ return OK;
}
#endif /* USE_FORK */
return OK;
}
case GET_MONPARAMS: {
- src_vir = (vir_bytes) params_buffer;
- length = sizeof(params_buffer);
+ src_vir = (vir_bytes) kinfo.param_buf;
+ length = sizeof(kinfo.param_buf);
break;
}
case GET_RANDOMNESS: {
+++ /dev/null
-/* The kernel call implemented in this file:
- * m_type: SYS_NEWMAP
- *
- * The parameters for this kernel call are:
- * m1_i1: PR_ENDPT (install new map for this process)
- * m1_p1: PR_MEM_PTR (pointer to the new memory map)
- */
-#include "kernel/system.h"
-#include <minix/endpoint.h>
-
-#if USE_NEWMAP
-
-/*===========================================================================*
- * do_newmap *
- *===========================================================================*/
-int do_newmap(struct proc * caller, message * m_ptr)
-{
-/* Handle sys_newmap(). Fetch the memory map. */
- struct proc *rp; /* process whose map is to be loaded */
- struct mem_map *map_ptr; /* virtual address of map inside caller */
- int proc_nr;
-
- map_ptr = (struct mem_map *) m_ptr->PR_MEM_PTR;
- if (! isokendpt(m_ptr->PR_ENDPT, &proc_nr)) return(EINVAL);
- if (iskerneln(proc_nr)) return(EPERM);
- rp = proc_addr(proc_nr);
-
- return newmap(caller, rp, map_ptr);
-}
-
-
-/*===========================================================================*
- * newmap *
- *===========================================================================*/
-int newmap(struct proc *caller, struct proc *rp, struct mem_map *map_ptr)
-{
- int r;
-/* Fetch the memory map. */
- if((r=data_copy(caller->p_endpoint, (vir_bytes) map_ptr,
- KERNEL, (vir_bytes) rp->p_memmap, sizeof(rp->p_memmap))) != OK) {
- printf("newmap: data_copy failed! (%d)\n", r);
- return r;
- }
-
- alloc_segments(rp);
-
- return(OK);
-}
-#endif /* USE_NEWMAP */
-
* VSCP_VEC_SIZE number of significant elements in vector
*/
+#include <assert.h>
#include <minix/type.h>
#include <minix/safecopies.h>
vir_bytes size;
#endif
+ if(granter == NONE || grantee == NONE) {
+ printf("safecopy: nonsense processes\n");
+ return EFAULT;
+ }
+
/* See if there is a reasonable grant table. */
if(!(granter_p = endpoint_lookup(granter))) return EINVAL;
if(!HASGRANTTABLE(granter_p)) {
granter = new_granter;
/* Now it's a regular copy. */
- v_src.segment = D;
- v_dst.segment = D;
v_src.proc_nr_e = *src;
v_dst.proc_nr_e = *dst;
/* Set vector copy parameters. */
src.proc_nr_e = caller->p_endpoint;
+ assert(src.proc_nr_e != NONE);
src.offset = (vir_bytes) m_ptr->VSCP_VEC_ADDR;
- src.segment = dst.segment = D;
dst.proc_nr_e = KERNEL;
dst.offset = (vir_bytes) vec;
size_t size, int flag)
{
struct proc *src, *dst;
- phys_bytes lin_src, lin_dst;
src = endpoint_lookup(end_s);
dst = endpoint_lookup(end_d);
- lin_src = umap_local(src, D, off_s, size);
- lin_dst = umap_local(dst, D, off_d, size);
- if(lin_src == 0 || lin_dst == 0) {
- printf("map_invoke_vm: error in umap_local.\n");
- return EINVAL;
- }
-
/* Make sure the linear addresses are both page aligned. */
- if(lin_src % CLICK_SIZE != 0
- || lin_dst % CLICK_SIZE != 0) {
+ if(off_s % CLICK_SIZE != 0 || off_d % CLICK_SIZE != 0) {
printf("map_invoke_vm: linear addresses not page aligned.\n");
return EINVAL;
}
/* Map to the destination. */
caller->p_vmrequest.req_type = req_type;
caller->p_vmrequest.target = end_d; /* destination proc */
- caller->p_vmrequest.params.map.vir_d = lin_dst; /* destination addr */
+ caller->p_vmrequest.params.map.vir_d = off_d; /* destination addr */
caller->p_vmrequest.params.map.ep_s = end_s; /* source process */
- caller->p_vmrequest.params.map.vir_s = lin_src; /* source address */
+ caller->p_vmrequest.params.map.vir_s = off_s; /* source address */
caller->p_vmrequest.params.map.length = (vir_bytes) size;
caller->p_vmrequest.params.map.writeflag = flag;
unsigned char ub;
int i;
-#define COPYTOPROC(seg, addr, myaddr, length) { \
+#define COPYTOPROC(addr, myaddr, length) { \
struct vir_addr fromaddr, toaddr; \
int r; \
fromaddr.proc_nr_e = KERNEL; \
toaddr.proc_nr_e = tr_proc_nr_e; \
fromaddr.offset = (myaddr); \
toaddr.offset = (addr); \
- fromaddr.segment = D; \
- toaddr.segment = (seg); \
if((r=virtual_copy_vmcheck(caller, &fromaddr, \
&toaddr, length)) != OK) { \
printf("Can't copy in sys_trace: %d\n", r);\
} \
}
-#define COPYFROMPROC(seg, addr, myaddr, length) { \
+#define COPYFROMPROC(addr, myaddr, length) { \
struct vir_addr fromaddr, toaddr; \
int r; \
fromaddr.proc_nr_e = tr_proc_nr_e; \
toaddr.proc_nr_e = KERNEL; \
fromaddr.offset = (addr); \
toaddr.offset = (myaddr); \
- fromaddr.segment = (seg); \
- toaddr.segment = D; \
if((r=virtual_copy_vmcheck(caller, &fromaddr, \
&toaddr, length)) != OK) { \
printf("Can't copy in sys_trace: %d\n", r);\
return(OK);
case T_GETINS: /* return value from instruction space */
- COPYFROMPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+ COPYFROMPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long));
m_ptr->CTL_DATA = tr_data;
break;
case T_GETDATA: /* return value from data space */
- COPYFROMPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+ COPYFROMPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long));
m_ptr->CTL_DATA= tr_data;
break;
break;
case T_SETINS: /* set value in instruction space */
- COPYTOPROC(T, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+ COPYTOPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long));
m_ptr->CTL_DATA = 0;
break;
case T_SETDATA: /* set value in data space */
- COPYTOPROC(D, tr_addr, (vir_bytes) &tr_data, sizeof(long));
+ COPYTOPROC(tr_addr, (vir_bytes) &tr_data, sizeof(long));
m_ptr->CTL_DATA = 0;
break;
break;
case T_READB_INS: /* get value from instruction space */
- COPYFROMPROC(T, tr_addr, (vir_bytes) &ub, 1);
+ COPYFROMPROC(tr_addr, (vir_bytes) &ub, 1);
m_ptr->CTL_DATA = ub;
break;
case T_WRITEB_INS: /* set value in instruction space */
ub = (unsigned char) (tr_data & 0xff);
- COPYTOPROC(T, tr_addr, (vir_bytes) &ub, 1);
+ COPYTOPROC(tr_addr, (vir_bytes) &ub, 1);
m_ptr->CTL_DATA = 0;
break;
int endpt = (int) m_ptr->CP_SRC_ENDPT;
endpoint_t grantee = (endpoint_t) m_ptr->CP_DST_ENDPT;
int proc_nr, proc_nr_grantee;
- int naughty = 0;
phys_bytes phys_addr = 0, lin_addr = 0;
struct proc *targetpr;
/* See which mapping should be made. */
switch(seg_type) {
- case LOCAL_SEG:
- phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
- if(!lin_addr) return EFAULT;
- naughty = 1;
- break;
case LOCAL_VM_SEG:
if(seg_index == MEM_GRANT) {
vir_bytes newoffset;
/* New lookup. */
offset = newoffset;
targetpr = proc_addr(new_proc_nr);
- seg_index = D;
+ seg_index = VIR_ADDR;
}
- if(seg_index == T || seg_index == D || seg_index == S) {
- phys_addr = lin_addr = umap_local(targetpr, seg_index, offset, count);
+ if(seg_index == VIR_ADDR) {
+ phys_addr = lin_addr = offset;
} else {
printf("SYSTEM: bogus seg type 0x%lx\n", seg_index);
return EFAULT;
}
m_ptr->CP_DST_ADDR = phys_addr;
- if(naughty || phys_addr == 0) {
+ if(phys_addr == 0) {
printf("kernel: umap 0x%x done by %d / %s, pc 0x%lx, 0x%lx -> 0x%lx\n",
seg_type, caller->p_endpoint, caller->p_name,
caller->p_reg.pc, offset, phys_addr);
/* Swap global process slot addresses. */
swap_proc_slot_pointer(get_cpulocal_var_ptr(ptproc), src_rp, dst_rp);
- /* Fix segments. */
- alloc_segments(src_rp);
- alloc_segments(dst_rp);
- prot_init();
-
#if DEBUG
printf("do_update: updated %d (%s, %d, %d) into %d (%s, %d, %d)\n",
src_rp->p_endpoint, src_rp->p_name, src_rp->p_nr, priv(src_rp)->s_proc_nr,
RTS_UNSET(p, RTS_VMREQUEST);
return OK;
- case VMCTL_ENABLE_PAGING:
- if(vm_running)
- panic("do_vmctl: paging already enabled");
- if (arch_enable_paging(caller, m_ptr) != OK)
- panic("do_vmctl: paging enabling failed");
- return OK;
-
case VMCTL_KERN_PHYSMAP:
{
int i = m_ptr->SVMCTL_VALUE;
bits_fill(p->p_stale_tlb, CONFIG_MAX_CPUS);
#endif
return OK;
+ case VMCTL_CLEARMAPCACHE:
+ /* VM says: forget about old mappings we have cached. */
+ mem_clear_mapcache();
+ return OK;
}
/* Try architecture-specific vmctls. */
struct proc *procp;
struct vumap_vir vvec[MAPVEC_NR];
struct vumap_phys pvec[MAPVEC_NR];
- vir_bytes vaddr, paddr, vir_addr, lin_addr;
+ vir_bytes vaddr, paddr, vir_addr;
phys_bytes phys_addr;
int i, r, proc_nr, vcount, pcount, pmax, access;
size_t size, chunk, offset;
okendpt(granter, &proc_nr);
procp = proc_addr(proc_nr);
- lin_addr = umap_local(procp, D, vir_addr, size);
- if (!lin_addr)
- return EFAULT;
-
/* Each virtual range is made up of one or more physical ranges. */
while (size > 0 && pcount < pmax) {
- chunk = vm_lookup_range(procp, lin_addr, &phys_addr, size);
+ chunk = vm_lookup_range(procp, vir_addr, &phys_addr, size);
if (!chunk) {
/* Try to get the memory allocated, unless the memory
/* This call may suspend the current call, or return an
* error for a previous invocation.
*/
- return vm_check_range(caller, procp, lin_addr, size);
+ return vm_check_range(caller, procp, vir_addr, size);
}
pvec[pcount].vp_addr = phys_addr;
pvec[pcount].vp_size = chunk;
pcount++;
- lin_addr += chunk;
+ vir_addr += chunk;
size -= chunk;
}
#include "ipc.h"
#include <minix/com.h>
-/* Define boot process flags. */
-#define BVM_F (PROC_FULLVM) /* boot processes with VM */
-#define OVM_F (PERF_SYS_CORE_FULLVM ? PROC_FULLVM : 0) /* critical boot
- * processes with
- * optional VM.
- */
-
/* 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
* in the boot image and all kernel tasks must come first.
* to prioritize ping messages periodically delivered to system processes.
*/
-struct boot_image image[] = {
+struct boot_image image[NR_BOOT_PROCS] = {
/* process nr, flags, stack size, name */
-{ASYNCM, 0, 0, "asyncm"},
-{IDLE, 0, 0, "idle" },
-{CLOCK, 0, 0, "clock" },
-{SYSTEM, 0, 0, "system"},
-{HARDWARE, 0, 0, "kernel"},
+{ASYNCM, "asyncm"},
+{IDLE, "idle" },
+{CLOCK, "clock" },
+{SYSTEM, "system"},
+{HARDWARE, "kernel"},
-{DS_PROC_NR, BVM_F, 16, "ds" },
-{RS_PROC_NR, 0, 8125, "rs" },
+{DS_PROC_NR, "ds" },
+{RS_PROC_NR, "rs" },
-{PM_PROC_NR, OVM_F, 32, "pm" },
-{SCHED_PROC_NR,OVM_F, 32, "sched" },
-{VFS_PROC_NR, BVM_F, 16, "vfs" },
-{MEM_PROC_NR, BVM_F, 8, "memory"},
-{LOG_PROC_NR, BVM_F, 32, "log" },
-{TTY_PROC_NR, BVM_F, 16, "tty" },
-{MFS_PROC_NR, BVM_F, 128, "mfs" },
-{VM_PROC_NR, 0, 128, "vm" },
-{PFS_PROC_NR, BVM_F, 128, "pfs" },
-{INIT_PROC_NR, BVM_F, 64, "init" },
+{PM_PROC_NR, "pm" },
+{SCHED_PROC_NR, "sched" },
+{VFS_PROC_NR, "vfs" },
+{MEM_PROC_NR, "memory"},
+{LOG_PROC_NR, "log" },
+{TTY_PROC_NR, "tty" },
+{MFS_PROC_NR, "mfs" },
+{VM_PROC_NR, "vm" },
+{PFS_PROC_NR, "pfs" },
+{INIT_PROC_NR, "init" },
};
-/* Verify the size of the system image table at compile time.
- * If a problem is detected, the size of the 'dummy' array will be negative,
- * causing a compile time error. Note that no space is actually allocated
- * because 'dummy' is declared extern.
- */
-extern int dummy[(NR_BOOT_PROCS==sizeof(image)/
- sizeof(struct boot_image))?1:-1];
#include <minix/com.h>
#include <machine/interrupt.h>
+#include <machine/multiboot.h>
/* Process table and system property related types. */
typedef int proc_nr_t; /* process table entry number */
bitchunk_t chunk[BITMAP_CHUNKS(NR_SYS_PROCS)];
} sys_map_t;
-struct boot_image_memmap {
- phys_bytes text_vaddr; /* Virtual start address of text */
- phys_bytes text_paddr; /* Physical start address of text */
- phys_bytes text_bytes; /* Text segment's size (bytes) */
- phys_bytes data_vaddr; /* Virtual start address of data */
- phys_bytes data_paddr; /* Physical start address of data */
- phys_bytes data_bytes; /* Data segment's size (bytes) */
- phys_bytes stack_bytes; /* Size of stack set aside (bytes) */
- phys_bytes entry; /* Entry point of executable */
-};
-
-struct boot_image {
- proc_nr_t proc_nr; /* process number to use */
- int flags; /* process flags */
- int stack_kbytes; /* stack size (in KB) */
- char proc_name[P_NAME_LEN]; /* name in process table */
- endpoint_t endpoint; /* endpoint number when started */
- struct boot_image_memmap memmap; /* memory map info for boot image */
-};
-
typedef unsigned long irq_policy_t;
typedef unsigned long irq_id_t;
{
va_list arg;
/* The system has run aground of a fatal kernel error. Terminate execution. */
- if (minix_panicing == ARE_PANICING) {
+ if (kinfo.minix_panicing == ARE_PANICING) {
reset();
}
- minix_panicing = ARE_PANICING;
+ kinfo.minix_panicing = ARE_PANICING;
if (fmt != NULL) {
printf("kernel panic: ");
va_start(arg, fmt);
printf("kernel on CPU %d: ", cpuid);
util_stacktrace();
- printf("current process : ");
- proc_stacktrace(get_cpulocal_var(proc_ptr));
+#if 0
+ if(get_cpulocal_var(proc_ptr)) {
+ printf("current process : ");
+ proc_stacktrace(get_cpulocal_var(proc_ptr));
+ }
+#endif
/* Abort MINIX. */
minix_shutdown(NULL);
* to the output driver if an END_OF_KMESS is encountered.
*/
if (c != END_OF_KMESS) {
- static int blpos = 0;
- int maxblpos = sizeof(kmess_buf) - 2;
+ int maxblpos = sizeof(kmess.kmess_buf) - 2;
#ifdef DEBUG_SERIAL
- if (do_serial_debug) {
+ if (kinfo.do_serial_debug) {
if(c == '\n')
ser_putc('\r');
ser_putc(c);
}
#endif
kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */
- kmess_buf[blpos] = c;
+ kmess.kmess_buf[kmess.blpos] = c;
if (kmess.km_size < sizeof(kmess.km_buf))
kmess.km_size += 1;
kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE;
- if(blpos == maxblpos) {
- memmove(kmess_buf, kmess_buf+1, sizeof(kmess_buf)-1);
- } else blpos++;
+ if(kmess.blpos == maxblpos) {
+ memmove(kmess.kmess_buf,
+ kmess.kmess_buf+1, sizeof(kmess.kmess_buf)-1);
+ } else kmess.blpos++;
} else {
int p;
endpoint_t outprocs[] = OUTPUT_PROCS_ARRAY;
- if(!(minix_panicing || do_serial_debug)) {
+ if(!(kinfo.minix_panicing || kinfo.do_serial_debug)) {
for(p = 0; outprocs[p] != NONE; p++) {
- if(isokprocn(outprocs[p]) && !isemptyn(outprocs[p])) {
+ if(isokprocn(outprocs[p])) {
send_sig(outprocs[p], SIGKMESS);
}
}
return;
}
-void cpu_print_freq(unsigned cpu)
-{
- u64_t freq;
-
- freq = cpu_get_freq(cpu);
- printf("CPU %d freq %lu MHz\n", cpu, div64u(freq, 1000000));
-}
-
-int is_fpu(void)
-{
- return get_cpulocal_var(fpu_presence);
-}
typedef struct _asynfd asynfd_t;
+#undef IDLE
+
typedef enum state { IDLE, WAITING, PENDING } state_t;
}
sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf;
- i = sys_umap(SELF, D,
+ i = sys_umap(SELF, VM_D,
(vir_bytes) sub_dev_ptr->DmaBuf,
(phys_bytes) sizeof(sub_dev_ptr->DmaBuf),
&(sub_dev_ptr->DmaPhys));
#include <machine/elf.h>
#include <machine/vmparam.h>
#include <machine/memory.h>
+#include <minix/syslib.h>
/* For verbose logging */
#define ELF_DEBUG 0
{
*hdr = (Elf_Ehdr *) exec_hdr;
if(!elf_sane(*hdr)) {
-#if ELF_DEBUG
- printf("elf_sane failed\n");
-#endif
+ printf("elf_unpack: elf_sane failed\n");
return ENOEXEC;
}
*phdr = (Elf_Phdr *)(exec_hdr + (*hdr)->e_phoff);
if(!elf_ph_sane(*phdr)) {
-#if ELF_DEBUG
- printf("elf_ph_sane failed\n");
-#endif
+ printf("elf_unpack: elf_ph_sane failed\n");
return ENOEXEC;
}
#if 0
return OK;
}
-int read_header_elf(
- char *exec_hdr, /* executable header */
- int hdr_len, /* significant bytes in exec_hdr */
- vir_bytes *text_vaddr, /* text virtual address */
- phys_bytes *text_paddr, /* text physical address */
- vir_bytes *text_filebytes, /* text segment size (in the file) */
- vir_bytes *text_membytes, /* text segment size (in memory) */
- vir_bytes *data_vaddr, /* data virtual address */
- phys_bytes *data_paddr, /* data physical address */
- vir_bytes *data_filebytes, /* data segment size (in the file) */
- vir_bytes *data_membytes, /* data segment size (in memory) */
- vir_bytes *pc, /* program entry point (initial PC) */
- off_t *text_offset, /* file offset to text segment */
- off_t *data_offset /* file offset to data segment */
-)
-{
- Elf_Ehdr *hdr = NULL;
- Elf_Phdr *phdr = NULL;
- unsigned long seg_filebytes, seg_membytes;
- int e, i = 0;
-
- *text_vaddr = *text_paddr = 0;
- *text_filebytes = *text_membytes = 0;
- *data_vaddr = *data_paddr = 0;
- *data_filebytes = *data_membytes = 0;
- *pc = *text_offset = *data_offset = 0;
-
- if((e=elf_unpack(exec_hdr, hdr_len, &hdr, &phdr)) != OK) {
-#if ELF_DEBUG
- printf("elf_unpack failed\n");
-#endif
- return e;
- }
-
-#if ELF_DEBUG
- printf("Program header file offset (phoff): %ld\n", hdr->e_phoff);
- printf("Section header file offset (shoff): %ld\n", hdr->e_shoff);
- printf("Program header entry size (phentsize): %d\n", hdr->e_phentsize);
- printf("Program header entry num (phnum): %d\n", hdr->e_phnum);
- printf("Section header entry size (shentsize): %d\n", hdr->e_shentsize);
- printf("Section header entry num (shnum): %d\n", hdr->e_shnum);
- printf("Section name strings index (shstrndx): %d\n", hdr->e_shstrndx);
- printf("Entry Point: 0x%lx\n", hdr->e_entry);
-#endif
-
- for (i = 0; i < hdr->e_phnum; i++) {
- switch (phdr[i].p_type) {
- case PT_LOAD:
- if (phdr[i].p_memsz == 0)
- break;
- seg_filebytes = phdr[i].p_filesz;
- seg_membytes = round_page(phdr[i].p_memsz + phdr[i].p_vaddr -
- trunc_page(phdr[i].p_vaddr));
-
- if (hdr->e_entry >= phdr[i].p_vaddr &&
- hdr->e_entry < (phdr[i].p_vaddr + phdr[i].p_memsz)) {
- *text_vaddr = phdr[i].p_vaddr;
- *text_paddr = phdr[i].p_paddr;
- *text_filebytes = seg_filebytes;
- *text_membytes = seg_membytes;
- *pc = (vir_bytes)hdr->e_entry;
- *text_offset = phdr[i].p_offset;
- } else {
- *data_vaddr = phdr[i].p_vaddr;
- *data_paddr = phdr[i].p_paddr;
- *data_filebytes = seg_filebytes;
- *data_membytes = seg_membytes;
- *data_offset = phdr[i].p_offset;
- }
- break;
- default:
- break;
- }
- }
-
-#if ELF_DEBUG
- printf("Text vaddr: 0x%lx\n", *text_vaddr);
- printf("Text paddr: 0x%lx\n", *text_paddr);
- printf("Text filebytes: 0x%lx\n", *text_filebytes);
- printf("Text membytes: 0x%lx\n", *text_membytes);
- printf("Data vaddr: 0x%lx\n", *data_vaddr);
- printf("Data paddr: 0x%lx\n", *data_paddr);
- printf("Data filebyte: 0x%lx\n", *data_filebytes);
- printf("Data membytes: 0x%lx\n", *data_membytes);
- printf("PC: 0x%lx\n", *pc);
- printf("Text offset: 0x%lx\n", *text_offset);
- printf("Data offset: 0x%lx\n", *data_offset);
-#endif
-
- return OK;
-}
-
#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
(ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
(ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
}
execi->stack_size = roundup(execi->stack_size, PAGE_SIZE);
- execi->stack_high = VM_STACKTOP;
- assert(!(VM_STACKTOP % PAGE_SIZE));
+ execi->stack_high = rounddown(execi->stack_high, PAGE_SIZE);
stacklow = execi->stack_high - execi->stack_size;
assert(execi->copymem);
return ENOMEM;
}
+#if ELF_DEBUG
+ printf("stack mmapped 0x%lx-0x%lx\n", stacklow, stacklow+execi->stack_size);
+#endif
+
/* record entry point and lowest load vaddr for caller */
execi->pc = hdr->e_entry;
execi->load_base = startv;
return sys_memset(execi->proc_e, 0, vaddr, len);
}
+int libexec_copy_memcpy(struct exec_info *execi,
+ off_t off, off_t vaddr, size_t len)
+{
+ assert(off + len <= execi->hdr_len);
+ memcpy((char *) vaddr, (char *) execi->hdr + off, len);
+ return OK;
+}
+
+int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len)
+{
+ memset((char *) vaddr, 0, len);
+ return OK;
+}
+
void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base)
{
/* When doing an exec(name, argv, envp) call, the user builds up a stack
int elf_has_interpreter(char *exec_hdr, int hdr_len, char *interp, int maxsz);
int elf_phdr(char *exec_hdr, int hdr_len, vir_bytes *phdr);
-int read_header_elf(char *exec_hdr, int hdr_len,
- vir_bytes *text_vaddr, phys_bytes *text_paddr,
- vir_bytes *text_filebytes, vir_bytes *text_membytes,
- vir_bytes *data_vaddr, phys_bytes *data_paddr,
- vir_bytes *data_filebytes, vir_bytes *data_membytes,
- vir_bytes *pc, off_t *text_offset, off_t *data_offset);
void libexec_patch_ptr(char stack[ARG_MAX], vir_bytes base);
int libexec_pm_newexec(endpoint_t proc_e, struct exec_info *execi);
typedef int (*libexec_exec_loadfunc_t)(struct exec_info *execi);
int libexec_load_elf(struct exec_info *execi);
+int libexec_copy_memcpy(struct exec_info *execi, off_t offset, off_t vaddr, size_t len);
+int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len);
int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len);
int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len);
int libexec_clearproc_vm_procctl(struct exec_info *execi);
int _cpufeature(int cpufeature)
{
u32_t eax, ebx, ecx, edx;
- int proc;
eax = ebx = ecx = edx = 0;
- proc = getprocessor();
- /* If processor supports CPUID and its CPUID supports enough
- * parameters, retrieve EDX feature flags to test against.
- */
- if(proc >= 586) {
- eax = 0;
+ /* We assume >= pentium for cpuid */
+ eax = 0;
+ _cpuid(&eax, &ebx, &ecx, &edx);
+ if(eax > 0) {
+ eax = 1;
_cpuid(&eax, &ebx, &ecx, &edx);
- if(eax > 0) {
- eax = 1;
- _cpuid(&eax, &ebx, &ecx, &edx);
- }
}
switch(cpufeature) {
sys_kill.c \
sys_mcontext.c \
sys_memset.c \
- sys_newmap.c \
sys_out.c \
sys_physcopy.c \
sys_privctl.c \
vm_umap.c \
vm_yield_get_block.c \
vm_procctl.c \
- vprintf.c \
+ vprintf.c
.if ${MKCOVERAGE} != "no"
SRCS+= gcov.c \
#include <sys/mman.h>
#include <minix/sysutil.h>
-int sys_umap_data_fb(endpoint_t ep, vir_bytes buf, vir_bytes len, phys_bytes *phys)
-{
- int r;
-
- if((r=sys_umap(ep, VM_D, buf, len, phys)) != OK) {
- if(r != EINVAL)
- return r;
- r = sys_umap(ep, D, buf, len, phys);
- }
-
-
- return r;
-}
-
-
void *alloc_contig(size_t len, int flags, phys_bytes *phys)
{
vir_bytes buf;
}
/* Get physical address, if requested. */
- if(phys != NULL && sys_umap_data_fb(SELF, buf, len, phys) != OK)
+ if(phys != NULL && sys_umap(SELF, VM_D, buf, len, phys) != OK)
panic("sys_umap_data_fb failed");
return (void *) buf;
int max_len; /* maximum length of value */
{
message m;
- static char mon_params[128*sizeof(char *)]; /* copy parameters here */
+ static char mon_params[MULTIBOOT_PARAM_BUF_SIZE]; /* copy parameters here */
char *key_value;
int i, s;
size_t keylen;
struct memory *mem_chunks; /* where to store the memory bits */
int maxchunks; /* how many were found */
{
- int i, done = 0;
- char *s;
- struct memory *memp;
- char memstr[100], *end;
+ static kinfo_t kinfo;
+ int mm;
- /* Initialize everything to zero. */
- for (i = 0; i < maxchunks; i++) {
- memp = &mem_chunks[i]; /* next mem chunk is stored here */
- memp->base = memp->size = 0;
- }
-
- /* The available memory is determined by MINIX' boot loader as a list of
- * (base:size)-pairs in boothead.s. The 'memory' boot variable is set in
- * in boot.s. The format is "b0:s0,b1:s1,b2:s2", where b0:s0 is low mem,
- * b1:s1 is mem between 1M and 16M, b2:s2 is mem above 16M. Pairs b1:s1
- * and b2:s2 are combined if the memory is adjacent.
- */
- if(env_get_param("memory", memstr, sizeof(memstr)-1) != OK)
- return -1;
- s = memstr;
- for (i = 0; i < maxchunks && !done; i++) {
- phys_bytes base = 0, size = 0;
- memp = &mem_chunks[i]; /* next mem chunk is stored here */
- if (*s != 0) { /* get fresh data, unless at end */
+ sys_getkinfo(&kinfo);
- /* Read fresh base and expect colon as next char. */
- base = strtoul(s, &end, 0x10); /* get number */
- if (end != s && *end == ':') s = ++end; /* skip ':' */
- else *s=0; /* terminate, should not happen */
+ /* Initialize everything to zero. */
+ memset(mem_chunks, 0, maxchunks*sizeof(*mem_chunks));
- /* Read fresh size and expect comma or assume end. */
- size = strtoul(s, &end, 0x10); /* get number */
- if (end != s && *end == ',') s = ++end; /* skip ',' */
- else done = 1;
- }
- if (base + size <= base) continue;
- memp->base = base;
- memp->size = size;
+ for(mm = 0; mm < MAXMEMMAP; mm++) {
+ mem_chunks[mm].base = kinfo.memmap[mm].addr;
+ mem_chunks[mm].size = kinfo.memmap[mm].len;
}
return OK;
if (c != 0) {
/* Append a single character to the output buffer. */
- print_buf[buf_count++] = c;
+ print_buf[buf_count] = c;
+ buf_count++;
}
}
panic("RS unable to complete init: %d", r);
}
}
- else {
+ else if(sef_self_endpoint == VM_PROC_NR) {
+ /* VM handles initialization by RS later */
+ } else {
message m;
/* Wait for an initialization message from RS. We need this to learn the
#include "syslib.h"
-int sys_fork(parent, child, child_endpoint, map_ptr, flags, msgaddr)
+int sys_fork(parent, child, child_endpoint, flags, msgaddr)
endpoint_t parent; /* process doing the fork */
endpoint_t child; /* which proc has been created by the fork */
endpoint_t *child_endpoint;
-struct mem_map *map_ptr;
u32_t flags;
vir_bytes *msgaddr;
{
m.PR_ENDPT = parent;
m.PR_SLOT = child;
- m.PR_MEM_PTR = (char *) map_ptr;
m.PR_FORK_FLAGS = flags;
r = _kernel_call(SYS_FORK, &m);
*child_endpoint = m.PR_ENDPT;
+++ /dev/null
-#include "syslib.h"
-
-int sys_newmap(
-endpoint_t proc_ep, /* process whose map is to be changed */
-struct mem_map *ptr /* pointer to new map */
-)
-{
-/* A process has been assigned a new memory map. Tell the kernel. */
-
- message m;
-
- m.PR_ENDPT = proc_ep;
- m.PR_MEM_PTR = (char *) ptr;
- return(_kernel_call(SYS_NEWMAP, &m));
-}
/* provide backwards compatability arguments to old
* kernels based on process id's; NONE <=> physical
*/
- copy_mess.CP_DST_SPACE_OBSOLETE = (dst_proc == NONE ? PHYS_SEG : D);
- copy_mess.CP_SRC_SPACE_OBSOLETE = (src_proc == NONE ? PHYS_SEG : D);
+ copy_mess.CP_DST_SPACE_OBSOLETE = (dst_proc == NONE ? PHYS_SEG : D_OBSOLETE);
+ copy_mess.CP_SRC_SPACE_OBSOLETE = (src_proc == NONE ? PHYS_SEG : D_OBSOLETE);
return(_kernel_call(SYS_PHYSCOPY, ©_mess));
}
/* for older kernels that still need the 'seg' field
* provide the right value.
*/
- copy_mess.SCP_SEG_OBSOLETE = D;
+ copy_mess.SCP_SEG_OBSOLETE = D_OBSOLETE;
return(_kernel_call(SYS_SAFECOPYFROM, ©_mess));
/* for older kernels that still need the 'seg' field
* provide the right value.
*/
- copy_mess.SCP_SEG_OBSOLETE = D;
+ copy_mess.SCP_SEG_OBSOLETE = D_OBSOLETE;
return(_kernel_call(SYS_SAFECOPYTO, ©_mess));
copy_mess.SMAP_BYTES = bytes;
copy_mess.SMAP_FLAG = writable;
- copy_mess.SMAP_SEG_OBSOLETE = (void *) D;
+ copy_mess.SMAP_SEG_OBSOLETE = (void *) D_OBSOLETE;
return(_kernel_call(SYS_SAFEMAP, ©_mess));
copy_mess.SMAP_ADDRESS = my_address;
- copy_mess.SMAP_SEG_OBSOLETE = (void *) D;
+ copy_mess.SMAP_SEG_OBSOLETE = (void *) D_OBSOLETE;
return(_kernel_call(SYS_SAFEUNMAP, ©_mess));
}
copy_mess.CP_NR_BYTES = (long) bytes;
/* backwards compatability D segs */
- copy_mess.CP_DST_SPACE_OBSOLETE = D;
- copy_mess.CP_SRC_SPACE_OBSOLETE = D;
+ copy_mess.CP_DST_SPACE_OBSOLETE = D_OBSOLETE;
+ copy_mess.CP_SRC_SPACE_OBSOLETE = D_OBSOLETE;
return(_kernel_call(SYS_VIRCOPY, ©_mess));
}
return r;
}
-int sys_vmctl_enable_paging(void * data)
-{
- message m;
- m.SVMCTL_WHO = SELF;
- m.SVMCTL_PARAM = VMCTL_ENABLE_PAGING;
- m.SVMCTL_VALUE = (u32_t) data;
- return _kernel_call(SYS_VMCTL, &m);
-}
-
int sys_vmctl_get_mapping(int index,
phys_bytes *addr, phys_bytes *len, int *flags)
{
VAssert_Init(void)
{
uint32 eax, ebx, ecx, edx;
- VA page_address = (VA) &vassert_state.inReplay, ph;
+ VA page_address = (VA) &vassert_state.inReplay;
if (!VAssert_IsInVM()) {
return -1;
}
}
#endif
- /* vmware expects a linear address (or is simply forgetting
- * to adjust the given address for segments)
- */
-
- if(sys_umap(SELF, D, page_address, 1, (phys_bytes *) &ph)) {
- printf("VAssert_Init: sys_umap failed\n");
- return -1;
- }
-
- libvassert_process_backdoor(CMD_SET_ADDRESS, ph,
+ libvassert_process_backdoor(CMD_SET_ADDRESS, page_address,
MAGIC_PORT|(1<<16), &eax, &ebx, &ecx, &edx);
return (eax != -1) ? 0 : -1;
BINDIR?= /usr/sbin
-LDFLAGS+= -Wl,--section-start=.init=0x0
-
.include <bsd.prog.mk>
char *name;
} hooks[] = {
{ F1, proctab_dmp, "Kernel process table" },
- { F2, memmap_dmp, "Process memory maps" },
{ F3, image_dmp, "System image" },
{ F4, privileges_dmp, "Process privileges" },
{ F5, monparams_dmp, "Boot monitor parameters" },
static char *s_traps_str(int flags);
static char *s_flags_str(int flags);
static char *p_rts_flags_str(int flags);
-static char *boot_flags_str(int flags);
/* Some global data that is shared among several dumping procedures.
* Note that the process table copy has the same name as in the kernel
*===========================================================================*/
void monparams_dmp()
{
- char val[1024];
+ char val[MULTIBOOT_PARAM_BUF_SIZE];
char *e;
int r;
printf("\n");
}
-/*===========================================================================*
- * boot_flags_str *
- *===========================================================================*/
-static char *boot_flags_str(int flags)
-{
- static char str[10];
- str[0] = (flags & PROC_FULLVM) ? 'V' : '-';
- str[1] = '\0';
-
- return str;
-}
-
/*===========================================================================*
* image_dmp *
*===========================================================================*/
printf("---name- -nr- flags -stack-\n");
for (m=0; m<NR_BOOT_PROCS; m++) {
ip = &image[m];
- printf("%8s %4d %5s\n",
- ip->proc_name, ip->proc_nr,
- boot_flags_str(ip->flags));
+ printf("%8s %4d\n", ip->proc_name, ip->proc_nr);
}
printf("\n");
}
printf("Dump of kinfo structure.\n\n");
printf("Kernel info structure:\n");
- printf("- code_base: %5lu\n", kinfo.code_base);
- printf("- code_size: %5lu\n", kinfo.code_size);
- printf("- data_base: %5lu\n", kinfo.data_base);
- printf("- data_size: %5lu\n", kinfo.data_size);
- printf("- proc_addr: %5lu\n", kinfo.proc_addr);
- printf("- bootdev_base: %5lu\n", kinfo.bootdev_base);
- printf("- bootdev_size: %5lu\n", kinfo.bootdev_size);
- printf("- ramdev_base: %5lu\n", kinfo.ramdev_base);
- printf("- ramdev_size: %5lu\n", kinfo.ramdev_size);
printf("- nr_procs: %3u\n", kinfo.nr_procs);
printf("- nr_tasks: %3u\n", kinfo.nr_tasks);
printf("- release: %.6s\n", kinfo.release);
register struct proc *rp;
static struct proc *oldrp = BEG_PROC_ADDR;
int r;
- phys_clicks text, data, size;
/* First obtain a fresh copy of the current process table. */
if ((r = sys_getproctab(proc)) != OK) {
printf("\n-nr-----gen---endpoint-name--- -prior-quant- -user----sys-rtsflags-from/to-\n");
PROCLOOP(rp, oldrp)
- text = rp->p_memmap[T].mem_phys;
- data = rp->p_memmap[D].mem_phys;
- size = rp->p_memmap[T].mem_len
- + ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len) - data);
printf(" %5d %10d ", _ENDPOINT_G(rp->p_endpoint), rp->p_endpoint);
printf("%-8.8s %5u %5u %6lu %6lu ",
rp->p_name,
}
}
-/*===========================================================================*
- * memmap_dmp *
- *===========================================================================*/
-void memmap_dmp()
-{
- register struct proc *rp;
- static struct proc *oldrp = proc;
- int r;
- phys_clicks size;
-
- /* First obtain a fresh copy of the current process table. */
- if ((r = sys_getproctab(proc)) != OK) {
- printf("IS: warning: couldn't get copy of process table: %d\n", r);
- return;
- }
-
- printf("\n-nr/name--- --pc-- --sp-- -text---- -data---- -stack--- -cr3-\n");
- PROCLOOP(rp, oldrp)
- size = rp->p_memmap[T].mem_len
- + ((rp->p_memmap[S].mem_phys + rp->p_memmap[S].mem_len)
- - rp->p_memmap[D].mem_phys);
- printf("%-7.7s%7lx %8lx %4x %4x %4x %4x %5x %5x %8u\n",
- rp->p_name,
- (unsigned long) rp->p_reg.pc,
- (unsigned long) rp->p_reg.sp,
- rp->p_memmap[T].mem_phys, rp->p_memmap[T].mem_len,
- rp->p_memmap[D].mem_phys, rp->p_memmap[D].mem_len,
- rp->p_memmap[S].mem_phys, rp->p_memmap[S].mem_len,
- rp->p_seg.p_cr3);
- }
-}
-
/*===========================================================================*
* proc_name *
*===========================================================================*/
{
static int vri_count, vri_prev_set;
static struct vm_region_info vri_prev;
- char c;
int is_repeat;
/* part of a contiguous identical run? */
is_repeat =
vri &&
vri_prev_set &&
- vri->vri_seg == vri_prev.vri_seg &&
vri->vri_prot == vri_prev.vri_prot &&
vri->vri_flags == vri_prev.vri_flags &&
vri->vri_length == vri_prev.vri_length &&
/* NULL indicates the end of a list of mappings, nothing else to do */
if (!vri) return;
- /* first in a run, print all info */
- switch (vri->vri_seg) {
- case T: c = 'T'; break;
- case D: c = 'D'; break;
- default: c = '?';
- }
-
- printf(" %c %08lx-%08lx %c%c%c %c (%lu kB)\n", c, vri->vri_addr,
+ printf(" %08lx-%08lx %c%c%c %c (%lu kB)\n", vri->vri_addr,
vri->vri_addr + vri->vri_length,
(vri->vri_prot & PROT_READ) ? 'r' : '-',
(vri->vri_prot & PROT_WRITE) ? 'w' : '-',
/* dmp_kernel.c */
void proctab_dmp(void);
void procstack_dmp(void);
-void memmap_dmp(void);
void privileges_dmp(void);
void image_dmp(void);
void irqtab_dmp(void);
*
* The entry points into this file are:
* do_exec: perform the EXEC system call
- * do_exec_newmem: allocate new memory map for a process that tries to exec
+ * do_newexec: handle PM part of exec call after VFS
* do_execrestart: finish the special exec call for RS
* exec_restart: finish a regular exec call
*/
proc_e= m_in.EXC_NM_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK) {
- panic("do_exec_newmem: got bad endpoint: %d", proc_e);
+ panic("do_newexec: got bad endpoint: %d", proc_e);
}
rmp= &mproc[proc_n];
ptr= m_in.EXC_NM_PTR;
r= sys_datacopy(who_e, (vir_bytes)ptr,
SELF, (vir_bytes)&args, sizeof(args));
if (r != OK)
- panic("do_exec_newmem: sys_datacopy failed: %d", r);
+ panic("do_newexec: sys_datacopy failed: %d", r);
allow_setuid = 0; /* Do not allow setuid execution */
rmp->mp_flags &= ~TAINTED; /* By default not tainted */
/* Global variables. */
EXTERN struct mproc *mp; /* ptr to 'mproc' slot of current process */
EXTERN int procs_in_use; /* how many processes are marked as IN_USE */
-EXTERN char monitor_params[128*sizeof(char *)]; /* boot monitor parameters */
+EXTERN char monitor_params[MULTIBOOT_PARAM_BUF_SIZE];
EXTERN struct kinfo kinfo; /* kernel information */
/* Misc.c */
EXTERN u32_t system_hz; /* System clock frequency. */
EXTERN int abort_flag;
-EXTERN char monitor_code[256];
EXTERN struct machine machine; /* machine info */
#ifdef CONFIG_SMP
* Handle its reply first.
*/
if (call_nr == PM_REBOOT_REPLY) {
- vir_bytes code_addr;
- size_t code_size;
-
/* Ask the kernel to abort. All system services, including
* the PM, will get a HARD_STOP notification. Await the
* notification in the main loop.
*/
- code_addr = (vir_bytes) monitor_code;
- code_size = strlen(monitor_code) + 1;
- sys_abort(abort_flag, PM_PROC_NR, code_addr, code_size);
+ sys_abort(RBT_DEFAULT);
return;
}
/* See how the system should be aborted. */
abort_flag = (unsigned) m_in.reboot_flag;
if (abort_flag >= RBT_INVALID) return(EINVAL);
- if (RBT_MONITOR == abort_flag) {
- int r;
- if(m_in.reboot_strlen >= sizeof(monitor_code))
- return EINVAL;
- if((r = sys_datacopy(who_e, (vir_bytes) m_in.reboot_code,
- SELF, (vir_bytes) monitor_code, m_in.reboot_strlen)) != OK)
- return r;
- monitor_code[m_in.reboot_strlen] = '\0';
- }
- else
- monitor_code[0] = '\0';
/* Order matters here. When VFS is told to reboot, it exits all its
* processes, and then would be confused if they're exited again by
memset(&vui, 0, sizeof(vui));
if (!is_zombie(i)) {
- /* We don't care if this fails. It may still return
- * zero memory usage for processes that don't have a
- * pagetable, though. Look at vui_total instead.
- */
+ /* We don't care if this fails. */
(void) vm_info_usage(proc[i].p_endpoint, &vui);
-
- if (vui.vui_total == 0L) {
- vui.vui_total =
- (proc[i].p_memmap[T].mem_len +
- proc[i].p_memmap[D].mem_len) <<
- CLICK_SHIFT;
- }
}
if (mproc[pi].mp_flags & PAUSED)
*/
struct vm_region_info vri[MAX_VRI_COUNT];
vir_bytes next;
- int i, r, seg, count;
+ int i, r, count;
count = 0;
next = 0;
break;
for (i = 0; i < r; i++) {
- switch (vri[i].vri_seg) {
- case T: seg = 'T'; break;
- case D: seg = 'D'; break;
- default: seg = '?'; break;
- }
-
- buf_printf("%c %08lx-%08lx %c%c%c %c\n",
- seg, vri[i].vri_addr,
- vri[i].vri_addr + vri[i].vri_length,
+ buf_printf("%08lx-%08lx %c%c%c %c\n",
+ vri[i].vri_addr, vri[i].vri_addr + vri[i].vri_length,
(vri[i].vri_prot & PROT_READ) ? 'r' : '-',
(vri[i].vri_prot & PROT_WRITE) ? 'w' : '-',
(vri[i].vri_prot & PROT_EXEC) ? 'x' : '-',
return count;
}
-/*===========================================================================*
- * dump_segments *
- *===========================================================================*/
-static void dump_segments(int slot)
-{
- /* Print the memory segments of a process.
- */
- int i;
-
- for (i = 0; i < NR_LOCAL_SEGS; i++) {
- buf_printf("%c %08lx-%08lx %s -\n",
- i == T ? 'T' : 'D',
- proc[slot].p_memmap[i].mem_vir << CLICK_SHIFT,
- (proc[slot].p_memmap[i].mem_vir +
- proc[slot].p_memmap[i].mem_len) << CLICK_SHIFT,
- (i == T) ? "r-x" :
- (proc[slot].p_memmap[T].mem_len == 0) ? "rwx" : "rw-");
- }
-}
-
/*===========================================================================*
* pid_map *
*===========================================================================*/
if (dump_regions(slot) != 0)
return;
}
-
- /* For kernel tasks, or for processes that have no regions according to
- * VM, we assume they are not using virtual memory, and we print their
- * segments instead.
- */
- dump_segments(slot);
}
#define SRV_SF (SF_CORE_SRV) /* system services */
#define SRVR_SF (SRV_SF | SF_NEED_REPL) /* services needing a replica */
#define DSRV_SF (0) /* dynamic system services */
-#define VM_SF (SRVR_SF | SF_SYNCH_BOOT) /* vm */
+#define VM_SF (SRVR_SF) /* vm */
/* Define device flags for the various process types. */
#define SRV_DF (DRV_FORCED) /* system services */
static int exec_restart(int proc_e, int result, vir_bytes pc);
static int read_seg(struct exec_info *execi, off_t off,
off_t seg_addr, size_t seg_bytes);
+static int exec_restart(int proc_e, int result, vir_bytes pc);
/* Array of loaders for different object formats */
static struct exec_loaders {
memset(&execi, 0, sizeof(execi));
+ execi.stack_high = kinfo.user_sp;
execi.stack_size = DEFAULT_STACK_LIMIT;
execi.proc_e = proc_e;
execi.hdr = exec;
EXTERN struct machine machine; /* machine info */
+EXTERN struct kinfo kinfo; /* kernel information */
+
#endif /* RS_GLO_H */
if (OK != (s=sys_getmachine(&machine)))
panic("couldn't get machine info: %d", s);
+ if (OK != (s=sys_getkinfo(&kinfo)))
+ panic("couldn't get kernel kinfo: %d", s);
+
/* Main loop - get work and do it, forever. */
while (TRUE) {
fill_call_mask(calls, NR_SYS_CALLS,
rp->r_priv.s_k_call_mask, KERNEL_CALL, TRUE);
- /* Set the privilege structure. */
- if(boot_image_priv->endpoint != RS_PROC_NR) {
+ /* Set the privilege structure. RS and VM are exceptions and are already
+ * running.
+ */
+ if(boot_image_priv->endpoint != RS_PROC_NR &&
+ boot_image_priv->endpoint != VM_PROC_NR) {
if ((s = sys_privctl(ip->endpoint, SYS_PRIV_SET_SYS, &(rp->r_priv)))
!= OK) {
panic("unable to set privilege structure: %d", s);
rp = &rproc[boot_image_priv - boot_image_priv_table];
rpub = rp->r_pub;
- /* RS is already running as we speak. */
- if(boot_image_priv->endpoint == RS_PROC_NR) {
+ /* RS/VM are already running as we speak. */
+ if(boot_image_priv->endpoint == RS_PROC_NR ||
+ boot_image_priv->endpoint == VM_PROC_NR) {
if ((s = init_service(rp, SEF_INIT_FRESH)) != OK) {
- panic("unable to initialize RS: %d", s);
+ panic("unable to initialize %d: %d", boot_image_priv->endpoint, s);
}
continue;
}
panic("couldn't set alarm: %d", s);
#if USE_LIVEUPDATE
- /* Now create a new RS instance with a private page table and let the current
+ /* Now create a new RS instance and let the current
* instance live update into the replica. Clone RS' own slot first.
*/
rp = rproc_ptr[_ENDPOINT_P(RS_PROC_NR)];
if (rp->r_flags & RS_EXITING) {
/* If a core system service is exiting, we are in trouble. */
if (rp->r_pub->sys_flags & SF_CORE_SRV && !shutting_down) {
- panic("core system service died: %s", srv_to_string(rp));
+ printf("core system service died: %s\n", srv_to_string(rp));
+ _exit(1);
}
/* See if a late reply has to be sent. */
/* passed from exec() libc code */
execi.userflags = user_exec_flags;
+ execi.args.stack_high = kinfo.user_sp;
execi.args.stack_size = DEFAULT_STACK_LIMIT;
okendpt(proc_e, &slot);
if (off + seg_bytes > LONG_MAX) return(EIO);
if ((unsigned long) vp->v_size < off+seg_bytes) return(EIO);
- if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING,
- execi->proc_e, (char*)seg_addr, seg_bytes,
- &new_pos, &cum_io)) != OK) {
- printf("VFS: read_seg: req_readwrite failed (data)\n");
- return(r);
- }
+ if ((r = req_readwrite(vp->v_fs_e, vp->v_inode_nr, cvul64(off), READING,
+ execi->proc_e, (char*)seg_addr, seg_bytes,
+ &new_pos, &cum_io)) != OK) {
+ printf("VFS: read_seg: req_readwrite failed (data)\n");
+ return(r);
+ }
- if (r == OK && cum_io != seg_bytes)
- printf("VFS: read_seg segment has not been read properly\n");
+ if (r == OK && cum_io != seg_bytes)
+ printf("VFS: read_seg segment has not been read properly\n");
return(r);
}
extern int(*pfs_call_vec[]) (void);
extern char mode_map[]; /* mapping from O_ACCMODE mask to R_BIT/W_BIT flags */
+EXTERN struct kinfo kinfo; /* kernel information */
+
#endif
printf("Started VFS: %d worker thread(s)\n", NR_WTHREADS);
+ if (OK != (sys_getkinfo(&kinfo)))
+ panic("couldn't get kernel kinfo");
+
/* This is the main loop that gets work, processes it, and sends replies. */
while (TRUE) {
yield_all(); /* let other threads run */
no_sys, /* 97 = unused */
no_sys, /* 98 = (sprofile) */
no_sys, /* 99 = (cprofile) */
- no_sys, /* 100 = (exec_newmem) */
+ no_sys, /* 100 = (newexec) */
no_sys, /* 101 = (srv_fork) */
no_sys, /* 102 = (exec_restart) */
no_sys, /* 103 = unused */
.include <bsd.own.mk>
PROG= vm
-SRCS= main.c alloc.c utility.c exec.c exit.c fork.c break.c \
+SRCS= main.c alloc.c utility.c exit.c fork.c break.c \
signal.c mmap.c slaballoc.c region.c pagefaults.c addravl.c \
physravl.c rs.c queryexit.c yieldedavl.c regionavl.c
DPADD+= ${LIBSYS}
-LDADD+= -lsys
+LDADD+= -lsys -lexec
MAN=
}
#if SANITYCHECKS
-static void sanitycheck(void)
+void mem_sanitycheck(char *file, int line)
{
pagerange_t *p, *prevp = NULL;
addr_iter iter;
assert(p->size > 0);
if(prevp) {
assert(prevp->addr < p->addr);
- assert(prevp->addr + p->addr < p->addr);
+ assert(prevp->addr + prevp->size < p->addr);
}
+ usedpages_add(p->addr * VM_PAGE_SIZE, p->size * VM_PAGE_SIZE);
+ prevp = p;
addr_incr_iter(&iter);
}
}
*nodes = 0;
*pages = 0;
*largest = 0;
-#if SANITYCHECKS
- sanitycheck();
-#endif
+
while((p=addr_get_iter(&iter))) {
SLABSANE(p);
(*nodes)++;
#endif
memstats(&firstnodes, &firstpages, &largest);
- sanitycheck();
wantnodes = firstnodes;
wantpages = firstpages - pages;
#endif
#if SANITYCHECKS
memstats(&finalnodes, &finalpages, &largest);
- sanitycheck();
assert(finalnodes == wantnodes);
assert(finalpages == wantpages);
int finalnodes, finalpages, largest;
memstats(&firstnodes, &firstpages, &largest);
- sanitycheck();
wantnodes = firstnodes;
wantpages = firstpages + npages;
wantnodes = firstnodes;
wantpages = firstpages + npages;
- sanitycheck();
#endif
assert(npages > 0);
USE(pr, pr->addr = pageno;
#if SANITYCHECKS
memstats(&finalnodes, &finalpages, &largest);
- sanitycheck();
assert(finalnodes == wantnodes);
assert(finalpages == wantpages);
*===========================================================================*/
int usedpages_add_f(phys_bytes addr, phys_bytes len, char *file, int line)
{
- pagerange_t *pr;
u32_t pagestart, pages;
if(!incheck)
assert(pagestart < MAXPAGES);
thisaddr = pagestart * VM_PAGE_SIZE;
if(GET_BIT(pagemap, pagestart)) {
- int i;
printf("%s:%d: usedpages_add: addr 0x%lx reused.\n",
file, line, thisaddr);
return EFAULT;
#Arch-specific sources
.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}
-SRCS+= vm.c pagetable.c #util.S
+SRCS+= pagetable.c #util.S
+++ /dev/null
-
-#include <minix/config.h>
-#include <minix/const.h>
-#include <minix/type.h>
-#include <minix/com.h>
-#include <minix/ipc.h>
-#include <minix/safecopies.h>
-#include <timers.h>
-
-struct vm_arch {
- struct mem_map vm_seg[NR_LOCAL_SEGS]; /* text, data, stack */
-
- /* vm_data_top points to top of data address space, as visible
- * from user-space, in bytes.
- * for segments processes this is the same
- * as the top of vm_seg[S] segment. for paged processes this
- * can be much higher (so more memory is available above the
- * stack).
- */
- u32_t vm_data_top; /* virtual process space in bytes */
-};
#include <machine/vm.h>
/* And what is the highest addressable piece of memory, when in paged
- * mode? Some data for kernel and stack are subtracted from this, the
- * final results stored in bytes in arch.vm_data_top.
+ * mode?
*/
-#define VM_DATATOP 0xFFFFF000
+#define VM_DATATOP kernel_boot_info.user_end
+#define VM_STACKTOP kernel_boot_info.user_sp
#define SLAB_PAGESIZE I386_PAGE_SIZE
#define VM_PAGE_SIZE I386_PAGE_SIZE
-/* Where do processes start in linear (i.e. page table) memory? */
-#define VM_PROCSTART (I386_BIG_PAGE_SIZE*100)
-
#define CLICKSPERPAGE (I386_PAGE_SIZE/CLICK_SIZE)
-
-/* Where is the kernel? */
-#define KERNEL_TEXT CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[T].mem_phys)
-#define KERNEL_TEXT_LEN CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[T].mem_len)
-#define KERNEL_DATA CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[D].mem_phys)
-#define KERNEL_DATA_LEN CLICK2ABS(vmproc[VMP_SYSTEM].vm_arch.vm_seg[D].mem_len \
- + vmproc[VMP_SYSTEM].vm_arch.vm_seg[S].mem_len)
-
#include "memory.h"
-/* Free PDE slots we tell kernel about */
-#define FREE_PDES 2
-static int first_free_pde = -1;
-
/* PDE used to map in kernel, kernel physical address. */
-static int id_map_high_pde = -1, pagedir_pde = -1;
+static int pagedir_pde = -1;
static u32_t global_bit = 0, pagedir_pde_val;
-static int proc_pde = 0;
+static multiboot_module_t *kern_mb_mod = NULL;
+static size_t kern_size = 0;
+static int kern_start_pde = -1;
/* 4MB page size available in hardware? */
static int bigpage_ok = 0;
* circular dependency on allocating memory and writing it into VM's
* page table.
*/
-#define SPAREPAGES 25
+#define SPAREPAGES 15
int missing_spares = SPAREPAGES;
static struct {
void *page;
static struct {
phys_bytes phys_addr; /* Physical addr. */
phys_bytes len; /* Length in bytes. */
- vir_bytes lin_addr; /* Offset in page table. */
+ vir_bytes vir_addr; /* Offset in page table. */
int flags;
} kern_mappings[MAX_KERNMAPPINGS];
int kernmappings = 0;
#error CLICK_SIZE must be page size.
#endif
-/* Bytes of virtual address space one pde controls. */
-#define BYTESPERPDE (I386_VM_PT_ENTRIES * I386_PAGE_SIZE)
-
-/* Nevertheless, introduce these macros to make the code readable. */
-#define CLICK2PAGE(c) ((c) / CLICKSPERPAGE)
-
/* Page table that contains pointers to all page directories. */
phys_bytes page_directories_phys;
u32_t *page_directories = NULL;
#define STATIC_SPAREPAGES 10
-static char static_sparepages[I386_PAGE_SIZE*STATIC_SPAREPAGES + I386_PAGE_SIZE];
+static char static_sparepages[I386_PAGE_SIZE*STATIC_SPAREPAGES + I386_PAGE_SIZE] __aligned(I386_PAGE_SIZE);
#if SANITYCHECKS
/*===========================================================================*
void pt_sanitycheck(pt_t *pt, char *file, int line)
{
/* Basic pt sanity check. */
- int i;
int slot;
MYASSERT(pt);
}
MYASSERT(usedpages_add(pt->pt_dir_phys, I386_PAGE_SIZE) == OK);
-
- for(i = proc_pde; i < I386_VM_DIR_ENTRIES; i++) {
- if(pt->pt_pt[i]) {
- int pte;
- MYASSERT(vm_addrok(pt->pt_pt[i], 1));
- if(!(pt->pt_dir[i] & I386_VM_PRESENT)) {
- printf("slot %d: pt->pt_pt[%d] = %p, but pt_dir entry 0x%lx\n",
- slot, i, pt->pt_pt[i], pt->pt_dir[i]);
- }
- MYASSERT(pt->pt_dir[i] & I386_VM_PRESENT);
- MYASSERT(usedpages_add(I386_VM_PFA(pt->pt_dir[i]),
- I386_PAGE_SIZE) == OK);
- } else {
- MYASSERT(!(pt->pt_dir[i] & I386_VM_PRESENT));
- }
- }
}
#endif
/*===========================================================================*
* findhole *
*===========================================================================*/
-static u32_t findhole(pt_t *pt, u32_t vmin, u32_t vmax)
+static u32_t findhole(void)
{
-/* Find a space in the virtual address space of pageteble 'pt',
- * between page-aligned BYTE offsets vmin and vmax, to fit
- * a page in. Return byte offset.
- */
+/* Find a space in the virtual address space of VM. */
u32_t curv;
int pde = 0, try_restart;
static u32_t lastv = 0;
+ pt_t *pt = &vmprocess->vm_pt;
+ extern char _end;
+ vir_bytes vmin, vmax;
+
+ vmin = (vir_bytes) (&_end) & I386_VM_ADDR_MASK; /* marks end of VM BSS */
+ vmax = VM_STACKTOP;
/* Input sanity check. */
assert(vmin + I386_PAGE_SIZE >= vmin);
static void vm_freepages(vir_bytes vir, vir_bytes phys, int pages, int reason)
{
assert(reason >= 0 && reason < VMP_CATEGORIES);
- if(vir >= vmprocess->vm_stacktop) {
- assert(!(vir % I386_PAGE_SIZE));
- assert(!(phys % I386_PAGE_SIZE));
- free_mem(ABS2CLICK(phys), pages);
- if(pt_writemap(vmprocess, &vmprocess->vm_pt, arch_vir2map(vmprocess, vir),
- MAP_NONE, pages*I386_PAGE_SIZE, 0, WMF_OVERWRITE) != OK)
- panic("vm_freepages: pt_writemap failed");
- } else {
- printf("VM: vm_freepages not freeing VM heap pages (%d)\n",
- pages);
+ assert(!(vir % I386_PAGE_SIZE));
+ assert(!(phys % I386_PAGE_SIZE));
+ extern char _end;
+
+ if(vir < (vir_bytes) &_end) {
+ printf("VM: not freeing static page\n");
+ return;
}
+ free_mem(ABS2CLICK(phys), pages);
+ if(pt_writemap(vmprocess, &vmprocess->vm_pt, vir,
+ MAP_NONE, pages*I386_PAGE_SIZE, 0, WMF_OVERWRITE) != OK)
+ panic("vm_freepages: pt_writemap failed");
+
#if SANITYCHECKS
/* If SANITYCHECKS are on, flush tlb so accessing freed pages is
* always trapped, also if not in tlb.
assert(level >= 1);
assert(level <= 2);
- if(level > 1 || !(vmprocess->vm_flags & VMF_HASPT) || !meminit_done) {
+ if(level > 1 || !meminit_done) {
void *s;
s=vm_getsparepage(phys);
level--;
/* VM does have a pagetable, so get a page and map it in there.
* Where in our virtual address space can we put it?
*/
- loc = findhole(pt, arch_vir2map(vmprocess, vmprocess->vm_stacktop),
- vmprocess->vm_arch.vm_data_top);
+ loc = findhole();
if(loc == NO_MEM) {
level--;
printf("VM: vm_allocpage: findhole failed\n");
level--;
/* Return user-space-ready pointer to it. */
- ret = (void *) arch_map2vir(vmprocess, loc);
+ ret = (void *) loc;
return ret;
}
void vm_pagelock(void *vir, int lockflag)
{
/* Mark a page allocated by vm_allocpage() unwritable, i.e. only for VM. */
- vir_bytes m;
+ vir_bytes m = (vir_bytes) vir;
int r;
u32_t flags = I386_VM_PRESENT | I386_VM_USER;
pt_t *pt;
pt = &vmprocess->vm_pt;
- m = arch_vir2map(vmprocess, (vir_bytes) vir);
assert(!(m % I386_PAGE_SIZE));
*===========================================================================*/
int vm_addrok(void *vir, int writeflag)
{
-/* Mark a page allocated by vm_allocpage() unwritable, i.e. only for VM. */
pt_t *pt = &vmprocess->vm_pt;
int pde, pte;
- vir_bytes v = arch_vir2map(vmprocess, (vir_bytes) vir);
-
- /* No PT yet? Don't bother looking. */
- if(!(vmprocess->vm_flags & VMF_HASPT)) {
- return 1;
- }
+ vir_bytes v = (vir_bytes) vir;
pde = I386_VM_PDE(v);
pte = I386_VM_PTE(v);
/* Allocate all the page tables in the range specified. */
int pde, first_pde, last_pde;
- first_pde = start ? I386_VM_PDE(start) : proc_pde;
- last_pde = end ? I386_VM_PDE(end) : I386_VM_DIR_ENTRIES - 1;
+ first_pde = I386_VM_PDE(start);
+ last_pde = I386_VM_PDE(end-1);
assert(first_pde >= 0);
assert(last_pde < I386_VM_DIR_ENTRIES);
return r;
}
}
+ assert(pt->pt_dir[pde]);
assert(pt->pt_dir[pde] & I386_VM_PRESENT);
}
end = end ? end : VM_DATATOP;
assert(start % I386_PAGE_SIZE == 0);
assert(end % I386_PAGE_SIZE == 0);
- assert(I386_VM_PDE(start) >= proc_pde && start <= end);
+ assert(I386_VM_PDE(start) >= 0 && start <= end);
assert(I386_VM_PDE(end) < I386_VM_DIR_ENTRIES);
#if LU_DEBUG
vir_bytes viraddr;
pt_t *pt;
- assert(src_vmp->vm_stacktop == dst_vmp->vm_stacktop);
pt = &src_vmp->vm_pt;
#if LU_DEBUG
#endif
/* Transfer mapping to the page directory. */
- assert((vir_bytes) pt->pt_dir >= src_vmp->vm_stacktop);
- viraddr = arch_vir2map(src_vmp, (vir_bytes) pt->pt_dir);
+ viraddr = (vir_bytes) pt->pt_dir;
physaddr = pt->pt_dir_phys & I386_VM_ADDR_MASK;
if((r=pt_writemap(dst_vmp, &dst_vmp->vm_pt, viraddr, physaddr, I386_PAGE_SIZE,
I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE,
#endif
/* Scan all non-reserved page-directory entries. */
- for(pde=proc_pde; pde < I386_VM_DIR_ENTRIES; pde++) {
+ for(pde=0; pde < I386_VM_DIR_ENTRIES; pde++) {
if(!(pt->pt_dir[pde] & I386_VM_PRESENT)) {
continue;
}
/* Transfer mapping to the page table. */
- assert((vir_bytes) pt->pt_pt[pde] >= src_vmp->vm_stacktop);
- viraddr = arch_vir2map(src_vmp, (vir_bytes) pt->pt_pt[pde]);
+ viraddr = (vir_bytes) pt->pt_pt[pde];
physaddr = pt->pt_dir[pde] & I386_VM_ADDR_MASK;
if((r=pt_writemap(dst_vmp, &dst_vmp->vm_pt, viraddr, physaddr, I386_PAGE_SIZE,
I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE,
return r;
}
}
-#if LU_DEBUG
- printf("VM: pt_ptmap: transferred mappings to page tables, pde range %d - %d\n",
- proc_pde, I386_VM_DIR_ENTRIES - 1);
-#endif
return OK;
}
void pt_clearmapcache(void)
{
- int f;
/* Make sure kernel will invalidate tlb when using current
* pagetable (i.e. vm's) to make new mappings before new cr3
* is loaded.
*/
- for(f = first_free_pde; f < first_free_pde+FREE_PDES; f++) {
- vmprocess->vm_pt.pt_dir[f] = 0;
- }
+ if(sys_vmctl(SELF, VMCTL_CLEARMAPCACHE, 0) != OK)
+ panic("VMCTL_CLEARMAPCACHE failed");
}
/*===========================================================================*
*/
ret = pt_ptalloc_in_range(pt, v, v + I386_PAGE_SIZE*pages, flags, verify);
if(ret != OK) {
+ printf("VM: writemap: pt_ptalloc_in_range failed\n");
goto resume_exit;
}
int pde = I386_VM_PDE(v);
int pte = I386_VM_PTE(v);
+ if(!v) { printf("VM: warning: making zero page for %d\n",
+ vmp->vm_endpoint); }
+
assert(!(v % I386_PAGE_SIZE));
assert(pte >= 0 && pte < I386_VM_PT_ENTRIES);
assert(pde >= 0 && pde < I386_VM_DIR_ENTRIES);
/* Page table has to be there. */
assert(pt->pt_dir[pde] & I386_VM_PRESENT);
+ /* We do not expect it to be a bigpage. */
+ assert(!(pt->pt_dir[pde] & I386_VM_BIGPAGE));
+
/* Make sure page directory entry for this page table
* is marked present and page table entry is available.
*/
- assert((pt->pt_dir[pde] & I386_VM_PRESENT));
assert(pt->pt_pt[pde]);
#if SANITYCHECKS
}
} else {
/* Write pagetable entry. */
-#if SANITYCHECKS
- assert(vm_addrok(pt->pt_pt[pde], 1));
-#endif
pt->pt_pt[pde][pte] = entry;
}
return OK;
}
+static int freepde(void)
+{
+ int p = kernel_boot_info.freepde_start++;
+ assert(kernel_boot_info.freepde_start < I386_VM_DIR_ENTRIES);
+ return p;
+}
+
/*===========================================================================*
* pt_init *
*===========================================================================*/
-void pt_init(phys_bytes usedlimit)
+void pt_init(void)
{
-/* By default, the kernel gives us a data segment with pre-allocated
- * memory that then can't grow. We want to be able to allocate memory
- * dynamically, however. So here we copy the part of the page table
- * that's ours, so we get a private page table. Then we increase the
- * hardware segment size so we can allocate memory above our stack.
- */
pt_t *newpt;
- int s, r;
- vir_bytes v;
- phys_bytes lo, hi;
- vir_bytes extra_clicks;
- u32_t moveup = 0;
+ int s, r, p;
int global_bit_ok = 0;
- int free_pde;
- struct vm_ep_data ep_data;
vir_bytes sparepages_mem;
- phys_bytes sparepages_ph;
- vir_bytes ptr;
- int f = 0;
-
- /* Shorthand. */
- newpt = &vmprocess->vm_pt;
+ static u32_t currentpagedir[I386_VM_DIR_ENTRIES];
+ int m = kernel_boot_info.kern_mod;
+ u32_t mycr3;
+
+ /* Find what the physical location of the kernel is. */
+ assert(m >= 0);
+ assert(m < kernel_boot_info.mods_with_kernel);
+ assert(kernel_boot_info.mods_with_kernel < MULTIBOOT_MAX_MODS);
+ kern_mb_mod = &kernel_boot_info.module_list[m];
+ kern_size = kern_mb_mod->mod_end - kern_mb_mod->mod_start;
+ assert(!(kern_mb_mod->mod_start % I386_BIG_PAGE_SIZE));
+ assert(!(kernel_boot_info.vir_kern_start % I386_BIG_PAGE_SIZE));
+ kern_start_pde = kernel_boot_info.vir_kern_start / I386_BIG_PAGE_SIZE;
/* Get ourselves spare pages. */
- ptr = (vir_bytes) static_sparepages;
- ptr += I386_PAGE_SIZE - (ptr % I386_PAGE_SIZE);
- if(!(sparepages_mem = ptr))
- panic("pt_init: aalloc for spare failed");
- if((r=sys_umap(SELF, VM_D, (vir_bytes) sparepages_mem,
- I386_PAGE_SIZE*SPAREPAGES, &sparepages_ph)) != OK)
- panic("pt_init: sys_umap failed: %d", r);
+ sparepages_mem = (vir_bytes) static_sparepages;
+ assert(!(sparepages_mem % I386_PAGE_SIZE));
+
+ /* Spare pages are used to allocate memory before VM has its own page
+ * table that things (i.e. arbitrary physical memory) can be mapped into.
+ * We get it by pre-allocating it in our bss (allocated and mapped in by
+ * the kernel) in static_sparepages. We also need the physical addresses
+ * though; we look them up now so they are ready for use.
+ */
missing_spares = 0;
assert(STATIC_SPAREPAGES < SPAREPAGES);
for(s = 0; s < SPAREPAGES; s++) {
+ vir_bytes v = (sparepages_mem + s*I386_PAGE_SIZE);;
+ phys_bytes ph;
+ if((r=sys_umap(SELF, VM_D, (vir_bytes) v,
+ I386_PAGE_SIZE*SPAREPAGES, &ph)) != OK)
+ panic("pt_init: sys_umap failed: %d", r);
if(s >= STATIC_SPAREPAGES) {
sparepages[s].page = NULL;
missing_spares++;
continue;
}
- sparepages[s].page = (void *) (sparepages_mem + s*I386_PAGE_SIZE);
- sparepages[s].phys = sparepages_ph + s*I386_PAGE_SIZE;
+ sparepages[s].page = (void *) v;
+ sparepages[s].phys = ph;
}
/* global bit and 4MB pages available? */
if(global_bit_ok)
global_bit = I386_VM_GLOBAL;
- /* The kernel and boot time processes need an identity mapping.
- * We use full PDE's for this without separate page tables.
- * Figure out which pde we can start using for other purposes.
- */
- id_map_high_pde = usedlimit / I386_BIG_PAGE_SIZE;
-
- /* We have to make mappings up till here. */
- free_pde = id_map_high_pde+1;
-
- /* Initial (current) range of our virtual address space. */
- lo = CLICK2ABS(vmprocess->vm_arch.vm_seg[T].mem_phys);
- hi = CLICK2ABS(vmprocess->vm_arch.vm_seg[S].mem_phys +
- vmprocess->vm_arch.vm_seg[S].mem_len);
-
- assert(!(lo % I386_PAGE_SIZE));
- assert(!(hi % I386_PAGE_SIZE));
-
- if(lo < VM_PROCSTART) {
- moveup = VM_PROCSTART - lo;
- assert(!(VM_PROCSTART % I386_PAGE_SIZE));
- assert(!(lo % I386_PAGE_SIZE));
- assert(!(moveup % I386_PAGE_SIZE));
- }
-
- /* Make new page table for ourselves, partly copied
- * from the current one.
- */
- if(pt_new(newpt) != OK)
- panic("pt_init: pt_new failed");
-
- /* Set up mappings for VM process. */
- for(v = lo; v < hi; v += I386_PAGE_SIZE) {
- /* We have to write the new position in the PT,
- * so we can move our segments.
- */
- if(pt_writemap(vmprocess, newpt, v+moveup, v, I386_PAGE_SIZE,
- I386_VM_PRESENT|I386_VM_WRITE|I386_VM_USER, 0) != OK)
- panic("pt_init: pt_writemap failed");
- }
-
- /* Move segments up too. */
- vmprocess->vm_arch.vm_seg[T].mem_phys += ABS2CLICK(moveup);
- vmprocess->vm_arch.vm_seg[D].mem_phys += ABS2CLICK(moveup);
- vmprocess->vm_arch.vm_seg[S].mem_phys += ABS2CLICK(moveup);
-
/* Allocate us a page table in which to remember page directory
* pointers.
*/
panic("no virt addr for vm mappings");
memset(page_directories, 0, I386_PAGE_SIZE);
-
- /* Increase our hardware data segment to create virtual address
- * space above our stack. We want to increase it to VM_DATATOP,
- * like regular processes have.
- */
- extra_clicks = ABS2CLICK(VM_DATATOP - hi);
- vmprocess->vm_arch.vm_seg[S].mem_len += extra_clicks;
-
- /* We pretend to the kernel we have a huge stack segment to
- * increase our data segment.
- */
- vmprocess->vm_arch.vm_data_top =
- (vmprocess->vm_arch.vm_seg[S].mem_vir +
- vmprocess->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT;
-
- /* Where our free virtual address space starts.
- * This is only a hint to the VM system.
- */
- newpt->pt_virtop = 0;
-
- /* Let other functions know VM now has a private page table. */
- vmprocess->vm_flags |= VMF_HASPT;
/* Now reserve another pde for kernel's own mappings. */
{
int flags, index = 0;
u32_t offset = 0;
- kernmap_pde = free_pde++;
+ kernmap_pde = freepde();
offset = kernmap_pde * I386_BIG_PAGE_SIZE;
while(sys_vmctl_get_mapping(index, &addr, &len,
kern_mappings[index].phys_addr = addr;
kern_mappings[index].len = len;
kern_mappings[index].flags = flags;
- kern_mappings[index].lin_addr = offset;
+ kern_mappings[index].vir_addr = offset;
kern_mappings[index].flags =
- I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE |
- global_bit;
+ I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE;
if(flags & VMMF_UNCACHED)
kern_mappings[index].flags |= PTF_NOCACHE;
if(addr % I386_PAGE_SIZE)
panic("VM: addr unaligned: %d", addr);
if(len % I386_PAGE_SIZE)
panic("VM: len unaligned: %d", len);
- vir = arch_map2vir(&vmproc[VMP_SYSTEM], offset);
+ vir = offset;
if(sys_vmctl_reply_mapping(index, vir) != OK)
panic("VM: reply failed");
offset += len;
}
/* Find a PDE below processes available for mapping in the
- * page directories (readonly).
+ * page directories.
*/
- pagedir_pde = free_pde++;
+ pagedir_pde = freepde();
pagedir_pde_val = (page_directories_phys & I386_VM_ADDR_MASK) |
- I386_VM_PRESENT | I386_VM_USER | I386_VM_WRITE;
-
- /* Tell kernel about free pde's. */
- first_free_pde = free_pde;
- while(free_pde*I386_BIG_PAGE_SIZE < VM_PROCSTART && f < FREE_PDES) {
- if((r=sys_vmctl(SELF, VMCTL_I386_FREEPDE, free_pde++)) != OK) {
- panic("VMCTL_I386_FREEPDE failed: %d", r);
- }
- f++;
- }
+ I386_VM_PRESENT | I386_VM_WRITE;
+
+ /* Allright. Now. We have to make our own page directory and page tables,
+ * that the kernel has already set up, accessible to us. It's easier to
+ * understand if we just copy all the required pages (i.e. page directory
+ * and page tables), and set up the pointers as if VM had done it itself.
+ *
+ * This allocation will happen without using any page table, and just
+ * uses spare pages.
+ */
+ newpt = &vmprocess->vm_pt;
+ if(pt_new(newpt) != OK)
+ panic("vm pt_new failed");
+
+ /* Get our current pagedir so we can see it. */
+ if(sys_vmctl_get_cr3_i386(SELF, &mycr3) != OK)
+ panic("VM: sys_vmctl_get_cr3_i386 failed");
+ if(sys_vircopy(NONE, mycr3, SELF,
+ (vir_bytes) currentpagedir, I386_PAGE_SIZE) != OK)
+ panic("VM: sys_vircopy failed");
+
+ /* We have mapped in kernel ourselves; now copy mappings for VM
+ * that kernel made, including allocations for BSS. Skip identity
+ * mapping bits; just map in VM.
+ */
+ for(p = 0; p < I386_VM_DIR_ENTRIES; p++) {
+ u32_t entry = currentpagedir[p];
+ phys_bytes ptaddr_kern, ptaddr_us;
- /* first pde in use by process. */
- proc_pde = free_pde;
+ /* BIGPAGEs are kernel mapping (do ourselves) or boot
+ * identity mapping (don't want).
+ */
+ if(!(entry & I386_VM_PRESENT)) continue;
+ if((entry & I386_VM_BIGPAGE)) continue;
- /* Give our process the new, copied, private page table. */
- pt_mapkernel(newpt); /* didn't know about vm_dir pages earlier */
- pt_bind(newpt, vmprocess);
-
- /* new segment limit for the kernel after paging is enabled */
- ep_data.data_seg_limit = free_pde*I386_BIG_PAGE_SIZE;
- /* the memory map which must be installed after paging is enabled */
- ep_data.mem_map = vmprocess->vm_arch.vm_seg;
+ if(pt_ptalloc(newpt, p, 0) != OK)
+ panic("pt_ptalloc failed");
+ assert(newpt->pt_dir[p] & I386_VM_PRESENT);
- /* Now actually enable paging. */
- if(sys_vmctl_enable_paging(&ep_data) != OK)
- panic("pt_init: enable paging failed");
+ ptaddr_kern = entry & I386_VM_ADDR_MASK;
+ ptaddr_us = newpt->pt_dir[p] & I386_VM_ADDR_MASK;
- /* Back to reality - this is where the stack actually is. */
- vmprocess->vm_arch.vm_seg[S].mem_len -= extra_clicks;
+ /* Copy kernel-initialized pagetable contents into our
+ * normally accessible pagetable.
+ */
+ if(sys_abscopy(ptaddr_kern, ptaddr_us, I386_PAGE_SIZE) != OK)
+ panic("pt_init: abscopy failed");
+ }
- /* Pretend VM stack top is the same as any regular process, not to
- * have discrepancies with new VM instances later on.
- */
- vmprocess->vm_stacktop = VM_STACKTOP;
+ /* Inform kernel vm has a newly built page table. */
+ assert(vmproc[VM_PROC_NR].vm_endpoint == VM_PROC_NR);
+ pt_mapkernel(newpt);
+ pt_bind(newpt, &vmproc[VM_PROC_NR]);
/* All OK. */
return;
}
-/*===========================================================================*
- * pt_init_mem *
- *===========================================================================*/
-void pt_init_mem()
-{
-/* Architecture-specific memory initialization. Make sure all the pages
- * shared with the kernel and VM's page tables are mapped above the stack,
- * so that we can easily transfer existing mappings for new VM instances.
- */
- phys_bytes new_page_directories_phys;
- u32_t *new_page_directories;
- phys_bytes new_pt_dir_phys;
- u32_t *new_pt_dir;
- phys_bytes new_pt_phys;
- u32_t *new_pt;
- pt_t *vmpt;
- int i;
-
- vmpt = &vmprocess->vm_pt;
-
- /* We should be running this when VM has been assigned a page
- * table and memory initialization has already been performed.
- */
- assert(vmprocess->vm_flags & VMF_HASPT);
- assert(meminit_done);
-
- /* Throw away static spare pages. */
- vm_checkspares();
- for(i = 0; i < SPAREPAGES; i++) {
- if(sparepages[i].page && (vir_bytes) sparepages[i].page
- < vmprocess->vm_stacktop) {
- sparepages[i].page = NULL;
- missing_spares++;
- }
- }
- vm_checkspares();
-
- /* Rellocate page for page directories pointers. */
- if(!(new_page_directories = vm_allocpage(&new_page_directories_phys,
- VMP_PAGETABLE)))
- panic("unable to reallocated page for page dir ptrs");
- assert((vir_bytes) new_page_directories >= vmprocess->vm_stacktop);
- memcpy(new_page_directories, page_directories, I386_PAGE_SIZE);
- page_directories = new_page_directories;
- pagedir_pde_val = (new_page_directories_phys & I386_VM_ADDR_MASK) |
- (pagedir_pde_val & ~I386_VM_ADDR_MASK);
-
- /* Remap in kernel. */
- pt_mapkernel(vmpt);
-
- /* Reallocate VM's page directory. */
- if((vir_bytes) vmpt->pt_dir < vmprocess->vm_stacktop) {
- if(!(new_pt_dir= vm_allocpage(&new_pt_dir_phys, VMP_PAGEDIR))) {
- panic("unable to reallocate VM's page directory");
- }
- assert((vir_bytes) new_pt_dir >= vmprocess->vm_stacktop);
- memcpy(new_pt_dir, vmpt->pt_dir, I386_PAGE_SIZE);
- vmpt->pt_dir = new_pt_dir;
- vmpt->pt_dir_phys = new_pt_dir_phys;
- pt_bind(vmpt, vmprocess);
- }
-
- /* Reallocate VM's page tables. */
- for(i = proc_pde; i < I386_VM_DIR_ENTRIES; i++) {
- if(!(vmpt->pt_dir[i] & I386_VM_PRESENT)) {
- continue;
- }
- assert(vmpt->pt_pt[i]);
- if((vir_bytes) vmpt->pt_pt[i] >= vmprocess->vm_stacktop) {
- continue;
- }
- vm_checkspares();
- if(!(new_pt = vm_allocpage(&new_pt_phys, VMP_PAGETABLE)))
- panic("unable to reallocate VM's page table");
- assert((vir_bytes) new_pt >= vmprocess->vm_stacktop);
- memcpy(new_pt, vmpt->pt_pt[i], I386_PAGE_SIZE);
- vmpt->pt_pt[i] = new_pt;
- vmpt->pt_dir[i] = (new_pt_phys & I386_VM_ADDR_MASK) |
- (vmpt->pt_dir[i] & ~I386_VM_ADDR_MASK);
- }
-}
-
/*===========================================================================*
* pt_bind *
*===========================================================================*/
/* This is where the PDE's will be visible to the kernel
* in its address space.
*/
- pdes = (void *) arch_map2vir(&vmproc[VMP_SYSTEM],
- pagedir_pde*I386_BIG_PAGE_SIZE +
+ pdes = (void *) (pagedir_pde*I386_BIG_PAGE_SIZE +
slot * I386_PAGE_SIZE);
#if 0
slot, who->vm_endpoint, page_directories[slot], pdes);
#endif
/* Tell kernel about new page table root. */
- return sys_vmctl_set_addrspace(who->vm_endpoint,
- pt ? pt->pt_dir_phys : 0,
- pt ? pdes : 0);
+ return sys_vmctl_set_addrspace(who->vm_endpoint, pt->pt_dir_phys, pdes);
}
/*===========================================================================*
int pt_mapkernel(pt_t *pt)
{
int i;
+ int kern_pde = kern_start_pde;
+ phys_bytes addr, mapped = 0;
/* Any i386 page table needs to map in the kernel address space. */
- assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE);
-
- if(bigpage_ok) {
- int pde;
- for(pde = 0; pde <= id_map_high_pde; pde++) {
- phys_bytes addr;
- addr = pde * I386_BIG_PAGE_SIZE;
- assert((addr & I386_VM_ADDR_MASK) == addr);
- pt->pt_dir[pde] = addr | I386_VM_PRESENT |
- I386_VM_BIGPAGE | I386_VM_USER |
- I386_VM_WRITE | global_bit;
- }
- } else {
- panic("VM: pt_mapkernel: no bigpage");
+ assert(bigpage_ok);
+ assert(pagedir_pde >= 0);
+ assert(kern_pde >= 0);
+
+ /* pt_init() has made sure this is ok. */
+ addr = kern_mb_mod->mod_start;
+
+ /* Actually mapping in kernel */
+ while(mapped < kern_size) {
+ pt->pt_dir[kern_pde] = addr | I386_VM_PRESENT |
+ I386_VM_BIGPAGE | I386_VM_WRITE | global_bit;
+ kern_pde++;
+ mapped += I386_BIG_PAGE_SIZE;
+ addr += I386_BIG_PAGE_SIZE;
}
- if(pagedir_pde >= 0) {
- /* Kernel also wants to know about all page directories. */
- pt->pt_dir[pagedir_pde] = pagedir_pde_val;
- }
+ /* Kernel also wants to know about all page directories. */
+ assert(pagedir_pde > kern_pde);
+ pt->pt_dir[pagedir_pde] = pagedir_pde_val;
+ /* Kernel also wants various mappings of its own. */
for(i = 0; i < kernmappings; i++) {
if(pt_writemap(NULL, pt,
- kern_mappings[i].lin_addr,
+ kern_mappings[i].vir_addr,
kern_mappings[i].phys_addr,
kern_mappings[i].len,
kern_mappings[i].flags, 0) != OK) {
+++ /dev/null
-
-#define _SYSTEM 1
-
-#include <minix/callnr.h>
-#include <minix/com.h>
-#include <minix/config.h>
-#include <minix/const.h>
-#include <minix/ds.h>
-#include <minix/endpoint.h>
-#include <minix/keymap.h>
-#include <minix/minlib.h>
-#include <minix/type.h>
-#include <minix/ipc.h>
-#include <minix/sysutil.h>
-#include <minix/syslib.h>
-#include <minix/bitmap.h>
-
-#include <sys/mman.h>
-
-#include <errno.h>
-#include <assert.h>
-#include <env.h>
-
-#include "proto.h"
-#include "vm.h"
-#include "util.h"
-
-#include "memory.h"
-
-/*===========================================================================*
- * arch_map2vir *
- *===========================================================================*/
-vir_bytes arch_map2vir(struct vmproc *vmp, vir_bytes addr)
-{
- vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
- vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
- vir_bytes datasegbase = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys -
- vmp->vm_arch.vm_seg[D].mem_vir);
-
- /* Could be a text address. */
- assert(datastart <= addr || textstart <= addr);
-
- return addr - datasegbase;
-}
-
-/*===========================================================================*
- * arch_map2str *
- *===========================================================================*/
-char *arch_map2str(struct vmproc *vmp, vir_bytes addr)
-{
- static char bufstr[100];
- vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
- vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
- vir_bytes textsegbase = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys -
- vmp->vm_arch.vm_seg[T].mem_vir);
- vir_bytes datasegbase = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys -
- vmp->vm_arch.vm_seg[D].mem_vir);
-
- if(addr < textstart) {
- sprintf(bufstr, "<lin:0x%lx>", addr);
- } else if(addr < datastart) {
- sprintf(bufstr, "0x%lx (codeseg)", addr - textsegbase);
- } else {
- sprintf(bufstr, "0x%lx (dataseg)", addr - datasegbase);
- }
-
- return bufstr;
-}
-
-/*===========================================================================*
- * arch_map2info *
- *===========================================================================*/
-vir_bytes arch_map2info(struct vmproc *vmp, vir_bytes addr, int *seg,
- int *prot)
-{
- vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
- vir_bytes textend = textstart +
- CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_len);
- vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
- vir_bytes textsegbase = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys -
- vmp->vm_arch.vm_seg[T].mem_vir);
- vir_bytes datasegbase = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys -
- vmp->vm_arch.vm_seg[D].mem_vir);
-
- /* The protection to be returned here is that of the segment. */
- if(addr < textstart) {
- *seg = D;
- *prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- return addr;
- } else if(addr < datastart) {
- *seg = T;
- *prot = PROT_READ | PROT_EXEC;
- return addr - textsegbase;
- } else {
- *seg = D;
- if (textstart == textend) /* common I&D? */
- *prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- else
- *prot = PROT_READ | PROT_WRITE;
- return addr - datasegbase;
- }
-}
-
-/*===========================================================================*
- * arch_addrok *
- *===========================================================================*/
-vir_bytes arch_addrok(struct vmproc *vmp, vir_bytes addr)
-{
- vir_bytes textstart = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys);
- vir_bytes textend = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys +
- vmp->vm_arch.vm_seg[T].mem_phys);
- vir_bytes datastart = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys);
-
- if(addr >= textstart && addr < textstart+textend)
- return 1;
-
- if(addr >= datastart && addr < VM_DATATOP)
- return 1;
-
- return 0;
-}
-
-/*===========================================================================*
- * arch_vir2map *
- *===========================================================================*/
-vir_bytes arch_vir2map(struct vmproc *vmp, vir_bytes addr)
-{
- vir_bytes datasegbase = CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys -
- vmp->vm_arch.vm_seg[D].mem_vir);
-
- return addr + datasegbase;
-}
-
-/*===========================================================================*
- * arch_vir2map_text *
- *===========================================================================*/
-vir_bytes arch_vir2map_text(struct vmproc *vmp, vir_bytes addr)
-{
- vir_bytes textsegbase = CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys -
- vmp->vm_arch.vm_seg[T].mem_vir);
-
- return addr + textsegbase;
-}
return real_brk(&vmproc[proc], (vir_bytes) msg->VMB_ADDR);
}
-/*===========================================================================*
- * adjust *
- *===========================================================================*/
-int adjust(rmp, data_clicks, sp)
-struct vmproc *rmp; /* whose memory is being adjusted? */
-vir_clicks data_clicks; /* how big is data segment to become? */
-vir_bytes sp; /* new value of sp */
-{
-/* See if data and stack segments can coexist, adjusting them if need be.
- * Memory is never allocated or freed. Instead it is added or removed from the
- * gap between data segment and stack segment. If the gap size becomes
- * negative, the adjustment of data or stack fails and ENOMEM is returned.
- */
-
- register struct mem_map *mem_sp, *mem_dp;
- vir_clicks sp_click, gap_base, sp_lower, old_clicks;
- int changed, r, sp_in_dp;
- long base_of_stack, sp_delta; /* longs avoid certain problems */
-
- mem_dp = &rmp->vm_arch.vm_seg[D]; /* pointer to data segment map */
- mem_sp = &rmp->vm_arch.vm_seg[S]; /* pointer to stack segment map */
- changed = 0; /* set when either segment changed */
-
- /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
- base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
- sp_click = sp >> CLICK_SHIFT; /* click containing sp */
- if (sp_click >= base_of_stack)
- {
- return(ENOMEM); /* sp too high */
- }
-
- /* In order to support user-space libraries, processes might change sp to
- point to somewhere inside the data segment. If that's the case, be careful
- not to erroneously think that the data and stack have collided. */
- sp_in_dp = (mem_dp->mem_vir <= sp_click) &&
- (mem_dp->mem_vir + mem_dp->mem_len >= sp_click);
-
- /* Compute size of gap between stack and data segments. */
- sp_delta = (long) mem_sp->mem_vir - (long) sp_click;
- sp_lower = ((sp_delta > 0 && !sp_in_dp) ? sp_click : mem_sp->mem_vir);
-
- /* Add a safety margin for future stack growth. Impossible to do right. */
-#define SAFETY_BYTES (384 * sizeof(char *))
-#define SAFETY_CLICKS ((vir_clicks) (CLICK_CEIL(SAFETY_BYTES) >> CLICK_SHIFT))
- gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
- if (sp_lower < gap_base)
- {
- return(ENOMEM); /* data and stack collided */
- }
-
- /* Update data length (but not data orgin) on behalf of brk() system call. */
- old_clicks = mem_dp->mem_len;
- if (data_clicks != mem_dp->mem_len) {
- mem_dp->mem_len = data_clicks;
- changed |= DATA_CHANGED;
- }
-
- /* Update stack length and origin due to change in stack pointer. */
- if (sp_delta > 0 && !sp_in_dp) {
- mem_sp->mem_vir -= sp_delta;
- mem_sp->mem_phys -= sp_delta;
- mem_sp->mem_len += sp_delta;
- changed |= STACK_CHANGED;
- }
-
- /* Do the new data and stack segment sizes fit in the address space? */
- r = (rmp->vm_arch.vm_seg[D].mem_vir + rmp->vm_arch.vm_seg[D].mem_len >
- rmp->vm_arch.vm_seg[S].mem_vir) ? ENOMEM : OK;
-
- if(r == OK && (rmp->vm_flags & VMF_HASPT) &&
- rmp->vm_endpoint != VM_PROC_NR && rmp->vm_heap) {
- if(old_clicks < data_clicks) {
- vir_bytes more;
- more = (data_clicks - old_clicks) << CLICK_SHIFT;
- if(map_region_extend(rmp, rmp->vm_heap, more) != OK) {
- printf("VM: brk: map_region_extend failed\n");
- return ENOMEM;
- }
- } else if(old_clicks > data_clicks) {
- vir_bytes less;
- less = (old_clicks - data_clicks) << CLICK_SHIFT;
- if(map_region_shrink(rmp->vm_heap, less) != OK) {
- printf("VM: brk: map_region_shrink failed\n");
- return ENOMEM;
- }
- }
- }
-
- if (r == OK)
- return(OK);
-
- /* New sizes don't fit or require too many page/segment registers. Restore.*/
- if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks;
- if (changed & STACK_CHANGED) {
- mem_sp->mem_vir += sp_delta;
- mem_sp->mem_phys += sp_delta;
- mem_sp->mem_len -= sp_delta;
- }
- return(ENOMEM);
-}
-
/*===========================================================================*
* real_brk *
*===========================================================================*/
struct vmproc *vmp;
vir_bytes v;
{
- if(!(vmp->vm_flags & VMF_HASPT))
- return OK;
-
if(map_region_extend_upto_v(vmp, v) == OK)
return OK;
+++ /dev/null
-
-#define _SYSTEM 1
-
-#include <minix/callnr.h>
-#include <minix/com.h>
-#include <minix/config.h>
-#include <minix/const.h>
-#include <minix/ds.h>
-#include <minix/endpoint.h>
-#include <minix/keymap.h>
-#include <minix/minlib.h>
-#include <minix/type.h>
-#include <minix/ipc.h>
-#include <minix/sysutil.h>
-#include <minix/syslib.h>
-#include <minix/const.h>
-#include <minix/bitmap.h>
-
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <env.h>
-#include <pagetable.h>
-#include <sys/param.h>
-
-#include "glo.h"
-#include "proto.h"
-#include "util.h"
-#include "vm.h"
-#include "region.h"
-#include "sanitycheck.h"
-
-#include "memory.h"
-
-/*===========================================================================*
- * find_kernel_top *
- *===========================================================================*/
-phys_bytes find_kernel_top(void)
-{
-/* Find out where the kernel is, so we know where to start mapping
- * user processes.
- */
- u32_t kernel_top = 0;
-#define MEMTOP(v, i) \
- (vmproc[v].vm_arch.vm_seg[i].mem_phys + vmproc[v].vm_arch.vm_seg[i].mem_len)
- assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE);
- kernel_top = MEMTOP(VMP_SYSTEM, T);
- kernel_top = MAX(kernel_top, MEMTOP(VMP_SYSTEM, D));
- kernel_top = MAX(kernel_top, MEMTOP(VMP_SYSTEM, S));
- assert(kernel_top);
-
- return CLICK2ABS(kernel_top);
-}
-
-void regular_segs(struct vmproc *vmp)
-{
- int s;
- memset(vmp->vm_arch.vm_seg, 0, sizeof(vmp->vm_arch.vm_seg));
- vmp->vm_arch.vm_seg[T].mem_phys =
- vmp->vm_arch.vm_seg[D].mem_phys = ABS2CLICK(VM_PROCSTART);
- vmp->vm_arch.vm_seg[T].mem_len =
- vmp->vm_arch.vm_seg[D].mem_len =
- vmp->vm_arch.vm_seg[S].mem_len = ABS2CLICK(VM_DATATOP-VM_PROCSTART);
- if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK)
- panic("regular_segs: sys_newmap failed: %d", s);
- if((s=pt_bind(&vmp->vm_pt, vmp)) != OK)
- panic("regular_segs: pt_bind failed: %d", s);
-}
-
-/*===========================================================================*
- * proc_new *
- *===========================================================================*/
-int proc_new(struct vmproc *vmp,
- phys_bytes vstart, /* where to start the process in page table */
- phys_bytes text_addr, /* address at which to load code */
- phys_bytes text_bytes, /* how much code, in bytes but page aligned */
- phys_bytes data_addr, /* address at which to load data */
- phys_bytes data_bytes, /* how much data + bss, in bytes but page aligned */
- phys_bytes stack_bytes, /* stack space to reserve, in bytes, page aligned */
- phys_bytes gap_bytes, /* gap bytes, page aligned */
- phys_bytes text_start, /* text starts here, if preallocated, otherwise 0 */
- phys_bytes data_start, /* data starts here, if preallocated, otherwise 0 */
- phys_bytes stacktop,
- int prealloc_stack,
- int is_elf,
- int full_memview
-)
-{
- int s;
- vir_bytes hole_bytes;
- struct vir_region *reg;
- phys_bytes map_text_addr, map_data_addr, map_stack_addr;
-
- assert(!(vstart % VM_PAGE_SIZE));
- assert(!(text_addr % VM_PAGE_SIZE));
- assert(!(text_bytes % VM_PAGE_SIZE));
- assert(!(data_addr % VM_PAGE_SIZE));
- assert(!(data_bytes % VM_PAGE_SIZE));
- assert(!(stack_bytes % VM_PAGE_SIZE));
- assert(!(gap_bytes % VM_PAGE_SIZE));
- assert(!(text_start % VM_PAGE_SIZE));
- assert(!(data_start % VM_PAGE_SIZE));
- assert((!text_start && !data_start) || (text_start && data_start));
-
- /* Place text at start of process. */
- map_text_addr = vstart + text_addr;
- vmp->vm_arch.vm_seg[T].mem_phys = ABS2CLICK(map_text_addr);
- vmp->vm_arch.vm_seg[T].mem_vir = ABS2CLICK(text_addr);
- if(full_memview) {
- vmp->vm_arch.vm_seg[T].mem_len = ABS2CLICK(VM_DATATOP) -
- vmp->vm_arch.vm_seg[T].mem_phys;
- } else {
- vmp->vm_arch.vm_seg[T].mem_len = ABS2CLICK(text_bytes);
- }
-
- vmp->vm_offset = vstart;
-
- /* page mapping flags for code */
-#define TEXTFLAGS (PTF_PRESENT | PTF_USER)
- SANITYCHECK(SCL_DETAIL);
- if(text_bytes > 0) {
- if(!(reg=map_page_region(vmp, map_text_addr, 0, text_bytes,
- text_start ? text_start : MAP_NONE,
- VR_ANON | VR_WRITABLE, text_start ? 0 : MF_PREALLOC))) {
- SANITYCHECK(SCL_DETAIL);
- printf("VM: proc_new: map_page_region failed (text)\n");
- map_free_proc(vmp);
- SANITYCHECK(SCL_DETAIL);
- return(ENOMEM);
- }
-
- map_region_set_tag(reg, VRT_TEXT);
- SANITYCHECK(SCL_DETAIL);
- }
- SANITYCHECK(SCL_DETAIL);
-
- /* Allocate memory for data (including bss, but not including gap
- * or stack), make sure it's cleared, and map it in after text
- * (if any).
- */
- if (is_elf) {
- map_data_addr = vstart + data_addr;
- } else {
- map_data_addr = vstart + text_bytes;
- }
-
- if(!(vmp->vm_heap = map_page_region(vmp, map_data_addr, 0,
- data_bytes, data_start ? data_start : MAP_NONE, VR_ANON | VR_WRITABLE,
- data_start ? 0 : MF_PREALLOC))) {
- printf("VM: exec: map_page_region for data failed\n");
- map_free_proc(vmp);
- SANITYCHECK(SCL_DETAIL);
- return ENOMEM;
- }
-
- /* Tag the heap so brk() call knows which region to extend. */
- map_region_set_tag(vmp->vm_heap, VRT_HEAP);
-
- /* How many address space clicks between end of data
- * and start of stack?
- * stacktop is the first address after the stack, as addressed
- * from within the user process.
- */
- hole_bytes = stacktop - data_bytes - stack_bytes
- - gap_bytes - data_addr;
-
- map_stack_addr = map_data_addr + data_bytes + hole_bytes;
-
- if(!(reg=map_page_region(vmp,
- map_stack_addr,
- 0, stack_bytes + gap_bytes, MAP_NONE,
- VR_ANON | VR_WRITABLE, prealloc_stack ? MF_PREALLOC : 0)) != OK) {
- panic("map_page_region failed for stack");
- }
-
- map_region_set_tag(reg, VRT_STACK);
-
- vmp->vm_arch.vm_seg[D].mem_phys = ABS2CLICK(map_data_addr);
- vmp->vm_arch.vm_seg[D].mem_vir = ABS2CLICK(data_addr);
- vmp->vm_arch.vm_seg[D].mem_len = ABS2CLICK(data_bytes);
-
- vmp->vm_arch.vm_seg[S].mem_phys = ABS2CLICK(map_data_addr +
- data_bytes + gap_bytes + hole_bytes);
- vmp->vm_arch.vm_seg[S].mem_vir = ABS2CLICK(data_addr +
- data_bytes + gap_bytes + hole_bytes);
-
- /* Where are we allowed to start using the rest of the virtual
- * address space?
- */
- vmp->vm_stacktop = stacktop;
-
- vmp->vm_flags |= VMF_HASPT;
-
- if(vmp->vm_endpoint != NONE) {
-
- /* Pretend the stack is the full size of the data segment, so
- * we get a full-sized data segment, up to VM_DATATOP.
- * After sys_newmap(), change the stack to what we know the
- * stack to be (up to stacktop).
- */
- vmp->vm_arch.vm_seg[S].mem_len = (VM_DATATOP >> CLICK_SHIFT) -
- vmp->vm_arch.vm_seg[S].mem_vir - ABS2CLICK(map_data_addr);
-
- /* What is the final size of the data segment in bytes? */
- vmp->vm_arch.vm_data_top =
- (vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len) << CLICK_SHIFT;
-
- if((s=sys_newmap(vmp->vm_endpoint, vmp->vm_arch.vm_seg)) != OK)
- panic("sys_newmap (vm) failed: %d", s);
- if((s=pt_bind(&vmp->vm_pt, vmp)) != OK)
- panic("exec_newmem: pt_bind failed: %d", s);
- }
-
- return OK;
-}
void free_proc(struct vmproc *vmp)
{
map_free_proc(vmp);
- vmp->vm_heap = NULL;
- if(vmp->vm_flags & VMF_HASPT) {
- vmp->vm_flags &= ~VMF_HASPT;
- pt_free(&vmp->vm_pt);
- }
+ pt_free(&vmp->vm_pt);
region_init(&vmp->vm_regions_avl);
vmp->vm_region_top = 0;
#if VMSTATS
vmp->vm_region_top = 0;
vmp->vm_callback = NULL; /* No pending vfs callback. */
vmp->vm_flags = 0; /* Clear INUSE, so slot is free. */
- vmp->vm_heap = NULL;
vmp->vm_yielded = 0;
#if VMSTATS
vmp->vm_bytecopies = 0;
if(vmp->vm_flags & VMF_HAS_DMA) {
release_dma(vmp);
- } else if(vmp->vm_flags & VMF_HASPT) {
+ } else {
/* Free pagetable and pages allocated by pt code. */
SANITYCHECK(SCL_DETAIL);
free_proc(vmp);
SANITYCHECK(SCL_DETAIL);
- } else {
- /* Free the data and stack segments. */
- free_mem(vmp->vm_arch.vm_seg[D].mem_phys,
- vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len -
- vmp->vm_arch.vm_seg[D].mem_vir);
- }
+ }
SANITYCHECK(SCL_DETAIL);
/* Reset process slot fields. */
return EPERM;
free_proc(vmp);
pt_new(&vmp->vm_pt);
- vmp->vm_flags |= VMF_HASPT;
pt_bind(&vmp->vm_pt, vmp);
- regular_segs(vmp);
return OK;
default:
return EINVAL;
*===========================================================================*/
int do_fork(message *msg)
{
- int r, proc, childproc, fullvm;
+ int r, proc, childproc;
struct vmproc *vmp, *vmc;
pt_t origpt;
vir_bytes msgaddr;
return EINVAL;
}
- fullvm = vmp->vm_flags & VMF_HASPT;
-
/* The child is basically a copy of the parent. */
origpt = vmc->vm_pt;
*vmc = *vmp;
region_init(&vmc->vm_regions_avl);
vmc->vm_endpoint = NONE; /* In case someone tries to use it. */
vmc->vm_pt = origpt;
- vmc->vm_flags &= ~VMF_HASPT;
#if VMSTATS
vmc->vm_bytecopies = 0;
return ENOMEM;
}
- vmc->vm_flags |= VMF_HASPT;
-
- if(fullvm) {
- SANITYCHECK(SCL_DETAIL);
-
- if(map_proc_copy(vmc, vmp) != OK) {
- printf("VM: fork: map_proc_copy failed\n");
- pt_free(&vmc->vm_pt);
- return(ENOMEM);
- }
-
- if(vmp->vm_heap) {
- vmc->vm_heap = map_region_lookup_tag(vmc, VRT_HEAP);
- assert(vmc->vm_heap);
- }
-
- SANITYCHECK(SCL_DETAIL);
- } else {
- vir_bytes sp;
- struct vir_region *heap, *stack;
- vir_bytes text_bytes, data_bytes, stack_bytes, parent_gap_bytes,
- child_gap_bytes;
- vir_bytes text_addr, data_addr;
- int is_elf = 0;
-
- /* Get SP of new process (using parent). */
- if(get_stack_ptr(vmp->vm_endpoint, &sp) != OK) {
- printf("VM: fork: get_stack_ptr failed for %d\n",
- vmp->vm_endpoint);
- return ENOMEM;
- }
-
- /* Update size of stack segment using current SP. */
- if(adjust(vmp, vmp->vm_arch.vm_seg[D].mem_len, sp) != OK) {
- printf("VM: fork: adjust failed for %d\n",
- vmp->vm_endpoint);
- return ENOMEM;
- }
-
- /* Copy newly adjust()ed stack segment size to child. */
- vmc->vm_arch.vm_seg[S] = vmp->vm_arch.vm_seg[S];
-
- text_addr = CLICK2ABS(vmc->vm_arch.vm_seg[T].mem_vir);
- text_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[T].mem_len);
- data_addr = CLICK2ABS(vmc->vm_arch.vm_seg[D].mem_vir);
- data_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[D].mem_len);
- stack_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_len);
-
- /* how much space after break and before lower end (which is the
- * logical top) of stack for the parent
- */
- parent_gap_bytes = CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir -
- vmc->vm_arch.vm_seg[D].mem_len -
- vmc->vm_arch.vm_seg[D].mem_vir);
-
- /* how much space can the child stack grow downwards, below
- * the current SP? The rest of the gap is available for the
- * heap to grow upwards.
- */
- child_gap_bytes = VM_PAGE_SIZE;
-
-#if defined(__ELF__)
- is_elf = 1;
-#endif
+ SANITYCHECK(SCL_DETAIL);
- if((r=proc_new(vmc, VM_PROCSTART,
- text_addr, text_bytes,
- data_addr, data_bytes,
- stack_bytes, child_gap_bytes, 0, 0,
- CLICK2ABS(vmc->vm_arch.vm_seg[S].mem_vir +
- vmc->vm_arch.vm_seg[S].mem_len),
- 1, is_elf, 0)) != OK) {
- printf("VM: fork: proc_new failed\n");
- return r;
- }
-
- if(!(heap = map_region_lookup_tag(vmc, VRT_HEAP)))
- panic("couldn't lookup heap");
- assert(heap->phys);
- if(!(stack = map_region_lookup_tag(vmc, VRT_STACK)))
- panic("couldn't lookup stack");
- assert(stack->phys);
-
- /* Now copy the memory regions. */
-
- if(vmc->vm_arch.vm_seg[T].mem_len > 0) {
- struct vir_region *text;
- if(!(text = map_region_lookup_tag(vmc, VRT_TEXT)))
- panic("couldn't lookup text");
- assert(text->phys);
- if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys),
- text, 0, text_bytes) != OK)
- panic("couldn't copy text");
- }
-
- if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys),
- heap, 0, data_bytes) != OK)
- panic("couldn't copy heap");
-
- if(copy_abs2region(CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys +
- vmc->vm_arch.vm_seg[D].mem_len) + parent_gap_bytes,
- stack, child_gap_bytes, stack_bytes) != OK)
- panic("couldn't copy stack");
+ if(map_proc_copy(vmc, vmp) != OK) {
+ printf("VM: fork: map_proc_copy failed\n");
+ pt_free(&vmc->vm_pt);
+ return(ENOMEM);
}
/* Only inherit these flags. */
- vmc->vm_flags &= (VMF_INUSE|VMF_SEPARATE|VMF_HASPT);
+ vmc->vm_flags &= VMF_INUSE;
/* inherit the priv call bitmaps */
memcpy(&vmc->vm_call_mask, &vmp->vm_call_mask, sizeof(vmc->vm_call_mask));
/* Tell kernel about the (now successful) FORK. */
if((r=sys_fork(vmp->vm_endpoint, childproc,
- &vmc->vm_endpoint, vmc->vm_arch.vm_seg,
- PFF_VMINHIBIT, &msgaddr)) != OK) {
+ &vmc->vm_endpoint, PFF_VMINHIBIT, &msgaddr)) != OK) {
panic("do_fork can't sys_fork: %d", r);
}
if((r=pt_bind(&vmc->vm_pt, vmc)) != OK)
panic("fork can't pt_bind: %d", r);
- if(fullvm) {
+ {
vir_bytes vir;
/* making these messages writable is an optimisation
* and its return value needn't be checked.
*/
- vir = arch_vir2map(vmc, msgaddr);
+ vir = msgaddr;
if (handle_memory(vmc, vir, sizeof(message), 1) != OK)
panic("do_fork: handle_memory for child failed\n");
- vir = arch_vir2map(vmp, msgaddr);
+ vir = msgaddr;
if (handle_memory(vmp, vir, sizeof(message), 1) != OK)
panic("do_fork: handle_memory for parent failed\n");
}
#include <minix/sys_config.h>
+#include <minix/type.h>
#include <sys/stat.h>
#include <a.out.h>
#include <tools.h>
#define EXTERN
#endif
-#define VMP_SYSTEM _NR_PROCS
-#define VMP_EXECTMP _NR_PROCS+1
-#define VMP_NR _NR_PROCS+2
+#define VMP_EXECTMP _NR_PROCS
+#define VMP_NR _NR_PROCS+1
EXTERN struct vmproc vmproc[VMP_NR];
+EXTERN kinfo_t kernel_boot_info;
+
#if SANITYCHECKS
EXTERN int nocheck;
EXTERN int incheck;
#include <minix/crtso.h>
#include <minix/rs.h>
+#include <libexec.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <env.h>
extern int missing_spares;
#include <machine/archtypes.h>
+#include <sys/param.h>
#include "kernel/const.h"
#include "kernel/config.h"
#include "kernel/proc.h"
static int map_service(struct rprocpub *rpub);
static int vm_acl_ok(endpoint_t caller, int call);
+static int do_rs_init(message *m);
/* SEF functions and variables. */
-static void sef_local_startup(void);
-static int sef_cb_init_fresh(int type, sef_init_info_t *info);
static void sef_cb_signal_handler(int signo);
+void init_vm(void);
+
/*===========================================================================*
* main *
*===========================================================================*/
int caller_slot;
struct vmproc *vmp_caller;
- /* SEF local startup. */
- sef_local_startup();
+ /* Initialize system so that all processes are runnable */
+ init_vm();
+
+ /* Register init callbacks. */
+ sef_setcb_init_restart(sef_cb_init_fail);
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
+ /* Let SEF perform startup. */
+ sef_startup();
SANITYCHECK(SCL_TOP);
}
who_e = msg.m_source;
if(vm_isokendpt(who_e, &caller_slot) != OK)
- panic("invalid caller", who_e);
+ panic("invalid caller %d", who_e);
vmp_caller = &vmproc[caller_slot];
c = CALLNUMBER(msg.m_type);
result = ENOSYS; /* Out of range or restricted calls return this. */
- if (msg.m_type == VM_PAGEFAULT) {
+
+ if(msg.m_type == RS_INIT && msg.m_source == RS_PROC_NR) {
+ result = do_rs_init(&msg);
+ } else if (msg.m_type == VM_PAGEFAULT) {
if (!IPC_STATUS_FLAGS_TEST(rcv_sts, IPC_FLG_MSG_FROM_KERNEL)) {
printf("VM: process %d faked VM_PAGEFAULT "
"message!\n", msg.m_source);
return(OK);
}
-/*===========================================================================*
- * sef_local_startup *
- *===========================================================================*/
-static void sef_local_startup()
+static int do_rs_init(message *m)
{
- /* Register init callbacks. */
- sef_setcb_init_fresh(sef_cb_init_fresh);
- sef_setcb_init_restart(sef_cb_init_fail);
+ int s, i;
+ static struct rprocpub rprocpub[NR_BOOT_PROCS];
+
+ /* Map all the services in the boot image. */
+ if((s = sys_safecopyfrom(RS_PROC_NR, m->RS_INIT_RPROCTAB_GID, 0,
+ (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) {
+ panic("vm: sys_safecopyfrom (rs) failed: %d", s);
+ }
- /* No live update support for now. */
+ for(i=0;i < NR_BOOT_PROCS;i++) {
+ if(rprocpub[i].in_use) {
+ if((s = map_service(&rprocpub[i])) != OK) {
+ panic("unable to map service: %d", s);
+ }
+ }
+ }
- /* Register signal callbacks. */
- sef_setcb_signal_handler(sef_cb_signal_handler);
+ /* RS expects this response that it then again wants to reply to: */
+ m->RS_INIT_RESULT = OK;
+ sendrec(RS_PROC_NR, m);
- /* Let SEF perform startup. */
- sef_startup();
+ return(SUSPEND);
}
-/*===========================================================================*
- * sef_cb_init_fresh *
- *===========================================================================*/
-static int sef_cb_init_fresh(int type, sef_init_info_t *info)
+struct vmproc *init_proc(endpoint_t ep_nr)
{
-/* Initialize the vm server. */
- int s, i;
- struct memory mem_chunks[NR_MEMS];
- struct boot_image image[NR_BOOT_PROCS];
- struct boot_image *ip;
- struct rprocpub rprocpub[NR_BOOT_PROCS];
- phys_bytes limit = 0;
- int is_elf = 0;
+ static struct boot_image *ip;
-#if SANITYCHECKS
- incheck = nocheck = 0;
-#endif
+ for (ip = &kernel_boot_info.boot_procs[0];
+ ip < &kernel_boot_info.boot_procs[NR_BOOT_PROCS]; ip++) {
+ struct vmproc *vmp;
-#if SANITYCHECKS
- env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel, 0, SCL_MAX);
-#endif
+ if(ip->proc_nr != ep_nr) continue;
- /* Get chunks of available memory. */
- get_mem_chunks(mem_chunks);
+ if(ip->proc_nr >= _NR_PROCS || ip->proc_nr < 0)
+ panic("proc: %d", ip->proc_nr);
- /* Initialize VM's process table. Request a copy of the system
- * image table that is defined at the kernel level to see which
- * slots to fill in.
- */
- if (OK != (s=sys_getimage(image)))
- panic("couldn't get image table: %d", s);
+ vmp = &vmproc[ip->proc_nr];
+ assert(!(vmp->vm_flags & VMF_INUSE)); /* no double procs */
+ clear_proc(vmp);
+ vmp->vm_flags = VMF_INUSE;
+ vmp->vm_endpoint = ip->endpoint;
+ vmp->vm_boot = ip;
- /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */
- memset(vmproc, 0, sizeof(vmproc));
+ return vmp;
+ }
- for(i = 0; i < ELEMENTS(vmproc); i++) {
- vmproc[i].vm_slot = i;
+ panic("no init_proc");
+}
+
+struct vm_exec_info {
+ struct exec_info execi;
+ struct boot_image *ip;
+ struct vmproc *vmp;
+};
+
+static int libexec_copy_physcopy(struct exec_info *execi,
+ off_t off, off_t vaddr, size_t len)
+{
+ vir_bytes end;
+ struct vm_exec_info *ei = execi->opaque;
+ end = ei->ip->start_addr + ei->ip->len;
+ assert(ei->ip->start_addr + off + len <= end);
+ return sys_physcopy(NONE, ei->ip->start_addr + off,
+ execi->proc_e, vaddr, len);
+}
+
+static void boot_alloc(struct exec_info *execi, off_t vaddr,
+ size_t len, int flags)
+{
+ struct vmproc *vmp = ((struct vm_exec_info *) execi->opaque)->vmp;
+
+ if(!(map_page_region(vmp, vaddr, 0,
+ len, MAP_NONE, VR_ANON | VR_WRITABLE | VR_UNINITIALIZED, flags))) {
+ panic("VM: exec: map_page_region for boot process failed");
}
+}
- /* Walk through boot-time system processes that are alive
- * now and make valid slot entries for them.
- */
- for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
- phys_bytes proclimit;
- struct vmproc *vmp;
+static int libexec_alloc_vm_prealloc(struct exec_info *execi,
+ off_t vaddr, size_t len)
+{
+ boot_alloc(execi, vaddr, len, MF_PREALLOC);
+ return OK;
+}
- if(ip->proc_nr >= _NR_PROCS) { panic("proc: %d", ip->proc_nr); }
- if(ip->proc_nr < 0 && ip->proc_nr != SYSTEM) continue;
+static int libexec_alloc_vm_ondemand(struct exec_info *execi,
+ off_t vaddr, size_t len)
+{
+ boot_alloc(execi, vaddr, len, 0);
+ return OK;
+}
-#define GETVMP(v, nr) \
- if(nr >= 0) { \
- vmp = &vmproc[ip->proc_nr]; \
- } else if(nr == SYSTEM) { \
- vmp = &vmproc[VMP_SYSTEM]; \
- } else { \
- panic("init: crazy proc_nr: %d", nr); \
- }
+void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
+{
+ struct vm_exec_info vmexeci;
+ struct exec_info *execi = &vmexeci.execi;
+ char hdr[VM_PAGE_SIZE];
+
+ memset(&vmexeci, 0, sizeof(vmexeci));
+
+ if(pt_new(&vmp->vm_pt) != OK)
+ panic("VM: no new pagetable");
+
+ if(pt_bind(&vmp->vm_pt, vmp) != OK)
+ panic("VM: pt_bind failed");
+
+ if(sys_physcopy(NONE, ip->start_addr, SELF,
+ (vir_bytes) hdr, sizeof(hdr)) != OK)
+ panic("can't look at boot proc header");
+
+ execi->stack_high = kernel_boot_info.user_sp;
+ execi->stack_size = DEFAULT_STACK_LIMIT;
+ execi->proc_e = vmp->vm_endpoint;
+ execi->hdr = hdr;
+ execi->hdr_len = sizeof(hdr);
+ strcpy(execi->progname, ip->proc_name);
+ execi->frame_len = 0;
+ execi->opaque = &vmexeci;
+
+ vmexeci.ip = ip;
+ vmexeci.vmp = vmp;
+
+ /* callback functions and data */
+ execi->copymem = libexec_copy_physcopy;
+ execi->clearproc = NULL;
+ execi->clearmem = libexec_clear_sys_memset;
+ execi->allocmem_prealloc = libexec_alloc_vm_prealloc;
+ execi->allocmem_ondemand = libexec_alloc_vm_ondemand;
+
+ if(libexec_load_elf(execi) != OK)
+ panic("vm: boot process load of %d failed\n", vmp->vm_endpoint);
+
+ if(sys_exec(vmp->vm_endpoint, (char *) execi->stack_high - 12,
+ (char *) ip->proc_name, execi->pc) != OK)
+ panic("vm: boot process exec of %d failed\n", vmp->vm_endpoint);
+}
- /* Initialize normal process table slot or special SYSTEM
- * table slot. Kernel memory is already reserved.
- */
- GETVMP(vmp, ip->proc_nr);
+void init_vm(void)
+{
+ int s, i;
+ static struct memory mem_chunks[NR_MEMS];
+ static struct boot_image *ip;
- /* reset fields as if exited */
- clear_proc(vmp);
+#if SANITYCHECKS
+ incheck = nocheck = 0;
+#endif
- /* Get memory map for this process from the kernel. */
- if ((s=get_mem_map(ip->proc_nr, vmp->vm_arch.vm_seg)) != OK)
- panic("couldn't get process mem_map: %d", s);
+ /* Retrieve various crucial boot parameters */
+ if(OK != (s=sys_getkinfo(&kernel_boot_info))) {
+ panic("couldn't get bootinfo: %d", s);
+ }
- /* Remove this memory from the free list. */
- reserve_proc_mem(mem_chunks, vmp->vm_arch.vm_seg);
+ /* Sanity check */
+ assert(kernel_boot_info.mmap_size > 0);
+ assert(kernel_boot_info.mods_with_kernel > 0);
- /* Set memory limit. */
- proclimit = CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_phys +
- vmp->vm_arch.vm_seg[S].mem_len) - 1;
+#if SANITYCHECKS
+ env_parse("vm_sanitychecklevel", "d", 0, &vm_sanitychecklevel, 0, SCL_MAX);
- if(proclimit > limit)
- limit = proclimit;
+ vm_sanitychecklevel = 1;
+#endif
- vmp->vm_flags = VMF_INUSE;
- vmp->vm_endpoint = ip->endpoint;
- vmp->vm_stacktop =
- CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len);
+ /* Get chunks of available memory. */
+ get_mem_chunks(mem_chunks);
+
+ /* Set table to 0. This invalidates all slots (clear VMF_INUSE). */
+ memset(vmproc, 0, sizeof(vmproc));
- if (vmp->vm_arch.vm_seg[T].mem_len != 0)
- vmp->vm_flags |= VMF_SEPARATE;
+ for(i = 0; i < ELEMENTS(vmproc); i++) {
+ vmproc[i].vm_slot = i;
}
/* region management initialization. */
map_region_init();
/* Architecture-dependent initialization. */
- pt_init(limit);
+ init_proc(VM_PROC_NR);
+ pt_init();
/* Initialize tables to all physical memory. */
mem_init(mem_chunks);
meminit_done = 1;
- /* Architecture-dependent memory initialization. */
- pt_init_mem();
-
/* Give these processes their own page table. */
- for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {
+ for (ip = &kernel_boot_info.boot_procs[0];
+ ip < &kernel_boot_info.boot_procs[NR_BOOT_PROCS]; ip++) {
struct vmproc *vmp;
- vir_bytes old_stacktop, old_stacklen;
if(ip->proc_nr < 0) continue;
- GETVMP(vmp, ip->proc_nr);
+ assert(ip->start_addr);
- if(!(ip->flags & PROC_FULLVM))
- continue;
-
- if(pt_new(&vmp->vm_pt) != OK)
- panic("VM: no new pagetable");
-#define BASICSTACK VM_PAGE_SIZE
- old_stacktop = CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len);
- if(sys_vmctl(vmp->vm_endpoint, VMCTL_INCSP,
- VM_STACKTOP - old_stacktop) != OK) {
- panic("VM: vmctl for new stack failed");
- }
+ /* VM has already been set up by the kernel and pt_init().
+ * Any other boot process is already in memory and is set up
+ * here.
+ */
+ if(ip->proc_nr == VM_PROC_NR) continue;
- old_stacklen =
- vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len -
- vmp->vm_arch.vm_seg[D].mem_len -
- vmp->vm_arch.vm_seg[D].mem_vir;
+ vmp = init_proc(ip->proc_nr);
- free_mem(vmp->vm_arch.vm_seg[D].mem_phys +
- vmp->vm_arch.vm_seg[D].mem_len,
- old_stacklen);
+ exec_bootproc(vmp, ip);
-#if defined(__ELF__)
- is_elf = 1;
-#endif
-
- if(proc_new(vmp,
- VM_PROCSTART,
- CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_vir),
- CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_len),
- CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_vir),
- CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_len),
- BASICSTACK,
- CLICK2ABS(vmp->vm_arch.vm_seg[S].mem_vir +
- vmp->vm_arch.vm_seg[S].mem_len -
- vmp->vm_arch.vm_seg[D].mem_len -
- vmp->vm_arch.vm_seg[D].mem_vir) - BASICSTACK,
- CLICK2ABS(vmp->vm_arch.vm_seg[T].mem_phys),
- CLICK2ABS(vmp->vm_arch.vm_seg[D].mem_phys),
- VM_STACKTOP, 0, is_elf, 0) != OK) {
- panic("failed proc_new for boot process");
- }
+ /* Free the file blob */
+ assert(!(ip->start_addr % VM_PAGE_SIZE));
+ ip->len = roundup(ip->len, VM_PAGE_SIZE);
+ free_mem(ABS2CLICK(ip->start_addr), ABS2CLICK(ip->len));
}
/* Set up table of calls. */
CALLMAP(VM_FORGETBLOCK, do_forgetblock);
CALLMAP(VM_YIELDBLOCKGETBLOCK, do_yieldblockgetblock);
- /* Sanity checks */
- if(find_kernel_top() >= VM_PROCSTART)
- panic("kernel loaded too high");
-
/* Initialize the structures for queryexit */
init_query_exit();
-
- /* Map all the services in the boot image. */
- if((s = sys_safecopyfrom(RS_PROC_NR, info->rproctab_gid, 0,
- (vir_bytes) rprocpub, sizeof(rprocpub))) != OK) {
- panic("sys_safecopyfrom failed: %d", s);
- }
- for(i=0;i < NR_BOOT_PROCS;i++) {
- if(rprocpub[i].in_use) {
- if((s = map_service(&rprocpub[i])) != OK) {
- panic("unable to map service: %d", s);
- }
- }
- }
-
- return(OK);
}
/*===========================================================================*
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT))
- return ENXIO;
-
if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) {
u32_t vrflags = VR_ANON | VR_WRITABLE;
size_t len = (vir_bytes) m->VMM_LEN;
vr = NULL;
if (m->VMM_ADDR || (m->VMM_FLAGS & MAP_FIXED)) {
/* An address is given, first try at that address. */
- addr = arch_vir2map(vmp, m->VMM_ADDR);
+ addr = m->VMM_ADDR;
vr = map_page_region(vmp, addr, 0, len, MAP_NONE,
vrflags, mfflags);
if(!vr && (m->VMM_FLAGS & MAP_FIXED))
}
if (!vr) {
/* No address given or address already in use. */
- addr = arch_vir2map(vmp, vmp->vm_stacktop);
- vr = map_page_region(vmp, addr, VM_DATATOP, len,
+ vr = map_page_region(vmp, 0, VM_DATATOP, len,
MAP_NONE, vrflags, mfflags);
}
if (!vr) {
/* Return mapping, as seen from process. */
assert(vr);
- m->VMM_RETADDR = arch_map2vir(vmp, vr->vaddr);
+ m->VMM_RETADDR = vr->vaddr;
return OK;
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT))
- return ENXIO;
-
offset = startaddr % VM_PAGE_SIZE;
len += offset;
startaddr -= offset;
if(len % VM_PAGE_SIZE)
len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);
- if(!(vr = map_page_region(vmp, arch_vir2map(vmp, vmp->vm_stacktop),
- VM_DATATOP, len, startaddr,
+ if(!(vr = map_page_region(vmp, 0, VM_DATATOP, len, startaddr,
VR_DIRECT | VR_NOPF | VR_WRITABLE, 0))) {
return ENOMEM;
}
- m->VMMP_VADDR_REPLY = (void *) (arch_map2vir(vmp, vr->vaddr) + offset);
+ m->VMMP_VADDR_REPLY = (void *) (vr->vaddr + offset);
return OK;
}
vmp = &vmproc[n];
- if(!(region = map_lookup(vmp,
- arch_vir2map(vmp, (vir_bytes) m->VMUM_ADDR)))) {
+ if(!(region = map_lookup(vmp, (vir_bytes) m->VMUM_ADDR))) {
return EINVAL;
}
* about whether the user needs to bind to
* THAT address or be chosen by the system.
*/
- sa = arch_vir2map(svmp, sa);
-
if (!(region = map_lookup(svmp, sa)))
return EINVAL;
if ((r = map_remap(dvmp, da, size, region, &startv, readonly)) != OK)
return r;
- m->VMRE_RETA = (char *) arch_map2vir(dvmp, startv);
+ m->VMRE_RETA = (char *) startv;
return OK;
}
vmp = &vmproc[n];
- addr = arch_vir2map(vmp, m->VMUN_ADDR);
+ addr = m->VMUN_ADDR;
if(!(vr = map_lookup(vmp, addr))) {
printf("VM: addr 0x%lx not found.\n", m->VMUN_ADDR);
return EINVAL;
vmp = &vmproc[n];
- addr = arch_vir2map(vmp, addr);
r = map_get_phys(vmp, addr, &ret);
return EINVAL;
vmp = &vmproc[n];
- addr = arch_vir2map(vmp, addr);
r = map_get_ref(vmp, addr, &cnt);
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT))
- return ENXIO;
-
if(m->m_type == VM_MUNMAP) {
- addr = (vir_bytes) arch_vir2map(vmp, (vir_bytes) m->VMUM_ADDR);
+ addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
} else if(m->m_type == VM_MUNMAP_TEXT) {
- addr = (vir_bytes) arch_vir2map_text(vmp, (vir_bytes) m->VMUM_ADDR);
+ addr = (vir_bytes) (vir_bytes) m->VMUM_ADDR;
} else {
panic("do_munmap: strange type");
}
vir_bytes laddr;
if(!unmap_ok)
return ENOSYS;
- laddr = (vir_bytes) arch_vir2map(&vmproc[VM_PROC_NR], (vir_bytes) addr);
+ laddr = (vir_bytes) (vir_bytes) addr;
return munmap_lin(laddr, len);
}
vir_bytes laddr;
if(!unmap_ok)
return ENOSYS;
- laddr = (vir_bytes) arch_vir2map_text(&vmproc[VM_PROC_NR],
- (vir_bytes) addr);
+ laddr = (vir_bytes) addr;
return munmap_lin(laddr, len);
}
/* See if address is valid at all. */
if(!(region = map_lookup(vmp, addr))) {
assert(PFERR_NOPAGE(err));
- printf("VM: pagefault: SIGSEGV %d bad addr %s; %s\n",
- ep, arch_map2str(vmp, addr), pf_errstr(err));
+ printf("VM: pagefault: SIGSEGV %d bad addr 0x%x; %s\n",
+ ep, addr, pf_errstr(err));
if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
panic("sys_kill failed: %d", s);
if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
/* If process was writing, see if it's writable. */
if(!(region->flags & VR_WRITABLE) && wr) {
- printf("VM: pagefault: SIGSEGV %d ro map 0x%lx %s\n",
- ep, arch_map2vir(vmp, addr), pf_errstr(err));
+ printf("VM: pagefault: SIGSEGV %d ro map 0x%x %s\n",
+ ep, addr, pf_errstr(err));
if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
panic("sys_kill failed: %d", s);
if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
if(r != OK) {
#if VERBOSE
printf("VM: memory range 0x%lx-0x%lx not available in %d\n",
- arch_map2vir(vmp, mem), arch_map2vir(vmp, mem+len),
- vmp->vm_endpoint);
+ mem, mem+len, vmp->vm_endpoint);
#endif
return r;
}
struct vmproc;
struct stat;
-struct mem_map;
struct memory;
struct vir_region;
struct phys_region;
#include "yielded.h"
/* alloc.c */
+void mem_sanitycheck(char *file, int line);
phys_clicks alloc_mem(phys_clicks clicks, u32_t flags);
struct memlist *alloc_mem_in_list(phys_bytes bytes, u32_t flags);
int do_adddma(message *msg);
void mem_init(struct memory *chunks);
/* utility.c */
-int get_mem_map(int proc_nr, struct mem_map *mem_map);
void get_mem_chunks(struct memory *mem_chunks);
void reserve_proc_mem(struct memory *mem_chunks, struct mem_map
*map_ptr);
/* fork.c */
int do_fork(message *msg);
-/* exec.c */
-int do_exec_newmem(message *msg);
-int proc_new(struct vmproc *vmp, phys_bytes start, phys_bytes text_addr,
- phys_bytes text_bytes, phys_bytes data_addr, phys_bytes data_bytes,
- phys_bytes stack, phys_bytes gap, phys_bytes text_here, phys_bytes
- data_here, vir_bytes stacktop, int prealloc_stack, int is_elf, int full);
-phys_bytes find_kernel_top(void);
-void regular_segs(struct vmproc *);
-
/* break.c */
int do_brk(message *msg);
int adjust(struct vmproc *rmp, vir_clicks data_clicks, vir_bytes sp);
wrflag);
/* $(ARCH)/pagetable.c */
-void pt_init(phys_bytes limit);
+void pt_init();
void pt_init_mem(void);
void pt_check(struct vmproc *vmp);
int pt_new(pt_t *pt);
int do_yieldblockgetblock(message *m);
vir_bytes free_yielded(vir_bytes bytes);
-/* $(ARCH)/vm.c */
-vir_bytes arch_map2vir(struct vmproc *vmp, vir_bytes addr);
-char *arch_map2str(struct vmproc *vmp, vir_bytes addr);
-vir_bytes arch_map2info(struct vmproc *vmp, vir_bytes addr, int *space,
- int *prot);
-vir_bytes arch_vir2map(struct vmproc *vmp, vir_bytes addr);
-vir_bytes arch_vir2map_text(struct vmproc *vmp, vir_bytes addr);
-vir_bytes arch_addrok(struct vmproc *vmp, vir_bytes addr);
-
/* rs.c */
int do_rs_set_priv(message *m);
int do_rs_update(message *m);
physr_iter iter;
struct phys_region *ph;
printf("map_printmap: map_name: %s\n", map_name(vr));
- printf("\t%s (len 0x%lx, %lukB), %s\n",
- arch_map2str(vmp, vr->vaddr), vr->length,
- vr->length/1024, map_name(vr));
+ printf("\t%lx (len 0x%lx, %lukB), %p\n",
+ vr->vaddr, vr->length, vr->length/1024, map_name(vr));
printf("\t\tphysblocks:\n");
physr_start_iter_least(vr->phys, &iter);
while((ph = physr_get_iter(&iter))) {
- printf("\t\t@ %s (refs %d): phys 0x%lx len 0x%lx\n",
- arch_map2str(vmp, vr->vaddr + ph->offset),
+ printf("\t\t@ %lx (refs %d): phys 0x%lx len 0x%lx\n",
+ (vr->vaddr + ph->offset),
ph->ph->refcount, ph->ph->phys, ph->ph->length);
physr_incr_iter(&iter);
}
int rw;
int r;
- if(!(vmp->vm_flags & VMF_HASPT))
- return OK;
-
if(WRITABLE(vr, pb))
rw = PTF_WRITE;
else
static vir_bytes region_find_slot_range(struct vmproc *vmp,
vir_bytes minv, vir_bytes maxv, vir_bytes length)
{
- struct vir_region *firstregion;
+ struct vir_region *lastregion;
vir_bytes startv = 0;
int foundflag = 0;
region_iter iter;
assert(minv < maxv);
assert(minv + length <= maxv);
-#define FREEVRANGE(rangestart, rangeend) { \
+#define FREEVRANGE_TRY(rangestart, rangeend) { \
vir_bytes frstart = (rangestart), frend = (rangeend); \
frstart = MAX(frstart, minv); \
frend = MIN(frend, maxv); \
if(frend > frstart && (frend - frstart) >= length) { \
- startv = frstart; \
+ startv = frend-length; \
foundflag = 1; \
} }
- /* find region before minv. */
- region_start_iter(&vmp->vm_regions_avl, &iter, minv, AVL_LESS_EQUAL);
- firstregion = region_get_iter(&iter);
+#define FREEVRANGE(start, end) { \
+ assert(!foundflag); \
+ FREEVRANGE_TRY(((start)+VM_PAGE_SIZE), ((end)-VM_PAGE_SIZE)); \
+ if(!foundflag) { \
+ FREEVRANGE_TRY((start), (end)); \
+ } \
+}
- if(!firstregion) {
- /* This is the free virtual address space before the first region. */
- region_start_iter(&vmp->vm_regions_avl, &iter, minv, AVL_GREATER_EQUAL);
- firstregion = region_get_iter(&iter);
- FREEVRANGE(0, firstregion ? firstregion->vaddr : VM_DATATOP);
+ /* find region after maxv. */
+ region_start_iter(&vmp->vm_regions_avl, &iter, maxv, AVL_GREATER_EQUAL);
+ lastregion = region_get_iter(&iter);
+
+ if(!lastregion) {
+ /* This is the free virtual address space after the last region. */
+ region_start_iter(&vmp->vm_regions_avl, &iter, maxv, AVL_LESS);
+ lastregion = region_get_iter(&iter);
+ FREEVRANGE(lastregion ?
+ lastregion->vaddr+lastregion->length : 0, VM_DATATOP);
}
if(!foundflag) {
struct vir_region *vr;
while((vr = region_get_iter(&iter)) && !foundflag) {
struct vir_region *nextvr;
- region_incr_iter(&iter);
+ region_decr_iter(&iter);
nextvr = region_get_iter(&iter);
- FREEVRANGE(vr->vaddr + vr->length,
- nextvr ? nextvr->vaddr : VM_DATATOP);
+ FREEVRANGE(nextvr ? nextvr->vaddr+nextvr->length : 0,
+ vr->vaddr);
}
}
if(!foundflag) {
printf("VM: region_find_slot: no 0x%lx bytes found for %d between 0x%lx and 0x%lx\n",
length, vmp->vm_endpoint, minv, maxv);
+ util_stacktrace();
return SLOT_FAIL;
}
*/
if(maxv && hint < maxv && hint >= minv) {
- v = region_find_slot_range(vmp, hint, maxv, length);
+ v = region_find_slot_range(vmp, minv, hint, length);
if(v != SLOT_FAIL)
return v;
SANITYCHECK(SCL_FUNCTIONS);
+ if((flags & VR_CONTIG) && !(mapflags & MF_PREALLOC)) {
+ printf("map_page_region: can't make contiguous allocation without preallocating\n");
+ return NULL;
+ }
+
startv = region_find_slot(vmp, minv, maxv, length);
if (startv == SLOT_FAIL)
return NULL;
if((region->flags & VR_CONTIG) &&
(start_offset > 0 || length < region->length)) {
- printf("VM: map_new_physblock: non-full allocation requested\n");
+ printf("VM: region length 0x%lx, offset 0x%lx length 0x%lx\n",
+ region->length, start_offset, length);
+ map_printmap(vmp);
+ printf("VM: map_new_physblock: non-full contig allocation requested\n");
return EFAULT;
}
#if SANITYCHECKS
if(OK != pt_checkrange(&vmp->vm_pt, region->vaddr+offset, length, write)) {
- printf("handle mem %s-", arch_map2str(vmp, region->vaddr+offset));
- printf("%s failed\n", arch_map2str(vmp, region->vaddr+offset+length));
+ printf("handle mem 0x%lx-0x%lx failed\n",
+ region->vaddr+offset,region->vaddr+offset+length);
map_printregion(vmp, region);
panic("checkrange failed");
}
return OK;
}
-/*========================================================================*
- * map_proc_kernel *
- *========================================================================*/
-struct vir_region *map_proc_kernel(struct vmproc *vmp)
-{
- struct vir_region *vr;
-
- /* We assume these are the first regions to be mapped to
- * make the function a bit simpler (free all regions on error).
- */
- assert(!region_search_root(&vmp->vm_regions_avl));
- assert(vmproc[VMP_SYSTEM].vm_flags & VMF_INUSE);
- assert(!(KERNEL_TEXT % VM_PAGE_SIZE));
- assert(!(KERNEL_TEXT_LEN % VM_PAGE_SIZE));
- assert(!(KERNEL_DATA % VM_PAGE_SIZE));
- assert(!(KERNEL_DATA_LEN % VM_PAGE_SIZE));
-
- if(!(vr = map_page_region(vmp, KERNEL_TEXT, 0, KERNEL_TEXT_LEN,
- KERNEL_TEXT, VR_DIRECT | VR_WRITABLE | VR_NOPF, 0)) ||
- !(vr = map_page_region(vmp, KERNEL_DATA, 0, KERNEL_DATA_LEN,
- KERNEL_DATA, VR_DIRECT | VR_WRITABLE | VR_NOPF, 0))) {
- map_free_proc(vmp);
- return NULL;
- }
-
- return vr; /* Return pointer not useful, just non-NULL. */
-}
-
int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes v)
{
- vir_bytes offset, o, end;
+ vir_bytes offset = v, end;
struct vir_region *vr, *nextvr;
+ int r = OK;
- offset = arch_vir2map(vmp, v);
-
- if((o=(offset % VM_PAGE_SIZE))) {
- offset+= VM_PAGE_SIZE - o;
- }
-
- if(!(vr = region_search(&vmp->vm_regions_avl, offset, AVL_LESS_EQUAL))) {
+ if(!(vr = region_search(&vmp->vm_regions_avl, offset, AVL_LESS))) {
printf("VM: nothing to extend\n");
return ENOMEM;
}
assert(vr->vaddr <= offset);
if((nextvr = getnextvr(vr))) {
- assert(offset < nextvr->vaddr);
+ assert(offset <= nextvr->vaddr);
}
end = vr->vaddr + vr->length;
- if(offset < end)
- return map_region_shrink(vr, end - offset);
+ offset = roundup(offset, VM_PAGE_SIZE);
- return map_region_extend(vmp, vr, offset - end);
+ if(end < offset)
+ r = map_region_extend(vmp, vr, offset - end);
- return ENOMEM;
+ return r;
}
/*========================================================================*
assert(vr);
assert(vr->flags & VR_ANON);
assert(!(delta % VM_PAGE_SIZE));
+ if(vr->flags & VR_CONTIG) {
+ printf("VM: can't grow contig region\n");
+ return EFAULT;
+ }
if(!delta) return OK;
end = vr->vaddr + vr->length;
/* da is handled differently */
if (!da)
- dst_addr = dvmp->vm_stacktop;
+ dst_addr = 0;
else
dst_addr = da;
- dst_addr = arch_vir2map(dvmp, dst_addr);
/* round up to page size */
assert(!(size % VM_PAGE_SIZE));
if(!ph1 || !ph2) { assert(!ph1 && !ph2); continue; }
/* Report start+length of region starting from lowest use. */
- vri->vri_addr = arch_map2info(vmp, vr->vaddr + ph1->offset,
- &vri->vri_seg, &vri->vri_prot);
+ vri->vri_addr = vr->vaddr + ph1->offset;
+ vri->vri_prot = 0;
vri->vri_length = ph2->offset + ph2->ph->length - ph1->offset;
/* "AND" the provided protection with per-page protection. */
vir_bytes regionoffset, mapaddr;
struct phys_region *ph;
- mapaddr = arch_vir2map(vmp, vaddr);
+ mapaddr = vaddr;
if(!(region = map_lookup(vmp, mapaddr))) {
printf("VM: get_clean_phys_region: 0x%lx not found\n", vaddr);
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT)) {
- printf("do_forgetblocks: no pt\n");
- return EFAULT;
- }
-
free_yielded_proc(vmp);
return OK;
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT)) {
- printf("do_forgetblock: no pt\n");
- return EFAULT;
- }
-
id = make64(m->VMFB_IDLO, m->VMFB_IDHI);
blockid.id = id;
vmp = &vmproc[n];
- if(!(vmp->vm_flags & VMF_HASPT)) {
- printf("do_yieldblockgetblock: no pt\n");
- return EFAULT;
- }
-
len = m->VMYBGB_LEN;
if((len % VM_PAGE_SIZE)) {
this_vm_vmp = &vmproc[VM_PROC_NR];
- /* Copy settings from current VM. */
- new_vm_vmp->vm_stacktop = this_vm_vmp->vm_stacktop;
- new_vm_vmp->vm_arch.vm_data_top = this_vm_vmp->vm_arch.vm_data_top;
-
/* Pin memory for the new VM instance. */
r = map_pin_memory(new_vm_vmp);
if(r != OK) {
usedpages_reset(); \
slab_sanitycheck(__FILE__, __LINE__); \
for(vmpr = vmproc; vmpr < &vmproc[VMP_NR]; vmpr++) { \
- if((vmpr->vm_flags & (VMF_INUSE | VMF_HASPT)) == \
- (VMF_INUSE | VMF_HASPT)) { \
+ if((vmpr->vm_flags & (VMF_INUSE))) { \
PT_SANE(&vmpr->vm_pt); \
} \
} \
map_sanitycheck(__FILE__, __LINE__); \
+ mem_sanitycheck(__FILE__, __LINE__); \
assert(incheck == 1); \
incheck = 0; \
+ /* printf("(%s:%d OK) ", __FILE__, __LINE__); */ \
}
#define SLABSANE(ptr) { \
*===========================================================================*/
void slabstats(void)
{
- int s, total = 0, totalbytes = 0;
+ int s, totalbytes = 0;
static int n;
n++;
if(n%1000) return;
#include "kernel/type.h"
#include "kernel/proc.h"
-/*===========================================================================*
- * get_mem_map *
- *===========================================================================*/
-int get_mem_map(proc_nr, mem_map)
-int proc_nr; /* process to get map of */
-struct mem_map *mem_map; /* put memory map here */
-{
- struct proc p;
- int s;
-
- if ((s=sys_getproc(&p, proc_nr)) != OK)
- return(s);
-
- memcpy(mem_map, p.p_memmap, sizeof(p.p_memmap));
- return(OK);
-}
-
/*===========================================================================*
* get_mem_chunks *
*===========================================================================*/
}
}
+#if 0
/*===========================================================================*
* reserve_proc_mem *
*===========================================================================*/
map_ptr[T].mem_phys);
}
}
+#endif
/*===========================================================================*
* vm_isokendpt *
* deadlock. Note that no memory mapping can be undone without the
* involvement of VM, so we are safe until we're done.
*/
- r = handle_memory(vmp, arch_vir2map(vmp, ptr), size, 1 /*wrflag*/);
+ r = handle_memory(vmp, ptr, size, 1 /*wrflag*/);
if (r != OK) return r;
/* Now that we know the copy out will succeed, perform the actual copy
printf("VM: swap_proc_dyn_data: tranferring regions above the stack from old VM (%d) to new VM (%d)\n",
src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
#endif
- assert(src_vmp->vm_stacktop == dst_vmp->vm_stacktop);
- r = pt_map_in_range(src_vmp, dst_vmp,
- arch_vir2map(src_vmp, src_vmp->vm_stacktop), 0);
+ r = pt_map_in_range(src_vmp, dst_vmp, VM_STACKTOP, 0);
if(r != OK) {
printf("swap_proc_dyn_data: pt_map_in_range failed\n");
return r;
* new instance and prevent state corruption on rollback, we share all
* the regions between the two instances as COW.
*/
- if(!is_vm && (dst_vmp->vm_flags & VMF_HASPT)) {
+ if(!is_vm) {
struct vir_region *vr;
- vr = map_lookup(dst_vmp, arch_vir2map(dst_vmp, dst_vmp->vm_stacktop));
- if(vr && !map_lookup(src_vmp, arch_vir2map(src_vmp, src_vmp->vm_stacktop))) {
+ vr = map_lookup(dst_vmp, VM_STACKTOP);
+ if(vr && !map_lookup(src_vmp, VM_STACKTOP)) {
#if LU_DEBUG
printf("VM: swap_proc_dyn_data: tranferring regions above the stack from %d to %d\n",
src_vmp->vm_endpoint, dst_vmp->vm_endpoint);
#endif
- assert(src_vmp->vm_stacktop == dst_vmp->vm_stacktop);
r = map_proc_copy_from(src_vmp, dst_vmp, vr);
if(r != OK) {
return r;
#define _VMPROC_H 1
#include <pagetable.h>
-#include <arch_vmproc.h>
#include <minix/bitmap.h>
#include <machine/archtypes.h>
typedef void (*callback_t)(struct vmproc *who, message *m);
struct vmproc {
- struct vm_arch vm_arch; /* architecture-specific data */
int vm_flags;
endpoint_t vm_endpoint;
- pt_t vm_pt; /* page table data, if VMF_HASPT is set */
- vir_bytes vm_stacktop; /* top of stack as seen from process */
- vir_bytes vm_offset; /* offset of addr 0 for process */
-
- /* File identification for cs sharing. */
- ino_t vm_ino; /* inode number of file */
- dev_t vm_dev; /* device number of file system */
- time_t vm_ctime; /* inode changed time */
+ pt_t vm_pt; /* page table data */
+ struct boot_image *vm_boot; /* if boot time process */
/* Regions in virtual address space. */
region_avl vm_regions_avl;
vir_bytes vm_region_top; /* highest vaddr last inserted */
- /* Heap for brk() to extend. */
- struct vir_region *vm_heap;
-
bitchunk_t vm_call_mask[VM_CALL_MASK_SIZE];
/* State for requests pending to be done to vfs on behalf of
/* Bits for vm_flags */
#define VMF_INUSE 0x001 /* slot contains a process */
-#define VMF_SEPARATE 0x002 /* separate i&d */
-#define VMF_HASPT 0x004 /* has private page table */
-#define VMF_EXITING 0x008 /* PM is cleaning up this process */
-#define VMF_HAS_DMA 0x010 /* Process directly or indirectly granted
+#define VMF_EXITING 0x002 /* PM is cleaning up this process */
+#define VMF_HAS_DMA 0x004 /* Process directly or indirectly granted
* DMA buffers.
*/
-#define VMF_WATCHEXIT 0x020 /* Store in queryexit table */
+#define VMF_WATCHEXIT 0x008 /* Store in queryexit table */
#endif
# rumpfs_tmpfs rumpfs_udf rumpfs_ufs
.for _lib in \
c curses blockdriver chardriver netdriver edit end m sys timers util \
- bz2 l audiodriver exec ddekit devman usb elf bdev sffs hgfs vboxfs
+ bz2 l audiodriver exec ddekit devman usb elf bdev sffs hgfs vboxfs \
+ minc minlib
.ifndef LIB${_lib:tu}
LIB${_lib:tu}= ${DESTDIR}/usr/lib/lib${_lib}.a
.MADE: ${LIB${_lib:tu}} # Note: ${DESTDIR} will be expanded
# MINIX-specific boot program options
.include <bsd.own.mk>
-LDFLAGS+= -Wl,--section-start=.init=0x0
-
.include <minix.service.mk>
SUBDIR+= ministat
# Minix commands
-SUBDIR+= top mkimage
+SUBDIR+= top
.include <bsd.subdir.mk>
+++ /dev/null
-PROG= mkimage
-SRCS= mkimage.c
-MAN=
-
-DPADD+= ${LIBELF}
-LDADD+= -lelf
-
-.include <bsd.prog.mk>
+++ /dev/null
-/*
- * Update physical addresses of boot services
- */
-
-#include <sys/param.h>
-
-#include <err.h>
-#include <fcntl.h>
-
-#include <gelf.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#define BOOTPROG_LOAD_START 0x01000000ULL
-
-int nflag = 0;
-
-int stack_kbytes[] = {
- /* ds rs pm sched vfs memory log tty mfs vm pfs init */
- 16, 8125, 32, 32, 16, 8, 32, 16, 128, 128, 128, 64
-};
-
-static void usage(void);
-
-GElf_Addr
-update_paddr(int nr, char *fname, GElf_Addr startaddr)
-{
- int i, fd;
- Elf *e;
- size_t n;
-
- GElf_Phdr phdr;
- GElf_Addr endaddr = 0;
-
- if ((fd = open(fname, O_RDWR, 0)) < 0)
- err(EX_NOINPUT, "open \"%s\" failed", fname);
-
- if ((e = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
- errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
-
- if (elf_kind(e) != ELF_K_ELF)
- errx(EX_DATAERR, "\"%s\" is not an ELF object.", fname);
-
- if (elf_getphdrnum(e, &n) != 0)
- errx(EX_DATAERR, "elf_getphdrnum() failed: %s.", elf_errmsg(-1));
-
- for (i = 0; i < n; i++) {
- if (gelf_getphdr(e, i, &phdr) != &phdr)
- errx(EX_SOFTWARE, "getphdr() failed: %s.",
- elf_errmsg(-1));
-
- if (phdr.p_type == PT_LOAD) {
- phdr.p_paddr = startaddr + phdr.p_vaddr;
-
- endaddr = round_page(phdr.p_paddr + phdr.p_memsz)
- + round_page(stack_kbytes[nr] * 1024);
-
- if (gelf_update_phdr(e, i, &phdr) < 0)
- errx(EX_SOFTWARE,
- "gelf_update_phdr failed: %s.",
- elf_errmsg(-1));
- }
-
- }
-
- if (elf_update(e, ELF_C_WRITE) < 0)
- errx(EX_SOFTWARE, "elf_update failed: %s.", elf_errmsg(-1));
-
- (void) elf_end(e);
- (void) close(fd);
-
- return endaddr;
-
-}
-
-int
-main(int argc, char **argv)
-{
- int i, ch;
- GElf_Addr startaddr;
-
- startaddr = BOOTPROG_LOAD_START;
-
- while ((ch = getopt(argc, argv, "n")) != -1) {
- switch (ch) {
- case 'n':
- nflag = 1;
- break;
- case '?':
- default:
- usage();
- exit(EX_USAGE);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc < 1)
- usage();
-
- if (elf_version(EV_CURRENT) == EV_NONE)
- errx(EX_SOFTWARE, "ELF library intialization failed: %s",
- elf_errmsg(-1));
-
- startaddr = BOOTPROG_LOAD_START;
- for (i = 0; i < argc; i++) {
- startaddr = update_paddr(i, argv[i], startaddr);
- }
-
- exit(EX_OK);
-}
-
-static void
-usage(void)
-{
- (void) fprintf(stderr, "usage: %s [-n] elf1 elf2...\n", getprogname());
-}