Kernel Mode vs User Mode

Tempo de leitura estimado: 6 minutos

Aprofundar o conhecimento em um software, requer entender muitas características do sistema operacional. No caso de SO’s como o Windows, é comum, em cursos avançados ouvir as expressões “Kernel Mode” e “User Mode”. Com o intuito de fazer um rápido esclarecimento sobre o que significam estes nomes, eu preparei este post.

Certas áreas de memória contém dados vitais para o correto funcionamento do Windows. Por exemplo, imagine que no endereço  0xFFFF0000, o Windows guardasse a quantidade total de memória livre para alocação. Ora, se uma thread qualquer  altera esse valor, o Windows poderia achar que havia mais ou menos memória disponível para alocação. Isso traria instabilidade e incosistência para todo o sistema operacional, e, consequentemente, todos os processos em execução.

Para se prevenir deste tipo de caso, e outros, o Windows fornece privilégios que permitem ou impedem que uma thread acesse um determinado recurso, como certos endereços de memória. Na verdade, isso é possível graças ao processador: Nos primeiros momentos do boot, ele está livre e sem restrições, então o sistema operacional interage com ele e registra uma série de rotinas e códigos necessários para serem executados quando certos eventos ocorrem durante as execuções das instruções. Alguns destes eventos são disparados justamente quando uma thread necessita acessar algum recurso protegido. Diante disso, o processador irá executar o código que o sistema operacional registrou e o mesmo irá tratar de forma adequada o acesso. No exemplo acima, ao acessar o endereço de memória crítico, o Windows irá impedir a ação de ser executada e gerar um erro para a thread que tentou fazer o acesso.

Mas não é todo momento que uma thread deve ser impedida de acessar recursos críticos. Por exemplo, ao realizar um leitura de arquivo, a thread necessita chamar a função “ReadFile”, da API do Windows. Essa função vai executar um código que requer o acesso a estruturas protegidas pelo sistema operacional. Neste caso, se houver o impedimento por parte do sistema operacinal, a thread não irá conseguir efetuar a leitura do arquivo.

Para resolver isso, o Windows define dois modos de operação das threads:

  • User Mode
    O User Mode é o modo de operação em que as threads executam na maior parte do tempo. Neste modo, a thread não pode acessar recursos vitais para o funcionamento do sistema, como certos endereços de memória e registradores. Para acessar, é necessário entrar no “Kernel Mode”.
  • Kernel Mode
    Este é o modo sob o qual as threads que executam o código do sistema operam, já que o mesmo referencia estruturas internas para completar os serviços oferecidos. A API do Windows contém funções que executam instruções que fazem com que o sistema entre neste modo. Um leitor curioso, pode então, concluir que seria fácil burlar as proteções do Kernel Mode, bastando apenas executar esta instruções que ativam o Kernel Mode. Bom, não é bem assim.

Transição User Mode – Kernel Mode

Quando a thread executa a instrução que faz o modo de operação mudar para Kernel Mode, o processador interrompe a execução da mesma e passa o controle para umas dessas rotinas que o Windows registrou lá no boot. Isso significa, que graças ao suporte que o processador oferece, a thread passa a rodar um código confiável pelo Windows, isto é, que faz parte do kernel. Dessa maneira, ela deixa de executar o seu código original, e passa a executar um código específico para tratar este evento gerado pelo processador. O nome da instrução que solicita essa transição depende da arquitetura e família do processador. No caso de processadores Intel x64, o nome da instrução é syscall (Fonte: Intel® 64 and IA-32 Architectures, Página 1788). Esse processo tambem é conhecido como “uso dos serviços do sistema operacional”, pois é assim que um processo consegue interagir com as centenas de rotinas (os chamados “serviços”) que provê alguma funcionalidade do Windows (como ler arquivos, criar processos, transferir dados via rede, etc.).

Mesmo que o usuário utilizasse a instrução syscall em seu código diretamente, o código do sistema tomaria o controle da execução e impediria o usuário de realizar qualquer modificação que não fosse por parte de um código criado pelos desenvolvedores do Windows.

É comum observar nas literaturas a respeito da arquitetura do Windows, o fato de que a API do Windows possui uma parte User Mode e uma parte Kernel Mode. Utilizar a instrução syscall diretamente seria chato e complexo para os desenvolvedores. Ao realizar a transição para Kernel Mode, é necessário informar uma série de parâmetros (via registradores da CPU), que o código do Windows irá validar para determinar o que deverá ser feito a partir dali. Ao invés do desenvolvedor ter que decorar as centenas de códigos que são definidos, o Windows disponibiliza uma série de funções em DLLs como “kernel32.dll” e “user32.dll”. Essa funções são responsáveis por preparar os parâmetros e executar a instrução “syscall”.  Então, por isso, até que a instrução “syscall” seja executada, o código da DLL que faz parte do Windows, ainda estava rodando em User Mode, isto é, se houvesse uma tentativa de acessar um recurso protegido nesse momento, haveria uma falha (o que seria um bug no sistema operacional, já que a DLL faz parte do Windows). Por exemplo, a função ReadFile é definida na DLL “Kernel32.dll” (Fonte: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx). Essa é a função que deve ser usada sempre que um processo necessita ler um arquivo (ou uma de suas variações, como ReadFileEx). O SQL Server faz uso dessa função para ler o conteúdo dos arquivos de dados e log. Ao iniciar a sua execução, a função irá realizar todas as validações necessárias e irá executar outras funções que estão defindias em outras DLLs do Windows. E são essas funções que irão preparar e executar a instrução syscall.

Transição Kernel Mode – User Mode

Depois que o código do sistema operacional termina seu trabalho, é necessário retomar a execução do código original, isto é, o codigo que causou a transição para Kernel Mode. Mas antes, é necessário voltar ao User Mode, caso contrário, toda o esquema de proteção feito até aqui seria inútil.  Assim como existem instruções para entrar em Kernel Mode, existem para sair. De novo, o nome vai depender da família e arquitetura do processador. No caso de x64 , a instrução é a sysret ( Fonte: Intel® 64 and IA-32 Architectures, Página 1796  ). Quando o código do sistema operacional termina de fazer o que lhe foi solicitado, então ele executa a instrução sysret, saindo do Kernel Mode e retomando a execução do código após o syscall que causou a transição para Kernel Mode.

Mais alguns comentários…

 

Antes de encerrar, é importante fortalecer alguns pontos.

  1. Tudo isso foi um resumo do resumo da resenha do rascunho do que é realmente o Kernel Mode e o User Mode, e como ocorre toda essas transições. Se você quer se aprofundar no assunto, pode usar a referência que deixei no final do artigo (e, se ainda não o fez, aproveita para estudar C++ e Assembly, pois vai facilitar o entendimento de muita coisa).
  2. User Mode e Kernel Mode não são threads ou processos diferentes. Uma thread pode em um determinado momento estar em User Mode, e um outro determinado momento em Kernel Mode. O que muda é que em Kernel Mode ela estara executando um código do sistema operacional ou driver. Isso indica que se a thread passa muito tempo em Kernel Mode, é uma grande chance de ser um problema de hardware, uso intenso de recursos do SO ou bug do sistema (este último com chances bem menores, mas não impossível).

    Vida da thread e modos de operação

  3. Algumas ferramentas, como o gerenciador de tarefas e o Process Explorer, permite que você monitore o uso de CPU em Kernel Mode. Por exemplo, você consegue determinar quanto de tempo foi gasto pelas threads executando em Kernel Mode.

    O gráfico em vermelho mostra o tempo gasto pela CPU executando instruções sob o modo Kernel Mode. Também, é possivel obter informações por processo. Na imagem, é possível observar o texto “Kernel Time” na janela da direita. Esta informação indica o tempo total gasto em Kernel Mode pelo processo. O mesmo vale pro “User Time”.

  4. O que tudo isso tem a ver com SQL Server? Não somente com SQL Server, mas com qualquer software que rode no Windows. Todos eles fazem uso constante de serviços do sistema. Assim, entender o que é o Kernel Mode é útil para determinar se um possível problema está no sistema operacional ou no software. A transição para Kernel Mode é algo muito custoso do ponto de vista de um processo. Envolve a execução de mais algumas centenas instruções, acesso a memória, recursos compartilhados, etc. O SQL Server foi desenvolvido para evitar ao máximo fazer transições de User Mode para Kernel Mode, para salvar a perfomance. É obvio que existem casos onde não é possivel evitar isso, como no momento em que é necessário ler ou escrever dos arquivos. Mas é sempre bom estar de olho nas métricas relativo ao uso dos recursos em Kernel Mode.

 

Referências:

 

Compartilhe este post!

Leave a Reply