WIP: SD write debugging (store-TB TCI + sd-watch) and vvfat/ssi-sd fixes
Diagnostic: routes store-containing TBs through TCI and logs out-of-bounds guest stores to isolate the SdSpiCard corruption. Also carries the FAT32 vvfat root/cluster fixes and ssi-sd command framing. Squash/split before upstreaming.
This commit is contained in:
+16
-4
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+91
-50
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+48
-3
@@ -29,8 +29,10 @@
|
||||
#include <emscripten.h>
|
||||
#include <emscripten/threading.h>
|
||||
#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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user