• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

'Реверс' SDK Espressif и ROM-BIOS для создания открытого SDK.

pvvx

Активный участник сообщества
Можем завести отдельный репозиторий на гитхабе под это направление, чтобы больше людей могло участвовать в процессе, т.к. работа очень большая и в одиночку ее сделать почти не реально.
На сегодня частичная сборка переведенных исходников SDK, для запуска моего Web, тут:
https://github.com/pvvx/esp8266web
Загрузчик SDK составлен из переписанных кусков libmain.a
Перевод BIOS и интересовавших кусков SDK в info/libs (это не подлежит трансляции - чисто для инфы)
Открытый LwIP использован v1.4.0
Стыковка его с SDK 1.1.2 в файле eagle_lwip_if.c
Заголовки процедур ROM-BIOS тут , по самому чипу тут
Начал вырезать лишний код из libphy.a . Но там связи по переменным и для трансляции необходимо сразу всё из неё переработать.
C новым патчем для SDK 1.1.2 есть и беда с WDT - китайцы вписали переустановку своего таймера по изменению режима sleep для WiFi и он отключает другие варианты обработки... Тоже надо доделывать до конца libmain.a:user_interface.o, но он такой кривой, что для OpenSDK из него взять нечего и пока необходим только для поддержки китай-глюка-SDK.
---
Загрузчик+SDK без WiFi:
https://github.com/pvvx/SDKnoWiFi
Полностью открытая система на ESP8266.
Создается в основном для обработки датчиков в режиме deep_sleep и других малопотребляющих режимах с последующим запуском обычной SDK для передачи набранных данных.
Может использовать ESP8266 в качестве обычного микроконтроллера* с загрузкой Arduino и прочих систем, таких как интерпретатор Lua с целью получения максимальной RAM и т.д..
*как второй ESP8266 в системе для унификации, вместо всяких "АрДурин".
---
Все данные, включая указанные git не имеют никаких лицензий в отличии от других. Ограничение в использовании и копировании одно - как можно менее упоминать меня, а замещать своими (с) :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Начало тему раскидано по форуму и будет продолжаться тут.
Данное сообщение пока зарезервировано для дальнейшего изменения в соответствии с темой.
Предыстория вопроса:
http://esp8266.ru/forum/threads/smi...abotki-proshivok-esp8266.167/page-4#post-4909
Просьба модераторам перенести сообщения сюда...
 

pvvx

Активный участник сообщества
Первым делом предполагается создание отдельной системы 'хидеров' для СИ с полным описанием заголовков процедур и форматов ROM-BIOS, а так-же и оборудования чипа (что возможно) без "вкрапления" процедур и данных из SDK Espressif. Это требуется для создания загрузчиков и альтернативных систем на модуле и возможности загружать разные готовые "прошивки" с большой flash на ходу.
У меня данное дело пока встало на изменении PLL CLK CPU, т.к. ROM-BIOS считает, что у неё кварц на 40 MHz, а не как на большинстве модулей (26 MHz). В итоге и скорость UART 74880 Baud, а не 115200 (115200*26/40=74880)...
Интересно, что время загрузки первого блока из flash и его старта напрямую зависит от кол-ва блоков в заголовке flash. Происходит тормоз на выводе в UART с 74880 Baud сообщений по каждому загружаемому блоку. Их у нас по "стандарту" имеющихся сборщиков и программаторов всегда 3 шт. Но если указать 0 - то ROM-BIOS грузит один первый блок и не выводит сообщений, что значительно ускоряет процесс старта до исполнения первых пользовательских команд в загруженном куске. Итог около 30 ms и уже можно включить "кеширование" flash и использовать процедуры из неё...
Весь код "загрузчика" до старта "кеширования":
Код:
//=============================================================================
// IRAM code
//=============================================================================
// call_user_start() - вызов из заголовка, загрузчиком
// ENTRY(call_user_start) in eagle.app.v6.ld
//-----------------------------------------------------------------------------
void call_user_start(void)
{
       // Загрзука заголовка flash
       struct SPIFlashHead fhead;
        SPI0_USER |= SPI_CS_SETUP; // +1 такт перед CS
        SPIRead(0, (uint32_t *)&fhead, sizeof(fhead));
        // Установка размера Flash от 256Kbytes до 32Mbytes
        // High four bits fhead.hsz.flash_size: 0 = 512K, 1 = 256K, 2 = 1M, 3 = 2M, 4 = 4M, ... 7 = 32M
       uint32 fsize = fhead.hsz.flash_size & 7;
        if(fsize < 2) flashchip->chip_size = (8 >> fsize) << 16;
        else flashchip->chip_size = (4 << fsize) << 16;
       uint32 fspeed = fhead.hsz.spi_freg;
        // Установка:
        // SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT)
        // and Speed QSPI: 0 = 40MHz, 1= 26MHz, 2 = 20MHz, ... = 80MHz
        sflash_something(fspeed);
        // SPIFlashCnfig(fhead.spi_interface & 3, (speed > 2)? 1 : speed + 2);
        // SPIReadModeCnfig(5); // in ROM
        // Всё - включаем кеширование, далее можно вызывать процедуры из flash
        Cache_Read_Enable(0,0,1);
        // Инициализация
        startup(); // <-- там уже исполняются программы из Flash
        // Передача управления ROM-BIOS
        ets_run();
}
//-----------------------------------------------------------------------------
// Установка скорости QSPI
//  0 = 40MHz, 1 = 26MHz, 2 = 20MHz, >2 = 80MHz
//-----------------------------------------------------------------------------
void sflash_something(uint32 flash_speed)
{
    //    Flash QIO80:
    //  SPI_CTRL = 0x16ab000 : QIO_MODE | TWO_BYTE_STATUS_EN | WP_REG | SHARE_BUS | ENABLE_AHB | RESANDRES | FASTRD_MODE | BIT12
    //    IOMUX_BASE = 0x305
    //  Flash QIO40:
    //    SPI_CTRL = 0x16aa101
    //    IOMUX_BASE = 0x205
    uint32 xreg = (SPI0_CTRL >> 12) << 12; //  & 0xFFFFF000
    uint32 value;
    if (flash_speed > 2) { // 80 MHz
        value = BIT(12); // 0x60000208 |= 0x1000
        GPIO_MUX_CFG |= (1<< MUX_SPI0_CLK_BIT); // HWREG(IOMUX_BASE, 0) |= BIT(8);  // 80 MHz
    }
    else { // 0:40, 1:26, 2:20 MHz // 0x101, 0x202, 0x313
        value = 1 + flash_speed + ((flash_speed + 1) << 8) + ((flash_speed >> 1)<< 4);
        xreg &= ~BIT(12);  // 0x60000208 &= 0xffffefff
        GPIO_MUX_CFG &= MUX_CFG_MASK & (~(1<< MUX_SPI0_CLK_BIT)); // HWREG(IOMUX_BASE, 0) &= ~(BIT(8));  // 0x60000800 &=  0xeff
    }
    SPI0_CTRL = xreg | value;
}
В заголовке flash ставится кол-во блоков загрузки = 0. Тогда нет сообщения ROM-BIOS о всяких контрольках и загрузках, на что уходит очень много времени на вывод их в UART на скорости 74880 Baud *. Итого от включения (reset или deep-sleep), до startup() проходит всего ~30 ms.
Заголовки пока можно найти в Разработка ‘библиотеки’ малого webсервера на esp8266.
* ROM-BIOS выводи сообщения в UART без fifo. Т.е. каждый новый символ перед выводом ожидает полного опустошения TX fifo UART:
Код:
// ROM:40003B30
int uart_tx_one_char(uint8 ch)
{
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    while(uartregs[IDX_UART_STATUS] & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S));
    uartregs[IDX_UART_FIFO] = ch;
    return 0;
}
 
Последнее редактирование:

Sonic

New member
Предполагается сделать полное описание функций из eagle.rom.addr.v6.ld c описанием аргументов, назначением адресов и логикой работы? По возможности с примерным кодом C тела функций?
 

pvvx

Активный участник сообщества
Предполагается сделать полное описание функций из eagle.rom.addr.v6.ld c описанием аргументов, назначением адресов и логикой работы? По возможности с примерным кодом C тела функций?
Хотя-бы заголовки, а то вообще ничего нет.
Вместо описания, я обычно включаю IDA и смотрю, что они делают.
Ещё не организовано "место и система сбора" где эти заголовки будут собираться. Т.е. пока этим озабочен я один, а мне легче это делать в своей "свалке".
 

anakod

Moderator
Команда форума
pvvx, давайте подготовим краткий список ссылок по базовому введению в структуру SDK и процесс декомопиляции - какие плагины ставить, какие инструменты использовать. Это будет хорошей отправной точкой для всех кто будет готов помочь. Вы вроде уже писали по этой теме, можно здесь просто собрать подборку ссылок.
 

pvvx

Активный участник сообщества
anakod -
Дело в том, что путей дизассемблирования несколько, и каждый случай имеет свои варианты.

Для реверса ROM-BIOS ещё возможно что-то указать, но для совместного дизассемблирования некой прошивки+ ROM-BIOS необходимо создавать специальные скрипты и вариантов и предпочтений бесчисленное множество.

Как итог, можно описать базовый вариант дизассемблирования только ROM-BIOS и только ELF файла прошивки с SDK. Совмещать их сложно и требуется (очень желательно) считывание всей памяти и регистров из чипа в базу IDA. Без этого очень сложно понять, что за данные и зачем туда обращается некий код. А при видимом содержимом разбор десятикратно упрощается. Для считывания всех данных надо писать специальную программу в сам чип. Тем более версий SDK множество и они обновляются – на всё дать готовые скрипты для IDA не выйдет.
Базы IDA выходят большими и выкладывать их в сеть нет смысла.

ELF файл просто грузится в IDA и она сама там всё разберет, но данных не будет. Смотрите описание хоть тут:
Цикл статей Reverse Engineering ESP8266 на хабре
Часть 1: http://habrahabr.ru/post/255135/
Часть 2: http://habrahabr.ru/post/255153/

Но надо учесть, что там много ошибок по описанию самого чипа...

И главное - в данном деле разбираются и принимают участие обычно (по опыту других больших народных проектов за последние 25 лет, а тут проект не "большой") не более 2..5 человек. Остальные - ничего не дают, а только требуют.
 
Последнее редактирование:

pvvx

Активный участник сообщества
В итоге проще выкладывать так, к примеру текущий вариант по SPI в ROM-BIOS:
Код:
/******************************************************************************
* FileName: SpiFlash.c
* Description: SPI FLASH funcs in ROM-BIOS
* Alternate SDK ver 0.0.0 (b0)
* Author: PV`
* (c) PV` 2015
*******************************************************************************/
#include "c_types.h"
#include "bios/spiflash.h"
#include "esp8266.h"
#include "driver/spi_register.h"

// ROM:4000448C
SpiFlashOpResult Wait_SPI_Idle(SpiFlashChip *sflashchip)
{
    uint32_t status;
    While(HWREG(INTC_BASE, 0x0C) & BIT9);
    return SPI_read_status(sflashchip, &status);
}

// ROM:4000443C
SpiFlashOpResult SPI_write_enable(SpiFlashChip *sflashchip)
{
    uint32_t status = 0;
    Wait_SPI_Idle();
    IOREG(SPI_CMD(0)) = SPI_WREN;
    while(IOREG(SPI_CMD(0)));
    while((status & BIT1) == 0) SPI_read_status(sflashchip,&status);
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004400
SpiFlashOpResult SPI_write_status(SpiFlashChip *sflashchip, uint32_t sta)
{
    Wait_SPI_Idle(sflashchip);
    IOREG(SPI_RD_STATUS(0)) = sta;
    IOREG(SPI_CMD(0)) = SPI_WREN;
    while(IOREG(SPI_CMD(0)));
    return SPI_FLASH_RESULT_OK;
}

SpiFlashOpResult SPI_read_status(SpiFlashChip *sflashchip, uint32_t *sta)
{
    uint32_t status;
    do {
        IOREG(SPI_RD_STATUS(0)) = sta;
        IOREG(SPI_CMD(0)) = SPI_READ;
        while(IOREG(SPI_CMD(0)));
        status = IOREG(SPI_RD_STATUS(0)) & sflashchip->status_mask;
    } while(status & BIT0);
    *sta = status;
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004644
SpiFlashOpResult spi_flash_attach(void){
    SelectSpiFunction();
    SPIFlashCnfig(5,4);
    return SPIReadModeCnfig(5);
}

// ROM:40004B44
// ВНИМАНИЕ! имеет внутренную ошибку. Не используйте SPIEraseArea() функцию ROM-BIOS!
SpiFlashOpResult SPIEraseArea (uint32 start_addr, uint32 lenght)
{
    uint32 num_sec_in_block;    // *(a1 + 0xC) = SP + 0xC
    uint32 var_st_1;             // *(a1 + 4) = SP + 0x4
    uint32 num_sec_erase;         // *(a1 + 0) = SP + 0x0
    uint32 var_r_13;             // a13
    uint32 first_sec_erase;     // a12
    uint32 var_r_3;                // a3
    uint32 var_r_0;                // a0

    SPIReadModeCnfig (5);
    if (flashchip.chip_size >= (start_addr + lenght))
    {
        if ((start_addr % flashchip.sector_size) == 0)
        {
            if (SPIUnlock (flashchip) == 0)
            {
                first_sec_erase = start_addr / flashchip.sector_size;             // First sector to erase
                num_sec_in_block = flashchip.block_size / flashchip.sector_size;     // Number of sectors in block
                num_sec_erase = lenght / flashchip.sector_size;                // Number of sectors to erase
                // Округляем количество секторов для стирания в большую сторону.
                if ((lenght % flashchip.sector_size) != 0) num_sec_erase ++; //
                var_r_13 = num_sec_erase;  // 9
                // Стираем посекторно до адреса кратного блочному стиранию.
                var_r_0 = num_sec_in_block - (first_sec_erase % num_sec_in_block); // кол-во секторов до адреса кратного блочному стиранию.
                if (var_r_0 < num_sec_erase) var_r_13 = var_r_0; // запомнить кол-во секторов до стирания

                for ( ; var_r_13 != 0; first_sec_erase++, var_r_13--)
                    if (SPIEraseSector (first_sec_erase) != 0) return 1;
                // Если оставшеестя количество секторов для стирания помещается в n-блоков,
                // то стираем n-блоков.
                var_r_13 = num_sec_erase - var_r_13; // var_r_13 = num_sec_erase - 0
                for ( ; num_sec_in_block < var_r_13; first_sec_erase += num_sec_in_block, var_r_13 -= num_sec_in_block)
                    if (SPIEraseBlock(first_sec_erase / num_sec_in_block) != 0) return 1;
                // Стираем оставшиеся сектора в конце.
                for ( ; var_r_13 != 0; first_sec_erase ++,  var_r_13 --)
                    if (SPIEraseSector (first_sec_erase) != 0) return 1;
                return SPI_FLASH_RESULT_OK;
            }
        }
    }
    return SPI_FLASH_RESULT_ERR;
}

// ROM:40004C2C
SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask)
{
    flashchip->deviceId = deviceId;
    flashchip->chip_size = chip_size;
    flashchip->block_size = block_size;
    flashchip->sector_size = sector_size;
    flashchip->page_size = page_size;
    flashchip->status_mask = status_mask;
    return SPI_FLASH_RESULT_OK;
}

// ROM:400048A8
SpiFlashOpResult SPILock(void)
{
    if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    return SPI_write_status(flashchip, 0x1C);
}

// ROM:40004878
SpiFlashOpResult SPIUnlock(void)
{
    if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    return SPI_write_status(flashchip, 0);
}


// ROM:40004120
SpiFlashOpResult spi_erase_block(SpiFlashChip *fchip, uint32_t addr)
{
    Wait_SPI_Idle(fchip);
    IOREG(SPI_ADDR(0)) =  addr & 0xFFFFFF;
    IOREG(SPI_CMD(0)) = SPI_BE;
    while(IOREG(SPI_CMD(0)));
    Wait_SPI_Idle(fchip);
    return SPI_FLASH_RESULT_OK;
}

// ROM:400049B4
SpiFlashOpResult SPIEraseBlock(uint32_t blocknum)
{
    SpiFlashChip *fchip = flashchip;
    if(blocknum > fchip->chip_size / fchip->block_size) return SPI_FLASH_RESULT_ERR;
    if(SPI_write_enable(fchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    if(spi_erase_block(fchip, fchip->block_size * blocknum) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    return SPI_FLASH_RESULT_OK;
}

// ROM:400040C0
SpiFlashOpResult spi_erase_sector(SpiFlashChip *fchip, uint32_t addr)
{
    if(addr*0xFFF) return SPI_FLASH_RESULT_ERR;
    Wait_SPI_Idle(fchip);
    IOREG(SPI_ADDR(0)) =  addr & 0xFFFFFF;
    IOREG(SPI_CMD(0)) = SPI_SE;
    while(IOREG(SPI_CMD(0)));
    Wait_SPI_Idle(fchip);
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004A00
SpiFlashOpResult SPIEraseSector(uint32_t sectornum)
{
    SpiFlashChip *fchip = flashchip;
    if(sectornum > fchip->chip_size / fchip->sector_size) return SPI_FLASH_RESULT_ERR;
    if(SPI_write_enable(fchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    if(spi_erase_sector(fchip, fchip->sector_size * sectornum) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004080
SpiFlashOpResult spi_erase_chip(SpiFlashChip *fchip)
{
    Wait_SPI_Idle(fchip);
    IOREG(SPI_CMD(0)) = SPI_CE;
    while(IOREG(SPI_CMD(0)));
    Wait_SPI_Idle(fchip);
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004984
SpiFlashOpResult SPIEraseChip(void)
{
    if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    if(spi_erase_chip(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004568
void SPIFlashCnfig(uint32_t spi_interface, uint32_t spi_freg)
{
    //    Flash QIO80:
    //  SPI_CTRL = 0x16ab000 - QIO_MODE | TWO_BYTE_STATUS_EN | WP_REG | SHARE_BUS | ENABLE_AHB | RESANDRES | FASTRD_MODE | BIT12
    //    IOMUX_BASE = 0x305
    //  Flash QIO40:
    //    SPI_CTRL = 0x16aa101
    //    IOMUX_BASE = 0x205
    uint32 a6 = 0; // spi_interface > 4
    uint32 a2;
    HWREG(SPI0_BASE,0x1C) |= 4;
    if(spi_interface == 0) a6 = 1<<24; // SPI_QIO_MODE
    else if(spi_interface == 1) a6 = 1<<20; // SPI_QOUT_MODE
    else if(spi_interface == 2) a6 = 1<<23; // SPI_DIO_MODE
    else if(spi_interface == 3) a6 = 1<<14; // SPI_DOUT_MODE
    else if(spi_interface == 4) a6 = 1<<13; // SPI_FASTRD_MODE
    if(spi_freg < 2) {
        a2 = 0x100;
        HWREG(SPI0_BASE,0x08) |= 0x1000; // ???
        HWREG(IOMUX_BASE,0) |= a2;
    }
    else {
        a2 = (((spi_freg - 1) << 8) + spi_freg + (((spi_freg >> 1) - 1) << 4) - 1);
        HWREG(SPI0_BASE,0x08) &= 0xFFFFEFFF;
        HWREG(IOMUX_BASE,0) &= 0xEFF;
    }
    a2 |= a6;
    a2 |= 0x288000; // SPI_RESANDRES | SPI_SHARE_BUS | SPI_WP_REG
    HWREG(SPI0_BASE,0x08) |= a2;
    HWREG(SPI0_BASE,0) = 0x100000;
    while(HWREG(SPI0_BASE,0) != 0);
    // [0x60000208] = 0x016aa101;
    //                 0x00288000
    //                 0x00411000 // BIT12 BIT16 BIT22
}

// ROM:400042AC
SpiFlashOpResult spi_flash_read(SpiFlashChip *fchip, uint32_t faddr, uint32_t *dst, size_t size)
{
    if(faddr + size > fchip->chip_size) return SPI_FLASH_RESULT_ERR;
    Wait_SPI_Idle(fchip);
    while(size >= 1) {
        if(size < 32) {
            IOREG(SPI_ADDR(0)) = faddr | (size << 24);
            IOREG(SPI_CMD(0)) = SPI_READ;
            while(IOREG(SPI_CMD(0)));
        }
        else {
            IOREG(SPI_ADDR(0)) = faddr | BIT29; // 0x20000000 = 32 << 24
            IOREG(SPI_CMD(0)) = SPI_READ;
            while(IOREG(SPI_CMD(0)));
        }
//        move dst, SPI0_W0+...
//        size -= read
    }
    return SPI_FLASH_RESULT_OK;
}

// ROM:40004B1C
SpiFlashOpResult SPIRead(uint32_t faddr, uint32_t *dst, size_t size)
{
    return spi_flash_read(flashchip, faddr, dst, size);
}
Но уже в окончательном варианте.
 

pvvx

Активный участник сообщества
Но и этого "описания функции" в Eclipse:
Sampl23.gif
большинству не нравится. Им требуется полный Help, да "с пивом и девками надом". :)
Вы хотите слишком много – чтобы я стал и литературным писателем и описал всё имеющееся и как-то связанное ПО с проектами на ESP8266, да ещё “разреверсил” всю SDK, да описал, как это использовать... Один человек это будет делать очень долго. Надо распределять задачи. Наброски как и что – даны и лежат уже месяцами на форуме. Где желающие потратить своё время на разбор и выложить всем? Нема :p Пока только одни "дом советов" и портировщики чужого.
------
Мы не закончили разговор где и как сделать “базу” на гитхабе. Я её обслуживать не смогу, но добавлять и исправлять – смогу (научите).
 
Последнее редактирование:

anakod

Moderator
Команда форума
pvvx, с описанием\структурированием я вероятно смогу помочь. Статьи на хабре прочитал, в целом все понятно, первоочередной вопрос - есть ли возможность автоматической частичной декомпиляции в Си код или только ассемблерный код и ручками?

По гитхабу все очень просто, через веб интерфейс создаете проект, затем синхронизируете его к себе на компьютер и добавляете все файлы локально. Я использую SourceTree, но как понимаю, Github for Windows должен быть еще проще\удобнее. После того как у Вас есть локальная копия Вы в один клик можете пушить актуальные измениеия на сервер, очень большое удобство в том что ничего никогда не потеряется и все изменения на виду - ясно что добавилось и изменилось, пользователям и другим разработчикам проще следить за развитием, помогать выявлять баги. Если кто-то делает какую-нибдь часть работы, он присылает Вам pull request, Вы его принимаете или запрашиваете дополнительные доработки перед принятием. Изменения автоматически сливаются, т.к. Git умеет сливать код самостоятельно (конфликты возможно но бывают крайне редко).

Я бы предложил завести отдельный простой проект содержащий только разобранную часть SDK без всего лишнего. Этот проект может собираться в библиотеку (или несколько библиотек), которая(ые) будет линковаться к любому проекту (всем Вашим веб разработкам, моему Sming и т.д.) и будет заменять стандартный прожорливый SDK Espressif.

Если есть какие-нибудь вопросы - готов подсказать\помочь. Направление это на мой взгляд сейчас одно из самых важных.
 

pvvx

Активный участник сообщества
первоочередной вопрос - есть ли возможность автоматической частичной декомпиляции в Си код или только ассемблерный код и ручками?
Ручками. IDA и имеющийся к ней плагин и так с ошибками, тем более он ничего не понимает в передаче параметров функциям через регистры у данного CPU.
Я бы предложил завести отдельный простой проект содержащий только разобранную часть SDK без всего лишнего.
Ещё раз: По началу надо отделить полностью "мух от котлет" - нужны отдельные описания ROM-BIOS без всяких SDK. Это будет базой, на которую уже можно писать загрузчики и будут опираться ссылки из SDK. Иначе опять бардак с 'инклудами'. На этом всё и висит. К данной теме можно сделать и проект, пока без WiFi, но обработкой датчиков и прочего. Загрузить SDK и сейчас можно.
 
Последнее редактирование:

anakod

Moderator
Команда форума
Ручками. IDA и имеющийся к ней плагин и так с ошибками, тем более он ничего не понимает в передаче параметров функциям через регистры у данного CPU.
Очень жаль если честно. А где можно почитать про данный Assembler?

Ещё раз: По началу надо отделить полностью "мух от котлет" - нужны отдельные описания ROM-BIOS без всяких SDK. Это будет базой, на которую уже можно писать загрузчики и будут опираться ссылки из SDK. Иначе опять бардак с 'инклудами'. На этом всё и висит. К данной теме можно сделать и проект, пока без WiFi, но обработкой датчиков и прочего. Загрузить SDK и сейчас можно.
А насколько много еще работы по ROM-BIOS и какие части надо доразобрать? Делать SDK можно как сейчас постепенно замещая закрытые библиотеки Espressif, но насчет разделения на слои (описания ROM-BIOS и отдельно SDK) - полностью согласен. По идее это может быть и два проекта на гитхабе (один затем может использоваться как подмодуль в другом).

Касательно SDK - не обязательно делать его "толстым", вполне подойдет минимальный необходимый набор от которого уже можно будет двигаться к следующему новому функционалу (типа динамической загрузки и т.п.).
 

pvvx

Активный участник сообщества
Очень жаль если честно. А где можно почитать про данный Assembler?
В Xtensa® Instruction Set Architecture (ISA) Reference Manual (4.8 MB)
А насколько много еще работы по ROM-BIOS и какие части надо доразобрать?
Только основные, которые можно использовать. Загрузчик с его процедурами не нужен, а c WiFi там тоже "темный лес". Так что не так много ещё - под 80% заголовков уже есть. Описания нет, т.е. мало.
Счас закончил с UART процедурами (типа исходники всех процедур, что можно запользовать в ROM-BIOS)...
Код:
/******************************************************************************
 * FileName: UartDev.c
 * Description: UART funcs in ROM-BIOS
 * Alternate SDK ver 0.0.0 (b0)
 * Author: PV`
 * (c) PV` 2015
*******************************************************************************/
#include "bios/uartdev.h"
#include "esp8266.h"

//uint8 RcvBuff[256];
//uint8 TrxBuff[100];
#define RcvBuff  ((uint8 *)0x3fffde60)
#define TrxBuff  (&RcvBuff[0x100]) // ((uint8 *)0x3fffdf60)

// ROM:40003BBC
void uart_rx_intr_handler(void *par)
{
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    if((uartregs[2] & UART_RXFIFO_FULL_INT_ST) == 0) return; // UART_INT_ST(x) & UART_RXFIFO_FULL_INT_ST
    uartregs[4] = 1; // UART_INT_CLR
    while(uartregs[7] & UART_RXFIFO_CNT) { // UART_STATUS(x) & UART_RXFIFO_CNT
        RcvMsgBuff * rcvmsg = (RcvMsgBuff *)par;
        register uint8 c = uartregs[0]; // UART_FIFO(x)
        if(c == '\n') rcvmsg->BuffState = WRITE_OVER;
        *rcvmsg->pWritePos++ = c;
        if(rcvmsg->pWritePos >= rcvmsg->pRcvMsgBuff + rcvmsg->RcvBuffSize) {
            rcvmsg->pWritePos = rcvmsg->pRcvMsgBuff;
        }
    }
}

// ROM:4000383C
void uartAttach(void)
{
    // &UartDev.RcvMsgBuff;
    UartDev.baut_rate = BIT_RATE_115200;
    UartDev.data_bits = EIGHT_BITS;
    UartDev.exist_parity = STICK_PARITY_DIS;
    UartDev.parity = NONE_BITS;
    UartDev.stop_bits = ONE_STOP_BIT;
    UartDev.flow_ctrl = NONE_CTRL;
    UartDev.rcv_buff.RcvBuffSize = RX_BUFF_SIZE;
    UartDev.rcv_buff.pRcvMsgBuff = RcvBuff; //    &UartDev + 0x50
    UartDev.rcv_buff.pWritePos = RcvBuff;
    UartDev.rcv_buff.pReadPos = RcvBuff;
    UartDev.rcv_buff.TrigLvl = 1;
    UartDev.rcv_buff.BuffState = EMPTY;
    UartDev.trx_buff.TrxBuffSize = TX_BUFF_SIZE;
    UartDev.trx_buff.pTrxBuff =    TrxBuff;
    UartDev.rcv_state = BAUD_RATE_DET;
    UartDev.received = 0;
    UartDev.buff_uart_no = UART0;

    ets_isr_mask(1 << ETS_UART_INUM);
    ets_isr_attach(ETS_UART_INUM, uart_rx_intr_handler, &UartDev.rcv_buff);
}

// ROM:40003B8C
int uart_rx_one_char(uint8 *ch)
{
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    if(uartregs[7] & UART_RXFIFO_CNT) {
        *ch = uartregs[0];
        return 0;
    }
    return 1;
}

// ROM:40003B64
uint8 uart_rx_one_char_block(void)
{
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    while((uartregs[7] & UART_RXFIFO_CNT)==0);
    return uartregs[0];
}

// ROM:40003EC8
int uart_rx_readbuff(RcvMsgBuff * rcvmsg, uint8 *dst)
{
    if(rcvmsg->pReadPos == rcvmsg->pWritePos) return 1;
    *dst = *rcvmsg->pReadPos++;
    if(rcvmsg->pReadPos >= rcvmsg->pRcvMsgBuff + rcvmsg->RcvBuffSize) {
                rcvmsg->pReadPos = rcvmsg->pRcvMsgBuff;
    }
    return 0;
}

// ROM:40003B30
int uart_tx_one_char(uint8 ch)
{
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    while(uartregs[7] & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S));
    uartregs[0] = ch;
    return 0;
}

// ROM:400038A4
void uart_buff_switch(uint8 uartnum)
{
    if(uartnum) {
        UartDev.buff_uart_no = uartnum;
        return;
    }
    volatile uint32_t *uartregs = REG_UART_BASE(UartDev.buff_uart_no);
    uartregs[4] = 0xFFFF; // UART_INT_CLR(UartDev.buff_uart_no)
    uartregs[3] &= 0xE00;
    uint8 ch;
    while(uart_rx_one_char(&ch) == 0 &&    uart_rx_readbuff(&UartDev.rcv_buff, &ch));
    UartDev.rcv_buff.BuffState = EMPTY;
}

// ROM:400039D8
void uart_div_modify(uint32 uart_num, uint32 div_baud)
{
    volatile uint32_t *uartregs = REG_UART_BASE(uart_num);
    register uint32 x = uartregs[6];
    uartregs[6] = x | UART_TXFIFO_RST | UART_RXFIFO_RST;
    uartregs[5] = div_baud; // UART_CLKDIV(uart_num) = div_baud
    uartregs[8] = x  & (~(UART_TXFIFO_RST | UART_RXFIFO_RST));
}

// ROM:40003924
uint32 uart_baudrate_detect(uint32 uart_num, uint32 flg)
{
    volatile uint32_t *uartregs = REG_UART_BASE(uart_num);
    if(UartDev.rcv_state != BAUD_RATE_DET) {
        uartregs[6] &= 0x7E; // UART_AUTOBAUD(uart_num)
        uartregs[6] = 0x801; // UART_AUTOBAUD(uart_num)
        UartDev.rcv_state = WAIT_SYNC_FRM;
    }
    while(uartregs[12] >= 29) { // UART_PULSE_NUM(uart_num)
        if(flg) return 0;
        ets_delay_us(1000);
    }
    uint32 ret = (((uartregs[10] & 0xFFFFF) + (uartregs[11] & 0xFFFFF)) >> 1) + 12;  // UART_LOWPULSE(uart_num) + UART_HIGHPULSE(uart_num)
    uartregs[6] &= 0x7E; // UART_AUTOBAUD(uart_num)
    return ret;
}

// ROM:40003EF4
int UartGetCmdLn(uint8 *buf)
{
    if(UartDev.rcv_buff.BuffState == WRITE_OVER) {
        uint8 ch;
        if(uart_rx_readbuff(&UartDev.rcv_buff, &ch) == 0) {
            do {
                *buf++ = ch;
            } while(uart_rx_readbuff(&UartDev.rcv_buff, &ch)==0);
            *buf = '\0';
            UartDev.rcv_buff.BuffState = EMPTY;
            return 0;
        }
    }
    return 1;
}
 
Последнее редактирование:

pvvx

Активный участник сообщества
Значит что у нас на сегодня c функциями ROM-BIOS?
Использовать это нельзя:
/* WARNING !!! mem_xxx use size < 4096 !!! */
extern void mem_init(void * start_addr); // uint8 *
extern void * mem_malloc(uint16 size); // size < 4096
extern void * mem_calloc(uint16 n, uint16 count); // n*count < 4096
extern void * mem_zalloc(uint16 size); // size < 4096, = mem_calloc(1, size);
extern void * mem_realloc(void * p, uint16 size);
extern void * mem_trim(void * p, uint16 size);
extern void mem_free(uint8 * x);

Они ограничены 4 килобайтами - это песочница в ram для bios и даже в нем не используется....
void rtc_enter_sleep(void);
Работает без SDK, но потребление у модуля падает до порядков в 5..9 mA (измерено с включенной внешней FT2232C на 2UART TX/RX/RTS.. и т.д. чтобы смотреть логи и поведение). UART и прочее тактирование тухнет на время sleep...
Для теста можно задать dtm_params_init(NULL, NULL) + dtm_set_params(0, time, 0, 0, 0) и вызвать rtc_enter_sleep().
void dtm_params_init(void * sleep_func, void * int_func);
void dtm_set_params(int a2, int time_ms, int a4, int a5, int a6);
 

anakod

Moderator
Команда форума
nikolz, наиболее полные исходники реверса SDK находятся здесь: http://esp8266.ru/forum/threads/razrabotka-biblioteki-malogo-webservera-na-esp8266.56/

В первую очередь смотрите:
  • app/include
  • app/main
  • app/phy
- это разобранные исходники соответствующих библиотек из комплекта SDK и инклуды описывающие множество встроенных функций.

Отдельного github репозитория под SDK к сожалению пока еще нет..

Использовать это нельзя:
/* WARNING !!! mem_xxx use size < 4096 !!! */
Прикольно, я когда их в первый раз заметил, подумал почему бы не взять их вместо portMalloc... :)
 

pvvx

Активный участник сообщества
Отдельного github репозитория под SDK к сожалению пока еще нет..
И не будет, пока не соберется что-то значительное. Т.е. в нем нет смысла, т.к. всё меняется постоянно в исходниках и они пока представляют из себя киш-миш :)
 

pvvx

Активный участник сообщества
Прикольно, я когда их в первый раз заметил, подумал почему бы не взять их вместо portMalloc... :)
Их можно использовать, задав базовый адрес песочницы:
Код:
void call_user_start(void)
{
    ets_update_cpu_frequency(52);
    ets_printf("\nStart RAM porg\n");
    mem_init((uint8 *)0x3fff0000);
      ets_uart_printf("--------\n");

      uint32 x = 32;
      dtm_params_init(NULL, NULL);
      dtm_set_params(0,3000*26/40,0,0,0);
      while(x) {
            uint8 *addr1 = mem_malloc(x);
            ets_uart_printf("mem_malloc(%u) = %p # ", x, addr1);
         ets_delay_us(3000); // чтобы прошли UART символы, иначе залипнет прямо на выводе бита и будет светить светодиодом на GPIO1 (который используется как прерывание sleep и при настроенном как выход TX не пашет :) )
            rtc_enter_sleep();
         ets_delay_us(3000); // а тут чтобы восстановилась pll была нормальная скорость UART для следующих soo...
            uint8 *addr2 = mem_malloc(x-32);
            ets_uart_printf("mem_malloc(%u) = %p\n", x-32, addr2);
            mem_free(addr1);
            mem_free(addr2);
            x <<= 1;
      }
      ets_uart_printf("--------\n");
    ets_run();
}
Загружается в IRAM для теста. Make примерно так
loadram: $(APP).elf
$(ESPTOOL) -p $(ESPPORT) load_ram $(APP)-0x00000.bin

Скорость вывода UART будет та, с которой загружался код в ESPTOOL.
Получаем лог:
Код:
Start RAM porg
--------
mem_malloc(32) = 0x3fff0008 # mem_malloc(0) = 0x00000000
mem_malloc(64) = 0x3fff0008 # mem_malloc(32) = 0x3fff0050
mem_malloc(128) = 0x3fff0008 # mem_malloc(96) = 0x3fff0090
mem_malloc(256) = 0x3fff0008 # mem_malloc(224) = 0x3fff0110
mem_malloc(512) = 0x3fff0008 # mem_malloc(480) = 0x3fff0210
mem_malloc(1024) = 0x3fff0008 # mem_malloc(992) = 0x3fff0410
mem_malloc(2048) = 0x3fff0008 # mem_malloc(2016) = 0x3fff0810
mem_malloc(4096) = 0x00000000 # mem_malloc(4064) = 0x3fff0008
mem_malloc(8192) = 0x00000000 # mem_malloc(8160) = 0x00000000
mem_malloc(16384) = 0x00000000 # mem_malloc(16352) = 0x00000000
mem_malloc(32768) = 0x00000000 # mem_malloc(32736) = 0x00000000
mem_malloc(65536) = 0x00000000 # mem_malloc(65504) = 0x00000000
mem_malloc(131072) = 0x00000000 # mem_malloc(131040) = 0x00000000
mem_malloc(262144) = 0x00000000 # mem_malloc(262112) = 0x00000000
mem_malloc(524288) = 0x00000000 # mem_malloc(524256) = 0x00000000
mem_malloc(1048576) = 0x00000000 # mem_malloc(1048544) = 0x00000000
mem_malloc(2097152) = 0x00000000 # mem_malloc(2097120) = 0x00000000
mem_malloc(4194304) = 0x00000000 # mem_malloc(4194272) = 0x00000000
mem_malloc(8388608) = 0x00000000 # mem_malloc(8388576) = 0x00000000
mem_malloc(16777216) = 0x00000000 # mem_malloc(16777184) = 0x00000000
mem_malloc(33554432) = 0x00000000 # mem_malloc(33554400) = 0x00000000
mem_malloc(67108864) = 0x00000000 # mem_malloc(67108832) = 0x00000000
mem_malloc(134217728) = 0x00000000 # mem_malloc(134217696) = 0x00000000
mem_malloc(268435456) = 0x00000000 # mem_malloc(268435424) = 0x00000000
mem_malloc(536870912) = 0x00000000 # mem_malloc(536870880) = 0x00000000
mem_malloc(1073741824) = 0x00000000 # mem_malloc(1073741792) = 0x00000000
mem_malloc(2147483648) = 0x00000000 # mem_malloc(2147483616) = 0x00000000
--------
и видим - максимальный удовлетворенный запрос = 4064 байта :)
В большинстве функций mem_xxx стоит входная проверка > 4096 ничего незя.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Вышла новая версия SDK 1.1.0.
В IRAM перенесены вектора прерываний CPU с отладкой kernel-vector, nmi-vector....
l32r a2, _stext ; 0x40100000
wsr.vecbase a2

В основные библиотеки (libmain.a) добавлены коды драйверов, таких как программный pwm и подобное (пухнут с каждым новым SDK)...
Введена поддержка второй flash и флаг по которому происходит переключение, по тому добавлены разные вызовы Cache_Read_Enable(0, 0, 1) и Cache_Read_Enable(1, 0, 1)...
Объем доступной пользователю памяти "heap" ещё уменьшился, но не сильно до сотни байт в сравнении с прошлым SDK (если использовать основные огрызки от библиотек Espressif). Объем iram уменьшился катастрофически (примерно ещё на пару кило).
 
Последнее редактирование:

anakod

Moderator
Команда форума
Да вроде и так давно уже ясно что все это идёт не туда..
 
Сверху Снизу