Пример #1
0
/* generic write for an fd */
ssize_t sys_write(int fd, char *buf, size_t n)
{
    struct file_s *flip = get_file(fd);

    if (flip == NULL)
        return ERROR;

    if (flip->f_op == NULL)
        debug_panic("sys_read: f_op is NULL");

    if (flip->f_op->write == NULL)
        debug_panic("sys_read: write func pointer is NULL");

    return flip->f_op->write(flip, buf, n);
}
Пример #2
0
/* generic lseek */
size_t sys_lseek(int fd, off_t offset, int whence)
{
    struct file_s *flip = get_file(fd);

    if (flip == NULL)
        return ERROR;

    if (flip->f_op == NULL)
        debug_panic("sys_read: f_op is NULL");

    if (flip->f_op->lseek == NULL)
        debug_panic("sys_lseek: lseek func pointer is NULL");

    return flip->f_op->lseek(flip, offset, whence);
}
Пример #3
0
/* generic flush */
int sys_flush(int fd)
{
    struct file_s *flip = get_file(fd);

    if (flip == NULL)
        return ERROR;

    if (flip->f_op == NULL)
        debug_panic("sys_flush: f_op is NULL");

    if (flip->f_op->flush == NULL)
        debug_panic("sys_flush: flush func pointer is NULL");

    return flip->f_op->flush(flip);
}
Пример #4
0
struct thread *fault_page(struct thread *image) {
	uint32_t cr2;

	/* Get faulting address from register CR2 */
	cr2 = cpu_get_cr2();

	/* If in kernelspace, panic */
	if ((image->cs & 0x3) == 0) { /* i.e. if it was kernelmode */	

		debug_printf("page fault at %x, ip = %x, frame %x, esp = %x\n", 
			cr2, image->eip, page_get(cr2), image->esp);

		debug_panic("page fault exception");
	}

	if (cr2 >= image->stack && cr2 < image->stack + SEGSZ) {
		/* allocate stack */
		mem_alloc(cr2 & ~0xFFF, PAGESZ, PF_PRES | PF_RW | PF_USER);
		return image;
	}
	else {
		/* fault */
		debug_printf("%d: %s: page fault at %x, ip = %x, frame %x\n", 
			image->proc->pid, image->proc->name, cr2, image->eip, page_get(cr2));
		debug_printf("user stack: %x - %x\n", image->stack, image->stack + SEGSZ);
		debug_printf("user stack dump: (ebp = %x)\n", image->ebp);
		debug_dumpi((void*) image->useresp, 30);

		process_freeze(image->proc);
		return thread_send(image, image->proc->pid, PORT_PAGE, NULL);
	}
}
Пример #5
0
struct thread *fault_double(struct thread *image) {

	/* Can only come from kernel problems */
	debug_printf("DS:%x CS:%x\n", image->ds, image->cs);
	debug_panic("double fault exception");
	return NULL;
}
Пример #6
0
/* make new device file in /dev folder, with type, major and minor numbers */
int fs_make_dev(const char *name, int type, dev_t major, dev_t minor)
{
    struct inode_s *ino, *dev;

    ino = dev = NULL;

    if ( (dev = find_inode(NULL, "/dev", FS_SEARCH_CREAT)) == NULL)
        debug_panic("fs_make_dev: error searching/creating /dev");

    if ( (ino = find_inode(dev, name, FS_SEARCH_CREAT)) == NULL)
        goto err;

    ino->i_zone[0] = major;
    ino->i_zone[1] = minor;
    ino->i_dirty = 1;

    release_inode(dev);
    release_inode(ino);

    return OK;

err:
    release_inode(dev);
    release_inode(ino);

    return ERROR;
}
Пример #7
0
void schedule_remove(struct thread *thread) {
	struct thread *temp;

	if (!schedule_queue.out) {
		debug_printf("scheduler empty, but tried to remove %x\n", thread);
		debug_panic("");
		return;
	}

	if (schedule_queue.out == thread) {
		schedule_queue.out = thread->next;
		return;
	}

	for (temp = schedule_queue.out; temp->next; temp = temp->next) {
		if (temp->next == thread) {
			temp->next = thread->next;

			if (schedule_queue.in == thread) {
				schedule_queue.in = temp;
			}

			thread->next = NULL;

			break;
		}
	}
}
Пример #8
0
struct thread *syscall_exit(struct thread *image) {

	if (image->proc->pid == 1) {
		debug_panic("init died");
	}

	process_switch(process_get(1));
	process_kill(image->proc);

	return thread_switch(image, schedule_next());
}
Пример #9
0
struct thread *fault_generic(struct thread *image) {

	/* If in kernelspace, panic */
	if ((image->cs & 0x3) == 0) {
		debug_printf("EIP:%x NUM:%d ERR:%x\n", image->eip, image->num, image->err);
		debug_panic("unknown exception");
	}

	process_freeze(image->proc);
	return thread_send(image, image->proc->pid, PORT_ILL, NULL);
}
Пример #10
0
void fault_generic(struct thread *image) {

	/* If in kernelspace, panic */
	if (image->cs & 0x3) {
		debug_printf("EIP:%x NUM:%d ERR:%x\n", image->eip, image->num, image->err);
		debug_panic("unknown exception");
	}

	// pause thread
	thread_save(image);
	image->state = TS_PAUSED;
	image->fault = FV_ACCS;

	// add to fault queue
	fault_push(image);
}
Пример #11
0
void schedule_insert(struct thread *thread) {

	if (!schedule_queue.out && schedule_queue.in) {
		debug_printf("scheduler inconsistency\n");
		debug_panic("");
	}

	if (!schedule_queue.in) {
		schedule_queue.out = thread;
		schedule_queue.in  = thread;
		thread->next = NULL;
	}
	else {
		schedule_queue.in->next = thread;
		schedule_queue.in = thread;
		thread->next = NULL;
	}
}
Пример #12
0
/* main
   The portable side of a multiboot-loaded kernel starts here. It is called by some bootstrap
   code, initialises the system and begins running programs. We'll assume the
   following:
   1. The kernel is mapped into 0xC0400000 (4MB into top 1GB) logical,
      and 0x00400000 physical.
   2. The lowest 2x4MB pages of physical RAM are mapped from 0xC0000000 logical.
   3. We're running on an architecture with 4KB page sizes, and the multiboot
      data will be stored below the lowest 1MB boundary. It's 4.30am, and I'll
      try to worry about portability later. A multiboot bootloader is also
      essential.
   => mbd = ptr to multiboot data about the system we're running in
      magic = special word passed by the bootloader to prove it is multiboot capable
*/
void _main(multiboot_info_t *mbd, unsigned int magic)
{
   if(DEBUG) debug_initialise();
   dprintf("[core] %s rev %s" " " __TIME__ " " __DATE__ " (built with GCC " __VERSION__ ")\n", KERNEL_IDENTIFIER, SVN_REV);
   
   if(magic != MULTIBOOT_MAGIC) /* as defined in the multiboot spec */
      dprintf("*** warning: bootloader magic was %x (expecting %x).\n", magic, MULTIBOOT_MAGIC);
   
   /* initialise critical infrastructure of the kernel */
   locks_initialise(KernelPhysLockPage);
   
   /* ---- multiboot + SMP data must be preserved during these calls ------- */
   /* discover processor(s), get exception handling running */
   if(mp_initialise()) goto goforhalt;
   
   /* parse modules payloaded by the boot loader, best halt if there are none? */
   if(payload_preinit(mbd)) goto goforhalt;

   /* initialise the memory manager or halt if it fails */
   if(vmm_initialise(mbd)) goto goforhalt;
   
   /* initialise the interrupt and hardware driver subsystem */
   if(int_initialise()) goto goforhalt;
   
   /* bring up the remaining processor(s) cores */
   if(mp_post_initialise()) goto goforhalt;

   /* initialise process and thread management, prepare first process */
   if(proc_initialise()) goto goforhalt;

   /* ---- multiboot + SMP data is no longer required by this point ------- */

   /* hocus pocus, mumbo jumbo, black magic */
   sched_initialise(); /* enable interrupts and start the execution of
                          userspace processes */
   /* shouldn't fall through... but halt if so */
   
goforhalt:
   /* halt here - there is nothing to return to */
   debug_panic("unexpected end-of-boot");
}
Пример #13
0
struct thread *syscall_exit(struct thread *image) {
	struct thread *new_image;
	uint16_t pid;
	uint32_t parent;

	pid = image->proc->pid;

	if (pid == 1) {
		debug_panic("init died");
	}

	parent = image->proc->parent->pid;

	process_switch(process_get(1));

	new_image = thread_send(image, parent, PORT_CHILD, NULL);

	image->proc->status = image->eax;
	process_kill(image->proc);

	return new_image;
}
Пример #14
0
Файл: heap.c Проект: UIKit0/flux
static void *heap_valloc(uintptr_t size) {
	static uintptr_t brk = KERNEL_HEAP;
	int i;

	if (brk + size >= KERNEL_HEAP_END) {
		/* out of memory */

		/* print analysis */
		for (i = 0; i < 16; i++) {
			debug_printf("%d: %d\n", i, analysis[i]);
		}

		debug_panic("out of virtual memory");
		return NULL;
	}
	else {
		page_set(brk, page_fmt(frame_new(), PF_PRES | PF_RW));
		mem_alloc(brk, size, PF_PRES | PF_RW);

		brk += size;
		return (void*) (brk - size);
	}
}
Пример #15
0
void fault_page(struct thread *image) {
	uint32_t cr2;

	/* Get faulting address from register CR2 */
	cr2 = cpu_get_cr2();

	/* If in kernelspace, panic */
	if ((image->cs & 0x3) == 0) { /* i.e. if it was kernelmode */	

		debug_printf("page fault at %x, ip = %x, frame %x, esp = %x\n", 
			cr2, image->eip, page_get(cr2), image->esp);

		debug_panic("page fault exception");
	}

	/* fault */
	thread_save(image);
	image->fault_addr = cr2;
	image->fault = FV_PAGE;
	image->state = TS_PAUSED;

	// add to fault queue
	fault_push(image);
}
Пример #16
0
struct thread *init(struct multiboot *mboot, uint32_t mboot_magic) {
	struct process *idle, *init;
	struct module *module;
	struct memory_map *mem_map;
	size_t mem_map_count, i, addr;
	uintptr_t boot_image_size;
	void *boot_image;
	struct elf32_ehdr *init_image;
	struct elf32_ehdr *dl_image;

	/* initialize debugging output */
	debug_init();
	debug_printf("Rhombus Operating System Kernel v0.8a\n");

	/* check multiboot header */
	if (mboot_magic != 0x2BADB002) {
		debug_panic("bootloader is not multiboot compliant");
	}

	/* touch pages for the kernel heap */
	for (i = KSPACE; i < KERNEL_HEAP_END; i += SEGSZ) {
		page_touch(i);
	}

	/* identity map kernel boot frames */
	for (i = KSPACE + KERNEL_BOOT; i < KSPACE + KERNEL_BOOT_END; i += PAGESZ) {
		page_set(i, page_fmt(i - KSPACE, PF_PRES | PF_RW));
	}

	/* parse the multiboot memory map to find the size of memory */
	mem_map       = (void*) (mboot->mmap_addr + KSPACE);
	mem_map_count = mboot->mmap_length / sizeof(struct memory_map);

	for (i = 0; i < mem_map_count; i++) {
		if (mem_map[i].type == 1 && mem_map[i].base_addr_low <= 0x100000) {
			for (addr = 0; addr < mem_map[i].length_low; addr += PAGESZ) {
				frame_add(mem_map[i].base_addr_low + addr);
			}
		}
	}

	/* bootstrap process 0 (idle) */
	idle = process_alloc();
	idle->space = cpu_get_cr3();
	idle->user  = 0;

	/* fork process 1 (init) and switch */
	init = process_clone(idle, NULL);
	process_switch(init);

	/* get multiboot module information */
	if (mboot->mods_count < 3) {
		if (mboot->mods_count < 2) {
			if (mboot->mods_count < 1) {
				debug_panic("no boot or init or dl modules found");
			}
			else {
				debug_panic("no boot or dl modules found");
			}
		}
		else {
			debug_panic("no dl module found");
		}
	}
	module     = (void*) (mboot->mods_addr + KSPACE);
	init_image = (void*) (module[0].mod_start + KSPACE);
	boot_image = (void*) (module[1].mod_start + KSPACE);
	dl_image   = (void*) (module[2].mod_start + KSPACE);
	boot_image_size = module[1].mod_end - module[1].mod_start;

	/* move boot image to BOOT_IMAGE in userspace */
	mem_alloc(BOOT_IMAGE, boot_image_size, PF_PRES | PF_USER | PF_RW);
	memcpy((void*) BOOT_IMAGE, boot_image, boot_image_size);

	/* bootstrap thread 0 in init */
	thread_bind(init->thread[0], init);
	init->thread[0]->useresp = init->thread[0]->stack + SEGSZ;
	init->thread[0]->esp     = (uintptr_t) &init->thread[0]->num;
	init->thread[0]->ss      = 0x23;
	init->thread[0]->ds      = 0x23;
	init->thread[0]->cs      = 0x1B;
	init->thread[0]->eflags  = cpu_get_eflags() | 0x3200; /* IF, IOPL = 3 */

	/* bootstrap idle thread */
	idle->thread[0] = &__idle_thread;
	__idle_thread.proc = idle;

	/* load dl */
	if (elf_check_file(dl_image)) {
		debug_panic("dl.so is not a valid ELF executable");
	}
	elf_load_file(dl_image);

	/* execute init */
	if (elf_check_file(init_image)) {
		debug_panic("init is not a valid ELF executable");
	}
	elf_load_file(init_image);
	init->thread[0]->eip = init_image->e_entry;

	/* register system calls */
	int_set_handler(SYSCALL_SEND, syscall_send);
	int_set_handler(SYSCALL_DONE, syscall_done);
	int_set_handler(SYSCALL_WHEN, syscall_when);
	int_set_handler(SYSCALL_RIRQ, syscall_rirq);
	int_set_handler(SYSCALL_ALSO, syscall_also);
	int_set_handler(SYSCALL_STAT, syscall_stat);
	int_set_handler(SYSCALL_PAGE, syscall_page);
	int_set_handler(SYSCALL_PHYS, syscall_phys);
	int_set_handler(SYSCALL_FORK, syscall_fork);
	int_set_handler(SYSCALL_EXIT, syscall_exit);
	int_set_handler(SYSCALL_STOP, syscall_stop);
	int_set_handler(SYSCALL_WAKE, syscall_wake);
	int_set_handler(SYSCALL_GPID, syscall_gpid);
	int_set_handler(SYSCALL_TIME, syscall_time);
	int_set_handler(SYSCALL_USER, syscall_user);
	int_set_handler(SYSCALL_AUTH, syscall_auth);
	int_set_handler(SYSCALL_PROC, syscall_proc);
	int_set_handler(SYSCALL_KILL, syscall_kill);
	int_set_handler(SYSCALL_VM86, syscall_vm86);
	int_set_handler(SYSCALL_NAME, syscall_name);
	int_set_handler(SYSCALL_REAP, syscall_reap);

	/* register fault handlers */
	int_set_handler(FAULT_DE, fault_float);
	int_set_handler(FAULT_DB, fault_generic);
	int_set_handler(FAULT_NI, fault_generic);
	int_set_handler(FAULT_BP, fault_generic);
	int_set_handler(FAULT_OF, fault_generic);
	int_set_handler(FAULT_BR, fault_generic);
	int_set_handler(FAULT_UD, fault_generic);
	int_set_handler(FAULT_NM, fault_nomath);
	int_set_handler(FAULT_DF, fault_double);
	int_set_handler(FAULT_CO, fault_float);
	int_set_handler(FAULT_TS, fault_generic);
	int_set_handler(FAULT_NP, fault_generic);
	int_set_handler(FAULT_SS, fault_generic);
	int_set_handler(FAULT_GP, fault_gpf);
	int_set_handler(FAULT_PF, fault_page);
	int_set_handler(FAULT_MF, fault_float);
	int_set_handler(FAULT_AC, fault_generic);
	int_set_handler(FAULT_MC, fault_generic);
	int_set_handler(FAULT_XM, fault_nomath);

	/* start timer (for preemption) */
	timer_set_freq(64);

	/* initialize FPU/MMX/SSE */
	cpu_init_fpu();

	/* drop to usermode, scheduling the next thread */
	debug_printf("dropping to usermode\n");
	return thread_switch(NULL, schedule_next());
}
Пример #17
0
/* lock_gate
   Allow multiple threads to read during a critical section, but only
   allow one writer. To avoid deadlocks, it keeps track of the exclusive
   owner - so that a thread can enter a gate as a reader and later
   upgrade to a writer, or start off a writer and call a function that
   requires a read or write lock. This function will block and spin if
   write access is requested and other threads are reading/writing, or
   read access is requested and another thread is writing.
   => gate = lock structure to modify
      flags = set either LOCK_READ or LOCK_WRITE, also set LOCK_SELFDESTRUCT
              to mark a gate as defunct, causing other threads to fail if
              they try to access it
   <= success or a failure code
*/
kresult lock_gate(rw_gate *gate, unsigned int flags)
{
#ifndef UNIPROC
   kresult err = success;
   unsigned int caller;

#ifdef LOCK_TIME_CHECK
   unsigned long long ticks = x86_read_cyclecount();
#endif

   /* sanity checks */
   if(!gate) return e_failure;
   if(!cpu_table) return success; /* only one processor running */
   
#ifdef LOCK_DEBUG
   if(cpu_table)
   {
      LOCK_DEBUG("[lock:%i] -> lock_gate(%p, %x) by thread %p\n", CPU_ID, gate, flags, cpu_table[CPU_ID].current);
   }
   else
   {
      LOCK_DEBUG("[lock:%i] -> lock_gate(%p, %x) during boot\n", CPU_ID, gate, flags);
   }
#endif
   
   /* cpu_table[CPU_ID].current cannot be lower than the kernel virtual base 
      so it won't collide with the processor's CPU_ID, which is used to
      identify the owner if no thread is running */
   if(cpu_table[CPU_ID].current)
      caller = (unsigned int)cpu_table[CPU_ID].current;
   else
      caller = (CPU_ID) + 1; /* zero means no owner, CPU_IDs start at zero... */
   
   while(1)
   {
      lock_spin(&(gate->spinlock));
      
      /* we're in - is the gate claimed? */
      if(gate->owner)
      {
         /* it's in use - but is it another thread? */
         if(gate->owner != caller)
         {
            /* another thread has it :( perform checks */
            
            /* this lock is defunct? */
            if(gate->flags & LOCK_SELFDESTRUCT)
            {
               err = e_failure;
               goto exit_lock_gate;
            }
            
            /* if we're not trying to write and the owner isn't
               writing and a writer isn't waiting, then it's safe to progress */
            if(!(flags & LOCK_WRITE) && !(gate->flags & LOCK_WRITE) && !(gate->flags & LOCK_WRITEWAITING))
               goto exit_lock_gate;

            /* if we're trying to write then set a write-wait flag.
               when this flag is set, stop allowing new reading threads.
               this should prevent writer starvation */
            if(flags & LOCK_WRITE)
               gate->flags |= LOCK_WRITEWAITING;
         }
         else
         {
            /* if the gate's owned by this thread, then carry on */
            gate->refcount++; /* keep track of the number of times we're entering */
            goto exit_lock_gate;
         }
      }
      else
      {
         /* no one owns this gate, so make our mark */
         gate->owner = caller;
         gate->flags = flags;
         gate->refcount = 1; /* first in */
         goto exit_lock_gate;
      }
      
      unlock_spin(&(gate->spinlock));
      
      /* small window of opportunity for the other thread to
         release the gate :-/ */
      /* hint to newer processors that this is a spin-wait loop or
         NOP for older processors */
      __asm__ __volatile__("pause");
      
#ifdef LOCK_TIME_CHECK
      if((x86_read_cyclecount() - ticks) > LOCK_TIMEOUT)
      {
         /* prevent other cores from trashing the output debug while we dump this info */
         lock_spin(&lock_time_check_lock);
         
         KOOPS_DEBUG("[lock:%i] OMGWTF waited too long for gate %p to become available (flags %x)\n"
                     "         lock is owned by %p", CPU_ID, gate, flags, gate->owner);
         if(gate->owner > KERNEL_SPACE_BASE)
         {
            thread *t = (thread *)(gate->owner);
            KOOPS_DEBUG(" (thread %i process %i on cpu %i)", t->tid, t->proc->pid, t->cpu);
         }
         KOOPS_DEBUG("\n");
         debug_stacktrace();
         
         unlock_spin(&lock_time_check_lock);
         
         debug_panic("deadlock in kernel: we can't go on together with suspicious minds");
      }
#endif
   }

exit_lock_gate:
   /* release the gate so others can inspect it */
   unlock_spin(&(gate->spinlock));
   
   LOCK_DEBUG("[lock:%i] locked %p with %x\n", CPU_ID, gate, flags);
   
   return err;
#endif
}