Working version
This commit is contained in:
parent
549b12a862
commit
0f510c4fc8
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,21 @@
|
|||
const Builder = @import("std").build.Builder;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
const exe = b.addExecutable("update-em-bootloader", "src/main.zig");
|
||||
exe.setBuildMode(builtin.Mode.ReleaseSmall);
|
||||
exe.strip = true;
|
||||
|
||||
exe.setTarget(builtin.Arch.mipsel, builtin.Os.linux, builtin.Abi.musl);
|
||||
|
||||
exe.addIncludeDir("/usr/include");
|
||||
exe.linkSystemLibrary("c");
|
||||
exe.install();
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
const std = @import("std");
|
||||
const math = std.math;
|
||||
const mtd_user = @cImport(@cInclude("mtd/mtd-user.h"));
|
||||
|
||||
const uboot_bin = @embedFile("../bin/uboot-feb2019.bin");
|
||||
const mtd_rw = @import("mtd-rw.zig");
|
||||
const mtd = @import("mtd.zig");
|
||||
|
||||
pub fn main() !u8 {
|
||||
try mtd_rw.load();
|
||||
defer mtd_rw.unload();
|
||||
|
||||
// Read and hash mtd0
|
||||
const mtd0_size = try mtd.mtd_info_get_usize("size");
|
||||
|
||||
if (uboot_bin.len > mtd0_size) {
|
||||
std.debug.warn("Error: mtd0 isn\'t large enough to hold the new image ({} > {})\n",
|
||||
.{uboot_bin.len, mtd0_size});
|
||||
return 1;
|
||||
}
|
||||
|
||||
const no_write_needed = try mtd.verify("/dev/mtd0", uboot_bin);
|
||||
if (no_write_needed) {
|
||||
std.debug.warn("U-Boot is up to date. Exiting.\n", .{});
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Erase mtd0
|
||||
try mtd.erase_device("/dev/mtd0");
|
||||
|
||||
// Write mtd0
|
||||
std.debug.warn("Writing payload\n", .{});
|
||||
try mtd.write_device("/dev/mtd0", uboot_bin);
|
||||
|
||||
// Verify mtd0
|
||||
const writing_verified = try mtd.verify("/dev/mtd0", uboot_bin);
|
||||
if (!writing_verified) {
|
||||
std.debug.warn("Verify Failed!\n", .{});
|
||||
return 2;
|
||||
}
|
||||
std.debug.warn("Success\n", .{});
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
const std = @import("std");
|
||||
const os = std.os;
|
||||
|
||||
const mtd_rw_ko = @embedFile("../bin/mtd-rw.ko");
|
||||
|
||||
const InitModuleError = error {
|
||||
ModuleSignatureMisformatted,
|
||||
TimeoutResolvingSymbol,
|
||||
BadAddress,
|
||||
ModuleSigInvalid,
|
||||
OutOfMemory,
|
||||
PermissionDenied,
|
||||
AlreadyLoaded,
|
||||
BadParams,
|
||||
InvalidModule,
|
||||
|
||||
};
|
||||
|
||||
const DeleteModuleError = error {
|
||||
ModuleNotLive,
|
||||
BadAddress,
|
||||
ModuleNotFound,
|
||||
PermissionDenied,
|
||||
ModuleInUse,
|
||||
};
|
||||
|
||||
pub fn load() !void {
|
||||
try insmod(mtd_rw_ko, "i_want_a_brick=1");
|
||||
}
|
||||
|
||||
pub fn unload() void {
|
||||
rmmod("mtd_rw", os.O_NONBLOCK) catch |err| {
|
||||
std.debug.warn("Failed to unload module: {}\n", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn insmod(buf: []const u8, args: [*:0]const u8) !void {
|
||||
const errno = os.linux.getErrno(
|
||||
os.linux.syscall3(
|
||||
os.linux.SYS_init_module, @ptrToInt(&buf[0]), buf.len, @ptrToInt(args)));
|
||||
switch (errno) {
|
||||
0 => return,
|
||||
os.EEXIST => return, // It's not a failure if we have what we need
|
||||
os.EBADMSG => return InitModuleError.ModuleSignatureMisformatted,
|
||||
os.EBUSY => return InitModuleError.TimeoutResolvingSymbol,
|
||||
os.EFAULT => return InitModuleError.BadAddress,
|
||||
// os.ENOKEY => return InitModuleError.ModuleSigInvalid,
|
||||
os.ENOMEM => return InitModuleError.OutOfMemory,
|
||||
os.EPERM => return InitModuleError.PermissionDenied,
|
||||
os.EINVAL => return InitModuleError.BadParams,
|
||||
os.ENOEXEC => return InitModuleError.InvalidModule,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rmmod(mod_name: [*:0]const u8, flags: u32) !void {
|
||||
const errno = os.linux.getErrno(
|
||||
std.os.linux.syscall2(
|
||||
std.os.linux.SYS_delete_module, @ptrToInt(mod_name), flags));
|
||||
switch (errno) {
|
||||
0 => return,
|
||||
os.EBUSY => return DeleteModuleError.ModuleNotLive,
|
||||
os.EFAULT => return DeleteModuleError.BadAddress,
|
||||
os.ENOENT => return DeleteModuleError.ModuleNotFound,
|
||||
os.EPERM => return DeleteModuleError.PermissionDenied,
|
||||
os.EWOULDBLOCK => return DeleteModuleError.ModuleInUse,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
const std = @import("std");
|
||||
const os = std.os;
|
||||
|
||||
const mtd_user = @cImport(@cInclude("mtd/mtd-user.h"));
|
||||
|
||||
const Allocator = std.heap.c_allocator;
|
||||
|
||||
const MEMUNLOCK = 2148027654;
|
||||
const MEMERASE = 2148027650;
|
||||
|
||||
pub fn mtd_info_get(name: []const u8, out: []u8) !void {
|
||||
var path_buf: [64]u8 = undefined;
|
||||
const path = try std.fmt.bufPrint(path_buf[0..], "{}/{}", .{"/sys/class/mtd/mtd0/", name});
|
||||
|
||||
var f = try std.fs.openFileAbsolute(path, .{.read = true});
|
||||
defer f.close();
|
||||
const num_read = try f.read(out);
|
||||
out = out[0..num_read-1];
|
||||
}
|
||||
|
||||
pub fn mtd_info_get_usize(name: []const u8) !usize {
|
||||
var buf: [64]u8 = undefined;
|
||||
var buf_sl = buf[0..];
|
||||
try mtd_info_get(name, buf_sl);
|
||||
return try std.fmt.parseUnsigned(usize, buf_sl, 10);
|
||||
}
|
||||
|
||||
const IoctlError = error {
|
||||
BadFd,
|
||||
SignalCaught,
|
||||
BadIoctl,
|
||||
IOError,
|
||||
NotSupported,
|
||||
NotSupportedSub,
|
||||
Failed,
|
||||
};
|
||||
|
||||
fn ioctl3(fildes: os.fd_t, request: usize, arg: usize) !void {
|
||||
const errno = os.linux.getErrno(
|
||||
os.linux.syscall3(std.os.SYS_ioctl, @intCast(usize, fildes), request, arg));
|
||||
switch (errno) {
|
||||
0 => return,
|
||||
os.EBADF => return IoctlError.BadFd,
|
||||
os.EINTR => return IoctlError.SignalCaught,
|
||||
os.EINVAL => return IoctlError.BadIoctl,
|
||||
os.EIO => return IoctlError.IOError,
|
||||
os.ENOTTY => return IoctlError.NotSupportedSub,
|
||||
os.ENXIO => return IoctlError.Failed,
|
||||
os.ENODEV => return IoctlError.NotSupported,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
const MtdError = error {
|
||||
TruncatedWrite,
|
||||
TruncatedRead,
|
||||
};
|
||||
|
||||
pub fn write_device(dev: []const u8, buf: []const u8) !void {
|
||||
var f = try std.fs.openFileAbsolute(dev, .{.write = true});
|
||||
defer f.close();
|
||||
try f.write(buf);
|
||||
}
|
||||
|
||||
pub fn erase_device(dev: []const u8) !void {
|
||||
const erasesize = try mtd_info_get_usize("erasesize");
|
||||
const size = try mtd_info_get_usize("size");
|
||||
var erased: usize = 0;
|
||||
const fd = try os.open(dev, os.O_RDWR, 0);
|
||||
defer os.close(fd);
|
||||
while (erased < size) {
|
||||
try erase_page(fd, erased, erasesize);
|
||||
erased += erasesize;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn erase_page(fd: os.fd_t, start: usize, len: usize) !void {
|
||||
const end = start + len - 1;
|
||||
std.debug.warn("Erasing {} -> {}\n", .{start, end});
|
||||
|
||||
const ei = mtd_user.erase_info_t{ .length = len, .start = start };
|
||||
try ioctl3(fd, MEMERASE, @ptrToInt(&ei));
|
||||
}
|
||||
|
||||
pub fn verify(dev: []const u8, buf: []const u8) !bool {
|
||||
const size = try mtd_info_get_usize("size");
|
||||
var current = try Allocator.alloc(u8, size);
|
||||
|
||||
var f = try std.fs.openFileAbsolute(dev, .{.read = true});
|
||||
defer f.close();
|
||||
|
||||
const num_read = try f.read(current);
|
||||
if (num_read != size) {
|
||||
std.debug.warn("Incomplete read of {}. {}/{} bytes read", .{dev, num_read, size});
|
||||
return MtdError.TruncatedRead;
|
||||
}
|
||||
|
||||
var dev_digest: [std.crypto.Md5.digest_length]u8 = undefined;
|
||||
std.crypto.Md5.hash(current, dev_digest[0..]);
|
||||
|
||||
var buf_digest: [std.crypto.Md5.digest_length]u8 = undefined;
|
||||
std.crypto.Md5.hash(buf, buf_digest[0..]);
|
||||
|
||||
return std.mem.eql(u8, dev_digest[0..], buf_digest[0..]);
|
||||
}
|
Loading…
Reference in New Issue