Example #1
0
File: acpi.c Project: Hooman3/minix
static u32_t acpi_phys2vir(u32_t p)
{
	if(!vm_running) {
		DEBUGEXTRA(("acpi: returning 0x%lx as vir addr\n", p));
		return p;
	}
	panic("acpi: can't get virtual address of arbitrary physical address");
}
Example #2
0
int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
/* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
{
	char *buf;
	size_t cnt, n;

	cnt= 0;
	while (*size > 0) {
		if (cnt == 0) {
			if ((buf= get_sector((*vsec)++)) == nil) return 0;
			cnt= SECTOR_SIZE;
		}
		if (*addr + click_size > limit) 
		{ 
			DEBUGEXTRA(("get_segment: out of memory; "
				"addr=0x%lx; limit=0x%lx; size=%lx\n", 
				*addr, limit, size));
			errno= ENOMEM; 
			return 0; 
		}
		n= click_size;
		if (n > cnt) n= cnt;
		DEBUGMAX(("raw_copy(0x%lx, 0x%lx/0x%x, 0x%lx)... ", 
			*addr, mon2abs(buf), buf, n));
		raw_copy(*addr, mon2abs(buf), n);
		DEBUGMAX(("done\n"));
		*addr+= n;
		*size-= n;
		buf+= n;
		cnt-= n;
	}

	/* Zero extend to a click. */
	n= align(*addr, click_size) - *addr;
	DEBUGMAX(("raw_clear(0x%lx, 0x%lx)... ", *addr, n));
	raw_clear(*addr, n);
	DEBUGMAX(("done\n"));
	*addr+= n;
	*size-= n;
	return 1;
}
Example #3
0
void bsp_finish_booting(void)
{
  int i;
#if SPROFILE
  sprofiling = 0;      /* we're not profiling until instructed to */
#endif /* SPROFILE */
  cprof_procs_no = 0;  /* init nr of hash table slots used */

  cpu_identify();

  vm_running = 0;
  krandom.random_sources = RANDOM_SOURCES;
  krandom.random_elements = RANDOM_ELEMENTS;

  /* MINIX is now ready. All boot image processes are on the ready queue.
   * Return to the assembly code to start running the current process. 
   */
  
  /* it should point somewhere */
  get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc);
  get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc);
  announce();				/* print MINIX startup banner */

  /*
   * we have access to the cpu local run queue, only now schedule the processes.
   * We ignore the slots for the former kernel tasks
   */
  for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) {
	RTS_UNSET(proc_addr(i), RTS_PROC_STOP);
  }
  /*
   * enable timer interrupts and clock task on the boot CPU
   */
  if (boot_cpu_init_timer(system_hz)) {
	  panic("FATAL : failed to initialize timer interrupts, "
			  "cannot continue without any clock source!");
  }

  fpu_init();

/* Warnings for sanity checks that take time. These warnings are printed
 * so it's a clear warning no full release should be done with them
 * enabled.
 */
#if DEBUG_SCHED_CHECK
  FIXME("DEBUG_SCHED_CHECK enabled");
#endif
#if DEBUG_VMASSERT
  FIXME("DEBUG_VMASSERT enabled");
#endif
#if DEBUG_PROC_CHECK
  FIXME("PROC check enabled");
#endif

  DEBUGEXTRA(("cycles_accounting_init()... "));
  cycles_accounting_init();
  DEBUGEXTRA(("done\n"));

#ifdef CONFIG_SMP
  cpu_set_flag(bsp_cpu_id, CPU_IS_READY);
  machine.processors_count = ncpus;
  machine.bsp_id = bsp_cpu_id;
#else
  machine.processors_count = 1;
  machine.bsp_id = 0;
#endif

  /* Kernel may no longer use bits of memory as VM will be running soon */
  kernel_may_alloc = 0;

  switch_to_user();
  NOT_REACHABLE;
}
Example #4
0
/*===========================================================================*
 *				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;
  strlcpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
  strlcpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));

  /* 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();
}
Example #5
0
/*===========================================================================*
 *			kmain 	                             		*
 *===========================================================================*/
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;

  /* save a global copy of the boot parameters */
  memcpy(&kinfo, local_cbi, sizeof(kinfo));
  memcpy(&kmess, kinfo.kmess, sizeof(kmess));

#ifdef __arm__
  /* We want to initialize serial before we do any output */
  omap3_ser_init();
#endif
  /* We can talk now */
  printf("MINIX booting\n");

  /* Kernel may use bits of main memory before VM is started */
  kernel_may_alloc = 1;

  assert(sizeof(kinfo.boot_procs) == sizeof(image));
  memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));

  cstart();

  BKL_LOCK();
 
   DEBUGEXTRA(("main()\n"));

   proc_init();

   if(NR_BOOT_MODULES != kinfo.mbi.mods_count)
   	panic("expecting %d boot processes/modules, found %d",
		NR_BOOT_MODULES, kinfo.mbi.mods_count);

  /* 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;
	int ipc_to_m, kcalls;
	sys_map_t map;

	ip = &image[i];				/* process' attributes */
	DEBUGEXTRA(("initializing %s... ", ip->proc_name));
	rp = proc_addr(ip->proc_nr);		/* get process pointer */
	ip->endpoint = rp->p_endpoint;		/* ipc endpoint */
	make_zero64(rp->p_cpu_time_left);
	if(i < NR_TASKS)			/* name (tasks only) */
		strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_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);

	/* See if this process is immediately schedulable.
	 * In that case, set its privileges now and allow it to run.
	 * Only kernel tasks and the root system process get to run immediately.
	 * All the other system processes are inhibited from running by the
	 * RTS_NO_PRIV flag. They can only be scheduled once the root system
	 * process has set their privileges.
	 */
	proc_nr = proc_nr(rp);
	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(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. */
                priv(rp)->s_trap_mask = (proc_nr == CLOCK 
                    || proc_nr == SYSTEM  ? CSK_T : TSK_T);
                ipc_to_m = TSK_M;                  /* allowed targets */
                kcalls = TSK_KC;                   /* allowed kernel calls */
            }
            /* Priviliges for the root system process. */
            else {
	    	assert(isrootsysn(proc_nr));
                priv(rp)->s_flags= RSYS_F;        /* privilege flags */
                priv(rp)->s_trap_mask= SRV_T;     /* allowed traps */
                ipc_to_m = SRV_M;                 /* allowed targets */
                kcalls = SRV_KC;                  /* allowed kernel calls */
                priv(rp)->s_sig_mgr = SRV_SM;     /* signal manager */
                rp->p_priority = SRV_Q;	          /* priority queue */
                rp->p_quantum_size_ms = SRV_QT;   /* quantum size */
            }

            /* Fill in target mask. */
            memset(&map, 0, sizeof(map));

            if (ipc_to_m == ALL_M) {
                for(j = 0; j < NR_SYS_PROCS; j++)
                    set_sys_bit(map, j);
            }

            fill_sendto_mask(rp, &map);

            /* Fill in kernel call mask. */
            for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
                priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
            }
	}
	else {
	    /* Don't let the process run for now. */
            RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
	}

	/* 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;

	/* 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_BOOTINHIBIT;
	}

	rp->p_rts_flags |= RTS_PROC_STOP;
	rp->p_rts_flags &= ~RTS_SLOT_FREE;
	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(NOTIFY);
  IPCNAME(SENDNB);
  IPCNAME(SENDA);

  /* 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"));
	  smp_single_cpu_fallback();
  } else if (config_no_smp) {
	  BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n"));
	  smp_single_cpu_fallback();
  } else {
	  smp_init();
	  /*
	   * if smp_init() returns it means that it failed and we try to finish
	   * single CPU booting
	   */
	  bsp_finish_booting();
  }
#else
  /* 
   * if configured for a single CPU, we are already on the kernel stack which we
   * are going to use everytime we execute kernel code. We finish booting and we
   * never return here
   */
  bsp_finish_booting();
#endif

  NOT_REACHABLE;
}
Example #6
0
/*===========================================================================*
 *				main                                         *
 *===========================================================================*/
PUBLIC int main(void)
{
/* 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 */

  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.
   */

  for (i=0; i < NR_BOOT_PROCS; ++i) {
	int schedulable_proc;
	proc_nr_t proc_nr;
	int ipc_to_m, kcalls;
	sys_map_t map;

	ip = &image[i];				/* process' attributes */
	DEBUGEXTRA(("initializing %s... ", ip->proc_name));
	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 */
	
	reset_proc_accounting(rp);

	/* See if this process is immediately schedulable.
	 * In that case, set its privileges now and allow it to run.
	 * Only kernel tasks and the root system process get to run immediately.
	 * All the other system processes are inhibited from running by the
	 * RTS_NO_PRIV flag. They can only be scheduled once the root system
	 * process has set their privileges.
	 */
	proc_nr = proc_nr(rp);
	schedulable_proc = (iskerneln(proc_nr) || isrootsysn(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)) {
                /* Privilege flags. */
                priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
                /* Allowed traps. */
                priv(rp)->s_trap_mask = (proc_nr == CLOCK 
                    || proc_nr == SYSTEM  ? CSK_T : TSK_T);
                ipc_to_m = TSK_M;                  /* allowed targets */
                kcalls = TSK_KC;                   /* allowed kernel calls */
            }
            /* Priviliges for the root system process. */
            else if(isrootsysn(proc_nr)) {
                priv(rp)->s_flags= RSYS_F;        /* privilege flags */
                priv(rp)->s_trap_mask= SRV_T;     /* allowed traps */
                ipc_to_m = SRV_M;                 /* allowed targets */
                kcalls = SRV_KC;                  /* allowed kernel calls */
                priv(rp)->s_sig_mgr = SRV_SM;     /* signal manager */
                rp->p_priority = SRV_Q;	          /* priority queue */
                rp->p_quantum_size_ms = SRV_QT;   /* quantum size */
            }
            /* Priviliges for ordinary process. */
            else {
		NOT_REACHABLE;
            }

            /* Fill in target mask. */
            memset(&map, 0, sizeof(map));

            if (ipc_to_m == ALL_M) {
                for(j = 0; j < NR_SYS_PROCS; j++)
                    set_sys_bit(map, j);
            }

            fill_sendto_mask(rp, &map);

            /* Fill in kernel call mask. */
            for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
                priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
            }
	}
	else {
	    /* 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);
	}

	/* 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)
		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"));
  }

#define IPCNAME(n) { \
	assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
	assert(!ipc_call_names[n]);	\
	ipc_call_names[n] = #n; \
}

  IPCNAME(SEND);
  IPCNAME(RECEIVE);
  IPCNAME(SENDREC);
  IPCNAME(NOTIFY);
  IPCNAME(SENDNB);
  IPCNAME(SENDA);

  /* Architecture-dependent initialization. */
  DEBUGEXTRA(("arch_init()... "));
  arch_init();
  DEBUGEXTRA(("done\n"));

  /* System and processes initialization */
  DEBUGEXTRA(("system_init()... "));
  system_init();
  DEBUGEXTRA(("done\n"));

#ifdef CONFIG_SMP
  if (config_no_apic) {
	  BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n"));
	  smp_single_cpu_fallback();
  } else if (config_no_smp) {
	  BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n"));
	  smp_single_cpu_fallback();
  } else {
	  smp_init();
	  /*
	   * if smp_init() returns it means that it failed and we try to finish
	   * single CPU booting
	   */
	  bsp_finish_booting();
  }
#else
  /* 
   * if configured for a single CPU, we are already on the kernel stack which we
   * are going to use everytime we execute kernel code. We finish booting and we
   * never return here
   */
  bsp_finish_booting();
#endif

  NOT_REACHABLE;
  return 1;
}
Example #7
0
void exec_image(char *image)
/* Get a Minix image into core, patch it up and execute. */
{
	int i;
	struct image_header hdr;
	char *buf;
	u32_t vsec, addr, limit, aout, n, totalmem = 0;
	struct process *procp;		/* Process under construction. */
	long a_text, a_data, a_bss, a_stack;
	int banner= 0;
	long processor= a2l(b_value("processor"));
	u16_t kmagic, mode;
	char *console;
	char params[SECTOR_SIZE];
	extern char *sbrk(int);
	char *verb;

	/* The stack is pretty deep here, so check if heap and stack collide. */
	(void) sbrk(0);

	if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil)
		verboseboot = a2l(verb);

	printf("\nLoading ");
	pretty_image(image);
	printf(".\n");

	vsec= 0;			/* Load this sector from image next. */
	addr= mem[0].base;		/* Into this memory block. */
	limit= mem[0].base + mem[0].size;
	if (limit > caddr) limit= caddr;

	/* Allocate and clear the area where the headers will be placed. */
	aout = (limit -= PROCESS_MAX * A_MINHDR);

	/* Clear the area where the headers will be placed. */
	raw_clear(aout, PROCESS_MAX * A_MINHDR);

	/* Read the many different processes: */
	for (i= 0; vsec < image_size; i++) {
		u32_t startaddr;
		startaddr = addr;
		if (i == PROCESS_MAX) {
			printf("There are more then %d programs in %s\n",
				PROCESS_MAX, image);
			errno= 0;
			return;
		}
		procp= &process[i];

		/* Read header. */
		DEBUGEXTRA(("Reading header... "));
		for (;;) {
			if ((buf= get_sector(vsec++)) == nil) return;

			memcpy(&hdr, buf, sizeof(hdr));

			if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }

			/* Check the optional label on the process. */
			if (selected(hdr.name)) break;

			/* Bad label, skip this process. */
			vsec+= proc_size(&hdr);
		}
		DEBUGEXTRA(("done\n"));

		/* Sanity check: an 8086 can't run a 386 kernel. */
		if (hdr.process.a_cpu == A_I80386 && processor < 386) {
			printf("You can't run a 386 kernel on this 80%ld\n",
				processor);
			errno= 0;
			return;
		}

		/* Get the click shift from the kernel text segment. */
		if (i == KERNEL_IDX) {
			if (!get_clickshift(vsec, &hdr)) return;
			addr= align(addr, click_size);

			/* big kernels must be loaded into extended memory */
			if (k_flags & K_KHIGH) {
				addr= mem[1].base;
				limit= mem[1].base + mem[1].size;
			}
		}

		/* Save a copy of the header for the kernel, with a_syms
		 * misused as the address where the process is loaded at.
		 */
		DEBUGEXTRA(("raw_copy(0x%x, 0x%lx, 0x%x)... ", 
			aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR));
		hdr.process.a_syms= addr;
		raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
		DEBUGEXTRA(("done\n"));

		if (!banner) {
			DEBUGBASIC(("     cs       ds     text     data      bss"));
			if (k_flags & K_CHMEM) DEBUGBASIC(("    stack"));
			DEBUGBASIC(("\n"));
			banner= 1;
		}

		/* Segment sizes. */
		DEBUGEXTRA(("a_text=0x%lx; a_data=0x%lx; a_bss=0x%lx; a_flags=0x%x)\n",
			hdr.process.a_text, hdr.process.a_data, 
			hdr.process.a_bss, hdr.process.a_flags));

		a_text= hdr.process.a_text;
		a_data= hdr.process.a_data;
		a_bss= hdr.process.a_bss;
		if (k_flags & K_CHMEM) {
			a_stack= hdr.process.a_total - a_data - a_bss;
			if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
		} else {
			a_stack= 0;
		}

		/* Collect info about the process to be. */
		procp->cs= addr;

		/* Process may be page aligned so that the text segment contains
		 * the header, or have an unmapped zero page against vaxisms.
		 */
		procp->entry= hdr.process.a_entry;
		if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
		if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;

		/* Separate I&D: two segments.  Common I&D: only one. */
		if (hdr.process.a_flags & A_SEP) {
			/* Read the text segment. */
			DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
				vsec, a_text, addr, limit));
			if (!get_segment(&vsec, &a_text, &addr, limit)) return;
			DEBUGEXTRA(("get_segment done vsec=0x%lx a_text=0x%lx "
				"addr=0x%lx\n", 
				vsec, a_text, addr));

			/* The data segment follows. */
			procp->ds= addr;
			if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
			procp->data= addr;
		} else {
			/* Add text to data to form one segment. */
			procp->data= addr + a_text;
			procp->ds= procp->cs;
			a_data+= a_text;
		}

		/* Read the data segment. */
		DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n", 
			vsec, a_data, addr, limit));
		if (!get_segment(&vsec, &a_data, &addr, limit)) return;
		DEBUGEXTRA(("get_segment done vsec=0x%lx a_data=0x%lx "
			"addr=0x%lx\n", 
			vsec, a_data, addr));

		/* Make space for bss and stack unless... */
		if (i != KERNEL_IDX && (k_flags & K_CLAIM)) a_bss= a_stack= 0;

		DEBUGBASIC(("%07lx  %07lx %8ld %8ld %8ld",
			procp->cs, procp->ds, hdr.process.a_text,
			hdr.process.a_data, hdr.process.a_bss));
		if (k_flags & K_CHMEM) DEBUGBASIC((" %8ld", a_stack));

		/* Note that a_data may be negative now, but we can look at it
		 * as -a_data bss bytes.
		 */

		/* Compute the number of bss clicks left. */
		a_bss+= a_data;
		n= align(a_bss, click_size);
		a_bss-= n;

		/* Zero out bss. */
		DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit));
		if (addr + n > limit) { errno= ENOMEM; return; }
		raw_clear(addr, n);
		DEBUGEXTRA(("done\n"));
		addr+= n;

		/* And the number of stack clicks. */
		a_stack+= a_bss;
		n= align(a_stack, click_size);
		a_stack-= n;

		/* Add space for the stack. */
		addr+= n;

		/* Process endpoint. */
		procp->end= addr;

		if (verboseboot >= VERBOSEBOOT_BASIC)
			printf("  %s\n", hdr.name);
		else {
			u32_t mem;
			mem = addr-startaddr;
			printf("%s ", hdr.name);
			totalmem += mem;
		}

		if (i == 0 && (k_flags & (K_HIGH | K_KHIGH)) == K_HIGH) {
			/* Load the rest in extended memory. */
			addr= mem[1].base;
			limit= mem[1].base + mem[1].size;
		}
	}

	if (verboseboot < VERBOSEBOOT_BASIC)
		printf("(%dk)\n", totalmem/1024);

	if ((n_procs= i) == 0) {
		printf("There are no programs in %s\n", image);
		errno= 0;
		return;
	}

	/* Check the kernel magic number. */
	raw_copy(mon2abs(&kmagic), 
		process[KERNEL_IDX].data + MAGIC_OFF, sizeof(kmagic));
	if (kmagic != KERNEL_D_MAGIC) {
		printf("Kernel magic number is incorrect (0x%x@0x%lx)\n", 
			kmagic, process[KERNEL_IDX].data + MAGIC_OFF);
		errno= 0;
		return;
	}

	/* Patch sizes, etc. into kernel data. */
	DEBUGEXTRA(("patch_sizes()... "));
	patch_sizes();
	DEBUGEXTRA(("done\n"));

#if !DOS
	if (!(k_flags & K_MEML)) {
		/* Copy the a.out headers to the old place. */
		raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
	}
#endif

	/* Run the trailer function just before starting Minix. */
	DEBUGEXTRA(("run_trailer()... "));
	if (!run_trailer()) { errno= 0; return; }
	DEBUGEXTRA(("done\n"));

	/* Translate the boot parameters to what Minix likes best. */
	DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params)));
	if (!params2params(params, sizeof(params))) { errno= 0; return; }
	DEBUGEXTRA(("done\n"));

	/* Set the video to the required mode. */
	if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
		mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
								MONO_MODE;
	}
	DEBUGEXTRA(("set_mode(%d)... ", mode));
	set_mode(mode);
	DEBUGEXTRA(("done\n"));

	/* Close the disk. */
	DEBUGEXTRA(("dev_close()... "));
	(void) dev_close();
	DEBUGEXTRA(("done\n"));

	/* Minix. */
	DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n", 
		process[KERNEL_IDX].entry, process[KERNEL_IDX].cs,
		process[KERNEL_IDX].ds, params, sizeof(params), aout));
	minix(process[KERNEL_IDX].entry, process[KERNEL_IDX].cs,
			process[KERNEL_IDX].ds, params, sizeof(params), aout);

	if (!(k_flags & K_BRET)) {
		extern u32_t reboot_code;
		raw_copy(mon2abs(params), reboot_code, sizeof(params));
	}
	parse_code(params);

	/* Return from Minix.  Things may have changed, so assume nothing. */
	fsok= -1;
	errno= 0;

	/* Read leftover character, if any. */
	scan_keyboard();

	/* Restore screen contents. */
	restore_screen();
}
Example #8
0
void exec_mb(char *kernel, char* modules)
/* Get a Minix image into core, patch it up and execute. */
{
	int i;
	static char hdr[SECTOR_SIZE];
	char *buf;
	u32_t vsec, addr, limit, n, totalmem = 0;
	u16_t kmagic, mode;
	char *console;
	char params[SECTOR_SIZE];
	extern char *sbrk(int);
	char *verb;
	u32_t text_vaddr, text_paddr, text_filebytes, text_membytes;
	u32_t data_vaddr, data_paddr, data_filebytes, data_membytes;
	u32_t pc;
	u32_t text_offset, data_offset;
	i32_t segsize;
	int r;
	u32_t cs, ds;
	char *modstring, *mod;
	multiboot_info_t *mbinfo;
	multiboot_module_t *mbmodinfo;
	u32_t mbinfo_size, mbmodinfo_size;
	char *memvar;
	memory *mp;
	u32_t mod_cmdline_start, kernel_cmdline_start;
	u32_t modstringlen;
	int modnr;

	/* The stack is pretty deep here, so check if heap and stack collide. */
	(void) sbrk(0);

	if ((verb= b_value(VERBOSEBOOTVARNAME)) != nil)
		verboseboot = a2l(verb);

	printf("\nLoading %s\n", kernel);

	vsec= 0;			/* Load this sector from kernel next. */
	addr= mem[0].base;		/* Into this memory block. */
	limit= mem[0].base + mem[0].size;
	if (limit > caddr) limit= caddr;

	/* set click size for get_segment */
	click_size = PAGE_SIZE;

	k_flags = K_KHIGH|K_BRET|K_MEML|K_INT86|K_RET|K_HDR
	    |K_HIGH|K_CHMEM|K_I386;

	/* big kernels must be loaded into extended memory */
	addr= mem[1].base;
	limit= mem[1].base + mem[1].size;

	/* Get first sector */
	DEBUGEXTRA(("get_sector\n"));
	if ((buf= get_sector(vsec++)) == nil) {
	    DEBUGEXTRA(("get_sector failed\n"));
	    return;
	}
	memcpy(hdr, buf, SECTOR_SIZE);

	/* Get ELF header */
	DEBUGEXTRA(("read_header_elf\n"));
	r = read_header_elf(hdr, &text_vaddr, &text_paddr,
			    &text_filebytes, &text_membytes,
			    &data_vaddr, &data_paddr,
			    &data_filebytes, &data_membytes,
			    &pc, &text_offset, &data_offset);
	if (r < 0) { errno= ENOEXEC; return; }

	/* Read the text segment. */
	addr = text_paddr;
	segsize = (i32_t) text_filebytes;
	vsec = text_offset / SECTOR_SIZE;
	DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
		    vsec, segsize, addr, limit));
	if (!get_segment(&vsec, &segsize, &addr, limit)) return;
	DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
		    "addr=0x%lx\n",
		    vsec, segsize, addr));

	/* Read the data segment. */
	addr = data_paddr;
	segsize = (i32_t) data_filebytes;
	vsec = data_offset / SECTOR_SIZE;

	DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
		    vsec, segsize, addr, limit));
	if (!get_segment(&vsec, &segsize, &addr, limit)) return;
	DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
		    "addr=0x%lx\n",
		    vsec, segsize, addr));

	n = data_membytes - align(data_filebytes, click_size);

	/* Zero out bss. */
	DEBUGEXTRA(("\nraw_clear(0x%lx, 0x%lx); limit=0x%lx... ", addr, n, limit));
	if (addr + n > limit) { errno= ENOMEM; return; }
	raw_clear(addr, n);
	DEBUGEXTRA(("done\n"));
	addr+= n;

	/* Check the kernel magic number. */
	raw_copy(mon2abs(&kmagic),
		 data_paddr + MAGIC_OFF, sizeof(kmagic));
	if (kmagic != KERNEL_D_MAGIC) {
		printf("Kernel magic number is incorrect (0x%x@0x%lx)\n",
			kmagic, data_paddr + MAGIC_OFF);
		errno= 0;
		return;
	}

	/* Translate the boot parameters to what Minix likes best. */
	DEBUGEXTRA(("params2params(0x%x, 0x%x)... ", params, sizeof(params)));
	if (!params2params(params, sizeof(params))) { errno= 0; return; }
	DEBUGEXTRA(("done\n"));

	/* Create multiboot info struct */
	mbinfo = malloc(sizeof(multiboot_info_t));
	if (mbinfo == nil) { errno= ENOMEM; return; }
	memset(mbinfo, 0, sizeof(multiboot_info_t));

	/* Module info structs start where kernel ends */
	mbinfo->mods_addr = addr;

	modstring = strdup(modules);
	if (modstring == nil) {errno = ENOMEM; return; }
	modstringlen = strlen(modules);
	mbinfo->mods_count = split_module_list(modules);

	mbmodinfo_size = sizeof(multiboot_module_t) * mbinfo->mods_count;
	mbmodinfo = malloc(mbmodinfo_size);
	if (mbmodinfo == nil) { errno= ENOMEM; return; }
	addr+= mbmodinfo_size;
	addr= align(addr, click_size);

	mod_cmdline_start = mbinfo->mods_addr + sizeof(multiboot_module_t) *
	    mbinfo->mods_count;

	raw_copy(mod_cmdline_start, mon2abs(modules),
		 modstringlen+1);

	mbmodinfo[0].cmdline = mod_cmdline_start;
	modnr = 1;
	for (i= 0; i < modstringlen; ++i) {
	    if (modules[i] == '\0') {
		mbmodinfo[modnr].cmdline = mod_cmdline_start + i + 1;
		++modnr;
	    }
	}

	kernel_cmdline_start = mod_cmdline_start + modstringlen + 1;
	mbinfo->cmdline = kernel_cmdline_start;
	raw_copy(kernel_cmdline_start, mon2abs(kernel),
		 strlen(kernel)+1);

	mbinfo->flags = MULTIBOOT_INFO_MODS|MULTIBOOT_INFO_CMDLINE|
	    MULTIBOOT_INFO_BOOTDEV|MULTIBOOT_INFO_MEMORY;

	mbinfo->boot_device = mbdev;
	mbinfo->mem_lower = mem[0].size/1024;
	mbinfo->mem_upper = mem[1].size/1024;

	for (i = 0, mod = strtok(modstring, " "); mod != nil;
	     mod = strtok(nil, " "), i++) {

		mod = select_image(mod);
		if (mod == nil) {errno = 0; return; }

		mbmodinfo[i].mod_start = addr;
		mbmodinfo[i].mod_end = addr + image_bytes;
		mbmodinfo[i].pad = 0;

		segsize= image_bytes;
		vsec= 0;
		DEBUGEXTRA(("get_segment(0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
		       vsec, segsize, addr, limit));
		if (!get_segment(&vsec, &segsize, &addr, limit)) return;
		DEBUGEXTRA(("get_segment done vsec=0x%lx size=0x%lx "
		       "addr=0x%lx\n",
		       vsec, segsize, addr));
		addr+= segsize;
		addr= align(addr, click_size);
	}
	free(modstring);

	DEBUGEXTRA(("modinfo raw_copy: dst 0x%lx src 0x%lx sz 0x%lx\n",
	    mbinfo->mods_addr, mon2abs(mbmodinfo),
	    mbmodinfo_size));
	raw_copy(mbinfo->mods_addr, mon2abs(mbmodinfo),
	    mbmodinfo_size);
	free(mbmodinfo);

	raw_copy(MULTIBOOT_INFO_ADDR, mon2abs(mbinfo),
		 sizeof(multiboot_info_t));
	free(mbinfo);

	/* Run the trailer function just before starting Minix. */
	DEBUGEXTRA(("run_trailer()... "));
	if (!run_trailer()) { errno= 0; return; }
	DEBUGEXTRA(("done\n"));

	/* Set the video to the required mode. */
	if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
		mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
								MONO_MODE;
	}
	DEBUGEXTRA(("set_mode(%d)... ", mode));
	set_mode(mode);
	DEBUGEXTRA(("done\n"));

	/* Close the disk. */
	DEBUGEXTRA(("dev_close()... "));
	(void) dev_close();
	DEBUGEXTRA(("done\n"));

	/* Minix. */
	cs = ds = text_paddr;
	DEBUGEXTRA(("minix(0x%lx, 0x%lx, 0x%lx, 0x%x, 0x%x, 0x%lx)\n",
		pc, cs, ds, params, sizeof(params), 0));
	minix(pc, cs, ds, params, sizeof(params), 0);

	if (!(k_flags & K_BRET)) {
		extern u32_t reboot_code;
		raw_copy(mon2abs(params), reboot_code, sizeof(params));
	}
	parse_code(params);

	/* Return from Minix.  Things may have changed, so assume nothing. */
	fsok= -1;
	errno= 0;

	/* Read leftover character, if any. */
	scan_keyboard();

	/* Restore screen contents. */
	restore_screen();
}