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.
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).
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:
/proc/device-tree
est supprimé! ne autre raison de relire l'avertissement.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:
#define MAX_BUFFER_SIZE 65535
static unsigned int proc_buffer_length_v;
(pour qu'il puisse contenir un numéro> 65535
)Le module lui-même:
/proc/device-tree
/proc/device-tree
vierge avec des autorisations 0666
Le script bash
lui-même:
/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
Terminal
avec Ctrl+Alt+tmkdir <folder_name>
cd <folder_name>
device-tree
et nommez-le device-tree_new
switch.sh
" comme exécutable: chmod a+x switch.sh
make
(deux avertissements seront émis par gcc
)bash
: ./switch.sh
cat /proc/device-tree
pour voir le résultat/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.
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