|  | /* See COPYRIGHT for copyright information. */ | 
|  |  | 
|  | #ifndef ROS_PROCINFO_H | 
|  | #define ROS_PROCINFO_H | 
|  |  | 
|  | #include <ros/memlayout.h> | 
|  | #include <ros/common.h> | 
|  | #include <ros/resource.h> | 
|  | #include <ros/atomic.h> | 
|  | #include <ros/arch/arch.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #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; | 
|  | uint32_t			nr_preempts_sent;	/* these two differ when a preempt*/ | 
|  | uint32_t			nr_preempts_done;	/* is in flight. */ | 
|  | uint64_t			preempt_pending; | 
|  | }; | 
|  |  | 
|  | 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; | 
|  | void *heap_bottom; | 
|  | /* for traditional forks, these two need to be memcpy'd over: */ | 
|  | char *argp[PROCINFO_MAX_ARGP]; | 
|  | char argbuf[PROCINFO_ARGBUF_SIZE]; | 
|  | /* 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_CPUS]; | 
|  | uint32_t			num_vcores; | 
|  | struct pcore		pcoremap[MAX_NUM_CPUS]; | 
|  | seq_ctr_t			coremap_seqctr; | 
|  | } procinfo_t; | 
|  | #define PROCINFO_NUM_PAGES  ((sizeof(procinfo_t)-1)/PGSIZE + 1) | 
|  |  | 
|  | static int | 
|  | procinfo_pack_args(procinfo_t* p, char* const* argv, char* const* envp) | 
|  | { | 
|  | int nargv = 0, nenvp = 0; | 
|  | if(argv) while(argv[nargv]) nargv++; | 
|  | if(envp) while(envp[nenvp]) nenvp++; | 
|  |  | 
|  | if(nargv+nenvp+2 > PROCINFO_MAX_ARGP) | 
|  | return -1; | 
|  |  | 
|  | int pos = 0; | 
|  | int i; | 
|  | for(i = 0; i < nargv; i++) | 
|  | { | 
|  | int len = strlen(argv[i])+1; | 
|  | if(pos+len > PROCINFO_ARGBUF_SIZE) | 
|  | return -1; | 
|  | p->argp[i] = ((procinfo_t*)UINFO)->argbuf+pos; | 
|  | memcpy(p->argbuf+pos,argv[i],len); | 
|  | pos += len; | 
|  | } | 
|  | p->argp[nargv] = 0; | 
|  |  | 
|  | for(i = 0; i < nenvp; i++) | 
|  | { | 
|  | int len = strlen(envp[i])+1; | 
|  | if(pos+len > PROCINFO_ARGBUF_SIZE) | 
|  | return -1; | 
|  | p->argp[nargv+1+i] = ((procinfo_t*)UINFO)->argbuf+pos; | 
|  | memcpy(p->argbuf+pos,envp[i],len); | 
|  | pos += len; | 
|  | } | 
|  | p->argp[nargv+nenvp+1] = 0; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // this is how user programs access the procinfo page | 
|  | #ifndef ROS_KERNEL | 
|  | # define __procinfo (*(procinfo_t*)UINFO) | 
|  |  | 
|  | #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; | 
|  | 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 */ | 
|  |  | 
|  | #endif // !ROS_PROCDATA_H |