Skip to content

Commit 88b5cab

Browse files
committed
test: chainloading via a multiboot module
1 parent 3dfb6d8 commit 88b5cab

13 files changed

Lines changed: 126 additions & 21 deletions

File tree

File renamed without changes.

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ set(OS_OBJECTS
3737
util/memstream.c util/async.cpp util/statman.cpp util/logger.cpp
3838
util/os_statman.cpp util/sha1.cpp
3939
util/syslog_facility.cpp util/syslogd.cpp util/uri.cpp util/percent_encoding.cpp
40-
util/tar.cpp util/path_to_regex.cpp
40+
util/tar.cpp util/path_to_regex.cpp util/elf_binary.cpp
4141
crt/c_abi.c crt/string.c crt/quick_exit.cpp crt/cxx_abi.cpp
4242
hw/ide.cpp hw/pci_device.cpp hw/ps2.cpp hw/serial.cpp hw/serial1.cpp
4343
hw/cmos.cpp hw/block_device.cpp hw/msi.cpp hw/pci_msi.cpp

src/kernel/elf.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include <string>
2525
#include <unistd.h>
2626
#include <vector>
27-
#include "../../vmbuild/elf.h"
27+
#include <util/elf.h>
2828

2929
static const char* boot_stringz = "Bootloader area";
3030
extern "C" char _ELF_START_;
Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1-
#include "elf_binary.hpp"
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2015-2017 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#include "../api/util/elf_binary.hpp"
219

320
#include <cstdlib>
421
#include <iostream>

test/kernel/integration/modules/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ set(SERVICE_NAME "Kernel modules test")
1414
set(BINARY "test_mods")
1515
set(MAX_MEM 128)
1616
set(SOURCES
17-
service.cpp
17+
service.cpp hotswap.cpp
1818
)
1919
#set(LOCAL_INCLUDES ".")
2020

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
/*
19+
* Self sufficient Utility function that will copy a binary to a certain
20+
* location and then jump to it. The idea (from fwsgonzo) is to have this
21+
* function copied to an otherwise unused place in memory so that we can
22+
* overwrite the currently running binary with a new one.
23+
*/
24+
25+
asm(".org 0x8000");
26+
#define BOOT_MAGIC 0x1
27+
28+
extern "C" __attribute__((noreturn))
29+
void hotswap(const char* base, int len, char* dest, void* start)
30+
{
31+
// replace old kernel with new
32+
for (int i = 0; i < len; i++)
33+
dest[i] = base[i];
34+
35+
// jump to _start
36+
asm volatile("jmp *%1" : : "a" (BOOT_MAGIC), "b" (start) : "eax", "ebx");
37+
38+
// we can never get here!
39+
__builtin_unreachable();
40+
}

test/kernel/integration/modules/mod2/service.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919

2020
void Service::start()
2121
{
22-
printf("Hello world - OS included!\n");
22+
printf("IncludeOS was just chainloaded by IncludeOS\n");
23+
exit(0);
2324
}

test/kernel/integration/modules/service.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,29 @@
1616
// limitations under the License.
1717

1818
#include <os>
19+
#include <util/elf_binary.hpp>
20+
#include <util/sha1.hpp>
21+
22+
bool verb = true;
23+
24+
#define MYINFO(X,...) INFO("Service", X, ##__VA_ARGS__)
25+
26+
extern "C" void hotswap(const char* base, int len, char* dest, void* start);
1927

2028
void Service::start(const std::string& args)
2129
{
22-
printf("Testing kernel modules. Args: %s \n", args.c_str());
30+
MYINFO("Testing kernel modules. Args: %s", args.c_str());
2331

2432
auto mods = OS::modules();
2533

26-
Expects(mods.size() == 3);
34+
//Expects(mods.size() == 3);
2735

2836
printf("Found %i modules: \n", mods.size());
2937

3038
for (auto mod : mods)
31-
printf("\t* %s @ 0x%x - 0x%x, size: %ib \n",
39+
INFO2("* %s @ 0x%x - 0x%x, size: %ib",
3240
reinterpret_cast<char*>(mod.cmdline),
33-
mod.mod_start, mod.mod_end, mod.mod_end - mod.mod_start);
41+
mod.mod_start, mod.mod_end, mod.mod_end - mod.mod_start);
3442

3543
// Verify module cmdlines
3644
Expects(std::string((char*)mods[0].cmdline) == "../mod1.json");
@@ -44,11 +52,34 @@ void Service::start(const std::string& args)
4452
Expects(std::string((char*)mods[2].mod_start)
4553
== "{\"module3\" : \"More JSON data, for mod2 service\" }\n");
4654

47-
// TODO: Properly verify mod2 as ELF binary
48-
Expects(((uint8_t*) mods[1].mod_start)[0] == 0x7f);
49-
Expects(((char*) mods[1].mod_start)[1] == 'E');
50-
Expects(((char*) mods[1].mod_start)[2] == 'L');
51-
Expects(((char*) mods[1].mod_start)[3] == 'F');
55+
multiboot_module_t binary = mods[1];
56+
57+
MYINFO("Verifying mod2 as ELF binary");
58+
Elf_binary elf ({(char*)binary.mod_start, (int)(binary.mod_end - binary.mod_start)});
59+
60+
MYINFO("Moving hotswap function (now at %p)", &hotswap);
61+
memcpy((void*)0x8000, (void*)&hotswap, 1024);
62+
63+
MYINFO("Preparing for jump to %s", (char*)binary.cmdline);
64+
65+
char* base = (char*)binary.mod_start;
66+
int len = (int)(binary.mod_end - binary.mod_start);
67+
char* dest = (char*)0x100000;
68+
void* start = (void*)elf.entry();
69+
70+
SHA1 sha;
71+
sha.update(base, len);
72+
MYINFO("Sha1 of ELF binary module: %s", sha.as_hex().c_str());
73+
74+
75+
MYINFO("Jump params: base: %p, len: %i, dest: %p, start: %p",
76+
base, len, dest, start);
77+
78+
MYINFO("Disabling interrupts and calling hotswap...");
79+
80+
asm("cli");
81+
((decltype(&hotswap))0x8000)(base, len, dest, start);
82+
83+
panic("Should have jumped\n");
5284

53-
exit(0);
5485
}

test/kernel/integration/modules/test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,21 @@
1111

1212
vm = vmrunner.vms[0];
1313

14+
chainloaded = False
15+
16+
17+
def chainload_ok(string):
18+
global chainloaded
19+
chainloaded = True
20+
return chainloaded
21+
22+
23+
def verify_chainload():
24+
print "<test.py>", "Chainloaded: ", chainloaded
25+
return chainloaded
26+
27+
vm.on_output("IncludeOS was just chainloaded", chainload_ok);
28+
vm.on_exit(verify_chainload)
29+
1430
# Build, run and clean
1531
vm.cmake().boot().clean()

0 commit comments

Comments
 (0)