Ejemplo n.º 1
0
//*****************************************************************************
//
// This example demonstrates how to configure MPU regions for different levels
// of memory protection.  The following memory map is set up:
//
// 0000.0000 - 0000.1C00 - rgn 0: executable read-only, flash
// 0000.1C00 - 0000.2000 - rgn 0: no access, flash (disabled sub-region 7)
// 0100.0000 - 0100.8000 - rgn 1: executable read-only, ROM
// 2000.0000 - 2000.8000 - rgn 2: read-write, RAM
// 2000.8000 - 2000.A000 - rgn 3: read-only, RAM (disabled sub-rgn 4 of rgn 1)
// 2000.A000 - 2000.FFFF - rgn 2: read-write, RAM
// 4000.0000 - 4001.0000 - rgn 4: read-write, peripherals
// 4001.0000 - 4002.0000 - rgn 4: no access (disabled sub-region 1)
// 4002.0000 - 4006.0000 - rgn 4: read-write, peripherals
// 4006.0000 - 4008.0000 - rgn 4: no access (disabled sub-region 6, 7)
// E000.E000 - E000.F000 - rgn 5: read-write, NVIC
//
// The example code will attempt to perform the following operations and check
// the faulting behavior:
//
// - write to flash                         (should fault)
// - read from the disabled area of flash   (should fault)
// - read from the read-only area of RAM    (should not fault)
// - write to the read-only section of RAM  (should fault)
//
//*****************************************************************************
int
main(void)
{
    unsigned int bFail = 0;

    //
    // Set the clocking to run directly from the crystal.
    //
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    //
    // Initialize the UART and write status.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioInit(0);
    UARTprintf("\033[2JMPU example\n");

    //
    // Configure an executable, read-only MPU region for flash.  It is an 8 KB
    // region with the last 1 KB disabled to result in a 7 KB executable
    // region.  This region is needed so that the program can execute from
    // flash.
    //
    ROM_MPURegionSet(0, FLASH_BASE,
                     MPU_RGN_SIZE_8K |
                     MPU_RGN_PERM_EXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO |
                     MPU_SUB_RGN_DISABLE_7 |
                     MPU_RGN_ENABLE);

    //
    // Configure an executable, read-only MPU region for ROM.  This region is
    // needed so that the program can execute DriverLib from ROM.
    //
    ROM_MPURegionSet(1, 0x01000000,
                     MPU_RGN_SIZE_32K |
                     MPU_RGN_PERM_EXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO |
                     MPU_RGN_ENABLE);

    //
    // Configure a read-write MPU region for RAM.  It is a 64+32 KB region.
    // There is a 8 KB sub-region in the middle that is disabled in order to
    // open up a hole in which different permissions can be applied.
    //
    ROM_MPURegionSet(2, SRAM_BASE,
                     MPU_RGN_SIZE_64K |
                     MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW |
                     MPU_SUB_RGN_DISABLE_4 |
                     MPU_RGN_ENABLE);
    ROM_MPURegionSet(3, SRAM_BASE + 65536,
                     MPU_RGN_SIZE_32K |
                     MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW |
                     MPU_SUB_RGN_DISABLE_4 |
                     MPU_RGN_ENABLE);

    //
    // Configure a read-only MPU region for the 8 KB of RAM that is disabled in
    // the previous region.  This region is used for demonstrating read-only
    // permissions.
    //
    ROM_MPURegionSet(4, SRAM_BASE + 0x8000,
                     MPU_RGN_SIZE_2K |
                     MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO |
                     MPU_RGN_ENABLE);

    //
    // Configure a read-write MPU region for peripherals.  The region is 512 KB
    // total size, with several sub-regions disabled to prevent access to areas
    // where there are no peripherals.  This region is needed because the
    // program needs access to some peripherals.
    //
    ROM_MPURegionSet(5, 0x40000000,
                     MPU_RGN_SIZE_512K |
                     MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW |
                     MPU_SUB_RGN_DISABLE_1 |
                     MPU_SUB_RGN_DISABLE_6 |
                     MPU_SUB_RGN_DISABLE_7 |
                     MPU_RGN_ENABLE);

    //
    // Configure a read-write MPU region for access to the NVIC.  The region is
    // 4 KB in size.  This region is needed because NVIC registers are needed
    // in order to control the MPU.
    //
    ROM_MPURegionSet(6, NVIC_BASE,
                     MPU_RGN_SIZE_4K |
                     MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW |
                     MPU_RGN_ENABLE);

    //
    // Need to clear the NVIC fault status register to make sure there is no
    // status hanging around from a previous program.
    //
    g_ulFaultStatus = HWREG(NVIC_FAULT_STAT);
    HWREG(NVIC_FAULT_STAT) = g_ulFaultStatus;

    //
    // Enable the MPU fault.
    //
    ROM_IntEnable(FAULT_MPU);

    //
    // Enable the MPU.  This will begin to enforce the memory protection
    // regions.  The MPU is configured so that when in the hard fault or NMI
    // exceptions, a default map will be used.  Neither of these should occur
    // in this example program.
    //
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    //
    // Attempt to write to the flash.  This should cause a protection fault due
    // to the fact that this region is read-only.
    //
    UARTprintf("Check flash write...");
    g_ulMPUFaultCount = 0;
    HWREG(0x100) = 0x12345678;

    //
    // Verify that the fault occurred, at the expected address.
    //
    if((g_ulMPUFaultCount == 1) &&
       (g_ulFaultStatus == 0x82) &&
       (g_ulMMAR == 0x100))
    {
        UARTprintf("OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("Fail\n");
    }

    //
    // The MPU was disabled when the previous fault occurred, so it needs to be
    // re-enabled.
    //
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    //
    // Attempt to read from the disabled section of flash, the upper 1 KB of
    // the 8 KB region.
    //
    UARTprintf("Check flash read...");
    g_ulMPUFaultCount = 0;
    g_ulValue = HWREG(0x1C10);

    //
    // Verify that the fault occurred, at the expected address.
    //
    if((g_ulMPUFaultCount == 1) &&
       (g_ulFaultStatus == 0x82) &&
       (g_ulMMAR == 0x1C10))
    {
        UARTprintf("OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("Fail\n");
    }

    //
    // The MPU was disabled when the previous fault occurred, so it needs to be
    // re-enabled.
    //
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    //
    // Attempt to read from the read-only area of RAM, the middle 8 KB of the
    // 64 KB region.
    //
    UARTprintf("Check RAM read...");
    g_ulMPUFaultCount = 0;
    g_ulValue = HWREG(0x20008440);

    //
    // Verify that the RAM read did not cause a fault.
    //
    if(g_ulMPUFaultCount == 0)
    {
        UARTprintf("OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("Fail\n");
    }

    //
    // The MPU should not have been disabled since the last access was not
    // supposed to cause a fault.  But if it did cause a fault, then the MPU
    // will be disabled, so re-enable it here anyway, just in case.
    //
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    //
    // Attempt to write to the read-only area of RAM, the middle 8 KB of the
    // 64 KB region.
    //
    UARTprintf("Check RAM write...");
    g_ulMPUFaultCount = 0;
    HWREG(0x20008460) = 0xabcdef00;

    //
    // Verify that the RAM write caused a fault.
    //
    if((g_ulMPUFaultCount == 1) &&
       (g_ulFaultStatus == 0x82) &&
       (g_ulMMAR == 0x20008460))
    {
        UARTprintf("OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("Fail\n");
    }

    //
    // Display the results of the example program.
    //
    if(bFail)
    {
        UARTprintf("Failure!\n");
    }
    else
    {
        UARTprintf("Success!\n");
    }

    //
    // Disable the MPU, so there are no lingering side effects if another
    // program is run.
    //
    ROM_MPUDisable();

    //
    // Finished.
    //
    while(1)
    {
    }
}
//*****************************************************************************
//
// This example demonstrates how to configure MPU regions for different levels
// of memory protection.  The following memory map is set up:
//
// 0000.0000 - 0000.1C00 - rgn 0: executable read-only, flash
// 0000.1C00 - 0000.2000 - rgn 0: no access, flash (disabled sub-region 7)
// 2000.0000 - 2000.4000 - rgn 1: read-write, RAM
// 2000.4000 - 2000.6000 - rgn 2: read-only, RAM (disabled sub-rgn 4 of rgn 1)
// 2000.6000 - 2000.7FFF - rgn 1: read-write, RAM
// 4000.0000 - 4001.0000 - rgn 3: read-write, peripherals
// 4001.0000 - 4002.0000 - rgn 3: no access (disabled sub-region 1)
// 4002.0000 - 4006.0000 - rgn 3: read-write, peripherals
// 4006.0000 - 4008.0000 - rgn 3: no access (disabled sub-region 6, 7)
// E000.E000 - E000.F000 - rgn 4: read-write, NVIC
// 0100.0000 - 0100.FFFF - rgn 5: executable read-only, ROM
//
// The example code will attempt to perform the following operations and check
// the faulting behavior:
//
// - write to flash                         (should fault)
// - read from the disabled area of flash   (should fault)
// - read from the read-only area of RAM    (should not fault)
// - write to the read-only section of RAM  (should fault)
//
//*****************************************************************************
int
main(void)
{
    unsigned int bFail = 0;

    // Enable lazy stacking for interrupt handlers.  This allows floating-point
    // instructions to be used within interrupt handlers, but at the expense of
    // extra stack usage.
    ROM_FPULazyStackingEnable();

    // Set the clocking to run directly from the crystal.
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_16MHZ);

    // Initialize the UART and write status.
    ConfigureUART();

    UARTprintf("\033[2JMPU example\n");

    // Configure an executable, read-only MPU region for flash.  It is a 16 KB
    // region with the last 2 KB disabled to result in a 14 KB executable
    // region.  This region is needed so that the program can execute from
    // flash.
    ROM_MPURegionSet(0, FLASH_BASE,
                     MPU_RGN_SIZE_16K | MPU_RGN_PERM_EXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO | MPU_SUB_RGN_DISABLE_7 |
                     MPU_RGN_ENABLE);

    // Configure a read-write MPU region for RAM.  It is a 32 KB region.  There
    // is a 4 KB sub-region in the middle that is disabled in order to open up
    // a hole in which different permissions can be applied.
    ROM_MPURegionSet(1, SRAM_BASE,
                     MPU_RGN_SIZE_32K | MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW | MPU_SUB_RGN_DISABLE_4 |
                     MPU_RGN_ENABLE);

    // Configure a read-only MPU region for the 4 KB of RAM that is disabled in
    // the previous region.  This region is used for demonstrating read-only
    // permissions.
    ROM_MPURegionSet(2, SRAM_BASE + 0x4000,
                     MPU_RGN_SIZE_2K | MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO | MPU_RGN_ENABLE);

    // Configure a read-write MPU region for peripherals.  The region is 512 KB
    // total size, with several sub-regions disabled to prevent access to areas
    // where there are no peripherals.  This region is needed because the
    // program needs access to some peripherals.
    ROM_MPURegionSet(3, 0x40000000,
                     MPU_RGN_SIZE_512K | MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW | MPU_SUB_RGN_DISABLE_1 |
                     MPU_SUB_RGN_DISABLE_6 | MPU_SUB_RGN_DISABLE_7 |
                     MPU_RGN_ENABLE);

    // Configure a read-write MPU region for access to the NVIC.  The region is
    // 4 KB in size.  This region is needed because NVIC registers are needed
    // in order to control the MPU.
    ROM_MPURegionSet(4, NVIC_BASE,
                     MPU_RGN_SIZE_4K | MPU_RGN_PERM_NOEXEC |
                     MPU_RGN_PERM_PRV_RW_USR_RW | MPU_RGN_ENABLE);

    // Configure an executable, read-only MPU region for ROM.  It is a 64 KB
    // region.  This region is needed so that ROM library calls work.
    ROM_MPURegionSet(5, (uint32_t)ROM_APITABLE & 0xFFFF0000,
                     MPU_RGN_SIZE_64K | MPU_RGN_PERM_EXEC |
                     MPU_RGN_PERM_PRV_RO_USR_RO | MPU_RGN_ENABLE);

    // Need to clear the NVIC fault status register to make sure there is no
    // status hanging around from a previous program.
    g_ui32FaultStatus = HWREG(NVIC_FAULT_STAT);
    HWREG(NVIC_FAULT_STAT) = g_ui32FaultStatus;

    // Enable the MPU fault.
    ROM_IntEnable(FAULT_MPU);

    // Enable the MPU.  This will begin to enforce the memory protection
    // regions.  The MPU is configured so that when in the hard fault or NMI
    // exceptions, a default map will be used.  Neither of these should occur
    // in this example program.
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    // Attempt to write to the flash.  This should cause a protection fault due
    // to the fact that this region is read-only.
    UARTprintf("Flash write... ");
    g_ui32MPUFaultCount = 0;
    HWREG(0x100) = 0x12345678;

    // Verify that the fault occurred, at the expected address.
    if((g_ui32MPUFaultCount == 1) && (g_ui32FaultStatus == 0x82) &&
       (g_ui32MMAR == 0x100))
    {
        UARTprintf(" OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("NOK\n");
    }

    // The MPU was disabled when the previous fault occurred, so it needs to be
    // re-enabled.
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    // Attempt to read from the disabled section of flash, the upper 2 KB of
    // the 16 KB region.
    UARTprintf("Flash read... ");
    g_ui32MPUFaultCount = 0;
    g_ui32Value = HWREG(0x3820);

    // Verify that the fault occurred, at the expected address.
    if((g_ui32MPUFaultCount == 1) && (g_ui32FaultStatus == 0x82) &&
       (g_ui32MMAR == 0x3820))
    {
        UARTprintf(" OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("NOK\n");
    }

    // The MPU was disabled when the previous fault occurred, so it needs to be
    // re-enabled.
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    // Attempt to read from the read-only area of RAM, the middle 4 KB of the
    // 32 KB region.
    UARTprintf("RAM read... ");
    g_ui32MPUFaultCount = 0;
    g_ui32Value = HWREG(0x20004440);

    // Verify that the RAM read did not cause a fault.
    if(g_ui32MPUFaultCount == 0)
    {
        UARTprintf(" OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("NOK\n");
    }

    // The MPU should not have been disabled since the last access was not
    // supposed to cause a fault.  But if it did cause a fault, then the MPU
    // will be disabled, so re-enable it here anyway, just in case.
    ROM_MPUEnable(MPU_CONFIG_HARDFLT_NMI);

    // Attempt to write to the read-only area of RAM, the middle 4 KB of the
    // 32 KB region.
    UARTprintf("RAM write... ");
    g_ui32MPUFaultCount = 0;
    HWREG(0x20004460) = 0xabcdef00;

    //
    // Verify that the RAM write caused a fault.
    //
    if((g_ui32MPUFaultCount == 1) && (g_ui32FaultStatus == 0x82) &&
       (g_ui32MMAR == 0x20004460))
    {
        UARTprintf(" OK\n");
    }
    else
    {
        bFail = 1;
        UARTprintf("NOK\n");
    }

    // Display the results of the example program.
    if(bFail)
    {
        UARTprintf("Failure!\n");
    }
    else
    {
        UARTprintf("Success!\n");
    }

    // Disable the MPU, so there are no lingering side effects if another
    // program is run.
    ROM_MPUDisable();

    // Loop forever.
    while(1);
}