web-dev-qa-db-fra.com

Écrire dans un emplacement de mémoire spécifique

J'essaie de modifier un fichier à l'intérieur de /proc/devices- arbre pour être exact, et je suis incapable de le faire, je reçois:

"autorisation refusée" ou "erreur d'entrée/sortie".

J'ai essayé toutes les combinaisons possibles d'éditeurs, chown, chmod et même Sudo dd. Je connais aussi l'emplacement exact de la mémoire sur laquelle écrire 7000c400 en hexadécimal. J'ai besoin de remplacer 4 octets, existe-t-il une méthode qui pourrait m'aider à atteindre cet objectif?.

Edit: Qu'est-ce que j'essaie de réaliser en essayant ceci?

  • J'ai une carte Jetson-TK1 et un bus i2c est défini à un défaut de 400kHz, mais je veux l'exécuter à 100kHz. Je pense que je peux le faire en modifiant la structure de l’arborescence de périphériques et la recompilation, mais la recompilation est un casse-tête beaucoup plus gros, car le noyau que j’utilise n’est pas un standard (nvidia ne le fournit pas).

    J'avais lu quelque part que sous Linux presque tout se présente sous la forme d'un fichier. Donc, en cherchant cela, j’ai trouvé un fichier de 4 octets qui donne 400000, je pense que changer ce fichier changerait la fréquence.

  • Maintenant, le vrai problème, c’est que j’étais incapable de le changer (je pense que je suis un utilisateur assez décent et, si je comprends bien, s’il ya quelque chose en mémoire et que j’ai toutes sortes de mots de passe, je devrais pouvoir le changer. le fait que je gâche quelque chose n’est pas la question). J'ai essayé toutes les méthodes possibles connues de moi (comme je l'ai ajouté dans la question). Alors, comment je fais ça.

5
Rishabh

J'ai examiné cette question principalement pour le plaisir et pour apprendre (et j'espère pour le représentant!). J'aimerais avoir plus de temps pour jouer avec ioctl (merci à Sneetsher pour cette suggestion) et avec ce que j'ai fait jusqu'à présent afin de proposer une solution plus élégante, mais la prime est sur le point d'expirer et il est peu probable que je puisse tout faire à temps, alors je poste cette solution "en l'état" (du moins pour le moment).

Avertissement:

Je ne sais pas quelles sont les conséquences de la transformation de quelque chose en /proc/device-tree, alors si vous savez vraiment ce que vous faites, continuez à lire.

Cette implémentation particulière de cette solution nécessite un noyau en cours d'exécution> 3.10. Cela implique la compilation d'un module de noyau personnalisé et l'exécution d'un script bash pour effectuer une sorte de basculement à chaud entre /proc/device-tree et un fichier personnalisé device-tree_new.

Limites:

  1. Lors du retrait du module, le fichier personnalisé /proc/device-tree est supprimé! ne autre raison de relire l'avertissement.
  2. Le tampon personnalisé /proc/device-tree a une limite de 65535 caractères. Tout ce qui se trouve sur le caractère 65535 est tronqué. Pour ajuster la taille du tampon, modifiez la définition de constante et la déclaration de variable suivantes dans le code source du module:

    1. #define MAX_BUFFER_SIZE 65535
    2. static unsigned int proc_buffer_length_v; (pour qu'il puisse contenir un numéro> 65535)

Comment ça fonctionne:

Le module lui-même:

  • supprime/proc/device-tree
  • crée un nouveau /proc/device-tree vierge avec des autorisations 0666

Le script bash lui-même:

  1. Charge le module
  2. Écrit dans /proc/device-tree le contenu de device-tree_new

Ceci est la "Makefile" Makefile du module (notez que tous les espaces au début de chaque ligne make doivent être remplacés par un caractère 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

Voici le fichier source "proc_module.c" du module:

#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] = '\0';
    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");

Voici le script "switch.sh" bash:

#!/bin/bash

Sudo rmmod proc_module.ko
Sudo insmod proc_module.ko && cat device-tree_new > /proc/device-tree

Instructions:

  1. Ouvrez une Terminal avec Ctrl+Alt+t
  2. Créez un nouveau dossier: mkdir <folder_name>
  3. Changez le répertoire de travail actuel dans le nouveau dossier: cd <folder_name>
  4. Créez les trois fichiers ci-dessus en utilisant exactement les mêmes noms entre les guillemets
  5. Créez le fichier personnalisé device-tree et nommez-le device-tree_new
  6. Marquer "switch.sh" comme exécutable: chmod a+x switch.sh
  7. Compilez le module: make (deux avertissements seront émis par gcc)
  8. Lancez le script bash: ./switch.sh
  9. cat /proc/device-tree pour voir le résultat
3
kos

/proc/ est un pseudo système de fichiers: lorsque vous lisez/écrivez sur n'importe quel /proc/file, vous n'accédez pas à un fichier réel ou à une mémoire réelle, mais vous appelez une fonction du noyau spécifique (en fonction du fichier) qui agit sous forme de fichier. Il renvoie des données si vous lisez le fichier, définissez des données si vous écrivez dans le fichier. Et si aucune fonction d'écriture n'est définie pour un fichier spécifique, l'écriture dans le fichier ne changera rien.

Dans ce cas, le /proc/device-tree est un moyen de lire l’arborescence de périphériques fournie au noyau en cours d’exécution pendant son démarrage. (pas d'activation en écriture)

De plus, actuellement, l’arborescence des périphériques est une configuration en lecture seule, vous ne pouvez pas la mettre à jour après le démarrage. Et pour votre cas spécifique, les valeurs configurant votre i2c sont lues et utilisées lorsque le i2c est sondé ('installé'). Si vous voulez reconfigurer i2c, vous devez, comme dit joshumax, utiliser le ioctl correct sur le périphérique i2c (dans /dev/ où une "entrée de pilote" spécifique est définie )

Une autre solution consiste à créer une nouvelle arborescence de périphériques, en configurant le périphérique I2C à votre guise. Et demandez au noyau (vérifiez le chargeur de démarrage que vous utilisez) d’utiliser l’arborescence de périphériques que vous venez de compiler.

2
Nimlar

Vous aurez besoin de pouvoirs fondamentaux pour utiliser Sudo. Essayez ceci: vous pouvez utiliser gdb (débogueur GNU) en tant que root pour manipuler le contenu de la mémoire. Ceux-ci peuvent vous intéresser:

http://sourceware.org/gdb/current/onlinedocs/gdb/

https://stackoverflow.com/questions/3305164/how-to-modify-memory-contents-using-gdb

1
j0h