__ros_syscall -> __ros_syscall_noerrno (XCC)
[akaros.git] / kern / include / ros / procinfo.h
1 /* See COPYRIGHT for copyright information. */
2
3 #ifndef ROS_PROCINFO_H
4 #define ROS_PROCINFO_H
5
6 #include <ros/memlayout.h>
7 #include <ros/common.h>
8 #include <ros/resource.h>
9 #include <ros/atomic.h>
10 #include <ros/arch/arch.h>
11 #include <string.h>
12
13 #define PROCINFO_MAX_ARGP 32
14 #define PROCINFO_ARGBUF_SIZE 3072
15
16 #ifdef ROS_KERNEL
17 #include <sys/queue.h>
18 #endif /* ROS_KERNEL */
19
20 /* Not necessary to expose all of this, but it doesn't hurt, and is convenient
21  * for the kernel.  Need to do some acrobatics for the TAILQ_ENTRY. */
22 struct vcore;
23 struct vcore {
24 #ifdef ROS_KERNEL
25         TAILQ_ENTRY(vcore)      list;
26 #else /* userspace */
27         void                            *dummy_ptr1;
28         void                            *dummy_ptr2;
29 #endif /* ROS_KERNEL */
30         uint32_t                        pcoreid;
31         bool                            valid;
32         uint32_t                        nr_preempts_sent;       /* these two differ when a preempt*/
33         uint32_t                        nr_preempts_done;       /* is in flight. */
34         uint64_t                        preempt_pending;
35 };
36
37 struct pcore {
38         uint32_t                        vcoreid;
39         bool                            valid;
40 };
41
42 typedef struct procinfo {
43         pid_t pid;
44         pid_t ppid;
45         size_t max_vcores;
46         uint64_t tsc_freq;
47         uint64_t timing_overhead;
48         void *heap_bottom;
49         /* for traditional forks, these two need to be memcpy'd over: */
50         char *argp[PROCINFO_MAX_ARGP];
51         char argbuf[PROCINFO_ARGBUF_SIZE];
52         /* glibc relies on stuff above this point.  if you change it, you need to
53          * rebuild glibc. */
54         bool is_mcp;                    /* is in multi mode */
55         unsigned long           res_grant[MAX_NUM_RESOURCES];
56         struct vcore            vcoremap[MAX_NUM_CPUS];
57         uint32_t                        num_vcores;
58         struct pcore            pcoremap[MAX_NUM_CPUS];
59         seq_ctr_t                       coremap_seqctr;
60 } procinfo_t;
61 #define PROCINFO_NUM_PAGES  ((sizeof(procinfo_t)-1)/PGSIZE + 1) 
62
63 static int
64 procinfo_pack_args(procinfo_t* p, char* const* argv, char* const* envp)
65 {
66         int nargv = 0, nenvp = 0;
67         if(argv) while(argv[nargv]) nargv++;
68         if(envp) while(envp[nenvp]) nenvp++;
69
70         if(nargv+nenvp+2 > PROCINFO_MAX_ARGP)
71                 return -1;
72
73         int pos = 0;
74         int i;
75         for(i = 0; i < nargv; i++)
76         {
77                 int len = strlen(argv[i])+1;
78                 if(pos+len > PROCINFO_ARGBUF_SIZE)
79                         return -1;
80                 p->argp[i] = ((procinfo_t*)UINFO)->argbuf+pos;
81                 memcpy(p->argbuf+pos,argv[i],len);
82                 pos += len;
83         }
84         p->argp[nargv] = 0;
85
86         for(i = 0; i < nenvp; i++)
87         {
88                 int len = strlen(envp[i])+1;
89                 if(pos+len > PROCINFO_ARGBUF_SIZE)
90                         return -1;
91                 p->argp[nargv+1+i] = ((procinfo_t*)UINFO)->argbuf+pos;
92                 memcpy(p->argbuf+pos,envp[i],len);
93                 pos += len;
94         }
95         p->argp[nargv+nenvp+1] = 0;
96         
97         return 0;
98 }
99
100 // this is how user programs access the procinfo page
101 #ifndef ROS_KERNEL
102 # define __procinfo (*(procinfo_t*)UINFO)
103
104 #include <ros/common.h>
105 #include <ros/atomic.h>
106 #include <ros/syscall.h>
107
108 /* Figure out what your vcoreid is from your pcoreid and procinfo.  Only low
109  * level or debugging code should call this. */
110 static inline uint32_t __get_vcoreid_from_procinfo(void)
111 {
112         /* The assumption is that any IPIs/KMSGs would knock userspace into the
113          * kernel before it could read the closing of the seqctr.  Put another way,
114          * there is a 'memory barrier' between the IPI write and the seqctr write.
115          * I think this is true. */
116         uint32_t kpcoreid, kvcoreid;
117         seq_ctr_t old_seq;
118         do {
119                 cmb();
120                 old_seq = __procinfo.coremap_seqctr;
121                 kpcoreid = __ros_syscall_noerrno(SYS_getpcoreid, 0, 0, 0, 0, 0, 0);
122                 if (!__procinfo.pcoremap[kpcoreid].valid)
123                         continue;
124                 kvcoreid = __procinfo.pcoremap[kpcoreid].vcoreid;
125         } while (seqctr_retry(old_seq, __procinfo.coremap_seqctr));
126         return kvcoreid;
127 }
128
129 static inline uint32_t __get_vcoreid(void)
130 {
131         /* since sys_getvcoreid could lie (and might never change) */
132         return __get_vcoreid_from_procinfo();
133 }
134
135 #endif /* ifndef ROS_KERNEL */
136
137 #endif // !ROS_PROCDATA_H