// prevent this function being placed inline with main // to keep main's stack size as small as possible // don't mark as static or it'll be optimised out when // using the assembler stub uint32 NOINLINE find_image() { uint8 flag; uint32 runAddr; uint32 flashsize; int32 romToBoot; uint8 gpio_boot = FALSE; uint8 updateConfig = TRUE; uint8 buffer[SECTOR_SIZE]; rboot_config *romconf = (rboot_config*)buffer; rom_header *header = (rom_header*)buffer; // delay to slow boot (help see messages when debugging) //ets_delay_us(2000000); ets_printf("\r\nrBoot v1.2.1 - [email protected]\r\n"); // read rom header SPIRead(0, header, sizeof(rom_header)); // print and get flash size ets_printf("Flash Size: "); flag = header->flags2 >> 4; if (flag == 0) { ets_printf("4 Mbit\r\n"); flashsize = 0x80000; } else if (flag == 1) { ets_printf("2 Mbit\r\n"); flashsize = 0x40000; } else if (flag == 2) { ets_printf("8 Mbit\r\n"); flashsize = 0x100000; } else if (flag == 3) { ets_printf("16 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x200000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else if (flag == 4) { ets_printf("32 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x400000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else { ets_printf("unknown\r\n"); // assume at least 4mbit flashsize = 0x80000; } // print spi mode ets_printf("Flash Mode: "); if (header->flags1 == 0) { ets_printf("QIO\r\n"); } else if (header->flags1 == 1) { ets_printf("QOUT\r\n"); } else if (header->flags1 == 2) { ets_printf("DIO\r\n"); } else if (header->flags1 == 3) { ets_printf("DOUT\r\n"); } else { ets_printf("unknown\r\n"); } // print spi speed ets_printf("Flash Speed: "); flag = header->flags2 & 0x0f; if (flag == 0) ets_printf("40 MHz\r\n"); else if (flag == 1) ets_printf("26.7 MHz\r\n"); else if (flag == 2) ets_printf("20 MHz\r\n"); else if (flag == 0x0f) ets_printf("80 MHz\r\n"); else ets_printf("unknown\r\n"); // print enabled options #ifdef BOOT_BIG_FLASH ets_printf("rBoot Option: Big flash\r\n"); #endif #ifdef BOOT_CONFIG_CHKSUM ets_printf("rBoot Option: Config chksum\r\n"); #endif #ifdef BOOT_IROM_CHKSUM ets_printf("rBoot Option: irom chksum\r\n"); #endif ets_printf("\r\n"); // read boot config SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); // fresh install or old version? if (romconf->magic != BOOT_CONFIG_MAGIC || romconf->version != BOOT_CONFIG_VERSION #ifdef BOOT_CONFIG_CHKSUM || romconf->chksum != calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum) #endif ) { /* Modified by Cesanta */ ets_printf("Writing default boot config.\r\n"); ets_memset(romconf, 0x00, sizeof(rboot_config)); romconf->magic = BOOT_CONFIG_MAGIC; romconf->version = BOOT_CONFIG_VERSION; romconf->count = 2; romconf->mode = MODE_STANDARD; /* FWx_ADDR, FWx_FS_ADDR and FS_SIZE, FW_SIZE must be defined by -D */ romconf->roms[0] = FW1_ADDR; romconf->roms[1] = FW2_ADDR; romconf->fs_addresses[0] = FW1_FS_ADDR; romconf->fs_addresses[1] = FW2_FS_ADDR; romconf->fs_sizes[0] = romconf->fs_sizes[1] = FS_SIZE; romconf->roms_sizes[0] = romconf->roms_sizes[1] = FW_SIZE; #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif // write new config sector SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } // if gpio mode enabled check status of the gpio if ((romconf->mode & MODE_GPIO_ROM) && (get_gpio16() == 0)) { ets_printf("Booting GPIO-selected.\r\n"); romToBoot = romconf->previous_rom; /* * Modified by Cesanta * Make FD current */ updateConfig = TRUE; romconf->fw_updated = 0; romconf->is_first_boot = 0; gpio_boot = TRUE; } else if (romconf->current_rom >= romconf->count) { // if invalid rom selected try rom 0 ets_printf("Invalid rom selected, defaulting.\r\n"); romToBoot = 0; romconf->current_rom = 0; romconf->fw_updated = 0; romconf->is_first_boot = 0; updateConfig = TRUE; } else { /* Modified by Cesanta */ if (romconf->is_first_boot != 0) { ets_printf("First boot, attempt %d\n", romconf->boot_attempts); /* boot is unconfirmed */ if (romconf->boot_attempts == 0) { /* haven't try to load yes */ ets_printf("Boot is unconfirmed\r\n"); romconf->boot_attempts++; } else { ets_printf("Boot failed, fallback to fw #%d\r\n", romconf->previous_rom); romconf->current_rom = romconf->previous_rom; /* clear fw update flag, to avoid post-update acttions */ romconf->fw_updated = 0; romconf->boot_attempts = 0; } updateConfig = TRUE; } /* End of Cesanta modifications */ // try rom selected in the config romToBoot = romconf->current_rom; } // try to find a good rom do { runAddr = check_image(romconf->roms[romToBoot]); if (runAddr == 0) { ets_printf("Rom %d is bad.\r\n", romToBoot); if (gpio_boot) { // don't switch to backup for gpio-selected rom ets_printf("GPIO boot failed.\r\n"); return 0; } else { // for normal mode try each previous rom // until we find a good one or run out updateConfig = TRUE; romToBoot--; if (romToBoot < 0) romToBoot = romconf->count - 1; if (romToBoot == romconf->current_rom) { // tried them all and all are bad! ets_printf("No good rom available.\r\n"); return 0; } } } } while (runAddr == 0); // re-write config, if required if (updateConfig) { romconf->current_rom = romToBoot; #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } ets_printf("Booting rom %d.\r\n", romToBoot); // copy the loader to top of iram ets_memcpy((void*)_text_addr, _text_data, _text_len); // return address to load from return runAddr; }
static void ICACHE_FLASH_ATTR SendSpecificService( int sid, uint8_t*namestartptr, int xactionid, int stlen, int is_prefix ) { uint8_t outbuff[256]; uint8_t * obptr = outbuff; uint16_t * obb = (uint16_t*)outbuff; const char *sn = MDNSServices[sid]; const char *st = MDNSServiceTexts[sid]; int stl = ets_strlen( st ); int sp = MDNSServicePorts[sid]; *(obb++) = xactionid; *(obb++) = HTONS(0x8400); //We are authoratative. And this is a response. *(obb++) = 0; *(obb++) = HTONS(sp?4:3); //4 answers. (or 3 if we don't have a port) *(obb++) = 0; *(obb++) = 0; if( !sn || !st ) return; obptr = (uint8_t*)obb; // ets_memcpy( obptr, namestartptr, stlen+1 ); //Hack: Copy the name in. // obptr += stlen+1; obptr = SendPathSegment( obptr, sn ); obptr = SendPathSegment( obptr, "local" ); *(obptr++) = 0; *(obptr++) = 0x00; *(obptr++) = 0x0c; //PTR record *(obptr++) = 0x00; *(obptr++) = 0x01; //No Flush cache + in ptr. *(obptr++) = 0x00; *(obptr++) = 0x00; //TTL *(obptr++) = 0x00; *(obptr++) = 100; //very short. (100 seconds) if( !is_prefix ) { *(obptr++) = 0x00; *(obptr++) = ets_strlen( MDNSNames[0] ) + 3; //Service... obptr = TackTemp( obptr ); } else { *(obptr++) = 0x00; *(obptr++) = 2; *(obptr++) = 0xc0; *(obptr++) = 0x0c; //continue the name. } if( !is_prefix ) { obptr = TackTemp( obptr ); } else { *(obptr++) = 0xc0; *(obptr++) = 0x0c; //continue the name. } *(obptr++) = 0x00; *(obptr++) = 0x10; //TXT record *(obptr++) = 0x80; *(obptr++) = 0x01; //Flush cache + in ptr. *(obptr++) = 0x00; *(obptr++) = 0x00; //TTL *(obptr++) = 0x00; *(obptr++) = 100; //very short. (100 seconds) *(obptr++) = 0x00; *(obptr++) = stl + 1; //Service... *(obptr++) = stl; //Service length ets_memcpy( obptr, st, stl ); obptr += stl; //Service record if( sp ) { int localnamelen = ets_strlen( MyLocalName ); if( !is_prefix ) { obptr = TackTemp( obptr ); } else { *(obptr++) = 0xc0; *(obptr++) = 0x0c; //continue the name. } //obptr = TackTemp( obptr ); //*(obptr++) = 0xc0; *(obptr++) = 0x2f; //continue the name. *(obptr++) = 0x00; *(obptr++) = 0x21; //SRV record *(obptr++) = 0x80; *(obptr++) = 0x01; //Don't Flush cache + in ptr. *(obptr++) = 0x00; *(obptr++) = 0x00; //TTL *(obptr++) = 0x00; *(obptr++) = 100; //very short. (100 seconds) *(obptr++) = 0x00; *(obptr++) = localnamelen + 7 + 1; //Service? *(obptr++) = 0x00; *(obptr++) = 0x00; //Priority *(obptr++) = 0x00; *(obptr++) = 0x00; //Weight *(obptr++) = sp>>8; *(obptr++) = sp&0xff; //Port# obptr = SendPathSegment( obptr, MyLocalName ); *(obptr++) = 0; } //A Record obptr = SendPathSegment( obptr, MyLocalName ); *(obptr++) = 0; *(obptr++) = 0x00; *(obptr++) = 0x01; //A record *(obptr++) = 0x80; *(obptr++) = 0x01; //Flush cache + in ptr. *(obptr++) = 0x00; *(obptr++) = 0x00; //TTL *(obptr++) = 0x00; *(obptr++) = 30; //very short. (30 seconds) *(obptr++) = 0x00; *(obptr++) = 0x04; //Size 4 (IP) ets_memcpy( obptr, pMDNSServer->proto.udp->local_ip, 4 ); obptr+=4; //Send to broadcast. uint32_t md = MDNS_BRD; ets_memcpy( pMDNSServer->proto.udp->remote_ip, &md, 4 ); espconn_sent( pMDNSServer, outbuff, obptr - outbuff ); }
// prevent this function being placed inline with main // to keep main's stack size as small as possible // don't mark as static or it'll be optimised out when // using the assembler stub uint32 NOINLINE find_image() { uint8 flag; uint32 runAddr; uint32 flashsize; int32 romToBoot; uint8 gpio_boot = FALSE; uint8 updateConfig = TRUE; uint8 buffer[SECTOR_SIZE]; rboot_config *romconf = (rboot_config*)buffer; rom_header *header = (rom_header*)buffer; // delay to slow boot (help see messages when debugging) //ets_delay_us(2000000); ets_printf("\r\nrBoot v1.2.0 - [email protected]\r\n"); // read rom header SPIRead(0, header, sizeof(rom_header)); // print and get flash size ets_printf("Flash Size: "); flag = header->flags2 >> 4; if (flag == 0) { ets_printf("4 Mbit\r\n"); flashsize = 0x80000; } else if (flag == 1) { ets_printf("2 Mbit\r\n"); flashsize = 0x40000; } else if (flag == 2) { ets_printf("8 Mbit\r\n"); flashsize = 0x100000; } else if (flag == 3) { ets_printf("16 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x200000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else if (flag == 4) { ets_printf("32 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x400000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else { ets_printf("unknown\r\n"); // assume at least 4mbit flashsize = 0x80000; } // print spi mode ets_printf("Flash Mode: "); if (header->flags1 == 0) { ets_printf("QIO\r\n"); } else if (header->flags1 == 1) { ets_printf("QOUT\r\n"); } else if (header->flags1 == 2) { ets_printf("DIO\r\n"); } else if (header->flags1 == 3) { ets_printf("DOUT\r\n"); } else { ets_printf("unknown\r\n"); } // print spi speed ets_printf("Flash Speed: "); flag = header->flags2 & 0x0f; if (flag == 0) ets_printf("40 MHz\r\n"); else if (flag == 1) ets_printf("26.7 MHz\r\n"); else if (flag == 2) ets_printf("20 MHz\r\n"); else if (flag == 0x0f) ets_printf("80 MHz\r\n"); else ets_printf("unknown\r\n"); // print enabled options #ifdef BOOT_BIG_FLASH ets_printf("rBoot Option: Big flash\r\n"); #endif #ifdef BOOT_CONFIG_CHKSUM ets_printf("rBoot Option: Config chksum\r\n"); #endif // read boot config SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); // fresh install or old version? if (romconf->magic != BOOT_CONFIG_MAGIC || romconf->version != BOOT_CONFIG_VERSION #ifdef BOOT_CONFIG_CHKSUM || romconf->chksum != calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum) #endif ) { // create a default config for a standard 2 rom setup ets_printf("Writing default boot config.\r\n"); ets_memset(romconf, 0x00, sizeof(rboot_config)); #ifndef BOOT_BIG_FLASH if (flashsize > 0x100000) flashsize = 0x100000; #else if (flashsize > 0x200000) flashsize = 0x200000; #endif romconf->magic = BOOT_CONFIG_MAGIC; romconf->version = BOOT_CONFIG_VERSION; romconf->count = 2; romconf->roms[0] = SECTOR_SIZE * 2; romconf->roms[1] = (flashsize / 2) + (SECTOR_SIZE * 2); #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif // write new config sector SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } // if gpio mode enabled check status of the gpio if ((romconf->mode & MODE_GPIO_ROM) && (get_gpio16() == 0)) { ets_printf("Booting GPIO-selected.\r\n"); romToBoot = romconf->gpio_rom; gpio_boot = TRUE; } else if (romconf->current_rom >= romconf->count) { // if invalid rom selected try rom 0 ets_printf("Invalid rom selected, defaulting.\r\n"); romToBoot = 0; romconf->current_rom = 0; updateConfig = TRUE; } else { // try rom selected in the config romToBoot = romconf->current_rom; } ets_printf("ROM0: 0x%08X, ROM1: 0x%08X\r\n", romconf->roms[0], romconf->roms[1]); // try to find a good rom do { runAddr = check_image(romconf->roms[romToBoot]); if (runAddr == 0) { ets_printf("Rom %d is bad.\r\n", romToBoot); if (gpio_boot) { // don't switch to backup for gpio-selected rom ets_printf("GPIO boot failed.\r\n"); return 0; } else { // for normal mode try each previous rom // until we find a good one or run out updateConfig = TRUE; romToBoot--; if (romToBoot < 0) romToBoot = romconf->count - 1; if (romToBoot == romconf->current_rom) { // tried them all and all are bad! ets_printf("No good rom available.\r\n"); return 0; } } } } while (runAddr == 0); // re-write config, if required if (updateConfig) { romconf->current_rom = romToBoot; #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } ets_printf("Booting rom %d.\r\n", romToBoot); // copy the loader to top of iram ets_memcpy((void*)_text_addr, _text_data, _text_len); // return address to load from return runAddr; }
void* memcpy(void *dest, const void *src, size_t n) { return ets_memcpy(dest, src, n); }
//============================================================================= // call_user_start //----------------------------------------------------------------------------- void call_user_start(void) { struct SPIFlashHead sfh; // заголовок flash struct StoreWifiHdr wifihdr; // заголовок из последнего сектора flash с индексом на сохранение последней конфигурации WiFi struct BootConfig bootcfg; // начало блока сохранения последней конфигурации WiFi, часть с boot параметрами ets_printf("\n2nd boot version : 1.2\n"); SPIRead(0, &sfh, sizeof(sfh)); ets_printf(" SPI Speed : "); switch (sfh.hsz.spi_freg) { case SPEED_40MHZ: ets_printf("40MHz\n"); break; case SPEED_26MHZ: ets_printf("26.7MHz\n"); break; case SPEED_20MHZ: ets_printf("20MHz\n"); break; case SPEED_80MHZ: ets_printf("80MHz\n"); break; } ets_printf(" SPI Mode : "); switch (sfh.spi_interface) { case MODE_QIO: ets_printf("QIO\n"); break; case MODE_QOUT: ets_printf("QOUT\n"); break; case MODE_DIO: ets_printf("DIO\n"); break; case MODE_DOUT: ets_printf("DOUT\n"); break; } ets_printf(" SPI Flash Size : "); uint32 sector; switch (sfh.hsz.flash_size) { case SIZE_4MBIT: ets_printf("4Mbit\n"); sector = 128-4; break; case SIZE_2MBIT: ets_printf("2Mbit\n"); sector = 64-4; break; case SIZE_8MBIT: ets_printf("8Mbit\n"); sector = 256-4; break; case SIZE_16MBIT: ets_printf("16Mbit\n"); sector = 512-4; break; case SIZE_32MBIT: ets_printf("32Mbit\n"); sector = 1024-4; break; default: ets_printf("4Mbit\n"); sector = 128-4; break; } uint32 addr = sector * FSECTOR_SIZE; SPIRead(addr + 3 * FSECTOR_SIZE, &wifihdr.bank, sizeof(wifihdr)); if(wifihdr.bank == 0) { SPIRead(addr + FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); } else { SPIRead(addr + 2 * FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); } if(bootcfg.boot_version == 0xff) { bootcfg.boot_number = 0; } if(bootcfg.boot_version != 2) { bootcfg.boot_version = 2; if(wifihdr.bank == 0) wifihdr.bank = 1; else wifihdr.bank = 0; SPIEraseSector(sector+wifihdr.bank+1); SPIWrite((sector+wifihdr.bank+1) * FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); SPIEraseSector(sector+3); SPIWrite(addr + 3 * FSECTOR_SIZE, &wifihdr.bank, sizeof(wifihdr)); } ets_memcpy((void *)0x4010800, &code_blk, size_code_blk); // загрузчик не прикреплен! ets_printf("jump to run user"); switch(bootcfg.boot_number & 0x0f) { case 0: ets_printf("1\n\n"); uint32 seg_size = get_seg_size(FSECTOR_SIZE); if(seg_size == 0xffffffff) return; if(seg_size == 0) { 0x4010800C(FSECTOR_SIZE); } else { 0x4010800C(seg_size + 0x1010); } break; case 1: ets_printf("2\n\n"); if(sector == 512 - 4 || sector == 1024 - 4) sector = 256 - 4; get_seg_size(((sector + 4)>>1)*FSECTOR_SIZE + FSECTOR_SIZE); if(seg_size == 0xffffffff) return; if(seg_size == 0) { 0x4010800C(FSECTOR_SIZE); } else { 0x4010800C(seg_size + 0x1010); } break; default: ets_printf("error user bin flag, flag = %x\n", bootcfg.boot_number & 0x0f); } }
void ICACHE_FLASH_ATTR WebSocketGotData( uint8_t c ) { switch( curhttp->state_deets ) { case 0: { int i = 0; char inkey[120]; unsigned char hash[SHA1_HASH_LEN]; SHA1_CTX c; int inkeylen = 0; curhttp->is_dynamic = 1; while( curlen > 20 ) { curdata++; curlen--; if( strncmp( curdata, "Sec-WebSocket-Key: ", 19 ) == 0 ) { break; } } if( curlen <= 21 ) { HTDEBUG( "No websocket key found.\n" ); curhttp->state = HTTP_WAIT_CLOSE; return; } curdata+= 19; curlen -= 19; #define WS_KEY_LEN 36 #define WS_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" #define WS_RETKEY_SIZEM1 32 while( curlen > 1 ) { uint8_t lc = *(curdata++); inkey[i] = lc; curlen--; if( lc == '\r' ) { inkey[i] = 0; break; } i++; if( i >= sizeof( inkey ) - WS_KEY_LEN - 5 ) { HTDEBUG( "Websocket key too big.\n" ); curhttp->state = HTTP_WAIT_CLOSE; return; } } if( curlen <= 1 ) { HTDEBUG( "Invalid websocket key found.\n" ); curhttp->state = HTTP_WAIT_CLOSE; return; } if( i + WS_KEY_LEN + 1 >= sizeof( inkey ) ) { HTDEBUG( "WSKEY Too Big.\n" ); curhttp->state = HTTP_WAIT_CLOSE; return; } ets_memcpy( &inkey[i], WS_KEY, WS_KEY_LEN + 1 ); i += WS_KEY_LEN; SHA1_Init( &c ); SHA1_Update( &c, inkey, i ); SHA1_Final( hash, &c ); #if (WS_RETKEY_SIZE > MAX_PATHLEN - 10 ) #error MAX_PATHLEN too short. #endif my_base64_encode( hash, SHA1_HASH_LEN, curhttp->pathbuffer + (MAX_PATHLEN-WS_RETKEY_SIZEM1) ); curhttp->bytessofar = 0; curhttp->bytesleft = 0; NewWebSocket(); //Respond... curhttp->state_deets = 1; break; } case 1: if( c == '\n' ) curhttp->state_deets = 2; break; case 2: if( c == '\r' ) curhttp->state_deets = 3; else curhttp->state_deets = 1; break; case 3: if( c == '\n' ) curhttp->state_deets = 4; else curhttp->state_deets = 1; break; case 5: //Established connection. { //XXX TODO: Seems to malfunction on large-ish packets. I know it has problems with 140-byte payloads. if( curlen < 5 ) //Can't interpret packet. break; uint8_t fin = c & 1; uint8_t opcode = c << 4; uint16_t payloadlen = *(curdata++); curlen--; if( !(payloadlen & 0x80) ) { HTDEBUG( "Unmasked packet.\n" ); curhttp->state = HTTP_WAIT_CLOSE; break; } payloadlen &= 0x7f; if( payloadlen == 127 ) { //Very long payload. //Not supported. HTDEBUG( "Unsupported payload packet.\n" ); curhttp->state = HTTP_WAIT_CLOSE; break; } else if( payloadlen == 126 ) { payloadlen = (curdata[0] << 8) | curdata[1]; curdata += 2; curlen -= 2; } wsmask[0] = curdata[0]; wsmask[1] = curdata[1]; wsmask[2] = curdata[2]; wsmask[3] = curdata[3]; curdata += 4; curlen -= 4; wsmaskplace = 0; //XXX Warning: When packets get larger, they may split the //websockets packets into multiple parts. We could handle this //but at the cost of prescious RAM. I am chosing to just drop those //packets on the floor, and restarting the connection. if( curlen < payloadlen ) { HTDEBUG( "Websocket Fragmented. %d %d\n", curlen, payloadlen ); curhttp->state = HTTP_WAIT_CLOSE; return; } WebSocketData( payloadlen ); curlen -= payloadlen; curdata += payloadlen; break; } default: break; } }
static uint32 sub_3FFE8018(uint32 readpos) { uint8 stack[0x10]; uint8 temp[0x10]; rom_header header; uint32 sectaddr; uint32 sectcount; uint32 sectlen; uint8 chksum; uint32 loop; bool fullsize; uint32 blocksof16; uint32 remainder; uint32 processed; uint32 toprocess; uint8 *datapos; if (SPIRead(readpos, &header, 0x10) != 0) { return 1; } if (header.magic1 != 0xe9) { return 1; } sectaddr = header.add[3] << 24 | header.add[2] << 16 | header.add[1] << 8 | header.add[0]; sectlen = header.len[3] << 24 | header.len[2] << 16 | header.len[1] << 8 | header.len[0]; if (SPIRead(readpos + 0x10, stack, 0x10) != 0) { return 1; } readpos += 0x20; if (sectcount != 0) { datapos = stack; // read data chksum = CHKSUM_INIT; // checksum init outaddr = sectaddr; // section address processed = 0; for (sectcount = header.count; sectcount > 0; sectcount--) { toprocess = 0x10 - processed; // left to process if (sectlen < toprocess) { // section shorter than remaining bytes fullsize = false; blocksof16 = 0; remainder = sectlen; } else { fullsize = true; // process what's left in the buffer if ((toprocess & 3 == 0) && (toprocess > 0)) { // non-zero exact multiple of 4 a9 = toprocess / 4; for (loop = 0; loop < a9; loop++) { // process 4 bytes at a time chksum ^= datapos[0]; // chksum the 4 bytes chksum ^= datapos[1]; chksum ^= datapos[2]; chksum ^= datapos[3]; *(uint32*)outaddr = *(uint32*)datapos; // copy the 4 bytes datapos += 4; // advance input pointer outaddr += 4; // advance output pointer } } else { // single byte method for (loop = 0; loop < toprocess; loop++) { chksum ^= datapos[0]; // add to chksum outaddr[0] = datapos[0]; // copy byte datapos++; // advance input pointer outaddr++; // advance output pointer } } blocksof16 = (sectlen - toprocess) / 16; remainder = (sectlen - toprocess) % 16; } // process full blocks of 16 if (blocksof16) { for (loop = 0; loop < blocksof16; loop++) { // loop for remaining/16 times if (SPIRead(readpos, stack, 0x10) != 0) { // read 16 bytes return 1; } readpos += 0x10; // increment readpos for (a0 = 0; a0 < 0x10; a0++) { chksum ^= stack[a0]; // add to chksum } ets_memcpy(outaddr, stack, 0x10); // copy block outaddr += 0x10; // increment outaddr } } if (fullsize) { // get next block for remainder if (SPIRead(readpos, stack, 0x10) != 0) { return 1; } readpos += 0x10; datapos = stack; processed = 0; } if (remainder) { // process the remainder after the blocks of 16 if (remainder % 4 == 0) { // multiple of 4 a7 = remainder / 4; for (loop = 0; loop < a7; loop++) { // process 4 bytes at a time chksum ^= datapos[3]; // chksum the 4 bytes chksum ^= datapos[2]; chksum ^= datapos[1]; chksum ^= datapos[0]; *(uint32*)(outaddr) = *(uint32*)(datapos); // copy the 4 bytes datapos += 4; // advance input pointer outaddr += 4; // advance output pointer } } else { // single byte version for (loop = 0; loop < remainder; loop++) { chksum ^= datapos[0]; // chksum outaddr[0] = datapos[0]; // copy byte datapos++; outaddr++; } } processed += remainder; } if (sectcount > 1) { // read next section toprocess = 0x10 - processed; // left to process in buffer if (toprocess >= 8) { // next header is already in buffer sectlen = datapos[7] << 24 | datapos[6] << 16 | datapos[5] << 8 | datapos[4]; outaddr = datapos[3] << 24 | datapos[2] << 16 | datapos[1] << 8 | datapos[0]; processed += 8; // processed another 8 } else { ets_memcopy(temp, stack + processed, toprocess); // copy remaining to temp buffer if (SPIRead(readpos, stack, 0x10) != 0) { // read as normal break; } readpos += 0x10; processed = 8 - toprocess; // how many of new will be processed in this operation ets_memcpy(temp + toprocess, stack, processed); // copy needed bytes from new read to temp buffer outaddr = *(uint32*)(temp); // get values from temp buffer sectlen = *(uint32*)(temp+4); } datapos = stack + processed; } } if (stack[0x0f] != chksum) { // compare calculated and stored checksums return 1; // chksum failed } } callx0(header.entry); return 0; }