forked from M-Labs/artiq
artiq_coreboot: allow hot-rebooting the device.
This commit is contained in:
parent
1bd4d13391
commit
296dc3b0c4
|
@ -13,6 +13,7 @@ class Request(Enum):
|
||||||
SetLogFilter = 3
|
SetLogFilter = 3
|
||||||
|
|
||||||
Hotswap = 4
|
Hotswap = 4
|
||||||
|
Reboot = 5
|
||||||
|
|
||||||
|
|
||||||
class Reply(Enum):
|
class Reply(Enum):
|
||||||
|
@ -20,7 +21,7 @@ class Reply(Enum):
|
||||||
|
|
||||||
LogContent = 2
|
LogContent = 2
|
||||||
|
|
||||||
HotswapImminent = 3
|
RebootImminent = 3
|
||||||
|
|
||||||
|
|
||||||
class LogLevel(Enum):
|
class LogLevel(Enum):
|
||||||
|
@ -130,4 +131,8 @@ class CommMgmt:
|
||||||
def hotswap(self, firmware):
|
def hotswap(self, firmware):
|
||||||
self._write_header(Request.Hotswap)
|
self._write_header(Request.Hotswap)
|
||||||
self._write_bytes(firmware)
|
self._write_bytes(firmware)
|
||||||
self._read_expect(Reply.HotswapImminent)
|
self._read_expect(Reply.RebootImminent)
|
||||||
|
|
||||||
|
def reboot(self):
|
||||||
|
self._write_header(Request.Reboot)
|
||||||
|
self._read_expect(Reply.RebootImminent)
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub enum Request {
|
||||||
SetLogFilter(LogLevelFilter),
|
SetLogFilter(LogLevelFilter),
|
||||||
|
|
||||||
Hotswap(Vec<u8>),
|
Hotswap(Vec<u8>),
|
||||||
|
Reboot,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Reply<'a> {
|
pub enum Reply<'a> {
|
||||||
|
@ -19,7 +20,7 @@ pub enum Reply<'a> {
|
||||||
|
|
||||||
LogContent(&'a str),
|
LogContent(&'a str),
|
||||||
|
|
||||||
HotswapImminent,
|
RebootImminent,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
|
@ -42,6 +43,7 @@ impl Request {
|
||||||
Request::SetLogFilter(level)
|
Request::SetLogFilter(level)
|
||||||
}
|
}
|
||||||
4 => Request::Hotswap(reader.read_bytes()?),
|
4 => Request::Hotswap(reader.read_bytes()?),
|
||||||
|
5 => Request::Reboot,
|
||||||
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type"))
|
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -59,7 +61,7 @@ impl<'a> Reply<'a> {
|
||||||
writer.write_string(log)?;
|
writer.write_string(log)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::HotswapImminent => {
|
Reply::RebootImminent => {
|
||||||
writer.write_u8(3)?;
|
writer.write_u8(3)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,18 @@ fn worker(mut stream: &mut TcpStream) -> io::Result<()> {
|
||||||
},
|
},
|
||||||
|
|
||||||
Request::Hotswap(firmware) => {
|
Request::Hotswap(firmware) => {
|
||||||
Reply::HotswapImminent.write_to(stream)?;
|
Reply::RebootImminent.write_to(stream)?;
|
||||||
stream.close()?;
|
stream.close()?;
|
||||||
warn!("hotswapping firmware");
|
warn!("hotswapping firmware");
|
||||||
unsafe { board::boot::hotswap(&firmware) }
|
unsafe { board::boot::hotswap(&firmware) }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Request::Reboot => {
|
||||||
|
Reply::RebootImminent.write_to(stream)?;
|
||||||
|
stream.close()?;
|
||||||
|
warn!("rebooting");
|
||||||
|
unsafe { board::boot::reboot() }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from artiq.tools import verbosity_args, init_logger
|
from artiq.tools import verbosity_args, init_logger
|
||||||
|
@ -10,13 +11,21 @@ from artiq.coredevice.comm_mgmt import CommMgmt
|
||||||
|
|
||||||
|
|
||||||
def get_argparser():
|
def get_argparser():
|
||||||
parser = argparse.ArgumentParser(description="ARTIQ core device hotswap tool")
|
parser = argparse.ArgumentParser(description="ARTIQ core device boot tool")
|
||||||
|
|
||||||
verbosity_args(parser)
|
verbosity_args(parser)
|
||||||
parser.add_argument("--device-db", default="device_db.pyon",
|
parser.add_argument("--device-db", default="device_db.pyon",
|
||||||
help="device database file (default: '%(default)s')")
|
help="device database file (default: '%(default)s')")
|
||||||
|
|
||||||
parser.add_argument("image", metavar="IMAGE", type=argparse.FileType('rb'),
|
subparsers = parser.add_subparsers(dest="action")
|
||||||
|
|
||||||
|
p_reboot = subparsers.add_parser("reboot",
|
||||||
|
help="reboot the currently running firmware")
|
||||||
|
|
||||||
|
p_hotswap = subparsers.add_parser("hotswap",
|
||||||
|
help="load the specified firmware in RAM")
|
||||||
|
|
||||||
|
p_hotswap.add_argument("image", metavar="IMAGE", type=argparse.FileType('rb'),
|
||||||
help="runtime image to be executed")
|
help="runtime image to be executed")
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
@ -29,7 +38,13 @@ def main():
|
||||||
try:
|
try:
|
||||||
core_addr = device_mgr.get_desc("comm")["arguments"]["host"]
|
core_addr = device_mgr.get_desc("comm")["arguments"]["host"]
|
||||||
mgmt = CommMgmt(device_mgr, core_addr)
|
mgmt = CommMgmt(device_mgr, core_addr)
|
||||||
|
if args.action == "reboot":
|
||||||
|
mgmt.reboot()
|
||||||
|
elif args.action == "hotswap":
|
||||||
mgmt.hotswap(args.image.read())
|
mgmt.hotswap(args.image.read())
|
||||||
|
else:
|
||||||
|
print("An action needs to be specified.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
finally:
|
finally:
|
||||||
device_mgr.close_devices()
|
device_mgr.close_devices()
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,7 @@ def main():
|
||||||
logger.info("Hotswapping firmware")
|
logger.info("Hotswapping firmware")
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(["python3",
|
subprocess.check_call(["python3",
|
||||||
"-m", "artiq.frontend.artiq_coreboot",
|
"-m", "artiq.frontend.artiq_coreboot", "hotswap",
|
||||||
"/tmp/{target}/software/{firmware}/{firmware}.bin"
|
"/tmp/{target}/software/{firmware}/{firmware}.bin"
|
||||||
.format(target=args.target, firmware=firmware)])
|
.format(target=args.target, firmware=firmware)])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
|
|
Loading…
Reference in New Issue