Porte de Sistemas Embebidos para Uclinux

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 95

Porte de Sistemas Embebidos para uClinux

António José da Silva

Dissertação para obtenção do Grau de Mestre em

Engenharia Informática e de Computadores

Júri
Presidente: Prof. Luís Eduardo Teixeira Rodrigues
Orientador: Prof. Alberto Manuel Ramos da Cunha
Vogais: Prof. José Carlos Alves Pereira Monteiro

Julho de 2008
Abstract
The emergence of embedded computing in our daily lives has made the embedded applications into one of
the crucial factors for embedded systems. Given the diversity of currently available applications, not only for
embedded, but also for general purpose systems, it will be important to easily reuse part, if not all, of these
applications in future and current products. To accomplish this task, a common development basis must be
defined and the operating system plays an undeniable role in it.
Often companies have their entire embedded product built out of their own proprietary embedded opera-
ting system. This is the case of Tecmic and the in-house developed Xtran-3 board, which serves as the object
study of this work. The widespread interest and enthusiasm generated by Linux’s successful use in a number
of embedded systems has led to many contributions from developers, hardware and software vendors, which
made Linux a strong presence in the embedded market.
In this thesis, several commercial and open source alternatives for embedded operating systems, including
uClinux, are reviewed, emphasising their feature set, ease of use and bottlenecks as possible candidates
for deployment on the XTran-3 board. A detailed porting guide to uClinux using the XTran-3 board is also
presented. All the relevant steps, from the development environment set up, to the kernel configuration,
device driver implementation and application writing are thoroughly described.

Keywords: embedded, linux, uClinux, operating system, kernel, XTran-3, hardware, driver

i
Resumo
A importância emergente da computação embebida no nosso dia-a-dia tornou as aplicações embebidas num
factor crucial para os sistemas embebidos. Dada a diversidade de aplicações proprietárias e sobretudo de
código aberto que existe actualmente, quer nos sistemas embebidos, quer nos sistemas de âmbito geral, é
de todo o interesse reaproveitar ao máximo o que já se encontra desenvolvido, testado e disponível. Para
isso, é necessário que haja uma base de desenvolvimento comum, tendo o sistema operativo um papel
fundamental na sua definição. Muitas empresas ainda baseiam as suas soluções embebidas em sistemas
operativos fechados e desenvolvidos de raiz para as suas soluções. É este o caso da Tecmic e de um dos
seus produtos, a placa XTran-3, sob a qual se debruça este trabalho. Graças ao aumento de popularidade do
Linux, impulsionado pelo seu uso nalguns sistemas embebidos comerciais, tem havido um aumento da parti-
cipação no desenvolvimento deste sistema operativo, desde simples entusiastas até aos próprios fabricantes
de hardware e software. Este interesse crescente de várias fontes distintas fez com que o Linux ganhasse
uma presença cada vez mais forte no mercado embebido.
Neste documento, são analisados vários sistemas operativos embebidos proprietários e de código aberto,
incluindo o uClinux, expondo os pontos fortes e fracos de cada um no contexto do porte para a placa XTran-3.
É também explicado detalhadamente o porte daquele hardware para uClinux, desde a preparação do ambi-
ente de desenvolvimento até à escrita de aplicações, passando pela configuração do núcleo e implementação
de controladores.

Palavras Chave: embebido, linux, uClinux, sistema operativo, núcleo, XTran-3, hardware, controlador

iii
Agradecimentos
Não teria conseguido terminar este trabalho sem a preciosa ajuda de algumas pessoas às quais gostaria de
agradecer:

• Ao meu orientador Prof. Alberto Cunha, pelos esclarecimentos prestados na elaboração desta disser-
tação.
• Ao meu co-orientador Eng. Gabriel Saragoça, da Tecmic, pela extraordinária paciência e disponibili-
dade demonstradas e pela partilha de conhecimento sobre o funcionamento da placa XTran-3.
• Ao meu colega e amigo Eng. Nelson Silva, pelos vários esclarecimentos e discussões sobre o funcio-
namento do kernel e da configuração do uClinux.
• Ao meu colega e amigo Cláudio Martins, pelos vários esclarecimentos e discussões sobre o kernel e
algumas ferramentas e utilitários usados nos sistemas não embebidos Linux.
• Ao meu colega e amigo Eng. Samuel Martins, pelos esclarecimentos sobre LATEX.
• Aos meus chefes de equipa Eng. Tiago Esperança e Eng. Pedro Gonçalves, da Xpand-IT Solutions,
pela compreensão demonstrada ao longo do ano lectivo e por terem dado bastante importância a este
trabalho final.

v
Índice

Abstract i

Resumo iii

Agradecimentos v

Lista de Figuras xi

Lista de Tabelas xiii

Lista de Acrónimos xv

1 Introdução 1
1.1 Noção de sistema operativo embebido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Motivação para o uso de um sistema operativo embebido . . . . . . . . . . . . . . . . . . . . 2
1.3 Contexto de utilização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Sobre esta dissertação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2 uClinux e outros sistemas operativos embebidos 7


2.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.1 Arquitectura do núcleo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.1.2 Parâmetros analisados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 QNX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 VxWorks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

vii
2.4 Windows Embedded CE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.5.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.5.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.5.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.5.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.6 RTLinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.6.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.6.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.6.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7 uClinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7.1 Instalação e configuração . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7.2 Gestão de tarefas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.3 Gestão de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.4 Gestão de interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.5 Suporte de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.6 Ferramentas de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.7.8 Metodologia de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.8 Inferno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.9 eCos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.10 Contiki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

viii
2.11 Symbian OS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

2.12 Tabelas de síntese comparativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

2.13 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

3 Porte de um sistema embebido para uClinux 31

3.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.2 Ambiente de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.3 Sistema de configuração uClinux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

3.4 Configuração do núcleo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.5 Detecção de hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.5.1 Arranque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

3.5.2 Controladores de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.5.3 Partições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

3.6 Controladores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3.6.1 Memórias flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3.6.2 Relógio de tempo real . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

3.6.3 Porta série não standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.6.4 Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

3.6.5 Leds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.6.6 Integração dos controladores no sistema de configuração . . . . . . . . . . . . . . . . 47

3.7 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3.7.1 Programa ds2404help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

3.7.2 Programa ledshow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

3.8 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

4 Análise de desempenho ao sistema portado 51

4.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.2 Ferramenta de análise de desempenho lmbench . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.2.1 lat_syscall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

4.2.2 lat_proc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

4.2.3 lat_ctx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52

4.3 Testes ao sistema original vs Testes ao sistema portado . . . . . . . . . . . . . . . . . . . . . 55

4.4 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5 Conclusões e trabalho futuro 57

5.1 Conclusões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

5.2 Trabalho futuro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

Bibliografia 61

ix
A Algumas considerações sobre o núcleo do uClinux 63
A.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
A.2 Arquitectura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
A.3 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
A.4 Controlo de Concorrência . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
A.5 Controlo de entradas e saídas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
A.6 Interrupções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
A.7 Sistema de ficheiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
A.8 Modelo geral de um controlador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

B Tabela de instruções para o RTC ds2404 77


B.1 Tabela de instruções para o RTC ds2404 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

x
Lista de Figuras

1.1 Arquitectura genérica de um sistema embebido. . . . . . . . . . . . . . . . . . . . . . . . . . 2


1.2 Sistema XTran desenvolvido pela Tecmic. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.1 Arquitectura de um núcleo monolítico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9


2.2 Arquitectura de um micro-núcleo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Arquitectura de um núcleo híbrido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3.1 Sistema de configuração do uClinux, primeiro ecrã. . . . . . . . . . . . . . . . . . . . . . . . . 34


3.2 Mapa da configuração do núcleo do uClinux. . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3 Mapa de memória da imagem do uClinux na Ram da placa XTran-3. . . . . . . . . . . . . . . 37
3.4 Hardware a detectar na placa XTran-3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.5 Implementação dos periféricos do tipo MTD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.6 Ecrã de configuração do controlador ds2404 . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

A.1 Arquitectura do núcleo do Linux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

xi
Lista de Tabelas

2.1 Soluções comerciais analisadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27


2.2 Soluções grátis analisadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

4.1 Resultados de execução do teste lat_syscall na placa XTran-3 . . . . . . . . . . . . . . . . . . 52


4.2 Resultados de execução do teste lat_proc na placa XTran-3 . . . . . . . . . . . . . . . . . . . 52
4.3 Resultados de execução do teste lat_ctx na placa XTran-3 . . . . . . . . . . . . . . . . . . . . 53
4.4 Resultados de execução do teste lat_ctx na placa S3C24A0 (valores em microssegundos) . . 54
4.5 Resultados de execução do teste à consola série na placa XTran-3 (valores em milissegundos) 55

B.1 Instruções em modo 3-wire para o DS2404 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

xiii
Lista de Acrónimos
ANSI - American National Standards Institute
API - Application Program Interface
ASP - Active Server Pages, a web-scripting interface by Microsoft
bash - Bourne Again Shell
BDM - Background Debug Mode, a programming interface to embedded systems microcontrollers like JTAG
binutils - A GNU collection of binary utilities
BIOS - Basic Input/Output System
CPU - Central Processing Unit
EEPROM - Electrically Erasable Programmable Read-Only Memory
FIFO - First In, First Out: a queue type
Flash - A nonvolatile memory capable of retaining digital information
FTP - File Transfer Protocol
GCC - GNU C and C++ Compiler
GDB - GNU debugger
GNU - A recursive acronym for “GNU’s Not Unix”
GPL - The GNU General Public License
GUI - General User Interface
HTTP - Hypertext Transfer Protocol
IEEE - Institute of Electrical & Electronics Engineers
IRQ - Hypertext Transfer Protocol
ISAPI - The Internet Server Application Programming Interface (ISAPI) is an N-tier API of Internet Informa-
tion Services (IIS), Microsoft’s collection of Windows-based web server services
I/O - Input-Output
I2C - Inter-Integrated Circuit
ioctl - The ictol() system call: for device input and output control
IP - Internet Protocol
IPC - Interprocess Communication
JFFS/2 - The Journaling Flash File system: two different versions
m68k - Family of 32-bit CISC microprocessor CPU made by Motorola
motd - Message Of The Day
LED - Light Emiting Diode
LRU - Least Recently Used
MCF - Motorola Cold Fire
MMU - Memory Management Unit
MTD - Memory Technology Device
NFS - Network File System
OSI - Open Systems Interconnection
PC - Personal Computer

xv
POSIX - Portable Operating System Interface for Unix
RAM - Random Access Memory
RAMDISK - A software abstraction that treats a segment of random access memory (RAM) as secondary
storage, a role typically filled by hard drives
ROM - Read-Only Memory
romfs - Read-only filesystem for Linux
RCU - Read-Copy-Update
RTC - Real Time Clock
SMP - Symmetric Multi Processing
SREC - Computer file format containing binary data.
SSH - Secure Shell
TCP - Transmission Control Protocol
TFTP - Trivial File Transfer Protocol
UART - Universal Asynchronous Receiver Transmitter
uClibc/uC-libc - Micro libc
uClinux - Micro-controller Linux
UDP - User Datagram Protocol
UNIX - Uniplexed Information and Computing System
USB - Universal Serial Bus
vfork - The vfork() system call: to create processes and block parent
VFS - Virtual File System

xvi
1 Introdução
Antes de entrar no âmago deste trabalho, que incide essencialmente sobre o porte de um sistema embebido
para uClinux, torna-se necessária a introdução de conceitos e motivações que explicam o problema de porte.
É importante perceber a razão do aparecimento dos sistemas operativos classificados como embebidos, ou
embarcados, e até dos próprios sistemas embebidos, antes de enveredar pelos capítulos posteriores que
incidem sobre o caso concreto do uClinux. Este capítulo pretende enquadrar o leitor para o uso não só
do uClinux como sistema operativo embebido, mas também para o próprio uso de um sistema operativo
num sistema embebido, pois estes são conceitos que nem sempre estiveram tão fortemente ligados como
actualmente.

1.1 Noção de sistema operativo embebido

Todos conhecemos o vulgar pc de secretária, cujo propósito serve uma panóplia de necessidades mais ou
menos relacionadas: jogos, filmes, edição de texto, contabilidade, disponibilização de pequenos serviços,
acesso à Internet, entre outros propósitos que poderão ou não ser realizados dentro da mesma máquina,
usando o mesmo sistema operativo de âmbito geral. Ao contrário destes sistemas, os sistemas embebidos
são concebidos para desempenhar apenas e somente um conjunto bem definido de tarefas. De facto, a
diferença principal entre estes dois tipos de sistemas está precisamente no propósito que servem, o que leva
também à distinção do sistema operativo (a camada de software que comunica directamente com o hard-
ware) que irá correr sobre eles. Tendo em conta as diferentes finalidades a que se destinam os sistemas
embebidos existentes actualmente no mercado (routers, switches, leitores de mp3, telemóveis, satélites, en-
tre outros) existem algumas características comuns que os permitem distinguir de um sistema de âmbito
geral:

• Tempos de resposta bem definidos (o sistema tem de responder sem atrasos a determinadas tarefas)
• Requisitos funcionais de hardware são baixos relativamente a um pc normal (pouca RAM/ROM, pro-
cessadores especializados)
• Requisitos de hardware são específicos para cada sistema embebido e adaptados a cada funcionali-
dade
• Eventual existência de limitações ao consumo de energia
• Custo total do sistema é um factor importante (tem que ser reduzido)

Para gerir todos os periféricos de um sistema de âmbito geral, é necessário um sistema operativo comum,
construído de base para suportar um número elevado de periféricos, estando também preparado para cor-
rer um ainda maior número de programas compilados especificamente para estes, com ou sem bibliotecas
externas associadas. Um sistema operativo embebido possui normalmente um conjunto limitado de funcio-
nalidades e é específico para o hardware onde irá correr. No limite, um sistema operativo embebido simples
poderá ser apenas um pedaço de código assembly que se executa em ciclo e chama um número arbitrário
de funções a cada iteração. Este código precisa de suportar o conjunto de periféricos que estão presentes
no sistema embebido onde irá correr, assegurando o tempo de resposta aceitável para o desempenho do
sistema. Estas restrições de tempos de resposta podem ser:

1
Hard Real Time O não cumprimento da restrição (falhar um deadline) causa falhas no sistema
Soft Real Time O não cumprimento da restrição apenas diminui a performance do sistema

Estes dois comportamentos (hard e soft real time) são apenas um dos vários requisitos não funcionais
que existem num sistema embebido. Outros requisitos não funcionais são as características físicas do sis-
tema embebido (tamanho, peso...), o consumo de energia e a fiabilidade.
Ao nível dos requisitos funcionais, verifica-se que, com o passar do tempo, a complexidade dos sistemas
embebidos aumentou, bem como a do software que corre nestes. A capacidade de desempenhar várias ta-
refas com prioridades diferentes e o cumprimento de uma lista cada vez maior de funcionalidades levou a que
o software dos sistemas embebidos evoluisse para possuir, à semelhança dos sistemas operativos de âmbito
geral, mecanismos de gestão de processos e memória, temporizadores, implementações de protocolos es-
pecíficos etc. Este tipo de requisitos fazem com que a barreira entre os sistemas operativos embebidos e os
sistemas operativos de âmbito geral esteja cada vez mas ténue. Os sistemas embebidos actuais já se asse-
melham aos sistemas considerados de âmbito geral há uns anos atrás. As necessidades dos utilizadores de
sistemas de âmbito geral mudam significativamente com o passar do tempo, fazendo com que a definição de
âmbito geral esteja, ela própria, em constante redefinição. Apesar do aumento do número de funcionalida-
des dos sistemas embebidos actuais e da elevada capacidade de controlo que se pretende de um software
capaz de gerir estes sistemas, pretende-se também que o custo seja minimizado, daí que, nos dias de hoje,
se verifique que a evolução da tecnologia associada ao desenho de sistemas operativos embebidos esteja a
caminhar para implementações genéricas com graus de adaptabilidade cada vez maiores.

1.2 Motivação para o uso de um sistema operativo embebido

Um sistema embebido contém essencialmente um microprocessador e software que corre numa memória
ligada directa ou indirectamente ao resto do sistema. Estas memórias são normalmente RAM, ROM ou flash
e servem como espaço de armazenamento (volátil no caso da RAM) de código e/ou dados.
Independentemente das características do processador da figura 1.1, para controlar um hipotético sis-
tema embebido mínimo com um processador e uma memória, seria necessária, para além das ferramentas
de compilação e ambiente de desenvolvimento, a escrita de pelo menos algum código de inicialização do pro-

Figura 1.1: Arquitectura genérica de um sistema embebido.

2
cessador (e do respectivo controlador de memória) e ainda da própria memória associada. A este sistema
embebido hipotético poderão ser acrescentadas chamadas a funções que irão executar tarefas distintas.
Deste modo, obter-se-ia um sistema operativo mínimo, com uma sequência de tarefas a ser executada a
cada iteração do ciclo.

begin
initialize_hardware()
do
call_to_task_1()
...
call_to_task_n()
while(1)
end

Note-se que não existe qualquer relação de prioridade na execução das tarefas, estas são simplesmente
chamadas e executadas, cada uma na sua vez. Esta arquitectura de software é denominada de round-robin
e é a mais simples de implementar, mas também é a que tem menos flexibilidade. A partir deste ponto, a
complexidade do sistema aumenta significativamente. No grau de complexidade seguinte, tem-se o caso
dos dispositivos de entrada poderem sinalizar o processador que possuem dados para processar através
de interrupções. Estas interrupções, quando ocorrem, provocam a execução de funções específicas para o
atendimento daqueles eventos. Se adicionarmos essas funções ao código acima, teremos a chamada arqui-
tectura em round-robin com interrupções. Apesar das interrupções poderem conduzir o fluxo de execução
de código na arquitectura em round-robin com interrupções, ainda não é possível definir prioridades para
cada tarefa. Uma maneira de implementar estas prioridades é fazer com que, na rotina de atendimento à
interrupção, seja despoletado um mecanismo de escalonamento da tarefa associada. Este mecanismo de
escalonamento poderá ser uma simples fila FIFO, ou seja, quando ocorre uma interrupção, a função que vai
tratar os dados que serão lidos do periférico é inserida numa fila. Quando a rotina de atendimento à inter-
rupção termina, terá de ser executada uma função que retirará a função da fila, invocando-a após isso. Esta
arquitectura é denominada de Function-Queue Scheduling. Para realizar outros tipos de escalonamento, terá
de ser implementada uma política que se concretizará num troço de código que irá realizar a comutação de
tarefas, denominado escalonador. As tarefas, por suas vez, terão de explicitamente informar o escalonador
que estão a realizar uma operação lenta e podem abdicar do processamento por alguns instantes. Esta no-
tificação explícita das tarefas ao escalonador poderá ser feita programaticamente através de uma chamada
à função de escalonamento ou através de uma interrupção de software, obtendo-se assim um algoritmo
de cooperative multi-tasking. No caso em que o escalonador possui um mecanismo de atribuição de blocos
temporais às tarefas, deixa de ser necessário serem estas a notificá-lo, pois este irá correr quando aquele
intervalo acabar. Este mecanismo é denominado de preempção.
No parágrafo anterior foram introduzidos dois graus de complexidade ao hipotético sistema embebido
apresentado. O primeiro deve-se essencialmente ao carácter imprevisível da ocorrência de interrupções e
o segundo à introdução de um mecanismo de escalonamento dinâmico (que altere a sua escala em tempo
de execução) de tarefas. Este aumento de complexidade poderá ser ainda maior à medida que se forem

3
ligando periféricos ao processador. Dependendo da natureza do periférico, vários tipos de mecanismos
de software (preempção voluntária, atendimento de interrupções, acesso exclusivo a zonas de memória,
protocolos de comunicação, etc) terão de ser implementados no seu controlador (a rotina de software que
controla o periférico) para que este funcione de maneira correcta e sem prejudicar o funcionamento do
resto do sistema. Por exemplo, um controlador de uma memória flash terá um desempenho correcto caso
se verifique que os dados são efectivamente escritos na memória sem corrupção. Este desempenho será
óptimo quando a execução das suas tarefas não produz um efeito de míngua de recursos do sistema noutras
tarefas existentes. Para periféricos tão ou mais rápidos como o processador e que não possuam mecanismos
de interrupções associados, a escrita destas rotinas, bem como a sua integração com o resto do sistema
operativo deste exemplo, será trivial, no entanto, este conjunto de periféricos é demasiado restrito para as
necessidades comuns dos sistemas embebidos actuais [Wol01].

Dado o valor crescente da Internet e da conectividade com redes locais, um dos possíveis componentes
essenciais para conseguir integrar esta funcionalidade no sistema embebido apresentado é, por exemplo, um
controlador de rede. Este controlador teria que ser fisicamente ligado ao processador (ou a um controlador de
periféricos que esteja ligado ao processador) e, naturalmente, teria que ser suportado pelo sistema operativo
minimal construído no início desta introdução. Para além das funções de comunicação com este periférico,
teriam também de ser implementados alguns componentes da camada OSI, nomeadamente a camada de
rede (por exemplo, o protocolo IP) e ainda a camada de transporte (por exemplo, o protocolo TCP) [JFK05].
Escrever estas camadas eficientemente seria reinventar a roda face ao que existe disponível actualmente,
para além de que poderá ser fatal de um ponto de vista de viabilidade do negócio.

Assim, dada a necessidade da existência de mecanismos de controlo de interrupções, tarefas, periféricos


e protocolos de um sistema embebido actual, será necessária uma análise às implementações existentes de
sistemas operativos capazes de funcionar num sistema embebido, no caso deste trabalho, da placa XTran-3
da Tecmic. Consoante a escolha que será tomada, serão ainda descritas as tarefas associadas a toda a
operação de porte de controladores de periféricos que, no contexto deste trabalho, será feita para o uClinux.

1.3 Contexto de utilização

O contexto deste trabalho consiste na utilização de equipamentos embarcados para monitorização remota.
O equipamento utilizado, com nome comercial XTran-3, é um produto desenvolvido pela empresa Tecmic,
destinando-se a ser instalado em cada veículo a monitorizar. Tal como os seus projectos predecessores
XTran-1 e Xtran-2, tem a função de recolher e enviar vários dados sobre o estado do veículo, nomeada-
mente horas de funcionamento, quilometragem, alarme de manutenção e de outras métricas e diagnósticos,
alguns obtidos utilizando o protocolo CAN Bus. Estes sistemas embebidos fazem parte de um sistema maior,
denominado XTran, que é também constituído por um sistema informático central interligado aos sistemas
de back-office para solidez de informação, quer no sentido ascendente, quer descendente (ver figura 1.2).
Centralmente é um sistema de gestão que consegue falar com todas as unidades através de qualquer meio
de comunicação (TETRA, CDMA, GSM, GPRS, Trunking, Inmarsat Standard C, VHF MPT 1327), georeferen-
ciando as viaturas em mapas. Para os desenvolvimentos deste trabalho foi utilizado um protótipo funcional

4
Figura 1.2: Sistema XTran desenvolvido pela Tecmic.

da placa XTran-3, com parte do software desenvolvido pela Tecmic previamente instalado. Este software,
apesar de completamente funcional, cresceu bastante em complexidade e, sendo uma solução desenvolvida
à medida, todas as aplicações ou protocolos que sejam necessários foram implementados de raiz, sem poder
tirar partido das implementações existentes, comerciais ou de código aberto. Assim, a Tecmic está a estudar
alternativas ao sistema operativo que actualmente utiliza, sendo o Linux, que é de código aberto e suporta
um grande número de protocolos relevantes neste contexto (TCP/IP, USB, CAN, entre outros), um candidato
promissor.

1.4 Sobre esta dissertação

No próximo capítulo, é apresentado um estudo comparativo entre várias distribuições de sistemas operativos
usados em sistemas embebidos, entre elas a uClinux sob a qual assenta a parte prática deste trabalho, bem
como a motivação para o seu uso. São também explicadas as vantagens e requisitos de cada uma destas
distribuições e é ainda feito um enquadramento destas no âmbito da placa XTran-3 da Tecmic.
No capítulo 3 é documentado o porte de um sistema embebido para uClinux. O hardware a ser utilizado
no porte consiste num protótipo da placa XTran-3, desenhada pela empresa Tecmic. É feita, em primeiro
lugar, uma análise funcional às tarefas envolvidas no porte e, para alguns componentes, nomeadamente o
relógio de tempo real, a interface I2C e as memórias flash presentes nesta placa, é descrita uma solução
técnica detalhada para a colocação em funcionamento no núcleo do Linux, desde a instalação e arranque do
núcleo, até à execução de programas no novo ambiente de desenvolvimento. É também explicada, de uma
forma genérica, a configuração do núcleo bem como das aplicações da distribuição, colocando sempre em
evidência os passos e decisões mais comuns que terão de ser tomadas aquando do porte de um sistema
embebido para esta distribuição.
No capítulo 4 é feita uma análise ao desempenho do sistema portado. Esta análise inclui testes realisados
noutros sistemas operativos e ainda no software original antes do porte.
Por último, no capítulo 5 são apresentadas as conclusões deste trabalho, bem como possíveis melhora-
mentos às soluções apresentadas, quer de software, quer de possíveis alternativas ao hardware utilizado.

5
2 uClinux e outros sistemas operativos embebidos
2.1 Introdução

Apesar de, no âmbito deste trabalho, o uClinux estar já escolhido à partida, foram analisados outros sistemas
operativos relevantes para sistemas embebidos, quer pela sua popularidade, quer pelos conceitos inovado-
res que possuem. Assim, foram escolhidos o windows CE, o VxWorks, o QNX e o Symbian OS pela sua
popularidade em áreas distintas do mercado embebido. O Linux, o uClinux e o RTLinux foram escolhidos
pela sua relevância para o porte e também para realçar as diferenças e implicações envolvidas na escolha
do uClinux face a outros núcleos Linux. Foi também seleccionado um conjunto de soluções pouco populares
mas consideradas promissoras para futuras soluções embebidas, quer por se basearem em abordagens ra-
dicalmente diferentes das outras soluções analisadas, quer pelo elevado rácio entre o tamanho reduzido do
projecto e o número de funcionalidades ou elevada extensibilidade da sua implementação. Deste conjunto,
fazem parte o Inferno Os, o eCos e o Contiki.
Algumas das soluções abordadas neste capítulo seguem o paradigma do código aberto, ou seja, todas
as pessoas podem ver, modificar e usar o código sob um conjunto de restrições (normalmente GPL) que
terão de respeitar, enquanto outras são de código fechado, em que apenas são disponibilizados módulos
pré-compilados que se poderão juntar consoante o tipo de resultado pretendido. Esta diferença terá impac-
tos significativos ao nível do custo da solução, daí que a avaliação de todas as soluções analisadas neste
capítulo será feita tendo também em atenção este factor. Actualmente, existe um número muito elevado de
arquitecturas disponíveis no mercado e que são usadas para sistemas embebidos. Exemplos destas arqui-
tecturas são: x86, 8051, PowerPC, Coldfire68k, MIPS, ARM, SuperH entre outras. Estas arquitecturas não
são discutidas neste capítulo, embora o número de arquitecturas suportadas seja uma variável importante
na análise feita aos sistemas operativos.
O sistema operativo, mais propriamente o núcleo, ou kernel, é a parte do software de um sistema capaz
de transformar os vários blocos de hardware em ferramentas de computação através de uma API uniformi-
zada e abstraída dos pormenores de cada componente físico. Os seus componentes principais são:

Controlo de hardware Interrupções e modos do processador (supervisor ou restrito).


Controladores de periféricos Pequenos blocos de software destinados a providenciar toda a lógica exis-
tente entre um periférico e os mecanismos de controlo genéricos do sistema operativo.
Sistema de ficheiros Sistemas de ficheiros suportados pelo núcleo.
Comunicação entre processos Escalonamento, mecanismos de comunicação entre processos e gestão
de memória.
API do sistema Chamadas de sistema que são usadas pelas aplicações.
Aplicações do utilizador Os programas propriamente ditos.

2.1.1 Arquitectura do núcleo

A maneira como todos os componentes do núcleo se vão interligar entre si e as aplicações do utilizador, é
definida pela arquitectura do núcleo, que pode ser monolítica (ver figura 2.1), em micro-núcleo (ver figura 2.2)
ou híbrida (ver figura 2.3). Muitos núcleos modernos, independentemente da sua arquitectura, possuem

7
uma configuração flexível, permitindo remover alguns componentes em tempo de compilação e simplificando
assim a arquitectura obtida na imagem compilada. No entanto, cada arquitectura apresentada define o
nível conceptual em que cada componente se situa, independentemente de este estar presente ou não na
implementação de cada núcleo.

2.1.1.1 Arquitectura monolítica

Na arquitectura monolítica, todos os componentes que têm contacto directo com o hardware, ou que contro-
lam os recursos lógicos do sistema, estão integrados no núcleo e correm em modo de supervisor. Apesar de
este tipo de núcleos ter o melhor desempenho face aos outros dois apresentados neste capítulo, a integra-
ção de todos os componentes é particularmente difícil, quer pela dimensão do problema a resolver, quer pelo
facto de que, como todo o código do núcleo corre com todos os privilégios, ser fácil escrever fora do espaço
de endereçamento ou zonas de outros componentes, comprometendo assim a estabilidade e integridade do
sistema.

2.1.1.2 Arquitectura em micro-núcleo

Na arquitectura em micro-núcleo, apenas correm em modo de supervisor um conjunto restrito de compo-


nentes que providenciam funcionalidades básicas. Todos os outros componentes são implementados como
serviços, ou seja, processos que correm fora do núcleo. Nesta arquitectura, os serviços de sistema (siste-
mas de ficheiros, controladores de periféricos, gestores de memória, entre outros) ligam-se ao núcleo por
um mecanismo de subscrição que, periodicamente, o núcleo utiliza para verificar se estes estão “vivos” e
a responder. Caso algum temporizador expire durante uma destas verificações, o núcleo irá assumir que
ocorreu uma falha grave e encarregar-se-á de reiniciar este processo, através do chamado o mecanismo de
“ressurreição” de componentes.

2.1.1.3 Arquitectura híbrida

Neste tipo de arquitectura, apesar de existir também um modo de supervisor e um modo de utilizador, bem
como uma separação de componentes semelhante à existente na arquitectura em micro-núcleo, verifica-se
que todos os componentes, ou servidores, correm também em modo de supervisor. Existe alguma contro-
vérsia em relação a esta nomenclatura, no entanto, no âmbito deste documento, é considerado que esta
arquitectura difere da monolítica no sentido em que existe um maior grau de isolamento lógico entre cada
componente do núcleo como é apresentado na figura 2.3.

2.1.2 Parâmetros analisados

Tal como foi dito anteriormente, nos sistemas embebidos há uma integração total entre o hardware e o soft-
ware que o controla. No entanto, quando esse software é um sistema operativo com uma das arquitecturas
descritas na secção 2.1.1, existe também um conjunto de características que o passam a definir como embe-
bido. Estas características, que serão medidas na avaliação feita neste capítulo, descrevem todos os passos

8
Figura 2.1: Arquitectura de um núcleo monolítico.

Figura 2.2: Arquitectura de um micro-núcleo.

9
Figura 2.3: Arquitectura de um núcleo híbrido.

que envolvem a utilização de um sistema operativo embebido, desde a instalação e configuração, até à me-
todologia de desenvolvimento adoptada, passando por factores cruciais como a gestão de tarefas, memória
e interrupções, suporte de rede e quantidade de ferramentas disponíveis.

2.1.2.1 Instalação e configuração

O processo de instalação e configuração de um sistema operativo embebido varia de sistema para sistema.
No entanto, existe um processo comum a todos os sistemas operativos avaliados que consiste na criação
de uma imagem configurada para determinado conjunto de hardware. A forma como este processo é feito
(por linha de comandos, interface gráfica) e até onde é que este processo ocorre (já no sistema de destino
(sistema embebido) ou num sistema anfitrião que comunica de alguma maneira com o sistema embebido) é
considerada um factor importante na escolha de um sistema operativo embebido e será descrita e comparada
ao longo deste capítulo.

2.1.2.2 Gestão de tarefas

Um dos papéis principais de um sistema operativo é a sua capacidade de gerir consistentemente as várias
tarefas que possam estar em execução no sistema ao longo do tempo. Neste parâmetro, é avaliada a
capacidade de escalonar as diferentes tarefas e/ou processos em diferentes critérios utilizando, por exemplo,
mecanismos de garantia de comportamento de tempo real e de suspensão voluntária de processos ou tarefas
(preempção). Uma gestão de tarefas eficaz minimiza situações de míngua, de esgotamento de recursos ou
de não cumprimento de deadlines no caso dos sistemas de tempo real.

2.1.2.3 Gestão de memória

Apesar de estar muito dependente do suporte de hardware nos sistemas operativos embebidos, esta ca-
racterística permite determinar o grau de liberdade do programador em relação aos recursos consumidos

10
durante a execução de um programa. A existência ou não de uma MMU no processador, cuja função princi-
pal é traduzir endereços virtuais em endereços físicos, vai condicionar o suporte de hardware para eventuais
mecanismos de paginação e protecção de memória.

2.1.2.4 Gestão de interrupções

O suporte para interrupções de hardware e software é essencial na arquitectura de um sistema operativo


embebido. As interrupções são a maneira mais básica de os periféricos notificarem assincronamente a ocor-
rência de eventos que necessitem de ser tratados pelo software. No entanto, atender múltiplas interrupções
num sistema que já esteja em carga, mantendo um desempenho expectável, é um problema não trivial,
agravado ainda mais num sistema embebido onde os recursos são limitados. Neste critério será descrita
a metodologia seguida por cada sistema operativo para gerir as interrupções dos sistemas onde se irão
executar.

2.1.2.5 Suporte de rede

Recentemente, a capacidade de comunicar com exterior através de infra-estruturas de rede é um requi-


sito quase obrigatório em todos os sistemas embebidos para uso pessoal. Neste critério serão avaliadas
as primitivas de comunicação fornecidas por cada sistema operativo, bem como os protocolos e hardware
suportados por estes.

2.1.2.6 Ferramentas de desenvolvimento

Devido às diferentes origens de cada sistema operativo analisado, muitas vezes as ferramentas típicas de
desenvolvimento (compiladores da GNU, por exemplo) podem não estar disponíveis para os sistemas ope-
rativos analisados. Neste critério é classificada a abundância de ferramentas disponíveis para desenvolver
para cada sistema operativo apresentado.

2.1.2.7 Aplicações

Devido ao diferente grau de aceitação e popularidade dos sistemas operativos analisados, existe um número
variável de aplicações destinadas ao utilizador final, quer feitas de raiz, quer portadas de outros sistemas
operativos. Neste critério é classificada a abundância de aplicações existentes em cada sistema operativo.

2.1.2.8 Metodologia de desenvolvimento

Existem actualmente várias abordagens no desenvolvimento para sistemas embebidos: no sistema alvo,
ou numa máquina anfitriã. Cada uma destas metodologias tem um conjunto de ferramentas associadas
que permitem, por exemplo, fazer a instalação no sistema alvo, ou simular a execução de aplicações numa
máquina anfitriã. Neste critério, são descritas e comparadas todas estas metodologias de desenvolvimento
para cada sistema operativo analisado.

11
2.2 QNX

2.2.1 Instalação e configuração

O QNX Neutrino RTOS 6.3 é rápido e fácil de instalar (cerca de 15 minutos na máquina de testes). Poderá
ser usado um cd que contém tudo o que é necessário até para usar este sistema operativo no dia-a-dia, in-
cluindo o kernel (que possui uma arquitectura em micro-núcleo), e um sistema de janelas (Photon Windowing
System). Durante a instalação, todo o hardware crítico (placas de rede, discos) é detectado e instalado au-
tomaticamente. Para criar uma imagem configurada para determinado hardware, poderá ser usado um IDE
gráfico (System Builder) ou apenas um editor de texto para editar os ficheiros de configuração. A documen-
tação é bastante rica e cobre muitos exemplos de aplicações distintas. O System Builder é considerado pelo
autor uma ferramenta acima da média, na medida em que faz exactamente o que é pedido sem criar proble-
mas, ao contrário de outras tentativas de fazer um construtor gráfico de imagens “amigável” noutros sistemas
operativos analisados. No System Builder poderão ser importados ficheiros de build de outras configurações,
todas as dependências são calculadas automaticamente e o programador é notificado das bibliotecas que
estão em falta antes da compilação (e consequentemente da execução do código no sistema alvo). Possui
também um dietitian que é capaz de criar versões mais pequenas das bibliotecas utilizadas, que possuem
apenas as funções utilizadas.

2.2.2 Gestão de tarefas

O QNX usa processos e tarefas. Cada processo define um espaço de endereçamento em que as suas
threads irão correr. Na versão 6.3 as tarefas podem ter até 255 níveis de prioridades que foram divididos em
três grupos:

0 Tarefa Idle

1-63 Valores que o utilizador define para as threads que cria

64-255 Valores utilizados apenas por processos com privilégios de super-utilizador, como por exemplo, os
servidores que fazem parte da arquitectura em micro-núcleo deste sistema operativo

Para tarefas com a mesma prioridade, é possível definir o tipo de escalonamento utilizado:

FIFO A tarefa na posição mais à frente da fila de espera é executada, até voluntariamente ceder o controlo
a outras aplicações (por exemplo, efectuando uma chamada de sistema) Round-Robin: Funciona de
maneira semelhante ao FIFO, excepto a maneira como as tarefas saem da frente da fila é baseada
num intervalo de tempo.

Sporadic Scheduling É um modo de escalonamento adaptável em tempo de execução na medida em que


cada tarefa possui várias prioridades. À medida que o intervalo de tempo vai sendo consumido, a
prioridade da tarefa vai decrescendo caso esta consuma demasiado CPU. Após algum tempo em que
a tarefa possui uma prioridade baixa, o escalonador volta a atribuir a prioridade inicial à tarefa.

12
2.2.3 Gestão de memória

A arquitectura do QNX permite que cada aplicação, protocolo, sistema de ficheiros e até os controladores
de periféricos, corram fora do núcleo, num espaço de memória protegido. Os limites de cada página de
endereços usada variam consoante o processador, e até se pode optar por não usar paginação. O QNX
tem dois modos de execução. Durante o desenvolvimento é possível configurá-lo de maneira a verificar os
tamanhos dos heaps de cada aplicação, sendo também gerado um diagnóstico eficaz de eventuais fugas de
memória ou escritas indesejadas ao nível do sistema. Estas funcionalidades são normalmente desactivadas
após a instalação na máquina alvo pois comprometem o desempenho do sistema e servem apenas para a
fase de desenvolvimento.

2.2.4 Gestão de interrupções

O QNX permite mecanismos de partilha de interrupções, aninhamento de interrupções e diferentes níveis


de prioridade para cada interrupção. As rotinas de serviço à interrupção correm no mesmo contexto que o
processo que definiu a rotina de atendimento para cada interrupção.

2.2.5 Suporte de rede

O QNX possui suporte para TCP, UDP, IPv4 e v6 e, como é compatível com a norma Posix, possui toda a
API do núcleo que esta norma descreve. Para além destas funcionalidades, possui também um servidor web
embebido, um browser com a maior parte das funcionalidades dos browsers conhecidos e completamente
configurável a partir de ferramentas que vêm incluídas com o QNX.

2.2.6 Ferramentas de desenvolvimento

O QNX vem com um pacote de desenvolvimento chamado Momentics que é baseado no Eclipse e que possui
a capacidade de criar uma imagem configurada para cada sistema alvo. Para além do Eclipse, existe também
suporte para as ferramentas da GNU, tais como o gcc, gdb, gcc++ etc... Existe ainda uma aplicação para
desenhar interfaces gráficas no sistema de janelas do QNX e bibliotecas multimédia e 3D (opengl, mesa).

2.2.7 Aplicações

Practicamente não existem aplicações feitas por terceiros para QNX e as aplicações fornecidas com a dis-
tribuição são para utilização básica (calculadora, editor de texto mininalista etc). Apesar de toda a riqueza
de ferramentas de desenvolvimento, o QNX não tem muito mais para o utilizador comum. A estratégia se-
guida pelo fabricante deste sistema foca-se em fornecer facilidades para os seus clientes portarem o que
for necessário, o que não exige muito esforço visto que existe compatibilidade com a norma Posix e ainda
uma implementação de uma máquina virtual de Java. Devido ao modelo comercial seguido, as eventuais
aplicações portadas não ficam disponíveis para o utilizador comum. Claramente, este ponto é uma falha da
distribuição.

13
2.2.8 Metodologia de desenvolvimento

QNX segue uma metodologia em que o sistema anfitrião e o sistema alvo são o mesmo. Como foi descrito
anteriormente, o QNX pode ser não só apenas um micro-núcleo, mas também um sistema operativo com
todas as capacidades a que um utilizador de pc está habituado a ter, apesar de pobre em aplicações. É
igualmente possível utilizar as ferramentas de desenvolvimento cruzado (por exemplo, o Metrowerks IDE
para Windows) para seguir uma abordagem em que o software compilado é transferido para o sistema alvo
e as máquinas de desenvolvimento e de utilização diferem. O QNX permite ambas as abordagens e deixa
ao gosto do programador a escolha entre cada uma.

2.3 VxWorks

2.3.1 Instalação e configuração

O VxWorks vem disponível através de um conjunto de ferramentas que se instalam facilmente (pelos pro-
cessos comuns a programas vulgares) num ambiente Windows ou Linux. Uma vez instaladas todas essas
ferramentas (a instalação varia consoante a licença que se possui, o que faz variar também o número de
componentes disponíveis). As imagens do VxWorks são bastante difíceis de configurar devido ao número
muito elevado de opções que acabam por conferir uma flexibilidade ao VxWorks difícil de superar por um
sistema de código fechado. Apesar de difícil e moroso, a interface de configuração torna esta tarefa menos
difícil. No entanto, existe uma falta de documentação crónica para a configuração deste sistema operativo.
A página da Wind River, a companhia que desenvolveu o VxWorks, possui bastantes papers e outros docu-
mentos que ajudam a perceber o contexto de todas as opções, mas existem pontos que só se encontram
esclarecidos no Google através de testemunhos de pessoas que já tiveram problemas semelhantes.

2.3.2 Gestão de tarefas

O “coração” deste sistema operativo é o micro-núcleo Wind. Este micro-núcleo suporta multi-tarefa, vários
algoritmos de escalonamento de tarefas, mecanismos de sincronização e comunicação entre processos e
gestão de memória. Nas versões anteriores do VxWorks, era utilizado um único espaço de endereçamento
para conter todos os dados e código (núcleo e aplicações). Contudo, apesar de manter a compatibilidade
com as versões anteriores, a versão testada do VxWorks introduz o conceito de “domínio de protecção”, onde
cada aplicação ou componente do núcleo possui um domínio diferente. Embora não pareça um avanço drás-
tico em relação às técnicas de protecção de memória existentes actualmente para os sistemas operativos,
esta característica nova consegue sê-lo pois para além de se ter mantido a compatibilidade, foi também man-
tida a robustez, desempenho e fiabilidade que tornaram o VxWorks popular em aplicações críticas (Nasa,
por exemplo). O VxWorks possui 256 níveis de prioridade, tal como o QNX. Os algoritmos de escalonamento
disponíveis são apenas dois: com preempção ou em round robin. Possui mecanismos de partilha de me-
mória entre processos, semáforos, filas de mensagens, pipes e sinais. Suporta a norma Posix, tal como o
QNX.

14
2.3.3 Gestão de memória

O VxWorks suporta o uso de MMU. O tamanho de cada página física depende da arquitectura da máquina
alvo. Este suporte pode ser desabilitado.

2.3.4 Gestão de interrupções

As interrupções no VxWorks podem ser aninhadas e possuem prioridades. As rotinas de atendimento às


interrupções correm num espaço de endereçamento especial e que não se intercepta com qualquer outra
tarefa. No sistema, existe apenas uma pilha para guardar as interrupções e reside no espaço de memória
do núcleo. No código das rotinas que atendem as interrupções existem bastantes limitações no que respeita
ao acesso a memória partilhada e mecanismos de sincronização (não se podem criar ou destruir buffers
circulares (os buffers circulares são um tipo especial do núcleo do VxWorks), apenas podem ser enviadas
(não recebidas) filas de mensagens, apenas se pode escrever (não ler) para pipes, penas se podem enviar
(não receber) sinais e apenas podem abrir (não fechar) semáforos). Contudo, mesmo com estas limitações,
a flexibilidade do VxWorks a este nível é a melhor face aos outros sistemas operativos analisados.

2.3.5 Suporte de rede

O VxWorks possui suporte para TCP, UDP, IPv4 e v6 e, como é compatível com a norma Posix, possui toda
a API do núcleo que esta norma descreve. O VxWorks possui também um produto chamado “Tornado for
Embedded Internet” que consiste numa suite de aplicações que inclui:

• Servidor HTTP (Wind Web Server)


• Web browser
• Suporte Java
• Drivers adicionais para hardware de rede
• Protocolos de rede adicionais

2.3.6 Ferramentas de desenvolvimento

Apesar de o conjunto de ferramentas que vêm com o VxWorks ser bastante extenso, poderão ser adquiridas
ferramentas adicionais que encarecerão a compra do produto. No que toca a ferramentas de terceiros, são
poucas as aplicações que podem ser utilizadas para optimizar e/ou desenhar aplicações para o VxWorks.
O utilizador estará confinado ao que vem no pacote, em que até o compilador de C é proprietário da Wind
River, impossibilitando o uso de grande parte das ferramentas GNU. Existe ainda o Tornado IDE que conse-
gue integrar com sucesso a maior parte dos componentes que a Wind River disponibiliza para desenvolver e
depurar aplicações para o VxWorks. Este IDE é proprietário e foi implementado utilizando scripts de TCL/TK
que, dado o seu tamanho, prejudicam o seu desempenho, mesmo num computador actual. Este é um ponto
negativo, pois não existe alternativa à altura, em termos de funcionalidades, deste ambiente de desenvolvi-
mento.

15
2.3.7 Aplicações

À semelhança do QNX, o VxWorks também não possui aplicações portadas ou desenvolvidas de raiz dispo-
níveis. No entanto, existem igualmente ferramentas de desenvolvimento para portar aplicações já existentes
para outros sistemas Posix.

2.3.8 Metodologia de desenvolvimento

No VxWorks, é seguida claramente uma metodologia em que o sistema anfitrião e o sistema alvo são máqui-
nas distintas, apesar de poderem comunicar entre si de alguma maneira (cabo de série, de rede ou outros).
No sistema anfitrião (Windows ou Linux) corre o ambiente de desenvolvimento Tornado. A vantagem desta
abordagem reside na separação que é feita entre o sistema alvo e o sistema de desenvolvimento que pode
usar propriedades dos sistemas onde corre. Esta separação introduz também o problema da comunicação
entre ambos os sistemas (alvo e anfitrião) durante a depuração. Para resolver este problema, a Wind Ri-
ver introduziu o conceito de agentes de depuração que correm no sistema alvo e que enviam informação
ao sistema anfitrião, dando a impressão ao programador que a sua aplicação está a correr localmente. O
VxWorks possui ainda a capacidade de carregar e descarregar módulos em tempo de execução. Assim,
quando o programador pretender fazer alguma alteração, poderá alterar apenas o módulo específico e voltar
a carregá-lo em tempo de execução, sem ser necessária a ligação estática com o resto do código. Existe
também o ambiente de simulação VxSim, que é uma ferramenta de prototipagem e simulação de hardware,
especialmente indicada para os casos em que é necessário iniciar o desenvolvimento antes de o hardware
alvo estar disponível.

2.4 Windows Embedded CE

2.4.1 Instalação e configuração

O primeiro passo na instalação do Windows CE é instalar o Windows CE Platform Builder. Este software
consiste num conjunto de ferramentas que servem para configurar e criar uma imagem do Windows CE. É
possível escolher qual a arquitectura alvo e são instaladas as ferramentas específicas para cada arquitectura.
A instalação deste software foi a mais fácil de todas, pois a interface é semelhante à de outros programas
da Microsoft. Apesar do elevado número de assistentes para a criação de configurações e componentes,
grande parte do trabalho de configuração tem de ser feito manualmente através da edição de ficheiros de
texto, variáveis de sistema e eventuais scripts de configuração. A configuração de uma imagem do Windows
CE provou ser uma tarefa complexa, apesar de todas as facilidades concedidas pela interface existente.
O Windows CE é muito configurável pois é constituído por um conjunto discreto de módulos, em que cada
um fornece uma funcionalidade específica. A maior parte destes módulos está dividida em componentes que
podem ou não ser incluídos no sistema final. Uma configuração compacta do Windows CE ocupa cerca de
300KB. No processo de compilação, todos os módulos são incluídos no núcleo. Os módulos principais
são o núcleo, o gestor de objectos (de sistema), o sub-sistema gráfico e os componentes de comunicação
entre processos. Para além destes módulos primários, existem ainda outros que disponibilizam suporte para

16
multimédia, COM (Component Object Model), Windows CE shell e gestor de periféricos.

2.4.2 Gestão de tarefas

O Windows CE é um sistema multi-tarefa e de tempo real. Do ponto de vista do sistema existem processos e
tarefas que podem ter até 256 níveis de prioridade. Existia, até à versão 5, uma limitação de 32 processos a
correr simultaneamente e de 32MB de endereçamento disponíveis para cada processo. Na versão actual (6),
o limite do número de processos é de 32768 e a memória acessível para cada processo subiu para 2GB. O
escalonador apenas tem disponível o algoritmo de round-robin com quantum slices ajustáveis. Tarefas com
quantum igual a zero, são executadas até terminarem.

2.4.3 Gestão de memória

O Windows CE precisa obrigatoriamente de MMU pois apenas trabalha com memória paginada, sendo que
o tamanho das páginas depende da arquitectura. São suportados mecanismos de Page Swapping/Demand
Paging mas estas funcionalidades podem ser desabilitadas no núcleo caso se queira obter comportamento
de um sistema de tempo real.

2.4.4 Gestão de interrupções

É suportado aninhamento de interrupções bem como a prioritização das mesmas. O contexto das rotinas de
atendimento à interrupção é estaticamente definido pelos fabricantes do hardware. A tarefa de atendimento
às interrupções é uma aplicação normal e possui o seu próprio contexto. Dentro de uma rotina de serviço
às interrupção não é possível utilizar primitivas de comunicação do sistema, a não ser por eventos passados
à tarefa de atendimento de interrupções ou por zonas de memória partilhada mapeadas estaticamente pelo
fabricante de hardware.

2.4.5 Suporte de rede

O Windows CE possui suporte para TCP, UDP, IPv4 e v6. Ao contrário de outras versões do Windows, não
é compatível com a norma Posix. Apesar desta limitação, o Windows CE vem com um conjunto bastante
completo de ferramentas e produtos orientados para o funcionamento em rede, são eles:

• Um servidor HTTP com suporte para ASP e extensões ISAPI


• Uma versão minimal do Internet Explorer (o browser da Microsoft) com suporte para Javascript
• Um servidor de Telnet

2.4.6 Ferramentas de desenvolvimento

Existem bastantes ferramentas de desenvolvimento disponíveis, quer da Microsoft, quer de terceiros e até
aplicações já feitas para diagnosticar problemas em tempo de compilação e execução que são fornecidas por
empresas ou por entusiastas (algumas são comerciais). O desempenho da aplicação disponibilizada pela
Microsoft para construção de imagens do Windows CE é aceitável, embora por vezes tenha paragens ines-
peradas e tenha de ser reinstalado, nomeadamente, se a comunicação com a máquina alvo for interrompida

17
enquanto o IDE estiver ligado. O desenvolvimento para Windows CE é também facilitado pela integração total
com o muito conhecido e adoptado Visual Studio. Este produto é actualmente uma aposta dos fabricantes
de hardware, que desenvolvem componentes para integrar o Visual Studio com tarefas de desenvolvimento
específicas dos seus produtos.

2.4.7 Aplicações

O Windows CE tem claramente uma vantagem sob todos os seus concorrentes nesta área. Uma vez que
o windows CE possui parte da API disponibilizada pelo Windows para PC, a grande maioria das aplicações
correrá no Windows CE sem mudanças. Para tornar este elo entre plataformas ainda mais forte, a Microsoft
disponibiliza também uma versão compacta da sua framework .Net e que possibilita a compatibilidade com
aplicações desenvolvidas naquela linguagem.

2.4.8 Metodologia de desenvolvimento

A Microsoft preocupou-se claramente em fornecer ferramentas adequadas à programação nos dois níveis do
Windows CE: núcleo e aplicações. Estas ferramentas são, respectivamente, o Platform Builder e o Visual
Studio que com a ajuda das Embedded Visual Tools se torna num IDE ideal para simular e testar uma
aplicação.

2.5 Linux

2.5.1 Instalação e configuração

O Linux é sistema operativo da família Unix gratuito e de código aberto. Para testes, foi escolhida uma
distribuição conhecida: o Debian Linux, que pode ser configurada para utilizar o núcleo vanilla 1 . A instalação
do Debian é fácil e rápida e tem vindo a ser muito simplificada ao longo do tempo, em parte devido ao
nascimento de uma grande comunidade (Ubuntu) que, apesar de muito nova face ao Debian, tem sido a
responsável pelo aumento quase desmedido da comunidade de utilizadores Linux, tanto em desktops, como
em servidores, o que trouxe como consequência, um aumento da maturidade desta distribuição. A grande
variedade de periféricos é suportada sem qualquer dificuldade devido à crescente qualidade das rotinas
de instalação, detecção e (auto) configuração de hardware pelo instalador. No entanto, a liberdade é total
para utilizadores avançados, pois existe sempre uma linha de comandos disponível à distância de duas
teclas. Cerca de noventa por cento do sistema é configurado out-of-the-box. Esta percentagem inclui o
ajuste automático das taxas de refrescamento e resolução do ecrã e eventuais ligações de rede (local e/ou
Internet). Este sistema, no entanto, é de âmbito geral, na medida em que a distribuição em causa pode
ser utilizada para todos os fins que se queiram (os principais são servidor, ou desktop de uso diário). No
contexto deste documento, é feita uma análise dos utilitários existentes para configuração, desenvolvimento
e instalação num sistema embebido, tendo em conta que, face a outras soluções comerciais analisadas, não
existe propriamente um nível de integração de ferramentas bem definido.
1
O termo inglês vanilla é usado para designar algo que é disponibilizado sem sofrer alterações. No caso do núcleo do Linux, a
distribuição vanilla designa a versão como esta se encontra no repositório de código, sem alterações feitas pelos distribuidores.

18
2.5.2 Gestão de tarefas

O Linux possui um escalonador de classe assimptótica O(1). Este escalonador possui muitas funcionalidades
implementadas:

• Filas pré-ordenadas
• Filas por processador
• Reentrante
• Com preempção em modo núcleo e modo utilizador
• Quatro classes de escalonamento:
• Normal (prioridades dinâmicas)
• FIFO
• Round robin
• Batch

As time-slices do escalonador não são possíveis de alterar em tempo de execução. O núcleo do Linux
suporta SMP sem perda de quaisquer funcionalidades, ao contrário do que acontece nos sistemas de tempo
real analisados. Desde a versão 2.6, foram integrados no Linux componentes que lhe dão características de
um sistema operativo de tempo real. As versões de RTLinux para o Linux 2.6 tiram partido destas caracterís-
ticas, requerendo assim menos esforço de integração. Assim, o suporte para tempo real na versão vanilla do
núcleo do Linux é considerado parcial, o que é uma vantagem muito grande face aos sistemas concorrentes,
quer de tempo real ou não.

2.5.3 Gestão de memória

O Linux suporta até 64GB de RAM em arquitecturas de 32bit (apesar de continuar a existir a limitação de
2GB visíveis por processo) e mais de 1024GB em arquitecturas de 64 bits. O tamanho de cada página é
ajustável em tempo de compilação.

2.5.4 Gestão de interrupções

Neste campo o Linux tem claramente uma vantagem sobre os sistemas analisados pois suporta um conjunto
enorme de gestão de interrupções, nomeadamente:

• SoftIRQs (geração e manuseamento de IRQs por software)


• Tasklets (ver anexo A.6)
• Bottom Halves (ver anexo A.6)
• Task Queues[Wil03]
• Temporizadores

2.5.5 Suporte de rede

O suporte de rede é uma das maiores virtudes do Linux pois para além de suportar quase todos os proto-
colos de rede conhecidos, fá-lo de uma maneira considerada segura (isto apesar de ser um sistema aberto)

19
dado o seu uso intensivo em servidores de rede. É principalmente esta característica, aliada a ciclos de
desenvolvimento curtos das versões do núcleo e também à rápida correcção de bugs reportados, que faz
com que o mercado dos servidores esteja a voltar-se cada vez mais exclusivamente para o Linux, com o
mercado dos sistemas embebidos a seguir o mesmo caminho.

2.5.6 Ferramentas de desenvolvimento

Todo o universo de ferramentas de desenvolvimento GNU.

2.5.7 Aplicações

O número de aplicações disponíveis para Linux rivaliza com a quantidade disponível para windows CE, be-
neficiando da participação de muitos projectos de código aberto. Desde clientes de protocolos conhecidos
até servidores (http, ftp, ssh, entre outros), passando por ambientes desktop completos e activamente de-
senvolvidos por comunidades open source, torna-se quase um desafio encontrar um protocolo ou aplicação
que não possua uma implementação de código aberto para Linux.

2.5.8 Metodologia de desenvolvimento

No Linux, poderão ser seguidas ambas as metodologias de desenvolvimento (o sistema anfitrião pode ou não
ser igual ao sitema alvo). Apesar de ser um sistema aberto, possui uma comunidade enorme de utilizadores
e de chamados kernel hackers que normalmente providenciam esclarecimentos e ajuda quando requisitados.
Um dos objectivos do Linux é ser independente da plataforma onde corre. Este objectivo levou a que fosse
definido um conjunto relativamente pequeno e simples de passos para conseguir portar o núcleo para outras
arquitecturas. Esta característica faz com que seja muito utilizado para sistemas embebidos, havendo alguns
autores que o definem como dominante a médio e longo prazo[Yag03][DPB00]. A quantidade e diversidade
enorme de ferramentas trazem vantagens e desvantagens. As vantagens são a liberdade de escolha e
flexibilidade global do processo de desenvolvimento. As desvantagens são a descentralização do processo,
que tem como consequência o difícil diagnóstico de problemas e ainda a falta de uma metodologia definida
para cada caso.

2.6 RTLinux

Uma vez que o núcleo Linux não possui comportamento de tempo real, surgiram várias soluções que lhe
fornecem estas características. Uma destas soluções é o RTLinux que consiste num conjunto de patches
que podem ser aplicados a um kernel vanilla do Linux, obtendo um núcleo dividido logicamente numa parte
de tempo real e noutra não tempo real. Estes patches utilizam uma abordagem inédita até ao seu apa-
recimento, em 1999, que consiste em conservar todo o código do kernel do Linux, mas corrê-lo como um
processo normal do ponto de vista de um micro-núcleo de tempo real. Este micro-núcleo novo (o RTLinux) é
responsável por todos os processos que necessitem de comportamento em tempo real, agulhando o controlo
dos processos e tarefas que não necessitem de comportamento em tempo real para um processo especial

20
que é o kernel “antigo” e que possui baixa prioridade. Esta funcionalidade pode ser inserida ou removida
num núcleo em tempo de execução, pois pode ser compilada como módulo, semelhante a um controlador de
um periférico.

2.6.1 Instalação e configuração

A instalação e configuração consiste apenas no descarregamento, descompressão e compilação dos módu-


los associados ao RTLinux e ainda ao código fonte do Linux kernel. O grau de dificuldade deste processo
é o mesmo para a configuração e compilação de um kernel vanilla. Este conjunto de patches é uma das
alternativas para conseguir obter comportamento de tempo real a partir do Linux. Existem outras que não
são abordadas neste documento, quer por quebrarem a especificação Posix, quer por serem comerciais. O
RTLinux analisado é o RTLinux Free, que é grátis e de código aberto.

2.6.2 Gestão de tarefas

Apesar do RTLinux seguir um modelo de duplo-núcleo, a existência de um micro-núcleo de tempo real é


transparente do ponto de vista das aplicações, excepto o conhecimento de que existem mais ciclos de re-
lógio gastos pelo núcleo durante a comutação de processos. Mesmo assim, esta abordagem possui vários
pontos negativos: As tarefas que correm no núcleo de tempo real não beneficiam da protecção de memória
madura, testada e robusta do núcleo do Linux vanilla. Estas tarefas correm sempre em modo supervisor,
comprometendo muitas vezes a fiabilidade expectável de um sistema de tempo real. Cada processo que
precise de correr no micro-núcleo deixa de ser um processo normal de Linux, passando a ser uma tarefa
com rotinas de serviço a interrupções. Para complicar este método, a criação deste tipo de tarefas é base-
ada num sub conjunto da norma Posix, o que torna a migração de aplicações existentes para o micro-núcleo
de tempo real uma tarefa difícil na maior parte dos casos.

2.6.3 Gestão de memória

As tarefas que correm dentro do núcleo de tempo real correm em modo supervisor, tendo acesso directo a
qualquer recurso. Estas tarefas nunca são swapped out e como correm dentro do espaço de endereçamento
no micro-núcleo, há uma redução drástica nos TLB misses.

2.6.4 Gestão de interrupções

As interrupções possuem uma flag associada que indica se são ou não para ser tratadas por uma tarefa que
corre dentro do núcleo de tempo real. Todas as outras são redireccionadas para o núcleo vanilla.

2.6.5 Suporte de rede

O suporte de rede e periféricos é o mesmo do núcleo de Linux, no entanto, estes controladores não têm
comportamento de tempo real. Para aumentar a fiabilidade, o programador terá de voltar a implementar
todos os recursos de que necessitar se quiser obter um sistema com a fiabilidade característica de um

21
sistema de tempo real. Existem, de facto, muitas ferramentas disponíveis para correrem no núcleo normal
do Linux, no entanto, todas estas ferramentas e módulos correrão na parte não tempo real do núcleo.

2.6.6 Ferramentas de desenvolvimento

Todas as do Linux.

2.6.7 Aplicações

Todas as do Linux.

2.6.8 Metodologia de desenvolvimento

Semelhante à do Linux.

2.7 uClinux

O uClinux foi inicialmente um porte do Linux da altura (2.0.33) para processadores sem MMU. O núcleo
do Linux, desenvolvido inicialmente para o processador 80386 da Intel, foi concebido de raiz para trabalhar
com memória virtual paginada, o que impossibilitava o seu uso em processadores que não possuíssem
MMU. A ausência deste componente implica que a memória disponível no sistema se apresente como um
bloco contínuo, cuja gestão terá que ser feita completamente por software. Assim, o núcleo do uClinux
possui implementados mecanismos que permitem a execução de código recolocável nestas arquitecturas,
bem como o conceito de página, para assim permitir a reutilização de código existente no núcleo vanilla.
No entanto, apesar de internamente se continuarem a usar páginas (lógicas) para contabilizar a memória
utilizada e facilitar a portabilidade, o código de alocação e libertação de memória foi adaptado para trabalhar
directamente com o espaço de endereçamento da memória do sistema em vez de utilizar a MMU. Para
além do código específico a cada processador desta classe (sem MMU) que foi necessário escrever para
implementar as tarefas do núcleo não portáveis, para que os programas existentes pudessem ser utilizados
sem grandes modificações foi necessário rescrever também parte das bibliotecas de C, dando origem à
chamada uClibC, um componente essencial da distribuição uClinux. Uma das diferenças fulcrais da uClibC
em relação à libC convencional é a implementação das rotinas de alocação de memória, como explicado na
secção 2.7.3. Apesar de ser um projecto separado, o nível de maturidade de desenvolvimento e as inovações
implementadas até à verão 2.4 levaram a que, na actual versão 2.6, muito do código tivesse sido incluído na
versão vanilla do Linux kernel, fazendo com que ambas as versões partilhem actualmente a maior parte das
funcionalidades.

2.7.1 Instalação e configuração

Actualmente, o uClinux é também um conjunto de patches que podem ser aplicados à versão vanilla do
Linux kernel. O pacote disponível para descarregamento inclui um kit completo de desenvolvimento, incluindo
ferramentas de compilação e depuração do uClinux na máquina alvo, bem como um conjunto de programas

22
já portados para a uClibc. Este processo é bastante moroso e difícil. Não só terá o utilizador de possuir
um anfitrião com as ferramentas de compilação e instalação necessárias (é necessário compilar todas as
ferramentas que serão usadas na máquina alvo) como terá também de possuir um conhecimento bastante
técnico e actualizado do núcleo do Linux.

2.7.2 Gestão de tarefas

O mesmo que o Linux.

2.7.3 Gestão de memória

O facto de poder funcionar sem suportar o uso de MMU traz bastantes diferenças ao modelo de gestão
de memória no Linux, que foi desenhada tendo em conta a existência, embora a um nível abstraído da
implementação específica de cada arquitectura, desta funcionalidade de cada processador. Muitos dos pro-
cessadores utilizados actualmente em sistemas embebidos não possuem MMU, pelo que foram portados
bastantes processadores para o uClinux, ARM e Motorola incluídos. Apesar de não existir gestão de memó-
ria e, consequentemente, a primitiva fork não estar implementada, existe a primitiva vfork, que faz com que
o processo pai fique bloqueado até que o processo filho faça exec ou exit (ver secção 2.7.7). O tamanho
do stack de cada programa é fixo e definido em tempo de compilação. Alocações de memória dinâmicas
são possíveis utilizando o malloc-simple ou malloc2. Ambos servem para alocar memória, com a diferença
de que o malloc-simple aloca apenas blocos que são potências de dois e o malloc2 aloca sucessivamente
blocos de 4KB. A memória do sistema é contabilizada pelo núcleo através da implementação de uma pool,
onde blocos são marcados como livres ou usados. A tradução de endereços é feita internamente pelo núcleo,
simulando por software, parte das tarefas de uma MMU.

2.7.4 Gestão de interrupções

O kernel do uClinux suporta os mesmos mecanismos que o do Linux vanilla, com algumas limitações ineren-
tes à arquitectura usada.

2.7.5 Suporte de rede

Tal como o Linux, o uClinux possui implementações seguras dos protocolos ipv4, v6, TCP, UDP entre outros.
Existem ainda aplicações já portadas para uClinux, nomeadamente servidores e cliente web (ftp, http, dhcp
etc), que já vêm incluídas no pacote da distribuição.

2.7.6 Ferramentas de desenvolvimento

Todas as disponíveis para Linux.

23
2.7.7 Aplicações

Está disponível apenas um subconjunto das aplicações disponíveis para Linux, devido a incompatibilidades
com a biblioteca de C utilizada. Numa abordagem simplista, portar programas para esta arquitectura requer
apenas algumas modificações menores no código, substituindo as chamadas à função malloc por uma das
implementações alternativas (malloc2 ou malloc-simple) e ainda substituir as chamadas à função fork pela
função vfork. Muitas vezes, estas duas modificações têm implicações drásticas no desempenho da aplica-
ção e tornam impossível, ou inviável, o seu funcionamento no uClinux. No caso das alocações de memória,
mesmo utilizando o mais eficiente malloc2, a fragmentação de memória no sistema torna-se um problema
para aplicações que aloquem e libertem constantemente pequenos blocos. Isto deve-se ao facto de que, a
partir de certo ponto, poderá não ser possível alocar um bloco com o tamanho mínimo configurado (normal-
mente 4KB), apesar de, no total, poder existir memória livre suficiente, embora esteja fragmentada. Quando
à substituição do fork pelo vfork, estas duas funções permitem a um processo pai criar um processo filho,
estando a diferença ao nível do comportamento do processo pai após a chamada àquela função. No caso do
fork, o processo pai continua a sua execução, o que não acontece na chamada ao vfork, que obriga o pro-
cesso pai a ficar bloqueado. Após esta substituição, o processo filho deverá chamar a chamada de sistema
exec com o seu próprio ficheiro para desbloquear e o pai e continuar a sua execução. Esta sequência de
chamadas (vfork - exec) é necessária devido à implementação actual do mecanismo de paginação de memó-
ria virtual do uClinux, que adia a cópia de páginas para o último momento, em que se torna indispensável a
existência de duas cópias separadas. Na operação fork, o núcleo do Linux apenas incrementa o contador de
uso da(s) página(s) da MMU para aquele processo, pedindo e duplicando novas páginas apenas quando são
feitas operações de escrita numa delas. Na ausência da MMU, este mecanismo de Copy-On-Write (COW)
é impossível de implementar e a solução é despoletar sempre a cópia das páginas do processo, o que é
conseguido pela chamada ao exec, que também têm a função secundária de desbloquear o processo pai,
simulando assim um fork sem Copy-On-Write.

2.7.8 Metodologia de desenvolvimento

Semelhante à do Linux, embora com as limitações impostas pela uCibc.

2.8 Inferno

Inicialmente concebido para suportar serviços distribuídos, tal como a sua ascendência ao Plan 9, o projecto
de onde derivou, este sistema operativo pertence à família de “sucessores Unix”, uma nova vaga de sistemas
operativos que levam as ideias e objectivos iniciais do Unix ao extremo. Algumas destas ideias são:

• Todos os recursos do sistema são ficheiros identificados inequivocamente no sistema de ficheiros


• Existe um espaço de nomes coerente que possui uma estrutura hierárquica tal como um sistema de
ficheiros
• Todos os recursos, locais e remotos, comunicam utilizando o mesmo protocolo (no Inferno OS denomi-
nado Styx)

24
O InfernoOS pode correr em modo anfitrião num conjunto de sistemas operativos (Windows 2000, Win-
dows XP, Irix, Linux, Mas OS X, FreeBSD etc), ou pode correr nativamente em várias arquitecturas supor-
tadas (x86, XScale, PowerPC, ARM, SPARC). As aplicações para este sistema operativo são escritas numa
linguagem com uma sintaxe parecida com a da linguagem C chamada Limbo. Esta linguagem possui uma
representação binária que é mantida nas diferentes plataformas, um pouco à semelhança do bytecode Java,
e é executada utilizando a técnica de jit (just-in-time compilation) tal como numa máquina virtual. O núcleo
do Inferno OS, apesar de correr sempre em modo supervisor, providencia protecção de memória ao nível da
máquina virtual. Uma imagem do Inferno OS necessita apenas de 1 MB de memória ram e vem com várias
ferramentas de desenvolvimento, nomeadamente:

• Acme IDE: compiladores, shell, comandos Unix e depurador gráfico


• Bibliotecas Limbo para acesso à rede, GUI, algoritmos de segurança
• Código fonte e aplicações de exemplo
• Browser com suporte para Javascript
• Compilador de C

O autor considera que este sistema operativo é um candidato a ser utilizado em sistemas embebidos
devido à sua natureza “pós unix” em que existe apenas a noção de recurso e ao facto de funcionar como
uma máquina virtual. Este facto, só por si, resolveria um dos maiores problemas de hoje em dia nos sistemas
embebidos (por exemplo nos telemóveis) que é a compatibilidade das aplicações entre modelos diferentes.

2.9 eCos

O eCos (embeddable, configurable operating system) é um sistema operativo de código aberto e de tempo
real concebido de raiz para sistemas embebidos ou para aplicações que necessitem de apenas um processo
com múltiplas tarefas em execução. Este sistema operativo pode ser usado em hardware que não possua
as características para correr uma versão do Linux. Este hardware normalmente possui memória na ordem
das dezenas ou centenas de KB, ou então necessita do comportamento tempo real que o uClinux ainda
não pode oferecer. As plataformas suportadas são bastantes (ARM, Hitachi, H8, Motorola 68000. MIPS,
PowerPC, SPARC, SuperH etc). Uma das aplicações chave do eCos é o RedBoot que tira partido do me-
canismo de abstracção de hardware do eCos para providenciar um mecanismo de bootstrap para sistemas
embebidos. Neste processo de bootstrap, podem ser descarregadas via porta série ou ethernet aplicações
ou ainda imagens do Linux. Esta aplicação possui ainda uma interface por linha de comandos que pode ser
útil para controlar/reiniciar as aplicações que foram descarregadas. Embora minimal, o eCos é altamente
configurável[Mas04], podendo ser adaptado às mais variadas configurações de hardware. O seu núcleo é
de tempo real e suporta interrupções, vários algoritmos de escalonamento , processos e tarefas, primitivas
de sincronização, temporizadores, e várias implementações para o método de alocação de memória. Para
além destas características, a API do eCos é compatível com a norma Posix. Suporta ainda um enorme
conjunto de hardware, mais do que seria de esperar para um sistema operativo tão minimal, como por exem-
plo dispositivos USB e alguns watchdogs. Possui ainda completamente implementado o protocolo TCP/IP.
A metodologia de desenvolvimento é semelhante à do Linux, sendo o mesmo conjunto de ferramentas GNU

25
aplicáveis também ao desenvolvimento de controladores ou aplicações para este sistema operativo embe-
bido.

2.10 Contiki

O Contiki é um sistema operativo de código aberto especialmente desenhado para ser usado em hardware
com poucos recursos de memória, nomeadamente, uma série de máquinas de 8 bits (por exemplo, o Com-
modore 64) e alguns microcontroladores. Possui um núcleo monolítico com multi-tarefa, um biblioteca gráfica
suficiente para desenvolver GUIs e ainda uma implementação do protocolo TCP/IP. Para correr com estas
características, este sistema operativo necessita apenas de 30 KB de ram. O núcleo do Contiki é conduzido
por eventos, através dos quais o modelo de tarefas convencional foi desenvolvido. É suportada a preempção,
configurável por processo, comunicação entre processos através de mensagens (por eventos)[AD07] e, tal
como foi dito acima, está ainda disponível uma interface gráfica que pode ser usada em terminais que este-
jam ligados ou em displays virtuais tais como o VNC. Uma característica notável deste sistema operativo é o
rasto de memória utilizado que pode ser, no limite, na ordem das dezenas de bytes[AD07].

2.11 Symbian OS

O Symbian OS é um sistema operativo de código fechado concebido exclusivamente para soluções móveis
cujo ciclo de vida tenha um carácter permanente (meses ou até anos). Tal como muitos dos sistemas ope-
rativos conhecidos do domínio dos desktops, o Symbian OS é um sistema multi-tarefa com preempção, com
processos, tarefas e protecção de memória[Haa08]. O Symbian OS introduziu alguns conceitos novos no seu
desenho, nomeadamente descritores de recursos e uma operação de cleanup stack, bem como um conjunto
de outras técnicas com o objectivo de consumir o mínimo de memória possível e assim evitar fugas. Outro
dos conceitos inovadores são os Active Objects. Estes Objectos Activos permitem ligar aplicações a eventos,
podendo ser também vistos como um modo de escalonamento cooperativo. Destinam-se a aplicações que
passem a maior parte do seu tempo à espera de eventos que possam ocorrer no sistema embebido (premir
uma tecla, por exemplo). Através dos Active Objects, o escalonador do núcleo tem conhecimento do compor-
tamento destas tarefas e trata-as de uma maneira especial, permitindo optimizar tempos de resposta para
outras aplicações e ainda o consumo de energia, podendo até desligar o processador quando não existirem
aplicações a tratar eventos. Este mecanismo segue uma abordagem diferente de outros sistemas operati-
vos analisados pois permite que sejam as aplicações a controlarem, de forma indirecta, mas explícita, os
recursos do sistema[Haa08]. A linguagem de programação principal é uma versão específica para Symbian
da linguagem C++, embora existam compiladores para outra linguagens tais como Python, Visual Basic e
algumas variantes de Java. O Symbian OS compete directamente com o Windows CE, competição esta
que inclui semelhanças com o modelo de negócio, em que há uma relação muito próxima entre o desen-
volvimento do sistema operativo e o desenvolvimento do hardware. Apesar de suportar Bluetooth, IrDA e
USB, a arquitectura do Symbian OS é bastante flexível, na medida em que novos protocolos de comunica-
ção ou componentes podem ser adicionados como plugins para os subsistemas já existentes no Symbian.
No núcleo, existem também implementadas primitivas para desenhar e gerir os recursos consumidos pela

26
interface gráfica disponibilizada, para além de um servidor de fontes e de janelas. Existem também imple-
mentadas, embora a nível aplicacional, bibliotecas com as funcionalidades características de dispositivos
móveis, tais como calendário, agenda, lista de contactos, lista de tarefas entre outros. Apesar de ter a maior
quota de mercado dos sistemas operativos móveis, uma das maiores falhas apontadas ao Symbian é a
crescente complexidade do sistema operativo em geral, em parte pelo crescimento desmesurado do número
de classes e funções existentes, fruto das necessidades dos fabricantes de hardware que sejam parceiros
do Symbian[Hri05]. Apesar de ser um sistema operativo comercial, existe uma falta de documentação que,
aliada à dimensão do sistema, faz com que o desenvolvimento para este sistema operativo seja um pro-
cesso cada vez mais tortuoso. O Symbian corre apenas em processadores ARM, o que lhe confere uma
flexibilidade limitada, pois crê-se que o facto de não ter sido pensado tendo em conta a portabilidade, tenha
influenciado negativamente o desenho do sistema[Hri05].

2.12 Tabelas de síntese comparativa

As tabelas abaixo resumem a análise qualitativa feita às soluções analisadas. A classificação atribuída é um
valor entre 1 e 5, sendo o valor 1 muito fraco, sinónimo de pouca maturidade de desenvolvimento e/ou com
erros reportados presentes nas distribuições analisadas. O valor 5 é a classificação máxima e é atribuído
quando o parâmetro em causa não possui erros reportados, tem um grande número de funcionalidades
implementadas, está testado e instalado em ambientes reais (de produção).

Tabela 2.1: Soluções comerciais analisadas

QNX VxWorks WinCE Symbian


Instalação e Configuração 4 4 5 3
Gestão de Tarefas 4 5 3 4
Gestão de Memória 4 5 2 3
Gestão de Interrupções 5 5 1 4
Suporte de Rede 5 5 3 4
Ferramentas de Desenvolvimento 4 4 5 4
Aplicações 2 2 5 4
Média 4 4.2 3.4 3.7

2.13 Conclusão

A escolha de um sistema operativo tem um papel vital do campo dos sistemas embebidos. Um factor impor-
tante a ter em conta no porte de um sistema embebido é que, tal como foi exemplificado, a escolha do sistema
operativo que vai ser usado em determinado sistema embebido vem depois da escolha do hardware, o que
elimina logo à partida uma série de opções para as quais um eventual porte será incomportável em termos
de custo e de tempo. Alternativamente, nos casos para os quais a arquitectura não está definida à partida,

27
Tabela 2.2: Soluções grátis analisadas

Linux RTLinux uClinux Inferno eCos Contiki


Instalação e Configuração 2 2 2 2 1 1
Gestão de Tarefas 5 3 4 4 3 3
Gestão de Memória 5 4 3 4 3 4
Gestão de Interrupções 5 3 4 4 4 3
Suporte de Rede 5 2 4 3 3 2
Ferramentas de Desenvolvimento 5 5 5 2 1 1
Aplicações 5 5 3 2 2 2
Média 4.5 3.4 3.5 3 2.4 2.2

terá de ser encontrado um equilíbrio entre o custo do hardware adequado à natureza das tarefas a executar
e o seu grau de compatibilidade com o sistema operativo a ser usado, incluindo custos associados ao de-
senvolvimento de controladores para periféricos não suportados. O facto de os desenhadores de hardware
trabalharem isolados dos desenhadores dos drivers ou até dos próprios sistemas operativos é extremamente
prejudicial e leva normalmente a enormes problemas de compatibilidade[JCKH05]. Uma característica ex-
clusiva dos sistemas operativos em sistemas embebidos é o seu carácter ad eternum, ou seja, uma vez feita
a sua introdução no mercado, não poderão ser efectuadas correcções de uma maneira transparente para o
utilizador e/ou sem custos elevados para o fabricante. O autor conclui que existe, de facto, a necessidade da
existência de uma arquitectura (de software) genérica que devesse cobrir todos os requisitos dos sistemas
embebidos actuais, mas configurável ao ponto de se adaptar a qualquer solução de hardware que se queira.
Todas as soluções analisadas, excepto aquelas que suportam apenas uma arquitectura, tentam caminhar
nesta direcção, quer providenciando suporte directo para um grande número de arquitecturas, quer tornando
o porte para novas arquitecturas relativamente fácil. Neste aspecto, o autor conclui que arquitecturas de
sistemas operativos como a do Inferno OS são, de facto, pioneiras devido ao sistema ter sido desenhado
de raiz segundo padrões robustos, como o paradigma do código (bytecode) semi-compilado independente
da arquitectura e ainda o da existência de um formato único para as mensagens que atravessam os compo-
nentes do sistema. Das soluções de tempo real comerciais analisadas, as principais vantagens são a sua
compatibilidade com normas conhecidas (Posix), o seu carácter multi-plataforma, apesar da lista de proces-
sadores compatíveis não ser tão extensa como a das soluções genéricas, e ainda uma componente que não
existe nas soluções de código aberto: integração total do ambiente de teste e desenvolvimento e o ambiente
que corre na máquina alvo. Todas as soluções analisadas possuem um conjunto de características cujo grau
de eficácia e facilidade com que se obtém convém medir e ponderar antes de se fazer uma escolha, nomea-
damente: a portabilidade, a escalabilidade, capacidade de preempção e multi-tarefa, gestão de interrupções,
gestão de memória e ainda uma API rica em funcionalidades. De todos os sistemas comerciais testados,
aquele que demonstrou melhor desempenho global foi o QNX, por possuir uma arquitectura muito sólida,
para além da existência abundante de boa documentação e da maturidade do sistema operativo a todos os

28
níveis. Dos sistemas operativos de código aberto analisado, aquele que demonstrou melhor desempenho
foi o uClinux, apesar de não possuir documentação à altura da qualidade do seu código, que é bastante
alta (tendo em conta o facto de que este tem vindo a ser integrado no código da distribuição vanilla), nem
um conjunto bem definido e integrado de ferramentas, considera-se que existe uma comunidade de gran-
des proporções que adoptou o uClinux para as soluções embebidas, comunidade esta que inúmeras vezes
presta apoio gratuitamente através de fóruns, mailing lists, IRC etc. No âmbito deste trabalho, de entre os
sistemas operativos analisados, nem todos correriam na placa XTran-3 da Tecmic. Tendo em conta o pro-
cessador utilizado, poder-se-ão descartar o QNX e o Windows Embeded CE, que não suportam a linha de
processadores Coldfire, da Motorola. Dos núcleos Linux analisados, apenas o uClinux suporta a ausência de
MMU e das restantes soluções analisadas, apenas o eCos corre no processador da placa XTran-3. Assim, a
escolha terá de recair sobre uma das três soluções compatíveis: o VxWorks, o uClinux e o eCos. Tal como
foi analisado, o VxWorks é um produto pago e cujo preço está acima da média. Quando ao eCos, após uma
análise à documentação existente, verificou-se que o estado daquele projecto na arquitectura Coldfire é não
funcional, ou seja, o código existe, mas tem problemas por resolver. Actualmente, parte destes problemas
são de compilação, para além de alguns colaboradores do projecto, que é de código aberto, terem reportado
anomalias funcionais que já ocorriam antes deste ter deixado de compilar. Assim, das soluções analisadas
e face ao hardware existente na placa XTran-3, a escolha recai sobre o uClinux que, mesmo sendo o núcleo
do Linux alterado para suportar sistemas sem MMU, é um projecto maduro face a outras soluções existentes,
possuindo um excelente suporte de rede[Yag03], um grande número de mecanismos de controlo, nomeada-
mente primitivas de sincronização, controlo de entradas, saídas e gestão de interrupções, adequados aos
problemas mais comuns que surgem aquando da necessidade suporte para hardware adicional e/ou escrita
de aplicações do utilizador.

29
3 Porte de um sistema embebido para uClinux

3.1 Introdução

Este capítulo resume todo o trabalho prático desenvolvido no porte do sistema embebido XTran-3, a placa
desenvolvida pela Tecmic, para uClinux. O objectivo principal do porte consistiu inicialmente na instalação de
uma imagem uClinux na placa XTran-3 e do seu arranque com sucesso. Uma vez conseguido este objectivo,
foram seleccionados alguns componentes a portar para uClinux: as quatro memórias flash, o controlador
dos leds e ainda o relógio de tempo real presente na placa. Para a entrada em funcionamento destes dis-
positivos no núcleo do uClinux foram necessárias não só alterações à configuração da distribuição, mas
também a escrita dos controladores associados. Foram também implementadas duas aplicações para con-
trolar o relógio e os leds, utilizando os controladores desenvolvidos. Adicionalmente, foi também feita uma
breve análise à implementação dos controladores para as portas série que se encontram fora do processador
e foi ainda adicionado suporte para o watchdog. Ao longo deste capítulo é apresentado o ambiente de build
do uClinux e são enumerados os passos necessários à criação de uma nova configuração dedicada que
guardará todas as opções seleccionadas quer da parte do núcleo, quer de programas e bibliotecas externas
ou de userspace. É também explicado o processo de arranque e detecção de hardware da parte do bootlo-
ader e da parte do núcleo. São ainda apresentados os problemas técnicos mais comuns neste processo e
a maneira como foram superados no âmbito deste trabalho. São ainda detalhadas as implementações dos
controladores dos periféricos não suportados, bem como a sua integração com as várias classes existentes
e com os restantes mecanismos presentes no núcleo. Fora do núcleo, é ainda apresentada a configuração
de aplicações já incluídas na distribuição e são descritos os passos para a inclusão de novas aplicações. Por
fim, são ainda revistas duas aplicações implementadas no âmbito deste trabalho, destinadas a comunicar
com o driver RTC e com o controlador dos LEDs em userspace.

3.2 Ambiente de desenvolvimento

Actualmente, para desenvolver na placa XTran-3, é utilizada a ferramenta CodeWarrior, um ambiente inte-
grado de desenvolvimento em liguagem C, com compilador incluído, especialmente concebido para produzir
código que corre nas placas e processadores da Motorola. A configuração utilizada pela Tecmic utiliza a
porta BDM. Esta porta destina-se a providenciar funcionalidades de depuração, estando ligada directamente
ao processador. É possível, através dela, não só saber informação acerca do estado do processador, in-
cluindo dos vários registos, mas também escrever em posições de memória e nos vários periféricos ligados
a este. O processador alvo, como é o caso do Coldfire 5282 presente na placa XTran-3, tem de possuir
suporte para este tipo de ligação, para permitir a invocação de comandos de depuração e saber executar
instruções em modo background. Inicialmente foi utilizada a distribuição Debian Linux, instalada numa má-
quina dedicada, para desenvolver e testar a distribuição de uClinux, mas tornou-se necessário recorrer a
uma máquina Windows com o CodeWarrior instalado. Esta necessidade deveu-se ao mau funcionamento
da versão do CodeWarrior para Linux. A instalação desta versão é difícil e obscura por causa do sistema
de licenças usado. Apesar desta dificuldade, mesmo após a instalação dos drivers para Linux do conector

31
BDM (P&E USB Coldfire Multilink) usado, a aplicação nunca detectou com sucesso aquele conector, apesar
de várias tentativas e configurações usadas. Com a vulgarização do uso dos sistemas operativos baseados
em Linux, bem como de software de virtualização de hardware, foi escolhida uma distribuição mais fácil de
configurar e usar: o Ubuntu Linux e foi usada uma versão gratuita do programa VMWare Workstation. Assim,
o ambiente de desenvolvimento consistiu num pc a correr Windows XP, os controladores do conector BDM e
o CodeWarrior e ainda o VMWare Workstation. No VMWare Workstation, foi instalado o Kubuntu Linux com
os pacotes adicionais build essencial (que contém as ferramentas de compilação usadas), ainda as ferra-
mentas da motorola para uClinux, as bibliotecas do ncurses (necessárias para a configuração do uClinux) e
ainda as bibliotecas da zlib (necessárias para a compilação de alguns componentes do uClinux). Foi ainda
necessário um cabo série (RS232) para ligação da placa XTran-3 ao PC permitindo assim ver a consola ou
terminal e interagir com o sistema alvo através da linha de comandos. O programa usado no windows para
este efeito foi o TeraTerm, que, na opinião do autor, é bastante melhor e mais configurável que a alternativa
actualmente usada na Tecmic (HiperTerminal), apesar de também ser uma questão de gosto e hábitos de
utilização.

3.3 Sistema de configuração uClinux

A distribuição do uClinux está disponível para descarregamento em http://www.uclinux.org, não tem custos e
vem sob a forma de um ficheiro comprimido que possui todo o código e sistema de configuração necessário
para criar uma imagem. No entanto, não existe compilador integrado, pelo que a máquina usada para desen-
volvimento deverá possuir um compilador de C (no âmbito deste trabalho foi usado o gcc 4.1.3) e o pacote de
ferramentas de compilação para o processador que se encontra na máquina alvo. O processador existente
na placa XTran-3 é o Motorola ColdFire 5282, por isso foram instaladas as ferramentas de compilação da
motorola.
Uma vez que este trabalho incide sobre o problema de porte de um sistema embebido já existente, o
primeiro passo a realizar será enumerar os componentes indispensáveis ao arranque e execução do uClinux,
bem como as particularidades destes na placa alvo. Para o caso da placa XTran-3, estes componentes são
o processador, a memória RAM para onde será copiada a imagem e ainda a porta série da consola, a porta
0 do processador 5282, necessária para obter feedback textual do sistema. Tal como presente na figura 1.1,
estes são os componentes mínimos para definir um sistema embebido no âmbito deste trabalho.
Após a descompressão, a configuração da distribuição pode ser feita de duas maneiras diferentes a nível
de interface, mas iguais em termos de processo:

$ cd uClinux-dist
uClinux-dist $ make menuconfig

Este comando irá compilar o sistema de configuração e irá usar as bibliotecas (que terão de existir na má-
quina de desenvolvimento) ncurses, que permitem assim efectuar todo o processo de configuração mesmo
em modo texto. Alternativamente, poderá ser usado o comando make xconfig que correrá o mesmo sis-
tema de configuração mas em modo gráfico recorrendo às bibliotecas Tcl/tk, que terão de ser instaladas na
máquina de desenvolvimento.

32
O sistema de configuração da distribuição uClinux está dividido em três fases, como demonstrado na
figura 3.1:

Configuração da distribuição Onde é escolhido o fornecedor do hardware, o processador a usar, a versão


do núcleo a usar (2.0, 2.2, 2.4 ou 2.6), a versão da uClibc a usar e, adicionalmente, que passos
adicionais queremos ter na configuração (configuração do núcleo e/ou das aplicações).
Configuração do núcleo Onde é configurado o núcleo propriamente dito.
Configuração das aplicações Onde são configuradas as aplicações de userspace a incluir na imagem.

Uma vez que a placa XTran-3 é semelhante à placa de EVB5282, da Freescale, foi seleccionado inicial-
mente o vendor Freescale e a placa EVB5282. A versão do núcleo a usar é a 2.6 por ser a mais recente
e com mais funcionalidades disponíveis (as outras estão disponíveis por uma questão de compatibilidade
com clientes mais antigos que ainda estejam “presos” a essas versões) e enriquecimento da distribuição. Foi
criada uma configuração personalisada para a placa a portar. Para isso, foi criado um novo vendor Tecmic
e ainda um novo produto, a placa XTran-3. No fim do desenvolvimento, a configuração usada foi guardada
com os valores e opções mais recentes. Isto faz com que, independentemente das alterações à configura-
ção, a selecção original poderá ser restaurada ao seleccionar aquele fabricante e o respectivo produto. A
criação desta configuração resume-se à alteração do conteúdo da directoria vendors. Eis o conteúdo desta
directoria:

Tecmic
XTran-3
Makefile
config.arch
config.linux-2.6.x
config-uClibc
config-vendor
config-vendor-2.6.x
romfs_contents
big
inittab
rc
httpd
boa.conf
index.html
romfs
etc
config
config
options
start
lib

33
Figura 3.1: Sistema de configuração do uClinux, primeiro ecrã.

fstab
inetd.conf
motd
services

A estrutura acima descrita foi criada para acomodar a nova configuração. A única restrição reside na
existência de uma Makefile com um conjunto de alvos pré-determinados, todos os outros nomes de ficheiros
são convenções de um sistema de ficheiros Linux. Estes alvos (all, romfs e image) serão invocados pela
Makefile de nível superior que reside na directoria vendors para efectuar um deploy, recriar os conteúdos
do sistema de ficheiros e criar a imagem completa (núcleo e userspace) para posterior instalação na placa
XTran-3. É de referir que as entradas no /dev, ou seja, os nós dos vários periféricos, são criados pela
Makefile, incluindo o major e minor number associado. Todos os ficheiros começados por config destinam-
se a guardar configuração e são gerados automaticamente pelo sistema de configuração do uClinux. Na
directoria romfs_contents encontram-se alguns ficheiros de configuração que são fixos e nunca variam, tendo
sido escritos de raiz. Estes ficheiros possuem as mesmas funções que os seus homónimos num sistema não
embebido Linux ou mesmo Unix e apenas contém as opções de inicialização dos daemons que irão correr
após o arranque, dos mount points existentes no sistema de ficheiros e respectivos periféricos associados e
ainda dos módulos a carregar pelo sistema.

3.4 Configuração do núcleo

A configuração do núcleo é um processo complexo e moroso, com uma curva de aprendizagem bastante
acentuada. O sistema de configuração do uClinux possui a tecla ? que perite visualizar um pequeno texto

34
de ajuda para a opção seleccionada e que pode ajudar a esclarecer algumas dúvidas sobre cada uma das
funcionalidades.

Na figura 3.2 é apresentada uma visão geral sobre as secções disponíveis para configuração. É um
facto que, para alguns conjuntos de opções, a processo de compilação falha sem razão aparente (como
acontece actualmente quando se seleciona o suporte para o watchdog do processador MCF5282), daí que
alguma intervenção será necessária, corringindo eventuais ficheiros (normalmente falta apenas a inclusão
dos cabeçalhos respectivos), ou, no limite, alterando o código problemático. Esta é uma prática bastante
avançada e é desencorajada numa fase inicial de adaptação a este ambiente de desenvolvimento. Para uma
configuração inicial correcta, a filosofia a tomar é seleccionar apenas as opções estritamente necessárias,
quer do núcleo quer de userspace, para obter uma imagem minimamente funcional. Existem opções cujo
texto de ajuda indica o procedimento em caso de dúvida.

Numa versão inicial da imagem criada, foram retiradas todas as funcionalidades do núcleo, excepto aque-
las necessárias ao processo de arranque. A primeira versão que efectivamente arrancou com sucesso pouco
mais fazia do que imprimir o motd. No entanto, esta abordagem permitiu depurar o que estava a acontecer
com as imagens que nunca botavam. Um passo essencial foi seleccionar o controlador correcto da porta
série do processador. Sem este periférico a funcionar, não existia maneira de saber o que estava a aconte-
cer ao sistema, independentemente das outras opções seleccionadas. O controlador em causa é o ColdFire
Serial Port e situa-se no caminho Device Drivers/ Character Devices/ Serial Drivers/ Motorola ColdFire Se-
rial Port da figura 3.2. Os comandos de inicialização da porta poderão ser dados automaticamente pelo
núcleo, através de uma sintaxe própria. Este comando, que se insere no caminho Kernel Hacking / Com-
piled In Boot Parameter, possui uma sintaxe especial que permite configurar várias opções usando apenas
uma string. Cada par parâmetro=valor é separado por espaços (não podem haver espaços nem no nome
do parâmetro, nem no seu valor), os nomes e sintaxe dos parâmetros encontram-se descritos em uClinux-
dist/linux-2.6.x/Documentation/kernel-parameters.txt.

Outro passo essencial da configuração, reside na configuração do ecrã Processor Type and Features.
Aqui é configurado o local (endereço físico acessível directamente pelo processador), onde se encontra a
zona de memória dedicada ao armazenamento dos vectores do sistema e a zona a partir da qual se vai
realizar o arranque. Para que estes endereços sejam válidos, os chip selects do controlador de SDRAM do
processador terão de ser configurados previamente. No caso da placa XTran-3, a imagem foi configurada
para ter a seguinte configuração presente na figura 3.3

A partir daqui, ter-se-á o núcleo compilado, embora ainda sem programas ou uma shell. No entanto, tal
como foi mencionado no parágrafo anterior, existe um conjunto de componentes de hardware que precisa
de ser inicializado ainda antes do arranque do Linux. A maneira como esta inicialização é conseguida, é
explicada nas secção 3.5.1.

3.5 Detecção de hardware

Esta secção descreve o processo de arranque do uClinux, desde o bootloader, que contém o código que é
executado quando o sistema é ligado, até à inicialização do núcleo do Linux propriamente dita. Na figura 3.4

35
Figura 3.2: Mapa da configuração do núcleo do uClinux.

36
Figura 3.3: Mapa de memória da imagem do uClinux na Ram da placa XTran-3.

é apresentada uma representação simplificada do hardware a detectar na placa XTran-3.

3.5.1 Arranque

Actualmente, o código do Linux, por si só, é incapaz de arrancar. Existe um conjunto de recursos que deverá
ser inicializado para que o código do núcleo consiga pelo menos aceder a si próprio através do espaço de
endereçamento atribuído à memória onde este se encontra (configurado numa das opções mencionadas
na secção 3.4. Quem inicializa estes recursos é o bootloader, que se encarrega de executar instruções
de baixo nível, presentes no manual de cada periférico. O processador ColdFire 5282 possui 512 KB de
memória (flash) interna, mais do que suficientes para armazenar um programa de inicialização. O bootloader
utilizado neste trabalho é um programa previamente desenvolvido pela Tecmic, denominado XTran3-Test,
que possui implementadas todas as funcionalidades de comunicação com o hardware. No entanto, apesar
da API disponível ser bastante rica, durante o porte para uClinux faltaram funcionalidades que tiveram de
ser implementadas para que a imagem fosse efectivamente colocada na memória e para que o código fosse
executado uma vez transferido. Uma dessas funcionalidades foi a capacidade de receber ficheiros no formato
SREC pela porta série e de escrever os dados transferidos para a memória. O formato SREC foi concebido
especificamente para transferências de dados e, sumariamente, é constituído por pares endereço-dados
iniciados pelo caracter S a ser escritos na memória de destino. O formato contempla ainda um carácter
de checksum que permite verificar se o que foi escrito para a memória foi efectivamente o que foi transmitido.
Outra das funcionalidades que foi implementada foi a capacidade do processador saltar para um endereço
especificado pelo utilizador. Esta última funcionalidade é necessária pois, dada a natureza da arquitectura
presente na placa XTran-3, o núcleo do Linux pode ficar em qualquer zona do espaço de endereçamento,
bastando ao processador saltar para a primeira instrução para iniciar o processo de arranque do uClinux.
Assim, a ordem de acontecimentos para realizar a operação de deploy neste sistema embebido é:

1. Transferir a imagem do bootloader para a memória interna do processador via BDM (esta operação só
tem de ser feita uma única vez pois a memória interna do processador não é volátil).
2. Arrancar o bootloader.
3. Converter o ficheiro binário contendo a imagem criada para o formato SREC.
4. Transferir o ficheiro SREC via porta série.
5. Iniciar a execução do código do uClinux

Os componentes que têm de ser inicializados pelo bootloader são: o processador, a porta série, os
chipselects das memórias a utilizar (para que estas fiquem endereçadas numa zona do espaço de endereça-

37
Figura 3.4: Hardware a detectar na placa XTran-3

mento conhecida pelo núcleo) e o controlador de interrupções. Existem ainda componentes que não deverão
ser inicializados pelo bootloader, a fim de deixar o seu controlo e inicialização para o núcleo do Linux. Um
destes componentes é o watchdog que a placa XTran-3 possui e que, caso seja activado no arranque do
bootloader, irá certamente forçar um reset ao processador aquando no arranque do Linux, já que um dos
primeiros passos do código do núcleo é “tomar conta” de todas as interrupções do sistema, reajustando os
endereços das rotinas de atendimento à interrupção para as suas próprias rotinas. Isto despoleta o me-
canismo de reset do watchdog, pois a rotina associada à notificção deste deixa de ser executada, tendo o
mesmo efeito que um eventual crash do sistema. Todos estes detalhes de implementação foram concreti-
zados ao longo da execução do trabalho. Surgiram bastantes problemas com a velocidade de transferência
utilizando a porta série devido aprentemente à ineficácia do controlo de fluxo por hardware da porta série
utilizada. Numa fase posterior do desenvolvimento, veio a ser utilizada a porta BDM (que já estava a ser
utilizada para colocar a imagem do bootloader na memória interna do processador) para, através dela, se
colocar a imagem do uClinux na RAM do sistema, o que reduziu o tempo médio de deploy de quarenta
e cinco, para apenas três minutos, provocando um aumento de produtividade significativo. Para que esta
transferência seja possível via BDM, é necessário inicializar o processador em modo debug, correndo pos-
teriormente o código assembly necessário para que a memória RAM possa ser endereçada e escrita pelo
processador. Após esta inicialização, é utilizada a funcionalidade do CodeWarrior de carregamento de um
ficheiro binário para um endereço especificado. No fim desta transferência, a placa XTran-3 é inicializada
com o firmware da Tecmic. No menu inicial, foi implementada uma funcionalidade extra que permite saltar
para o código da imagem transferida. Dada a natureza da arquitectura, esta mudança abrupta de sistema
operativo pode ser feita apenas mudando o valor do registo PC (program counter) do processador:

asm_jmp_to_address :
_asm_jmp_to_address :

38
move . l 4 ( sp ) , a0
addq . l #8 , sp
jmp ( a0 )
_asm_jmp_to_address_end :

Numa fase posterior de desenvolvimento, a interface BDM passou a ser utilizada apenas para fazer ape-
nas o primeiro deploy da imagem. Durante o desenvolvimento dos módulos dos controladores, os módulos
a testar eram compilados na máquina de desenvolvimento e passaram a ser transferidos via porta série di-
rectamente para sistema de ficheiros do uClinux, a correr na placa XTran-3, utilizando o protocolo Zmodem.
Uma vez que o chipethernet não está montado na placa XTran-3 utilizada, a porta série teve que ser utilizada.
O protocolo Zmodem é um protocolo de transferênca de ficheiros baseado no conceito de sliding window,
que consiste na ordenação e envio de sequências de pacotes (que constituem partes do ficheiro a transmitir)
e de flags associadas que simbolizam o estado da transferência de cada pacote. O número de pacotes a
enviar sem receber informação de recepção determina o tamanho da janela a utilizar. O receptor e o emissor
têm que possuir uma implementação deste protocolo. O emissor, neste caso o programa TeraTerm, possui
a funcionalidade de enviar ou receber um ficheiro via protocolo Zmodem e o receptor, o uClinux a correr na
placa XTran-3, possui instalados os programas lrz e lsz que permitem enviar e receber, respectivamente,
transferências utilizando também aquele protocolo. Os módulos recebidos são colocados no núcleo do uCli-
nux em tempo de execução através do comando insmod e retirados através do comando rmmod. Só em
caso de um crash, ou kernel panic, é que terá de ser novamente utilizada a interface BDM para transferir
novamente toda a imagem para memória.

3.5.2 Controladores de memória

A operação de inicialização dos controladores de memória é feita também pelo bootloader. Para algumas
placas suportadas directamente pelo núcleo, estes controladores poderão ter que ser inicializados aquando
do arranque. Como não é o caso no ColdFire 5282, a memória RAM foi simplesmente usada, sem precisar
sequer de ser detectada.

3.5.3 Partições

Como descrito no anexo A.7, o sistema de ficheiros virtual do Linux terá a função de tornar disponível ao
núcleo a partição do disco (neste caso, da RAM) onde está a estrutura de ficheiros criada automaticamente
pelo processo de configuração. Isto é feito a partir do driver de RAMDISK, que permite mapear regiões da
memória RAM para partições tipicamente associadas a discos rígidos. No entanto, no caso da configuração
elaborada na secção 3.4, é necessário adicionar um parâmetro adicional ao núcleo, pelo método descrito
nessa mesma secção. Este parâmetro indica ao subsistema VFS qual o periférico do tipo bloco associado à
partição de root, ou seja, à partição principal do sistema de ficheiros do Linux, conhecida por / . Mesmo nos
sistemas Linux não embebidos, este parâmetro é obrigatório. No caso da placa XTran-3, cada ram disk é
controlado por um driver MTD (memory technology device), que lhe associa um periférico do tipo bloco. Este
periférico é especificado no parâmetro de boot e terá os conteúdos do sistema de ficheiros.

39
3.6 Controladores

Nesta secção são descritas as decisões de implementação tomadas para implementar os controladores de
alguns periféricos da placa XTran-3.

3.6.1 Memórias flash

A placa XTran-3 possui quatro módulos de memória flash do tipo NOR, disponíveis a partir do seu espaço de
endereçamento. Este tipo de memórias tem uma implementação especial no núcleo do Linux[Woo99], como
ilustrado na figura 3.5.
Na camada inferior, mais próxima do hardware, existem dois protocolos de comunicação: Jedec e CFI.
Estes protocolos implementam um standard para invocar operações de escrita e leitura de blocos das me-
mórias flash e, no caso do CFI, o mais recente dos dois, é possível determinar dados sobre a topologia da
memória. Uma memória flash do tipo NOR difere de uma memória normal na medida em que é constituída
por blocos. O tamanho dos blocos é normalmente fixo dentro de um certo intervalo da memória. Fora desse
intervalo, no princípio ou no fim, existem os boot blocks, mais pequenos que os outros, destinados a isolar e
armazenar partes vitais (de boot, por exemplo) de software do sistema. O modelo utilizado na placa XTran-3
é o M29W160DB do fabricante ST. Após uma análise à datasheet daquela memória, conclui-se que o boot
block se encontra no início do endereçamento e que o tamanho dos blocos é de 0x10000 bits, ou seja, 64KB,
exceptuando o primeiro que está dividido em blocos mais pequenos com 16, 8, 8 e 32 KB. Várias tentativas
de detecção automática via CFI foram feitas, com multiplas configurações, no entanto, a configuração final
que ficou a funcionar usa apenas o código Jedec para fazer a correcta detecção e inicialização de hardware
e um CFI command set da AMD, para escritas e leituras, que funciona correctamente para alguns chips
da ST. Teve de ser desenvolvido um patch ao ficheiro jedec_probe.c, que na versão do uClinux usada nem
sequer compilava. Neste patch, foi declarado mais um membro ao enum uaddr e ainda acrescentado mais
um membro à estrutura unlock_addr. O enum apenas aglomera as várias sequências de comandos de des-
bloqueamento dos blocos da flash (que estão bloqueados após o boot) e a estrutura modificada contém os
comandos de desbloqueamento dos blocos. Estes problemas de compilação não foram provocados pelo au-
tor, mas tiveram que ser corrigidos pois caso contrário todo o código Jedec não poderia ser utilizado. O patch
foi submetido para a mailing list do uClinux.
Na camada seguinte, a de mapeamento, inicialmente foi utilizado o módulo physmap. Este modulo per-
mite associar uma memória flash mapeada no espaço de endereçamento do sistema a dois nós criados no
sistema de ficheiros para controlar o chip: um do tipo carácter, que recebe comandos, e um do tipo bloco, que
recebe ou envia os dados lidos ou a ser escritos na memória. Actualmente, apesar da configuração deste
módulo ser flexível ao ponto de ser possível ter mapeamentos relativamente complicados, por exemplo, não
contínuos entrelaçados com outros dispositivos, apenas permite mapear com sucesso um único chip. Uma
vez que existem quatro chips e de modo a permitir usar apenas alguns deles em tempo de execução, foram
escritos quatro módulos de mapeamento, um para cada chip detectado, que podem ser inseridos ou remo-
vidos no núcleo a qualquer altura, activando ou desactivando o funcionamento de cada chip. Cada módulo
possui três parâmetros de configuração: o início do endereçamento, o tamanho do endereçamento e o tama-

40
Figura 3.5: Implementação dos periféricos do tipo MTD

nho do barramento de endereços da memória. Durante a fase de probe, cada módulo informa o núcleo de
que o intervalo de memória associado através da configuração lhe pertence e é da sua exclusiva responsabi-
lidade. Além desta operação, são ainda detectados os chips MTD, o que neste caso será feito apenas com o
código Jedec. Adicionalmente, são ainda suportadas partições e, caso exista informação sobre as partições
(passada através do parâmetro de boot), esta é lida e são criados os minor numbers para cada partição. Na
fase de remoção de um destes módulos, o espaço de endereçamento ocupado fica novamente sem dono e
disponível para qualquer outro módulo pedir para si. Os recursos do periférico físico associado são também
eles libertados do núcleo. Esta desagregação de recursos em tempo de execução só é efectuada se os con-
troladores forem compilados como módulos. Caso sejam compilados em modo compiled in, ficarão a fazer
parte do núcleo e nunca são desagregados ou libertados os recursos que alocarem. Uma possível configura-
ção de partições para um destes módulos seria passada da seguinte maneira no parâmetro de inicialização
do núcleo:

xt3map-flash1.0:1024k(flash0),512k(flash1),512k(flash2)

Aquando da inserção do módulo, o chip da ST seria detectado e a zona de memória era então atribuída ao
mesmo. Ainda durante a fase de inserção do módulo, aquela string seria lida, pois o nome do módulo xt3map-
flash1 coincide com o especificado no módulo, bem como o número do device, neste caso o 0 (o primeiro).
São então criados três nós com o mesmo major number mas com minor numbers intervalados entre si, um
para cada partição encontrada (flash0, flash1 e flash2). Posteriormente, cada uma destas partições poderá
ser montada com um sistema de ficheiros apropriado, o que irá ser oportunamente explicado.

Apesar de, com o driver de mapeamento carregado, os nós dos periféricos ficarem disponíveis para
escrita byte a byte, para poder ler e escrever ficheiros e directórios comuns a um sistema de ficheiros terá

41
que ser usada a uma camada lógica que permita a um utilizador abstrair-se da existência de blocos, da
topologia dos mesmos e até do facto de estar a escrever para uma memória flash.

Actualmente, esta camada pode ser definida de duas maneiras distintas: com o componente FTL ou com
um sistema de ficheiros que suporte lidar directamente com os pares de nós carácter e bloco de cada chip.
Inicialmente, o objectivo principal do porte era usar o sistema de ficheiros FAT na flash. Apesar de ser possí-
vel, é fortemente desaconselhado pois aquele sistema de ficheiros não foi desenhado para memórias flash.
Este facto deve-se, como foi dito acima, ao facto de cada chippossuir topologias diferentes e, para além disso,
cada bloco ter um número limite de vezes que pode ser rescrito, pelo que fica usado, ou wared out, ficando
inutilizado a partir daí. Um sistema de ficheiros óptimo para estes chips terá que usar os blocos de maneira
a efectuar o mesmo número de escritas em cada um destes, para assim retardar o efeito de ware out. O
sistema de ficheiros FAT, tal como o nome indica, possui uma zona especial chamada file allocation table que
consiste numa representação em árvore da estrutura hierárquica dos directórios e ficheiros existentes e dos
blocos que ocupam. Esta zona é escrita muito mais vezes do que qualquer outra zona do periférico, daí que,
numa memória flash, estes blocos ficariam usados muito mais rapidamente. Nos discos rígidos ou noutros
periféricos que saibam lidar internamente (por hardware) com blocos que eventualmente tenham ficado inuti-
lizáveis e consigam distribuir a carga das escritas igualmente por cada um destes, é possível usar o sistema
de ficheiros FAT directamente, ou até qualquer outro que tenha sido desenhado para block devices. Exem-
plos destes periféricos são, por exemplo, as chamadas pen drives, que apesar de internamente serem flash,
possuem uma implementação por hardware de uma FTL (Flash translation layer) que se encarrega de distri-
buir as escritas e marcar blocos como inutilizados, mostrando-se perante o sistema operativo como um block
device normal, como um disco rígido. No Linux, existe uma implementação de uma FTL, por software, que
faz com que um par de nós do tipo carácter e bloco, associados a uma memória flash, possam aparecer
como um block device e passe a suportar escritas normais, como se se tratasse de um disco rígido. Esta
implementação é pouco usada pelos motivos descritos acima e está no código do kernel como prova de
conceito. Apesar de vários utilizadores desta camada tenham reportado sucesso com a versão 2.4, existem
problemas graves com a versão 2.6, que normalmente resultam num kernel panic seguido de paragem do
sistema, que impediram o seu uso neste trabalho.

Em vez de ser usada uma camada lógica, como a FTL, pode também ser usado um sistema de fichei-
ros que suporte escritas e leituras para o chipdirectamente, expondo ele próprio as rotinas necessárias à
implementação de um sistema de ficheiros (integração com o VFS do núcleo). Um exemplo deste sistema
de ficheiros é o JFFS, Journaled Flash File System, que faz exactamente o que afirma ser: guarda um jour-
nal com os blocos que já foram usados, apenas escreve nos que foram usados menos vezes e providencia
integração com o sistema de ficheiros virtual do núcleo. Na placa XTran-3 foi usado o JFFS2 pois possui com-
pressão automática (e transparente para o utilizador) e ainda um garbage collector melhorado em relação à
primeira versão. Nestes sistemas de ficheiros é normal a existência de um garbage collector que é executado
em threads separadas do núcleo e que percorre os blocos usados marcando-os como lixo e ainda, caso seja
necessário, mova o seu conteúdo para outros blocos para evitar fragmentação e maximizar o espaço livre
existente. Assim, um utilizador apenas tem que saber o nó do tipo bloco associado ao chip flash para poder
dar o comando mount, com a switch apropriada, e assim criar um sistema de ficheiros jffs2 numa flash pre-

42
viamente apagada (com o comando eraseall, por exemplo). Ao associar um mount point à partição montada
usando aquele comando, é então possível escrever e ler ficheiros para dentro da flash, como se se estivesse
a mover ou a criar ficheiros numa directoria normal. Na criação de um ficheiro, por exemplo, um utilizador
do sistema poderia fazer simplesmente touch nomedoficheiro.txt dentro do mount point correspondente. A
partir daqui, o programa touch irá fazer uma chamada de sistema que corresponde à criação de um ficheiro.
O núcleo atende aquela chamada de sistema, agulhando a chamada para a função do sistema de ficheiros
(JFFS2) correspondente. O JFFS2 encontra os endereços dos blocos que vai escrever, de acordo com a
informação do seu journal e invoca os comandos no nó do tipo carácter associado àquele chip, colocando
em seguida os dados no nó do tipo bloco. Aí, o módulo de mapeamento desenvolvido, neste caso o xt3map-
flash1, intercepta a escrita naqueles nós e agulha para o endereçamento físico respectivo, chamando as
funções de escrita, ou leitura, do nível físico. O nível físico, por sua vez, irá invocar os comandos CFI, nome-
adamente o conjunto de comandos da AMD denominado 0002, de maneira a executar todas as operações
envolvidas directamente no hardware.

3.6.2 Relógio de tempo real

O controlador do relógio de tempo real Dallas ds2404 foi o primeiro controlador a ser escrito pelo autor na
placa XTran-3. Após uma análise inicial, verificou-se que apesar de existirem controladores já implementa-
dos para vários periféricos da Dallas, incluindo um driver genérico para periféricos daquela marca ligados
apenas por um pino (Dallas 1-Wire Bus), não existia ainda nenhum controlador compatível com o periférico
a portar, nem sequer para o protocolo de comunicação que este utiliza, denominado 3-Wire Bus. O con-
trolador para este periférico foi integrado na classe RTC e a comunicação com o periférico foi conseguida
implementando parte do protocolo 3-Wire utilizando a interface GPIO do processador M5282. No entanto,
algumas funcionalidades não puderam ser implementadas, pois, por motivos técnicos, algumas das saídas
do chipRTC usado (Dallas 2404) não estão ligadas ao processador, nomeadamente, o pino de IRQ e o pino
onde são gerados impulsos a 1Hz, comum nos periféricos deste tipo. Assim, apenas tiveram de ser portadas
as funções de ajuste e leitura do valor do relógio e ainda de leitura e escrita do alarme. A comunicação com
esta classe de periféricos pode ser feita através da função ioctl, que remonta aos tempos do Unix[Tan93],
utilizando identificadores e estruturas de dados conhecidos à partida pelo núcleo e estipulados desde o
aparecimento da classe RTC. Também é possível invocar as funções de escrita e leitura directamente, co-
nhecendo de antemão a classe RTC, apesar de ser arriscado em termos de compatibilidade com futuras
versões do núcleo.
O relógio de tempo real DS2404 possui uma memória divida em páginas onde são guardadas as infor-
mações do seu estado, incluindo o valor actual do contador de tempo e o valor actual do alarme, que são
os valores que interessam para o controlador a escrever. Existem 16 páginas e cada página possui 256 bits
de memória não volátil. No entanto, quer o alarme, quer a hora actual encontram-se apenas numa das
páginas, com o endereço 0x0200h. Estas páginas de memória não podem ser lidas nem escritas directa-
mente, tendo que ser antes copiadas, total ou parcialmente, para uma memória temporária de 256 bits, não
volátil, chamada scratch buffer. Existem três comandos principais que este periférico aceita, e que, sendo
parametrizáveis, permitem realizar todas as operações para controlar o relógio e o alarme, são elas:

43
• Cópia de uma página de memória para o scratch buffer
• Cópia do scratch buffer para a memória
• Leitura do scratch buffer

Quando se invoca a cópia entre o scratch buffer e a memória ou vice-versa, é sempre necessário fornecer
o endereço de origem (dentro da página) e também a quantidade de bytes a ser escritos. Cada valor de
horas, da hora actual e do alarme, é constituído por 4 bytes que representam o hora Posix actual (número de
segundos que decorreram desde o dia 1 de Janeiro de 1970). Tal como foi dito acima, estes bytes são lidos
ou escritos no scratch buffer, sendo, no caso das escritas, dada a ordem de cópia para a devida secção da
página 0x0200, consoante se trate de uma escrita no alarme ou na hora actual. Todas estes dados contendo
as várias instruções a executar e os dados a inserir têm que ser enviados por uma ordem pré-definida pelo
protocolo de comunicação com o relógio (ver tabela de instruções possíveis no anexo B.1).
Graças à integração com a classe RTC existente no núcleo, foi possível reutilizar algumas funções de
conversão de tempo Posix para as estruturas de tempo existentes no núcleo do Linux. Foi ainda aproveitado
código já existente no núcleo para expor toda a informação sobre um periférico que pertença à classe RTC
num ficheiro existente no pseudo sistema de ficheiros /proc. Este mount point é denominado um pseudo
sistema de ficheiros pois não está ligado a nenhum periférico de armazenamento e é especial pois os fi-
cheiros que o compõem são frequentemente utilizados como pontos de leitura de informação dos vários
controladores que a pretendam disponibilizar. Assim, com o controlador implementado, basta abrir o ficheiro
/proc/drivers/rtc para ter acesso ao estado do relógio, pois serão invocadas as funções de leitura e do alarme
e da hora actual. O núcleo do Linux foi configurado também para usar o nó deste RTC como o relógio do
sistema. Isto faz com que, durante o arranque, a data do sistema seja ajustada de acordo com o valor actual
do RTC da Dallas. No entanto, após esta operação ter sido feita, ambos os relógios não ficam ligados perma-
nentemente, pois o núcleo conta o tempo pelos ciclos de relógio do processador. É possível definir também
uma opção para, na operação de encerramento do Linux, o RTC da Dallas ser sincronizado com relógio do
sistema, à semelhança do que acontece numa instalação típica de um pc. Eis um exemplo de interação com
esta interface:

# cat /proc/driver/rtc
rtc_time : 20:28:05
rtc_date : 2005-02-18
alrm_time : 17:10:47
alrm_date : 1973-10-08
alrm_wakeup : no
alrm_pending : no
24hr : yes
id : 0
#

Os utilitários normalmente utilizados para lidar com periféricos do tipo RTC, como o date e o hwclock
podem também ser usados graças ao controlador implementado, pois este foi devidamente integrado no
núcleo, nomeadamente com as operações da classe RTC, que é o que aquelas aplicações de userspace

44
estão à espera de encontrar.

3.6.3 Porta série não standard

A placa XTran-3 possui dois chips da Philips cuja função é providenciar quatro e oito portas série respec-
tivamente. Uma vez que estes componentes ainda não possuem nenhum controlador implementado, será
necessário desenhar uma solução para a sua entrada em funcionamento no uClinux. Apesar da solução não
ter sido implementada, são descritas algumas notas que terão de constar no desenho final:

• Uma das portas tem ligado a si o pino de impulsos gerados pelo RTC com a frequência de 1Hz. A
motivação técnica na base desta implementação reside no facto de este ser o único mecanismo eficaz
(dadas as limitações existentes quando foi implementado) de contabilizar periodicamente, sem falhas,
os dados do tacógrafo. Do ponto de vista do núcleo, a rotina de atendimento à interrupção terá de,
ao receber uma interrupção da porta série, averiguar se é uma interrupção periódica ou se se trata de
uma recepção normal de dados da porta série. Após esta verificação, caso seja uma entrada da porta
série, esta é tratada normalmente pelas funções da classe serial existente no núcleo para designar as
portas série. Caso seja uma interrupção vinda do RTC, poderão ser usadas três soluções:
– A interrupção é descartada. O mecanismo síncrono associado ao tacógrado será tratado por
um relógio de alta resolução. Estes relógios de alta resolução são o resultado do núcleo do
Linux estar a adquirir características de sistemas de tempo real, mais concretamente, alguns
mecanismos presentes na distribuição RTLinux estão agora embebidos no núcleo do Linux.
– A interrupção é atendida logo na rotina top half, ou alternativamente, na rotina de bottom half (ver
anexo A.6).
– A interrupção é descartada e é gerada uma interrupção de software que será apanhada por
um daemon de user space com prioridade elevada.
• Ambas as portas têm registos partilhados por todas as portas série, o que faz com que sejam ne-
cessários mecanismos de controlo de concorrência, como mencionado no anexo A.4, para assegurar
coerência entre leituras e escritas concorrentes.

Qualquer uma destas abordagens pode ser seguida, no entanto, dada a natureza destes periféricos, teriam
de ser efectuados testes com as diferentes velocidades de transferência e/ou diferentes níveis de carga do
sistema, e os resultados das escritas do tacógrafo teriam de ser verificados e comparados com os resultados
actuais, caso estes se considerem aceitáveis.

3.6.4 Watchdog

Actualmente, o suporte para o watchdog do processador ColdFire 5282 deveria ser suportado, mas foi ve-
rificado que não compila na distribuição de uClinux usada. Este facto deve-se à junção recente, a nível de
código do núcleo, de duas arquitecturas parecidas: o MCF5282 e o MCF5272, que originou o aparecimento
de um problema de compilação deste controlador (faltam directivas #define). No entanto, este problema está
diagnosticado e já foi corrigido através de um patch ao sistema de configuração, apesar de ainda não ter
entrado para a distribuição actual do uClinux.

45
3.6.5 Leds

Outro dos periféricos portado foi um conjunto de 13 leds. Destes 13 leds, presentes no painel de expansão
da placa XTran-3, um deles é controlado directamente pelo processador, ao contrário dos outros 12. Os
outros 12 dividem-se em dois grupos, um com 8 e outro com 4 leds, estando cada elemento de cada grupo
ligado a um de dois controladores I2C. Estes controladores I2C, modelo PCF8574SO16, são suportados
pelo núcleo do Linux, no entanto, uma vez que estes periféricos não se encontram ligados à interface I2C
presente no processador, não é possível usar esses módulos. Ambos os controladores I2C estão ligados a
um periférico que os controla, estando sim este último ligado ao processador (ver figura 3.4). Este periférico
consiste numa eeprom capaz de controlar outros controladores I2C. Devido à natureza do protocolo I2C,
vários controladores poderão estar ligados em open drain usando os dois fios (dados e relógio). Cada um
destes controladores possui um endereço e um determinado papel numa hierarquia composta por mestres e
escravos. Nesta hierarquia, os mestres controlam a frequência do relógio e atribuem endereços aos escravos.
O protocolo é poderoso o suficiente para contemplar casos em que existam vários mestres ou até que
se comute de mestre. No desenho actual da Tecmic (ver figura 3.4), o controlador da Atmel actua como
mestre, apesar dos endereços dos dois controladores escravos serem forçados por hardware. Assim, para
acender ou apagar cada um dos doze leds que compõem o conjunto, é necessário determinar primeiro qual
o controlador escravo que é necessário actuar. Após este passo, é ainda necessário saber qual o endereço
do led a acender ou apagar. Esta informação terá que ser enviada ao mestre respeitando o protocolo de
escrita na sua eeprom. O desenho do controlador dos leds para o Linux segue uma abordagem pouco
comum neste tipo de periféricos, que é tipicamente controlado acedendo a nós do tipo bloco e enviando
bytes com as acções a desempenhar. Contudo, o autor decidiu implementar uma interface mais amiga da
linha de comandos, baseada em texto e num nó do tipo carácter[JCKH05]. Assim, durante a inicialização
é criado um nó do tipo carácter com um major não assignado, para não colidir com nenhum periférico e
respeitar a convenção de atribuição destes números do núcleo do Linux. Este nó, que no fundo é um ficheiro
normal, pode ser aberto e escrito por uma aplicação normal, ou até várias como será explicado mais à
frente, e aceita uma gramática composta por sequências de número=bit separadas por :. Assim, caso se
queira acender o led número três, terá que ser escrito para o nó a sequência 3=1 . Esta abordagem faz com
que seja possível, apartir da shell, acender e apagar leds, usando comandos incluídos na imagem criada
para a placa XTran-3, por exemplo:

$ echo "3=1:4=1:5=1:10=0" > /dev/xtranleds

Como se pode ver pelo comando acima, o nó foi criado na directoria /dev, que se destina a armazenar nós
de periféricos, e tem o nome oportuno de xtranleds. O comando echo emite uma string para o ecrã, enquanto
que o comando de redirecção > faz com que a escrita seja feita para o argumento seguinte, que é o nome
do ficheiro que representa os leds. Para conseguir que o controlador aceda a um nó e intercepte as escritas
e os dados escritos neste, é necessário fornecer, durante a inicialização, as funções de leitura e escrita do
mesmo, para posterior invocação quando qualquer uma daquelas operações ocorrer. Como é possível ver
pelo código, não existe qualquer restrição que imponha acesso exclusivo ao nó, como é comum nalguns
periféricos[JCKH05]. No entanto, foi usada uma primitiva de sincronização, um spinlock (ver anexo A.4),

46
para restringir acessos em simultâneo à eeprom. A granularidade usada é ao nível da operação de um led
e é o mínimo que se consegue obter, visto que o protocolo de escrita não pode ser interrompido uma vez
iniciado (a trama de bits a enviar, contendo a indicação de início, o endereço e valor a escrever, e a indicação
de fim, não pode ser interrompida, caso contrário o periférico ficará num estado inconsistente). Assim, vários
processos do sistema podem abrir e escrever naquele ficheiro, acendendo ou apagando leds, sem que haja
qualquer corrupção de dados ou perda de informação.

3.6.6 Integração dos controladores no sistema de configuração

Para além dos ficheiros com o código fonte e respectivos cabeçalhos, para a inclusão de código extra no
núcleo do Linux é necessário editar pelo menos o ficheiro de configuração da página de opções onde deverá
figurar o novo módulo ou opção e ainda a Makefile dessa directoria. A edição no primeiro serve para que
o driver possa ser marcado como escolhido e no segundo para que o mesmo possa ser incluindo na fase de
compilação. Este é o caso mais simples, como o do ds2404, em que apenas foi necessário colocar o ficheiro
.c dentro da directoria que estará correcta logicamente (/drivers/rtc), editar o ficheiro Kconfig dessa directoria
e a Makefile. O código acrescentado ao ficheiro Kconfig explica-se a si próprio:

config RTC_DRV_DS2404
tristate "Dallas DS2404"
depends on RTC_CLASS && M528x
help
If you say yes here you get support for the
Dallas DS2404 timekeeping~\textit{chip}.

This driver can also be built as a module. If so, the module


will be called rtc-ds2404.

Foi também acrescentada a seguinte linha à Makefile:

obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o

Apesar desta configuração consistir na edição de ficheiros de texto, é bastante fácil de aprender e pôr
em prática. Este sistema de build surgiu apenas na versão 2.6 do núcleo do Linux. O ecrã de configuração
resultante da configuração alterada pelas linhas acima encontra-se na figura 3.6.

3.7 Aplicações

A configuração de aplicações do uClinux é, sem dúvida, a parte de configuração que precisa de mais
melhoramentos[Nik03]. Apesar de funcionar de maneira semelhante à configuração do núcleo, a verifica-
ção de escolhas dependentes, bem como a existência de vários binários com nome igual em contextos
iguais (referentes a várias variantes desse executável) tornam a obtenção de uma compilação com sucesso
um “feito” bastante difícil e moroso. No entanto, uma vez conseguido, ter-se-á concluído a construção da ima-
gem do uClinux e, se tudo correr como esperado, os binários com os programas já feitos estarão no sistema

47
Figura 3.6: Ecrã de configuração do controlador ds2404

embebido, à espera de serem executados. A configuração conseguida para a placa XTran-3 possui uma shell
semelhante à bash, vários utilitários de depuração e configuração do núcleo, o editor de texto vi e alguns
utilitários que testam o hardware implementado. Foram escritas duas aplicações para esta placa, posterior-
mente compiladas usando a uClibc, cujo desenvolvimento se desenrolou como se se estivesse a programar
para um sistema Linux normal, sem as restrições de um sistema embebido. Estas duas aplicações são:

ds2404help - Utilitário para configurar o RTC DS2404 portado


ledshow - Utilitário para controlar os leds presentes na placa XTran-3

3.7.1 Programa ds2404help

Uma vez que o controlador portado foi incorporado na classe RTC do núcleo do Linux, qualquer programa
existente capaz de controlar um relógio de tempo real para Linux funciona com o periférico portado. Alguns
destes utilitários (compilados e incluídos na imagem final) são o hwclock e o date. O programa date permite
alterar a data de sistema, no entanto uma das funcionalidades do programa hwclock é copiar a data de
sistema para o nó RTC designado e vice versa. No entanto, apesar do conjunto de funcionalidades de
leitura e escrita destes programas, existe ainda uma tarefa do relógio para a qual não foram encontrados
utilitários que a fizessem, que é ajustar o alarme. Os alarmes dos chips RTC, sobretudo num pc, são usados
para programar o sistema para “acordar” na hora descrita, e ligar-se automaticamente. No entanto, nos pcs
esta tarefa é feita exclusivamente pelo controlador de power management, o APM ou ACPI no núcleo do
Linux. Uma vez que num sistema embebido o power management não tem que obedecer a restrições de
arquitectura, como explicado no capítulo 1, foi implementado o utilitário ds2404help que permite ajustar e ler
a hora e o alarme de qualquer RTC para linux, incluindo o deste trabalho. A sintaxe implementada permite
invocar o comando com dois parâmetros opcionais de maneira a indicar se se vai escrever no alarme e/ou na

48
hora actual. Após as funções de leitura destes parâmetros, o ficheiro que representa o RTC é aberto e são
feitas as chamadas via ioctl respectivas. O código do controlador é então executado e o resultado, passado
por referência, é então preenchido com os valores.

3.7.2 Programa ledshow

O porte dos leds para Linux não interage com nenhuma camada conhecida, apenas foi feito utilizando um nó
do tipo carácter normal que pode ser aberto e escrito por várias aplicações ao mesmo tempo. No entanto,
para automatizar a mudança de estado dos vários leds ao longo do tempo, foi escrito o ledshow. Este
programa lê um ficheiro de texto fornecido e muda o estado dos leds de acordo com o especificado. O
formato deste ficheiro de texto foi o que motivou a escrita deste programa, pois o estado de cada led é
representado de uma maneira semelhante à sua distribuição física na placa, o que possibilita ao utilizador
esquecer a numeração de cada led. Entre cada estado, existe ainda um algarismo que indica o valor do
intervalo de tempo, em milisegundos, a aguardar até ler o estado seguinte. No início do ficheiro existe
também um algarismo que indica o número de vezes a repetir a sequência de estados. Cada ficheiro só
pode ter apenas uma sequência. Eis um exemplo de um ficheiro de configuração:

10
000000
000000
40
111111
111111
40
000111
111000
20

Esta animação, ou show, começa com todos os leds apagados durante 4 segundos, depois todos acesos
durante 4 segundos, depois os 3 de cima à direita e os 3 de baixo à esquerda acesos durante 2 segundos.
Esta sequência é repetida 10 vezes.

3.8 Conclusão

Ao portar, embora parcialmente, o uClinux para correr na placa XTran-3, foram descritos os passos relevan-
tes ao porte deste sistema operativo para outras arquitecturas. A configuração do uClinux é bastante flexível,
no entanto, nem todos os casos possíveis são cobertos. Devido a este facto, ocasionalmente poderão surgir
problemas de compilação que irão necessitar de uma análise do erro ocorrido e, no pior caso, terão sempre
desenvolvimento associado. Isto faz com que muitas vezes não se consiga criar a imagem do sistema uClinux
após as primeiras tentativas, sendo necessário procurar correcções disponíveis ou utilizar código da versão
de testes (classificada de não estável) do uClinux, facto que, pelo primeiro impacto negativo que causa,
pode prejudicar a familiaridade com esta distribuição. Por outro lado, o conjunto de ferramentas fornecidas,

49
para além do próprio sistema operativo discutido no capítulo 2, é enorme e abrangente. A implementa-
ção de software proprietária da Tecmic, actualmente instalada nas placas XTran-3, utiliza um mecanismo
de controlo relativamente simples, baseado no conceito de round-robin com interrupções, apresentado na
secção 1.2, com rotinas de atendimento às várias interrupções geradas pelo sistema. Esta complexidade,
impulsionada principalmente pelo número de funcionalidades já implementadas no sistema actual, deverá
ser medida comparativamente ao ganho obtido pelo porte. O autor considera que, dadas as capacidades da
placa XTran-3, o software que a controla actualmente tem grandes limitações apesar de, actualmente, servir
todos os propósitos do negócio associado. Das limitações actuais, destacam-se:

• Incapacidade de realizar tarefas em paralelo, tendo que se esperar por todos os periféricos dentro do
ciclo, excepto para o tratamento de interrupções (limitação inerente à arquitectura de software)
• Qualquer suporte “avançado” terá que ser implementado de raiz (exemplos: stack IPv4 completo, stack
IPv6, IPSec, sistemas de ficheiros (vfat, JFFS), stack USB, entre outros)
• Controladores para periféricos futuros terão de ser escritos (chip ethernet, porta USB)
• Todas as funcionalidades de userspace terão de ser implementadas de raiz (não há compatibilidade
binária com utilitários existentes)

Todas estas limitações ficaram resolvidas com este trabalho, para além dos drivers adicionais e aplica-
ções desenvolvidas. O autor considera que, face às necessidades existentes actualmente, será inevitável
o porte completo do uClinux para a placa XTran-3. Este deverá ser feito, se possível, em paralelo com o
desenvolvimento, caso ainda haja, de eventuais novas funcionalidades para a placa XTran-3.

50
4 Análise de desempenho ao sistema portado
4.1 Introdução

Após todo o desenvolvimento detalhado no capítulo 3, surge agora a necessidade de avaliar a performance
do sistema antes e depois do porte. As medições de performance contidas neste capítulo seguem uma
abordagem mais analítica e têm como base medições obtidas na placa XTran-3.
Face à necessidade de obter medidas relevantes e comparáveis com outras medições de outros siste-
mas que possam ser tomados como referência, é necessária uma ferramenta de testes que permita avaliar
imparcialmente cada um deles. Idealmente, esta ferramenta deverá também poder avaliar o sistema antes
do porte. No caso deste trabalho, como irá ser detalhado ao longo deste capítulo, tal não é possível, surgindo
assim dois grupos de medições diferentes a realizar:

• Medidas de performance face a sistemas semelhantes


• Medidas de performance do sistema antes e depois do porte

Nas secções seguintes, é apresentada uma ferramenta de benchmark utilizada em sistemas Unix e é
detalhada a implementação de um teste de performance, desenvolvido no âmbito deste trabalho, que permite
comparar o sistema antes e depois do porte ao desempenhar uma tarefa comum.

4.2 Ferramenta de análise de desempenho lmbench

Para testar o desempenho do porte realizado, foi utilizada a ferramenta lmbench. Esta ferramenta consiste
num conjunto de testes criado para medir certos aspectos do sistema operativo. Apesar de ser um projecto
de código aberto e ter sido escrito tendo em conta a portabilidade entre sistemas diferentes, não é possí-
vel efectuar a sua compilação na uClibc sem antes efectuar algumas alterações, à semelhança do que foi
descrito no capítulo 2. Foi utilizada, em vez da versão vanilla desta ferramenta de testes, uma versão previa-
mente alterada pela companhia Analog Devices no porte realizado para o processador Blackfin para uClinux.
Este código foi retirado do repositório público do uClinux para Blackfin e incorporado na distribuição usada
no porte da placa XTran-3.
A principal vantagem em usar uma compilação de testes já feita e muito divulgada na comunidade open
source, como o lmbench, consiste na abundância de resultados já disponíveis para vários ambientes dife-
rentes, incluindo alguns que utilizam processadores sem MMU, e que podem ser utilizados para referência
e termo de comparação com o porte efectuado neste trabalho, ou até com futuros desenvolvimentos nesta
placa da Tecmic. Apesar do lmbench possuir uma bateria de testes muito rica e de esta ter sido completa-
mente portada para uClinux (existem testes para desempenho de rede utilizando protocolos como o TCP e
UDP, testes ao sistema de ficheiros, ao sistema de memória virtual, entre outros), foram apenas escolhidos
três testes considerados relevantes no sistema embebido a testar: o lat_proc, o lat_ctx e o lat_syscal.

4.2.1 lat_syscall

Mede o tempo que demora a escrita de um byte no nó /dev/null. Embora simples, o resultado deste teste
deve ser considerado como o limite inferior de tempo que demora uma interacção (chamada de sistema) com

51
o sistema operativo.
A tabela 4.1 apresenta os resultados do teste lat_syscall no sistema portado. Estes resultados poderão
ser úteis para futuras comparações com outros processadores ou com outras versões da distribuição uClinux.

Tabela 4.1: Resultados de execução do teste lat_syscall na placa XTran-3

Modo de execução Tempo em microssegundos


null 8.8924
read 44.5169
write 37.5036

4.2.2 lat_proc

Permite calcular o tempo que o sistema operativo demora a criar e iniciar a execução de um processo. Este
teste foi executado de duas formas diferentes:

vfork + exit É medido o tempo de criação de um novo processo igual ao processo pai
vfork + execve É medido o tempo de criação de um novo processo e início da execução do processo filho

A tabela 4.2 apresenta os resultados do teste lat_proc no sistema portado. Estes resultados poderão ser
úteis para futuras comparações com outros processadores ou com outras versões da distribuição uClinux.

Tabela 4.2: Resultados de execução do teste lat_proc na placa XTran-3

Modo de execução Tempo em microssegundos


fork+exit 968.1667
fork+execve 1338.5

4.2.3 lat_ctx

Este teste mede o tempo entre mudanças de contexto entre um número especificado de processos de com-
plexidade configurável. Durante a execução destes testes, os processos são criados e ligados em anel
utilizando unix pipes. Cada processo lê um token do pipe, realiza algumas instruções (calcula o somatório
de um array), e envia o token para o pipe seguinte. Na invocação deste teste, é especificado o número de
processos, ou seja, o tamanho do anel, e ainda a carga de trabalho que estes realizam antes de passarem o
token ao próximo processo.
Na tabela 4.3 são apresentados os resultados do teste lat_ctx na placa XTran-3. Esta placa possui um
processador Motorola Coldfire, modelo 5282 a 66,6MHz e a versão do núcleo usado nestes testes é a 2.6.19.
Nos testes efectuados, foram feitas variações do parâmetro size, que controla o tamanho do array a calcular
o somatório. O valor ovr, presente nas medições, não é um parâmetro, mas sim um resultado, medido em

52
microssegundos, do tempo gasto em todas as operações do teste que não fazem parte da comutação de
processos.
Para poder comparar medições entre sistemas e assim situar o sistema portado, a nível de performance,
com sistemas embebidos semelhantes, foram retirados, da página do fabricante de outro sistema embebido,
vários valores do teste lat_ctx. Estes testes foram efectuados na placa Samsung S3C24A0 que possui um
processador ARM, modelo 926ej a 200MHz. As versões do núcleo usadas nestes testes são a 2.6.11.6, com
e sem patches uClinux, e ainda uma solução comercial baseada em Linux, da Montavista, que se baseia na
geração antiga do kernel do Linux 2.4.20 (ver tabela 4.4).

Tabela 4.3: Resultados de execução do teste lat_ctx na placa XTran-3

Número de processos Tempo em microssegundos (size=0KB, ovr=209.96)


2 73.48
4 92.84
6 91.40
8 96.50
10 100.53
12 103.87
14 101.71
16 104.84
Número de processos Tempo em microssegundos (size=1KB, ovr=258.70)
2 68.49
4 92.54
6 90.10
8 96.59
10 99.23
12 101.02
14 105.10
16 106.68
Número de processos Tempo em microssegundos (size=16KB, ovr=910.17)
2 67.50
4 94.79
6 100.50
8 108.33
10 103.73
12 108.08
14 104.88
16 107.48

53
Tabela 4.4: Resultados de execução do teste lat_ctx na placa S3C24A0 (valores em microssegundos)

Número de processos uclinux-2.6.11.6 linux-2.6.11.6 linux-2.4.20-mvista


size=0KB ovr=10.30 size=0KB ovr=14.19 size=0KB ovr=9.34
2 6.49 96.15 79.42
4 13.34 99.49 78.45
6 19.15 101.55 83.91
8 21.72 116.1 78.45
10 20.75 111.05 77.36
12 22.02 107.78 83.9
14 23.2 109.22 83.74
16 23.72 105.92 79.03
size=1KB ovr=18.38 size=1KB ovr=19.76 size=1KB ovr=15.38
2 68.91 195.78 196.79
4 125.45 217.87 196.02
6 139.46 204.04 197.2
8 147.54 205.21 196.33
10 150.56 202.95 196.31
12 151.65 208.61 195.73
14 152.41 209.37 196.62
16 153.07 207.43 196.31
size=16KB ovr=139.14 size=16KB ovr=104.56 size=16KB ovr=104.30
2 225.8 302.47 319.19
4 259.76 318.16 319.29
6 269.49 316.56 318.57
8 264.81 316.31 320.11
10 264.4 309.81 321.38
12 261.77 316.04 318.33
14 261.77 316.53 318.14
16 261.85 316.54 318.42

Após uma análise a estas tabelas (4.4 e 4.3), pode dizer-se que o núcleo do Linux vanilla é mais lento
que o uClinux, mesmo em hardware mais rápido, como é o caso da placa da Samsung. Verifica-se que
o tempo de mudança de contexto varia consoante o número de processos e a carga colocada em cada
um, sendo que o uClinux muda de contexto 4.5 vezes mais rápido para 16 processos e 9.7 vezes para
dois processos. Isto deve-se ao facto do mecanismo de memória virtual e do uso de MMU presente no
Linux, como explicado na secção 2.7.3. A versão do kernel utilizada na placa XTran-3 mostra ainda uma
independência entre o overhead imposto pelo parâmetro size e o tempo de mudança de contexto, facto que

54
se justifica pela existência de melhorias ao nível no desempenho do núcleo do Linux na versão utilizada neste
trabalho. Os altos valores de overhead medidos face aos valores presentes no ARM, devem-se à diferença
entre a velocidade dos processadores e da natureza das operações envolvidas (soma de valores de um
vector).

4.3 Testes ao sistema original vs Testes ao sistema portado

Dada a impossibilidade de correr o lmbench no firmware da Tecmic, foi desenvolvido um teste para permitir
avaliar ambos os sistemas de uma maneira comparável. Dada a diferente natureza dos dois sistemas, foi
medido o tempo de transferência de vários bytes via porta série, permitindo assim medir o tempo que estes
demoraram a atender as interrupções. Eis o algoritmo deste teste, aqui apresentado em pseudo-código:

begin
waitForFirstCharacter();
counterStart = getTimeOfDay();
do{
char = receiveChar();
print(char);
} while (char != CHAR_END);
counterEnd = getTimeOfDay();
print("Time spent: %d", counterEnd - counterStart);
end

Na placa XTran-3, este algoritmo foi implementado numa função dedicada, ou seja, uma vez iniciada,
apenas poderá ser interrompida pela execução de chamadas de atendimento à interrupção, retomando-se,
após estas, o fluxo normal deste código.
No uClinux, este algoritmo foi implementado como uma aplicação normal de userspace que lê e escreve
no ecrã utilizando as funções da libc comuns (scanf e printf ).

Tabela 4.5: Resultados de execução do teste à consola série na placa XTran-3 (valores em milissegundos)

300 bytes 900 bytes 3600 bytes


Tempo no uClinux 3.086 8.899 35.106
Tempo no firmware Tecmic 3.333 11.333 45.667

Contrariamente ao que seria de esperar, o sistema portado apresenta um desempenho superior ao sis-
tema à medida, desenvolvido pela Tecmic, para os testes realizados. No caso do firmware da Tecmic, e após
uma análise posterior, conclui-se que esta diferença se justifica pelo tamanho elevado das rotinas de aten-
dimento às interrupções, dado que todo o firmware (à excepção das rotinas de atendimento à interrupção)
corre com a mesma prioridade. Outra das causas desta diferença de tempos é a existência, um pouco por
todo o código do firmware da Tecmic, de ciclos de espera activa, inclusivé dentro de rotinas de atendimento à

55
interrupção. Apesar do firmware da Tecmic ter implementado suporte para mais periféricos do que o sistema
portado, estes periféricos não geraram interrupções durante a execução dos testes.
Verifica-se que, apesar dos resultados obtidos, este teste é injusto para o uClinux pois o código do teste
correu como um processo de utilizador normal o que fez com que o percurso dos dados, desde o núcleo até
ao programa de userspace (ver figura 2.2), fosse dificultado pela existência de camadas lógicas deste sistema
operativo, daí que seriam de esperar piores resultados. Mesmo assim, o uClinux mostrou um desempenho
superior ao firmware da Tecmic nos testes realizados o que demonstra, mais uma vez, a maturidade daquele
projecto e o seu uso crescente nos sistemas embebidos actuais.

4.4 Conclusão

Neste capítulo, foram comparados o desempenho do sistema XTran-3 antes e depois do porte para uCli-
nux. Foram também analisados resultados de benchmarks dos mesmos programas de teste noutro sistema
embebido, que utiliza como processador um membro da família ARM9, muito utilizado em sistemas em-
bebidos [Yag03]. Os testes de referência mostram que o núcleo do uClinux é mais rápido do que o Linux
em mudanças de contexto, facto que pode ser entendido dada a utilização de mecanismos de paginação e
memória virtual, ausentes no uClinux, que suporta apenas um espaço de endereçamento único e global ao
sistema. Nos testes efectuados na placa XTran-3 esta diferença manteve-se, como seria de esperar, o que
demonstra que o uClinux se adequa mais a aplicações embebidas que necessitem de elevado desempenho
na comutação de processos, como é o caso de sistemas embebidos com restrições de tempo real.
O teste comparativo realizado no firmware da Tecmic e no uClinux mostrou, para surpresa do autor,
que o uClinux tem um desempenho superior ao firmware da Tecmic, mesmo utilizando uma típica aplicação
de userspace como benchmark. Este resultado vem reforçar a importância que o porte para um sistema
operativo embebido tem, no âmbito de futuras aplicações deste hardware, já que as vantagens do uso de
um sistema operativo como uClinux permitem não só libertar a placa da arquitectura de software limitada
da infra-estrutura actual, mas também utilizar grande parte dos protocolos e aplicações suportadas, como
descrito na secção 2.7.7.

56
5 Conclusões e trabalho futuro

5.1 Conclusões

Neste trabalho foi analisado o problema do porte de um sistema embebido para o uso da distribuição uCli-
nux, que compreende essencialmente o núcleo do Linux com um conjunto de modificações para suportar
processadores sem MMU e ainda um conjunto de aplicações de código aberto, cujo funcionamento é possí-
vel devido ao uso da biblioteca de C uClibc. A análise foi feita abordando o problema de uma forma genérica,
concretizando posteriormente todos os procedimentos a efectuar para o porte da distribuição uClinux tendo
como hardware de destino a placa XTran-3 da Tecmic.
Apesar do porte daquela distribuição ter sido um objectivo pré-estabelecido no início deste trabalho, o au-
tor efectuou uma análise teórica e prática às soluções existentes para o problema em causa que comprova
que, dada a natureza do hardware da placa bem como os custos envolvidos, a distribuição uClinux será a que
melhor se adequa aos objectivos pretendidos. Nessa análise (ver capítulo 2), foram enumerados e descritos
todos os aspectos e características mais importantes na apreciação de sistemas operativos embebidos, bem
como a sua aplicação para o conjunto de sistemas analisado. O autor concluiu que, para se obter uma no-
ção concreta do grau de portabilidade dos sistemas operativos analisados é necessário pelo menos algum
trabalho de experimentação, que poderá ir desde a simples instalação e configuração na máquina de desen-
volvimento, até à tentativa de execução no sistema embebido em causa. Caso o processador tivesse MMU,
poderia ter sido escolhida uma distribuição do Linux vanilla, semelhante à de um desktop, mas customizada
para a placa XTran-3. Deste modo, para além das vantagens que se ganham em usar o núcleo do Linux (é
uma solução aberta, rica em ferramentas de desenvolvimento, grátis, bem documentada e compatível com
o standard Posix), ganhar-se-iam também todos os benefícios de protecção de memória, desenvolvimento
de aplicações igual ao de um sistema de âmbito geral e reaproveitamento directo (sem serem necessárias
modificações) ao código das aplicações existentes de código aberto. Sem MMU, o uClinux é, de facto, a
solução não comercial mais madura das analisadas no capítulo 2.
Uma vez feita a selecção do sistema operativo a utilizar na operação de porte, este deverá ser analisado
de uma forma mais profunda, de maneira a cobrir todos os aspectos técnicos inerentes ao funcionamento do
mesmo. Dado o carácter limitado e fixo dos recursos existentes num sistema embebido, torna-se necessária
uma análise profunda das práticas comuns para resolução de problemas no sistema operativo a portar, de
maneira a obter uma solução eficiente, tirando o máximo proveito da operação de porte. Verificou-se que
cada sistema operativo adopta um modelo de programação diferente, alguns bastante peculiares como por
exemplo o Inferno Os, daí que a análise técnica detalhada do sistema operativo a portar tenha como função
secundária a confirmação da escolha correcta não só do ponto de vista técnico, mas também do ponto de
vista de negócio, já que a partir daquela análise será possível determinar o esforço de toda a operação de
porte e ainda o grau de compatibilidade dos sistema operativo a portar com o sistema embebido em causa.
Adicionalmente, o autor conclui que em projectos como este, os desenhadores do hardware deverão estar em
contacto permanente com quem realizará o porte, discutindo alternativas e principais problemas encontrados
por ambos nas diferentes fases do projecto. Só assim o resultado final irá corresponder às espectativas de
ambos.

57
Do ponto de vista técnico, o autor pode concluir que existem essencialmente dois graus de dificuldade
diferentes associados à operação de porte: o porte do núcleo e o porte das aplicações. Na implementação
de software utilizada actualmente na placa XTran-3, a fronteira entre o código específico para o hardware
em causa (que terá de ser integrado no núcleo caso existam periféricos não suportados) e o código genérico
das aplicações existentes é bastante ténue, pois o sistema coexiste como um todo fixo, utilizando a arqui-
tectura round-robin com interrupções. Por um lado, existe um conjunto de barreiras técnicas inerentes ao
desenho do núcleo do sistema operativo a portar, nomeadamente paradigmas de programação diferentes e
integração com classes e interfaces pré-definidas para implementação eficiente no núcleo, que irão tornar
explícita a separação entre o que pertence ao âmbito do núcleo e o que pertence ao espaço de utilizador.
Tendo o núcleo a funcionar com todos os periféricos disponíveis, o passo seguinte é portar as aplicações
existentes. No caso da placa XTran-3, este porte não foi feito, no entanto, o autor conclui que, uma vez
que o porte destas aplicações é vital para assegurar as necessidades do negócio, terão de ser feitos testes
exaustivos que permitam comparar ambos os sistemas, antes e depois do porte, de maneira a assegurar a
verosimilhança entre os resultados obtidos nos sistemas antigo e portado.

Após o porte parcial do uClinux para a placa XTran-3 ter sido concluído, e tendo em conta todos os pon-
tos enunciados anteriormente, o autor conclui que, de um ponto de vista de negócio, o porte de um sistema
operativo para um sistema embebido é um problema cuja complexidade da resolução deverá ser sempre
medida previamente, usando como termo de comparação a possível extensibilidade do sistema existente já
implementado. O autor conclui que esta operação é benéfica principalmente se o projecto estiver envolvido
numa comunidade open source, pois quanto mais ricas estas distribuições forem, mais participantes acaba-
rão eventualmente por ser atraídos para o projecto e vice versa, alimentando um grau de participação (que
poderá advir de projectos como este) de milhares utilizadores, tal como o que se observa na comunidade
Linux. Para além disto, os testes realizados no capítulo 5 permitem concluir que não se prevêem impactos
no desempenho do uClinux face à solução implementada actualmente, tendo sido obtidos resultados bas-
tante favoráveis para o uClinux. As métricas utilizadas também permitirão a futuros desenvolvimentos avaliar
o desempenho face a outras potenciais alternativas, que poderão ser estudadas em simultâneo graças ao
suporte de hardware do uClinux e à utilização de ferramentas globalmente utilizadas nestes sistemas.

5.2 Trabalho futuro

Possíveis sequências a este trabalho poderiam ter como objectivo terminar o porte dos periféricos, implemen-
tando assim os controladores das duas portas série que restam e ainda realizando o porte das aplicações
que correm actualmente no XTran-3 para a uClibc. Poderá ainda ser feito um estudo sobre até que ponto
utilizar outro sistema operativo, nomeadamente o QNX, não trará melhores resultados de performance, uma
vez que, dada a natureza das tarefas que a placa XTran-3 desempenha, são necessárias características de
um sistema operativo de tempo real, que poderão ter impactos significativos na performance do sistema fi-
nal. Alternativamente, poderia ser estudada a inclusão de um processador com MMU, o que permitiria o uso
do núcleo do Linux vanilla directamente, bem como todos os utilitários e ferramentas de desenvolvimento
associados. Uma vez que existem vários processadores com MMU disponíveis, destinados a sistemas em-

58
bebidos, esta poderia ser uma oportunidade para se estudar uma mudança de processador. No contexto
dos sistemas embebidos, existem três marcas que competem directamente: MIPS, ARM e Motorola Coldfire,
cada uma com as suas vantagens e desvantagens. Os processadores baseados na arquitectura MIPS pos-
suem o maior rácio de instruções por segundo / custo, enquanto que os ARM são os que consomem menos
energia, sendo também, dos mencionados, os mais utilizados em sistemas embebidos. A família Coldfire
possui a melhor relação fucionalidades / custo e, para a maior parte das aplicações, possui um consumo de
energia comparável ao ARM. Assim, dependendo das aplicações futuras a correr neste produto da Tecmic,
terá de ser ponderada uma escolha. No entanto, dada a compatibilidade entre modelos presente na família
Coldfire, o autor considera que o Motorola Coldfire 5475 é um forte candidato a um modelo futuro do produto
XTran, pois facilita o porte das aplicações actuais da Tecmic, tendo como segurança o facto de ser possível
desabilitar a MMU, para assegurar compatibilidade total com o funcionamento de versões antigas. Do ponto
de vista do Linux, a escolha deste ou de outro processador dos mencionados acima terá impactos mínimos
nas aplicações portadas e nos controladores escritos, graças ao sistema de configuração do núcleo do Linux
e ainda ao método de compilação de programas usado baseado na uClibc.
Outra possível sequência a este trabalho inclui o porte das aplicações actualmente implementadas na
placa Xtran-3. As aplicações do sistema antigo poderão ser agora concretizadas em daemons que correrão
permanentemente no sistema portado, ou programas que serão executados a pedido. Estas aplicações
poderão ser desenvolvidas num sistema Linux normal de maneira a beneficiar da protecção de memória e,
após isso, compiladas para a uClibc. Para que esta transição entre versões da libc se dê sem problemas,
é necessário ter em atenção as limitações da uClibc descritas na secção 2.7.7. Dada a importância destas
aplicações e o papel vital que estas têm no negócio da Tecmic, terão que ser definidos testes de regressão
de maneira a providenciar ao cliente uma transição sem perda de funcionalidades.

59
Bibliografia
[AD07] Thiemo Voigt Adam Dunkels, Björn Grönvall. Contiki - a lightweight and flexible operating system
for tiny networked sensors. NOV 2007.

[Bou94] Elsayed A. Elsayed & Thomas O. Boucher. Analysis and Control of Production Systems. Prentice
Hall, first edition, 1994.

[Bow98] Ivan Bowman. Conceptual architecture of the linux kernel. Technical report, University of Waterloo,
JAN 1998.

[BWK88] Dennis M. Ritchie Brian W. Kerningham. The C Programming Language. Prentice Hall, second
edition, 1988.

[DPB00] Marco Cesati Daniel P. Bovet. Understanding the Linux Kernel. O’Reilly, first edition, 2000.

[Haa08] Aapo Haapanen. Active objects in symbian os. APR 2008.

[Hri05] Hrissan. Symbian os design faults. JAN 2005.

[JCKH05] Alessandro Rubini Jonathan Corbet and Greg Kroah-Hartman. Linux Device Drivers. O’Reilly, third
edition, 2005.

[JFK05] Keith W. Ross James F. Kurose. Computer Networking, a Top-Down Approach Featuring the Inter-
net. Prentice Hall, third edition, 2005.

[Loc05] C. Douglass Locke. Posix and linux application compatibility design rules. NOV 2005.

[Lov05] Robert Love. Linux Kernel Development. Sams Publishing, first edition, 2005.

[Mas04] Antony J. Massa. Embedded Software Development with eCos. Prentice Hall, first edition, 2004.

[McK03] Paul E. McKenney. Read-copy-update: Using execution history to solve concurrency problems.
2003.

[Nik03] Kimmo Nikkanen. uclinux as an embedded solution. Technical report, Turku Polytechnic, JAN
2003.

[Tan93] Andrew S. Tanenbaum. Modern Operating Systems. Prentice Hall, second edition, 1993.

[Wil03] Matthew Wilcox. I’ll do it later: Softirqs, tasklets, bottom halves, task queues, work queues and
timers. JAN 2003.

[Wol01] Wayne Wolf. Principles of Embedded Computing System Design. Morgan Kaufmann Publications,
first edition, 2001.

[Woo99] David Woodhouse. Jffs : The journalling flash file system. 1999.

[Yag03] Karim Yaghmour. Building Embedded Linux Systems. O’Reilly, first edition, 2003.

61
A Algumas considerações sobre o núcleo do uClinux

A.1 Introdução

O núcleo do uClinux é apenas uma das camadas de software que compõem um sistema embebido Linux.
Este núcleo pode ser dividido em subsistemas que agregam conjuntos de funcionalidades semelhantes e que
interagem entre si através de chamadas de sistema e de estruturas de dados partilhadas. Estes subsistemas
são responsáveis por manter uma representação interna consistente, de maneira a que cada recurso do
sistema (seja ele físico ou lógico) possa ser manipulado indiferentemente pelas camadas adjacentes a cada
subsistema[Bow98]. Do ponto de vista de desenvolvimento, o núcleo do Linux, por ser de código aberto,
adquiriu um grande número de recursos que, movidos por vários interesses académicos e/ou profissionais
e ainda graças a esta divisão clara entre componentes, puderam contribuir eficazmente para a evolução e
maturidade de cada parte enriquecendo a qualidade do núcleo como um todo.
Neste anexo, são resumidos os conceitos gerais que estão na base do enorme projecto que é o núcleo do
Linux. É introduzida a arquitectura e os diferentes componentes que compõem um sistema operativo em ge-
ral: o escalonador de processos, a gestão de memória, o sistema de ficheiros do núcleo e os mecanismos de
comunicação entre processos[Tan93]. São também descritas as classes presentes actualmente no núcleo,
bem como a motivação para o seu aparecimento. São apresentados os principais mecanismos de controlo
de concorrência, entradas e saídas e tratamento de interrupções do núcleo do Linux, bem como as conceitos
que estão na base da sua implementação actual. A versão do núcleo do Linux considerada para este traba-
lho foi a 2.6.19, presente na distribuição estável do uClinux de 30/01/2007 no núcleo. É ainda apresentado
e discutido o modelo geral de um controlador simples para Linux, para demonstrar como é relativamente
acessível, face à ausência de sistema operativo, a escrita de controladores para este núcleo.

A.2 Arquitectura

À semelhança dos sistemas Unix, vários processos concorrentes executam tarefas diferentes[Tan93]. Cabe
a cada processo pedir os recursos de sistema que necessita, nomeadamente, memória, processador, acesso
à rede, ou outro e cabe ao núcleo do Linux gerir eficientemente todos estes pedidos. Para conseguir esta
gestão de uma maneira eficiente, o núcleo do Linux foi dividido conceptualmente nas seguintes partes:

Gestão de Processos - Trata da criação e destruição de processos, bem como recursos dos recursos as-
sociados (ficheiros abertos, memória, entre outros recursos de entrada e saída). Cabe à gestão de
processos lidar também com os mecanismos de comunicação entre estes através de sinais, pipes, ou
outras funções de IPC que surgiram aquando do aparecimento do sistema Unix[Tan93]e que são man-
tidas, quer por razões de âmbito do projecto, quer pela compatibilidade com os sistemas POSIX1 . Uma
grande parte da complexidade da gestão de processos reside no escalonador. Escalonar tarefas efi-
cientemente é, por natureza, um problema complexo[Bou94], cuja resolução no contexto do núcleo do
Linux é dificultada pela existência de periféricos lentos, pela natureza incerta dos processos do utiliza-
1
O núcleo do Linux, apesar de não ser um sistema Posix[Loc05], o seu grau de compatibilidade com esta norma é considerado
elevado.

63
dor e ainda pelo suporte SMP que o núcleo possui. Actualmente, existem vários tipo de escalonamento
no núcleo do Linux: escalonamento de CPU (cujo código é fixo, apesar de ter vindo a sofrer alterações
entre cada major release) e escalonamento de I/O, cujo código possui uma arquitectura configurável
em tempo de execução, podendo ser alterado o algoritmo de escalonamento a utilizar consoante a
vontade do utilizador.
Gestão de Memória - Os diferentes tipos de memória existente em dado sistema formam um recurso cuja
gestão eficiente é crítica para o desempenho deste. O núcleo atribui um espaço de endereçamento
virtual a cada processo, de acordo com os recursos de memória disponíveis na altura, gerindo-o con-
soante as necessidades deste, explicitadas através de chamadas de sistema específicas (malloc/free).
Sistema de Ficheiros - Na filosofia Unix, “tudo é um ficheiro”[Tan93]. Apesar de este conceito não ser
universalmente válido para todos os recursos do sistema, o núcleo do Linux possui uma hierarquia
estruturada de todos estes. Esta hierarquia usa a abstracção do sistema de ficheiros, que também é
usada para aceder uniformemente a dados em diversos periféricos de armazenamento.
Controlo de periféricos - Os controlodadores, ou drivers propriamente ditos. Tirando a memória principal e
o processador, todos os periféricos presentes no sistema terão de ter um controlador associado que faz
a ponte entre o núcleo, ou algum componente específico deste, e o hardware desse periférico. Desde
a versão 2.2, o linux suporta carregamento e libertação de controladores em tempo de execução.
Suporte de Rede - No Linux, o suporte de rede está implementado ao nível do núcleo dada a natureza as-
síncrona desta funcionalidade. Todos os pacotes que chegam ou partem a determinado sistema terão
de passar pelo núcleo que os identifica e reencaminha para os processos respectivos. Dado o âmbito
genérico do sistema operativo e ainda a complexidade do problema de escalonamento eficiente[Bou94],
alguns processos terão de ser escalonados de acordo com a sua actividade na rede e isto só é possível
se o núcleo conhecer a relação entre os pacotes e os processos que os recebem.

No contexto dos sistemas embebidos tratados neste trabalho, não é necessário o suporte SMP. A fi-
gura A.1) procura ilustrar os diferentes componentes que compõem o núcleo do Linux.

A.3 Classes

Nas versões iniciais do núcleo no Linux, foram criadas três classes para distinguir as diferentes aborda-
gens à comunicação com os periféricos existentes[JCKH05]. Essas três classes iniciais ainda se encontram
presentes e são:

Carácter - O periférico pode ser acedido através das chamadas de sistema read e write, como se fosse
um ficheiro, excepto na forma como o acesso é feito que terá de ser sequencial (excepto para alguns
periféricos que permitem mapear todo o conteúdo de um buffer de tamanho fixo e aceder-lhe directa-
mente). Estes periféricos terão de implementar pelo menos as funções open, close, read e write. As
portas série e as consolas de texto são exemplos de periféricos desta classe, acessíveis através dos
entradas presentes no sistema de ficheiros /dev/ttyS0, /dev/console.
Bloco - A comunicação deste tipo de periféricos com o núcleo é feita através de operações de I/O em que
são transferidos blocos de dados cujo tamanho é uma potencia de 2. Apesar do núcleo do Linux possuir

64
Figura A.1: Arquitectura do núcleo do Linux.

a versatilidade de permitir transferir blocos de qualquer tamanho (à semelhança dos periféricos do tipo
carácter) para este tipo de periféricos, essa transparência é visível apenas para o utilizador, que se
limita a usar as entradas no /dev. Do ponto de vista da interface deste tipo de periféricos com o núcleo,
as diferenças são suficientes para que estes periféricos tenham a sua própria classe.
Rede - Do ponto de vista do núcleo, um periférico de rede possui a capacidade de realizar troca de dados
com sistemas externos. Tal como foi dito na secção A.2, é necessário o núcleo interceptar todos os
pacotes de rede que passam no sistema, daí que esta classe sirva para providenciar uma interface
genérica para realizar este tipo de controlo. É de notar que, apesar dos diferentes protocolos das
diferentes camadas OSI estarem implementados no núcleo, do ponto de vista deste apenas interessa
saber enviar e receber pacotes. Os protocolos (TCP, IP, UDP, entre outros), tal como seria de esperar de
uma implementação conceptualmente correcta[Tan93], estão implementados em camadas diferentes
do núcleo. Ao contrário dos dois tipos anteriores, estes periféricos não se encontram mapeados no
sistema de ficheiros de maneira a providenciar acesso a partir dele. A comunicação com este tipo de
periféricos é feita apenas utilizando funções de escrita e leitura de pacotes.

Para além destas três classes existem outras que se situam em diferentes níveis da arquitectura do
núcleo. No entanto, todas estas se traduzem numa ou várias instâncias destes três tipos. A função destas
classes adicionais é fornecer uma API pré-definida que facilite a vida do programador. Por exemplo, a classe
RTC permite a todos os periféricos que possuam a capacidade de realizar um conjunto de funcionalidades
comuns (neste caso, e para enriquecer este exemplo, ler e escrever as horas e accionar um alarme) se
possam identificar perante o núcleo como um relógio, que irá tirar partido de eventuais optimizações no
manuseamento do código do seu controlador e ainda integrar-se com as chamadas de sistema específicas
dessa classe. Isto faz com que seja possível escrever um programa genérico para controlar qualquer tipo
de relógio, como é demonstrado na secção A.8. Internamente, o controlador desta classe efectua a escrita
e leitura tipicamente através de um periférico (genérico) do tipo carácter. Adicionalmente, cada controlador

65
poderá implementar as funções das várias APIs de cada classe e assim suportar mais do que uma classe.
Outras classes que se enquadram neste tipo de implementação são os periféricos USB, SCSI, MTD e I2C.

A.4 Controlo de Concorrência

O núcleo do Linux implementa no núcleo diversos mecanismos de controlo de concorrência. Cada um destes
mecanismos tenta resolver problemas de sincronização comuns que estão na base de eventuais atrasos na
execução de processos, míngua no acesso aos recursos ou corrupção de dados. O núcleo do Linux é
particularmente rico neste tipo de mecanismos face a outros sistemas[Yag03] (ver capítulo 2), sobretudo
desde que se tornou completamente preemptivo. Nesta secção são resumidos alguns deles:

Semáforos - O núcleo do Linux disponibiliza semáforos que permitem proteger determinadas secções de
código contra acessos concorrentes[Tan93]. Actualmente os semáforos têm uma implementação gené-
rica que lhes permite serem criados em modo trinco, ou seja, não possuindo um contador explícito de
acessos[JCKH05]. Outro tipo de semáforo existente no núcleo do Linux são os rwsem. Estes semáfo-
ros permitem diferenciar o acesso para escrita e leitura de determinado código (resolvendo o problema
clássico do leitor/escritor[Tan93], deixando a tarefa da optimização de acessos a cargo do núcleo. A
única limitação deste tipo de primitiva de sincronização é o facto de não poder ser usada em blocos de
código que nunca perdem o processador, como por exemplo, rotinas de atendimento a interrupções.
Spinlocks - Para eliminar a restrição mencionada anteriormente, foi criada uma primitiva de sincronização
que se tornou na mais utilizada no código de controladores do núcleo do Linux[JCKH05]: os spinlocks 2 .
Apesar de funcionarem apenas como trincos (apenas possuem dois estados), existe implementação
para todas as arquitecturas suportadas, incluindo sistemas multi-processador. No entanto, tanta fle-
xibilidade de controlo traz um custo adicional, especialmente no uso em rotinas que nunca perdem
o processador. Esse custo é, muito provavelmente, uma situação de deadlock em que o núcleo fica
preso para sempre no spin. Existem também várias variantes de spinlocks, incluindo o equivalente aos
rwsem, falados anteriormente.
Variáveis atómicas - Uma alternativa a usar os mecanismos de sincronização baseados na criação de
trincos é usar variáveis de um tipo especial que lhes confere carácter atómico. Estas variáveis só
poderão ser inteiros (tipo int da linguagem C[BWK88] e o seu valor terá de ser modificado ou lido
segundo funções existentes. Para casos simples, são a melhor alternativa. No entanto, quando o
tamanho da informação classificada como atómica tem apenas um bit de tamanho, o núcleo do Linux
providencia as funções equivalentes à manipulação de inteiros atómicos para bits. É de notar que, em
ambos os casos, o código que implementa estas funções varia com a arquitectura (tal como no caso
dos spinlocks). No caso das variáveis atómicas é utilizada a conhecida instrução test-and-set[Tan93].
Seqlocks - Este mecanismo de sincronização apareceu na versão 2.6 do núcleo do Linux e permite obter
um mecanismo mais rápido, em média[JCKH05], que as alternativas anteriores para resolver o pro-
blema do leitor/escritor, sem o uso de espera em certos casos. Neste tipo de trinco, o acesso aos
2
Não existe tradução para português associada a esta palavra, no entanto, o conceito que está na origem deste mecanismo de
sincronização é a existência de um trinco (lock ) que, caso a sua abertura seja negada por este se encontrar fechado, a execução passa
para um ciclo que verifica se o trinco já se encontra aberto (spin).

66
leitores é sempre facultado e a verificação do estado do trinco é feita posteriormente. Caso o trinco
se encontre fechado, irá ocorrer uma colisão com um dos escritores, que será tratada pelo núcleo,
obrigando o leitor a reler novamente. O número de vezes que esta leitura repetitiva deverá ocorrer é
por definição menor do que nos mecanismos de controlo de concorrência definidos anteriormente, pois
estes trincos só devem ser usados para casos em que as escritas sejam raras e rápidas. Para além
desta característica, este tipo de trinco não protege, por exemplo, acessos a eventuais ponteiros de
estruturas que estejam dentro do código protegido.
RCU - Para eliminar a restrição dos trincos do tipo seqlocks, foi implementado no núcleo um mecanismo de
protecção de dados que introduz algumas restrições ao leitor e ao escritor, mas que, usado nos casos
apropriados (extremamente raros no código do núcleo do Linux[JCKH05] poderá ter uma performance
muito superior a todos os outros falados até aqui (excepto as variáveis atómicas). Para além dos casos
em que as escritas são raras, este mecanismo também é mais eficaz, em várias ordens de magnitude,
quando a concorrência ao recurso protegido é particularmente acentuada[McK03] (casos em que o
sistema apresenta elevada contenção).
The BIG Kernel Lock Este mecanismo, considerado arcaico, de sincronização no núcleo do Linux, funciona
como uma spinlock global a todo o núcleo, inclusive, no contexto SMP, a todos os processadores[DPB00].
Embora o seu uso ainda faça sentido nalgumas partes do núcleo[Lov05], verifica-se que estes são ca-
sos muito específicos e que o seu uso é evitável, pelo menos na escrita de controladores.

A.5 Controlo de entradas e saídas

A maneira de o núcleo aceder aos periféricos está profundamente relacionada com a arquitectura utilizada.
Existem, no entanto, duas abordagens possíveis:

Mapeamento Orientado ao Porto Acontece tipicamente na arquitectura x86. Será necessário invocar fun-
ções que verificam se determinados portos estão livres a fim de serem utilizados. Cada controlador
é responsável pelos portos que reservou para sim, podendo eventualmente libertá-los. Caso isto não
aconteça, nenhum controlador poderá aceder a portos já atribuídos. Existem optimizações relaciona-
das com a maneira como determinado processador lida com as transferências de dados, podendo, por
exemplo, escrever mais do que um byte por ciclo para um determinado porto. Estas optimizações não
estão implementadas em todas as arquitecturas.
Mapeamento Orientado à Memória Acontece na grande maioria das outras arquitecturas diferentes da
x86. Nestas arquitecturas, existe um conjunto de endereços que mapeia directamente os registos
dos eventuais periféricos (chamada memória de I/O). Tal como no caso dos portos, um controlador
poderá pedir ao núcleo um determinado conjunto (contínuo) de endereços e, após esse controlador
eventualmente libertar essa região de memória, mais nenhum outro controlador terá acesso.

O núcleo do Linux providencia ainda, para arquitecturas suportadas, um conjunto de funções que permite
mapear eventuais portos para endereços de memória dentro do espaço de endereçamento do processador.
No entanto, tal como já mencionado acima, esta e outras funcionalidades de I/O têm uma ligação forte ao
processador a ser usado, pelo que não estão disponíveis em todas as arquitecturas.

67
A.6 Interrupções

O mecanismo de gestão de interrupções do Linux é bastante semelhante ao controlo de entradas e saídas,


na medida em que há um mecanismo de subscrição e de rescisão de recursos, neste caso ao número do IRQ
associado. Neste caso, há a possibilidade de partilhar o mesmo IRQ entre vários controladores diferentes.
Quando isto acontece, cada controlador subscrito a uma mesma interrupção terá que possuir uma função
que é chamada pelo núcleo para determinar se aquele controlador é ou não responsável por atender aquela
interrupção.
Para além do mecanismo de subscrição de IRQs, o núcleo do Linux disponibiliza ainda um conjunto
de mecanismos que minimiza o carácter exclusivo que as rotinas de atendimento à interrupção possuem.
Existem dois mecanismos mais frequentemente utilizados[JCKH05]:

Top and Bottom Halves - A rotina de atendimento à interrupção é dividida em duas partes: a primeira,
designada de Top, que corresponde ao código que é invocado pelo núcleo para atender a interrupção,
e a segunda, designada de Bottom que é escalonada pela primeira para correr mais tarde. Assim,
uma vez que, durante as rotinas de atendimento a interrupções, as interrupções estão inactivas, este
período de tempo é minimizado, o que é desejável já que o sistema deixa de responder durante estas
rotinas. Durante segunda metade da rotina de atendimento à interrupção, as interrupções estão activas
e o código é executado no contexto normal do núcleo.
Tasklets - Funções especiais do núcleo que, à semelhança das Bottom Halves, são escalonadas para
correr mais tarde, já fora do contexto das rotinas de atendimento à interrupção. O seu uso é adequado
para sistemas multi-processador, pois é garantido pelo núcleo que nenhuma tasklet corre em paralelo
com ela mesma e ainda que estas funções irão correr no processador onde foi gerada a interrupção.

A.7 Sistema de ficheiros

O sistema de ficheiros do núcleo do uClinux, comummente designado por VFS, é o sub-sistema responsável
por abstrair o núcleo dos diferentes tipos de sistemas de ficheiros existentes. Graças a esta abstracção, é
fornecida uma interface comum a todos os sistemas de ficheiros existentes, possibilitando assim a interacção
estes.
Existe uma ligação profunda entre o sistema de ficheiros e os periféricos do tipo bloco, pois é sobre estes
que as operações dos sistemas de ficheiros fazem sentido (read, write e open).
O núcleo actual do Linux suporta mais de cinquenta sistemas de ficheiros diferentes, alguns bastante
relevantes no contexto de sistemas embebidos, como por exemplo, FAT, NFS, e JFFS.

A.8 Modelo geral de um controlador

Para ilustrar a relativa facilidade com que se escreve um controlador básico para Linux, é apresentada e
comentada a listagem de um módulo desenvolvido na placa de testes EVB5282 da Motorola (na verdade,
corre em qualquer sistema Linux versão 2.6).

68
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void){


printk(KERN_ALERT "Hello World\n");
return 0;
}

static void hello_exit(void){


printk(KERN_ALERT "Goodbye World\n");
}

module_init(hello_init);
module_exit(hello_exit);

Na secção de código acima, figura a implementação detalhada de um controlador básico para o núcleo
do uClinux. As funções de init e exit são chamadas pelo núcleo aquando da inserção ou remoção do módulo,
respectivamente. A função init, contém todo o código de inicialização do módulo. Este código consiste na
alocação das estruturas de dados necessárias para a implementação e, para as classes de controladores que
estejam a ser usadas, deverão também ser inicializadas as estruturas básicas dessas classes (normalmente,
este passo resume-se a inicializar os ponteiros dessas estruturas com as funções respectivas cujo código
terá de constar no módulo). A função exit é responsável pela libertação de recursos previamente alocados
pelo módulo. Eventuais estruturas de dados, IRQs, portos, ou zonas de memória que tenham sido alocados
ou subscritos, deverão ser libertados, de maneira que o sistema possa reutilizar esses recursos.
Abaixo é apresentado um exemplo mais complexo, comentado, para demonstrar o estilo de codigo pre-
sente num exemplo real de implementação (retirado da implementação do controlador do relógio ds2404
elaborada neste trabalho).

/*
* An rtc driver for the Dallas DS2404
* The target board does not use dallas one wire bus and does not have
* its irq pin assigned to the processor. Software interrupt generation
* is emulated
*
* Copyright (C) 2008 Antonio Jose Silva <antonio.jose.silva@ist.utl.pt>
*
*/
#include <linux/module.h>
#include <linux/err.h>

69
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
/* added */
#include <asm/coldfire.h>
#define MCF5282_GPIO_CLRE (*(volatile unsigned char *) (MCF_IPSBAR + 0x100040))

/*
Outros defines locais contendo endereços úteis
...
*/

/**************************
Funções específicas para interação com o periférico (relógio ds2404)
**************************/

static unsigned long ds2404_read_memory(unsigned short int size, unsigned char addr){
int i;
unsigned long result;
unsigned short int u;
result = 0;
spin_lock(&ds2404_lock);

/*zona de exclusão mútua, código específico do device


para ler as horas e data do alarme ou do relógio
*/

spin_unlock(&ds2404_lock);
return result;
}

static int ds2404_write_memory(unsigned long value){


unsigned short int i;
spin_lock(&ds2404_lock);

/*zona de exclusão mútua, código específico do device


para ajustar as horas e data
*/

70
spin_unlock(&ds2404_lock);
return 0;
}

static int ds2404_write_alarm_memory(unsigned long value){


spin_lock(&ds2404_lock);

/*zona de exclusão mútua, código específico do device


para ajustar as horas e data do alarme
*/

spin_unlock(&ds2404_lock);
return 0;
}

/**************************
Funções da API da classe (RTC) para integração com o núcleo
**************************/

static unsigned char ds2404_check_alarm(void){

/*API do RTC: Verificar se alarme se encontra ajustado */


spin_lock(&ds2404_lock);

/* Código específico do periférico */

spin_unlock(&ds2404_lock);
}

static int ds2404_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm){


alrm->enabled = ds2404_check_alarm();

/*API do RTC: ler as horas (e data) do alarme utilizando uma estrutura rtc_time */

if (alrm->enabled == 2){
alrm->enabled = 0;
return -1;
}
rtc_time_to_tm(ds2404_read_memory(4, ADD1_ALM_INIT), &(alrm->time));

71
return 0;
}

static int ds2404_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm){


unsigned long value;

/*API do RTC: ajustar as horas (e data) do alarme utilizando uma


estrutura rtc_time */

rtc_tm_to_time(&(alrm->time), &value);
ds2404_write_alarm_memory(value);
return 0;
}

static int ds2404_rtc_read_time(struct device *dev, struct rtc_time *tm){

/*API do RTC: ler as horas (e data) utilizando uma estrutura rtc_time */

rtc_time_to_tm(ds2404_read_memory(4, ADD1_INIT), tm);


return 0;
}
static int ds2404_rtc_set_time(struct device *dev, struct rtc_time *tm){
unsigned long value;

/*API do RTC: ajustar as horas (e data) utilizando uma estrutura rtc_time */

rtc_tm_to_time(tm, &value);
return ds2404_write_memory(value);
}

static int ds2404_rtc_set_mmss(struct device *dev, unsigned long secs){

/*API do RTC: ajustar as horas via valor de segundos do relógio*/

return ds2404_write_memory(secs);
}

static int ds2404_rtc_proc(struct device *dev, struct seq_file *seq){


struct platform_device *plat_dev = to_platform_device(dev);

72
/* Função chamada aquando da leitura da entrada no pseudo
sistema de ficheiros proc. Os restantes parâmetros (horas,
hora do alarme, data, etc, são previamente impressos pelo
código da classe RTC.
*/

seq_printf(seq, "id\t\t: %d\n", plat_dev->id);

return 0;
}

static int ds2404_rtc_ioctl(struct device *dev, unsigned int cmd,


unsigned long arg){

/* Este função é chamada quando ocorre uma interrupção destinada a este


driver. A classe RTC já possui as restantes (READ TIME, READ ALARM,
WRITE TIME, etc, implementadas e agulhadas para as funções que
esta classe precisa de ter.
*/

switch (cmd) {
case RTC_PIE_ON:
case RTC_PIE_OFF:
case RTC_UIE_ON:
case RTC_UIE_OFF:
case RTC_AIE_ON:
case RTC_AIE_OFF:
return 0;

default:
return -ENOIOCTLCMD;
}
}

static ssize_t ds2404_irq_show(struct device *dev,


struct device_attribute *attr, char *buf){

/* Mostra o irq atribuído (para fins de debug, por exemplo) */

73
}

static ssize_t ds2404_irq_store(struct device *dev,


struct device_attribute *attr,
const char *buf, size_t count){

/* Geração de interrupções (de software) */

/**************************
Inicialização/Libertação de recursos
**************************/

static const struct rtc_class_ops ds2404_rtc_ops = {


/*
Inicialização da estrutura do device.
Os ponteiros para funções são preenchidos com as implementações
do módulo
*/
.proc = ds2404_rtc_proc,
.read_time = ds2404_rtc_read_time,
.set_time = ds2404_rtc_set_time,
.read_alarm = ds2404_rtc_read_alarm,
.set_alarm = ds2404_rtc_set_alarm,
.set_mmss = ds2404_rtc_set_mmss,
.ioctl = ds2404_rtc_ioctl,
};

static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, ds2404_irq_show, ds2404_irq_store);


static int ds2404_probe(struct platform_device *plat_dev){

//Fase de probe da inicialização

int err;
struct rtc_device *rtc = rtc_device_register("ds2404", &plat_dev->dev,
&ds2404_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {

74
err = PTR_ERR(rtc);
return err;
}

/* Código específico do periférico (ASM or C)


...
*/

/*Criação da entrada no /dev */


device_create_file(&plat_dev->dev, &dev_attr_irq);
platform_set_drvdata(plat_dev, rtc);
spin_lock_init(&ds2404_lock);
return 0;
}

static int __devexit ds2404_remove(struct platform_device *plat_dev){

/* Libertação de recursos (instância RTC e nó do sistema de ficheiros) */

struct rtc_device *rtc = platform_get_drvdata(plat_dev);


rtc_device_unregister(rtc);
device_remove_file(&plat_dev->dev, &dev_attr_irq);
return 0;
}

/* Estrutura do driver deste device */


static struct platform_driver ds2404_drv = {
.probe = ds2404_probe,
.remove = __devexit_p(ds2404_remove),
.driver = {
.name = "rtc-ds2404",
.owner = THIS_MODULE,
},
};

static int __init ds2404_init(void){

//Alocação de recursos (driver e device)

75
int err;
if ((err = platform_driver_register(&ds2404_drv)))
return err;
if ((ds2404 = platform_device_alloc("rtc-ds2404", 0)) == NULL) {
err = -ENOMEM;
goto exit_driver_unregister;
}
if ((err = platform_device_add(ds2404)))
goto exit_device_unregister;
return 0;
exit_device_unregister:
platform_device_unregister(ds2404);
platform_device_put(ds2404);
exit_driver_unregister:
platform_driver_unregister(&ds2404_drv);
printk(KERN_EMERG "Unable to initialize driver...\n");
return err;
}
static void __exit ds2404_exit(void){

//Libertação de recursos (driver e device)

platform_device_unregister(ds2404);
platform_driver_unregister(&ds2404_drv);
}
MODULE_AUTHOR("Antonio Jose Silva <antonio.jose.silva@ist.utl.pt>");
MODULE_DESCRIPTION("Dallas DS2404 RTC driver");
MODULE_LICENSE("GPL");
module_init(ds2404_init); // Função de inicialização do módulo
module_exit(ds2404_exit); // Função de terminação do módulo

76
B Tabela de instruções para o RTC ds2404
B.1 Tabela de instruções para o RTC ds2404

Tabela B.1: Instruções em modo 3-wire para o DS2404

Master Mode Data (LSB first) Comments


TX Reset Issue“write scratchpad” command
TX 0Fh TA1, beginning offset=0
TX E0h TA2, address=01E0h
TX 01h Write 1 page of data to scratchpad
TX <32 data bytes> Master pulses RSTlow
TX Reset Issue“read scratchpad” command
TX AAh Read TA1, beginning offset=0
RX E0h Read TA2, address=01E0h
RX 01h Read E/S, ending offset=31d, flags=0
RX 1Fh Read scratchpad data and verify
RX <32 data bytes>
TX Reset Master pulses RST low
TX 55h Issue“copy scratchpad” command
TX E0h TA1 (Authorization command)
TX 01h TA2 (Authorization command)
TX 1Fh E/S (Authorization command)
RX <busy indicator> Wait until DQ=0 (30us typical)
TX Reset Master pulses RSTlow
TX F0h Issue“read memory” command
TX E0h TA1, beginning offset=0
TX 01h TA2, address=01E0h
RX <32 data bytes> Read memory page 15 and verify
TX Reset Master pulses RSTlow, done

77

You might also like