- Qual é a diferença entre a pilha do kernel e a pilha do usuário?
Em suma, nada - além de usar um local diferente na memória (e, portanto, um valor diferente para o registro do ponteiro de pilha) e, geralmente, diferentes proteções de acesso à memória. Ou seja, ao executar no modo de usuário, a memória do kernel (parte da qual é a pilha do kernel) não estará acessível mesmo se mapeada. Vice-versa, sem ser explicitamente solicitado pelo código do kernel (no Linux, por meio de funções como copy_from_user()
), a memória do usuário (incluindo a pilha do usuário) geralmente não é diretamente acessível.
- Por que [uma] pilha de kernel separada é usada?
Separação de privilégios e segurança. Por um lado, os programas do espaço do usuário podem fazer sua pilha (ponteiro) o que quiserem, e geralmente não há nenhum requisito arquitetônico para ter uma pilha válida. O kernel, portanto, não pode confiar que o ponteiro de pilha do espaço do usuário seja válido nem utilizável e, portanto, exigirá um conjunto sob seu próprio controle. Diferentes arquiteturas de CPU implementam isso de maneiras diferentes; As CPUs x86 trocam automaticamente os stackpointers quando ocorrem mudanças de modo de privilégio, e os valores a serem usados para diferentes níveis de privilégio são configuráveis - por código privilegiado (ou seja, apenas o kernel).
- Se uma variável local for declarada em um ISR, onde ela será armazenada?
Na pilha do kernel. O kernel (kernel do Linux, isto é) não conecta ISRs diretamente às portas de interrupção da arquitetura x86, mas, em vez disso, delega o despacho de interrupção para um mecanismo de entrada / saída de interrupção de kernel comum que salva o estado de registro de pré-interrupção antes de chamar o (s) manipulador (es) registrado (s) . A própria CPU ao despachar uma interrupção pode executar um privilégio e / ou troca de pilha, e isso é usado / configurado pelo kernel de forma que o código de entrada de interrupção comum já possa contar com a presença de uma pilha de kernel.
Dito isso, as interrupções que ocorrem durante a execução do código do kernel simplesmente (continuam a) usar a pilha do kernel instalada naquele ponto. Isso pode, se os manipuladores de interrupção tiverem caminhos de chamada profundamente aninhados, levar a estouros de pilha (se um caminho de chamada profundo do kernel for interrompido e o manipulador causar outro caminho profundo; no Linux, o código RAID do sistema de arquivos / software sendo interrompido pelo código de rede com iptables ativo é conhecido por acionar tais kernels antigos não ajustados ... a solução é aumentar o tamanho da pilha do kernel para tais cargas de trabalho).
- Cada processo tem sua própria pilha de kernel?
Não apenas cada processo - cada thread tem sua própria pilha de kernel (e, de fato, sua própria pilha de usuário também). Lembre-se de que a única diferença entre processos e threads (para Linux) é o fato de que vários threads podem compartilhar um espaço de endereço (formando um processo).
- Como o processo é coordenado entre essas duas pilhas?
Nem um pouco - não precisa. A programação (como / quando diferentes threads estão sendo executados, como seu estado é salvo e restaurado) é a tarefa do sistema operacional e os processos não precisam se preocupar com isso. Conforme os threads são criados (e cada processo deve ter pelo menos um thread), o kernel cria pilhas de kernel para eles, enquanto as pilhas de espaço de usuário são explicitamente criadas / fornecidas por qualquer mecanismo usado para criar um thread (funções como makecontext()
ou pthread_create()
permitir que o chamador especifique uma região de memória a ser usada para a pilha do thread "filho") ou herdada (por clonagem de memória ao acessar, geralmente chamada de "cópia na gravação" / COW, ao criar um novo processo).
Dito isto,(estado, entre eles está o stackpointer do thread). Existem várias maneiras para isso: sinais UNIX, setcontext()
, pthread_yield()
/ pthread_cancel()
, ... - mas isso é disgressing um pouco da pergunta original.
Minha resposta é coletada de outras perguntas do SO com minhas coisas.
Como um programador do kernel, você sabe que o kernel deve ser restrito a programas de usuário errôneos. Suponha que você mantenha a mesma pilha para kernel e espaço do usuário, então o segfault simples no aplicativo do usuário trava o kernel e precisa ser reiniciado.
Existe uma "pilha de kernel" por CPU como ISR Stack e uma "pilha de kernel" por processo. Há uma "pilha de usuário" para cada processo, embora cada thread tenha sua própria pilha, incluindo threads de usuário e kernel.
http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-10/3194.html
Portanto, quando estamos no modo kernel, o tipo de mecanismo de pilha é necessário para lidar com chamadas de função, variáveis locais semelhantes ao espaço do usuário.
http://www.kernel.org/doc/Documentation/x86/kernel-stacks
Ele será armazenado na pilha ISR (IRQSTACKSIZE). O ISR é executado em uma pilha de interrupção separada apenas se o hardware oferecer suporte. Caso contrário, os quadros de pilha ISR são colocados na pilha do thread interrompido.
O espaço do usuário não sabe e francamente não se importa se a interrupção é servida na pilha do kernel do processo atual ou em uma pilha ISR separada. Como as interrupções vêm por cpu, portanto, a pilha ISR deve ser por cpu.
Sim. Cada processo tem sua própria pilha de kernel.
A resposta do @FrankH parece ótima para mim.
fonte
Tomando como referência o Linux Kernel Development de Robert Love, a principal diferença é o tamanho:
Além disso, a pilha do kernel contém um ponteiro para a estrutura thread_info que contém informações sobre a thread.
fonte