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