feat(pager): resolve write faults and recycle scrubbed frames
7 files changed, +523 −0
- Makefile added +46 −0
- client.c added +19 −0
- microkit.patch added +73 −0
- pager.c added +249 −0
- setup.sh added +17 −0
- split.h added +43 −0
- split.system added +76 −0
Makefile added
| @@ -0,0 +1,46 @@ | ||
| 1 | +SDK ?= $(HOME)/.cache/split/microkit-sdk-2.3.1 | |
| 2 | +TOOL ?= $(HOME)/.cache/split/microkit-2.3.1/target/release/microkit | |
| 3 | +BOARD := $(SDK)/board/qemu_virt_aarch64/debug | |
| 4 | +CC := aarch64-linux-gnu-gcc | |
| 5 | +LD := aarch64-linux-gnu-ld | |
| 6 | +CFLAGS := -std=gnu11 -O2 -g -Wall -Wextra -Werror -Wno-unused-function -ffreestanding -nostdlib -mstrict-align -I$(BOARD)/include | |
| 7 | +QEMU := qemu-system-aarch64 -machine virt,virtualization=on -cpu cortex-a53 -m 2G -nographic -monitor none -serial stdio | |
| 8 | + | |
| 9 | +.PHONY: all proof clean | |
| 10 | +all: build/loader.img | |
| 11 | + | |
| 12 | +build: | |
| 13 | + mkdir -p build | |
| 14 | + | |
| 15 | +build/pager.o: pager.c split.h | build | |
| 16 | + $(CC) $(CFLAGS) -c $< -o $@ | |
| 17 | + | |
| 18 | +build/alpha.o: client.c split.h | build | |
| 19 | + $(CC) $(CFLAGS) -DCLIENT=0 -c $< -o $@ | |
| 20 | + | |
| 21 | +build/beta.o: client.c split.h | build | |
| 22 | + $(CC) $(CFLAGS) -DCLIENT=1 -c $< -o $@ | |
| 23 | + | |
| 24 | +build/unsafe.o: pager.c split.h | build | |
| 25 | + $(CC) $(CFLAGS) -DSHARED_WRITE=1 -c $< -o $@ | |
| 26 | + | |
| 27 | +build/%.elf: build/%.o | |
| 28 | + $(LD) -L$(BOARD)/lib $< -lmicrokit -Tmicrokit.ld -o $@ | |
| 29 | + | |
| 30 | +build/loader.img: build/pager.elf build/alpha.elf build/beta.elf split.system | |
| 31 | + MICROKIT_SDK=$(SDK) $(TOOL) --board qemu_virt_aarch64 --config debug --search-path build -o $@ -r build/report.txt split.system | |
| 32 | + | |
| 33 | +build/unsafe.img: build/unsafe.elf build/alpha.elf build/beta.elf split.system | |
| 34 | + sed 's/pager.elf/unsafe.elf/' split.system > build/unsafe.system | |
| 35 | + MICROKIT_SDK=$(SDK) $(TOOL) --board qemu_virt_aarch64 --config debug --search-path build -o $@ -r build/unsafe.txt build/unsafe.system | |
| 36 | + | |
| 37 | +proof: | |
| 38 | + isabelle build -D . | |
| 39 | + | |
| 40 | +build/split.ml: Export.thy Reuse.thy Snapshot.thy Execution.thy Protocol.thy Isolation.thy Model.thy ROOT | build | |
| 41 | + isabelle build -D . | |
| 42 | + isabelle export -n -d . -O build/generated -x 'Split.Export:code/**' Split | |
| 43 | + cp build/generated/Split.Export/code/split.ocaml $@ | |
| 44 | + | |
| 45 | +clean: | |
| 46 | + rm -rf build | |
client.c added
| @@ -0,0 +1,19 @@ | ||
| 1 | +#include "split.h" | |
| 2 | + | |
| 3 | +void init(void) {} | |
| 4 | + | |
| 5 | +void notified(microkit_channel channel) { | |
| 6 | + require(channel == 0, "unknown notification"); | |
| 7 | + volatile struct job *job = (void *)TASK; | |
| 8 | + unsigned p = job->page, length = job->length; | |
| 9 | + require(p < PAGES && length <= LIMIT, "edit bounds"); | |
| 10 | + volatile unsigned char *page = (void *)(BASE + p * BYTES); | |
| 11 | + for (unsigned i = 0; i <= length; ++i) { | |
| 12 | + page[i] = job->text[i]; | |
| 13 | + microkit_mr_set(0, p); | |
| 14 | + microkit_mr_set(1, i); | |
| 15 | + microkit_mr_set(2, page[i]); | |
| 16 | + (void)microkit_ppcall(0, microkit_msginfo_new(1, 3)); | |
| 17 | + } | |
| 18 | + (void)microkit_ppcall(0, microkit_msginfo_new(2, 0)); | |
| 19 | +} | |
microkit.patch added
| @@ -0,0 +1,73 @@ | ||
| 1 | +--- a/tool/microkit/src/sdf/cspace.rs | |
| 2 | ++++ b/tool/microkit/src/sdf/cspace.rs | |
| 3 | +@@ -17,6 +17,7 @@ | |
| 4 | + Tcb, | |
| 5 | + Sc, | |
| 6 | + VSpace, | |
| 7 | ++ Frame, | |
| 8 | + } | |
| 9 | + | |
| 10 | + #[derive(Debug, PartialEq, Eq)] | |
| 11 | +@@ -45,9 +46,9 @@ | |
| 12 | + // At the moment the four cap maps we support all have the 'pd' element, | |
| 13 | + // so we can include it here. When that stops being the case we will | |
| 14 | + // have to rework this a bit. | |
| 15 | +- check_attributes(xml_sdf, node, &["slot", "pd"])?; | |
| 16 | +- | |
| 17 | +- let pd = Rc::from(checked_lookup(xml_sdf, node, "pd")?); | |
| 18 | ++ let source = if cap_type == CapMapType::Frame { "mr" } else { "pd" }; | |
| 19 | ++ check_attributes(xml_sdf, node, &["slot", source])?; | |
| 20 | ++ let pd = Rc::from(checked_lookup(xml_sdf, node, source)?); | |
| 21 | + | |
| 22 | + let slot: u64 = sdf_parse_required_attribute(xml_sdf, node, "slot")?; | |
| 23 | + | |
| 24 | +@@ -91,6 +92,7 @@ | |
| 25 | + "cap_tcb" => CapMap::from_xml(CapMapType::Tcb, xml_sdf, &*child)?, | |
| 26 | + "cap_sc" => CapMap::from_xml(CapMapType::Sc, xml_sdf, &*child)?, | |
| 27 | + "cap_vspace" => CapMap::from_xml(CapMapType::VSpace, xml_sdf, &*child)?, | |
| 28 | ++ "cap_frame" => CapMap::from_xml(CapMapType::Frame, xml_sdf, &*child)?, | |
| 29 | + child_name => { | |
| 30 | + let location = loc_string(xml_sdf, child.range().start); | |
| 31 | + if let Some(type_name) = child_name.strip_prefix("cap_") { | |
| 32 | +--- a/tool/microkit/src/sdf.rs | |
| 33 | ++++ b/tool/microkit/src/sdf.rs | |
| 34 | +@@ -310,7 +310,11 @@ | |
| 35 | + | |
| 36 | + for pd in pds.values() { | |
| 37 | + for cap_map in pd.cap_maps.iter() { | |
| 38 | +- if !pds.contains_key(&cap_map.pd) { | |
| 39 | ++ if cap_map.cap_type == CapMapType::Frame { | |
| 40 | ++ if !mrs.iter().any(|mr| mr.name.as_str() == cap_map.pd.as_ref()) { | |
| 41 | ++ return Err(format!("Unknown frame region {}", cap_map.pd)); | |
| 42 | ++ } | |
| 43 | ++ } else if !pds.contains_key(&cap_map.pd) { | |
| 44 | + return Err(format!( | |
| 45 | + "Error: unknown PD name '{}': {}", | |
| 46 | + cap_map.pd, | |
| 47 | +--- a/tool/microkit/src/capdl/builder.rs | |
| 48 | ++++ b/tool/microkit/src/capdl/builder.rs | |
| 49 | +@@ -1332,12 +1332,23 @@ | |
| 50 | + for cap_map in pd.cap_maps.iter() { | |
| 51 | + // TODO: Once we add more CapMap options, they might not all have | |
| 52 | + // the pd_name. But for now, they do. | |
| 53 | +- let pd_src_shadow_cspace = &pd_shadow_cspaces[&cap_map.pd]; | |
| 54 | ++ let pd_src_shadow_cspace = if cap_map.cap_type == CapMapType::Frame { | |
| 55 | ++ &pd_shadow_cspaces[&pd.name] | |
| 56 | ++ } else { | |
| 57 | ++ &pd_shadow_cspaces[&cap_map.pd] | |
| 58 | ++ }; | |
| 59 | + | |
| 60 | + let cap_map_obj = match cap_map.cap_type { | |
| 61 | + CapMapType::Tcb => capdl_util_make_tcb_cap(pd_src_shadow_cspace.tcb), | |
| 62 | + CapMapType::Sc => capdl_util_make_sc_cap(pd_src_shadow_cspace.sched_context), | |
| 63 | + CapMapType::VSpace => capdl_util_make_page_table_cap(pd_src_shadow_cspace.vspace), | |
| 64 | ++ CapMapType::Frame => { | |
| 65 | ++ let frames = &mr_name_to_frames[cap_map.pd.as_ref()]; | |
| 66 | ++ if frames.len() != 1 { | |
| 67 | ++ return Err(format!("Frame region {} must contain one page", cap_map.pd)); | |
| 68 | ++ } | |
| 69 | ++ capdl_util_make_frame_cap(frames[0], true, true, false, true) | |
| 70 | ++ }, | |
| 71 | + }; | |
| 72 | + | |
| 73 | + // Map this into the destination pd's cspace and the specified slot. | |
pager.c added
| @@ -0,0 +1,249 @@ | ||
| 1 | +#include "split.h" | |
| 2 | + | |
| 3 | +#ifndef SHARED_WRITE | |
| 4 | +#define SHARED_WRITE 0 | |
| 5 | +#endif | |
| 6 | + | |
| 7 | +static unsigned mapping[SLOTS], next = PAGES; | |
| 8 | +static unsigned available[FRAMES - PAGES], returned; | |
| 9 | +static seL4_CPtr caps[SLOTS]; | |
| 10 | +static int started, busy = -1; | |
| 11 | +static char line[384]; | |
| 12 | +static unsigned used; | |
| 13 | +static volatile uint32_t *uart = (void *)0x70000000ul; | |
| 14 | + | |
| 15 | +static unsigned char *frame(unsigned f) { | |
| 16 | + return (unsigned char *)(BACKING + f * BYTES); | |
| 17 | +} | |
| 18 | + | |
| 19 | +static void done(void) { microkit_dbg_puts("@done\n"); } | |
| 20 | + | |
| 21 | +static seL4_Word physical(seL4_CPtr cap) { | |
| 22 | + seL4_ARM_Page_GetAddress_t result = seL4_ARM_Page_GetAddress(cap); | |
| 23 | + require(result.error == seL4_NoError, "frame address query"); | |
| 24 | + return result.paddr; | |
| 25 | +} | |
| 26 | + | |
| 27 | +static int length(const char *text, unsigned *size) { | |
| 28 | + unsigned n = 0; | |
| 29 | + while (text[n]) if (++n > LIMIT) return 0; | |
| 30 | + *size = n; | |
| 31 | + return 1; | |
| 32 | +} | |
| 33 | + | |
| 34 | +static void map(unsigned k, seL4_CPtr page, int write) { | |
| 35 | + seL4_CapRights_t rights = seL4_CapRights_new(0, 0, 1, write); | |
| 36 | + require(seL4_ARM_Page_Map(page, microkit_cspace_root_slot_to_cptr(1 + k / PAGES), | |
| 37 | + BASE + (k % PAGES) * BYTES, rights, | |
| 38 | + seL4_ARM_Default_VMAttributes | seL4_ARM_ExecuteNever) == seL4_NoError, | |
| 39 | + "page map"); | |
| 40 | +} | |
| 41 | + | |
| 42 | +static void table(void) { | |
| 43 | + microkit_dbg_puts("SPLIT TABLE"); | |
| 44 | + for (unsigned k = 0; k < SLOTS; ++k) { | |
| 45 | + microkit_dbg_puts(" "); number(mapping[k]); | |
| 46 | + } | |
| 47 | + microkit_dbg_puts("\n"); | |
| 48 | +} | |
| 49 | + | |
| 50 | +void init(void) { | |
| 51 | + for (unsigned f = 0; f < FRAMES; ++f) | |
| 52 | + for (unsigned b = 0; b < BYTES; ++b) frame(f)[b] = 0; | |
| 53 | + for (unsigned k = 0; k < SLOTS; ++k) { | |
| 54 | + mapping[k] = k % PAGES; | |
| 55 | + caps[k] = microkit_cspace_root_slot_to_cptr(10 + k); | |
| 56 | + map(k, caps[k], SHARED_WRITE); | |
| 57 | + } | |
| 58 | + uart[0x30 / 4] |= 0x301; | |
| 59 | + uart[0x2c / 4] = 0x60; | |
| 60 | + uart[0x44 / 4] = 0x7ff; | |
| 61 | + uart[0x38 / 4] = 0x10; | |
| 62 | + microkit_irq_ack(5); | |
| 63 | + table(); | |
| 64 | + microkit_dbg_puts("@ready\n"); | |
| 65 | +} | |
| 66 | + | |
| 67 | +seL4_Bool fault(microkit_child child, microkit_msginfo info, microkit_msginfo *reply) { | |
| 68 | + require(child < CLIENTS && microkit_msginfo_get_label(info) == seL4_Fault_VMFault, | |
| 69 | + "unexpected fault"); | |
| 70 | + seL4_Word address = microkit_mr_get(seL4_VMFault_Addr); | |
| 71 | + seL4_Word fsr = microkit_mr_get(seL4_VMFault_FSR); | |
| 72 | + seL4_Word ip = microkit_mr_get(seL4_VMFault_IP); | |
| 73 | + require(address >= BASE && address < BASE + PAGES * BYTES && (fsr & (1ul << 6)), | |
| 74 | + "not a managed write fault"); | |
| 75 | + unsigned k = child * PAGES + (address - BASE) / BYTES; | |
| 76 | + unsigned old = mapping[k], fresh = returned ? available[--returned] : next++; | |
| 77 | + require(old < PAGES && fresh < FRAMES, "frame pool exhausted"); | |
| 78 | + seL4_Word source = physical(caps[k]); | |
| 79 | + seL4_CPtr destination = microkit_cspace_root_slot_to_cptr(30 + fresh - PAGES); | |
| 80 | + seL4_Word target = physical(destination); | |
| 81 | + for (unsigned b = 0; b < BYTES; ++b) frame(fresh)[b] = frame(old)[b]; | |
| 82 | + require(seL4_ARM_Page_Unmap(caps[k]) == seL4_NoError, "page unmap"); | |
| 83 | + caps[k] = microkit_cspace_root_slot_to_cptr(30 + fresh - PAGES); | |
| 84 | + map(k, caps[k], 1); | |
| 85 | + mapping[k] = fresh; | |
| 86 | + microkit_dbg_puts("SPLIT COPY "); number(k); | |
| 87 | + microkit_dbg_puts(" "); number(old); | |
| 88 | + microkit_dbg_puts(" "); number(fresh); microkit_dbg_puts("\n"); | |
| 89 | + table(); | |
| 90 | + microkit_dbg_puts("SPLIT FAULT "); number(k); | |
| 91 | + microkit_dbg_puts(" "); number(address); | |
| 92 | + microkit_dbg_puts(" "); number(ip); | |
| 93 | + microkit_dbg_puts(" "); number(fsr); | |
| 94 | + microkit_dbg_puts(" "); number(source); | |
| 95 | + microkit_dbg_puts(" "); number(target); microkit_dbg_puts("\n"); | |
| 96 | + *reply = microkit_msginfo_new(0, 0); | |
| 97 | + return seL4_True; | |
| 98 | +} | |
| 99 | + | |
| 100 | +microkit_msginfo protected(microkit_channel channel, microkit_msginfo info) { | |
| 101 | + require(channel < CLIENTS && (int)channel == busy, "unexpected worker"); | |
| 102 | + if (microkit_msginfo_get_label(info) == 1) { | |
| 103 | + unsigned p = microkit_mr_get(0), offset = microkit_mr_get(1), byte = microkit_mr_get(2); | |
| 104 | + require(p < PAGES && offset <= LIMIT && byte < 256, "write bounds"); | |
| 105 | + unsigned k = channel * PAGES + p; | |
| 106 | + require(frame(mapping[k])[offset] == byte, "write observation"); | |
| 107 | + microkit_dbg_puts("SPLIT W "); number(k); | |
| 108 | + microkit_dbg_puts(" "); number(offset); | |
| 109 | + microkit_dbg_puts(" "); number(byte); microkit_dbg_puts("\n"); | |
| 110 | + } else { | |
| 111 | + require(microkit_msginfo_get_label(info) == 2, "unknown worker request"); | |
| 112 | + busy = -1; | |
| 113 | + done(); | |
| 114 | + } | |
| 115 | + return microkit_msginfo_new(0, 0); | |
| 116 | +} | |
| 117 | + | |
| 118 | +static void request(void) { | |
| 119 | + if (busy >= 0) { microkit_dbg_puts("@error worker busy\n"); return; } | |
| 120 | + if (line[0] == 'B' && !started && line[1] == ' ' && line[2] >= '0' && line[2] <= '3' && line[3] == ' ') { | |
| 121 | + unsigned p = line[2] - '0', size; | |
| 122 | + if (!length(line + 4, &size)) { microkit_dbg_puts("@error field too long\n"); return; } | |
| 123 | + for (unsigned b = 0; b < BYTES; ++b) frame(p)[b] = 0; | |
| 124 | + for (unsigned i = 0; i < size; ++i) frame(p)[i] = line[4 + i]; | |
| 125 | + done(); | |
| 126 | + } else if (line[0] == 'S' && !line[1] && !started) { | |
| 127 | + started = 1; | |
| 128 | + done(); | |
| 129 | + } else if (!started) { | |
| 130 | + microkit_dbg_puts("@error document not opened\n"); | |
| 131 | + } else if (line[0] == 'E' && line[1] == ' ' && line[2] >= '0' && line[2] <= '1' && line[3] == ' ' && line[4] >= '0' && line[4] <= '3' && line[5] == ' ') { | |
| 132 | + unsigned c = line[2] - '0', p = line[4] - '0', size; | |
| 133 | + if (!length(line + 6, &size)) { microkit_dbg_puts("@error field too long\n"); return; } | |
| 134 | + volatile struct job *job = (void *)(TASK + c * BYTES); | |
| 135 | + job->page = p; | |
| 136 | + for (unsigned i = 0; i < size; ++i) job->text[i] = line[6 + i]; | |
| 137 | + job->text[size] = 0; | |
| 138 | + job->length = size; | |
| 139 | + busy = c; | |
| 140 | + microkit_notify(c); | |
| 141 | + } else if (line[0] == 'Q' && line[1] == ' ' && line[2] >= '0' && line[2] <= '2' && !line[3]) { | |
| 142 | + unsigned c = line[2] - '0'; | |
| 143 | + for (unsigned p = 0; p < PAGES; ++p) { | |
| 144 | + unsigned k = c * PAGES + p, f = c == 2 ? p : mapping[k]; | |
| 145 | + if (c < CLIENTS) { | |
| 146 | + for (unsigned b = 0; b <= LIMIT; ++b) { | |
| 147 | + microkit_dbg_puts("SPLIT R "); number(k); | |
| 148 | + microkit_dbg_puts(" "); number(b); | |
| 149 | + microkit_dbg_puts(" "); number(frame(f)[b]); microkit_dbg_puts("\n"); | |
| 150 | + if (!frame(f)[b]) break; | |
| 151 | + } | |
| 152 | + } | |
| 153 | + microkit_dbg_puts("@field "); number(p); microkit_dbg_puts(" "); | |
| 154 | + for (unsigned b = 0; b < LIMIT && frame(f)[b]; ++b) { | |
| 155 | + char text[2] = {(char)frame(f)[b], 0}; microkit_dbg_puts(text); | |
| 156 | + } | |
| 157 | + microkit_dbg_puts("\n"); | |
| 158 | + } | |
| 159 | + done(); | |
| 160 | + } else if (line[0] == 'P' && !line[1]) { | |
| 161 | + for (unsigned k = 0; k < SLOTS; ++k) { | |
| 162 | + microkit_dbg_puts("@map "); number(k); | |
| 163 | + microkit_dbg_puts(" "); number(BASE + (k % PAGES) * BYTES); | |
| 164 | + microkit_dbg_puts(" "); number(physical(caps[k])); | |
| 165 | + microkit_dbg_puts(" "); number(mapping[k] >= PAGES); microkit_dbg_puts("\n"); | |
| 166 | + } | |
| 167 | + done(); | |
| 168 | + } else if (line[0] == 'D' && line[1] == ' ' && line[2] >= '0' && line[2] <= '1' && !line[3]) { | |
| 169 | + unsigned c = line[2] - '0'; | |
| 170 | + require(seL4_TCB_Suspend(BASE_TCB_CAP + c) == seL4_NoError, "worker suspend"); | |
| 171 | + microkit_dbg_puts("SPLIT STOP "); number(c); microkit_dbg_puts("\n"); | |
| 172 | + for (unsigned p = 0; p < PAGES; ++p) { | |
| 173 | + unsigned k = c * PAGES + p, f = mapping[k]; | |
| 174 | + if (f < PAGES) continue; | |
| 175 | + seL4_Word old = physical(caps[k]); | |
| 176 | + require(seL4_ARM_Page_Unmap(caps[k]) == seL4_NoError, "private page unmap"); | |
| 177 | + caps[k] = microkit_cspace_root_slot_to_cptr(10 + k); | |
| 178 | + map(k, caps[k], 0); | |
| 179 | + mapping[k] = p; | |
| 180 | + volatile unsigned char *bytes = frame(f); | |
| 181 | + for (unsigned b = 0; b < BYTES; ++b) bytes[b] = 0; | |
| 182 | + unsigned cleared = 0; | |
| 183 | + for (unsigned b = 0; b < BYTES; ++b) cleared += bytes[b] == 0; | |
| 184 | + require(cleared == BYTES && returned < FRAMES - PAGES, "frame scrub"); | |
| 185 | + available[returned++] = f; | |
| 186 | + microkit_dbg_puts("SPLIT RELEASE "); number(k); | |
| 187 | + microkit_dbg_puts(" "); number(f); | |
| 188 | + microkit_dbg_puts(" "); number(old); | |
| 189 | + microkit_dbg_puts(" "); number(physical(caps[k])); | |
| 190 | + microkit_dbg_puts(" "); number(cleared); microkit_dbg_puts("\n"); | |
| 191 | + } | |
| 192 | + table(); | |
| 193 | + require(seL4_TCB_Resume(BASE_TCB_CAP + c) == seL4_NoError, "worker resume"); | |
| 194 | + microkit_dbg_puts("SPLIT RUN "); number(c); microkit_dbg_puts("\n"); | |
| 195 | + done(); | |
| 196 | + } else if (line[0] == 'F' && !line[1]) { | |
| 197 | + for (unsigned i = returned; i > 0; --i) { | |
| 198 | + unsigned f = available[i - 1], cleared = 0; | |
| 199 | + volatile unsigned char *bytes = frame(f); | |
| 200 | + for (unsigned b = 0; b < BYTES; ++b) cleared += bytes[b] == 0; | |
| 201 | + microkit_dbg_puts("@free "); number(f); | |
| 202 | + microkit_dbg_puts(" "); number(physical(microkit_cspace_root_slot_to_cptr(30 + f - PAGES))); | |
| 203 | + microkit_dbg_puts(" "); number(cleared); microkit_dbg_puts("\n"); | |
| 204 | + for (unsigned b = 0; b < 32; ++b) { | |
| 205 | + microkit_dbg_puts("@zero "); number(f); | |
| 206 | + microkit_dbg_puts(" "); number(b); | |
| 207 | + microkit_dbg_puts(" "); number(bytes[b]); microkit_dbg_puts("\n"); | |
| 208 | + } | |
| 209 | + } | |
| 210 | + done(); | |
| 211 | + } else if (line[0] == 'H' && line[1] == ' ' && line[2] >= '0' && line[2] <= '2' && line[3] == ' ' && line[4] >= '0' && line[4] <= '3' && !line[5]) { | |
| 212 | + unsigned c = line[2] - '0', p = line[4] - '0', k = c * PAGES + p; | |
| 213 | + unsigned f = c == 2 ? p : mapping[k]; | |
| 214 | + seL4_CPtr cap = c == 2 ? microkit_cspace_root_slot_to_cptr(10 + p) : caps[k]; | |
| 215 | + microkit_dbg_puts("@addr "); number(c == 2 ? BACKING + p * BYTES : BASE + p * BYTES); | |
| 216 | + microkit_dbg_puts(" "); number(physical(cap)); microkit_dbg_puts("\n"); | |
| 217 | + for (unsigned b = 0; b < 64; ++b) { | |
| 218 | + if (c < CLIENTS) { | |
| 219 | + microkit_dbg_puts("SPLIT R "); number(k); | |
| 220 | + microkit_dbg_puts(" "); number(b); | |
| 221 | + microkit_dbg_puts(" "); number(frame(f)[b]); microkit_dbg_puts("\n"); | |
| 222 | + } | |
| 223 | + microkit_dbg_puts("@byte "); number(b); | |
| 224 | + microkit_dbg_puts(" "); number(frame(f)[b]); microkit_dbg_puts("\n"); | |
| 225 | + } | |
| 226 | + done(); | |
| 227 | + } else if (line[0] == 'M' && !line[1]) { | |
| 228 | + table(); | |
| 229 | + done(); | |
| 230 | + } else { | |
| 231 | + microkit_dbg_puts("@error unknown request\n"); | |
| 232 | + } | |
| 233 | +} | |
| 234 | + | |
| 235 | +void notified(microkit_channel channel) { | |
| 236 | + require(channel == 5, "unknown interrupt"); | |
| 237 | + uart[0x44 / 4] = 0x7ff; | |
| 238 | + while (!(uart[0x18 / 4] & 0x10)) { | |
| 239 | + unsigned ch = uart[0] & 255; | |
| 240 | + if (ch == '\n') { | |
| 241 | + line[used] = 0; | |
| 242 | + request(); | |
| 243 | + used = 0; | |
| 244 | + } else if (ch >= 32 && ch < 127 && used < sizeof(line) - 1) { | |
| 245 | + line[used++] = ch; | |
| 246 | + } | |
| 247 | + } | |
| 248 | + microkit_irq_ack(5); | |
| 249 | +} | |
setup.sh added
| @@ -0,0 +1,17 @@ | ||
| 1 | +#!/bin/sh | |
| 2 | +set -eu | |
| 3 | +cache="${SPLIT_CACHE:-$HOME/.cache/split}" | |
| 4 | +mkdir -p "$cache" | |
| 5 | +if [ ! -f "$cache/sdk.tar.gz" ]; then | |
| 6 | + curl -fL --retry 2 https://github.com/seL4/microkit/releases/download/2.3.1/microkit-sdk-2.3.1-linux-x86-64.tar.gz -o "$cache/sdk.tar.gz" | |
| 7 | +fi | |
| 8 | +if [ ! -f "$cache/source.tar.gz" ]; then | |
| 9 | + curl -fL --retry 2 https://codeload.github.com/seL4/microkit/tar.gz/refs/tags/2.3.1 -o "$cache/source.tar.gz" | |
| 10 | +fi | |
| 11 | +printf '%s %s\n' b1b285b8785db7557eba6d0665dd4fbf2f265ea5c0b39d6f91ae3dcc43d2c424 "$cache/sdk.tar.gz" 67ae034628465c35169c398dd7d9ea61dbe8bd93c7a9adb05b9bb31bae25c22f "$cache/source.tar.gz" | sha256sum -c - | |
| 12 | +if [ ! -d "$cache/microkit-sdk-2.3.1" ]; then | |
| 13 | + tar -xzf "$cache/sdk.tar.gz" -C "$cache" | |
| 14 | +fi | |
| 15 | +tar -xzf "$cache/source.tar.gz" -C "$cache" | |
| 16 | +patch -s -p1 -d "$cache/microkit-2.3.1" < "$(dirname "$0")/microkit.patch" | |
| 17 | +cargo build --release --locked -p microkit-tool --manifest-path "$cache/microkit-2.3.1/Cargo.toml" | |
split.h added
| @@ -0,0 +1,43 @@ | ||
| 1 | +#ifndef SPLIT_H | |
| 2 | +#define SPLIT_H | |
| 3 | +#include <microkit.h> | |
| 4 | +#include <stdint.h> | |
| 5 | + | |
| 6 | +#define PAGES 4u | |
| 7 | +#define CLIENTS 2u | |
| 8 | +#define SLOTS (PAGES * CLIENTS) | |
| 9 | +#define FRAMES (PAGES + SLOTS) | |
| 10 | +#define BYTES 4096u | |
| 11 | +#define BASE 0x40000000ul | |
| 12 | +#define BACKING 0x60000000ul | |
| 13 | +#define TASK 0x50000000ul | |
| 14 | +#define LIMIT 255u | |
| 15 | + | |
| 16 | +struct job { | |
| 17 | + unsigned page, length; | |
| 18 | + char text[LIMIT + 1]; | |
| 19 | +}; | |
| 20 | + | |
| 21 | +static inline void number(unsigned long n) { | |
| 22 | + char s[24]; | |
| 23 | + unsigned i = sizeof(s) - 1; | |
| 24 | + s[i] = 0; | |
| 25 | + do { | |
| 26 | + s[--i] = '0' + n % 10; | |
| 27 | + n /= 10; | |
| 28 | + } while (n); | |
| 29 | + microkit_dbg_puts(s + i); | |
| 30 | +} | |
| 31 | + | |
| 32 | +static inline unsigned char seed(unsigned page, unsigned offset) { | |
| 33 | + return (page * 17u + offset) % 256u; | |
| 34 | +} | |
| 35 | + | |
| 36 | +static inline void require(int ok, const char *message) { | |
| 37 | + if (ok) return; | |
| 38 | + microkit_dbg_puts("@error "); | |
| 39 | + microkit_dbg_puts(message); | |
| 40 | + microkit_dbg_puts("\n"); | |
| 41 | + for (;;) seL4_Yield(); | |
| 42 | +} | |
| 43 | +#endif | |
split.system added
| @@ -0,0 +1,76 @@ | ||
| 1 | +<system> | |
| 2 | + <memory_region name="frame0" size="0x1000" page_size="0x1000" /> | |
| 3 | + <memory_region name="frame1" size="0x1000" page_size="0x1000" /> | |
| 4 | + <memory_region name="frame2" size="0x1000" page_size="0x1000" /> | |
| 5 | + <memory_region name="frame3" size="0x1000" page_size="0x1000" /> | |
| 6 | + <memory_region name="frame4" size="0x1000" page_size="0x1000" /> | |
| 7 | + <memory_region name="frame5" size="0x1000" page_size="0x1000" /> | |
| 8 | + <memory_region name="frame6" size="0x1000" page_size="0x1000" /> | |
| 9 | + <memory_region name="frame7" size="0x1000" page_size="0x1000" /> | |
| 10 | + <memory_region name="frame8" size="0x1000" page_size="0x1000" /> | |
| 11 | + <memory_region name="frame9" size="0x1000" page_size="0x1000" /> | |
| 12 | + <memory_region name="frame10" size="0x1000" page_size="0x1000" /> | |
| 13 | + <memory_region name="frame11" size="0x1000" page_size="0x1000" /> | |
| 14 | + <memory_region name="reserve0" size="0x1000" page_size="0x1000" /> | |
| 15 | + <memory_region name="reserve1" size="0x1000" page_size="0x1000" /> | |
| 16 | + <protection_domain name="pager" priority="254"> | |
| 17 | + <program_image path="pager.elf" /> | |
| 18 | + <map mr="frame0" vaddr="0x60000000" perms="rw" /> | |
| 19 | + <map mr="frame1" vaddr="0x60001000" perms="rw" /> | |
| 20 | + <map mr="frame2" vaddr="0x60002000" perms="rw" /> | |
| 21 | + <map mr="frame3" vaddr="0x60003000" perms="rw" /> | |
| 22 | + <map mr="frame4" vaddr="0x60004000" perms="rw" /> | |
| 23 | + <map mr="frame5" vaddr="0x60005000" perms="rw" /> | |
| 24 | + <map mr="frame6" vaddr="0x60006000" perms="rw" /> | |
| 25 | + <map mr="frame7" vaddr="0x60007000" perms="rw" /> | |
| 26 | + <map mr="frame8" vaddr="0x60008000" perms="rw" /> | |
| 27 | + <map mr="frame9" vaddr="0x60009000" perms="rw" /> | |
| 28 | + <map mr="frame10" vaddr="0x6000a000" perms="rw" /> | |
| 29 | + <map mr="frame11" vaddr="0x6000b000" perms="rw" /> | |
| 30 | + <cspace> | |
| 31 | + <cap_vspace slot="1" pd="alpha" /> | |
| 32 | + <cap_frame slot="10" mr="frame0" /> | |
| 33 | + <cap_frame slot="11" mr="frame1" /> | |
| 34 | + <cap_frame slot="12" mr="frame2" /> | |
| 35 | + <cap_frame slot="13" mr="frame3" /> | |
| 36 | + <cap_vspace slot="2" pd="beta" /> | |
| 37 | + <cap_frame slot="14" mr="frame0" /> | |
| 38 | + <cap_frame slot="15" mr="frame1" /> | |
| 39 | + <cap_frame slot="16" mr="frame2" /> | |
| 40 | + <cap_frame slot="17" mr="frame3" /> | |
| 41 | + <cap_frame slot="30" mr="frame4" /> | |
| 42 | + <cap_frame slot="31" mr="frame5" /> | |
| 43 | + <cap_frame slot="32" mr="frame6" /> | |
| 44 | + <cap_frame slot="33" mr="frame7" /> | |
| 45 | + <cap_frame slot="34" mr="frame8" /> | |
| 46 | + <cap_frame slot="35" mr="frame9" /> | |
| 47 | + <cap_frame slot="36" mr="frame10" /> | |
| 48 | + <cap_frame slot="37" mr="frame11" /> | |
| 49 | + </cspace> | |
| 50 | + <protection_domain name="alpha" priority="100" id="0"> | |
| 51 | + <program_image path="alpha.elf" /> | |
| 52 | + <map mr="reserve0" vaddr="0x40010000" perms="r" /> | |
| 53 | + <map mr="task0" vaddr="0x50000000" perms="r" /> | |
| 54 | + </protection_domain> | |
| 55 | + <protection_domain name="beta" priority="99" id="1"> | |
| 56 | + <program_image path="beta.elf" /> | |
| 57 | + <map mr="reserve1" vaddr="0x40010000" perms="r" /> | |
| 58 | + <map mr="task1" vaddr="0x50000000" perms="r" /> | |
| 59 | + </protection_domain> | |
| 60 | + <map mr="uart" vaddr="0x70000000" perms="rw" cached="false" /> | |
| 61 | + <irq irq="33" id="5" trigger="level" /> | |
| 62 | + <map mr="task0" vaddr="0x50000000" perms="rw" /> | |
| 63 | + <map mr="task1" vaddr="0x50001000" perms="rw" /> | |
| 64 | + </protection_domain> | |
| 65 | + <channel> | |
| 66 | + <end pd="pager" id="0" /> | |
| 67 | + <end pd="alpha" id="0" pp="true" /> | |
| 68 | + </channel> | |
| 69 | + <channel> | |
| 70 | + <end pd="pager" id="1" /> | |
| 71 | + <end pd="beta" id="0" pp="true" /> | |
| 72 | + </channel> | |
| 73 | + <memory_region name="uart" size="0x1000" page_size="0x1000" phys_addr="0x09000000" /> | |
| 74 | + <memory_region name="task0" size="0x1000" page_size="0x1000" /> | |
| 75 | + <memory_region name="task1" size="0x1000" page_size="0x1000" /> | |
| 76 | +</system> | |