Files
QNX/services/kdebug/cache_ctrl.c
2025-08-20 19:02:58 +08:00

135 lines
3.9 KiB
C

/*
* $QNXLicenseC:
* Copyright 2007, QNX Software Systems. All Rights Reserved.
*
* You must obtain a written license from and pay applicable
* license fees to QNX Software Systems before you may reproduce,
* modify or distribute this software, or any work that includes
* all or part of this software. Free development licenses are
* available for evaluation and non-commercial purposes. For more
* information visit http://licensing.qnx.com or email
* licensing@qnx.com.
*
* This file may contain contributions from others. Please review
* this entire file for other proprietary rights or license notices,
* as well as the QNX Development Suite License Guide at
* http://licensing.qnx.com/license-guide/ for other information.
* $
*/
#include "kdebug.h"
static void
cache_one(struct cacheattr_entry *cache, uintptr_t base, size_t len, int flags) {
uintptr_t vaddr;
size_t cache_len;
vaddr = base & ~(cache->line_size-1);
cache_len = len + (base - vaddr);
while(cache_len != 0) {
unsigned lines;
paddr_t addr;
size_t valid_len;
valid_len = cache_len;
addr = vaddr;
if(cache->flags & CACHE_FLAG_CTRL_PHYS) {
if(vaddrinfo(NULL, vaddr, &addr, &valid_len) == PROT_NONE) {
unsigned page = SYSPAGE_ENTRY(system_private)->pagesize;
/* make vaddr skip to the next page boundary */
addr = (vaddr + page) & (~(page-1));
if(cache_len < (addr - vaddr)) {
cache_len = 0;
} else {
cache_len -= (addr - vaddr);
vaddr = addr;
}
continue;
}
}
lines = (valid_len + cache->line_size - 1) / cache->line_size;
while(lines != 0) {
unsigned done_lines;
size_t done_size;
//NYI: need to make handle 64 bit paddrs....
done_lines = cache->control((paddr32_t)addr, lines, flags, cache, _syspage_ptr);
if(done_lines == 0) return; /* whole cache handled */
done_size = done_lines * cache->line_size;
addr += done_size;
lines -= done_lines;
}
cache_len -= valid_len;
}
}
static void
cache_iterate(int cache_idx, uintptr_t base, size_t len, int flags, unsigned term_flag) {
struct cacheattr_entry *cache_base;
struct cacheattr_entry *cache;
struct cacheattr_entry *subset_cache;
subset_cache = NULL;
cache_base = SYSPAGE_ENTRY(cacheattr);
for(;;) {
if(cache_idx == CACHE_LIST_END) break;
cache = &cache_base[cache_idx];
if(cache->flags & term_flag) break;
if(cache->flags & CACHE_FLAG_SUBSET) {
//We'll get to it later
subset_cache = cache;
} else {
if(subset_cache != NULL) {
//
// We've skipped issuing control functions to some cache levels
// because they obey the 'subset' property. Have to issue one
// to the last level now.
//
cache_one(subset_cache, base, len, flags);
}
cache_one(cache, base, len, flags);
subset_cache = NULL;
}
cache_idx = cache->next;
}
if(subset_cache != NULL) {
//
// We've skipped issuing control functions to some cache levels
// because they obey the 'subset' property. Have to issue one
// to the last level now.
//
cache_one(subset_cache, base, len, flags);
}
}
int
cache_control(uintptr_t base, size_t len, int flags) {
struct cpuinfo_entry *cpu;
int data_flags;
int code_flags;
//NYI: deal with SMP issues
cpu = &SYSPAGE_ENTRY(cpuinfo)[0];
data_flags = flags & (MS_SYNC|MS_ASYNC|MS_INVALIDATE);
if(data_flags != 0) {
cache_iterate(cpu->data_cache, base, len, data_flags, 0);
}
code_flags = flags & (MS_INVALIDATE|MS_INVALIDATE_ICACHE);
if(code_flags != 0) {
if(data_flags == 0) {
//Push data towards main memory until we run into a unified
//cache. This is so that when the icache(s) refill, they'll
//get up-to-date data.
cache_iterate(cpu->data_cache, base, len, MS_SYNC, CACHE_FLAG_INSTR);
}
cache_iterate(cpu->ins_cache, base, len, code_flags, 0);
}
return(0);
}
void
cache_flush(uintptr_t base, size_t len) {
cache_control(base, len, MS_SYNC|MS_INVALIDATE_ICACHE);
}