<commit_before>/*
 *
 * proc.c
 *
 * Created at:  Sat 29 Nov 16:51:41 2014 16:51:41
 *
 * Author:  <NAME> <<EMAIL>>
 *
 * License:  please visit the LICENSE file for details.
 *
 */

#include "config.h"
#include "common.h"
#include "elf.h"
#include "gdt.h"
#include "idt.h"
#include "pm.h"
#include "vm.h"
#include "proc.h"
#include "vga.h"
#include "timer.h"
#include "tss.h"
#include "x86.h"

static struct proc procs[NPROCS];
static uint32_t next_pid = 0;

struct proc *idle = NULL;
volatile struct proc *current_proc = NULL;

static struct proc *find_next_proc(enum proc_state state)
{
  static int i = 0;
  int n = 0;

  for (i %= NPROCS; /* no guard */; n++, i = (i + 1) % NPROCS){
    if (n >= NPROCS)
      /* we've visited every slot */
      break;

    if (procs[i].state == state)
      return &procs[i++];
  }

  /* default to the idle process */
  return idle;
}

/*
 * This function pretty much just calls `proc_schedule_after_irq` (this is the
 * handler for software interrupt no. 127)
 * Well, it issues an interrupts so `proc_schedule_after_irq` has an interrupt
 * (actually, an INT not a IRQ but there's pretty much no difference) to work on
 * (the CPU state is needed to do a switch a task)
 */
void proc_schedule_without_irq(void)
{
  /* well that was simple */
  __asm volatile("int $0x7f");
}

struct intregs *proc_schedule_after_irq(struct intregs *cpu_state)
{
  cli();

  struct proc *next_proc;

  if (!current_proc)
    return cpu_state;

  /* find a new process that could be run */
  next_proc = find_next_proc(PROC_SLEEPING);

  current_proc->trapframe = cpu_state;
  current_proc->state = PROC_SLEEPING;

  current_proc = next_proc;

  tss_set_ss(SEG_KDATA);
  tss_set_esp((uint32_t)current_proc->kstack);
  set_cr3((uint32_t)current_proc->pdir);

  return current_proc->trapframe;
}

void proc_load(void)
{
  /* NOTE: current_proc->trapframe isn't valid here */
  /*       the contents of the trapframe have been popped during irq_common_stub
   *       before the iret */
  void *entry = elf_load(current_proc->location.memory.address);
  void *stack = pm_alloc();

  uint16_t code_seg = current_proc->privileged ? SEG_KCODE : SEG_UCODE;
  uint16_t data_seg = current_proc->privileged ? SEG_KDATA : SEG_UDATA;

  map_pages(stack, (void *)VM_USER_STACK_ADDR - PAGE_SIZE, PTE_W | PTE_U, PAGE_SIZE);

  vga_printf("proc_load says hi! blasting off to 0x%x though\n", entry);

  /* this is kind of ugly.. */
  __asm volatile("movw   %0, %%ax\n"
                 "movw %%ax, %%ds\n"
                 "movw %%ax, %%es\n"
                 "movw %%ax, %%fs\n"
                 "movw %%ax, %%gs\n" :: "Nd"(data_seg) : "%ax");

  __asm volatile("movl $0xfeedbabe, %eax\n"
                 "movl $0xfeedbabe, %ebx\n"
                 "movl $0xfeedbabe, %ecx\n"
                 "movl $0xfeedbabe, %edx\n"
                 "movl $0xfeedbabe, %esi\n"
                 "movl $0xfeedbabe, %edi\n");

  __asm volatile("pushl %0" :: "g"(data_seg));
  __asm volatile("pushl %0" :: "Nd"(VM_USER_STACK_ADDR));
  __asm volatile("pushl $0x200"); /* flags, interrupts enabled */
  __asm volatile("pushl %0" :: "g"(code_seg));
  __asm volatile("pushl %0" :: "g"(entry));
  __asm volatile("iretl");
}

void proc_kickoff_first_process(void)
{
  vga_printf("kicking off the first process (%s)\n", current_proc->name);

  current_proc->state = PROC_RUNNING;

  tss_set_ss(SEG_KDATA);
  tss_set_esp((uint32_t)current_proc->kstack);
  set_cr3((uint32_t)current_proc->pdir);

  proc_load();
}

struct proc *proc_new(const char *name, bool privileged)
{
  struct proc *proc = find_next_proc(PROC_UNUSED);
  uint32_t *stack = pm_alloc();

  map_page(stack, stack, PTE_W);

  proc->pid   = next_pid++;
  proc->state = PROC_SLEEPING;
  proc->pdir  = vm_copy_kernel_pdir();
  proc->memsz = PAGE_SIZE;
  proc->privileged = privileged;
  proc->kstack = (uint32_t *)((uint32_t)stack + PAGE_SIZE);
  /* set the name */
  /* FIXME use(/have even) strncpy (or even better strlcpy) */
  memcpy(proc->name, (char *)name, MAX_PROC_NAME_LEN);

  stack = (uint32_t *)((uint8_t *)(stack) + PAGE_SIZE);

  /* we're going to be jumping to proc_load anyway
   * that's the reason for the hardcoded KDATA/KCODE stuff */
  *--stack = SEG_KDATA; /* ss */
  *--stack = (uint32_t)proc->kstack; /* useresp */
  *--stack = 0x200; /* eflags - interrupts enabled */
  *--stack = SEG_KCODE; /* cs */
  *--stack = (uint32_t)proc_load; /* eip */

  *--stack = 0xdeadbeef; /* err */
  *--stack = 0xfeedbabe; /* num */

  *--stack = 0x0; /* eax */
  *--stack = 0x0; /* ecx */
  *--stack = 0x0; /* edx */
  *--stack = 0x0; /* ebx */
  *--stack = 0x0; /* esp */
  *--stack = 0x0; /* ebp */
  *--stack = 0x0; /* esi */
  *--stack = 0x0; /* edi */

  *--stack = SEG_KDATA; /* ds */
  *--stack = SEG_KDATA; /* es */
  *--stack = SEG_KDATA; /* fs */
  *--stack = SEG_KDATA; /* gs */

  proc->trapframe = (struct intregs *)stack;

  vga_printf("created new proc %s (kstack 0x%x, tf 0x%x, pdir 0x%x)\n", proc->name, proc->kstack, proc->trapframe, proc->pdir);

  return proc;
}

struct proc *proc_new_from_memory(const char *name, bool user, void *addr, uint32_t size)
{
  struct proc *proc = proc_new(name, user);

  proc->location.memory.address = addr;
  proc->location.memory.size    = size;

  return proc;
}

void proc_earlyinit(void)
{
  /* initialize the whole processes table to a "zero" state */
  for (int i = 0; i < NPROCS; i++){
    procs[i].pid = -1;
    procs[i].state = PROC_UNUSED;
  }

  idt_set_gate(0x7f, int127, 0x8, 0xee);
  int_install_handler(0x7f, proc_schedule_after_irq);
}

/*
 * vi: ft=c:ts=2:sw=2:expandtab
 */

<commit_msg>Add the most basic process type recognition<commit_after>/*
 *
 * proc.c
 *
 * Created at:  Sat 29 Nov 16:51:41 2014 16:51:41
 *
 * Author:  <NAME> <<EMAIL>>
 *
 * License:  please visit the LICENSE file for details.
 *
 */

#include "config.h"
#include "common.h"
#include "elf.h"
#include "gdt.h"
#include "idt.h"
#include "pm.h"
#include "vm.h"
#include "proc.h"
#include "vga.h"
#include "timer.h"
#include "tss.h"
#include "x86.h"

static struct proc procs[NPROCS];
static uint32_t next_pid = 0;

struct proc *idle = NULL;
volatile struct proc *current_proc = NULL;

static struct proc *find_next_proc(enum proc_state state)
{
  static int i = 0;
  int n = 0;

  for (i %= NPROCS; /* no guard */; n++, i = (i + 1) % NPROCS){
    if (n >= NPROCS)
      /* we've visited every slot */
      break;

    if (procs[i].state == state)
      return &procs[i++];
  }

  /* default to the idle process */
  return idle;
}

/*
 * This function pretty much just calls `proc_schedule_after_irq` (this is the
 * handler for software interrupt no. 127)
 * Well, it issues an interrupts so `proc_schedule_after_irq` has an interrupt
 * (actually, an INT not a IRQ but there's pretty much no difference) to work on
 * (the CPU state is needed to do a switch a task)
 */
void proc_schedule_without_irq(void)
{
  /* well that was simple */
  __asm volatile("int $0x7f");
}

struct intregs *proc_schedule_after_irq(struct intregs *cpu_state)
{
  cli();

  struct proc *next_proc;

  if (!current_proc)
    return cpu_state;

  /* find a new process that could be run */
  next_proc = find_next_proc(PROC_SLEEPING);

  current_proc->trapframe = cpu_state;
  current_proc->state = PROC_SLEEPING;

  current_proc = next_proc;

  tss_set_ss(SEG_KDATA);
  tss_set_esp((uint32_t)current_proc->kstack);
  set_cr3((uint32_t)current_proc->pdir);

  return current_proc->trapframe;
}

void proc_load(void)
{
  /* NOTE: current_proc->trapframe isn't valid here */
  /*       the contents of the trapframe have been popped during irq_common_stub
   *       before the iret */

  uint32_t *entry = NULL;
  uint32_t *addr = current_proc->location.memory.address;

  if (*addr == 0x464c457f){
    /* the contents at that memory location is an ELF */
    entry = elf_load(current_proc->location.memory.address);
  } else {
    /* assume it's straight-forward binary data */
    entry = addr;
  }

  void *stack = pm_alloc();

  uint16_t code_seg = current_proc->privileged ? SEG_KCODE : SEG_UCODE;
  uint16_t data_seg = current_proc->privileged ? SEG_KDATA : SEG_UDATA;

  /* fix stack page permissions for privileged processes */
  map_pages(stack, (void *)VM_USER_STACK_ADDR - PAGE_SIZE, PTE_W | PTE_U, PAGE_SIZE);

  vga_printf("proc_load says hi! blasting off to 0x%x though\n", entry);

  /* this is kind of ugly.. */
  __asm volatile("movw   %0, %%ax\n"
                 "movw %%ax, %%ds\n"
                 "movw %%ax, %%es\n"
                 "movw %%ax, %%fs\n"
                 "movw %%ax, %%gs\n" :: "Nd"(data_seg) : "%ax");

  __asm volatile("movl $0xfeedbabe, %eax\n"
                 "movl $0xfeedbabe, %ebx\n"
                 "movl $0xfeedbabe, %ecx\n"
                 "movl $0xfeedbabe, %edx\n"
                 "movl $0xfeedbabe, %esi\n"
                 "movl $0xfeedbabe, %edi\n");

  __asm volatile("pushl %0" :: "g"(data_seg));
  __asm volatile("pushl %0" :: "Nd"(VM_USER_STACK_ADDR));
  __asm volatile("pushl $0x200"); /* flags, interrupts enabled */
  __asm volatile("pushl %0" :: "g"(code_seg));
  __asm volatile("pushl %0" :: "g"(entry));
  __asm volatile("iretl");
}

void proc_kickoff_first_process(void)
{
  vga_printf("kicking off the first process (%s)\n", current_proc->name);

  current_proc->state = PROC_RUNNING;

  tss_set_ss(SEG_KDATA);
  tss_set_esp((uint32_t)current_proc->kstack);
  set_cr3((uint32_t)current_proc->pdir);

  proc_load();
}

struct proc *proc_new(const char *name, bool privileged)
{
  struct proc *proc = find_next_proc(PROC_UNUSED);
  uint32_t *stack = pm_alloc();

  map_page(stack, stack, PTE_W);

  proc->pid   = next_pid++;
  proc->state = PROC_SLEEPING;
  proc->pdir  = vm_copy_kernel_pdir();
  proc->memsz = PAGE_SIZE;
  proc->privileged = privileged;
  proc->kstack = (uint32_t *)((uint32_t)stack + PAGE_SIZE);
  /* set the name */
  /* FIXME use(/have even) strncpy (or even better strlcpy) */
  memcpy(proc->name, (char *)name, MAX_PROC_NAME_LEN);

  stack = (uint32_t *)((uint8_t *)(stack) + PAGE_SIZE);

  /* we're going to be jumping to proc_load anyway
   * that's the reason for the hardcoded KDATA/KCODE stuff */
  *--stack = SEG_KDATA; /* ss */
  *--stack = (uint32_t)proc->kstack; /* useresp */
  *--stack = 0x200; /* eflags - interrupts enabled */
  *--stack = SEG_KCODE; /* cs */
  *--stack = (uint32_t)proc_load; /* eip */

  *--stack = 0xdeadbeef; /* err */
  *--stack = 0xfeedbabe; /* num */

  *--stack = 0x0; /* eax */
  *--stack = 0x0; /* ecx */
  *--stack = 0x0; /* edx */
  *--stack = 0x0; /* ebx */
  *--stack = 0x0; /* esp */
  *--stack = 0x0; /* ebp */
  *--stack = 0x0; /* esi */
  *--stack = 0x0; /* edi */

  *--stack = SEG_KDATA; /* ds */
  *--stack = SEG_KDATA; /* es */
  *--stack = SEG_KDATA; /* fs */
  *--stack = SEG_KDATA; /* gs */

  proc->trapframe = (struct intregs *)stack;

  vga_printf("created new proc %s (kstack 0x%x, tf 0x%x, pdir 0x%x)\n", proc->name, proc->kstack, proc->trapframe, proc->pdir);

  return proc;
}

struct proc *proc_new_from_memory(const char *name, bool user, void *addr, uint32_t size)
{
  struct proc *proc = proc_new(name, user);

  proc->location.memory.address = addr;
  proc->location.memory.size    = size;

  return proc;
}

void proc_earlyinit(void)
{
  /* initialize the whole processes table to a "zero" state */
  for (int i = 0; i < NPROCS; i++){
    procs[i].pid = -1;
    procs[i].state = PROC_UNUSED;
  }

  idt_set_gate(0x7f, int127, 0x8, 0xee);
  int_install_handler(0x7f, proc_schedule_after_irq);
}

/*
 * vi: ft=c:ts=2:sw=2:expandtab
 */


{'fraction_non_alphanumeric': 0.1579129232895646, 'fraction_numerical': 0.020818935729094677, 'mean_word_length': 3.159899389148401, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 68, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2585872', 'n_tokens_mistral': 4671, 'n_tokens_neox': 4425, 'n_words': 1100}