<commit_before>#include "context.h"
#include "config.h"
#include "mmu.h"
#include "tinycstd.h"
#include "trap.h"
#include "diag.h"
#include "compiler-utils.h"

struct context_manager {
  struct context context;
  char is_used;
  struct context_manager* prev_scheduled;
  struct context_manager* next_scheduled;
};

struct context_manager all_contexts[MAX_AMOUNT_OF_CONTEXTS];

struct context kernel_context;

uint64_t num_of_used_contexts = 0;
struct context_manager* currently_active_context = &(all_contexts[0]);

struct context* kallocate_context() {
  struct context_manager* context_manager;
  struct context_manager* prev_scheduled = &all_contexts[0];
  struct context_manager* next_scheduled = &all_contexts[0];

  if (num_of_used_contexts == MAX_AMOUNT_OF_CONTEXTS)
    return NULL;

  for (size_t i = 0; i < MAX_AMOUNT_OF_CONTEXTS; ++i) {
    context_manager = &all_contexts[i];

    if (!context_manager->is_used) {
      context_manager->is_used = 1;
      ++num_of_used_contexts;
      context_manager->context.id = i + 1; // id 0 is reserved for the kernel context
      
      context_manager->prev_scheduled = prev_scheduled;
      context_manager->next_scheduled = next_scheduled;
      prev_scheduled->next_scheduled = context_manager;
      next_scheduled->prev_scheduled = context_manager;

      return &context_manager->context;
    } else {
      prev_scheduled = context_manager;
      next_scheduled = context_manager->next_scheduled;
    }
  }

  return NULL; // acutally unreachable but the compiler is too dumb to see this
}

void kinit_context(struct context* context) {
  // TODO: Check whether a page table has already been allocated
  context->pt = (struct pt_entry*)ppn_to_paddr(kzalloc());
  context->saved_regs.ra  = 0;
  context->saved_regs.sp  = USERSPACE_STACK_START;
  context->saved_regs.gp  = 0;
  context->saved_regs.tp  = 0;
  context->saved_regs.t0  = 0;
  context->saved_regs.t1  = 0;
  context->saved_regs.t2  = 0;
  context->saved_regs.s0  = 0;
  context->saved_regs.s1  = 0;
  context->saved_regs.a0  = 0;
  context->saved_regs.a1  = 0;
  context->saved_regs.a2  = 0;
  context->saved_regs.a3  = 0;
  context->saved_regs.a4  = 0;
  context->saved_regs.a5  = 0;
  context->saved_regs.a6  = 0;
  context->saved_regs.a7  = 0;
  context->saved_regs.s2  = 0;
  context->saved_regs.s3  = 0;
  context->saved_regs.s4  = 0;
  context->saved_regs.s5  = 0;
  context->saved_regs.s6  = 0;
  context->saved_regs.s7  = 0;
  context->saved_regs.s8  = 0;
  context->saved_regs.s9  = 0;
  context->saved_regs.s10 = 0;
  context->saved_regs.s11 = 0;
  context->saved_regs.t3  = 0;
  context->saved_regs.t4  = 0;
  context->saved_regs.t5  = 0;
  context->saved_regs.t6  = 0;

  context->legal_memory_boundaries.lowest_lo_page = 0;
  context->legal_memory_boundaries.highest_lo_page = 0;
  context->legal_memory_boundaries.lowest_mid_page = vaddr_to_vpn(USERSPACE_STACK_START) - 1;
  context->legal_memory_boundaries.highest_mid_page = vaddr_to_vpn(USERSPACE_STACK_START) - 1;
  context->legal_memory_boundaries.lowest_hi_page = SV39_PAGE_COUNT - 1;
  context->legal_memory_boundaries.highest_hi_page = SV39_PAGE_COUNT - 1;

  context->program_break = 0;

  kmap_page(context->pt, USERSPACE_STACK_START - PAGESIZE, true);

  kmap_kernel_upper_half(context->pt);
}

uint64_t roundUp(uint64_t addr, uint64_t align) {
  uint64_t delta = addr % align;
  if (delta > 0)
    addr = addr + (align - delta);

  return addr;
}
void kupload_argv(struct context* context, uint64_t argc, const char** argv) {
  uint64_t argvStrings[MAX_ARGV_LENGTH];

  for (uint64_t i = 0; i < argc; i++) {
    uint64_t stringSize = roundUp(strlen(argv[i]) + 1, 8); // 64bit-aligned

    // Reserve space on the stack
    context->saved_regs.sp -= stringSize;
    uint64_t uploadPaddr = vaddr_to_paddr(context->pt, context->saved_regs.sp);

    memcpy((void*)uploadPaddr, argv[i], stringSize);
    argvStrings[i] = context->saved_regs.sp;
  }

  // At the end of argv, put nullptr
  context->saved_regs.sp -= 8;
  *((uint64_t*)vaddr_to_paddr(context->pt, context->saved_regs.sp)) = 0;

  // copy argv pointer array to stack
  context->saved_regs.sp -= 8*argc;
  memcpy((void*)vaddr_to_paddr(context->pt, context->saved_regs.sp), argvStrings, 8*argc);

  // Copy argc to stack
  context->saved_regs.sp -= 8;
  *((uint64_t*)vaddr_to_paddr(context->pt, context->saved_regs.sp)) = argc;
}

extern void _start_hang();

void kfree_context(uint64_t context_id) {
  struct context_manager* context_manager = &all_contexts[context_id - 1];

  context_manager->is_used = 0;
  --num_of_used_contexts;

#ifdef DEBUG
  printf("freed context %u\n", context_id);
#endif /* DEBUG */

  if (num_of_used_contexts == 0) {
    panic("all processes are dead");
  }

  context_manager->prev_scheduled->next_scheduled = context_manager->next_scheduled;
  context_manager->next_scheduled->prev_scheduled = context_manager->prev_scheduled;
}
<commit_msg>Context: Free page table on kfree_context<commit_after>#include "context.h"
#include "config.h"
#include "mmu.h"
#include "tinycstd.h"
#include "trap.h"
#include "diag.h"
#include "compiler-utils.h"

struct context_manager {
  struct context context;
  char is_used;
  struct context_manager* prev_scheduled;
  struct context_manager* next_scheduled;
};

struct context_manager all_contexts[MAX_AMOUNT_OF_CONTEXTS];

struct context kernel_context;

uint64_t num_of_used_contexts = 0;
struct context_manager* currently_active_context = &(all_contexts[0]);

struct context* kallocate_context() {
  struct context_manager* context_manager;
  struct context_manager* prev_scheduled = &all_contexts[0];
  struct context_manager* next_scheduled = &all_contexts[0];

  if (num_of_used_contexts == MAX_AMOUNT_OF_CONTEXTS)
    return NULL;

  for (size_t i = 0; i < MAX_AMOUNT_OF_CONTEXTS; ++i) {
    context_manager = &all_contexts[i];

    if (!context_manager->is_used) {
      context_manager->is_used = 1;
      ++num_of_used_contexts;
      context_manager->context.id = i + 1; // id 0 is reserved for the kernel context
      
      context_manager->prev_scheduled = prev_scheduled;
      context_manager->next_scheduled = next_scheduled;
      prev_scheduled->next_scheduled = context_manager;
      next_scheduled->prev_scheduled = context_manager;

      return &context_manager->context;
    } else {
      prev_scheduled = context_manager;
      next_scheduled = context_manager->next_scheduled;
    }
  }

  return NULL; // acutally unreachable but the compiler is too dumb to see this
}

void kinit_context(struct context* context) {
  context->pt = (struct pt_entry*)ppn_to_paddr(kzalloc());
  context->saved_regs.ra  = 0;
  context->saved_regs.sp  = USERSPACE_STACK_START;
  context->saved_regs.gp  = 0;
  context->saved_regs.tp  = 0;
  context->saved_regs.t0  = 0;
  context->saved_regs.t1  = 0;
  context->saved_regs.t2  = 0;
  context->saved_regs.s0  = 0;
  context->saved_regs.s1  = 0;
  context->saved_regs.a0  = 0;
  context->saved_regs.a1  = 0;
  context->saved_regs.a2  = 0;
  context->saved_regs.a3  = 0;
  context->saved_regs.a4  = 0;
  context->saved_regs.a5  = 0;
  context->saved_regs.a6  = 0;
  context->saved_regs.a7  = 0;
  context->saved_regs.s2  = 0;
  context->saved_regs.s3  = 0;
  context->saved_regs.s4  = 0;
  context->saved_regs.s5  = 0;
  context->saved_regs.s6  = 0;
  context->saved_regs.s7  = 0;
  context->saved_regs.s8  = 0;
  context->saved_regs.s9  = 0;
  context->saved_regs.s10 = 0;
  context->saved_regs.s11 = 0;
  context->saved_regs.t3  = 0;
  context->saved_regs.t4  = 0;
  context->saved_regs.t5  = 0;
  context->saved_regs.t6  = 0;

  context->legal_memory_boundaries.lowest_lo_page = 0;
  context->legal_memory_boundaries.highest_lo_page = 0;
  context->legal_memory_boundaries.lowest_mid_page = vaddr_to_vpn(USERSPACE_STACK_START) - 1;
  context->legal_memory_boundaries.highest_mid_page = vaddr_to_vpn(USERSPACE_STACK_START) - 1;
  context->legal_memory_boundaries.lowest_hi_page = SV39_PAGE_COUNT - 1;
  context->legal_memory_boundaries.highest_hi_page = SV39_PAGE_COUNT - 1;

  context->program_break = 0;

  kmap_page(context->pt, USERSPACE_STACK_START - PAGESIZE, true);

  kmap_kernel_upper_half(context->pt);
}

uint64_t roundUp(uint64_t addr, uint64_t align) {
  uint64_t delta = addr % align;
  if (delta > 0)
    addr = addr + (align - delta);

  return addr;
}
void kupload_argv(struct context* context, uint64_t argc, const char** argv) {
  uint64_t argvStrings[MAX_ARGV_LENGTH];

  for (uint64_t i = 0; i < argc; i++) {
    uint64_t stringSize = roundUp(strlen(argv[i]) + 1, 8); // 64bit-aligned

    // Reserve space on the stack
    context->saved_regs.sp -= stringSize;
    uint64_t uploadPaddr = vaddr_to_paddr(context->pt, context->saved_regs.sp);

    memcpy((void*)uploadPaddr, argv[i], stringSize);
    argvStrings[i] = context->saved_regs.sp;
  }

  // At the end of argv, put nullptr
  context->saved_regs.sp -= 8;
  *((uint64_t*)vaddr_to_paddr(context->pt, context->saved_regs.sp)) = 0;

  // copy argv pointer array to stack
  context->saved_regs.sp -= 8*argc;
  memcpy((void*)vaddr_to_paddr(context->pt, context->saved_regs.sp), argvStrings, 8*argc);

  // Copy argc to stack
  context->saved_regs.sp -= 8;
  *((uint64_t*)vaddr_to_paddr(context->pt, context->saved_regs.sp)) = argc;
}

extern void _start_hang();

void kfree_context(uint64_t context_id) {
  struct context_manager* context_manager = &all_contexts[context_id - 1];

  context_manager->is_used = 0;
  --num_of_used_contexts;

  kfree_page_table(context_manager->context.pt);
  context_manager->context.pt = NULL;

#ifdef DEBUG
  printf("freed context %u\n", context_id);
#endif /* DEBUG */

  if (num_of_used_contexts == 0)
    panic("all processes are dead");

  context_manager->prev_scheduled->next_scheduled = context_manager->next_scheduled;
  context_manager->next_scheduled->prev_scheduled = context_manager->prev_scheduled;
}

{'fraction_non_alphanumeric': 0.12208421690396849, 'fraction_numerical': 0.023831162274058366, 'mean_word_length': 4.256900212314225, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 147, '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': '1154361', 'n_tokens_mistral': 3818, 'n_tokens_neox': 3624, 'n_words': 674}