Espruino loading source code from SD card?

Posted on
  • We have several customers that are located in a remote location like "Timbukto" and would like to protect our user application source file.

    Is there a easy way to put a hex code source file on the Espruino transflash drive and have it boot-up a new source code on a power-on reset?

    If not, it would be very cool to have this feature on the Espruino.

  • It's mighty hard to protect code on the Espruino... All they'd need to do is get on the console, hit ctrl+c if needed to break out of your code, and then type dump(); to get your code.

    Since the Espruino doesn't compile the code in any way, it would be hard to keep anyone who knew anything about the Espruino from ganking the code in it somehow.

  • As @DrAzzy says - because Espruino executes from source code, there are limits to how much you can 'hide' your code. However you can 'minify' your code, which (especially if you minify it yourself with more advanced optimisations turned on) will obfuscate it so much that nobody will be able to do anything useful with it.

    Have a quick google - there are a few options as obviously this comes up quite a lot with all the websites that use JavaScript and want to protect their IP.

    If you want to load code from the SD card (I guess you want to do this to allow quick upgrades?) it's as simple as writing a really simple bootloader and saving that to Espruino:

    function onInit() {
      eval(require('fs').readFile("boot.js"));­
    }
    

    If you want to make it more difficult for users to copy the code to another Espruino, you could look at encrypting the file somehow such that it can be decrypted with Espruino's unique ID (which you can get from process.env).

  • If you want to load code from the SD card (I guess you want to do this
    to allow quick upgrades?) it's as simple as writing a really simple
    bootloader and saving that to Espruino:

    Would be nice if this feature was built into the Espruino and all a user would have to do is to insert the transflash with the unique user ID with source code and just ground or tie to
    vcc a "pre-determined" GPIO pin. No PC required.

  • Yes, it'd be handy. It is only a single line to add though - and it allows you to put your own encryption in if you need to. If you're making a product with Espruino in it's trivial to include the bootloader code as part of the test that you'd have to make sure your hardware is working correctly.

    As Espruino is open source, adding some simple check to Espruino itself for the device's ID is useless as it's trivial for someone to compile a special version that just doesn't have that check and would run your code anyway.

  • OK, I agree the Espruino doesn't have JavaScript code protection without the user going to great lengths in writing specific code for encryption.

    On the second part, of the user writing a "simple bootloader" to the Espruino for
    auto-booting via transflash drive, is there anyone on this forum board ever attempted to write a simple bootloader for the Espruino? Any code examples are welcomed.

    function onInit() {
      exec(require('fs').readFile("boot.js"));­
    }
    

    BTW ... I hope I did not misunderstood that "boot.js" is actually the sd file user application code
    and not the bootloader code? (The bootloader code is the code above?)

  • I had considered doing some similar things in the past.

    I'd considered booting off of an EEPROM (not quite sure I remember why), and wrote some code for that, but never tested it.

    One of the things that makes it much more difficult is that (I don't know if your code is the same way) if I typed save(); while my code was running, the only thing I could be sure of is that it would not come up in a remotely usable state. And that'd be the case even if I didn't delete onInit() after it runs to save memory...

    I think that's what sank my old idea, I couldn't initialize it into a clean state to save() from. Oh! and thats why I was loading off of an eeprom, I could only use the flash for my javascript bootloader since there was no way for me to reinitialize it to a clean state to save() from. So effectively, that was ROM for me, and I needed some other sort of persistent memory. Hence going for EEPROM.

    I wonder how clean you could get it by having your onInit() code check for a signal that there's an update, and if so, delete all the functions and variables already defined, then load the files in (you'll need to break it up, as there's a limit on how large a chunk you can read from a file at once, and you can't pipe to exec() ), and those file swould recreate the stuff you deleted, and then you could have it save()?

    My conclusion was that you have to design your whole program to be amenable to this sort of thing.

  • So, writing a bootloader for the Espruino is not so simple after all.

  • That was my experience - I mean, the whole thing is trivially simple until you get to the part where you need a clean state to save();

    Having it read the code off the SD card every time would be a piece of cake.

    Actually, if that paradigm (having just bootloader save()'ed, and using some other sort of persistant storage for code) is okay, you could make it much harder on people trying to read the code by instead of using SD cards, have your bootloader load and run the code off of an EEPROM in a removable socket, and ship the code-update as a replacement EEPROM (or for lower security, put the new data on an SD card and have the bootloader first check for updates on SD card and apply them to EEPROM). Depending on how paranoid you were, you could grind off the part number on the EEPROM, or even put it on a little custom PCB that mixes up the pinouts and then dip that in black epoxy so people can't figure out what's in it or which pins to get on.

    That won't stop people from getting into the Espruino while it's running and perusing the code, though

  • Too bad, there isn't a "clean state" to save(); if someone ever created a simple SD/transflash bootloader for the Espruino. It would have been a very cool feature to automatically load the Espruino from SD and then execute after saving. (No PC required)

    As for code protection/encryption, it is not really worth the effort.

  • I don't really understand what you mean @DrAzzy... Do you have a simple example that doesn't work as you expect with something like the 'bootloader' code above?

  • What we were talking about was updating the code saved to the Espruino's flash.

    And my conclusion is that you can't really do that, because there's no way to get it back to the "clean" state you want to save(). You can of course have it load all it's code from the SD card every time it loads - that's easy - but then you need to keep the SD card in all the time.

    If you read what 7114 is asking about, he wants to be able to update the code stored on flash with save(); and have it automatically save and come out right. I don't think there's a way to do that that doesn't depend on writing the code to be amenable to that.

  • Ahh. That's not what I read it as. I assumed he would keep the SD card in at all times.

    If not I can see there would be problems - but to be honest a small card only costs maybe £2 in bulk so keeping one in isn't the end of the world.

  • Actually I just had a thought. Using the STM32Flash module you can do it pretty easily.

    If that is what you want I can come up with some example code.

  • You mean, by directly editing the part of the flash with the saved code? I'd love to see some example code for that!

  • Yes, that's the plan. I'll try and do something next week - it should be as easy as just copying the memory area to/from a file.

  • Yes, that's the plan. I'll try and do something next week - it should
    be as easy as just copying the memory area to/from a file.

    Just maybe, this task is much harder than Gordon thought?

  • Hmm... I was sure I'd posted this up a few days ago, but maybe I forgot to click submit:

    function saveToSD(filename) {
      var addr = process.memory().flash_code_start;
      var len = process.memory().flash_start + process.memory().flash_length - addr;
      var f = E.openFile(filename,"w");
      var block = new Uint32Array(512);
      addr -= 4;
      while (len>0) {
        block = block.map(function(v){return peek32(addr+=4);});
        f.write(block.buffer);
        len -= 2048;
      }
      f.close();
    }
    
    function loadFromSD(filename) {
      var addr = process.memory().flash_code_start;
      var len = process.memory().flash_start + process.memory().flash_length - addr;
      var rom = require("STM32F1Flash");
      rom.unlock();
      console.log("Erasing...");
      for (var i=0;i<len;i+=2048) {
        rom.erase(addr+i);
      }
      console.log("Writing...");
      var f = E.openFile(filename,"r");
      var block = new Uint32Array(512);
      addr -= 4;
      while (len>0) {
        console.log("0x"+(addr+4).toString(16));­
        new Uint8Array(block.buffer).set(f.read(2048­));
        block.forEach(function(v){rom.write(addr­+=4,v);});
        len -= 2048;
      }
      f.close();
    }
    

    So:

    • Get your program as you want it
    • Call save()
    • Load this script into Espruino and run saveToSD('myfile.bin');

    Then to load in a new Espruino:

    • Load the script and run loadFromSD('myfile.bin')

    So if you wanted to allow Espruino to auto-update, you'd make sure that the code that you saved on to flash contained something like this:

    function loadFromSD(filename) {
      var addr = process.memory().flash_code_start;
      var len = process.memory().flash_start + process.memory().flash_length - addr;
      var rom = require("STM32F1Flash");
      rom.unlock();
      console.log("Erasing...");
      for (var i=0;i<len;i+=2048) {
        rom.erase(addr+i);
      }
      console.log("Writing...");
      var f = E.openFile(filename,"r");
      var block = new Uint32Array(512);
      addr -= 4;
      while (len>0) {
        console.log("0x"+(addr+4).toString(16));­
        new Uint8Array(block.buffer).set(f.read(2048­));
        block.forEach(function(v){rom.write(addr­+=4,v);});
        len -= 2048;
      }
      f.close();
    }
    
    function onInit() {
      if (MYGPIO.read()) {
        LED1.set();
        loadFromSD('update.bin');
        LED1.reset();    
        LED2.set();    
      }
    }
    

    and then the process is:

    • Insert card
    • connect MYGPIO to 3.3v
    • reset Espruino
    • Wait until the red LED goes out and the green one lights
    • connect MYGPIO to 0v
    • reset Espruino
  • Hi @Gordon,

    function onInit() {
      exec(require('fs').readFile("boot.js"));­
    }
    

    i can't find any documentation about "exec". I tried it with my pico, but i just get

    Uncaught ReferenceError: "exec" is not defined at line 3 col 3
    exec();

    I would like to execute some code, that is stored on an connected sd card.
    What is missing? Could you help me with that?

    Thank you :)

  • Sorry, that was a typo - I've changed it now. I'm amazed nobody picked it up before :)

    It should be eval - then it'll work fine!

  • Hi @Gordon,

    oh great. Then everything is fine. I thought it is something special :P

    Thank you. Have a nice day.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Espruino loading source code from SD card?

Posted by Avatar for user7114 @user7114

Actions