内核中 通过 struct pt_regs 来获取 用户传递的参数 2017-02-23
基于 linux-2.6.35.7/drivers/char/mem.c
#include <asm/ptrace.h>
#include <asm/uaccess.h>
static ssize_t kmsg_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char *tmp;
ssize_t ret;
tmp = kmalloc(count + 1, GFP_KERNEL);
if (tmp == NULL)
return -ENOMEM;
ret = -EFAULT;
if (!copy_from_user(tmp, buf, count)) {
tmp[count] = 0;
//add
#define STR_FOUND "sth_will_show_in_dmesg"
if(NULL!=strstr(tmp,STR_FOUND))
{
struct pt_regs *usr_regs;
usr_regs=task_pt_regs(current);
if(valid_user_regs(usr_regs))
{
int fd=usr_regs->ARM_r0;
char *write_buf=usr_regs->ARM_r1;
int len=usr_regs->ARM_r2;
/*用户态程序:
#define STR_TMP "sth_will_show_in_dmesg"
int fd=open("/dev/kmsg", O_WRONLY);
write(fd,STR_TMP,strlen(STR_TMP));
*/
/*
内核打印:
kmsg_write(),969:3 0x6fee0 22
kmsg_write(),971:buf:sth_will_show_in_dmesg
也就是打印出了 用户态传递的参数
*/
tmp_print("%d 0x%x %d",fd,write_buf,len);
if(access_ok(VERIFY_READ, (void *) write_buf,strlen(write_buf)))
tmp_print("buf:%s\n",write_buf);
}
else
{
tmp_print("not valid_user_regs\n");
}
}
//end add
ret = printk("%s", tmp);
if (ret > count)
/* printk can add a prefix */
ret = count;
}
kfree(tmp);
return ret;
}
关于THREAD_START_SP 2017-02-23
1. 问题引入
https://awakening-fong.github.io/posts/arm/arm_qemu_02 中说到 startkernel前设置sp为 initthreadunion + THREADSTART_SP
#define THREAD_START_SP (THREAD_SIZE - 8)
为何要-8?
2. 解
static inline struct thread_info *current_thread_info(void)
{
register unsigned long sp asm ("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}
(图示中A点到B点 大小是8字节)
如果sp是SP0, 那么,(sp & ~(THREADSIZE - 1)) 后还是指向SP0 (A点);
如果sp是SP1, 那么, (sp & ~(THREADSIZE - 1)) 后指向的是thread_info (C点).
所以, 需要-8.
IIC相关内容的记忆 2017-02-15
本文的内容 仅仅是为了能够回想起IIC相关内容, 并不求严谨和准确.
1. 起始和停止信号
因为上拉省电, 所以, 空闲时, SDA是上拉的. 在时钟为高时, SDA若表示数据, 需维持稳定, 否则, 其表示起始或停止.
2. 数据的组织 和 表示
假定是7bit地址的情况.
先发送高位还是低位?
可以考虑/回忆下 7bit地址+1bit读写 时的情况, 我们是先发送地址的, 所以, 是先发送高位, 后发送低位的.
最常见的是r/w# 所以,读为1, 写为0.
时钟有, 代表心脏还在跳, 器件还在工作, 所以, 在SCL高电平时对SDA采样作为数据.
page reclaim 04:参数 2017-02-07
未开启CONFIGMEMCG, CONFIGSWAP.
1. scan_control
linux-3.10.86/mm/vmscan.c
struct scan_control {
/* Incremented by the number of inactive pages that were scanned */
unsigned long nr_scanned;
/* How many pages shrink_list() should reclaim
问题:nr_to_reclaim和nr_scanned的关系?
答:nr_to_reclaim是个setting data, nr_reclaimed是runtime date.
通常是先给struct scan_control sc设置好这个目标,
然后启动回收.
在 sum of shrink_list() > nr_to_reclaim后中断回收, see shrink_lruvec() or do_try_to_free_pages().
*/
unsigned long nr_to_reclaim;
/*
这里的may类似may I ..., may的意思是 是否可以, 是否允许
*/
int may_writepage;
/*
[Understanding the Linux Kernel, 3rd Edition]p695
Lower priority implies scanning more pages.
*/
int priority;
};
get_scan_count
{
size = get_lru_size(lruvec, lru);
scan = size >> sc->priority;
//扫描的量 与 list的大小 成比例
}
shrink_lruvec
|--//1. 根据优先级等 给数组nr[]赋值
|--get_scan_count(lruvec, sc, nr);
page reclaim 03:活跃度的表示和状态转换 2017-02-07
1. page_referenced
linux-3.10.86/mm/rmap.c
* Quick test_and_clear_referenced for all mappings to a page,
* returns the number of ptes which referenced the page.
这个注释过时了, 实际功能并不是返回指向该page的pte的个数.
问题:这个函数的用途?
答:用来反应在inactive list中的page的活跃程度.
返回数值1和返回数值2是有区别的, see page_check_references
{
referenced_ptes = page_referenced(...);
if (... || referenced_ptes > 1)
return PAGEREF_ACTIVATE;
}
*/
int page_referenced(struct page *page,
int is_locked,
struct mem_cgroup *memcg,
unsigned long *vm_flags)