| 1
| Débogage Exception |
Octet unique, int 3 | Int3
4 |
| 6
Opcode invalide | Invalid_op |
| 7
Device_not_available |
Device_not_available |
| 8
Double_fault
|
Double_fault |
| 9
Dépassement du segment du coprocesseur
|
Coprocessor_segment_overrun |
| 10
TSS invalide |
Incalid_tss |
| 11
Interruption de segment manquant |
Segment_not_present | _protection générale
|
14 | Exception de page | Page_fault |
15 | (Intel réservé) | Spurious_interrupt_bug |
16 | Erreur du coprocesseur
| Erreur_coprocesseur |
17 | Alignement contrôle interrompu | Alignment_check |
Les vecteurs d'interruption 0 à 31 ont été réservés, donc un total de 224 vecteurs d'interruption 32 à 255 sont disponibles. Comment ces 224 vecteurs d’interruption sont-ils alloués ? Dans la version 2.6 de Linux, à l'exception de 0x80 (SYSCALL_VECTOR) qui est utilisé comme appel systèmeentrée générale, les autres sont utilisés pour les sources d'interruption matérielles externes, y compris les 15 irqs du contrôleur d'interruption programmable 8259A ; Lorsque CONFIG_X86_IO_APIC n'est pas défini, seuls 15 des 223 autres vecteurs d'interruption (sauf 0x80) à partir du 32 sont utilisés, et les 208 autres restent vides.
2.2 Demande d'interruption
2.2.1 Présentation de la demande d'interruption
Interruption correspondante.
L'appareil envoie un niveau élevé au contrôleur d'interruption via la ligne d'interruption correspondante pour générer un signal d'interruption, et le système d'exploitation obtiendra l'interruption générée sur cette ligne d'interruption à partir du bit d'état du contrôleur d'interruption. Et ce n'est que lorsque l'appareil contrôle une certaine ligne d'interruption qu'il peut envoyer un signal à cette ligne d'interruption. De plus, comme il existe aujourd'hui de plus en plus de périphériques, les lignes d'interruption sont des ressources très précieuses et ne peuvent pas être mappées une à une. Par conséquent, avant d'utiliser la ligne d'interruption, vous devez demander la ligne d'interruption correspondante. Que la méthode d'interruption partagée ou une interruption exclusive soit utilisée, le processus d'application consiste d'abord à analyser toutes les lignes d'interruption pour découvrir celles qui ne sont pas occupées par d'autres, et à en sélectionner une comme IRQ du périphérique. Deuxièmement, demandez l'IRQ correspondante via la fonction d'application d'interruption. Enfin, vérifiez si l'interruption peut être exécutée en fonction du résultat de l'application.
2.2.2 Structures liées aux interruptions
La structure de base des données de traitement dans les interruptions est irq_desc, qui décrit complètement une ligne d'interruption, Linux 2.6. Le code source de 22.6 est le suivant. DIRQ_DESC
Définition dans include/Linux/IRQ.H
R/**
* struct irq_desc - interrupt descriptor
*
* @handle_irq: highlevel irq-events handler [if NULL, __do_IRQ()]
* @chip: low level interrupt hardware access
* @msi_desc: MSI descriptor
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
* @action: the irq action chain
* @status: status information
* @depth: disable-depth, for nested irq_disable() calls
* @wake_depth: enable depth, for multiple set_irq_wake() callers
* @irq_count: stats field to detect stalled irqs
* @irqs_unhandled: stats field for spurious unhandled interrupts
* @lock: locking for SMP
* @affinity: IRQ affinity on SMP
* @cpu: cpu index useful for balancing
* @pending_mask: pending rebalanced interrupts
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
* @name: flow handler name for /proc/interrupts output */struct irq_desc {
irq_flow_handler_t handle_irq; struct irq_chip *chip; struct msi_desc *msi_desc; void *handler_data; void *chip_data; struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
unsigned int cpu;#endif#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;#endif#ifdef CONFIG_PROC_FS struct proc_dir_entry *dir;#endif
const char *name;
} ____cacheline_internodealigned_in_smp;
Copier après la connexion
EIRQ_DESC Elle est la suivante :
définie dans include/linux/interrupt.h Structure d'action d'interruption : struct irqaction
struct irqaction {
irq_handler_t handler;
unsigned long flags;
cpumask_t mask; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir;
};
Copier après la connexion
Défini dans include/linux : collection de fonctions de traitement liées à la puce irq_chip
/**
* struct irq_chip - hardware interrupt chip descriptor
*
* @name: name for /proc/interrupts
* @startup: start up the interrupt (defaults to ->enable if NULL)
* @shutdown: shut down the interrupt (defaults to ->disable if NULL)
* @enable: enable the interrupt (defaults to chip->unmask if NULL)
* @disable: disable the interrupt (defaults to chip->mask if NULL)
* @ack: start of a new interrupt
* @mask: mask an interrupt source
* @mask_ack: ack and mask an interrupt source
* @unmask: unmask an interrupt source
* @eoi: end of interrupt - chip level
* @end: end of interrupt - flow level
* @set_affinity: set the CPU affinity on SMP machines
* @retrigger: resend an IRQ to the CPU
* @set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
* @set_wake: enable/disable power-management wake-on of an IRQ
*
* @release: release function solely used by UML
* @typename: obsoleted by name, kept as migration helper */struct irq_chip { const char *name;
unsigned int (*startup)(unsigned int irq); //中断开始 void (*shutdown)(unsigned int irq); //中断关闭 void (*enable)(unsigned int irq); //中断使能 void (*disable)(unsigned int irq); //中断禁用 void (*ack)(unsigned int irq); void (*mask)(unsigned int irq); void (*mask_ack)(unsigned int irq); void (*unmask)(unsigned int irq); void (*eoi)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, cpumask_t dest); int (*retrigger)(unsigned int irq); int (*set_type)(unsigned int irq, unsigned int flow_type); int (*set_wake)(unsigned int irq, unsigned int on); /* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHOD void (*release)(unsigned int irq, void *dev_id);#endif
/*
* For compatibility, ->typename is copied into ->name.
* Will disappear. */
const char *typename;
};
Copier après la connexion
2.2.3 Implémentation de la demande d'interruption
mécanisme des moitiés supérieure et inférieure
Nous espérons que le gestionnaire d'interruption fonctionnera rapidement, et Je veux qu'il accomplisse plus de travail. Ces deux objectifs se limitent mutuellement, comment résoudre le ——mécanisme de la moitié supérieure et inférieure
. Nous avons réduit de moitié la gestion des interruptions. Le gestionnaire d'interruption est la partie supérieure - accepte l'interruption et il commence à s'exécuter immédiatement, mais il ne peut fonctionner qu'avec une limite de temps stricte. Les travaux qui pourront être achevés ultérieurement seront reportés au second semestre, puis, le moment venu, le second semestre sera ouvert à l'exécution. La première moitié est simple et rapide, et désactive tout ou partie des interruptions pendant l'exécution
. La seconde moitié sera exécutée plus tard, et toutes les interruptions pourront recevoir une réponse pendant l'exécution. Cette conception peut rendre le système en état de protection contre les interruptions aussi court que possible, améliorant ainsi la réactivité du système. La moitié supérieure n'a que le mécanisme de gestion des interruptions, tandis que la moitié inférieure a une implémentation d'interruption logicielle, une implémentation de tasklet
et une implémentation de file d'attente de travail. Nous utilisons des cartes réseau pour expliquer ces deux moitiés. Lorsque la carte réseau reçoit le paquet de données, elle en informe le noyau et déclenche une interruption. La première moitié consiste à lire le paquet de données dans la mémoire à temps pour éviter toute perte due à un retard. Après avoir lu la mémoire, le traitement de ces données n'est plus urgent. A ce moment, le noyau peut exécuter le programme qui a été exécuté avant l'interruption, et le traitement des paquets de données réseau est laissé à la moitié inférieure.
Principe de division des moitiés supérieure et inférieure
1) Si une tâche est très sensible au temps, placez-la dans le gestionnaire d'interruption pour exécution
; 2) Si une tâche est liée au matériel, placez-la dans le gestionnaire d'interruption pour exécution
3) Si une tâche veut s'assurer qu'elle n'est pas interrompue par d'autres interruptions, mettez-la dans l'interruption ; handler Execution ;
4) Pour toutes les autres tâches, pensez à les placer dans la moitié inférieure pour l'exécution.
Interruption douce du mécanisme de mise en œuvre de la moitié inférieure
En tant que représentant du mécanisme de la moitié inférieure, l'interruption douce est née avec l'émergence de SMP (processeur de mémoire partagée), et c'est aussi La base de l'implémentation de tasklet (taskletajoute en fait simplement un certain mécanisme basé sur des interruptions logicielles). Softirq est généralement le terme général pour "fonction reportable", incluant parfois tasklet (les lecteurs sont invités à déduire si tasklet est inclus en fonction du contexte lorsqu'ils le rencontrent). Cela semble parce qu'il doit satisfaire à la distinction entre les moitiés supérieure et inférieure proposée ci-dessus, afin que les tâches insensibles au temps puissent être différées. L'interruption logicielle exécute les tâches restantes qui lui sont laissées par le gestionnaire d'interruption et peut être exécutée en parallèle sur plusieurs . Le CPU augmente l'efficacité globale du système. Ses fonctionnalités incluent :
a) Il ne peut pas être exécuté immédiatement après sa génération, et il doit attendre la planification du noyau avant de l'exécuter. peut être exécuté. Les interruptions logicielles ne peuvent pas être interrompues d'elles-mêmes, mais ne peuvent être interrompues que par des interruptions matérielles (partie supérieure).
b) peut s'exécuter simultanément sur plusieurs CPU (même du même type). Par conséquent, les interruptions logicielles doivent être conçues comme des fonctions réentrantes (permettant à plusieurs CPU de fonctionner en même temps), de sorte que des verrous tournants doivent également être utilisés pour protéger leurs structures de données.
La moitié inférieure du mécanisme d'implémentation tasklet
Tasklet est implémentée via des interruptions logicielles, elle est donc elle-même également une interruption logicielle.
Les interruptions logicielles sont traitées de manière par interrogation. S'il s'agit du dernier type d'interruption, tous les types d'interruption doivent être parcourus avant que la fonction de traitement correspondante puisse finalement être exécutée. Évidemment, afin de garantir l'efficacité du sondage, les développeurs ont limité le nombre d'interruptions à 32.
Afin d'augmenter le nombre de traitements d'interruption et d'améliorer l'efficacité du traitement, le mécanisme tasklet a été créé.
Tasklet adopte un mécanisme de file d'attente indifférenciée et n'est exécuté qu'en cas d'interruption, éliminant ainsi la difficulté de la recherche cyclique de table. TaskletEn tant que nouveau mécanisme, il peut évidemment présenter plus d'avantages. À cette époque, SMP devenait de plus en plus populaire, c'est pourquoi le mécanisme SMP a été ajouté à tasklet pour garantir que le même type d'interruption ne peut être exécuté que sur un seul cpu. À l’ère des interruptions douces, une telle considération n’existait évidemment pas. Par conséquent, la même interruption logicielle peut être exécutée sur deux cpu en même temps, ce qui est susceptible de provoquer des conflits.
Résumé des avantages de tasklet :
(1 ) Aucune limite sur le nombre de types
(2 ) Haute efficacité, pas besoin de rechercher une table en boucle
Prise en charge du mécanisme SMP ; les fonctionnalités sont les suivantes : ) un Ce type de
tasklet spécifique ne peut fonctionner que sur un seul CPU et ne peut pas être exécuté en parallèle, mais ne peut être exécuté qu'en série.
2) Plusieurs tasklets de types différents peuvent être exécutées en parallèle sur plusieurs CPU.
3) Les interruptions logicielles sont allouées de manière statique et ne peuvent pas être modifiées une fois le noyau compilé. Mais tasklet est beaucoup plus flexible et peut être modifié au moment de l'exécution (par exemple lors de l'ajout de modules).
La moitié inférieure du mécanisme d'implémentation - file d'attente de travail
La fonction différée que nous avons introduite ci-dessus s'exécute dans le contexte d'interruption (un point de contrôle de l'interruption logicielle est do_IRQheure de sortie), qui a causé quelques problèmes : les interruptions logicielles ne peuvent pas dormir ou se bloquer. Étant donné que le contexte d'interruption est dans l'état du noyau et qu'il n'y a pas de commutation de processus, si l'interruption logicielle est mise en veille ou bloquée, elle ne pourra pas quitter cet état, provoquant le gel de l'ensemble du noyau. Cependant, les fonctions de blocage ne peuvent pas être implémentées dans le contexte d'interruption et doivent être exécutées dans le contexte de processus, comme les fonctions qui accèdent aux blocs de données du disque. Par conséquent, les fonctions de blocage ne peuvent pas être implémentées à l'aide de softirqs. Mais ils ont souvent des propriétés reportables.
Les fonctions différées que nous avons introduites ci-dessus s'exécutent dans le contexte d'interruption, ce qui entraîne certains problèmes, indiquant qu'elles ne peuvent pas être suspendues, ce qui signifie que les interruptions logicielles ne peuvent pas dormir ou se bloquer. La raison en est que le contexte d'interruption est en dehors. l'état du noyau, il n'y a pas de commutation de processus, donc si l'interruption logicielle se met en veille ou est bloquée, elle ne pourra pas quitter cet état, provoquant le gel de l'ensemble du noyau. Par conséquent, les fonctions de blocage ne peuvent pas être implémentées à l'aide de softirqs. Mais ils ont souvent des propriétés reportables. Et comme il est exécuté en série, tant qu'un temps de traitement est long, cela entraînera un retard dans la réponse des autres interruptions. Afin d'accomplir ces tâches impossibles, une file d'attente de travail a émergé, qui peut basculer entre différents processus pour accomplir différentes tâches. Si la tâche reportée nécessite du sommeil, choisissez la file d'attente de travail. Si le sommeil n'est pas requis, choisissez une interruption douce ou tasklet. Les files d'attente de travail peuvent s'exécuter dans un contexte de processus et déléguer le travail à un thread du noyau. Pour faire simple, la file d'attente de travail est un groupe de threads du noyau, utilisés comme threads du démon d'interruption. Plusieurs interruptions peuvent être placées dans un thread, ou chaque interruption peut se voir attribuer un thread. Nous utilisons la structure workqueue_struct pour représenter le thread de travail, qui est implémenté à l'aide du thread du noyau. Comment le thread de travail exécute-t-il le travail reporté——Il existe une telle liste chaînée, qui se compose de la structure work_struct, et ce work_struct décrit un travail une fois le travail terminé, le work_struct correspondant. L'objet est supprimé de la liste chaînée. Lorsqu'il n'y a plus d'objets dans la liste chaînée, le thread de travail continue de dormir. Étant donné que les files d'attente de travail sont des threads, nous pouvons utiliser toutes les méthodes pouvant être utilisées dans les threads.
Quel est le rôle des interruptions logicielles et des files d'attente de travail sous Linux Le rôle des interruptions logicielles et des files d'attente de travail sous Linux est d'implémenter le traitement des interruptions ; demi-mécanisme de mise en œuvre dans les mécanismes supérieur et inférieur.
1.L'interruption logicielle est généralement le nom général de "fonction différée
" Elle ne peut pas dormir ou se bloquer. Elle est dans le contexte d'interruption et ne peut pas basculer entre les processus. L'interruption logicielle ne peut pas être interrompue par elle-même. . Peut être interrompu par des interruptions matérielles (partie supérieure) et peut s'exécuter simultanément sur plusieurs CPU. Par conséquent, les interruptions logicielles doivent être conçues comme des fonctions réentrantes, des verrous tournants sont donc également nécessaires pour protéger leurs structures de données. 2.La fonction dans la file d'attente de travail est dans le contexte du processus. Elle peut dormir ou être bloquée et peut basculer entre différents processus pour effectuer différentes tâches.
Ni la fonction différée ni la file d'attente de travail ne peuvent accéder à l'espace de processus de l'utilisateur. Il ne peut y avoir de processus en cours d'exécution lorsque la fonction différée est exécutée par le processus du noyau et elle ne peut pas accéder à l'espace de processus. adresse de l'espace utilisateur. Recommandations associées : "
Tutoriel vidéo Linux"