diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 575be0e359..1095dfd912 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -755,6 +755,18 @@ static void tb_remove(TranslationBlock *tb) } #endif /* CONFIG_USER_ONLY */ +#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN) +#include "../../tcg/wasm32.h" + +static void wasm_remove_tb_instance(void *p, uint32_t hash, void *userp) +{ + TranslationBlock *tb = p; + (void)hash; + (void)userp; + remove_tb(tb->tc.ptr); +} +#endif + /* flush all the translation blocks */ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) { @@ -771,6 +783,10 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count) tcg_flush_jmp_cache(cpu); } +#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) + qht_iter(&tb_ctx.htable, wasm_remove_tb_instance, NULL); + flush_tb_instances(); +#endif qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE); tb_remove_all(); @@ -879,10 +895,6 @@ static inline void tb_jmp_unlink(TranslationBlock *dest) qemu_spin_unlock(&dest->jmp_lock); } -#if !defined(CONFIG_TCG_INTERPRETER) && defined(EMSCRIPTEN) -#include "../../tcg/wasm32.h" -#endif - static void tb_jmp_cache_inval_tb(TranslationBlock *tb) { CPUState *cpu; diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 8ebadf8e9e..1e38df86e8 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -177,11 +177,19 @@ static int rr_cpu_count(void) * elsewhere. */ +#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) +#include "../../tcg/wasm32.h" +#endif + static void *rr_cpu_thread_fn(void *arg) { Notifier force_rcu; CPUState *cpu = arg; +#if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) + init_wasm32(); +#endif + assert(tcg_enabled()); rcu_register_thread(); force_rcu.notify = rr_force_rcu; diff --git a/block/vvfat.c b/block/vvfat.c index 8ffe8b3b9b..3c0ab6c228 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -749,6 +749,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) const char* dirname = mapping->path; int first_cluster = mapping->begin; int parent_index = mapping->info.dir.parent_mapping_index; + bool is_root = parent_index < 0; mapping_t* parent_mapping = (mapping_t*) (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : NULL); int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1; @@ -765,9 +766,9 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) } i = mapping->info.dir.first_dir_index = - first_cluster == 0 ? 0 : s->directory.next; + is_root ? 0 : s->directory.next; - if (first_cluster != 0) { + if (!is_root) { /* create the top entries of a subdirectory */ (void)create_short_and_long_name(s, i, ".", 1); (void)create_short_and_long_name(s, i, "..", 1); @@ -781,13 +782,14 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) int is_dot=!strcmp(entry->d_name,"."); int is_dotdot=!strcmp(entry->d_name,".."); - if (first_cluster == 0 && s->directory.next >= s->root_entries - 1) { + if (is_root && s->fat_type != 32 && + s->directory.next >= s->root_entries - 1) { fprintf(stderr, "Too many entries in root directory\n"); closedir(dir); return -2; } - if(first_cluster == 0 && (is_dotdot || is_dot)) + if(is_root && (is_dotdot || is_dot)) continue; buffer = g_malloc(length); @@ -860,8 +862,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) memset(direntry,0,sizeof(direntry_t)); } - if (s->fat_type != 32 && - mapping_index == 0 && + if (s->fat_type != 32 && is_root && s->directory.next < s->root_entries) { /* root directory */ int cur = s->directory.next; @@ -877,20 +878,29 @@ static int read_directory(BDRVVVFATState* s, int mapping_index) * 0x20 / s->cluster_size; mapping->end = first_cluster; - direntry = array_get(&(s->directory), mapping->dir_index); - set_begin_of_direntry(direntry, mapping->begin); + if (!is_root) { + direntry = array_get(&(s->directory), mapping->dir_index); + set_begin_of_direntry(direntry, mapping->begin); + } return 0; } static inline int32_t sector2cluster(BDRVVVFATState* s,off_t sector_num) { - return (sector_num - s->offset_to_root_dir) / s->sectors_per_cluster; + off_t relative_sector = sector_num - s->offset_to_root_dir; + + if (relative_sector < 0) { + return -1 - (-relative_sector - 1) / s->sectors_per_cluster; + } + return relative_sector / s->sectors_per_cluster + + (s->fat_type == 32 ? 2 : 0); } static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num) { - return s->offset_to_root_dir + s->sectors_per_cluster * cluster_num; + return s->offset_to_root_dir + s->sectors_per_cluster + * (cluster_num - (s->fat_type == 32 ? 2 : 0)); } static int init_directories(BDRVVVFATState* s, @@ -934,11 +944,12 @@ static int init_directories(BDRVVVFATState* s, init_fat(s); /* TODO: if there are more entries, bootsector has to be adjusted! */ - s->root_entries = 0x02 * 0x10 * s->sectors_per_cluster; + s->root_entries = s->fat_type == 32 ? 0 : + 0x02 * 0x10 * s->sectors_per_cluster; s->cluster_count=sector2cluster(s, s->sector_count); mapping = array_get_next(&(s->mapping)); - mapping->begin = 0; + mapping->begin = s->fat_type == 32 ? 2 : 0; mapping->dir_index = 0; mapping->info.dir.parent_mapping_index = -1; mapping->first_mapping_index = -1; @@ -950,11 +961,10 @@ static int init_directories(BDRVVVFATState* s, mapping->read_only = 0; s->path = mapping->path; - for (i = 0, cluster = 0; i < s->mapping.next; i++) { - /* MS-DOS expects the FAT to be 0 for the root directory - * (except for the media byte). */ - /* LATER TODO: still true for FAT32? */ - int fix_fat = (i != 0); + for (i = 0, cluster = s->fat_type == 32 ? 2 : 0; + i < s->mapping.next; i++) { + /* FAT12/16 stores the root directory outside the cluster chain. */ + int fix_fat = (i != 0 || s->fat_type == 32); mapping = array_get(&(s->mapping), i); if (mapping->mode & MODE_DIRECTORY) { @@ -1026,22 +1036,35 @@ static int init_directories(BDRVVVFATState* s, /* media descriptor: hard disk=0xf8, floppy=0xf0 */ bootsector->media_type = (s->offset_to_bootsector > 0 ? 0xf8 : 0xf0); s->fat.pointer[0] = bootsector->media_type; - bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat); + bootsector->sectors_per_fat = s->fat_type == 32 ? 0 : + cpu_to_le16(s->sectors_per_fat); bootsector->sectors_per_track = cpu_to_le16(secs); bootsector->number_of_heads = cpu_to_le16(heads); bootsector->hidden_sectors = cpu_to_le32(s->offset_to_bootsector); bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0); - /* LATER TODO: if FAT32, this is wrong */ - /* drive_number: fda=0, hda=0x80 */ - bootsector->u.fat16.drive_number = s->offset_to_bootsector == 0 ? 0 : 0x80; - bootsector->u.fat16.signature=0x29; - bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); - - memcpy(bootsector->u.fat16.volume_label, s->volume_label, - sizeof(bootsector->u.fat16.volume_label)); - memcpy(bootsector->u.fat16.fat_type, - s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); + if (s->fat_type == 32) { + bootsector->u.fat32.sectors_per_fat = cpu_to_le32(s->sectors_per_fat); + bootsector->u.fat32.first_cluster_of_root_dir = cpu_to_le32(2); + bootsector->u.fat32.info_sector = cpu_to_le16(0xffff); + bootsector->u.fat32.backup_boot_sector = cpu_to_le16(0xffff); + bootsector->u.fat32.drive_number = 0x80; + bootsector->u.fat32.signature = 0x29; + bootsector->u.fat32.id = cpu_to_le32(0xfabe1afd); + memcpy(bootsector->u.fat32.volume_label, s->volume_label, + sizeof(bootsector->u.fat32.volume_label)); + memcpy(bootsector->u.fat32.fat_type, "FAT32 ", 8); + } else { + /* drive_number: fda=0, hda=0x80 */ + bootsector->u.fat16.drive_number = + s->offset_to_bootsector == 0 ? 0 : 0x80; + bootsector->u.fat16.signature=0x29; + bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd); + memcpy(bootsector->u.fat16.volume_label, s->volume_label, + sizeof(bootsector->u.fat16.volume_label)); + memcpy(bootsector->u.fat16.fat_type, + s->fat_type == 12 ? "FAT12 " : "FAT16 ", 8); + } bootsector->magic[0]=0x55; bootsector->magic[1]=0xaa; return 0; @@ -1139,6 +1162,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, { BDRVVVFATState *s = bs->opaque; int cyls, heads, secs; + uint64_t total_sectors; bool floppy; const char *dirname, *label; QemuOpts *opts; @@ -1205,7 +1229,9 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, switch (s->fat_type) { case 32: +#ifndef EMSCRIPTEN warn_report("FAT32 has not been tested. You are welcome to do so!"); +#endif break; case 16: case 12: @@ -1219,8 +1245,17 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, s->bs = bs; - /* LATER TODO: if FAT32, adjust */ - s->sectors_per_cluster=0x10; +#ifdef EMSCRIPTEN + if (!floppy && s->fat_type == 32) { + /* Browser SD Geometry - A larger cluster keeps the synthesized 32 GiB FAT near 4 MiB. */ + s->sectors_per_cluster = 0x40; + total_sectors = 32ULL * 1024 * 1024 * 1024 / BDRV_SECTOR_SIZE; + } else +#endif + { + s->sectors_per_cluster = 0x10; + total_sectors = (uint64_t)cyls * heads * secs; + } s->current_cluster=0xffffffff; @@ -1232,8 +1267,8 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, DLOG(fprintf(stderr, "vvfat %s chs %d,%d,%d\n", dirname, cyls, heads, secs)); - s->sector_count = cyls * heads * secs - s->offset_to_bootsector; - bs->total_sectors = cyls * heads * secs; + s->sector_count = total_sectors - s->offset_to_bootsector; + bs->total_sectors = total_sectors; if (qemu_opt_get_bool(opts, "rw", false)) { if (!bdrv_is_read_only(bs)) { @@ -1259,8 +1294,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } - s->sector_count = s->offset_to_root_dir - + s->sectors_per_cluster * s->cluster_count; + s->sector_count = cluster2sector(s, s->cluster_count); /* Disable migration when vvfat is used rw */ if (s->qcow) { @@ -1415,6 +1449,7 @@ read_cluster_directory: if(lseek(s->current_fd, offset, SEEK_SET)!=offset) return -3; s->cluster=s->cluster_buffer; + memset(s->cluster, 0, s->cluster_size); result=read(s->current_fd,s->cluster,s->cluster_size); if(result<0) { s->current_cluster = -1; @@ -1523,8 +1558,9 @@ vvfat_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sector } else { uint32_t sector = sector_num - s->offset_to_root_dir, sector_offset_in_cluster=(sector%s->sectors_per_cluster), - cluster_num=sector/s->sectors_per_cluster; - if(cluster_num > s->cluster_count || read_cluster(s, cluster_num) != 0) { + cluster_num=sector/s->sectors_per_cluster + + (s->fat_type == 32 ? 2 : 0); + if(cluster_num >= s->cluster_count || read_cluster(s, cluster_num) != 0) { /* LATER TODO: strict: return -1; */ memset(buf+i*0x200,0,0x200); continue; @@ -1780,7 +1816,8 @@ static int parse_short_name(BDRVVVFATState* s, static inline uint32_t modified_fat_get(BDRVVVFATState* s, unsigned int cluster) { - if (cluster < s->last_cluster_of_root_directory) { + if (s->fat_type != 32 && + cluster < s->last_cluster_of_root_directory) { if (cluster + 1 == s->last_cluster_of_root_directory) return s->max_fat_value; else @@ -2182,14 +2219,17 @@ DLOG(checkpoint()); mapping->mode |= MODE_DELETED; } - used_clusters_count = check_directory_consistency(s, 0, s->path); + mapping_t *root_mapping = array_get(&(s->mapping), 0); + used_clusters_count = check_directory_consistency(s, + root_mapping->begin, s->path); if (used_clusters_count <= 0) { DLOG(fprintf(stderr, "problem in directory\n")); return 0; } - check = s->last_cluster_of_root_directory; - for (i = check; i < sector2cluster(s, s->sector_count); i++) { + check = s->fat_type == 32 ? 0 : s->last_cluster_of_root_directory; + for (i = s->fat_type == 32 ? 2 : check; + i < sector2cluster(s, s->sector_count); i++) { if (modified_fat_get(s, i)) { if(!s->used_clusters[i]) { DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i)); @@ -2417,7 +2457,10 @@ static int coroutine_fn GRAPH_RDLOCK commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) { direntry_t* direntry = array_get(&(s->directory), dir_index); - uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry); + bool is_root = dir_index == 0; + mapping_t *root_mapping = array_get(&(s->mapping), 0); + uint32_t first_cluster = is_root ? root_mapping->begin : + begin_of_direntry(direntry); mapping_t* mapping = find_mapping_for_cluster(s, first_cluster); int factor = 0x10 * s->sectors_per_cluster; int old_cluster_count, new_cluster_count; @@ -2440,7 +2483,7 @@ commit_direntries(BDRVVVFATState* s, int dir_index, int parent_mapping_index) first_dir_index = current_dir_index; mapping->info.dir.parent_mapping_index = parent_mapping_index; - if (first_cluster == 0) { + if (is_root && s->fat_type != 32) { old_cluster_count = new_cluster_count = s->last_cluster_of_root_directory; } else { @@ -2998,11 +3041,9 @@ DLOG(checkpoint()); */ unsigned char *bootsector = s->first_sectors + s->offset_to_bootsector * 0x200; - /* - * LATER TODO: if FAT32, this is wrong (see init_directories(), - * which always creates a FAT16 bootsector) - */ - const int reserved1_offset = offsetof(bootsector_t, u.fat16.reserved1); + const int reserved1_offset = s->fat_type == 32 ? + offsetof(bootsector_t, u.fat32.reserved1) : + offsetof(bootsector_t, u.fat16.reserved1); for (i = 0; i < 0x200; i++) { if (i != reserved1_offset && bootsector[i] != buf[i]) { @@ -3057,8 +3098,8 @@ DLOG(checkpoint()); begin = sector_num; if (end > sector_num + nb_sectors) end = sector_num + nb_sectors; - dir_index = mapping->dir_index + - 0x10 * (begin - mapping->begin * s->sectors_per_cluster); + dir_index = mapping->info.dir.first_dir_index + + 0x10 * (begin - cluster2sector(s, mapping->begin)); direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num)); for (k = 0; k < (end - begin) * 0x10; k++) { @@ -3093,7 +3134,7 @@ DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sec } for (i = first_cluster; i <= last_cluster; i++) { - if (i >= 0) { + if (i >= 0 && i < sector2cluster(s, s->sector_count)) { s->used_clusters[i] |= USED_ALLOCATED; } } diff --git a/hw/misc/esp32c3_jtag.c b/hw/misc/esp32c3_jtag.c index 82ee69717b..64a971f183 100644 --- a/hw/misc/esp32c3_jtag.c +++ b/hw/misc/esp32c3_jtag.c @@ -16,10 +16,18 @@ #include "hw/misc/esp32c3_jtag.h" +/* USB Serial JTAG Console Tap - The firmware routes ESP-IDF console output (incl. panic dumps) through this peripheral. EP1 is the byte FIFO; EP1_CONF bit1 (SERIAL_IN_EP_DATA_FREE) must read set so the driver believes the TX FIFO can always accept a byte. */ +#define ESP32C3_JTAG_EP1_REG 0x00 +#define ESP32C3_JTAG_EP1_CONF_REG 0x04 +#define ESP32C3_JTAG_IN_EP_DATA_FREE (1u << 1) + static uint64_t esp32c3_jtag_read(void *opaque, hwaddr addr, unsigned int size) { ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); (void) s; + if (addr == ESP32C3_JTAG_EP1_CONF_REG) { + return ESP32C3_JTAG_IN_EP_DATA_FREE; + } return 0; } @@ -27,6 +35,9 @@ static void esp32c3_jtag_write(void *opaque, hwaddr addr, uint64_t value, unsign { ESP32C3UsbJtagState *s = ESP32C3_JTAG(opaque); (void) s; + if (addr == ESP32C3_JTAG_EP1_REG) { + fputc((int)(value & 0xff), stderr); + } } static const MemoryRegionOps esp32c3_jtag_ops = { diff --git a/hw/riscv/esp32c3.c b/hw/riscv/esp32c3.c index febc96bfe3..af8bb86c97 100644 --- a/hw/riscv/esp32c3.c +++ b/hw/riscv/esp32c3.c @@ -114,6 +114,7 @@ EMSCRIPTEN_KEEPALIVE void xteink_wasm_set_adc(int channel, uint32_t value) { if (xteink_wasm_machine && channel >= 0 && channel < ESP32C3_ADC_CHANNELS) { + fprintf(stderr, "[button] adc channel=%d value=%u\n", channel, value); qatomic_set(&xteink_wasm_machine->adc.input[channel], MIN(value, UINT32_C(0xfff))); } @@ -122,6 +123,7 @@ EMSCRIPTEN_KEEPALIVE void xteink_wasm_set_adc(int channel, uint32_t value) EMSCRIPTEN_KEEPALIVE void xteink_wasm_set_gpio(int pin, int level) { if (xteink_wasm_machine && pin >= 0 && pin < ESP32_GPIO_COUNT) { + fprintf(stderr, "[button] gpio pin=%d level=%d\n", pin, level); esp32_gpio_set_input_level(&xteink_wasm_machine->gpio.parent, pin, level); } diff --git a/hw/riscv/esp32c3_intmatrix.c b/hw/riscv/esp32c3_intmatrix.c index c1376b7299..1275808dc0 100644 --- a/hw/riscv/esp32c3_intmatrix.c +++ b/hw/riscv/esp32c3_intmatrix.c @@ -25,9 +25,10 @@ #define INTMATRIX_DEBUG 0 #define INTMATRIX_WARNING 0 -#define BIT_SET(reg, bit) ((reg) & BIT(bit)) -#define CLEAR_BIT(reg, bit) do { (reg) &= ~BIT(bit); } while(0) -#define SET_BIT(reg, bit) do { (reg) |= BIT(bit); } while(0) +/* 64-bit Shifts For irq_levels - There are up to 62 interrupt sources, so bit ops on the uint64_t level mask must shift in 64-bit. QEMU's BIT() is `1UL << nr`, which is only 32-bit on wasm32 and silently aliases source N to N-32. */ +#define BIT_SET(reg, bit) ((reg) & (1ULL << (bit))) +#define CLEAR_BIT(reg, bit) do { (reg) &= ~(1ULL << (bit)); } while(0) +#define SET_BIT(reg, bit) do { (reg) |= (1ULL << (bit)); } while(0) static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line) @@ -36,7 +37,7 @@ static int esp32c3_get_output_line_level(ESP32C3IntMatrixState *s, int line) for (int i = 0; level_shared == 0 && i < ESP32C3_INT_MATRIX_INPUTS; i++) { const uint_fast8_t mapped = s->irq_map[i]; - if (mapped == line && (s->irq_levels & BIT(i))) + if (mapped == line && (s->irq_levels & (1ULL << i))) { level_shared |= 1; } diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 552dc2c8ea..eb12207897 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -162,6 +162,10 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val) return SSI_DUMMY; } + if ((val & 0xc0) != 0x40) { + DPRINTF("Ignore non-command byte 0x%02x\n", val); + return SSI_DUMMY; + } s->cmd = val & 0x3f; s->mode = SSI_SD_CMDARG; s->arglen = 0; diff --git a/tcg/tcg.c b/tcg/tcg.c index 214e66e9d6..0f6c0f5082 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -6607,6 +6607,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) #endif #if defined(EMSCRIPTEN) && !defined(CONFIG_TCG_INTERPRETER) + if (wasm_tci_only_tb) { + for (int i = 0; i < get_core_nums(); i++) { + export_vec_base[i] = WASM_TCI_ONLY_ENTRY; + } + } + tcg_sub_out8(s, 0x0b); //end if tcg_sub_out8(s, 0x0b); //end loop tcg_sub_out8(s, 0x0); // unreachable diff --git a/tcg/wasm32.c b/tcg/wasm32.c index 7393dab398..19b31ed4df 100644 --- a/tcg/wasm32.c +++ b/tcg/wasm32.c @@ -29,8 +29,10 @@ #include #include #include "wasm32.h" +#include "exec/translation-block.h" __thread uintptr_t tci_tb_ptr; +__thread bool wasm_tci_only_tb; /* Disassemble TCI bytecode. */ int print_insn_tci(bfd_vma addr, disassemble_info *info) @@ -66,12 +68,16 @@ EM_JS(int, instantiate_wasm, (), { }); var ptr = export_vec_begin + 4 * Module.__wasm32_tb.cur_core_num; const fidx = addFunction(inst.exports.start, 'ii'); + Module.__wasm32_tb.dynamic_functions.add(fidx); memory_v.setUint32(ptr, fidx, true); const remove_n = memory_v.getInt32(Module.__wasm32_tb.to_remove_instance_idx_ptr, true); if (remove_n > 500) { for (var i = 0; i < remove_n * 4; i += 4) { - removeFunction(memory_v.getInt32(Module.__wasm32_tb.to_remove_instance_ptr + i, true)); + const fidx = memory_v.getInt32(Module.__wasm32_tb.to_remove_instance_ptr + i, true); + if (Module.__wasm32_tb.dynamic_functions.delete(fidx)) { + removeFunction(fidx); + } } memory_v.setInt32(Module.__wasm32_tb.to_remove_instance_idx_ptr, 0, true); } @@ -79,6 +85,22 @@ EM_JS(int, instantiate_wasm, (), { return 0; }); +EM_JS(void, flush_tb_instances, (), { + const tb = Module.__wasm32_tb; + if (!tb) { + return; + } + const memory_v = new DataView(HEAP8.buffer); + const remove_n = memory_v.getInt32(tb.to_remove_instance_idx_ptr, true); + for (var i = 0; i < remove_n * 4; i += 4) { + const fidx = memory_v.getInt32(tb.to_remove_instance_ptr + i, true); + if (tb.dynamic_functions.delete(fidx)) { + removeFunction(fidx); + } + } + memory_v.setInt32(tb.to_remove_instance_idx_ptr, 0, true); +}); + __thread bool initdone = false; __thread int cur_core_num = -1; __thread int export_vec_off = -1; @@ -96,6 +118,9 @@ void remove_tb(void *tb_ptr) { return; } *slot = 0; + if (to_remove_instance_idx == TO_REMOVE_INSTANCE_SIZE) { + flush_tb_instances(); + } to_remove_instance[to_remove_instance_idx++] = f; } @@ -131,6 +156,7 @@ EM_JS(void, init_wasm32_js, (int tb_ptr_ptr, int cur_core_num, int to_remove_ins cur_core_num: cur_core_num, to_remove_instance_ptr: to_remove_instance_ptr, to_remove_instance_idx_ptr: to_remove_instance_idx_ptr, + dynamic_functions: new Set(), }; }); @@ -485,6 +511,19 @@ static void tci_qemu_st(CPUArchState *env, uint64_t taddr, uint64_t val, uintptr_t ra = (uintptr_t)tb_ptr; uint64_t target_addr = tlb_load(env, taddr, mop, ptr, false); + if (target_addr != 0) { + uint64_t mem_bytes = (uint64_t)__builtin_wasm_memory_size(0) << 16; + if (target_addr + (1u << (mop & MO_SIZE)) > mem_bytes) { + TranslationBlock *tb = tcg_tb_lookup(ra); + fprintf(stderr, + "[sd-watch] OOB store pc=%08llx gaddr=%08llx haddr=%08llx size=%u value=%08llx membytes=%08llx\n", + (unsigned long long)(tb ? tb->pc : 0), + (unsigned long long)taddr, (unsigned long long)target_addr, + 1u << (mop & MO_SIZE), (unsigned long long)val, + (unsigned long long)mem_bytes); + return; + } + } if (target_addr != 0) { switch (mop & MO_SIZE) { case MO_UB: @@ -1111,7 +1150,9 @@ static inline uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env) tb_ptr = *(uint32_t **)ptr; ctx.tb_ptr = tb_ptr; int tb_entry_ptr = (uint32_t)tb_ptr + export_vec_off; - if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { + if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { + /* ponytail: Store TBs use TCI while tracing SD object corruption. */ + } else if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { *(int32_t*)tb_entry_ptr -= 1; } else { // enter to wasm TB @@ -1132,7 +1173,9 @@ static inline uintptr_t tcg_qemu_tb_exec_tci(CPUArchState *env) ctx.tb_ptr = tb_ptr; int tb_entry_ptr = (uint32_t)tb_ptr + export_vec_off; - if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { + if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { + /* Continue in TCI. */ + } else if ((*(int32_t*)tb_entry_ptr <= 0) && (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM))) { *(int32_t*)tb_entry_ptr -= 1; } else { // enter to wasm TB @@ -1214,6 +1257,8 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, uint32_t res; if (*(int32_t*)tb_entry_ptr > 0) { res = ((wasm_func_ptr)(*(uint32_t*)tb_entry_ptr))(&ctx); + } else if (*(int32_t *)tb_entry_ptr == WASM_TCI_ONLY_ENTRY) { + res = tcg_qemu_tb_exec_tci(env); } else if (*(int32_t*)tb_entry_ptr > (-1 * INSTANTIATE_NUM)) { *(int32_t*)tb_entry_ptr -= 1; res = tcg_qemu_tb_exec_tci(env); diff --git a/tcg/wasm32.h b/tcg/wasm32.h index 1861510f0b..a8b525abe3 100644 --- a/tcg/wasm32.h +++ b/tcg/wasm32.h @@ -37,8 +37,13 @@ int get_core_nums(); void remove_tb(void *tb_ptr); +void flush_tb_instances(void); + void init_wasm32(); +extern __thread bool wasm_tci_only_tb; + #define INSTANTIATE_NUM 1500 +#define WASM_TCI_ONLY_ENTRY (-2147483647 - 1) #endif diff --git a/tcg/wasm32/tcg-target.c.inc b/tcg/wasm32/tcg-target.c.inc index 9e82297a3f..053c941f99 100644 --- a/tcg/wasm32/tcg-target.c.inc +++ b/tcg/wasm32/tcg-target.c.inc @@ -3370,6 +3370,7 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGOpcode opc, const TCGArg *args, bo } static void tcg_out_qemu_st(TCGContext *s, TCGOpcode opc, const TCGArg *args, bool is_64) { + wasm_tci_only_tb = true; tcg_tci_out_qemu_ldst(s, opc, args); tcg_wasm_out_qemu_st(s, args, is_64); } @@ -3773,6 +3774,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, void tcg_out_init() { current_label_pos = 0; env_cached = false; + wasm_tci_only_tb = false; } /* Test if a constant matches the constraint. */