Skip to content

Commit 5bff2a1

Browse files
authored
Merge pull request #419 from ldierksheide/mpk_fwp
Initial Checkpoint
2 parents f9ed59f + df36639 commit 5bff2a1

9 files changed

Lines changed: 407 additions & 26 deletions

File tree

composition_scripts/chkpt.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[system]
2+
description = "Create and execute a checkpoint for the test_component"
3+
4+
[[components]]
5+
name = "booter"
6+
img = "no_interface.llbooter"
7+
implements = [{interface = "init"}]
8+
deps = [{srv = "kernel", interface = "init", variant = "kernel"}]
9+
constructor = "kernel"
10+
11+
[[components]]
12+
name = "test_component"
13+
img = "tests.chkpt"
14+
deps = [{srv = "booter", interface = "init"}]
15+
baseaddr = "0x1600000"
16+
constructor = "booter"

src/components/implementation/no_interface/llbooter/doc.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Creates a set of components as provided by the `composer`.
88
Takes a tarball of these components (accessed through `initargs`), and an `initargs` specification of those components to be booted.
99
This will FIFO schedule initialization through the components that depend on it for `init`.
1010

11+
First draft of checkpointing, such that a component can create a checkpoint of itself once initialized (in `init_done`). Then a new component can be created and executed from the checkpoint.
12+
1113
### Usage and Assumptions
1214

1315
- Strongly assumes that the `composer` is used to provide all necessary metadata to construct the rest of the system.

src/components/implementation/no_interface/llbooter/llbooter.c

Lines changed: 141 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,24 @@
3333
#ifndef BOOTER_CAPMGR_MB
3434
#define BOOTER_CAPMGR_MB 64
3535
#endif
36+
#ifndef BOOTER_MAX_CHKPT
37+
#define BOOTER_MAX_CHKPT 64
38+
#endif
39+
40+
/* UNCOMMENT HERE FOR CHECKPOINT FUNCTIONALITY */
41+
/* #ifndef ENABLE_CHKPT
42+
* #define ENABLE_CHKPT 1
43+
* #endif
44+
*/
3645

3746
static struct crt_comp boot_comps[MAX_NUM_COMPS];
3847
static const compid_t sched_root_id = 2;
3948
static long boot_id_offset = -1;
4049

41-
SS_STATIC_SLAB(sinv, struct crt_sinv, BOOTER_MAX_SINV);
42-
SS_STATIC_SLAB(thd, struct crt_thd, BOOTER_MAX_INITTHD);
43-
SS_STATIC_SLAB(rcv, struct crt_rcv, BOOTER_MAX_SCHED);
50+
SS_STATIC_SLAB(sinv, struct crt_sinv, BOOTER_MAX_SINV);
51+
SS_STATIC_SLAB(thd, struct crt_thd, BOOTER_MAX_INITTHD);
52+
SS_STATIC_SLAB(rcv, struct crt_rcv, BOOTER_MAX_SCHED);
53+
SS_STATIC_SLAB(chkpt, struct crt_chkpt, BOOTER_MAX_CHKPT);
4454

4555
/*
4656
* Assumptions: the component with the lowest id *must* be the one
@@ -136,7 +146,7 @@ comps_init(void)
136146
if (crt_comp_create(comp, name, id, elf_hdr, info)) {
137147
printc("Error constructing the resource tables and image of component %s.\n", comp->name);
138148
BUG();
139-
}
149+
}
140150
}
141151
assert(comp->refcnt != 0);
142152
}
@@ -261,6 +271,8 @@ comps_init(void)
261271
struct crt_sinv *sinv;
262272
int serv_id = atoi(args_get_from("server", &curr));
263273
int cli_id = atoi(args_get_from("client", &curr));
274+
struct crt_comp *serv = boot_comp_get(serv_id);
275+
struct crt_comp *cli = boot_comp_get(cli_id);
264276

265277
sinv = ss_sinv_alloc();
266278
assert(sinv);
@@ -270,8 +282,16 @@ comps_init(void)
270282
ss_sinv_activate(sinv);
271283
printc("\t%s (%lu->%lu):\tclient_fn @ 0x%lx, client_ucap @ 0x%lx, server_fn @ 0x%lx\n",
272284
sinv->name, sinv->client->id, sinv->server->id, sinv->c_fn_addr, sinv->c_ucap_addr, sinv->s_fn_addr);
285+
#ifdef ENABLE_CHKPT
286+
assert(serv->n_sinvs < CRT_COMP_SINVS_LEN);
287+
serv->sinvs[serv->n_sinvs] = *sinv;
288+
serv->n_sinvs++;
289+
assert(cli->n_sinvs < CRT_COMP_SINVS_LEN);
290+
cli->sinvs[cli->n_sinvs] = *sinv;
291+
cli->n_sinvs++;
292+
#endif /* ENABLE_CHKPT */
273293
}
274-
294+
275295
/*
276296
* Delegate the untyped memory to the capmgr. This should go
277297
* *after* all allocations that use untyped memory, so that we
@@ -299,6 +319,70 @@ comps_init(void)
299319
return;
300320
}
301321

322+
/*
323+
* We only support a single checkpoint directly above the existing components.
324+
* At this point we assume capability managers and schedulers will not be checkpointed
325+
*/
326+
void
327+
chkpt_comp_init(struct crt_comp *comp, struct crt_chkpt *chkpt, char *name)
328+
{
329+
#ifdef ENABLE_CHKPT
330+
/* create the component */
331+
void *elf_hdr;
332+
int keylen;
333+
compid_t id;
334+
const char *root = "binaries/";
335+
int len = strlen(root);
336+
char path[INITARGS_MAX_PATHNAME];
337+
struct crt_comp_exec_context ctxt = { 0 };
338+
struct crt_thd *t;
339+
340+
id = crt_ncomp() + 1;
341+
assert(id < MAX_NUM_COMPS && id > 0 && name);
342+
343+
assert(len < INITARGS_MAX_PATHNAME);
344+
memset(path, 0, INITARGS_MAX_PATHNAME);
345+
strncat(path, root, len);
346+
assert(path[len] == '\0');
347+
strncat(path, name, INITARGS_MAX_PATHNAME - len);
348+
assert(path[INITARGS_MAX_PATHNAME - 1] == '\0'); /* no truncation allowed */
349+
350+
if (id == cos_compid()) {
351+
/* this should never happen */
352+
assert(0);
353+
} else {
354+
if (crt_comp_create_from(comp, name, id, chkpt)) {
355+
printc("Error constructing the resource tables and image of component %s.\n", comp->name);
356+
BUG();
357+
}
358+
}
359+
assert(comp->refcnt != 0);
360+
361+
t = ss_thd_alloc();
362+
assert(t);
363+
364+
if (crt_comp_exec(comp, crt_comp_exec_thd_init(&ctxt, t))) BUG();
365+
ss_thd_activate(t);
366+
comp->init_state = CRT_COMP_INIT_COS_INIT;
367+
368+
/* create the sinvs */
369+
for (u32_t i = 0 ; i < comp->n_sinvs ; i++) {
370+
struct crt_sinv *sinv;
371+
int serv_id = comp->sinvs[i].server->id;
372+
int cli_id = comp->sinvs[i].client->id;
373+
374+
sinv = ss_sinv_alloc();
375+
assert(sinv);
376+
crt_sinv_create(sinv, comp->sinvs[i].name, comp->sinvs[i].server, comp->sinvs[i].client,
377+
comp->sinvs[i].c_fn_addr, comp->sinvs[i].c_ucap_addr, comp->sinvs[i].s_fn_addr);
378+
ss_sinv_activate(sinv);
379+
printc("\t(chkpt) sinv: %s (%lu->%lu):\tclient_fn @ 0x%lx, client_ucap @ 0x%lx, server_fn @ 0x%lx\n",
380+
sinv->name, sinv->client->id, sinv->server->id, sinv->c_fn_addr, sinv->c_ucap_addr, sinv->s_fn_addr);
381+
}
382+
#endif /* ENABLE_CHKPT */
383+
384+
}
385+
302386
unsigned long
303387
addr_get(compid_t id, addr_t type)
304388
{
@@ -344,18 +428,67 @@ execute(void)
344428
crt_compinit_execute(boot_comp_get);
345429
}
346430

431+
void
432+
init_done_chkpt(struct crt_comp *c)
433+
{
434+
struct crt_comp *new_comp = boot_comp_get(crt_ncomp() + 1);
435+
struct crt_chkpt *chkpt;
436+
thdcap_t thdcap;
437+
int ret;
438+
char name[INITARGS_MAX_PATHNAME];
439+
char *prefix = "chkpt_";
440+
int prefix_sz = strlen("chkpt_");
441+
442+
if (c->id == cos_compid()) {
443+
/* don't allow chkpnts of the booter */
444+
BUG();
445+
}
446+
447+
assert(INITARGS_MAX_PATHNAME > prefix_sz + strlen(c->name));
448+
memcpy(name, prefix, prefix_sz + 1);
449+
strncat(name, c->name, INITARGS_MAX_PATHNAME - prefix_sz - 1);
450+
c->name[INITARGS_MAX_PATHNAME - 1] = '\0';
451+
452+
/* completed all initialization */
453+
if (c->init_state >= CRT_COMP_INIT_MAIN) {
454+
if (crt_nchkpt() > BOOTER_MAX_CHKPT) {
455+
BUG();
456+
}
457+
458+
chkpt = ss_chkpt_alloc();
459+
if (crt_chkpt_create(chkpt, c) != 0) {
460+
BUG();
461+
}
462+
463+
ss_chkpt_activate(chkpt);
464+
chkpt_comp_init(new_comp, chkpt, name);
465+
thdcap = crt_comp_thdcap_get(new_comp);
466+
assert(thdcap);
467+
if ((ret = cos_defswitch(thdcap, TCAP_PRIO_MAX, TCAP_RES_INF, cos_sched_sync()))) {
468+
printc("Switch failure on thdcap %ld, with ret %d\n", thdcap, ret);
469+
BUG();
470+
}
471+
}
472+
473+
return;
474+
}
475+
347476
void
348477
init_done(int parallel_init, init_main_t main_type)
349478
{
350479
compid_t client = (compid_t)cos_inv_token();
351-
struct crt_comp *c;
480+
struct crt_comp *c;
352481

353482
assert(client > 0 && client <= MAX_NUM_COMPS);
354483
c = boot_comp_get(client);
355484

356485
crt_compinit_done(c, parallel_init, main_type);
357486

487+
#ifdef ENABLE_CHKPT
488+
init_done_chkpt(c);
489+
#endif /* ENABLE_CHKPT */
358490
return;
491+
359492
}
360493

361494

@@ -371,6 +504,8 @@ init_exit(int retval)
371504

372505
crt_compinit_exit(c, retval);
373506

507+
/* TODO: recycle back to a chkpt via chkpt_restore() */
508+
374509
while (1) ;
375510
}
376511

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Required variables used to drive the compilation process. It is OK
2+
# for many of these to be empty.
3+
#
4+
# The set of interfaces that this component exports for use by other
5+
# components. This is a list of the interface names.
6+
INTERFACE_EXPORTS =
7+
# The interfaces this component is dependent on for compilation (this
8+
# is a list of directory names in interface/)
9+
INTERFACE_DEPENDENCIES =
10+
# The library dependencies this component is reliant on for
11+
# compilation/linking (this is a list of directory names in lib/)
12+
LIBRARY_DEPENDENCIES = component
13+
# Note: Both the interface and library dependencies should be
14+
# *minimal*. That is to say that removing a dependency should cause
15+
# the build to fail. The build system does not validate this
16+
# minimality; that's on you!
17+
18+
include Makefile.subsubdir
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <cos_component.h>
2+
#include <llprint.h>
3+
#include <cos_types.h>
4+
5+
/*
6+
* USE THE chkpt.toml RUNSCRIPT FOR THIS TEST TO PASS
7+
* UNCOMMENT THE #DEFINE ENABLE_CHKPT IN llbooter.c FOR THIS TEST TO PASS
8+
* Component IDs are hardcoded:
9+
* we must be creating a checkpoint of component with ID 2
10+
* and the component created from the checkpoint must have ID 3
11+
*/
12+
static compid_t test_compid = 2;
13+
static compid_t chkpt_compid = 3;
14+
15+
static u32_t test_var = 2;
16+
17+
void
18+
cos_init(void)
19+
{
20+
assert(cos_compid() == test_compid);
21+
assert(test_var == 2);
22+
test_var = 5;
23+
}
24+
25+
void
26+
cos_parallel_init(coreid_t cid, int init_core, int ncores)
27+
{
28+
if (init_core) {
29+
assert(cos_compid() == test_compid);
30+
}
31+
}
32+
33+
void
34+
parallel_main(coreid_t cid)
35+
{
36+
assert(cos_compid() == chkpt_compid);
37+
assert(test_var == 5);
38+
39+
printc("Success: Checkpoint created and executed\n");
40+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Chkpt
2+
3+
### Description
4+
This component is a unit test for the baseline checkpoint functionality. This includes creating a checkpoint from a non-booter component (defined in `chkpt.c` in this case), creating a component from that checkpoint, and running it. The checkpoint copies the memory (we do not yet support the copying for dynamic allocations) and synchronous invocations from the initial component and allows the new component to skip initialization steps.
5+
6+
### Usage and Assumptions
7+
- Assumes that the `chkpt.toml` runscript is used
8+
- You must uncomment the `#define ENABLE_CHKPT` in `src/components/implementation/no_interface/llbooter/llbooter.c` for this test to work; checkpoint functionality is disabled by default in the system
9+

src/components/lib/component/cos_component.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ start_execution(coreid_t cid, int init_core, int ncores)
202202
const int parallel_init = cos_parallel_init != __crt_cos_parallel_init;
203203
int ret = 0;
204204
int main_time = 0;
205+
static volatile int initialization_completed = 0;
205206

206207
/* are parallel/regular main user-defined? */
207208
if (parallel_main != __crt_parallel_main) {
@@ -212,20 +213,23 @@ start_execution(coreid_t cid, int init_core, int ncores)
212213
}
213214

214215
/* single-core initialization */
215-
if (init_core) {
216-
cos_init();
217-
/* continue only if there is no user-defined main, or parallel exec */
218-
COS_EXTERN_INV(init_done)(parallel_init, main_type);
219-
assert(parallel_init || main_type != INIT_MAIN_NONE);
220-
}
216+
if (initialization_completed == 0) {
217+
if (init_core) {
218+
cos_init();
219+
/* continue only if there is no user-defined main, or parallel exec */
220+
COS_EXTERN_INV(init_done)(parallel_init, main_type);
221+
assert(parallel_init || main_type != INIT_MAIN_NONE);
222+
}
221223

222-
/* Parallel initialization */
223-
COS_EXTERN_INV(init_parallel_await_init)();
224-
if (parallel_init) {
225-
cos_parallel_init(cid, init_core, init_parallelism());
224+
/* Parallel initialization */
225+
COS_EXTERN_INV(init_parallel_await_init)();
226+
if (parallel_init) {
227+
cos_parallel_init(cid, init_core, init_parallelism());
228+
}
229+
/* All initialization completed here, go onto main execution */
230+
initialization_completed = 1;
231+
COS_EXTERN_INV(init_done)(0, main_type);
226232
}
227-
/* All initialization completed here, go onto main execution */
228-
COS_EXTERN_INV(init_done)(0, main_type);
229233
/* No main? we shouldn't have continued here... */
230234
assert(main_type != INIT_MAIN_NONE);
231235
assert(main_type == INIT_MAIN_PARALLEL || (main_type == INIT_MAIN_SINGLE && init_core));
@@ -299,6 +303,7 @@ cos_upcall_fn(upcall_type_t t, void *arg1, void *arg2, void *arg3)
299303
static unsigned long first_core = 1;
300304

301305
start_execution(cos_coreid(), ps_cas(&first_core, 1, 0), init_parallelism());
306+
302307
} else {
303308
u32_t idx = (int)arg1 - 1;
304309
if (idx >= COS_THD_INIT_REGION_SIZE) {

0 commit comments

Comments
 (0)