xref: /minix3/minix/servers/vm/pb.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc 
2*433d6423SLionel Sambuc #define	_SYSTEM 1
3*433d6423SLionel Sambuc 
4*433d6423SLionel Sambuc #include <minix/com.h>
5*433d6423SLionel Sambuc #include <minix/callnr.h>
6*433d6423SLionel Sambuc #include <minix/type.h>
7*433d6423SLionel Sambuc #include <minix/config.h>
8*433d6423SLionel Sambuc #include <minix/const.h>
9*433d6423SLionel Sambuc #include <minix/sysutil.h>
10*433d6423SLionel Sambuc #include <minix/syslib.h>
11*433d6423SLionel Sambuc #include <minix/debug.h>
12*433d6423SLionel Sambuc #include <minix/bitmap.h>
13*433d6423SLionel Sambuc #include <minix/hash.h>
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc #include <sys/mman.h>
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc #include <limits.h>
18*433d6423SLionel Sambuc #include <string.h>
19*433d6423SLionel Sambuc #include <errno.h>
20*433d6423SLionel Sambuc #include <assert.h>
21*433d6423SLionel Sambuc #include <stdint.h>
22*433d6423SLionel Sambuc #include <sys/param.h>
23*433d6423SLionel Sambuc 
24*433d6423SLionel Sambuc #include "vm.h"
25*433d6423SLionel Sambuc #include "proto.h"
26*433d6423SLionel Sambuc #include "util.h"
27*433d6423SLionel Sambuc #include "glo.h"
28*433d6423SLionel Sambuc #include "region.h"
29*433d6423SLionel Sambuc #include "sanitycheck.h"
30*433d6423SLionel Sambuc #include "memlist.h"
31*433d6423SLionel Sambuc 
pb_new(phys_bytes phys)32*433d6423SLionel Sambuc struct	phys_block *pb_new(phys_bytes phys)
33*433d6423SLionel Sambuc {
34*433d6423SLionel Sambuc 	struct phys_block *newpb;
35*433d6423SLionel Sambuc 
36*433d6423SLionel Sambuc 	if(!SLABALLOC(newpb)) {
37*433d6423SLionel Sambuc 		printf("vm: pb_new: couldn't allocate phys block\n");
38*433d6423SLionel Sambuc 		return NULL;
39*433d6423SLionel Sambuc 	}
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc 	if(phys != MAP_NONE)
42*433d6423SLionel Sambuc 		assert(!(phys % VM_PAGE_SIZE));
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc USE(newpb,
45*433d6423SLionel Sambuc 	newpb->phys = phys;
46*433d6423SLionel Sambuc 	newpb->refcount = 0;
47*433d6423SLionel Sambuc 	newpb->firstregion = NULL;
48*433d6423SLionel Sambuc 	newpb->flags = 0;
49*433d6423SLionel Sambuc 	);
50*433d6423SLionel Sambuc 
51*433d6423SLionel Sambuc 	return newpb;
52*433d6423SLionel Sambuc }
53*433d6423SLionel Sambuc 
pb_free(struct phys_block * pb)54*433d6423SLionel Sambuc void pb_free(struct phys_block *pb)
55*433d6423SLionel Sambuc {
56*433d6423SLionel Sambuc 	if(pb->phys != MAP_NONE)
57*433d6423SLionel Sambuc 		free_mem(ABS2CLICK(pb->phys), 1);
58*433d6423SLionel Sambuc 	SLABFREE(pb);
59*433d6423SLionel Sambuc }
60*433d6423SLionel Sambuc 
pb_link(struct phys_region * newphysr,struct phys_block * newpb,vir_bytes offset,struct vir_region * parent)61*433d6423SLionel Sambuc void pb_link(struct phys_region *newphysr, struct phys_block *newpb,
62*433d6423SLionel Sambuc 	vir_bytes offset, struct vir_region *parent)
63*433d6423SLionel Sambuc {
64*433d6423SLionel Sambuc USE(newphysr,
65*433d6423SLionel Sambuc 	newphysr->offset = offset;
66*433d6423SLionel Sambuc 	newphysr->ph = newpb;
67*433d6423SLionel Sambuc 	newphysr->parent = parent;
68*433d6423SLionel Sambuc 	newphysr->next_ph_list = newpb->firstregion;
69*433d6423SLionel Sambuc 	newpb->firstregion = newphysr;);
70*433d6423SLionel Sambuc 	newpb->refcount++;
71*433d6423SLionel Sambuc }
72*433d6423SLionel Sambuc 
pb_reference(struct phys_block * newpb,vir_bytes offset,struct vir_region * region,mem_type_t * memtype)73*433d6423SLionel Sambuc struct	phys_region *pb_reference(struct phys_block *newpb,
74*433d6423SLionel Sambuc 	vir_bytes offset, struct vir_region *region, mem_type_t *memtype)
75*433d6423SLionel Sambuc {
76*433d6423SLionel Sambuc 	struct phys_region *newphysr;
77*433d6423SLionel Sambuc 
78*433d6423SLionel Sambuc 	if(!SLABALLOC(newphysr)) {
79*433d6423SLionel Sambuc 	printf("vm: pb_reference: couldn't allocate phys region\n");
80*433d6423SLionel Sambuc 	return NULL;
81*433d6423SLionel Sambuc 	}
82*433d6423SLionel Sambuc 
83*433d6423SLionel Sambuc 	newphysr->memtype = memtype;
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc 	/* New physical region. */
86*433d6423SLionel Sambuc 	pb_link(newphysr, newpb, offset, region);
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	physblock_set(region, offset, newphysr);
89*433d6423SLionel Sambuc 
90*433d6423SLionel Sambuc 	return newphysr;
91*433d6423SLionel Sambuc }
92*433d6423SLionel Sambuc 
93*433d6423SLionel Sambuc /*===========================================================================*
94*433d6423SLionel Sambuc  *				pb_unreferenced				     *
95*433d6423SLionel Sambuc  *===========================================================================*/
pb_unreferenced(struct vir_region * region,struct phys_region * pr,int rm)96*433d6423SLionel Sambuc void pb_unreferenced(struct vir_region *region, struct phys_region *pr, int rm)
97*433d6423SLionel Sambuc {
98*433d6423SLionel Sambuc 	struct phys_block *pb;
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 	pb = pr->ph;
101*433d6423SLionel Sambuc 	assert(pb->refcount > 0);
102*433d6423SLionel Sambuc 	USE(pb, pb->refcount--;);
103*433d6423SLionel Sambuc /*	assert(pb->refcount >= 0); */ /* always true */
104*433d6423SLionel Sambuc 
105*433d6423SLionel Sambuc 	if(pb->firstregion == pr) {
106*433d6423SLionel Sambuc 		USE(pb, pb->firstregion = pr->next_ph_list;);
107*433d6423SLionel Sambuc 	} else {
108*433d6423SLionel Sambuc 		struct phys_region *others;
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 		for(others = pb->firstregion; others;
111*433d6423SLionel Sambuc 			others = others->next_ph_list) {
112*433d6423SLionel Sambuc 			assert(others->ph == pb);
113*433d6423SLionel Sambuc 			if(others->next_ph_list == pr) {
114*433d6423SLionel Sambuc 				USE(others, others->next_ph_list = pr->next_ph_list;);
115*433d6423SLionel Sambuc 				break;
116*433d6423SLionel Sambuc 			}
117*433d6423SLionel Sambuc 		}
118*433d6423SLionel Sambuc 
119*433d6423SLionel Sambuc 		assert(others); /* Otherwise, wasn't on the list. */
120*433d6423SLionel Sambuc 	}
121*433d6423SLionel Sambuc 
122*433d6423SLionel Sambuc 	if(pb->refcount == 0) {
123*433d6423SLionel Sambuc 		assert(!pb->firstregion);
124*433d6423SLionel Sambuc 		int r;
125*433d6423SLionel Sambuc 		if((r = pr->memtype->ev_unreference(pr)) != OK)
126*433d6423SLionel Sambuc 			panic("unref failed, %d", r);
127*433d6423SLionel Sambuc 
128*433d6423SLionel Sambuc 		SLABFREE(pb);
129*433d6423SLionel Sambuc 	}
130*433d6423SLionel Sambuc 
131*433d6423SLionel Sambuc 	pr->ph = NULL;
132*433d6423SLionel Sambuc 
133*433d6423SLionel Sambuc 	if(rm) physblock_set(region, pr->offset, NULL);
134*433d6423SLionel Sambuc }
135*433d6423SLionel Sambuc 
mem_cow(struct vir_region * region,struct phys_region * ph,phys_bytes new_page_cl,phys_bytes new_page)136*433d6423SLionel Sambuc int mem_cow(struct vir_region *region,
137*433d6423SLionel Sambuc         struct phys_region *ph, phys_bytes new_page_cl, phys_bytes new_page)
138*433d6423SLionel Sambuc {
139*433d6423SLionel Sambuc         struct phys_block *pb;
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc         if(new_page == MAP_NONE) {
142*433d6423SLionel Sambuc                 u32_t allocflags;
143*433d6423SLionel Sambuc                 allocflags = vrallocflags(region->flags);
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc                 if((new_page_cl = alloc_mem(1, allocflags)) == NO_MEM)
146*433d6423SLionel Sambuc                         return ENOMEM;
147*433d6423SLionel Sambuc 
148*433d6423SLionel Sambuc                 new_page = CLICK2ABS(new_page_cl);
149*433d6423SLionel Sambuc         }
150*433d6423SLionel Sambuc 
151*433d6423SLionel Sambuc 	assert(ph->ph->phys != MAP_NONE);
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc         if(sys_abscopy(ph->ph->phys, new_page, VM_PAGE_SIZE) != OK) {
154*433d6423SLionel Sambuc                 panic("VM: abscopy failed\n");
155*433d6423SLionel Sambuc                 return EFAULT;
156*433d6423SLionel Sambuc         }
157*433d6423SLionel Sambuc 
158*433d6423SLionel Sambuc         if(!(pb = pb_new(new_page))) {
159*433d6423SLionel Sambuc                 free_mem(new_page_cl, 1);
160*433d6423SLionel Sambuc                 return ENOMEM;
161*433d6423SLionel Sambuc         }
162*433d6423SLionel Sambuc 
163*433d6423SLionel Sambuc         pb_unreferenced(region, ph, 0);
164*433d6423SLionel Sambuc         pb_link(ph, pb, ph->offset, region);
165*433d6423SLionel Sambuc 	ph->memtype = &mem_type_anon;
166*433d6423SLionel Sambuc 
167*433d6423SLionel Sambuc         return OK;
168*433d6423SLionel Sambuc }
169