Escrevendo para um local de memória específico

5

Estou tentando editar um arquivo dentro de /proc/devices -tree para ser exato e eu sou incapaz de fazer isso, estou recebendo:

"permission denied" or "Input/Output error".

Eu tentei todas as combinações possíveis de editores, chown , chmod e até sudo dd . Eu também sei o local exato da memória para gravar em 7000c400 em hexadecimal. Eu preciso substituir 4 bytes lá, existe algum método que pode me ajudar a conseguir isso.

Editar: O que estou tentando conseguir tentando isso?

  • Eu tenho uma placa Jetson-TK1 , e um barramento i2c está configurado para o padrão 400kHz , mas eu quero executá-lo em 100kHz . Eu acho que posso fazer isso mudando a estrutura da árvore de dispositivos e a recompilação, mas a recompilação é uma dor de cabeça muito maior, já que o kernel que estou usando não é padrão (a nvidia não fornece isso).

    Eu li em algum lugar que no Linux quase tudo está na forma de um arquivo. Então, olhando para ele, eu encontrei um arquivo que contém 4 bytes que avalia a 400000 , acho que mudar este arquivo mudaria a frequência.

  • Agora, o problema real é que eu era incapaz de mudá-lo (eu acho que sou um usuário decente o suficiente e, tanto quanto eu entendo, se há algo na memória e eu tenho todos os tipos de senhas, eu deveria ser capaz de mudar isso. O fato de que eu estragar alguma coisa não é a questão). Eu tentei todos os métodos possíveis conhecidos para mim (como eu adicionei na pergunta). Então, como faço isso?

por Rishabh 23.03.2015 / 21:18

3 respostas

3

Eu olhei para isso principalmente por diversão e por aprendizado (e esperançosamente para o representante!). Eu gostaria de ter mais tempo para jogar com ioctl (graças a Sneetsher pela sugestão) e com o que eu fiz até agora para fazer uma solução mais elegante, mas a recompensa está prestes a expirar e não é É provável que eu possa fazer tudo a tempo, então estou postando essa solução "como está" (pelo menos por enquanto).

Aviso:

Eu não sei quais são as conseqüências de mudar algo para /proc/device-tree , então se você realmente sabe o que está fazendo, continue lendo.

Esta implementação específica desta solução requer um kernel em execução > 3,10. Ele envolve a compilação de um módulo de kernel personalizado e a execução de um script bash para executar uma espécie de hot-switch entre /proc/device-tree e um arquivo personalizado device-tree_new .

Limites :

  1. Após a remoção do módulo, o /proc/device-tree personalizado é removido! Outro motivo para ler o aviso novamente .
  2. O buffer personalizado de /proc/device-tree tem um limite de 65535 caracteres. Tudo sobre o caractere 65535 está truncado. Para ajustar o tamanho do buffer, altere a seguinte definição de constante e declaração de variável no código-fonte do módulo:

    1. #define MAX_BUFFER_SIZE 65535
    2. static unsigned int proc_buffer_length_v; (para que possa conter um número > 65535 )

Como funciona:

O próprio módulo:

  • elimina /proc/device-tree
  • cria um novo espaço em branco /proc/device-tree com permissões 0666

O script bash em si:

  1. Carrega o módulo
  2. Grava em /proc/device-tree o conteúdo de device-tree_new

Este é o " Makefile " Makefile para o módulo ( observe que todos os espaços brancos no início de cada linha make devem ser substituídos por um caractere TAB ):

obj-m += proc_module.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Este é o arquivo de origem " proc_module.c " do módulo:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#define DEBUG 1
#define MAX_BUFFER_SIZE 65535

static struct proc_dir_entry* proc_dir_entry_p;
static struct file_operations file_operations_s;
static char* proc_buffer_p;
static unsigned int proc_buffer_length_v;
static unsigned short int read_flag;

int read_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
    if(DEBUG) printk(KERN_INFO "read_proc() called.\n");
    if(read_flag)
        read_flag = 0;
    else {
        read_flag = 1;
        return 0;
    }
    copy_to_user(buffer, proc_buffer_p, proc_buffer_length_v);
    if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
    return proc_buffer_length_v;
}

int write_proc(struct file* file, char* buffer, size_t count, loff_t* offset) {
    size_t n;
    if(DEBUG) printk(KERN_INFO "write_proc() called.\n");
    if(count >= MAX_BUFFER_SIZE) {
        if(DEBUG) printk(KERN_INFO "write_proc(): Buffer exceeded!\n");
        n = MAX_BUFFER_SIZE;
    }
    else
        n = count;
    kfree(proc_buffer_p);
    if(DEBUG) printk(KERN_INFO "kfree() called.\n");
    if(!(proc_buffer_p = (char*)kmalloc(MAX_BUFFER_SIZE*sizeof(char), GFP_KERNEL))) {
        if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
        return count;
    }
    if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
    copy_from_user(proc_buffer_p, buffer, n);
    proc_buffer_length_v = n;
    if(DEBUG) printk(KERN_INFO "Ok. (count = %zu)\n", count);
    return count;
}

static int __init init_f(void) {
    if(DEBUG) printk(KERN_INFO "Module inserted.\n");
    remove_proc_entry("device-tree", NULL);
    if(!(proc_dir_entry_p = proc_create("device-tree", 0666, NULL, &file_operations_s))) {
        if(DEBUG) printk(KERN_INFO "Proc entry not created.\n");
        return -1;
    }
    if(DEBUG) printk(KERN_INFO "Proc entry created.\n");
    file_operations_s.read = read_proc;
    file_operations_s.write = write_proc;
    if(!(proc_buffer_p = (char*)kmalloc(1*sizeof(char), GFP_KERNEL))) {
        if(DEBUG) printk(KERN_INFO "kmalloc() ko.\n");
        return -1;
    }
    if(DEBUG) printk(KERN_INFO "kmalloc() ok.\n");
    proc_buffer_p[0] = '
#!/bin/bash

sudo rmmod proc_module.ko
sudo insmod proc_module.ko && cat device-tree_new > /proc/device-tree
'; proc_buffer_length_v = 0; read_flag = 1; if(DEBUG) printk(KERN_INFO "Ok.\n"); return 0; } static void __exit exit_f(void) { kfree(proc_buffer_p); if(DEBUG) printk(KERN_INFO "kfree() called.\n"); proc_remove(proc_dir_entry_p); if(DEBUG) printk(KERN_INFO "Proc entry removal requested.\n"); if(DEBUG) printk(KERN_INFO "Module removed.\n"); } module_init(init_f); module_exit(exit_f); MODULE_LICENSE("GPL"); MODULE_AUTHOR("kos"); MODULE_DESCRIPTION("proc_module");

Este é o script " switch.sh " bash :

obj-m += proc_module.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Instruções:

  1. Abra um Terminal com Ctrl + Alt + t
  2. Crie uma nova pasta: mkdir <folder_name>
  3. Altere o diretório de trabalho atual para a nova pasta: cd <folder_name>
  4. Crie os três arquivos acima usando os mesmos nomes exatos entre aspas duplas
  5. Crie o arquivo device-tree personalizado e nomeie-o como device-tree_new
  6. Marque " switch.sh " como executável: chmod a+x switch.sh
  7. Compile o módulo: make (dois avisos serão lançados por gcc )
  8. Inicie o script bash : ./switch.sh
  9. cat /proc/device-tree para ver o resultado
por kos 02.04.2015 / 01:28
2

/proc/ é um pseudo sistema de arquivos: quando você lê / escreve em qualquer /proc/file você não acessa um arquivo real ou memória real, mas você chama alguma função específica do kernel (dependendo do arquivo) que atua como um arquivo. Ele retorna dados se você ler o arquivo, definir dados se você gravar no arquivo. E se não houver uma função de gravação definida para um arquivo específico, a gravação no arquivo não alterará nada.

Nesse caso, o /proc/device-tree é uma maneira de ler a árvore de dispositivos fornecida ao executando o kernel durante a inicialização. (sem permissão de gravação)

Além disso, atualmente, a árvore de dispositivos é uma configuração somente leitura, você não pode atualizá-la após a inicialização. E, para o seu caso específico, os valores que configuram seu i2c são lidos e usados quando o i2c é sondado ('instalado'). Se você quiser reconfigurar i2c , você precisará, como dito joshumax, usar o ioctl correto no dispositivo i2c (em /dev/ onde algumas "entradas de driver" específicas estão definidas)

Uma outra solução é criar uma nova árvore de dispositivos, configurando o dispositivo I2C como você deseja. E pergunte ao kernel (verifique o gerenciador de inicialização que você está usando) para usar a árvore de dispositivos que você acabou de compilar.

    
por Nimlar 31.03.2015 / 11:01
1

Você precisará de poderes básicos usar o sudo para isso. Tente isto: você pode usar o gdb (GNU Debugger) rodando como root para manipular o conteúdo da memória. Estes podem lhe interessar:

link

link

    
por j0h 27.03.2015 / 15:06