xref: /minix/minix/lib/libsys/sef_st.c (revision 9f988b79)
1 #include "syslib.h"
2 #include <assert.h>
3 #include <string.h>
4 #include <machine/archtypes.h>
5 #include <minix/timers.h>
6 #include <minix/sysutil.h>
7 #include <minix/vm.h>
8 
9 #include "kernel/config.h"
10 #include "kernel/const.h"
11 #include "kernel/type.h"
12 #include "kernel/proc.h"
13 
14 EXTERN endpoint_t sef_self_endpoint;
15 
16 /* SEF Live update prototypes for sef_receive(). */
17 void do_sef_st_before_receive(void);
18 
19 /*===========================================================================*
20  *      	            do_sef_st_before_receive                         *
21  *===========================================================================*/
22 void do_sef_st_before_receive(void)
23 {
24 }
25 
26 /*===========================================================================*
27  *      	            sef_copy_state_region_ctl                        *
28  *===========================================================================*/
29 int sef_copy_state_region_ctl(sef_init_info_t *info, vir_bytes *src_address, vir_bytes *dst_address) {
30     if(info->copy_flags & SEF_COPY_DEST_OFFSET) {
31         *dst_address += sef_llvm_get_ltckpt_offset();
32     }
33     if(info->copy_flags & SEF_COPY_SRC_OFFSET) {
34         *src_address += sef_llvm_get_ltckpt_offset();
35     }
36 #if STATE_TRANS_DEBUG
37     printf("sef_copy_state_region_ctl. copy_flags:\nSEF_COPY_DEST_OFFSET\t%d\nSEF_COPY_SRC_OFFSET\t%d\nSEF_COPY_NEW_TO_NEW\t%d\nSEF_COPY_OLD_TO_NEW\t%d\n", info->copy_flags & SEF_COPY_DEST_OFFSET ? 1 : 0,
38             info->copy_flags & SEF_COPY_SRC_OFFSET ? 1 : 0, info->copy_flags & SEF_COPY_NEW_TO_NEW ? 1 : 0, info->copy_flags & SEF_COPY_OLD_TO_NEW ? 1 : 0);
39 #endif
40     if(info->copy_flags & SEF_COPY_NEW_TO_NEW)
41         return 1;
42     return 0;
43 }
44 
45 /*===========================================================================*
46  *      	             sef_copy_state_region                           *
47  *===========================================================================*/
48 int sef_copy_state_region(sef_init_info_t *info,
49     vir_bytes address, size_t size, vir_bytes dst_address, int may_have_holes)
50 {
51   vir_bytes base, top, target;
52   struct vm_region_info vri;
53   int r;
54 
55   base = address;
56 
57   if(sef_copy_state_region_ctl(info, &address, &dst_address)) {
58 #if STATE_TRANS_DEBUG
59       printf("sef_copy_state_region: memcpy %d bytes, addr = 0x%08x -> 0x%08x...\n",
60               size, address, dst_address);
61 #endif
62       /* memcpy region from current state */
63       memcpy((void*) dst_address, (void *)address, size);
64   } else if (may_have_holes && sef_self_endpoint != VM_PROC_NR &&
65     vm_info_region(info->old_endpoint, &vri, 1, &base) == 1) {
66       /* Perform a safe copy of a region of the old state.  The section may
67        * contain holes, so ask VM for the actual regions within the data
68        * section and transfer each one separately.  The alternative, just
69        * copying until a page fault happens, is not possible in the multi-
70        * component-with-VM live update case, where VM may not receive page
71        * faults during the live update window.  For now, we use the region
72        * iteration approach for the data section only; other cases have not
73        * been tested, but may work as well.
74        */
75 #if STATE_TRANS_DEBUG
76       printf("sef_copy_state_region: copying %d bytes, addr = 0x%08x -> "
77         "0x%08x, gid = %d, source = %d, with holes...\n", size, address,
78         dst_address, SEF_STATE_TRANSFER_GID, info->old_endpoint);
79 #endif
80 
81       /* The following is somewhat of a hack: the start of the data section
82        * may in fact not be page-aligned and may be part of the last page of
83        * of the preceding (text) section.  Therefore, if the first region we
84        * find starts above the known base address, blindly copy the area in
85        * between.
86        */
87       if (vri.vri_addr > address) {
88           if ((r = sys_safecopyfrom(info->old_endpoint, SEF_STATE_TRANSFER_GID,
89             address, dst_address, vri.vri_addr - address)) != OK) {
90 #if STATE_TRANS_DEBUG
91               printf("sef_copy_state_region: sys_safecopyfrom failed\n");
92 #endif
93               return r;
94           }
95       }
96 
97       top = address + size;
98       do {
99           assert(vri.vri_addr >= address);
100           if (vri.vri_addr >= top)
101               break;
102           if (vri.vri_length > top - vri.vri_addr)
103               vri.vri_length = top - vri.vri_addr;
104           target = dst_address + (vri.vri_addr - address);
105           if ((r = sys_safecopyfrom(info->old_endpoint,
106             SEF_STATE_TRANSFER_GID, vri.vri_addr, target,
107             vri.vri_length)) != OK) {
108 #if STATE_TRANS_DEBUG
109               printf("sef_copy_state_region: sys_safecopyfrom failed\n");
110 #endif
111               return r;
112           }
113           /* Save on a VM call if the next address is already too high. */
114           if (base >= top)
115               break;
116       } while (vm_info_region(info->old_endpoint, &vri, 1, &base) == 1);
117   } else {
118       /* Perform a safe copy of a region of the old state, without taking into
119        * account any holes.  This is the default for anything but the data
120        * section, with a few additioanl exceptions:  VM can't query VM, so
121        * simply assume there are no holes;  also, if we fail to get one region
122        * for the old process (and this is presumably possible if its heap is
123        * so small it fits in the last text page, see above), we also just
124        * blindly copy over the entire data section.
125        */
126 #if STATE_TRANS_DEBUG
127       printf("sef_copy_state_region: copying %d bytes, addr = 0x%08x -> "
128         "0x%08x, gid = %d, source = %d, without holes...\n", size, address,
129         dst_address, SEF_STATE_TRANSFER_GID, info->old_endpoint);
130 #endif
131       if ((r = sys_safecopyfrom(info->old_endpoint, SEF_STATE_TRANSFER_GID,
132         address, dst_address, size)) != OK) {
133 #if STATE_TRANS_DEBUG
134           printf("sef_copy_state_region: sys_safecopyfrom failed\n");
135 #endif
136           return r;
137       }
138   }
139 
140   return OK;
141 }
142 
143 /*===========================================================================*
144  *                          sef_old_state_table_lookup                       *
145  *===========================================================================*/
146  int sef_old_state_table_lookup(sef_init_info_t *info, void *addr)
147 {
148   struct priv old_priv;
149   int r;
150 
151   if ((r = sys_getpriv(&old_priv, info->old_endpoint)) != OK) {
152       printf("ERROR. sys_getpriv() failed.\n");
153       return r;
154   }
155 
156   if (sef_copy_state_region(info, old_priv.s_state_table
157     , sef_llvm_state_table_size(), (vir_bytes) addr, FALSE /*may_have_holes*/))
158   {
159       printf("ERROR. state table transfer failed\n");
160       return EGENERIC;
161   }
162 
163   return OK;
164 }
165 
166 /*===========================================================================*
167  *                       sef_old_state_table_lookup_opaque                   *
168  *===========================================================================*/
169 int sef_old_state_table_lookup_opaque(void *info_opaque, void *addr)
170 {
171   assert(info_opaque != NULL && "Invalid info_opaque pointer.");
172   return sef_old_state_table_lookup((sef_init_info_t *)(info_opaque), addr);
173 }
174 
175 /*===========================================================================*
176  *                         sef_copy_state_region_opaque                      *
177  *===========================================================================*/
178 int sef_copy_state_region_opaque(void *info_opaque, uint32_t address,
179 	size_t size, uint32_t dst_address)
180 {
181   assert(info_opaque != NULL && "Invalid info_opaque pointer.");
182   return sef_copy_state_region((sef_init_info_t *)(info_opaque),
183       (vir_bytes) address, size, (vir_bytes) dst_address,
184       FALSE /*may_have_holes*/);
185 }
186 
187 /*===========================================================================*
188  *                            sef_st_state_transfer                          *
189  *===========================================================================*/
190 int sef_st_state_transfer(sef_init_info_t *info)
191 {
192     return sef_llvm_state_transfer(info);
193 }
194 
195