blob: 08eaca04c9d00effc53a35eda5a6295b75d7f9e5 [file] [log] [blame]
/*
* Information about kernel needed for proca ta
*
* Copyright (C) 2018 Samsung Electronics, Inc.
* Hryhorii Tur, <hryhorii.tur@partner.samsung.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/proca.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/version.h>
#include "proca_config.h"
#include "proca_log.h"
#include "proca_porting.h"
#include "gaf/proca_gaf.h"
#define PROCA_CONFIG_VERSION 3U
#define PROCA_CONFIG_MAGIC 0xCD0436EAU
static int append_sys_ram_range(struct resource *res, void *arg)
{
struct proca_config *conf = arg;
PROCA_DEBUG_LOG("System RAM region %llx-%llx was found\n",
res->start, res->end);
if (conf->sys_ram_ranges_num == MAX_MEMORY_RANGES_NUM) {
PROCA_ERROR_LOG("Unsupported number of sys ram regions %llu\n",
MAX_MEMORY_RANGES_NUM);
return -ENOMEM;
}
conf->sys_ram_ranges[conf->sys_ram_ranges_num].start = res->start;
conf->sys_ram_ranges[conf->sys_ram_ranges_num].end = res->end;
++conf->sys_ram_ranges_num;
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 42)
#define __walk_system_ram_res_cb append_sys_ram_range
#else
static int __walk_system_ram_res_cb(u64 start, u64 end, void *arg)
{
struct resource res;
res.start = start;
res.end = end;
return append_sys_ram_range(&res, arg);
}
#endif
static int prepare_sys_ram_ranges(struct proca_config *conf)
{
int ret = 0;
ret = walk_system_ram_res(0, ULONG_MAX, conf, __walk_system_ram_res_cb);
if (ret)
conf->sys_ram_ranges_num = 0;
PROCA_DEBUG_LOG("Found %llu system RAM ranges\n",
conf->sys_ram_ranges_num);
return ret;
}
static void prepare_kernel_constants(struct proca_config *conf)
{
conf->page_offset = PAGE_OFFSET;
conf->va_bits = VA_BITS;
conf->va_start = VA_START;
conf->kimage_vaddr = get_kimage_vaddr();
conf->kimage_voffset = get_kimage_voffset();
}
static void dump_proca_config(const struct proca_config *conf)
{
size_t i;
PROCA_DEBUG_LOG("version: %u\n", conf->version);
PROCA_DEBUG_LOG("size: %u\n", conf->size);
PROCA_DEBUG_LOG("magic: %u\n", conf->magic);
PROCA_DEBUG_LOG("gaf_addr: %pK\n", conf->gaf_addr);
PROCA_DEBUG_LOG("proca_table_addr: %pK\n", conf->proca_table_addr);
PROCA_DEBUG_LOG("page_offset: %llx\n", conf->page_offset);
PROCA_DEBUG_LOG("va_bits: %llu\n", conf->va_bits);
PROCA_DEBUG_LOG("va_start: %llx\n", conf->va_start);
PROCA_DEBUG_LOG("kimage_vaddr: %llx\n", conf->kimage_vaddr);
PROCA_DEBUG_LOG("kimage_voffset: %llx\n", conf->kimage_voffset);
PROCA_DEBUG_LOG("Discovered %llu system RAM ranges:\n",
conf->sys_ram_ranges_num);
for (i = 0; i < conf->sys_ram_ranges_num; ++i) {
PROCA_DEBUG_LOG("%llx-%llx.\n",
conf->sys_ram_ranges[i].start,
conf->sys_ram_ranges[i].end);
}
}
int init_proca_config(struct proca_config *conf,
const struct proca_table *proca_table_addr)
{
int ret;
BUG_ON(!conf || !proca_table_addr);
prepare_kernel_constants(conf);
conf->gaf_addr = proca_gaf_get_addr();
conf->proca_table_addr = proca_table_addr;
conf->version = PROCA_CONFIG_VERSION;
conf->size = sizeof(*conf);
conf->magic = PROCA_CONFIG_MAGIC;
ret = prepare_sys_ram_ranges(conf);
if (ret)
return ret;
dump_proca_config(conf);
return ret;
}