I am working on an embedded RTOS system, where the CPU is a MIPS32.
The GNU ld.script specifies the final binary runs from 0x80000000, I think it is KSEG0 address space.
I wrote a test to read variable by converting its address to KSEG1 region (the MMU in SOC is NOT enabled). But I hit a unexpected result.
Here comes the test codes.
#define to_uncached(p) ((void*)((uintptr_t)(p) | 0x20000000UL))
#define to_cached(p) ((void*)((uintptr_t)(p) & ~0x20000000UL))
#define CACHE_LINE_SIZE 32
#define ALIGN_DOWN(p, a) ((void*)((uintptr_t)(p) & ~((a)-1)))
#define ALIGN_UP(p, a) ((void*)(((uintptr_t)(p) + (a) - 1) & ~((a)-1)))
static inline void cache_flush(void *addr, size_t len)
{
void *start = (void*)((uintptr_t)addr & ~31);
void *end = (void*)((uintptr_t)addr + len + 31 & ~31);
for (void *p = start; p < end; p = (char*)p + 32) {
__asm__ volatile ("cache 0x15, 0(%0)" : : "r"(p) : "memory"); // Hit_Writeback_Inv_D
}
__asm__ volatile ("sync");
}
static uint32_t intvar = 0x12345678;
static int kseg_test(void)
{
uint8_t *cached_buf = NULL, *uncached_buf = NULL;
intvar = 0xabcdef12;
__asm__ volatile("sync" ::: "memory");
cached_buf = (uint8_t *)&intvar;
uncached_buf = to_uncached(cached_buf);
printf("cached_buf: %p, uncached_buf: %p\n", cached_buf, uncached_buf);
printf("Initial: cached=%x, uncached=%x\n",
*(volatile uint32_t*)cached_buf,
*(volatile uint32_t*)uncached_buf);
cache_flush(cached_buf, 64);
printf("After flush: cached=%x, uncached=%x\n",
*(volatile uint32_t*)cached_buf,
*(volatile uint32_t*)uncached_buf);
return 0;
}
And the result is,
cached_buf: 0x804578d0, uncached_buf: 0xa04578d0
Initial: cached=abcdef12, uncached=12345678
After flush: cached=abcdef12, uncached=12345678
After calling cache_flush, reading the memory with KSEG1 address got the stale data!!!
I ran the RTOS command md to read memory by specifying the KSEG0 and KSEG1 addresses, I got the expected data, as follows,
# md 0x804578d0 1
0x804578d0: abcdef12
# md 0xa04578d0 1
0xa04578d0: abcdef12
The md is using _printf(" %08x", *(unsigned int *)addr); to read memory from address specified.
So what is wrong with my kseg_test, why it did NOT read the memory correctly, but md command can do it ??