Implementação de System Call no Linux

14
UNIVERSIDADE FEDERAL DE UBERLÂNDIA FACULDADE DE ENGENHARIA MECÂNICA Curso de Graduação em Engenharia Mecatrônica Trabalho de Conclusão de Disciplina Grupo 2 Professor Rivalino Matias Júnior Guilherme Ramalho 11311EMT008 Rafael Froede 11311EMT016 Taynara Brito 11311EMT027 Uberlândia, dezembro de 2015

description

Esse documento faz referência a implementação de uma system call especifica no Linux. Nele há passo a passo do modo de implementação, além da explicação de sua função, e pode servir de guia para implementações de system call no sistema operacional Linux.

Transcript of Implementação de System Call no Linux

Page 1: Implementação de System Call no Linux

UNIVERSIDADE FEDERAL DE UBERLÂNDIA

FACULDADE DE ENGENHARIA MECÂNICA

Curso de Graduação em Engenharia Mecatrônica

Trabalho de Conclusão de Disciplina

Grupo 2

Professor Rivalino Matias Júnior

Guilherme Ramalho – 11311EMT008

Rafael Froede – 11311EMT016

Taynara Brito – 11311EMT027

Uberlândia, dezembro de 2015

Page 2: Implementação de System Call no Linux

2

SUMÁRIO

Introdução ......................................................................................................................... 3

1 Objetivo ..................................................................................................................... 4

2 Problema proposto..................................................................................................... 5

3 Fundamentação Teórica ............................................................................................ 6

3.1 System Call ........................................................................................................ 6

4 Implementação da System Call ................................................................................. 7

4.1 Compilação do Kernel ....................................................................................... 7

4.2 System Call ........................................................................................................ 8

4.3 A implementação da System Call .................................................................... 12

5 Conclusões .............................................................................................................. 13

6 Bibliografia.............................................................................................................. 14

Page 3: Implementação de System Call no Linux

3

INTRODUÇÃO

Este relatório visa detalhar o trabalho realizado pelos alunos referentes ao Grupo

2 como parte integrante da disciplina de Sistemas Operacionais do curso de Engenharia

Mecatrônica da Universidade Federal de Uberlândia.

O tema é decorrente da discussão de gerenciamento de processos, que é um dos

tópicos abordados na teoria, sendo o presente trabalho uma das técnicas adotadas para

melhor abordagem do assunto, bem como tornar um pouco mais prático os conhecimentos

adquiridos em sala de aula.

Desta forma, este relatório irá abordar assuntos referentes a como implementar

uma system call no sistema operacional Linux que efetue análises a nível de processos

correntes no sistema.

Inicialmente, o grupo optou por uma abordagem teórica, embasada por fontes

eletrônicas e livros. Em sequência, encontra-se um detalhamento das práticas adotadas

para a implementação da mesma. E, finalmente, conclusões apresentado resultados e

dificuldades encontradas na execução do trabalho.

Page 4: Implementação de System Call no Linux

4

1 OBJETIVO

Este trabalho tem como objetivo a análise, o projeto, bem como a implementação

de uma system call para o sistema operacional Linux (x86) por parte dos alunos que estão

cursando a presente disciplina.

Tal system call tem como função a análise de características típicas de processos

existentes em sistemas operacionais, como PID do processo pai (PPID – parent process

identify), UID (user identify) e tempo de existência.

Page 5: Implementação de System Call no Linux

5

2 PROBLEMA PROPOSTO

Recebendo como parâmetro um valor do PID a ser pesquisado nos processos

correntes do sistema operacional, a system call implementada deve retornar os seguintes

dados pertencentes ao processo identificado pelo valor de PID escolhido:

UID – identificador de usuário;

PPID – identificador do processo pai; e

Tempo de existência.

Caso o valor entrado seja de um processo que não possui existência, a system

call deverá retornar -1 e encerrar a execução.

Page 6: Implementação de System Call no Linux

6

3 FUNDAMENTAÇÃO TEÓRICA

3.1 System Call

System Call, ou em português, chamada de sistema, pode ser definida como uma

função responsável por chamar o kernel do sistema para que este faça uma determinada

tarefa. Como o usuário não pode, diretamente, realizar operações com o kernel, as

chamadas de sistemas foram criadas.

A Figura 1 trata-se de uma ilustração de como funciona as system calls. Como

pode-se notar, uma determinada aplicação, ou mesmo o usuário, quando deseja solicitar

determinado serviço do kernel, faz uma system call, sendo que a mesma irá se ocupar do

papel de passar todas as informações para que ele execute a ação desejada.

Figura 1 - Ilustração da ação de uma system call no sistema operacional.

Para uma melhor análise, as system calls foram divididas em quatro grandes

grupos, sendo estes:

Chamadas de sistema para gerenciamento de processos;

Chamadas de sistema para gerenciamento de diretórios;

Chamadas de sistemas para gerenciamento de arquivo;

Chamadas de sistemas restantes.

Dado o fato de que o foco deste trabalho se dá sobre gerenciamento de processos,

este tópico será abordado mais detalhadamente.

Page 7: Implementação de System Call no Linux

7

4 IMPLEMENTAÇÃO DA SYSTEM CALL

4.1 Compilação do Kernel

A compilação do kernel se deu de forma apresentada pelo professor em sala de

aula. Ela será descrita brevemente pois não possui grande ênfase neste projeto.

Os arquivos do kernel utilizados e apresentados neste documento são

pertencentes a versão 3.17.1 do kernel do Linux – Ubuntu e foram obtidos pelo site

kernel.org.

Com os arquivos previamente descompactados em um novo diretório (mas não

necessariamente, podendo utilizar um diretório existente), pode-se inicializar as etapas de

compilação e instalação de um kernel modificado. Entretanto, neste primeiro momento,

o kernel está exatamente como quando foi baixado.

Para a execução do processo de compilação e instalação de um novo kernel, é

necessário que algumas funções estejam presentes no sistema operacional. Ativar estas

funções é o primeiro passo para a compilação e instalação.

Com tais funções já ativadas, deve-se estar no diretório em que os arquivos do

kernel, já baixados e descompactados. E então inicia-se as configurações do kernel para

a compilação e instalação. Embora existam diversas configurações que poderiam

aperfeiçoar a compilação, não se tratava do foco deste projeto então as únicas

configurações feitas foram a mudança do nome do novo kernel e a alteração da família

de processadores utilizado (quando necessário).

Assim, os arquivos estão prontos para a compilação. O comando para tal ação é

o make. Este comando é responsável por organizar um número mínimo de compilações

necessárias para que se possa atualizar todo o kernel. Ele foi utilizado com a sequência

–j4 para que todos os 4 processadores lógicos pudessem ser utilizados em sua máxima

capacidade a fim de minimizar o tempo de compilação.

Após o kernel compilado, compilou-se os módulos pertencentes e então os

instalou-se.

E, finalmente, o kernel pode ser instalado e, para que ele fosse inicializado com

o sistema operacional, uma reinicialização é necessária e a escolha do kernel se dá pelo

gerenciador de boot do Linux.

Page 8: Implementação de System Call no Linux

8

4.2 System Call

#include <linux/sched.h>

#include <linux/pid.h>

#include <linux/kernel.h>

#include <linux/cred.h>

#include <linux/ktime.h>

asmlinkage long sys_tcdso(int p){

pid_t pid = p;

kuid_t credd_uid;

long int tempost;

struct pid *pid_struct = find_get_pid(pid);

struct task_struct *task =

pid_task(pid_struct,PIDTYPE_PID);

struct task_struct *taskp =

pid_task(pid_struct,PIDTYPE_PID);

struct timespec tmp;

if (task == NULL){

return (-1);

}

else {

tempost = task -> start_time;

tmp = ktime_to_timespec(ktime_get_boottime());

credd_uid = task->cred->uid;

taskp = taskp -> parent;

printk("UID do processo: %ld.\n",credd_uid);

printk("PID do PAI: %ld.\n",(long int)taskp ->

pid);

printk("Tempo de vida [s]: %ld.\n", tmp.tv_sec

- tempost/1000000000);

return (0);

}

}

Page 9: Implementação de System Call no Linux

9

O código que apresentado é o utilizado para executar os requisitos do problema

proposto para o grupo. Nos parágrafos seguintes ele está explicado detalhadamente para

um melhor entendimento do leitor, tal explicação será dada por partes.

#include <linux/sched.h>

#include <linux/pid.h>

#include <linux/kernel.h>

#include <linux/cred.h>

#include <linux/ktime.h>

Este cabeçalho presente na system call mostra as bibliotecas utilizadas para o

funcionamento de todas as funções que foram necessárias para o desenvolvimento da

system call. A biblioteca <linux/sched.h> contém a estrutura necessária para

encontrar os parâmetros de identificação do processo. Por sua vez, <linux/pid.h>

possui parâmetros necessários para a localização de estruturas relacionadas ao PID do

processo procurado. Estas estruturas serão abordadas a seguir. A utilização da biblioteca

<linux/kernel.h> é necessária de modo a ser permitida a utilização da função de

impressão no buffer do kernel (função printk()). Para que o UID seja encontrado, a

biblioteca <linux/cred.h> é necessária. E, por fim mas não menos importante, a

biblioteca referente a análise do tempo de vida do processo, <linux/ktime.h>.

O trecho do código a seguir possui todas as declarações necessárias para o

funcionamento da system call que fora implementada.

asmlinkage long sys_tcdso(int p){

pid_t pid = p;

kuid_t credd_uid;

long int tempost;

struct pid *pid_struct = find_get_pid(pid);

struct task_struct *task =

pid_task(pid_struct,PIDTYPE_PID);

struct task_struct *taskp =

pid_task(pid_struct,PIDTYPE_PID);

struct timespec tmp;

Na primeira linha, está representado a declaração da system call nomeada por

sys_tcdso. Nota-se que esta função retornará um tipo long quando for chamada pelo

Page 10: Implementação de System Call no Linux

10

usuário ou por alguma aplicação. O marcador asmlinkage representa um macro que

instrui ao compilador GCC de que esta função necessita que seus argumentos sejam

colocados na pilha, ao invés de serem alocados em registradores. O argumento, como já

mencionado anteriormente, será um inteiro representando o PID que se deseja analisar.

A linha consequente é responsável de alocar o argumento passado pelo usuário

em uma variável tipo pid_t para que esta possa ser utilizadas em funções para análises

de PID.

Seguindo, assim como a linha anterior, as duas linhas seguintes se comprometem

a determinar um tipo kuid_t para um campo onde irá receber o UID requisitado pelo

projeto e um tipo long int para armazenar o tempo de início do processo.

A primeira estrutura será utilizada para encontrar um ponteiro para outra

estrutura. Esta estrutura é conhecida como task_struct. A task_struct se trata

de uma estrutura de dados que contém todas as informações que o kernel possui sobre um

processo e, para ela, criou-se um ponteiro. Que será inicializada nas duas linhas seguintes.

O fato de existir duas estruturas idênticas, apenas com nomes diferentes, se dá ao fato da

necessidade de encontrar o PID do processo pai do processo identificado pelo PID

passado como argumento. Logo, deve-se encontrar a estrutura para o processo pai

também.

E, por fim, uma última estrutura foi declarada. Este tipo de estrutura,

timespec, fora necessário para que o acesso ao tempo, em segundos desde o último

boot, fosse possível.

Assim, a seção de declarações é finalizada. O próximo trecho mostra o retorno

da system call caso o PID recebido não exista no momento da chamada. Como solicitado

pelo projeto, esta situação deve retornar o valor –1 para o usuário.

if (task == NULL){

return (-1);

}

Caso a comparação feita no trecho acima seja inválida, a chamada de sistema

continuará para o trecho mostrado a seguir:

else {

tempost = task -> start_time;

tmp = ktime_to_timespec(ktime_get_boottime());

credd_uid = task->cred->uid;

Page 11: Implementação de System Call no Linux

11

taskp = taskp -> parent;

printk("UID do processo: %ld.\n",credd_uid);

printk("PID do PAI: %ld.\n",(long int)taskp ->

pid);

printk("Tempo de vida [s]: %ld.\n", tmp.tv_sec -

tempost/1000000000);

return (0);

}

De forma a atender os dados solicitados pelo projeto, foi necessário acessar

alguns campos das estruturas.

O primeiro campo mostrado é um campo referente ao tempo em que o processo

foi inicializado no sistema, o start_time. Este campo é dado em nano segundos,

contados desde o boot do sistema até a inicialização do sistema.

Em sequência, deseja-se obter o tempo desde o boot até o momento de chamada

da função. Para isso, foi necessário a utilização de duas funções. A primeira,

ktime_get_boottime(), faz com que o tempo desde o boot seja acessado num tipo

de tempo chamado de ktime, o que inicialmente não é utilizável para o objetivo final.

Com este valor obtido, a segunda função, ktime_to_timespec(), transforma este

tempo de forma a preencher a estrutura timespec apresentada anteriormente. Nesta

estrutura encontra-se um campo para segundos e nano segundos.

Seguindo, encontramos a sequência de ponteiros que são utilizados para que o

valor do UID do processo identificado pelo PID passado pelo argumento seja encontrado.

Este valor se encontra dentro de uma estrutura diferente, a estrutura cred, mas que possui

um campo na estrutura task_struct. Com isso, apenas é necessário apontar para o

campo cred da task_struct e então apontar para o campo que possui o UID do

processo.

Assim como para o UID, o PPID não se encontra dentro da task_struct do

processo procurado. Entretanto, existe um campo que possui um ponteiro apontando para

a task_struct do processo pai. Assim, para que o PPID seja encontrado, é necessário

apontar para o processo pai, e então apontar para o PID. Esta última ação só é executada

na linha onde imprime o valor do PPID no buffer do kernel.

Por fim, os comandos de impressão são executados. Note que a conversão do

tempo de início do processo é feita diretamente.

Page 12: Implementação de System Call no Linux

12

4.3 A implementação da System Call

Após a definição do código, deve-se implementar a system call no kernel e então

compila-lo.

Os passos a seguir foram seguidos para que esta implementação fosse possível,

e assim, fosse utilizada após a compilação e instalação do novo kernel.

Ao iniciar, deve-se adicionar o código da system call no diretório /kernel nos

arquivos descompactados do kernel do Linux citados acima. Em seguida, as

configurações dos arquivos base para o reconhecimento da nova system call adicionada.

A ordem destes comandos não altera o resultado final, mas todos eles devem ser

feitos para a obtenção de sucesso na implementação.

Deve-se associar um número para a nova chamada de sistema. A tabela de

número das chamadas de sistema existentes no kernel pode ser encontrada em

arch/x86/syscalls/syscall_64.tbl e o formato para adicionar ela na lista é

[número] [ABI] [nome] [entry_point]. O número deve seguir a sequência

da tabela, o ABI deve ser preenchido com common para que a system call funcione em

diferentes ABIs, o nome da chamada de sistema, neste caso tcdso e o nome da função

sys_tcdso, que chamará a system call adicionada.

Deve-se então fornecer um protótipo para a system call e adicioná-lo em

include/linux/syscalls.h. Este protótipo será a declaração da system call

contida no código, asmlinkage long sys_tcdso(int p);.

Por fim, edita-se o arquivo /kernel/Makefile com a extensão da system

call, tcdso.o, para que a system call seja compilada quando acontecer a compilação do

kernel.

Após todas estas mudanças, o kernel pode ser compilado e a system call poderá

ser utilizada normalmente pelo usuário.

Page 13: Implementação de System Call no Linux

13

5 CONCLUSÕES

Com a modernização desenfreada do mundo atual, constantes atualizações

devem ser necessárias em sistemas regidos sistemas computacionais. Portanto, não se

existe o espaço para a criação diária de novos sistemas operacionais a fim de suprir as

necessidades de todos os consumidores.

As chamadas de sistemas analisadas durante o desenvolvimento desde trabalho

são um grande exemplo destas atualizações de forma a modificar um sistema já existente

e operando, a fim de acrescentar e este apenas novas funções.

Embora as funções implementadas neste projeto tenham sido bastantes

simplificadas, não foram triviais na implementação. A programação neste nível não era

familiar a nenhum dos integrantes. Houve grandes dificuldades relacionadas desde a

compilação e instalação do kernel, à implementação do código da system call. Outro fator

para grandes buscas fora o fato de estar programando em um ambiente diferente do

acostumado, dada a impossibilidade de utilização das funções de user level em kernel

level.

Contudo, concluímos que o presente trabalho foi de suma importância e de

grande incremento na vida acadêmica e profissional, uma vez que possibilitou através de

uma experiência prática, se adquirir um conhecimento mais aprofundado de como se

alterar um sistema operacional de forma a realizar funções impostas por condições de

projeto.

Page 14: Implementação de System Call no Linux

14

6 BIBLIOGRAFIA

[1] “Chamadas de Sistema - O que são, Para que servem e Exemplos de System Call,”

Programação Progressiva.net, [Online]. Available:

http://www.programacaoprogressiva.net/2014/09/O-que-sao-Chamadas-de-

Sistema-para-que-servem-Exemplos-de-System-Calss.html. [Acesso em 19

Novembro 2015].

[2] R. M. JUNIOR, “Sistemas Operacionais - Gerência de processador,” [Online].

Available:

http://www.facom.ufu.br/~rivalino/facom49060/%5b1%5d%20Slides%20(Lecture

%20Notes)/UNIDADE%20IV/FACOM49060%20-%20Unidade%20IV.pdf.

[Acesso em 19 Novembro 2015].

[3] “Tutorial - Compilação de um novo Kernel Linux,” [Online]. Available:

http://www.facom.ufu.br/~rivalino/facom49060/%5B2%5D%20Papers%20&%20

TRs/tutorial-kernel-generico.pdf. [Acesso em 19 Novembro 2015].

[4] “Tutorial - Adicionando novas chamadas de sistema ao kernel Linux,” [Online].

Available:

http://www.facom.ufu.br/~rivalino/facom49060/%5B2%5D%20Papers%20&%20

TRs/tutorial-syscall-linux.pdf. [Acesso em 22 Novembro 2015].

[5] A. S. TANENBAUM, Sistemas Operacionais Modernos, 3ª ed., vol. I, São Paulo:

Pearson Education do Brasil Ltda., 2010.

[6] R. LOVE, Linux Kernel Development - A thorough guide to the design and

implementation of the Linux kernel, 3ª ed., Crawfordsville: Pearson Education, Inc.,

2010.