Blocking External Table Reads

In addition to the code protection configuration bits, which restrict device programmers from reading back the content of program memory, some PIC18 devices implement external block table read configuration bits that offer an additional level of data protection at runtime. Enabling this feature prevents data within program memory blocks from being read by table read instructions that are located in other blocks.

To apply this protection, use the EBTRx config pragma setting, where x is a number that represents the program memory block, or is the letter B, representing the boot block. There is also the BBSIZ0 configuration bit, which controls the size of the boot block and which may also affect the range of block 0. For example to protect block 0 and use a 2k byte boot block use:

#pragma config EBTR0 = ON
#pragma config BBSIZ0 = BB2K

Your device data sheet will indicate how many blocks your device has and the address ranges these blocks cover. For example, enabling the EBTR0 setting on a 18Fx6K22 device will protect the program memory block from 0x1000 to 0x3FFF if the BBSIZ0 bits is set to BB2K. Once protected, any table read instruction inside block 0 can read bytes located within this same memory block, but those same bytes will not be accessible to any table read instruction located in another block.

One important consideration when using this feature is that the MPLAB® XC8 compiler stores const data and strings in program memory, and that this data has to be accessed using table read instructions. The compiler will not be aware that blocks have been made read protected by the configuration bit settings, and if the sections holding these data end up in a protected block, your code will almost certainly fail.

If you do want to use this feature, you must ensure that the protected blocks are used for the special data that you want to protect and the routines that read them, and that the protected blocks are not used for any other data. The easiest way to accomplish this is to reserve the memory taken up by the entire block or blocks you wish to protect, so that no other code or data will be placed in this region by the linker. Then you can explicitly place your protected data and read routines somewhere in this reserved area of memory.

Here’s how you might achieve this: place your protected data into a section with a name of your choosing, for example:

Do the same for your any routine that has to read this data or that needs to be located in the protected block.

Note that the routine above saves the table pointer registers (TBLPTR is comprised of 3 byte registers) before reading the data and restores them before returning. This is because the compiler might have preloaded some of the table pointer registers in the runtime startup code and assumes that they will not change during execution of the program. This assumption improves the performance of the program, but for situations when accessing const data that are located in special locations, as is the case when accessing data using the __section() specifier, the table pointer registers must be preserved to ensure that this assumption remains valid.

To reserve memory, use the —ROM compiler option, or the ROM ranges field in the project properties when using the MPLAB X IDE. Use the following ROM ranges argument to reserve block 0 on an 18F87K22 device with BBSIZ0 set to BB2K, so that the address range 0x1000 to 0x3FFF is removed from the linker’s classes and no code or data will be allocated to that region.

XC8 Linker > Memory model > ROM ranges: -1000-3FFF

Next define a linker class to represent the protected block or blocks, then place the code and data sections you have created into that class. This is performed using a process similar to that described in this article, so you might use the following options.

XC8 Linker > Additional options > Extra Linker Options:

-L-APROT_BLK0=1000-3fff  -L-Pebtr0_data=PROT_BLK0  -L-Pebtr0_code=PROT_BLK0

Alternatively, you could also link the sections without the use of a class, as in the following example which explicitly places the data at the beginning of the block and places the code immediately following.

-L-Pebtr0_data=01000h -L-Pebtr0_code=ebtr0_data

Check the map file (found in the <project>/dist/default/production folder for production builds) after you build to ensure that the data and code is linked where you intended, and that other areas of the protected block have not been populated.

© 2024 Microchip Technology, Inc.
Notice: ARM and Cortex are the registered trademarks of ARM Limited in the EU and other countries.
Information contained on this site regarding device applications and the like is provided only for your convenience and may be superseded by updates. It is your responsibility to ensure that your application meets with your specifications. MICROCHIP MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WHETHER EXPRESS OR IMPLIED, WRITTEN OR ORAL, STATUTORY OR OTHERWISE, RELATED TO THE INFORMATION, INCLUDING BUT NOT LIMITED TO ITS CONDITION, QUALITY, PERFORMANCE, MERCHANTABILITY OR FITNESS FOR PURPOSE. Microchip disclaims all liability arising from this information and its use. Use of Microchip devices in life support and/or safety applications is entirely at the buyer's risk, and the buyer agrees to defend, indemnify and hold harmless Microchip from any and all damages, claims, suits, or expenses resulting from such use. No licenses are conveyed, implicitly or otherwise, under any Microchip intellectual property rights.