summaryrefslogtreecommitdiff
path: root/minix/servers/vm/mem_shared.c
blob: 93e791dc48158c6081fc791deaf00c567624abbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211

/* This file implements the methods of shared memory.  */

#include <assert.h>

#include "proto.h"
#include "vm.h"
#include "region.h"
#include "glo.h"

/* These functions are static so as to not pollute the
 * global namespace, and are accessed through their function
 * pointers.
 */

static int shared_unreference(struct phys_region *pr);
static int shared_pagefault(struct vmproc *vmp, struct vir_region *region, 
	struct phys_region *ph, int write, vfs_callback_t cb, void *state,
	int len, int *io);
static int shared_sanitycheck(struct phys_region *pr, const char *file, int line);
static int shared_writable(struct phys_region *pr);
static void shared_delete(struct vir_region *region);
static u32_t shared_regionid(struct vir_region *region);
static int shared_copy(struct vir_region *vr, struct vir_region *newvr);
static int shared_refcount(struct vir_region *vr);
static int shared_pt_flags(struct vir_region *vr);

struct mem_type mem_type_shared = {
	.name = "shared memory",
	.ev_copy = shared_copy,
	.ev_unreference = shared_unreference,
	.ev_pagefault = shared_pagefault,
	.ev_sanitycheck = shared_sanitycheck,
	.ev_delete = shared_delete,
	.regionid = shared_regionid,
	.refcount = shared_refcount,
	.writable = shared_writable,
	.pt_flags = shared_pt_flags,
};

static int shared_pt_flags(struct vir_region *vr){
#if defined(__arm__)
	return ARM_VM_PTE_CACHED;
#else
	return 0;
#endif
}

static int shared_unreference(struct phys_region *pr)
{
	return mem_type_anon.ev_unreference(pr);
}

static int getsrc(struct vir_region *region,
	struct vmproc **vmp, struct vir_region **r)
{
	int srcproc;

	if(region->def_memtype != &mem_type_shared) {
		printf("shared region hasn't shared type but %s.\n",
			region->def_memtype->name);
		return EINVAL;
	}

	if(!region->param.shared.ep || !region->param.shared.vaddr) {
		printf("shared region has not defined source region.\n");
		util_stacktrace();
		return EINVAL;
	}

        if(vm_isokendpt((endpoint_t) region->param.shared.ep, &srcproc) != OK) {
		printf("VM: shared memory with missing source process.\n");
		util_stacktrace();
                return EINVAL;
	}

	*vmp = &vmproc[srcproc];

	if(!(*r=map_lookup(*vmp, region->param.shared.vaddr, NULL))) {
		printf("VM: shared memory with missing vaddr 0x%lx.\n",
			region->param.shared.vaddr);
                return EINVAL;
	}

	if((*r)->def_memtype != &mem_type_anon) {
		printf("source region hasn't anon type but %s.\n",
			(*r)->def_memtype->name);
		return EINVAL;
	}

	if(region->param.shared.id != (*r)->id) {
		printf("source region has no matching id\n");
		return EINVAL;
	}

	return OK;
}

static u32_t shared_regionid(struct vir_region *vr)
{
	struct vir_region *src_region;
	struct vmproc *src_vmp;

	if(getsrc(vr, &src_vmp, &src_region) != OK)
		return 0;

	return src_region->id;
}

static void shared_delete(struct vir_region *region)
{
	struct vir_region *src_region;
	struct vmproc *src_vmp;

	if(getsrc(region, &src_vmp, &src_region) != OK)
		return;

	assert(src_region->remaps > 0);
	src_region->remaps--;
}

static int shared_pagefault(struct vmproc *vmp, struct vir_region *region,
	struct phys_region *ph, int write, vfs_callback_t cb,
	void *state, int statelen, int *io)
{
	struct vir_region *src_region;
	struct vmproc *src_vmp;
	struct phys_region *pr;

	if(getsrc(region, &src_vmp, &src_region) != OK) {
		return EINVAL;
	}

	if(ph->ph->phys != MAP_NONE) {
		/* memory is there - pagefault does not need handling */
		return OK;
	}

	pb_free(ph->ph);

	if(!(pr = physblock_get(src_region, ph->offset))) {
		int r;
		if((r=map_pf(src_vmp, src_region, ph->offset, write,
			NULL, NULL, 0, io)) != OK)
			return r;
		if(!(pr = physblock_get(src_region, ph->offset))) {
			panic("missing region after pagefault handling");
		}
	}

	pb_link(ph, pr->ph, ph->offset, region);

	return OK;
}

static int shared_sanitycheck(struct phys_region *pr, const char *file, int line)
{
	return OK;
}

static int shared_writable(struct phys_region *pr)
{
	assert(pr->ph->refcount > 0);
	return pr->ph->phys != MAP_NONE;
}

void shared_setsource(struct vir_region *vr, endpoint_t ep,
	struct vir_region *src_vr)
{
	struct vmproc *vmp;
	struct vir_region *srcvr;
	int id = src_vr->id;
	vir_bytes vaddr = src_vr->vaddr;

	assert(vr->def_memtype == &mem_type_shared);

	if(!ep || !vaddr || !id) {
		printf("VM: shared_setsource: zero ep/vaddr/id - ignoring\n");
		return;
	}

	vr->param.shared.ep = ep;
	vr->param.shared.vaddr = vaddr;
	vr->param.shared.id = id;

	if(getsrc(vr, &vmp, &srcvr) != OK)
		panic("initial getsrc failed");

	assert(srcvr == src_vr);

	srcvr->remaps++;
}

static int shared_copy(struct vir_region *vr, struct vir_region *newvr)
{
	struct vmproc *vmp;
	struct vir_region *srcvr;

	if(getsrc(vr, &vmp, &srcvr) != OK)
		panic("copy: original getsrc failed");

	shared_setsource(newvr, vr->param.shared.ep, srcvr);

	return OK;
}

static int shared_refcount(struct vir_region *vr)
{
	return 1 + vr->remaps;
}