blob: 332ee613d2af482464b4ebd6dbc335d35969b686 [file] [log] [blame]
/* See COPYRIGHT for copyright information. */
#pragma once
#include <ros/memlayout.h>
#include <ros/common.h>
#include <ros/resource.h>
#include <ros/atomic.h>
#include <ros/arch/arch.h>
#include <ros/cpu_feat.h>
#include <string.h>
/* Process creation flags */
#define PROC_DUP_FGRP 1
#define PROCINFO_MAX_ARGP 32
#define PROCINFO_ARGBUF_SIZE 3072
#ifdef ROS_KERNEL
#include <sys/queue.h>
#endif /* ROS_KERNEL */
/* Not necessary to expose all of this, but it doesn't hurt, and is convenient
* for the kernel. Need to do some acrobatics for the TAILQ_ENTRY. */
struct vcore;
struct vcore {
#ifdef ROS_KERNEL
TAILQ_ENTRY(vcore) list;
#else /* userspace */
void *dummy_ptr1;
void *dummy_ptr2;
#endif /* ROS_KERNEL */
uint32_t pcoreid;
bool valid;
/* these two differ when a preempt is in flight. */
uint32_t nr_preempts_sent;
uint32_t nr_preempts_done;
uint64_t preempt_pending;
/* A process can see cumulative runtime as of the last resume, and can
* also calculate runtime in this interval, by adding (ns - resume) +
* total. */
uint64_t resume_ticks; /* TSC at resume time */
/* ticks up to last offlining */
uint64_t total_ticks;
};
struct pcore {
uint32_t vcoreid;
bool valid;
};
typedef struct procinfo {
pid_t pid;
pid_t ppid;
size_t max_vcores; /* TODO: change to a uint32_t */
uint64_t tsc_freq;
uint64_t timing_overhead;
uintptr_t program_end;
/* glibc relies on stuff above this point. if you change it, you need
* to rebuild glibc. */
bool is_mcp; /* is in multi mode */
unsigned long res_grant[MAX_NUM_RESOURCES];
struct vcore vcoremap[MAX_NUM_CORES];
uint32_t num_vcores;
struct pcore pcoremap[MAX_NUM_CORES];
seq_ctr_t coremap_seqctr;
} procinfo_t;
#define PROCINFO_NUM_PAGES ((sizeof(procinfo_t)-1)/PGSIZE + 1)
/* We align this so that the kernel can easily allocate it in the BSS */
struct proc_global_info {
unsigned long cpu_feats[__NR_CPU_FEAT_BITS];
uint64_t x86_default_xcr0;
uint64_t tsc_freq;
uint64_t tsc_overhead;
uint64_t bus_freq;
uint64_t walltime_ns_last;
uint64_t tsc_cycles_last;
} __attribute__((aligned(PGSIZE)));
#define PROCGINFO_NUM_PAGES (sizeof(struct proc_global_info) / PGSIZE)
#ifdef ROS_KERNEL
/* defined in init.c */
extern struct proc_global_info __proc_global_info;
#else /* Userland */
#define __procinfo (*(procinfo_t*)UINFO)
#define __proc_global_info (*(struct proc_global_info*)UGINFO)
#include <ros/common.h>
#include <ros/atomic.h>
#include <ros/syscall.h>
/* Figure out what your vcoreid is from your pcoreid and procinfo. Only low
* level or debugging code should call this. */
static inline uint32_t __get_vcoreid_from_procinfo(void)
{
/* The assumption is that any IPIs/KMSGs would knock userspace into the
* kernel before it could read the closing of the seqctr. Put another
* way, there is a 'memory barrier' between the IPI write and the seqctr
* write. I think this is true. */
uint32_t kpcoreid, kvcoreid;
extern long __ros_syscall_noerrno(unsigned int _num, long _a0, long _a1,
long _a2, long _a3, long _a4,
long _a5);
seq_ctr_t old_seq;
do {
cmb();
old_seq = __procinfo.coremap_seqctr;
kpcoreid = __ros_syscall_noerrno(SYS_getpcoreid, 0, 0, 0, 0, 0,
0);
if (!__procinfo.pcoremap[kpcoreid].valid)
continue;
kvcoreid = __procinfo.pcoremap[kpcoreid].vcoreid;
} while (seqctr_retry(old_seq, __procinfo.coremap_seqctr));
return kvcoreid;
}
static inline uint32_t __get_vcoreid(void)
{
/* since sys_getvcoreid could lie (and might never change) */
return __get_vcoreid_from_procinfo();
}
#endif /* ifndef ROS_KERNEL */