Compare commits

..

No commits in common. "master" and "brandon" have entirely different histories.

5 changed files with 1 additions and 809 deletions

View file

@ -1,9 +1,6 @@
MIT License
Copyright (c) 2018 AGORISE, LTD.
An International Business Company, Cyprus Reg# ΗΕ375959
Contains works from BitShares Munich IVS
Copyright (c) 2017 BitShares Munich IVS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,80 +0,0 @@
#*******************************************************************************
# Ledger Blue
# (c) 2016 Ledger
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#*******************************************************************************
ifeq ($(BOLOS_SDK),)
$(error BOLOS_SDK is not set)
endif
include $(BOLOS_SDK)/Makefile.defines
# Main app configuration
APPNAME = "Hello Perso"
APPVERSION = 1.0.0
APP_LOAD_PARAMS = --appFlags 0x40 $(COMMON_LOAD_PARAMS)
# Build configuration
APP_SOURCE_PATH += src
SDK_SOURCE_PATH += lib_stusb lib_stusb_impl
DEFINES += APPVERSION=\"$(APPVERSION)\"
DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=128
DEFINES += HAVE_BAGL HAVE_SPRINTF
DEFINES += PRINTF\(...\)=
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
# Compiler, assembler, and linker
ifneq ($(BOLOS_ENV),)
$(info BOLOS_ENV=$(BOLOS_ENV))
CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
else
$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH)
endif
ifeq ($(CLANGPATH),)
$(info CLANGPATH is not set: clang will be used from PATH)
endif
ifeq ($(GCCPATH),)
$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH)
endif
CC := $(CLANGPATH)clang
CFLAGS += -O3 -Os
AS := $(GCCPATH)arm-none-eabi-gcc
AFLAGS +=
LD := $(GCCPATH)arm-none-eabi-gcc
LDFLAGS += -O3 -Os
LDLIBS += -lm -lgcc -lc
# Main rules
all: default
load: all
python -m ledgerblue.loadApp $(APP_LOAD_PARAMS)
delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
# Import generic rules from the SDK
include $(BOLOS_SDK)/Makefile.rules

View file

@ -1,61 +0,0 @@
# Notes on Hello Perso sample app.
Hello Perso is a sample app from the LedgerHQ repository
[blue-sample-apps](https://github.com/LedgerHQ/blue-sample-apps). It's
stated purpose is to be a "a simple application showing the UI and master
seed derivation."
### Compiling:
Compiles fine inside Docker image, as in the process described in the
[Getting Started](http://ledger.readthedocs.io/en/latest/nanos/setup.html)
tutorial (which takes you through the Hello World tutorial).
In extracting the hex-encoded compiled app from the docker container to my
local machine, I changed the app name as follows:
``` bash
sudo docker cp [container_id]:/home/blue-sample-apps/blue-app-helloperso/bin/app.hex perso-app.hex
```
I then loaded the app onto the Nano S using the following, and then
discovered a problem:
``` bash
python -m ledgerblue.loadApp --targetId 0x31100002 --apdu --fileName perso-app.hex --appName HelloPerso --appFlags 0x00 --icon ""
```
The problem: Hello Perso app requires the `APPLICATION_FLAG_GLOBAL_PIN`
permission flag. I had just copied and pasted my loadApp command line for
HelloWorld and changed the app name and image name. But the `--appFlags`
argument needed to be changed to `--appFlags 0x40`.
Symptoms: With the wrong permissions set, even though the app was
successfuly loaded onto the device, it would freeze the Nano every
time I started the app, requiring a power-cycle to get back to the
dashboard.
The correct load command was:
``` bash
python -m ledgerblue.loadApp --targetId 0x31100002 --apdu --fileName perso-app.hex --appName HelloPerso --appFlags 0x40 --icon ""
```
### How to remove apps:
Problem Two: Repeating the loadApp() command with the correct flags failed
because the app already existed on the device. It apparently won't
overwrite. Thus I had to find a delete command, which fortunately is
referenced in the Makefile. To manually delete the app, this is the
command:
``` bash
python -m ledgerblue.deleteApp --targetId 0x31100002 --appName HelloPerso
```
### Permission flags defined:
The `0x40` permission flag that was needed is defined by macro constant
`APPLICATION_FLAG_GLOBAL_PIN` in
[nanos-secure-sdk/include/os.h](https://github.com/LedgerHQ/nanos-secure-sdk/blob/master/include/os.h),
along with many other application flags.

View file

@ -1,574 +0,0 @@
/*******************************************************************************
* Ledger Blue
* (c) 2016 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "os.h"
#include "cx.h"
#include <stdbool.h>
#include "os_io_seproxyhal.h"
unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
static const bagl_element_t *io_seproxyhal_touch_exit(const bagl_element_t *e);
static const bagl_element_t *io_seproxyhal_touch_next(const bagl_element_t *e);
static const bagl_element_t *io_seproxyhal_touch_auth(const bagl_element_t *e);
static bool derive(void);
static void ui_idle(void);
static char address[100];
static unsigned int path[5];
ux_state_t ux;
static const char NOT_AVAILABLE[] = "Not available";
// ********************************************************************************
// Ledger Blue specific UI
// ********************************************************************************
#ifdef TARGET_BLUE
static const bagl_element_t const bagl_ui_sample_blue[] = {
// {
// {type, userid, x, y, width, height, stroke, radius, fill, fgcolor,
// bgcolor, font_id, icon_id},
// text,
// touch_area_brim,
// overfgcolor,
// overbgcolor,
// tap,
// out,
// over,
// },
{
{BAGL_RECTANGLE, 0x00, 0, 60, 320, 420, 0, 0, BAGL_FILL, 0xf9f9f9,
0xf9f9f9, 0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_RECTANGLE, 0x00, 0, 0, 320, 60, 0, 0, BAGL_FILL, 0x1d2028,
0x1d2028, 0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_LABEL, 0x00, 20, 0, 320, 60, 0, 0, BAGL_FILL, 0xFFFFFF, 0x1d2028,
BAGL_FONT_OPEN_SANS_LIGHT_14px | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"Hello Perso",
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_LABEL, 0x00, 20, 100, 320, 60, 0, 0, 0, 0, 0xF9F9F9F9,
BAGL_FONT_OPEN_SANS_LIGHT_13px | BAGL_FONT_ALIGNMENT_CENTER, 0},
address,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 165, 225, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9, BAGL_FONT_OPEN_SANS_LIGHT_14px |
BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"EXIT",
0,
0x37ae99,
0xF9F9F9,
io_seproxyhal_touch_exit,
NULL,
NULL,
},
{
{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 165, 280, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9, BAGL_FONT_OPEN_SANS_LIGHT_14px |
BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"NEXT",
0,
0x37ae99,
0xF9F9F9,
io_seproxyhal_touch_next,
NULL,
NULL,
},
{
{BAGL_BUTTON | BAGL_FLAG_TOUCHABLE, 0x00, 165, 335, 120, 40, 0, 6,
BAGL_FILL, 0x41ccb4, 0xF9F9F9, BAGL_FONT_OPEN_SANS_LIGHT_14px |
BAGL_FONT_ALIGNMENT_CENTER | BAGL_FONT_ALIGNMENT_MIDDLE, 0},
"AUTH",
0,
0x37ae99,
0xF9F9F9,
io_seproxyhal_touch_auth,
NULL,
NULL,
},
};
static unsigned int
bagl_ui_sample_blue_button(unsigned int button_mask,
unsigned int button_mask_counter) {
return 0;
}
#endif
// ********************************************************************************
// Ledger Nano S specific UI
// ********************************************************************************
#ifdef TARGET_NANOS
static const bagl_element_t bagl_ui_sample_nanos[] = {
// {
// {type, userid, x, y, width, height, stroke, radius, fill, fgcolor,
// bgcolor, font_id, icon_id},
// text,
// touch_area_brim,
// overfgcolor,
// overbgcolor,
// tap,
// out,
// over,
// },
{
{BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000,
0xFFFFFF, 0, 0},
NULL,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_LABELINE, 0x02, 0, 12, 128, 11, 0, 0, 0, 0xFFFFFF, 0x000000,
BAGL_FONT_OPEN_SANS_REGULAR_11px | BAGL_FONT_ALIGNMENT_CENTER, 0},
"Address",
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_LABELINE, 0x02, 23, 26, 82, 11, 0x80 | 10, 0, 0, 0xFFFFFF,
0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px |
BAGL_FONT_ALIGNMENT_CENTER, 26},
address,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0,
BAGL_GLYPH_ICON_CROSS},
NULL,
0,
0,
0,
NULL,
NULL,
NULL,
},
{
{BAGL_ICON, 0x00, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0,
BAGL_GLYPH_ICON_CHECK},
NULL,
0,
0,
0,
NULL,
NULL,
NULL,
},
};
static const bagl_element_t*
bagl_ui_sample_nanos_prepro(const bagl_element_t *element) {
switch (element->component.userid) {
case 2:
io_seproxyhal_setup_ticker(
MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7)));
break;
}
return element;
}
static unsigned int
bagl_ui_sample_nanos_button(unsigned int button_mask,
unsigned int button_mask_counter) {
switch (button_mask) {
case BUTTON_EVT_RELEASED | BUTTON_LEFT:
io_seproxyhal_touch_auth(NULL);
break;
case BUTTON_EVT_RELEASED | BUTTON_RIGHT:
io_seproxyhal_touch_next(NULL);
break;
case BUTTON_EVT_RELEASED | BUTTON_LEFT | BUTTON_RIGHT: // EXIT
io_seproxyhal_touch_exit(NULL);
break;
}
return 0;
}
#endif
static const bagl_element_t *io_seproxyhal_touch_exit(const bagl_element_t *e) {
// Go back to the dashboard
os_sched_exit(0);
return NULL;
}
static const bagl_element_t *io_seproxyhal_touch_next(const bagl_element_t *e) {
path[4]++;
if (!derive()) {
path[4]--;
}
ui_idle();
return NULL;
}
static const bagl_element_t *io_seproxyhal_touch_auth(const bagl_element_t *e) {
if (!os_global_pin_is_validated()) {
bolos_ux_params_t params;
os_memset(&params, 0, sizeof(params));
params.ux_id = BOLOS_UX_VALIDATE_PIN;
os_ux_blocking(&params);
derive();
ui_idle();
}
return NULL;
}
unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
switch (channel & ~(IO_FLAGS)) {
case CHANNEL_KEYBOARD:
break;
// multiplexed io exchange over a SPI channel and TLV encapsulated protocol
case CHANNEL_SPI:
if (tx_len) {
io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
if (channel & IO_RESET_AFTER_REPLIED) {
reset();
}
return 0; // nothing received from the master so far (it's a tx
// transaction)
} else {
return io_seproxyhal_spi_recv(G_io_apdu_buffer,
sizeof(G_io_apdu_buffer), 0);
}
default:
THROW(INVALID_PARAMETER);
}
return 0;
}
static void ui_idle(void) {
#ifdef TARGET_BLUE
UX_DISPLAY(bagl_ui_sample_blue, NULL);
#else
UX_DISPLAY(bagl_ui_sample_nanos, bagl_ui_sample_nanos_prepro);
#endif
}
static void sample_main(void) {
volatile unsigned int rx = 0;
volatile unsigned int tx = 0;
volatile unsigned int flags = 0;
// DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only
// goal is to retrieve APDU.
// When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make
// sure the io_event is called with a
// switch event, before the apdu is replied to the bootloader. This avoid
// APDU injection faults.
for (;;) {
volatile unsigned short sw = 0;
BEGIN_TRY {
TRY {
rx = tx;
tx = 0; // ensure no race in catch_other if io_exchange throws
// an error
rx = io_exchange(CHANNEL_APDU | flags, rx);
flags = 0;
// no apdu received, well, reset the session, and reset the
// bootloader configuration
if (rx == 0) {
THROW(0x6982);
}
if (G_io_apdu_buffer[0] != 0x80) {
THROW(0x6E00);
}
// unauthenticated instruction
switch (G_io_apdu_buffer[1]) {
case 0x00: // reset
flags |= IO_RESET_AFTER_REPLIED;
THROW(0x9000);
break;
case 0x01: // case 1
THROW(0x9000);
break;
case 0x02: // echo
tx = rx;
THROW(0x9000);
break;
case 0xFF: // return to dashboard
goto return_to_dashboard;
default:
THROW(0x6D00);
break;
}
}
CATCH_OTHER(e) {
switch (e & 0xF000) {
case 0x6000:
case 0x9000:
sw = e;
break;
default:
sw = 0x6800 | (e & 0x7FF);
break;
}
// Unexpected exception => report
G_io_apdu_buffer[tx] = sw >> 8;
G_io_apdu_buffer[tx + 1] = sw;
tx += 2;
}
FINALLY {
}
}
END_TRY;
}
return_to_dashboard:
return;
}
void io_seproxyhal_display(const bagl_element_t *element) {
io_seproxyhal_display_default((bagl_element_t *)element);
}
unsigned char io_event(unsigned char channel) {
// nothing done with the event, throw an error on the transport layer if
// needed
// can't have more than one tag in the reply, not supported yet.
switch (G_io_seproxyhal_spi_buffer[0]) {
case SEPROXYHAL_TAG_FINGER_EVENT:
UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
break;
case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: // for Nano S
UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
break;
case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
if (UX_DISPLAYED()) {
// TODO perform actions after all screen elements have been
// displayed
} else {
UX_DISPLAYED_EVENT();
}
break;
case SEPROXYHAL_TAG_TICKER_EVENT:
UX_REDISPLAY();
break;
// unknown events are acknowledged
default:
break;
}
// close the event if not done previously (by a display or whatever)
if (!io_seproxyhal_spi_is_status_sent()) {
io_seproxyhal_general_status();
}
// command has been processed, DO NOT reset the current APDU transport
return 1;
}
static const char BASE58ALPHABET[] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
static unsigned int encode_base58(const void *in, unsigned int length,
char *out, unsigned int maxoutlen) {
char tmp[164];
char buffer[164];
unsigned char j;
unsigned char startAt;
unsigned char zeroCount = 0;
if (length > sizeof(tmp)) {
THROW(INVALID_PARAMETER);
}
os_memmove(tmp, in, length);
while ((zeroCount < length) && (tmp[zeroCount] == 0)) {
++zeroCount;
}
j = 2 * length;
startAt = zeroCount;
while (startAt < length) {
unsigned short remainder = 0;
unsigned char divLoop;
for (divLoop = startAt; divLoop < length; divLoop++) {
unsigned short digit256 = (unsigned short)(tmp[divLoop] & 0xff);
unsigned short tmpDiv = remainder * 256 + digit256;
tmp[divLoop] = (unsigned char)(tmpDiv / 58);
remainder = (tmpDiv % 58);
}
if (tmp[startAt] == 0) {
++startAt;
}
buffer[--j] = BASE58ALPHABET[remainder];
}
while ((j < (2 * length)) && (buffer[j] == BASE58ALPHABET[0])) {
++j;
}
while (zeroCount-- > 0) {
buffer[--j] = BASE58ALPHABET[0];
}
length = 2 * length - j;
if (maxoutlen < length) {
THROW(EXCEPTION_OVERFLOW);
}
os_memmove(out, (buffer + j), length);
return length;
}
static bool derive() {
cx_ecfp_private_key_t privateKey;
cx_ecfp_public_key_t publicKey;
union {
cx_sha256_t shasha;
cx_ripemd160_t riprip;
} u;
unsigned char privateKeyData[32];
unsigned char tmp[25];
unsigned int length;
if (!os_global_pin_is_validated()) {
os_memmove(address, NOT_AVAILABLE, sizeof(NOT_AVAILABLE));
return false;
}
os_perso_derive_node_bip32(CX_CURVE_256K1, path, 5, privateKeyData, NULL);
cx_ecdsa_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
cx_ecfp_generate_pair(CX_CURVE_256K1, &publicKey, &privateKey, 1);
publicKey.W[0] = ((publicKey.W[64] & 1) ? 0x03 : 0x02);
cx_sha256_init(&u.shasha);
cx_hash(&u.shasha.header, CX_LAST, publicKey.W, 33, privateKeyData);
cx_ripemd160_init(&u.riprip);
cx_hash(&u.riprip.header, CX_LAST, privateKeyData, 32, tmp + 1);
tmp[0] = 0;
cx_sha256_init(&u.shasha);
cx_hash(&u.shasha.header, CX_LAST, tmp, 21, privateKeyData);
cx_sha256_init(&u.shasha);
cx_hash(&u.shasha.header, CX_LAST, privateKeyData, 32, privateKeyData);
os_memmove(tmp + 21, privateKeyData, 4);
length = encode_base58(tmp, sizeof(tmp), address, sizeof(address));
address[length] = '\0';
return true;
}
__attribute__((section(".boot"))) int main(void) {
// exit critical section
__asm volatile("cpsie i");
// ensure exception will work as planned
os_boot();
UX_INIT();
BEGIN_TRY {
TRY {
io_seproxyhal_init();
// Invalidate the current authentication to demonstrate
// reauthentication
// Reauthenticate with "Auth" (Blue) or left button (Nano S)
os_global_pin_invalidate();
#ifdef LISTEN_BLE
if (os_seph_features() &
SEPROXYHAL_TAG_SESSION_START_EVENT_FEATURE_BLE) {
BLE_power(0, NULL);
// restart IOs
BLE_power(1, NULL);
}
#endif
USB_power(0);
USB_power(1);
path[0] = 44 | 0x80000000;
path[1] = 0 | 0x80000000;
path[2] = 0 | 0x80000000;
path[3] = 0;
path[4] = 0;
derive();
ui_idle();
sample_main();
}
CATCH_OTHER(e) {
}
FINALLY {
}
}
END_TRY;
}

View file

@ -1,90 +0,0 @@
# Some Background for getting started developing for Nano S
### Relevent Repositories
**The development SDK:** contains header and library files for compiling
Nano S applications. Located at:
[LedgerHQ/nanos-secure-sdk](https://github.com/LedgerHQ/nanos-secure-sdk).
**Python Tools for Ledger Blue and Nano S:** These contain tools for loading
apps onto the Nano S, and basic communication between Nano S and a python
interface on the computer. Located at:
[LedgerHQ/blue-loader-python](https://github.com/LedgerHQ/blue-loader-python).
* The various python scripts are documented reasonably well at:
[Script Reference](https://ledger.readthedocs.io/projects/blue-loader-python/en/0.1.15/script_reference.html)
**Sample Apps:** These provide examples of basic operations on the Nano S
device. Located at:
[LedgerHQ/blue-sample-apps](https://github.com/LedgerHQ/blue-sample-apps).
### Documentation
Comprehensive developer documentation does not seem to be available yet (but
is expected). Some very good general overview information for developers on
the way the BOLOS operating system and apps work and interact is located
here, however:
[Ledger Documentation Hub](http://ledger.readthedocs.io/en/latest/index.html).
A tutorial for building, installing, and running the Hello World sample app
is located here: (part of the docs mentioned above)
[Getting started](http://ledger.readthedocs.io/en/latest/nanos/setup.html).
It may be slightly out of date.
## Notes and tidbits
### Hardware memory and executable formats
Some basic info about the Nano S execution environment memory specs and
layout can be divined by looking at the linker scripts `script.ld` and
`script.ux.ld` in the SDK at
[LedgerHQ/nanos-secure-sdk](https://github.com/LedgerHQ/nanos-secure-sdk).
Note, what follows here comes from my *very fuzzy* understanding of the
linking and loading process and of the BOLOS architecture, and thus is
conjectural and could be very wrong, but... from these scripts it can be
devined, e.g., that UX code (I think this is BOLOS-provided library code
with different security priveledges that the app developer doesn't write,
but this is a pure guess) is loaded into a 2 kB window with a 768 byte
(wow!) stack size; and that application code is loaded into a 4 kB window
with another 768 byte stack. Obviously, this is an *extrememly* tight
execution envirement.
Some wiggle-room is provided by the fact that there is also a read-only (to
the application) non-volatile flash ram window of 400 kB. According to docs
at
[(Ledger docs)](http://ledger.readthedocs.io/en/latest/userspace/memory.html),
the executable code and const-declared variables are stored here, so that
the limited available volatile ram is not used up for this. And also, a
mechanism is provided to carve off *some* of the ro nvram as rw so that apps
can keep some persistant storage.
I actally have no idea how to read these linker scripts, so my conclusions
here are "as best I understand them." There is some documentation on linker
scripts here:
[LD Scripts](https://sourceware.org/binutils/docs/ld/Scripts.html).
Another interesting oddity: the link script places "RAM-initialized
variables" into a memory region titled DISCARD and apparently mapped to a
non-existent region of address-space on the Nano. This would have the
effect of just vaporizing ram-initialized variables altogether, I would
(naively??) think. It's weird, but I do think this is exactly what it does,
because the BOLOS documentation includes this warning:
> Initializers of global non-const variables (including NVRAM variables) are
> ignored. As such, this data must be initialized by application code.
So global data cannot have initializers. Got it. Couldn't tell you why, but
got it. :thumbsup:.
Another point: BOLOS code, being embedded, makes frequent use of the
**volatile** keyword. For some reminders of when/what/why `volatile` is
used, here are two links that came up in my google search:
* [How to Use C's volatile Keyword](https://barrgroup.com/Embedded-Systems/How-To/C-Volatile-Keyword)
* [Nine ways to break your systems code using volatile](https://blog.regehr.org/archives/28)
Ah, one reason for such frequent use of `volatile` is the TRY/CATCH macros
evidently can confuse the optimizer in some way. For this reason, it is
recommended to declare variables that may be modified inside
try/catch/finally contexts as `volatile`. Referenced in the docs here:
[Error Handling](http://ledger.readthedocs.io/en/latest/userspace/troubleshooting.html#error-handling).