summaryrefslogtreecommitdiff
path: root/minix/lib/libsys/sef_st.c
blob: 4b57ef786f0530dad006b1ab0805e25b9f551833 (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
#include "syslib.h"
#include <assert.h>
#include <string.h>
#include <machine/archtypes.h>
#include <minix/timers.h>
#include <minix/sysutil.h>
#include <minix/vm.h>

#include "kernel/config.h"
#include "kernel/const.h"
#include "kernel/type.h"
#include "kernel/proc.h"

EXTERN endpoint_t sef_self_endpoint;

/* SEF Live update prototypes for sef_receive(). */
void do_sef_st_before_receive(void);

/*===========================================================================*
 *      	            do_sef_st_before_receive                         *
 *===========================================================================*/
void do_sef_st_before_receive(void)
{
}

/*===========================================================================*
 *      	            sef_copy_state_region_ctl                        *
 *===========================================================================*/
int sef_copy_state_region_ctl(sef_init_info_t *info, vir_bytes *src_address, vir_bytes *dst_address) {
    if(info->copy_flags & SEF_COPY_DEST_OFFSET) {
        *dst_address += sef_llvm_get_ltckpt_offset();
    }
    if(info->copy_flags & SEF_COPY_SRC_OFFSET) {
        *src_address += sef_llvm_get_ltckpt_offset();
    }
#if STATE_TRANS_DEBUG
    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, 
            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);
#endif
    if(info->copy_flags & SEF_COPY_NEW_TO_NEW)
        return 1;
    return 0;
}

/*===========================================================================*
 *      	             sef_copy_state_region                           *
 *===========================================================================*/
int sef_copy_state_region(sef_init_info_t *info,
    vir_bytes address, size_t size, vir_bytes dst_address, int may_have_holes)
{
  vir_bytes base, top, target;
  struct vm_region_info vri;
  int r;

  base = address;

  if(sef_copy_state_region_ctl(info, &address, &dst_address)) {
#if STATE_TRANS_DEBUG
      printf("sef_copy_state_region: memcpy %d bytes, addr = 0x%08x -> 0x%08x...\n",
              size, address, dst_address);
#endif
      /* memcpy region from current state */
      memcpy((void*) dst_address, (void *)address, size);
  } else if (may_have_holes && sef_self_endpoint != VM_PROC_NR &&
    vm_info_region(info->old_endpoint, &vri, 1, &base) == 1) {
      /* Perform a safe copy of a region of the old state.  The section may
       * contain holes, so ask VM for the actual regions within the data
       * section and transfer each one separately.  The alternative, just
       * copying until a page fault happens, is not possible in the multi-
       * component-with-VM live update case, where VM may not receive page
       * faults during the live update window.  For now, we use the region
       * iteration approach for the data section only; other cases have not
       * been tested, but may work as well.
       */
#if STATE_TRANS_DEBUG
      printf("sef_copy_state_region: copying %d bytes, addr = 0x%08x -> "
        "0x%08x, gid = %d, source = %d, with holes...\n", size, address,
        dst_address, SEF_STATE_TRANSFER_GID, info->old_endpoint);
#endif

      /* The following is somewhat of a hack: the start of the data section
       * may in fact not be page-aligned and may be part of the last page of
       * of the preceding (text) section.  Therefore, if the first region we
       * find starts above the known base address, blindly copy the area in
       * between.
       */
      if (vri.vri_addr > address) {
          if ((r = sys_safecopyfrom(info->old_endpoint, SEF_STATE_TRANSFER_GID,
            address, dst_address, vri.vri_addr - address)) != OK) {
#if STATE_TRANS_DEBUG
              printf("sef_copy_state_region: sys_safecopyfrom failed\n");
#endif
              return r;
          }
      }

      top = address + size;
      do {
          assert(vri.vri_addr >= address);
          if (vri.vri_addr >= top)
              break;
          if (vri.vri_length > top - vri.vri_addr)
              vri.vri_length = top - vri.vri_addr;
          target = dst_address + (vri.vri_addr - address);
          if ((r = sys_safecopyfrom(info->old_endpoint,
            SEF_STATE_TRANSFER_GID, vri.vri_addr, target,
            vri.vri_length)) != OK) {
#if STATE_TRANS_DEBUG
              printf("sef_copy_state_region: sys_safecopyfrom failed\n");
#endif
              return r;
          }
          /* Save on a VM call if the next address is already too high. */
          if (base >= top)
              break;
      } while (vm_info_region(info->old_endpoint, &vri, 1, &base) == 1);
  } else {
      /* Perform a safe copy of a region of the old state, without taking into
       * account any holes.  This is the default for anything but the data
       * section, with a few additioanl exceptions:  VM can't query VM, so
       * simply assume there are no holes;  also, if we fail to get one region
       * for the old process (and this is presumably possible if its heap is
       * so small it fits in the last text page, see above), we also just
       * blindly copy over the entire data section.
       */
#if STATE_TRANS_DEBUG
      printf("sef_copy_state_region: copying %d bytes, addr = 0x%08x -> "
        "0x%08x, gid = %d, source = %d, without holes...\n", size, address,
        dst_address, SEF_STATE_TRANSFER_GID, info->old_endpoint);
#endif
      if ((r = sys_safecopyfrom(info->old_endpoint, SEF_STATE_TRANSFER_GID,
        address, dst_address, size)) != OK) {
#if STATE_TRANS_DEBUG
          printf("sef_copy_state_region: sys_safecopyfrom failed\n");
#endif
          return r;
      }
  }

  return OK;
}

/*===========================================================================*
 *                          sef_old_state_table_lookup                       *
 *===========================================================================*/
 int sef_old_state_table_lookup(sef_init_info_t *info, void *addr)
{
  struct priv old_priv;
  int r;

  if ((r = sys_getpriv(&old_priv, info->old_endpoint)) != OK) {
      printf("ERROR. sys_getpriv() failed.\n");
      return r;
  }

  if (sef_copy_state_region(info, old_priv.s_state_table
    , sef_llvm_state_table_size(), (vir_bytes) addr, FALSE /*may_have_holes*/))
  {
      printf("ERROR. state table transfer failed\n");
      return EGENERIC;
  }

  return OK;
}

/*===========================================================================*
 *                       sef_old_state_table_lookup_opaque                   *
 *===========================================================================*/
int sef_old_state_table_lookup_opaque(void *info_opaque, void *addr)
{
  assert(info_opaque != NULL && "Invalid info_opaque pointer.");
  return sef_old_state_table_lookup((sef_init_info_t *)(info_opaque), addr);
}

/*===========================================================================*
 *                         sef_copy_state_region_opaque                      *
 *===========================================================================*/
int sef_copy_state_region_opaque(void *info_opaque, uint32_t address,
	size_t size, uint32_t dst_address)
{
  assert(info_opaque != NULL && "Invalid info_opaque pointer.");
  return sef_copy_state_region((sef_init_info_t *)(info_opaque),
      (vir_bytes) address, size, (vir_bytes) dst_address,
      FALSE /*may_have_holes*/);
}

/*===========================================================================*
 *                            sef_st_state_transfer                          *
 *===========================================================================*/
int sef_st_state_transfer(sef_init_info_t *info)
{
    return sef_llvm_state_transfer(info);
}