Υλοποίηση δροµολογητή (Router Implementation)

ΤΕΧΝΟΛΟΓΙΚΟ ΕΚΠΑΙ∆ΕΥΤΙΚΟ Ι∆ΡΥΜΑ (ΤΕΙ)
∆ΥΤΙΚΗΣ ΜΑΚΕ∆ΟΝΙΑΣ
ΠΑΡΑΡΤΗΜΑ ΚΑΣΤΟΡΙΑΣ
ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΕΧΝΟΛΟΓΙΑΣ ΥΠΟΛΟΓΙΣΤΩΝ
Υλοποίηση δροµολογητή
(Router Implementation)
ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ
του
∆ΗΜΗΤΡΙΟΥ Α. ΡΟΥΣΗ
(ΑΕΜ: 355)
Επιβλέπων :
∆ηµήτριος Φωτιάδης
Καθηγητής Εφαρµογών
Καστοριά Νοέµβριος 2012
Η παρούσα σελίδα σκοπίµως παραµένει άδεια
2
ΤΕΧΝΟΛΟΓΙΚΟ ΕΚΠΑΙ∆ΕΥΤΙΚΟ Ι∆ΡΥΜΑ (ΤΕΙ)
∆ΥΤΙΚΗΣ ΜΑΚΕ∆ΟΝΙΑΣ
ΠΑΡΑΡΤΗΜΑ ΚΑΣΤΟΡΙΑΣ
ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΕΧΝΟΛΟΓΙΑΣ ΥΠΟΛΟΓΙΣΤΩΝ
Υλοποίηση δροµολογητή
(Router Implementation)
ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ
του
∆ΗΜΗΤΡΙΟΥ Α. ΡΟΥΣΗ
(ΑΕΜ: 355)
Επιβλέπων :
∆ηµήτριος Φωτιάδης
Καθηγητής Εφαρµογών
Εγκρίθηκε από την τριµελή εξεταστική επιτροπή την:
............................
Ον/µο Μέλος Ε.Π.
Ιδιότητα Μέλους Ε.Π.
/
............................
Ον/µο Μέλος Ε.Π.
Ιδιότητα Μέλους Ε.Π.
/
............................
Ον/µο Μέλος Ε.Π.
Ιδιότητα Μέλους Ε.Π.
Καστοριά Νοέµβριος 2012
3
ROUTER NGW100
Firmware version 1.0.0
MyThesis.org
4
Copyright © 2012 – ∆ηµήτριος Α. Ρούσης
Απαγορεύεται η αντιγραφή, αποθήκευση και διανοµή της παρούσας εργασίας, εξ ολοκλήρου
ή τµήµατος αυτής, για εµπορικό σκοπό. Επιτρέπεται η ανατύπωση, αποθήκευση και διανοµή
για σκοπό µη κερδοσκοπικό, εκπαιδευτικής ή ερευνητικής φύσης, υπό την προϋπόθεση να
αναφέρεται η πηγή προέλευσης και να διατηρείται το παρόν µήνυµα. Οι απόψεις και τα συµπεράσµατα που περιέχονται σε αυτό το έγγραφο εκφράζουν αποκλειστικά τον συγγραφέα
και δεν αντιπροσωπεύουν τις επίσηµες θέσεις του ΤΕΙ ∆υτικής Μακεδονίας.
5
Σε όσους αγαπούν
αυτό που κάνουν
6
Περιεχόµενα
Περιεχόµενα ........................................................................................................................................ 7
Ευρετήριο εικόνων ............................................................................................................................ 11
Ευρετήριο πινάκων ........................................................................................................................... 14
Ευχαριστίες ....................................................................................................................................... 15
Περίληψη........................................................................................................................................... 16
Εισαγωγή .......................................................................................................................................... 17
Το προαπαιτούµενο θεωρητικό υπόβαθρο .................................................................................. 17
∆οµή εργασίας .............................................................................................................................. 18
Θεωρητικό µέρος...................................................................................................................... 18
Πρακτικό µέρος ........................................................................................................................ 19
Παραρτήµατα............................................................................................................................ 20
1ο ΚΕΦΑΛΑΙΟ ...................................................................................................................................... 22
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux............................................................................... 22
Εισαγωγή ...................................................................................................................................... 22
1.1 Τι είναι το Linux....................................................................................................................... 23
1.2 Το ενσωµατωµένο Linux......................................................................................................... 23
1.3 Οι τύποι των ενσωµατωµένων συστηµάτων Linux................................................................. 24
1.4 Γιατί να προτιµήσουµε το Linux .............................................................................................. 25
1.5 Έτοιµες διανοµές και εργαλεία ανάπτυξης ............................................................................. 27
1.6 Μεθοδολογία σχεδίασης και ανάπτυξης ................................................................................. 28
1.7 Εργαλεία ανάπτυξης και αποσφαλµάτωσης........................................................................... 30
1.8 Οι τύποι ανάπτυξης ................................................................................................................ 31
1.9 Οι τύποι αποσφαλµάτωσης .................................................................................................... 33
1.10 Η αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux ................................................... 34
1.11 Εκκίνηση συστήµατος........................................................................................................... 36
1.11.1 Τύποι εκκίνησης ............................................................................................................ 37
Εκκίνηση από µνήµη στερεάς κατάστασης.......................................................................... 38
Εκκίνηση από σκληρό δίσκο ................................................................................................ 39
Εκκίνηση µέσω δικτύου........................................................................................................ 39
1.12 Μονάδα διαχείρισης µνήµης (MMU) ..................................................................................... 39
1.13 ∆ιαχείριση δευτερεύουσας µνήµης ....................................................................................... 41
2ο ΚΕΦΑΛΑΙΟ ...................................................................................................................................... 43
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux ............................................................. 43
Εισαγωγή ...................................................................................................................................... 43
2.1 Έτοιµες αλυσίδες εργαλείων ανάπτυξης ................................................................................ 43
2.2 Πακέτο υποστήριξης συστήµατος........................................................................................... 44
2.3 Αλυσίδα εργαλείων µεταγλώττισης......................................................................................... 44
2.4 ∆ηµιουργία της αλυσίδας µεταγλώττισης cross ...................................................................... 45
2.4.1 Binutils ............................................................................................................................. 45
2.4.2 Οι κεφαλίδες του Linux kernel ......................................................................................... 46
2.4.3 Η βιβλιοθήκη C ................................................................................................................ 46
2.4.4 Η βιβλιοθήκη νηµάτων .................................................................................................... 47
2.4.5 Εκδόσεις πακέτων λογισµικού και διαχείριση ................................................................. 48
2.4.6 Επισκόπηση δηµιουργίας της αλυσίδας cross ................................................................ 50
2.5 Αυτοµατοποιηµένα συστήµατα ............................................................................................... 50
2.5.1 Εναλλακτικές βιβλιοθήκες C ............................................................................................ 51
2.5.2 Το αυτοµατοποιηµένο σύστηµα Buildroot ....................................................................... 51
2.6 Παραµετροποίηση uClibc, kernel και BusyBox µέσω Buildroot ............................................. 60
2.7 Γραµµή εντολών ..................................................................................................................... 64
2.8 Βασικές εντολές φλοιού .......................................................................................................... 64
2.9 Προσοµοιωτές τερµατικών ..................................................................................................... 66
2.9.1 Ο προσοµοιωτής τερµατικού C-Kermit ........................................................................... 67
7
2.9.2 Ο προσοµοιωτής τερµατικού PuTTY .............................................................................. 69
2.10 IDEs για Linux....................................................................................................................... 71
2.10.1 Το IDE AVR32 Studio.................................................................................................... 71
3ο ΚΕΦΑΛΑΙΟ ...................................................................................................................................... 73
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux.......................................................................... 73
Εισαγωγή ...................................................................................................................................... 73
3.1 Αρχιτεκτονικές µικροελεγκτών ................................................................................................ 74
3.2 Οδηγοί συσκευών και Linux Kernel ........................................................................................ 76
3.2.1 Linux kernel ..................................................................................................................... 79
3.2.2 Modules ........................................................................................................................... 80
3.3 Παράδειγµα ανάπτυξης module ............................................................................................. 81
3.4 ∆ίαυλοι και διεπαφές............................................................................................................... 83
3.4.1 USB ................................................................................................................................. 83
3.4.2 I2C Linux Framework ...................................................................................................... 85
Ο ενσωµατωµένος Linux driver για το I2C........................................................................... 85
Παραµετροποίηση του Kernel.............................................................................................. 86
I2C µέσω GPIO .................................................................................................................... 87
Εγκατάσταση των I2C modules ........................................................................................... 89
Χρήση της διεπαφής I2C...................................................................................................... 90
Ανάπτυξη I2C Linux driver ................................................................................................... 93
3.4.3 SPI................................................................................................................................... 93
3.5 Είσοδοι και Έξοδοι (I/Os)........................................................................................................ 99
3.5.1 Το υποσύστηµα tty ........................................................................................................ 101
3.5.2 RS-232 .......................................................................................................................... 107
3.5.3 GPIO.............................................................................................................................. 107
Χρήση της διεπαφής /dev .................................................................................................. 109
Είσοδος και έξοδος σηµάτων GPIO................................................................................... 111
Έλεγχος GPIO µέσω module............................................................................................. 112
Linux LED Framework ....................................................................................................... 112
Χρήση του LED Framework στο user-space ..................................................................... 114
3.6 Modem .................................................................................................................................. 115
3.7 Επικοινωνία µε τη µνήµη ...................................................................................................... 115
3.7.1 ∆ηµιουργία του συστήµατος αρχείων root .................................................................... 116
Παράµετροι µνήµης flash ................................................................................................... 116
Το σύστηµα αρχείων JFFS2 .............................................................................................. 117
Το εργαλείο mkfs.jffs2 ........................................................................................................ 117
∆ιαµόρφωση και εγκατάσταση........................................................................................... 117
SPI modules....................................................................................................................... 120
Μεταγλώττιση και πρόσβαση............................................................................................. 121
3.8 Υλικό δικτύωσης ................................................................................................................... 121
4ο ΚΕΦΑΛΑΙΟ .................................................................................................................................... 123
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux ............................................... 123
Εισαγωγή .................................................................................................................................... 123
4.1 Το TCP/IP στα ενσωµατωµένα συστήµατα Linux ................................................................ 123
4.1.1 Το TCP/IP και το µοντέλο αναφοράς OSI ..................................................................... 124
4.1.2 Οι Απαιτήσεις του TCP/IP από το ενσωµατωµένο Linux .............................................. 124
4.1.3 Η στοίβα TCP/IP στο Linux ........................................................................................... 126
Αρχικοποίηση της στοίβας TCP/IP στον Router NGW100 ................................................ 127
4.2 Linux Sockets ....................................................................................................................... 128
4.2.1 Τί είναι η διεπαφή socket............................................................................................... 128
4.2.2 Οι βασικότερες δοµές διαχείρισης sockets.................................................................... 129
4.2.3 Οικογένειες πρωτοκόλλων ............................................................................................ 129
4.2.4 Αρχικοποίηση επιπέδου socket .................................................................................... 130
4.2.5 Πρωτόκολλο IP και sockets........................................................................................... 131
4.2.6 Η διεπαφή Socket ......................................................................................................... 132
4.2.7 Socket buffers ............................................................................................................... 135
8
4.2.8 Τα είδη των sockets ...................................................................................................... 135
Packet Sockets .................................................................................................................. 136
Raw Sockets ...................................................................................................................... 136
Netlink Sockets και πρωτόκολλο Netlink ........................................................................... 137
Routing Sockets ................................................................................................................. 137
Rtnetlink Sockets ............................................................................................................... 138
4.2.9 Το πρόγραµµα netstat................................................................................................... 138
4.2.10 ∆ιεπαφή socket και IPv6 ............................................................................................. 138
4.3 ∆ροµολόγηση πακέτων ........................................................................................................ 138
4.3.1 Πίνακες δροµολόγησης ................................................................................................. 139
Route cache ....................................................................................................................... 139
RPDB ................................................................................................................................. 139
Η βάση FIB αναλυτικά........................................................................................................ 141
Οι προγραµµατιστικές διεπαφές της FIB ........................................................................... 142
4.3.2 ∆ροµολογητές και δροµολόγηση IP .............................................................................. 142
∆ροµολόγηση εισερχόµενων πακέτων (LAN
WAN)...................................................... 143
∆ροµολόγηση εξερχόµενων πακέτων (LAN
WAN) ....................................................... 143
Η κεφαλίδα IP..................................................................................................................... 144
Αποστολή και λήψη πακέτων µέσω του πρωτοκόλλου IP................................................. 145
4.4 Τα πρωτόκολλα ARP, ICMP και IGMP................................................................................. 146
4.4.1 ARP ............................................................................................................................... 146
4.4.2 ICMP.............................................................................................................................. 147
4.4.3 IGMP ............................................................................................................................. 147
4.5 Οδηγοί δικτύου ..................................................................................................................... 148
4.5.1 H διεπαφή δικτύου......................................................................................................... 148
4.5.2 Ανάπτυξη οδηγού δικτύου............................................................................................. 149
4.5.3 Ο οδηγός δικτύου MACB............................................................................................... 149
NAPI................................................................................................................................... 150
ethtool API.......................................................................................................................... 150
Στατιστικά ........................................................................................................................... 150
Promiscuous mode ............................................................................................................ 151
Έλεγχος σφαλµάτων.......................................................................................................... 151
4.6 Απόδοση δικτύωσης του µικροελεγκτή AP7000................................................................... 152
Εισαγωγή πρακτικού µέρους ...................................................................................................... 153
5ο ΚΕΦΑΛΑΙΟ .................................................................................................................................... 154
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 .................................................. 154
Εισαγωγή .................................................................................................................................... 154
5.1 Περιγραφή και λογικό διάγραµµα του Router NGW100 ....................................................... 154
5.2 Ο µικροελεγκτής AP7000...................................................................................................... 157
5.3 ∆ιαθέσιµη µνήµη................................................................................................................... 159
5.3.1 Χάρτης φυσικών διευθύνσεων ...................................................................................... 164
5.4 Ethernet PHY και MAC ......................................................................................................... 165
5.5 Συνδεσιµότητα RS232 .......................................................................................................... 168
5.6 Ελεγκτής πλακέτας – Board Controller................................................................................. 169
5.7 ∆ιεπαφές προγραµµατισµού JTAG και NEXUS ................................................................... 171
5.8 Σύστηµα χρονισµού .............................................................................................................. 173
5.9 Κύκλωµα επαναφοράς (reset) .............................................................................................. 174
5.10 Σύστηµα τροφοδοσίας ........................................................................................................ 175
5.11 ∆ιαστάσεις πλακέτας .......................................................................................................... 178
5.12 Σχέδιο συναρµολόγησης .................................................................................................... 178
5.13 Σχηµατικά και PCB του Router NGW100 ........................................................................... 180
5.14 Επέκταση δυνατοτήτων υλικού........................................................................................... 180
6ο ΚΕΦΑΛΑΙΟ .................................................................................................................................... 182
Προγραµµατισµός και εκκίνηση του Router NGW100 .................................................................... 182
Εισαγωγή .................................................................................................................................... 182
6.1 Το σύστηµα ανάπτυξης host ................................................................................................ 182
9
6.2 Το πακέτο υποστήριξης συστήµατος Atmel Linux BSP 3.0 ................................................. 183
6.2.1 Τροποποίηση του πακέτου υποστήριξης Atmel Linux BSP 3.0.................................... 184
6.3 ∆ηµιουργία της εικονικής µηχανής Ubuntu 9.04................................................................... 185
6.3.1 Login µε δικαιώµατα root............................................................................................... 187
6.3.2 ∆ηµιουργία του κεντρικού κατάλογου εργασίας /rousis ................................................ 188
6.4 Το περιβάλλον ανάπτυξης AVR32 ....................................................................................... 188
6.4.1 Εγκατάσταση Buildroot και αλυσίδας GNU AVR32....................................................... 188
6.4.2 Το εξειδικευµένο λογισµικό του Router NGW100 ......................................................... 193
6.4.3 Εγκατάσταση του AVR32 Studio................................................................................... 193
6.5 Βοηθητικό λογισµικό ............................................................................................................. 196
6.6 ∆ιαµέριση µνήµης ................................................................................................................. 196
6.7 Η συσκευή JTAGICE mkII .................................................................................................... 197
6.8 Σύνδεση JTAGICE mkII µε το σύστηµα host........................................................................ 198
6.9 Εγγραφή U-Boot στην παράλληλη µνήµη ............................................................................ 202
6.10 Εγγραφή Linux Kernel στην παράλληλη µνήµη ................................................................. 206
6.11 Εγγραφή συστήµατος αρχείων /usr .................................................................................... 207
6.12 ∆ιαδικασία εκκίνησης .......................................................................................................... 209
7ο ΚΕΦΑΛΑΙΟ .................................................................................................................................... 217
Οι εφαρµογές του Router NGW100 ................................................................................................ 217
Εισαγωγή .................................................................................................................................... 217
7.1 Ανάπτυξη δοκιµαστικής εφαρµογής ..................................................................................... 217
7.1.2 Με χρήση κειµενογράφου και γραµµής εντολών........................................................... 218
7.1.3 Μέσω του AVR32 Studio............................................................................................... 221
7.2 Προσθήκη πακέτων λογισµικού στο Buildroot...................................................................... 226
7.2.1 Παράδειγµα προσθήκης εφαρµογής στο σύστηµα Buildroot ........................................ 227
7.3 Οι εφαρµογές του Router NGW100...................................................................................... 230
7.3.1 Πακέτο εφαρµογών BusyBox ........................................................................................ 231
7.3.2 Εφαρµογή inetd .......................................................................................................... 233
7.3.3 Εφαρµογή httpd .......................................................................................................... 233
7.3.4 Εφαρµογές για το Web interface................................................................................... 234
Εφαρµογή haserl ............................................................................................................ 234
Εφαρµογή awk ................................................................................................................... 234
Εφαρµογή webif............................................................................................................... 235
1.3.5 Eφαρµογές διαχείρισης των διεπαφών δικτύου ............................................................ 235
Εφαρµογή ifconfig ........................................................................................................ 235
Εφαρµογές ifup και ifdown............................................................................................ 236
7.3.6 Eφαρµογή route .......................................................................................................... 237
7.3.7 Εφαρµογή iptables ................................................................................................... 239
7.3.8 Εφαρµογές για DNS και DHCP server .......................................................................... 240
Εφαρµογή dnsmasq .......................................................................................................... 240
Εφαρµογή udhcpc ............................................................................................................ 241
7.3.9 Εφαρµογή telnetd...................................................................................................... 241
7.3.10 Εφαρµογή dropbear ................................................................................................. 242
7.3.11 Εφαρµογή ProFTPD ................................................................................................... 243
7.3.12 Εφαρµογή ethtool ................................................................................................... 244
7.3.13 Εφαρµογή portmap ................................................................................................... 245
7.3.14 Εφαρµογή bridge...................................................................................................... 245
7.3.15 Εφαρµογές ενηµέρωσης – εµφάνισης ώρας και ηµεροµηνίας.................................... 246
ΠΑΡΑΡΤΗΜΑΤΑ.................................................................................................................................. 248
ΒΙΒΛΙΟΓΡΑΦΙΑ ................................................................................................................................... 290
10
Ευρετήριο εικόνων
∆ιασυνδεδεµένος τύπος ανάπτυξης ενσωµατωµένων συστηµάτων Linux ........................................... 31
Ανάπτυξη ενσωµατωµένων συστηµάτων Linux µε αφαιρούµενο αποθηκευτικό µέσο ......................... 32
Αυτόνοµος τύπος ανάπτυξης ενσωµατωµένων συστηµάτων Linux ..................................................... 33
Η αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux .................................................................... 34
∆ιάταξη µνήµης στερεάς κατάστασης ................................................................................................... 38
Χάρτης µνήµης και µετάφραση εικονικών διευθύνσεων σε φυσικές ..................................................... 40
∆ιάγραµµα µονάδας διαχείρισης µνήµης MMU..................................................................................... 41
Το περιβάλλον Ubuntu Software Center ............................................................................................... 53
Περιβάλλον παραµετροποίησης του αυτοµατοποιηµένου συστήµατος buildroot ................................. 53
Το υποµενού Toolchain του Buildroot ................................................................................................... 57
Τα περιεχόµενα του καταλόγου dl του συστήµατος Buildroot ............................................................... 59
Γραφικό περιβάλλον παραµετροποίησης της uClibc 0.9.30 ................................................................. 60
Γραφικό περιβάλλον παραµετροποίησης του Linux Kernel 2.6.27.6 ................................................... 62
Γραφικό περιβάλλον παραµετροποίησης του BusyBox 1.13.1............................................................. 63
Εκτέλεση της εντολής loadb σε περιβάλλον Uboot ............................................................................... 69
Παράθυρο διαλόγου παραµετροποίησης του τερµατικού Putty............................................................ 70
Ρυθµίσεις σειριακής επικοινωνίας του τερµατικού Putty ....................................................................... 70
Εκτέλεση της εντολής ls σε περιβάλλον γραµµής εντολών BusyBox ................................................... 71
Οι αρχιτεκτονικές που υποστηρίζονται από τον Linux Kernel............................................................... 74
Περιβάλλον παραµετροποίησης Linux Kernel – Υποµενού: Device Drivers ........................................ 78
Ανατοµία του Linux Kernel .................................................................................................................... 79
Ενεργοποίηση υποστήριξης modules από τον Linux Kernel ................................................................ 80
Παράδειγµα ανάπτυξης module ............................................................................................................ 82
Ενεργοποίηση υποστήριξης USB από τον Linux Kernel ...................................................................... 84
Γραφική αναπαράσταση της επικοινωνίας USB στον Linux Kernel ...................................................... 84
Γραφική αναπαράσταση των µερών του Linux driver I2C .................................................................... 86
Ενεργοποίηση υποστήριξης I2C από τον Linux Kernel ........................................................................ 87
Ενεργοποίηση υποστήριξης I2C µέσω GPIO από τον Linux Kernel .................................................... 87
Ενεργοποίηση υποστήριξης SPI από τον Linux Kernel ........................................................................ 94
Γραφική αναπαράσταση της λειτουργίας του υποσυστήµατος TTY ................................................... 107
Ενεργοποίηση υποστήριξης GPIO από τον Linux Kernel................................................................... 108
Ενεργοποίηση του Linux LED Framework .......................................................................................... 113
Σύνδεση DataFlash µε µικροελεγκτή µέσω SPI .................................................................................. 116
Ενεργοποίηση υποστήριξης συσκευών MTD από τον Linux Kernel................................................... 118
Ενεργοποίηση CFI driver για την ανάγνωση µνηµών Flash ............................................................... 119
Ενεργοποίηση υποστήριξης µνηµών AT45xxx της Atmel από τον Linux Kernel................................ 119
Ενεργοποίηση υποστήριξης συστήµατος αρχείων JFFS2 από τον Linux Kernel............................... 120
Η ενσωµατωµένη στοίβα TCP/IP του Linux Kernel............................................................................. 126
Το µοντέλο επικοινωνίας client – server ............................................................................................. 133
Γραφική αναπαράσταση της χρήσης Sockets από εφαρµογες Linux ................................................. 136
Η εντολή route στον Router NGW100................................................................................................. 140
Η εντολή ifconfig στον Router NGW100.............................................................................................. 140
Η εντολή ping στον Router NGW100 .................................................................................................. 144
Ανάλυση κεφαλίδας IP µέσω του αναλυτή πακέτων Wireshark.......................................................... 145
Μπλοκ διάγραµµα του υλικού του Router NGW100 ........................................................................... 156
Το το package του µικροελεγκτή AP7000 ........................................................................................... 158
Οπτική αναγνώριση των µνηµών του Router NGW100...................................................................... 159
Η παράλληλη µνήµη AT49BV642D-70TU........................................................................................... 160
Η σειριακή µνήµη AT45DB642D ......................................................................................................... 161
Η µνήµη SDRAM MT48LC16M16A2................................................................................................... 161
∆ιασύνδεση µνήµης SDRAM µε µικροελεγκτή αρχιτεκτονικής AVR32 ............................................... 162
Η ιεραρχία µνήµης του Router NGW100 και τα σηµεία φόρτωσης του Linux..................................... 163
Το ολοκληρωµένο DP83848I (Ethernet PHY) ..................................................................................... 165
θύρες LAN και WAN, Ethernet controllers και ο µικροελεγκτής AP7000 ............................................ 166
Η θύρα Ethernet J3026G01DNL ......................................................................................................... 166
Σύνδεση του ολοκληρωµένου DP83848I (Ethernet PHY) µε τον µικροελεγκτή AP7000 .................... 167
11
Η διάταξη των ακροδεκτών (pinout) του ολοκληρωµένου DP83848I (Ethernet PHY) ........................ 168
Το ολοκληρωµένο MAX3232ECAE+................................................................................................... 169
Η διάταξη των ακροδεκτών του ολοκληρωµένου MAX3232ECAE+ ................................................... 169
Ο µικροελεγκτής ATtiny24-20SSU (board controller).......................................................................... 169
Η διάταξη των ακροδεκτών του µικροελεγκτή ATtiny24-20SSU ......................................................... 170
Η συνδεσµολογία του ATtiny24 µε τον µικροελεγκτή AP7000 ............................................................ 170
Η διάταξη των ακροδεκτών JTAG ....................................................................................................... 172
10 pin Header για σύνδεση JTAG ....................................................................................................... 172
Σχηµατικό σύνδεσης του 10 pin Header µε τον µικροελεγκτή AP7000.............................................. 172
Σχηµατικό σύνδεσης του εξωτερικού ρολογιού (external clock) µε τον µικροελεγκτή AP7000........... 173
Χαµηλοπερατό σύστηµα φιλτραρίσµατος συχνοτήτων (PLL low-pass filter) ...................................... 173
Το κύκλωµα επαναφοράς (reset) του Router NGW100 ...................................................................... 174
Ο διακόπτης reset SKHUAF010.......................................................................................................... 174
Το τροφοδοτικό του Router NGW100 ................................................................................................. 175
Η θύρα τροφοδοσίας RASM722P ....................................................................................................... 175
Το εσωτερικό κύκλωµα µετατροπής τάσης ......................................................................................... 176
Η γέφυρα ανόρθωσης τεσσάρων διόδων DF10S ............................................................................... 176
θεωρητική γραφική αναπαράσταση της λειτουργίας µιας γέφυρας ανόρθωσης................................. 176
Το ολοκληρωµένο LM2717 (DC/DC converter) .................................................................................. 177
Η διάταξη των ακροδεκτών του ολοκληρωµένου LM2717 .................................................................. 177
Το µηχανικό σχέδιο του PCB του Router NGW100 ............................................................................ 178
Το σχέδιο συναρµολόγησης του Router NGW100.............................................................................. 179
Επέκταση δυνατοτήτων υλικού του Router NGW100 ......................................................................... 181
Τα περιεχόµενα του πακέτου Atmel Linux BSP 3.0 ............................................................................ 183
Τα αρχεία εγκατάστασης του περιβάλλοντος ανάπτυξης.................................................................... 185
Τα περιεχόµενα του αρχείου rousis_toolchain.tar.gz .......................................................................... 185
Η εφαρµογή VMware µε εγκατεστηµένη την εικονική µηχανή Ubuntu 9.04 (jaunty) + AVR32 ........... 186
Τα αρχεία από τα οποία αποτελείται µια εικονική µηχανή στο VMware Player .................................. 186
Η επιφάνεια εργασίας του τελικού εικονικού συστήµατος ανάπτυξης host ......................................... 187
Τα αρχεία εγκατάστασης του περιβάλλοντος ανάπτυξης.................................................................... 188
Τα περιεχόµενα του καταλόγου binaries του συστήµατος Buidroot.................................................... 191
Τα περιεχόµενα του συµπιεσµένου αρχείου rootfs.avr32.tar.bz2 ....................................................... 192
Παράθυρο διαλόγου µετά την εγκατάσταση της µηχανής JAVA ......................................................... 194
Η αρχική οθόνη φόρτωσης του AVR32 Studio.................................................................................... 194
Παράθυρο διαλόγου για την επιλογή καταλόγου εργασίας του AVR32 Studio ................................... 195
Tο κεντρικό περιβάλλον εργασίας του AVR32 Studio......................................................................... 195
Η συσκευή programmer - emulator JTAGICE mkII της Atmel............................................................. 198
Η καλωδιοταινία σύνδεσης JTAG probe ............................................................................................. 199
Η διεπαφή υλικού JTAG του Router NGW100.................................................................................... 199
Σύνδεση της συσκευής JTAGICE mkII µε τον Router NGW100 ......................................................... 200
Θύρες, USB, RS232 και τροφοδοσίας στο πίσω µέρος της συσκευής JTAGICE mkII....................... 200
∆ιάγραµµα σύνδεσης του συστήµατός host µε τον Router NGW100 ................................................. 200
Εκτέλεση της εντολής cpuinfo –F µέσω του προγράµµατος avr32program και του JTAGICE mkII ... 201
Εκτέλεση της εντολής readregs µέσω του προγράµµατος avr32program και του JTAGICE mkII...... 202
Eκκαθάριση της παράλληλης µνήµης Flash µέσω του JTAGICE mkII ............................................... 202
Εγγραφή του λογισµικού εκκίνησης στην παράλληλη µνήµη µέσω του JTAGICE mkII ..................... 202
Καλώδιο σειριακής επικοινωνίας RS232............................................................................................. 203
Παράµετροι σειριακής επικοινωνίας της εφαρµογής PuTTY............................................................... 203
Το command prompt του U-Boot......................................................................................................... 204
Εκτλελεση της εντολής help στο U-Boot ............................................................................................. 205
Εκτλελεση της εντολής flinfo στο U-Boot............................................................................................. 206
Εγγραφή Linux Kernel στην παράλληλη µνήµη µέσω του JTAGICE mkII.......................................... 206
SanDisk MMC/SD-card ....................................................................................................................... 207
Εγγραφή συστήµατος αρχείων /usr από την SD-card µέσω της εντολής dd ...................................... 208
∆ιαδικασία εκκίνησης στάδιο 1 ............................................................................................................ 210
∆ιαδικασία εκκίνησης στάδιο 2 ............................................................................................................ 211
∆ιαδικασία εκκίνησης στάδιο 3 ............................................................................................................ 211
∆ιαδικασία εκκίνησης στάδιο 4 ............................................................................................................ 212
∆ιαδικασία εκκίνησης στάδιο 5 ............................................................................................................ 212
∆ιαδικασία εκκίνησης στάδιο 6 ............................................................................................................ 212
12
∆ιαδικασία εκκίνησης στάδιο 7 ............................................................................................................ 213
∆ιαδικασία εκκίνησης στάδιο 8 ............................................................................................................ 214
∆ιαδικασία εκκίνησης στάδιο 9 ............................................................................................................ 214
∆ιαδικασία εκκίνησης στάδιο 10 .......................................................................................................... 215
∆ιαδικασία εκκίνησης στάδιο 11 .......................................................................................................... 215
∆ιαδικασία εκκίνησης στάδιο 12 .......................................................................................................... 216
Ολοκλήρωση διαδικασίας εκκίνησης – έναρξη γραµµής εντολών BusyBox ....................................... 216
Καλώδιο συνεστραµµένων ζευγών UTP cat5e ................................................................................... 218
∆ηµιουργία άδειου αρχείου στην Ubuntu 9.04 .................................................................................... 219
Τα αρχεία του καταλόγου application µετά τη µεταγλώττιση του hello.c............................................. 219
Μεταφορά της εφαρµογής hello στον Router NGW100 µέσω εντολών FTP ..................................... 220
Εκτέλεση της δοκιµαστικής εφαρµογής hello µέσω Telnet ................................................................. 220
Παράθυρο διαλόγου µετά την εκτέλεση του αρχείου AVR32-Studio.sh µε διπλό κλικ........................ 221
Το κεντρικό περιβάλλον εργασίας του AVR32 Studio......................................................................... 222
AVR32 Studio - ∆ηµιουργία νέου C project – Βήµα 1 ......................................................................... 222
AVR32 Studio - ∆ηµιουργία νέου C project – Βήµα 2 ......................................................................... 223
AVR32 Studio - ∆ηµιουργία νέου αρχείου πηγαίου κώδικα C ............................................................ 224
AVR32 Studio - Περιεχόµενα καταλόγου Debug για το project "dokimastiki-efarmogi" ...................... 224
Μεταφορά αρχείου dokimastiki-efarmogi.elf στον Router NGW100 µέσω του FileZilla FTP client .... 225
Εκτέλεση της δοκιµαστικής εφαρµογής hello µέσω του τερµατικού PuTTY ....................................... 226
Buildroot – Πακέτο λογισµικού webif ................................................................................................... 228
Buildroot - Τα περιεχόµενα του καταλόγου package/webif ................................................................. 229
Εκτέλεση της εντολής busybox στον Router NGW100 ....................................................................... 232
Εκτέλεση της εντολής ethtool για τη διεπαφή eth1.............................................................................. 245
Βοήθεια για την εντολή brctl της εφαρµογής bridge ............................................................................ 245
13
Ευρετήριο πινάκων
Τα προγράµµατα του πακέτου binutils .................................................................................................. 46
Εντολές Linux ........................................................................................................................................ 65
Flags και λειτουργία της συνάρτησης at32_select_gpio ....................................................................... 89
Παράµετροι λειτουργίας της µνήµης SDRAM...................................................................................... 162
Χάρτης φυσικών διευθύνσεων του AP7000 ....................................................................................... 164
Η διαθέσιµη µνήµη του Router NGW100 ............................................................................................ 164
Λεπτοµέρειες σύνδεσης των Ethernet PHYs ...................................................................................... 165
Οι MAC διευθύσεις του Router NGW100 ............................................................................................ 168
Μηνύµατα απόκρισης του PMbus ....................................................................................................... 171
Η διαµόρφωση των φίλτρων PLL ........................................................................................................ 174
14
Ευχαριστίες
Θα ήθελα να ξεκινήσω ευχαριστώντας τους γονείς µου, Θανάση και Μαργαρίτα Ρούση, καθώς και τον αδερφό µου Άγγελο Ρούση, γιατί είναι πάντα εκεί για ‘µένα και µε υποστηρίζουν
σε όλες µου τις προσπάθειές.
Επιπλέον θα ήθελα να ευχαριστήσω την Ελένη Βασιλάκη, για την πολυδιάστατη και ουσιαστική στήριξη που µου πρόσφερε κατά τη διάρκεια της σχεδίασης, της ανάπτυξης και της
συγγραφής της εργασίας αυτής.
Ιδιαίτερα ευχαριστώ τον επιβλέποντα καθηγητή µου, κύριο ∆ηµήτρη Φωτιάδη, για την υποµονή, την πολύτιµη βοήθειά του και την κατανόησή του, όλους αυτούς τους µήνες. Αλλά και
το ΑΤΕΙ ∆υτικής Μακεδονίας για ότι καλό µου προσέφερε κατά τη διάρκεια της φοίτησής µου.
Ευχαριστώ τον Linus Torvalds, τον δηµιουργό του Linux Kernel και το ίδρυµα ελεύθερου
λογισµικού FSF (Free Software Foundation) και τον ιδρυτή του Richard Stallman, για όλη
τους τη συνεισφορά στην επιστήµη των υπολογιστών. Χωρίς αυτούς η παρούσα εργασία
απλά δεν θα υπήρχε.
Ευχαριστώ την εταιρεία Atmel για τα άρτια εργαλεία της, την τεκµηρίωσή της και το ευγενικό
της helpdesk. Επίσης ευχαριστώ πολύ την κοινότητα και το forum των AVR Freaks (ιδιαίτερα
τον χρήστη hce), όπου καµία απορία και κανένα πρόβληµα δεν µένουν αναπάντητα.
Τέλος, ευχαριστώ την µηχανή αναζήτησης Google η οποία µου έλυσε τα χέρια, τόσο σε επίπεδο εύρεσης απαραίτητων πληροφοριών, όσο και για την άψογη υπηρεσία µετάφρασης
που παρέχει.
15
Περίληψη
Η εργασία αυτή αφορά την διαδικασία υλοποίησης του οικιακού δροµολογητή Router
NGW100, ο οποίος είναι σε θέση να συνδέει τους υπολογιστές ενός τοπικού δικτύου µε το
Internet. Η δροµολόγηση των πακέτων από και προς το τοπικό δίκτυο, γίνεται µε ασφάλεια
και αξιοπιστία µέσω ειδικού λογισµικού. Η απόδοση του Router NGW100 είναι τέτοια, ώστε
να µπορεί να υποστηρίζει έναν αξιοπρεπή ρυθµό µετάδοσης για κάθε συνδεδεµένο σε αυτόν,
σύστηµα. Επίσης παρέχονται διεπαφές διαχείρισης και παραµετροποίησης του router, τόσο
σε επίπεδο γραµµής εντολών, µέσω των πρωτοκόλλων Telnet και SSH, όσο και σε επίπεδο
γραφικού περιβάλλοντος, µέσω του Web interface. Στην πρώτη περίπτωση απαιτούνται εξειδικευµένες γνώσεις από τον διαχειριστή, αλλά παρέχεται µεγαλύτερη ευελιξία και πιο προχωρηµένος έλεγχος. Στην δεύτερη περίπτωση, το περιβάλλον διαχείρισης είναι ιδιαιτέρα
εύκολο και φιλικό προς το χρήστη, καθώς απαιτείται απλά ένας φυλλοµετρητής και το ποντίκι
του υπολογιστή.
16
Εισαγωγή
Ουσιαστικά, η παρούσα εργασία, αποτελεί µια προσπάθεια δηµιουργίας του συγγράµµατος
το οποίο θα ήταν πολύ χρήσιµο και επιθυµητό να υπάρχει έτοιµο, από την πρώτη στιγµή. Η
ελληνική βιβλιογραφία είναι πολύ περιορισµένη σε ότι αφορά την επιστήµη των υπολογιστών. Εποµένως χρειάστηκαν εκατοντάδες ώρες µελέτης αγγλόφωνων συγγραµµάτων αλλά
και αναζήτησης στο ∆ιαδίκτυο.
Πολλά κεφάλαια τα οποία γράφτηκαν µε πολύ κόπο, δεν υπάρχουν εδώ, αφού αφαιρέθηκαν
λόγω περιεχοµένου που έβγαινε εκτός θέµατος. Επίσης πολλά κεφάλαια ξαναγράφτηκαν απ’
την αρχή. Αυτό συνέβη επειδή αρχικά δεν υπήρχε κάποιο προκαθορισµένο σχεδιάγραµµα.
Ήταν αδύνατο να υπάρχει. Το αντικείµενο των ενσωµατωµένων συστηµάτων Linux ήταν
πρωτόγνωρο και τα θέµατα που το αφορούσαν, άπειρα.
Η αφαίρεση περιττών πληροφοριών απαιτεί καλή γνώση του αντικειµένου του οποίου αναλύεται κάθε φορά. Για να είναι κάτι τέτοιο δυνατόν, θα πρέπει να υπάρχει το απαραίτητο και
προαπαιτούµενο θεωρητικό υπόβαθρο. Αυτό θα επιτρέψει την επικέντρωση της ανάλυσης
στα σηµαντικότερα θέµατα και όχι σε δευτερεύοντα ζητήµατα.
Το προαπαιτούµενο θεωρητικό υπόβαθρο
Η συγγραφή µιας πτυχιακής εργασίας η οποία αφορά την υλοποίηση ενός δροµολογητή
είναι ένα γιγάντιο εγχείρηµα για τις γνώσεις ενός προπτυχιακού φοιτητή. Το θεωρητικό υπόβαθρο το οποίο προαπαιτείται, είναι πολύ συνοπτικά το παρακάτω:
Θεωρία λειτουργικών συστηµάτων
Τοπικά δίκτυα και δίκτυα ευρείας περιοχής
Πρωτόκολλα δροµολόγησης
Το λειτουργικό σύστηµα Linux
Linux Kernel 2.6
Λογισµικό εκκίνησης
Το ενσωµατωµένο Linux
Αυτοµατοποιηµένα συστήµατα ανάπτυξης (πχ: Buildroot)
Το TCP/IP στον Linux kernel
Οικιακοί δροµολογητές (τρόπος λειτουργίας και διαχείριση)
Προγραµµατισµός στον φλοιό του Linux
∆ιερµηνευτικές γλώσσες (πχ: Perl και awk)
Γλώσσες προγραµµατισµού Assembly και C
Ανάπτυξη εφαρµογών Linux
Ανάπτυξη διεπαφών χρήστη (πχ: Web Interface)
Οδηγοί συσκευών Linux
Πρωτόκολλα και διεπαφές επικοινωνίας υλικού (πχ: SPI, I2C κλπ)
Ενσωµατωµένα συστήµατα – σχεδίαση µε µικροελεγκτή
Θεωρία ηλεκτρονικής
Ψηφιακή σχεδίαση
Μετρήσεις
Σχεδίαση Σχηµατικού – PCB, µε λογισµικό CAD
Απαιτείται πολύ βαθειά αντίληψη της λειτουργίας του υλικού αλλά και του λογισµικού. Επίσης απαιτείται αντίληψη του πως αυτά τα δύο συνενώνονται ώστε να αποτελούν ένα σύστηµα που λειτουργεί και φέρει εις πέρας χρήσιµες λειτουργίες.
17
Η λίστα που παρατέθηκε πιο πάνω είναι όπως είπαµε, πολύ συνοπτική. Αυτό είναι εύκολο
να το αντιληφθεί κανείς αν αναφερθεί για παράδειγµα, ότι για τη σχεδίαση του Router
NGW100 χρησιµοποιήθηκαν ακόµα και γλώσσες Web, όπως HTML, JavaScript και CSS.
Το βασικότερο τµήµα λογισµικού το οποίο απασχόλησε σε αρκετά µεγάλο µέρος της εργασίας, είναι το ενσωµατωµένο Linux. Το ενσωµατωµένο Linux και πιο συγκεκριµένα ο Linux
Kernel, µπορεί να έχει γραφτεί σε γλώσσα C, όµως οι ειδικοί µηχανισµοί του αποτελούνται
από χιλιάδες συναρτήσεις και περίπλοκες δοµές δεδοµένων, που το κάνουν να µοιάζει µε µια
ξεχωριστή και ανεξάρτητη γλώσσα προγραµµατισµού.
Κατά τη διάρκεια της υλοποίησης του δροµολογητή Router NGW100, χρησιµοποιήθηκαν
και τα Windows αλλά και το Linux ως συστήµατα ανάπτυξης. Το ένα λειτουργικό σύστηµα,
κάλυπτε τα κενά του άλλου. Ταυτόχρονα όµως, γινόταν και µια πιο σφαιρική προσέγγιση των
διαθέσιµων επιλογών ανάπτυξης ενσωµατωµένων συστηµάτων Linux.
Στο κείµενο της παρούσας εργασίας δεν αναφέρονται µονό τα εργαλεία που χρησιµοποιήθηκαν κατά την ανάπτυξη αλλά και κάποια επιπλέον, εξίσου δηµοφιλή και αποτελεσµατικά.
Αυτό γίνεται για να δοθεί η ευκαιρία σε οποίον διαβάσει κάποια στιγµή την εργασία, να αποφασίσει για το ποιο εργαλείο του ταιριάζει περισσότερο ανάλογα µε τις ιδιαίτερες απαιτήσεις
του συστήµατος που πρόκειται να υλοποιήσει. Για τον ίδιο σκοπό δηµιουργήθηκε και ειδική
ιστοσελίδα για την οποία υπάρχουν περισσότερες λεπτοµέρειες σε αντίστοιχο παράρτηµα.
∆οµή εργασίας
Η εργασία χωρίζεται σε τρία κύρια µέρη:
Θεωρητικό µέρος
Πρακτικό µέρος
Παραρτήµατα
Θεωρητικό µέρος
Στο θεωρητικό µέρος παρατίθεται το βασικό υπόβαθρο που αφορά τα ενσωµατωµένα συστήµατα Linux και τις δυνατότητες δικτύωσής τους. Πιο συγκεκριµένα, το θεωρητικό µέρος
αποτελείται από τα εξής κεφάλαια:
1ο Κεφάλαιο – Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux
2ο Κεφάλαιο – Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux
3ο Κεφάλαιο – Το υλικό που υποστηρίζει το ενσωµατωµένο Linux
4ο Κεφάλαιο – ∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux
Στο πρώτο κεφάλαιο γίνεται εισαγωγή στα ενσωµατωµένα συστήµατα Linux. Αναφέρονται
οι έτοιµες διανοµές ενσωµατωµένου Linux, τα εργαλεία ανάπτυξης και οι σηµαντικότεροι
προµηθευτές τους. Γίνεται µια γενική περιγραφή της µεθοδολογίας ανάπτυξης ενσωµατωµένων συστηµάτων Linux. Εξετάζονται οι τύποι ανάπτυξης, όπου αναφέρεται για πρώτη φορά
το µοντέλο host – target. Αναλύονται επιφανειακά έννοιες που αφορούν την εκκίνηση, τη διαχείριση της µνήµης και την αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux.
Στο δεύτερο κεφάλαιο δίνεται έµφαση στην ανάλυση των εργαλείων ανάπτυξης ενσωµατωµένων συστηµάτων Linux. Εισάγεται η έννοια της διασταυρούµενης αλυσίδας µεταγλώττισης,
και της τοπικής µεταγλώττισης. Περιγράφεται το αυτοµατοποιηµένο σύστηµα Buildroot και η
παραµετροποίηση της βιβλιοθήκης uClibc, του Linux Kernel, του πολυεργαλείου BusyBox,
καθώς και του ίδιου του Buildroot, προκειµένου να µπορεί να δηµιουργηθεί το λογισµικό που
18
θα εκτελείται στον Router NGW100. Επίσης, γίνεται αναφορά στη γραµµή εντολών, τις εντολές shell, τους προσοµοιωτές τερµατικού και τα γραφικά περιβάλλοντα ανάπτυξης IDEs.
Το τρίτο κεφάλαιο αφορά το υλικό που υποστηρίζει το ενσωµατωµένο Linux. Αφού γίνει µια
συνοπτική περιγραφή των διαφόρων αρχιτεκτονικών µικροελεγκτών που υποστηρίζει ο Linux
Kernel, ακολουθεί µια αρκετά λεπτοµερής ανάλυση των οδηγών συσκευών. Επειδή ένας οδηγός συσκευής είναι δυνατόν να φορτώνεται και κατά τη διάρκεια εκτέλεσης του Kernel, ως
module, παρουσιάζεται αντίστοιχο παράδειγµα. Αµέσως µετά αναλύονται οι σηµαντικότεροι
δίαυλοι και οι σηµαντικότερες διεπαφές υλικού που εντοπίζονται συχνότερα στα ενσωµατωµένα συστήµατα Linux και ειδικότερα στον Router NGW100. Τέλος παρατίθενται ορισµένες
πληροφορίες σχετικά µε την επικοινωνία µε την µνήµη και γίνεται µια εισαγωγή για το επόµενο κεφάλαιο το οποίο αφορά την δικτύωση ενσωµατωµένων συστηµάτων Linux.
Στο τέταρτο κεφάλαιο, το οποίο είναι και το τελευταίο του θεωρητικού µέρους, παρουσιάζεται συνοπτικά η δικτύωση και η δροµολόγηση στα ενσωµατωµένα συστήµατα Linux. Σε αυτό
το κεφάλαιο υπάρχουν θεµελιώδεις έννοιες της δικτύωσης. Μία από αυτές είναι και η στοίβα
TCP/IP. Μία άλλη, είναι τα Linux sockets. Επίσης γίνεται αναφορά στα πρωτόκολλα ARP,
ICMP και IGMP. Το κεφάλαιο ολοκληρώνεται µε την ανάλυση των οδηγών δικτύου και την
απόδοση δικτύωσης του µικροελεγκτή AP7000. Στην παράγραφο που αφορά τους οδηγούς
δικτύου παρουσιάζεται και ο οδηγός MACB που χρησιµοποιεί ο Router NGW100 για την επικοινωνία του µέσω Ethernet. Ο κώδικας του συγκεκριµένου οδηγού απασχολεί και ένα ολόκληρο παράρτηµα της εργασίας αυτής.
Πρακτικό µέρος
Στο πρακτικό µέρος αναλύεται εκτενώς το υλικό και το λογισµικό από το οποίο αποτελείται
ο Router NGW100. Αποτελείται από τα εξής κεφάλαια:
5ο Κεφάλαιο – Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100
6ο Κεφάλαιο – Προγραµµατισµός και εκκίνηση του Router NGW100
7ο Κεφάλαιο – Οι εφαρµογές του Router NGW100
Στο πέµπτο κεφάλαιο, τα ηλεκτρικά και τα ηλεκτρονικά χαρακτηριστικά του Router
NGW100, παρουσιάζονται µέσω της περιγραφής των λεπτοµερειών των αντίστοιχων ηλεκτρικών και ηλεκτρονικών στοιχείων, που βρίσκονται συγκολληµένα στο PCB του. Τα σηµαντικότερα από αυτά είναι: ο µικροελεγκτής AP7000, η µνήµη, το Ethernet PHY, το
ολοκληρωµένο για την επικοινωνία RS232 µε τον υπολογιστή, ο ελεγκτής πλακέτας, η διεπαφή προγραµµατισµού JTAG, τα συστήµατα χρονισµού και reset, και το σύστηµα τροφοδοσίας της πλακέτας. Κάποια λογικά διαγράµµατα που επίσης παρουσιάζονται, προσδίδουν
µια επιπλέον κατανόηση για το υλικό του Router NGW100 αλλά και για τον τρόπο επικοινωνίας του υλικού αυτού µε τον Kernel και το υπόλοιπο λογισµικό. Επίσης παρουσιάζονται ορισµένα από τα κυριότερα µηχανικά χαρακτηριστικά, καθώς και το σχέδιο συναρµολόγησης.
Το έκτο κεφάλαιο είναι πολύ σηµαντικό καθώς για πρώτη φορά το σύστηµά µας αποκτά
κάποια επαφή µε το περιβάλλον. Σε αυτό πραγµατοποιούνται ο προγραµµατισµός και η εκκίνηση του Router NGW100. Βήµα προς βήµα, παρουσιάζονται όλες οι ενέργειες που έγιναν
για τη δηµιουργία του περιβάλλοντος ανάπτυξης host AVR32. Για παράδειγµα, αναφέρεται το
πώς χρησιµοποιήθηκε το πακέτο BSP της ATMEL προκειµένου να είναι διαθέσιµα εξειδικευµένα εργαλεία και εξειδικευµένος κώδικας που αφορά το υλικό. Επίσης βήµα προς βήµα,
παρουσιάζεται και ό τρόπος µεταφοράς του λογισµικού εκκίνησης, του Linux Kernel, και του
περιβάλλοντος – συστήµατος αρχείων, χρήστη. Σε αυτό το σηµείο ο Router NGW100 µπορεί πλέον να αλληλεπιδρά µε το σύστηµα ανάπτυξης host και µε το δίκτυο.
19
Στο έβδοµο κεφάλαιο βρισκόµαστε στο τελικό στάδιο της εργασίας. Είµαστε σε θέση πλέον
να γράφουµε εφαρµογές που θα εκτελούνται “επάνω” από τον Linux Kernel του Router
NGW100. Αρχικά παρουσιάζεται ένα παράδειγµα ανάπτυξης της στοιχειώδους εφαρµογής
hello.c, η οποία παρά το ότι, το µόνο που κάνει, είναι να εµφανίζει το µήνυµα Hello
World!, αποτελεί ταυτόχρονα απόδειξη της σωστής λειτουργίας της διασταυρούµενης αλυσίδας µεταγλώττισης. Αµέσως µετά, δίνεται άλλο ένα παράδειγµα το οποίο όµως αφορά την
προσθήκη πακέτου λογισµικού στο αυτοµατοποιηµένο σύστηµα Buildroot. Αυτό λειτουργεί
ως εισαγωγή και ως µέσο κατανόησης, για να παρατεθούν έπειτα όλες οι εγκατεστηµένες
εφαρµογές του Router NGW100. Μία από αυτές είναι και η webif στην οποία βασίζεται η
ανάπτυξη του Web interface.
Παραρτήµατα
Στα παραρτήµατα γίνεται µια προσπάθεια να δοθούν κάποιες επιπλέον λεπτοµέρειες σχετικά µε τον Router NGW100. Τα παραρτήµατα είναι συνολικά τρία:
Παράρτηµα A – Το σχηµατικό του Router NGW100
Παράρτηµα B – Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB
Παράστηµα C – Το πακέτο RBSP και o ιστότοπος MyThesis.org
20
ΘΕΩΡΗΤΙΚΟ ΜΕΡΟΣ
21
ΚΕΦΑΛΑΙΟ
1
Ανάπτυξη Ενσωµατωµένων
Συστηµάτων Linux
Εισαγωγή
Παρά την ευρεία χρήση του Linux σε κινητά, οχήµατα, αεροσκάφη, αµυντικά όπλα, διαστηµικές αποστολές κλπ, υπάρχει πολύ µικρή βάση τεκµηριωµένης γνώσης για τη δηµιουργία,
την εγκατάσταση και τον έλεγχο του Linux Kernel και των εργαλείων που χρησιµοποιούνται
κατά την ανάπτυξη ενός ενσωµατωµένου συστήµατος Linux (Embedded Linux System).
Έτσι, πριν προχωρήσουµε στην ανάπτυξη ενός τέτοιου συστήµατος θα πρέπει πρώτα να
έχουµε κατανοήσει µια γενικότερη εικόνα. Σε αυτό το κεφάλαιο παρατίθενται κάποιες απαραίτητες γενικές γνώσεις που καλύπτουν το βασικό θεωρητικό υπόβαθρο ανάπτυξης ενσωµατωµένων συστηµάτων Linux και οι οποίες βοηθούν στην κατανόηση των παρακάτω θεµάτων:
Τι είναι το Linux
Το ενσωµατωµένο Linux
Οι τύποι των ενσωµατωµένων συστηµάτων Linux
Γιατί να προτιµήσουµε το Linux
Έτοιµες διανοµές και εργαλεία ανάπτυξης
Μεθοδολογία σχεδίασης και ανάπτυξης
Εργαλεία ανάπτυξης και αποσφαλµάτωσης
Επίσης θα εξετάσουµε κάποιες βασικές έννοιες που αφορούν τους τρόπους ανάπτυξης ενσωµατωµένων συστηµάτων Linux και θα παραθέσουµε πληροφορίες που αφορούν πιο εσωτερικά στοιχεία τους:
Οι τύποι ανάπτυξης
Οι τύποι αποσφαλµάτωσης
Η αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux
Εκκίνηση συστήµατος
Μονάδα διαχείρισης µνήµης (MMU)
∆ιαχείριση δευτερεύουσας µνήµης
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
1.1 Τι είναι το Linux
Το Linux είναι ένα Λειτουργικό Σύστηµα το οποίο δηµιουργήθηκε αρχικά από τον Linus Torvalds και τον οργανισµό FSF (Free Software Foundation) υπό την άδεια GNU (General Public License). Ο πυρήνας του Linux παρέχει µια µεγάλη ποικιλία βασικών λειτουργιών οι
οποίες απαιτούνται από κάθε σύστηµα για να λειτουργήσει σωστά. Ένα επίπεδο πιο «πάνω»
από τον πυρήνα βρίσκεται το λογισµικό εφαρµογών το οποίο βασίζεται σε συγκεκριµένες λειτουργίες του πυρήνα. Οι λειτουργίες αυτές αφορούν τον χειρισµό των συσκευών και την παροχή µιας ποικιλίας επιπέδων αφαίρεσης (abstraction layers), όπως είναι η εικονική µνήµη
(virtual memory), οι διεργασίες (tasks ή processes), τα sockets, τα συστήµατα αρχείων κλπ.
Για την εκκίνηση του πυρήνα του Linux χρησιµοποιείται συνήθως κάποιο εξειδικευµένο λογισµικό εκκίνησης.
Στις µέρες µας, ο όρος “Linux” είναι κάπως συγκεχυµένος λόγω της ολοένα και αυξανόµενης δηµοτικότητάς του καθώς και της καθηµερινής του χρήσης από ανθρώπους οι οποίοι δεν
είναι ειδικοί. Συνήθως ο όρος Linux χρησιµοποιείται εναλλακτικά όταν κάποιος θέλει να αναφερθεί είτε στον πυρήνα του Linux, είτε σε ένα σύστηµα Linux, είτε σε µια εφαρµογή που έχει
στηθεί επάνω στον πυρήνα του Linux.
Στη εργασία αυτή όταν θα αναφέρουµε τον όρο «Linux» θα εννοούµε τον πυρήνα του και τις
εφαρµογές µας, αν αναφερόµαστε στο σύστηµά µας που θα είναι ο Router, ενώ θα εννοούµε
κάποια διανοµή µε γραφικό περιβάλλον (πχ: Ubuntu), αν αναφερόµαστε στο σύστηµα ανάπτυξης που θα είναι κάποιος προσωπικός υπολογιστής ο οποίος θα περιέχει τα απαραίτητα
εργαλεία ανάπτυξης. Όλα αυτά θα γίνονται όλο και πιο κατανοητά στη συνέχεια.
Οι διανοµές Linux διαφέρουν στο σκοπό, το κόστος και το µέγεθος αλλά έχουν τον ίδιο στόχο. Ο στόχος είναι να παρέχουν στον τελικό χρήστη ένα προ-συσκευασµένο και συµπυκνωµένο σετ αρχείων και έναν µηχανισµό εγκατάστασης έτσι ώστε να µπορεί να εγκατασταθεί ο
πυρήνας και οι εφαρµογές, σε διάφορες αρχιτεκτονικές και για διάφορους σκοπούς.
1.2 Το ενσωµατωµένο Linux
Το ενσωµατωµένο Linux τυπικά αναφέρεται σε ένα πλήρες σύστηµα ή σε µια διανοµή που
είναι στοχευµένη για ενσωµατωµένα συστήµατα. Παρ’ όλο που ο όρος “ενσωµατωµένο” υποδηλώνει µια ειδική έκδοση Linux, δεν υπάρχει κάποιος ειδικός τύπος του Linux kernel για
εφαρµογές σε ενσωµατωµένα συστήµατα. Ο ίδιος πηγαίος κώδικας του πυρήνα που χρησιµοποιείται σε PCs ή σε Servers, µεταγλωττίζεται και για όλα τα είδη των διάφορων συστηµάτων που τον χρησιµοποιούν. Υπάρχουν όµως κάποιες παράµετροι που µπορούν να
τροποποιούνται κατά τη µεταγλώττιση ώστε να αφαιρούνται περιττά χαρακτηριστικά και να
προσθέτονται άλλα που είναι χρήσιµα. Για παράδειγµα, η υποστήριξη για terabytes µνήµης
σε ένα ενσωµατωµένο σύστηµα είναι εντελώς περιττή και µπορεί να αφαιρεθεί.
Στα πλαίσια της ανάπτυξης ενσωµατωµένων συστηµάτων Linux, γίνεται χρήση µιας σειράς
από λογισµικά. Εκτός από τις δωρεάν εκδοχές, υπάρχει και µία αρκετά µεγάλη ποικιλία εµπορικών διανοµών ενσωµατωµένου Linux που σχεδιάζονται ειδικά για ενσωµατωµένα συστήµατα. Οι διανοµές αυτές παράγονται από κάποιους εξειδικευµένους προµηθευτές. Οι πιο
σηµαντικοί από αυτούς είναι οι: MontaVista, Wind River, Lynuxworks, Timesys και Denx. Τα
εργαλεία που αναπτύσσονται από αυτές τις εταιρείες είναι: cross-compilers, debuggers, εφαρµογές διαχείρισης έργων (projects), boot image builders κλπ. Αυτό είναι ουσιαστικά και
αυτό που πληρώνουµε σε αυτές τις εταιρείες όταν στρεφόµαστε σε κάποια έτοιµη λύση.
Το αν θα χρησιµοποιήσουµε κάποια έτοιµη λύση βέβαια, εξαρτάται καθαρά από τις οικονοµικές µας δυνατότητες και τις ειδικές µας γνώσεις στο αντικείµενο. Στα πλαίσια αυτής της εργασίας προτιµήθηκαν οι δωρεάν λύσεις. Οπότε χρειάστηκε να χτίσουµε τα δικά µας εργαλεία
Ιστότοπος εργασίας: MyThesis.org
23
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
και την δική µας προσαρµοσµένη διανοµή Linux. Αυτό, αν και απαίτησε υπερβολικά πολύ
χρόνο, τελικά προσέφερε καλύτερη κατανόηση και µεγαλύτερη ανεξαρτησία. Τα πλεονεκτήµατα όµως της επιλογής έτοιµων λύσεων θα είναι πάντα η τεράστια εξοικονόµηση χρόνου και
η τεχνική υποστήριξη που παρέχεται.
1.3 Οι τύποι των ενσωµατωµένων συστηµάτων Linux
Η κατηγοριοποίηση των ενσωµατωµένων συστηµάτων Linux δεν είναι εύκολο να γίνει µε
βάση την εφαρµογή τους. Για να εντοπιστούν πραγµατικές διαφορές θα πρέπει να βρούµε
κάποια κριτήρια που θα παρέχουν πληροφορίες σχετικά µε τη δοµή του κάθε συστήµατος.
Τα κριτήρια αυτά είναι:
Το µέγεθος
Οι χρονικοί περιορισµοί
Η δυνατότητα δικτύωσης
Ο βαθµός αλληλεπίδρασης του χρήστη µε το σύστηµα.
Το µέγεθος ενός ενσωµατωµένου συστήµατος προσδιορίζεται από έναν αριθµό διαφορετικών παραγόντων που αφορά κυρίως τις φυσικές δυνατότητες των ολοκληρωµένων που υπάρχουν σε αυτό. Οι κυριότεροι παράγοντες είναι η ταχύτητα του µικροελεγκτή, η
χωρητικότητα της κύριας µνήµης RAM και η χωρητικότητα των µέσων µόνιµης αποθήκευσης.
Έτσι ανάλογα µε το µέγεθός τους, τα ενσωµατωµένα συστήµατα χωρίζονται σε µικρά, µεσαία και µεγάλα. Τα µικρά συστήµατα χαρακτηρίζονται από έναν µικροελεγκτή των 32bit χαµηλής κατανάλωσης και µνήµη ROM των 4ΜB. Η µνήµη συνήθως δεν είναι πραγµατική
ROM αλλά Flash και µπορεί να φτάσει µέχρι και τα 32MB.
Στα µεσαία συστήµατα, τα χαρακτηριστικά που εντοπίζουµε είναι: µικροελεγκτής µεσαίας
κατανάλωσης, µε 32MB ή και µεγαλύτερη ROM (σχεδόν πάντα NOR Flash, ή ακόµη και
NAND όταν υπάρχει δυνατότητα εκτέλεσης κώδικα από block-addressable NAND FLASH
µνήµες) και 64 – 128 MB RAM. Μεσαία συστήµατα θεωρούνται τα mp3 players, τα PDAs, οι
συσκευές δικτύωσης όπως είναι τα routers κλπ. Πρέπει να πούµε ότι κάποια από τα παραπάνω συστήµατα µπορούν να υποστηρίξουν (προς το παρόν) µέχρι και 32GB NAND Flash
βοηθητικής µνήµης σε δευτερεύοντες αποθηκευτικούς χώρους.
Τα µεγάλα συστήµατα χαρακτηρίζονται από έναν δυνατό επεξεργαστή ή από µια οµάδα επεξεργαστών σε συνδυασµό µε µεγάλα µεγέθη µνήµης RAM και µόνιµο αποθηκευτικό χώρο.
Τα συστήµατα αυτά χρησιµοποιούνται συνήθως σε περιβάλλοντα στα οποία εκτελούνται µεγάλοι αριθµοί απαιτητικών υπολογισµών ώστε να επιτευχθούν συγκεκριµένες διεργασίες. Οι
µεγάλοι τηλεπικοινωνιακοί σταθµοί και οι προσοµοιωτές πτήσης αποτελούν παραδείγµατα
τέτοιων µεγάλων συστηµάτων. Γι’ αυτά τα συστήµατα το κόστος και οι πόροι που απαιτούν
είναι δευτερεύοντα ζητήµατα. Το ζητούµενο είναι η επίτευξη ενός στόχου µε κάθε θυσία. Ένα
τέτοιο παράδειγµα είναι και το αµυντικό σύστηµα µιας χώρας.
Το σύστηµά µας παρόλο που λειτουργεί ως Router, ανήκει στην πρώτη κατηγορία, δηλαδή
στα µικρά συστήµατα. Αυτό θα γίνει περισσότερο κατανοητό στο πρακτικό µέρος της εργασίας που θα ασχοληθούµε αποκλειστικά µε το υλικό και το λογισµικό του.
Ας δούµε τώρα πως διαχωρίζονται τα ενσωµατωµένα συστήµατα Linux ως προς τους χρονικούς περιορισµούς. Υπάρχουν δύο τύποι χρονικών περιορισµών. Οι αυστηροί και οι ήπιοι.
Στους αυστηρούς περιορισµούς απαιτείται η ανάδραση του συστήµατος να γίνεται σε ένα
προκαθορισµένο χρονικό πλαίσιο, αλλιώς κάτι πολύ ανεπιθύµητο µπορεί να συµβεί. Ας πάρουµε για παράδειγµα, ένα µηχάνηµα κοπής ξυλείας όπου το χέρι ενός εργάτη πλησιάζει επικίνδυνα στην κορδέλα κοπής. Αν ο αισθητήρας που έχει τοποθετηθεί για τέτοιες
Επικοινωνία: [email protected]
24
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
περιπτώσεις, στείλει το µήνυµα για το συµβάν στο σύστηµα και εκείνο δεν προχωρήσει άµεσα στην ακινητοποίηση της κορδέλας, τότε σίγουρα κάποια στιγµή θα προκληθεί σοβαρό εργατικό ατύχηµα. Ένα τέτοιο σύστηµα λοιπόν πρέπει να δουλεύει αυστηρά και σε πραγµατικό
χρόνο (real time).
Τα συστήµατα ήπιων χρονικών περιορισµών τα οποία είναι και τα πιο συνηθισµένα, δεν
χρειάζεται να λειτουργούν σε πραγµατικό χρόνο. Για παράδειγµα, ένα µηχάνηµα αυτόµατης
ανάληψης χρηµάτων δεν θα θεωρηθεί αναξιόπιστο αν αργήσει λίγο παραπάνω για να ολοκληρώσει µια εντολή συναλλαγής που του αναθέτουµε. Φυσικά ακόµη και στα συστήµατα
αυτά, τα χρονικά όρια πρέπει να κινούνται σε κάποια λογικά πλαίσια διαφορετικά δίνεται στον
χρήστη η εντύπωση ότι δε λειτουργούν σωστά.
Συνεχίζοντας την κατηγοριοποίηση των ενσωµατωµένων συστηµάτων Linux θα ασχοληθούµε µε το κριτήριο δυνατότητας δικτύωσης. Με τον όρο “δυνατότητα δικτύωσης” καθορίζεται αν ένα ενσωµατωµένο σύστηµα µπορεί να συνδεθεί σε κάποιο δίκτυο ή όχι. Στις µέρες
µας, περιµένουµε σχεδόν από κάθε συσκευή που αγοράζουµε να µπορεί να είναι προσβάσιµη µέσω δικτύου. Αυτό ορισµένες φορές ισχύει ακόµα και για τις “λευκές” οικιακές συσκευές
(ψυγεία, πλυντήρια, κουζίνες κλπ). Όλα αυτά προσδίδουν νέες απαιτήσεις σε κάθε σύστηµα
που σχεδιάζεται. Εποµένως, ένας ακόµη παράγοντας για τον οποίο επιλέγεται το Linux είναι
και οι δυνατότητες δικτύωσης που παρέχει ο πυρήνας του.
Ολοκληρώνοντας την αναφορά µας στους τύπους των ενσωµατωµένων συστηµάτων Linux
θα εξετάσουµε την κατηγοριοποίησή τους ως προς τον βαθµό αλληλεπίδρασής τους µε τον
τελικό χρήστη. Ο βαθµός αυτός είναι διαφορετικός για κάθε σύστηµα. Κάποια συστήµατα
όπως είναι τα tablet PCs και τα PDAs βασίζονται σχεδόν ολοκληρωτικά στην αλληλεπίδρασή
τους µε τον χρήστη παρέχοντάς ένα πλούσιο User Interface µε οθόνες αφής, πλούσια µενού
και ηχητικές εντολές, ενώ άλλα, όπως είναι για παράδειγµα τα βιοµηχανικά συστήµατα ελέγχου παραγωγής, παρέχουν µόνο κάποια LEDs ενδείξεων και κουµπιά.
1.4 Γιατί να προτιµήσουµε το Linux
Υπάρχει µεγάλο φάσµα κινήτρων για την ενσωµάτωση του Linux σε ένα ενσωµατωµένο
σύστηµα. Πολλά από αυτά τα κίνητρα είναι ίδια µε εκείνα που µας κάνουν να επιλέγουµε το
Linux ως Λειτουργικό Σύστηµα στους προσωπικούς υπολογιστές, τους servers και στους
χώρους των επιχειρήσεων, ενώ άλλα είναι πιο εξειδικευµένα και αφορούν αποκλειστικά την
φύση των ενσωµατωµένων συστηµάτων.
Γενικά οι σηµαντικότεροι λόγοι που µας κάνουν να θέλουµε να χρησιµοποιούµε το Linux
είναι οι παρακάτω:
Ποιότητα και αξιοπιστία του κώδικα
∆ιαθεσιµότητα του κώδικα
Ευρεία υποστήριξη υλικού
Standards για πρωτόκολλα επικοινωνίας και λογισµικό
∆ιαθέσιµα εργαλεία
Υποστήριξη από την κοινότητα
Άδειες χρήσης λογισµικού
Ανεξαρτησία από τον προµηθευτή
Κόστος
Ποιοτικός κώδικας είναι ο κώδικάς που προσφέρει επεκτασιµότητα, έχει σωστή δοµή, είναι
ευανάγνωστος και παραµετροποιείται εύκολα. Η επεκτασιµότητα έχει να κάνει κυρίως µε τη
δυνατότητα εύκολης προσθήκης νέων λειτουργιών. Για να µπορεί όµως να είναι εύκολο κάτι
τέτοιο θα πρέπει µέσα στον κώδικα κάθε ξεχωριστή λειτουργία να έχει τη δική της ξεχωριστή,
Ιστότοπος εργασίας: MyThesis.org
25
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
ευδιάκριτη και ευανάγνωστη ενότητα. Η εύκολη παραµετροποίηση προκύπτει από τη δυνατότητα που παρέχει ο κώδικάς µας για την επιλογή των χαρακτηριστικών τα οποία θα είναι ή
όχι, διαθέσιµα στην τελική εφαρµογή.
Από την άλλη, αξιόπιστος κώδικας είναι ο κώδικας που παρέχει προβλεπτικότητα, ανοχή σε
σφάλµατα και βιωσιµότητα. Η προβλεπτικότητα αφορά τη συµπεριφορά της τελικής εφαρµογής η οποία θα πρέπει να βρίσκεται µέσα στα πλαίσια που είχαν οριστεί εξ’ αρχής από εµάς.
Η ανοχή σε σφάλµατα αφορά την οµαλή ανάδραση σε προβληµατικές περιστάσεις όπου επιπλέον θα πρέπει µέσω κατάλληλων µηνυµάτων να ειδοποιείται ο προγραµµατιστής σχετικά µε τη θέση µέσα στον κώδικα αλλά και το λόγο που προέκυψε το κάθε ξεχωριστό
σφάλµα. Τέλος, η βιωσιµότητα αφορά την αδιάκοπη και ακέραια λειτουργία της εφαρµογής
χωρίς κάποια υποβοήθηση από τον χρήστη για µεγάλα χρονικά διαστήµατα.
Οι περισσότεροι προγραµµατιστές – µηχανικοί που έχουν ασχοληθεί µε τον πυρήνα του
Linux, πιστεύουν ότι ο κώδικάς του πληροί όλες τις παραπάνω προϋποθέσεις και µπορεί να
χαρακτηριστεί ποιοτικός και αξιόπιστος.
Ως προς τη διαθεσιµότητα του κώδικα, είναι φανερό ότι το Linux υπερέχει κατά πολύ. Τόσο
ο πηγαίος κώδικας, όσο και τα εργαλεία για να τον µεταγλωττίσουµε, είναι διαθέσιµα χωρίς
περιορισµούς στην πρόσβασή τους από εµάς. Τα πιο σηµαντικά στοιχεία του Linux συµπεριλαµβανοµένου του kernel, διανέµονται υπό την άδεια χρήσης λογισµικού, GNU GPL (General Public License).
Όταν κατά καιρούς προκύπτουν προβλήµατα στην πρόσβαση του πηγαίου κώδικα, η κοινότητα προσπαθεί άµεσα να τον αντικαταστήσει µε κάποιον άλλο αντίστοιχων ιδιοτήτων. Επίσης, οι διορθώσεις για προβλήµατα ασφαλείας είναι άµεσα διαθέσιµες και µπορούµε να
αναβαθµίζουµε εύκολα και γρήγορα µε αυτές το σύστηµά µας. Τα κυριότερα πλεονεκτήµατα
που προκύπτουν από τη διαθεσιµότητα του πηγαίου κώδικα, είναι η δυνατότητα που µας
παρέχεται να µπορούµε να τον διορθώνουµε, να τον τροποποιούµε και να ψάχνουµε βαθύτερα σε αυτόν έτσι ώστε να καταλαβαίνουµε ευκολότερα τις λειτουργίες του και τις ιδιαιτερότητές του.
Ένας άλλος λόγος ο οποίος µας οδηγεί στην επιλογή του Linux, είναι η ευρεία υποστήριξη
υλικού που παρέχει. Το Linux υποστηρίζει πολλούς διαφορετικούς τύπους πλατφορµών υλικού και συσκευών. Επειδή οι περισσότεροι drivers γράφονται από την κοινότητα, µπορούµε
να τους χρησιµοποιήσουµε µε τη σιγουριά ότι δεν θα πάψουν να υποστηρίζονται στο µέλλον
όπως πιθανόν θα συνέβαινε σε περίπτωση που είχαν δηµιουργηθεί από κάποια εταιρεία.
Ευρεία υποστήριξη υλικού, σηµαίνει επίσης ότι το Linux τρέχει σε δεκάδες διαφορετικές αρχιτεκτονικές µικροελεγκτών. Έτσι, βλέποντας κάποιον µικροελεγκτή µπορούµε να σκεφτούµε
ότι πιθανότατα κάποιος έχει ήδη µπει στη διαδικασία προσαρµογής και παραµετροποίησης
του πυρήνα ώστε να τον υποστηρίζει. Μπορούµε επίσης να περιµένουµε ότι η εφαρµογή
που γράφουµε σε κάποια πλατφόρµα θα µπορεί εύκολα να µεταφερθεί σε µια άλλη µε πολύ
µικρές αλλαγές. Αυτό ισχύει και για τους drivers.
Ως προς τα πρότυπα του λογισµικού και των πρωτοκόλλων επικοινωνίας, το Linux παρέχει
ευρεία υποστήριξη. Κάτι τέτοιο καθιστά εύκολη την ενσωµάτωση του σε ήδη υπάρχοντα
frameworks καθώς και την ενσωµάτωση παλιότερων εκδόσεων λογισµικού σε αυτό. Έτσι, για
παράδειγµα µπορεί εύκολα κάποιος να συνδέσει κάποιο σύστηµα Linux σε ένα ήδη υπάρχον
δίκτυο Windows και να περιµένει από αυτό να εξυπηρετεί αιτήµατα µέσω του πρωτοκόλλου
SAMBA.
Το Linux µοιάζει µε το Unix και έτσι µπορούµε να µεταφέρουµε παλιές εφαρµογές του δεύτερου σε αυτό. Στη πραγµατικότητα, πολλές εφαρµογές που υπάρχουν εγκατεστηµένες στις
διάφορες διανοµές, έχουν αρχικά γραφτεί για εµπορικές εκδόσεις του Unix και αργότερα µεταφέρθηκαν (ported) σε συστήµατα Linux. Σήµερα αρκετός κώδικας γράφεται για Linux πά-
Επικοινωνία: [email protected]
26
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
ντα µε το κριτήριο της µεταφερσιµότητας. Μεταφερσιµότητα ακόµα και για συστήµατα που
δεν είναι Linux, αφού είναι δυνατόν να τρέχουµε εφαρµογές Linux και σε Windows µέσω κάποιων βιβλιοθηκών συµβατότητας όπως είναι για παράδειγµα το Cygwin.
Από τα παραπάνω αντιλαµβανόµαστε ότι υπάρχουν πολλά διαθέσιµα εργαλεία που έχουν
γραφτεί για Linux και το γεγονός αυτό το κάνει ένα πολύ ευέλικτο λειτουργικό σύστηµα. Αν
σκεφτούµε κάποια εφαρµογή την οποία χρειαζόµαστε είναι σχεδόν σίγουρο ότι κάποιοι από
την κοινότητα θα έχουν ήδη νιώσει την ανάγκη να τη δηµιουργήσουν και να τη διαθέσουν
δωρεάν στο Internet. Για να το αντιληφθεί καλύτερα αυτό κάποιος, αρκεί να επισκεφτεί τις
ιστοσελίδες freshmeat.net και sourcefourge.net .
Η υποστήριξη του Linux από την κοινότητά του είναι ένα σηµαντικότατο πλεονέκτηµα που
έχει σε σχέση µε άλλα Λειτουργικά Συστήµατα. Σε αυτή την κοινότητα µπορούµε να νιώσουµε απόλυτα το πνεύµα του δωρεάν και ελεύθερου λογισµικού. Επίσης µέσω των αδειών
χρήσης λογισµικού, µπορούµε να κάνουµε πράγµατα που ούτε θα µπορούσαµε να τα φανταστούµε µε βάση του τι ισχύει στην υπόλοιπη αγορά. Στην ουσία, µπορούµε να χρησιµοποιήσουµε, να τροποποιήσουµε και να αναδιανείµουµε το λογισµικό µας µε µοναδικό
περιορισµό την παροχή των ίδιων ακριβώς δικαιωµάτων και στους αποδέκτες του.
Είδαµε έως τώρα αρκετά από τα κυριότερα πλεονεκτήµατα που µας δίνουν σηµαντικά κίνητρα και λόγους έτσι ώστε να θέλουµε να χρησιµοποιήσουµε το Linux. Στη συνέχεια θα αναφέρουµε δύο ακόµα. Το πλεονέκτηµα της ανεξαρτησίας σε σχέση µε τον προµηθευτή
(vendor) και το πλεονέκτηµα του κόστους του Linux.
Ανεξαρτησία από τον προµηθευτή σηµαίνει ότι δε χρειάζεται να βασιστούµε σε κάποιον για
να προµηθευτούµε το Linux ή για να το χρησιµοποιήσουµε. Αν όµως έχουµε επιλέξει ήδη
κάποια εµπορική διανοµή ενός προµηθευτή και είµαστε δυσαρεστηµένοι, µπορούµε να τον
αλλάξουµε αφού στην ουσία έχουµε τα ίδια δικαιώµατα µε αυτόν. Ορισµένοι προµηθευτές
παρέχουν επιπλέον λογισµικό στις διανοµές τους, που δεν είναι open source. Για το κοµµάτι
αυτό θα πρέπει να βρεθεί µια δική µας λύση ή κάποιος άλλος προµηθευτής. Τέτοια ζητήµατα
πρέπει να λαµβάνονται σοβαρά υπ’ όψιν όταν επιλέγουµε διανοµή για το ενσωµατωµένο µας
σύστηµα.
Αφήσαµε το κόστος για το τέλος µιας και δεν έχει να κάνει µε το τεχνικό κοµµάτι του Linux.
Είναι όµως, ίσως το σηµαντικότερο πλεονέκτηµα του Linux, σε σχέση µε άλλες λύσεις που
υπάρχουν στην αγορά λογισµικού. Ιδιαίτερα τώρα που αυτές οι γραµµές γράφονται σε περίοδο βαθειάς οικονοµικής κρίσης.
Γενικά, υπάρχουν τρία τµήµατα λογισµικού που κοστίζουν κατά την ανάπτυξη ενός κλασσικού ενσωµατωµένου συστήµατος:
το αρχικό περιβάλλον ανάπτυξης
τα επιπρόσθετα εργαλεία
τα δικαιώµατα χρήσης
Το «µηδενικό» κόστος του Linux είναι αποτέλεσµα των αδειών χρήσης ανοικτού λογισµικού
και διαφέρει από οποιοδήποτε άλλο ενσωµατωµένο λειτουργικό σύστηµα. Με τη χρήση του
Linux tα περισσότερα εργαλεία ανάπτυξης και τα τµήµατα του λειτουργικού είναι δωρεάν και
οι άδειες υπό τις οποίες προστατεύονται, προστατεύουν την οικονοµική εκµετάλλευσή τους.
1.5 Έτοιµες διανοµές και εργαλεία ανάπτυξης
Αρχικά θα πρέπει να επαναλάβουµε ότι δεν είναι υποχρεωτικό να αγοράσουµε µια έτοιµη
διανοµή και τα έτοιµα εργαλεία ανάπτυξης που τη συνοδεύουν για να δηµιουργήσουµε ένα
Ιστότοπος εργασίας: MyThesis.org
27
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
ενσωµατωµένο σύστηµα Linux. Όλα τα απαραίτητα πακέτα λογισµικού είναι ήδη διαθέσιµα
για κατέβασµα από το Internet, και είναι τα ίδια πακέτα τα οποία κατεβάζουν και τυποποιούν
οι προµηθευτές διανοµών. Επίσης, οι έτοιµες λύσεις ίσως να µην ταιριάζουν απόλυτα σε αυτό που επιθυµούµε εµείς να κάνουµε. Γι’ αυτό αν θέλουµε να έχουµε τον έλεγχο των περιεχοµένων του συστήµατός µας, πρέπει να τα δηµιουργήσουµε «µόνοι» µας.
Κατά τη διάρκεια της εκπόνησης αυτής της εργασίας χρειάστηκαν ολόκληρες εβδοµάδες
απλά και µόνο για τη δηµιουργία του περιβάλλοντος ανάπτυξης. Ένα από τα δυσκολότερα
κοµµάτια αυτού του περιβάλλοντος ήταν η αλυσίδα µεταγλώττισης (toolchain – θα δούµε περισσότερα γι’ αυτή σε αντίστοιχη ενότητα). Κάποιες στιγµές λοιπόν, η επιλογή µια έτοιµης
λύσης από κάποιο προµηθευτή ήταν πολύ δελεαστική και λογική υπόθεση.
Για την επιλογή αυτή υπάρχουν ορισµένα χαρακτηριστικά στις διάφορες διανοµές που αν τα
εξετάσουµε µπορούµε να οδηγηθούµε σε κάποια σωστή απόφαση. Η ευκολία για παράδειγµα, της εγκατάστασης του περιβάλλοντος ανάπτυξης καθώς και της µεταφοράς του αποτελέσµατος στο ενσωµατωµένο µας σύστηµα, θα πρέπει να είναι σηµαντικά κριτήρια για την
επιλογή έτοιµης διανοµής. Ορισµένοι ακόµα παράγοντες που θα πρέπει να προσέξουµε είναι
η διαθέσιµη τεκµηρίωση (εσωτερική ή/και εξωτερική) και ο βαθµός παραµετροποίησης που
µας δίνεται κατά τη διαδικασία εγκατάστασης καθώς και η αυτοµατοποίηση των διαδικασιών.
Κάποιες φορές επίσης, ίσως είναι προτιµότερο να κινηθούµε αντίθετα από τη φυσική διαδικασία ανάπτυξης. ∆ηλαδή, πρώτα να επιλέξουµε διανοµή και µετά µικροελεγκτή ή πλακέτα
ανάπτυξης (development board). Αν δεν είµαστε υποχρεωµένοι να χρησιµοποιήσουµε έναν
συγκεκριµένο µικροελεγκτή, ίσως θα ήταν καλύτερα να ερευνήσουµε πρώτα την υποστήριξη
που παρέχουν οι γνωστοί προµηθευτές ενσωµατωµένων διανοµών Linux (πχ MontaVista)
για γνωστούς µικροελεγκτές και έπειτα να λειτουργήσουµε ανάλογα.
Κατά την αναζήτηση όλων αυτών των πληροφοριών συγκεντρώθηκε αρκετή γνώση ώστε
τελικά να µην είναι απαραίτητη µια έτοιµη διανοµή αλλά να χρησιµοποιηθούν µόνο τα απαραίτητα και δωρεάν εργαλεία. Αυτό παρ’ όλες τις δυσκολίες που υπήρξαν έδωσε µια αίσθηση
ανεξαρτησίας και ικανοποίησης. Εξάλλου αυτός είναι και ο λόγος που επιλέξαµε το Linux. Το
επιλέξαµε γιατί το µέλλον του δεν καθορίζεται από κανέναν εµπορικό παράγοντα, και για την
ανεξαρτησία που µας παρέχει.
1.6 Μεθοδολογία σχεδίασης και ανάπτυξης
Ο σχεδιασµός και η υλοποίηση ενός ενσωµατωµένου συστήµατος Linux µπορούν να πραγµατοποιηθούν µε συγκεκριµένο τρόπο. Η διαδικασία περιλαµβάνει πολλά στάδια και κάποια
από αυτά µπορούν να γίνουν παράλληλα, ενώ άλλα µπορούν ακόµα και να παραληφθούν
για την εξοικονόµηση χρόνου. Γενικά τα κυριότερα στάδια ανάπτυξης ενός ενσωµατωµένου
συστήµατος Linux είναι τα εξής:
Καθορισµός των στοιχείων (components) υλικού του συστήµατος
∆ιαµόρφωση (configuration) και δηµιουργία (build) του kernel
∆ηµιουργία του root ριζικού συστήµατος αρχείων (root filesystem)
Εγκατάσταση και παραµετροποίηση του λογισµικού εκκίνησης (bootloader)
Το πρώτο στάδιο όπως εύκολα αντιλαµβανόµαστε, είναι η επιλογή του υλικού. ∆ηλαδή, των
υποσυστηµάτων που θα απαρτίζουν το ενσωµατωµένο µας σύστηµα. Μικροελεγκτής, µνήµη,
ολοκληρωµένα, θύρες επικοινωνίας, αντιστάσεις, πυκνωτές και πολλά άλλα, “κόβονται και
ράβονται” επάνω σε µια πλακέτα τυπωµένου κυκλώµατος για να αποτελέσουν εν τέλει, ένα
ολοκληρωµένο ενσωµατωµένο σύστηµα, που στην παρούσα εργασία θα είναι ένας router.
Το λογισµικό, δηλαδή ο προγραµµατισµός και η ανάπτυξη, είναι ξεχωριστά θέµατα που
πραγµατοποιούνται σε επόµενα στάδια. Αυτό το µοντέλο είναι πολύ λογικό όταν αναπτύσ-
Επικοινωνία: [email protected]
28
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
σουµε λογισµικό σε επίπεδο hardware. Σε αρκετές περιπτώσεις το πρόγραµµα που γράφουµε τρέχει µόνο σε ένα συγκεκριµένο σύστηµα, οπότε πρέπει πρώτα να γνωρίζουµε την αρχιτεκτονική του και έπειτα να γράψουµε κώδικα που θα εκτελείται σε αυτό.
Το πρώτο στάδιο ανάπτυξης των ενσωµατωµένων συστηµάτων Linux είναι και το µοναδικό
ίσως, που δεν µπορεί να πραγµατοποιηθεί παράλληλα µε άλλα στάδια. Ο καθορισµός των
απαιτήσεων καθώς και η συµµόρφωση του Linux σε αυτές τις απαιτήσεις (πχ το µέγεθος συστήµατος αρχείων root) πρέπει να ολοκληρωθεί πριν απ’ οτιδήποτε άλλο.
Λόγω της ταχέως µεταβαλλόµενης φύσης του Linux είναι πολύ πιθανό κάποιος να θέλει τις
τελευταίες και καλύτερες εκδόσεις λογισµικού για το σύστηµά του. Σε αυτή την εργασία κάτι
τέτοιο αποφεύχθηκε έτσι ώστε να µην δηµιουργηθούν προβλήµατα που θα οφείλονταν στην
ανωριµότητα αυτών των νέων εκδόσεων. Επίσης κάθε τµήµα λογισµικού είναι πιθανό να εξαρτάται και από κάποιο άλλο (dependency) το οποίο θα πρέπει επίσης να αναβαθµιστεί και
έτσι είναι πολύ εύκολο να επιδοθούµε σε έναν ατελείωτο αγώνα αναβαθµίσεων που στο τέλος µπορεί να οδηγήσει και σε κάποιο αδιέξοδο ασυµβατότητας ή να καταστήσει το σύστηµά
µας ανεπαρκές από άποψη υλικού. Για τους λόγους αυτούς χρησιµοποιήθηκε ώριµο και δοκιµασµένο λογισµικό το οποίο δεν παρουσίαζε σφάλµατα και είχε λογικές απαιτήσεις από το
σύστηµά µας.
Αφού ολοκληρωθεί το πρώτο στάδιο και έχουµε επιλέξει τα κατάλληλα χαρακτηριστικά για
το σύστηµά µας, µπορούµε στη συνέχεια να επιλέξουµε ποια έκδοση του kernel θα χρησιµοποιήσουµε καθώς και τις σχετικές ρυθµίσεις που απαιτούνται. Ανεξάρτητα από το εάν αποφασίσουµε να ακολουθήσουµε τις ενηµερώσεις του kernel, θα πρέπει να κρατάµε σταθερή
την παραµετροποίηση του κατά τη διάρκεια της ανάπτυξης του συστήµατος. Αυτό θα βοηθήσει στο να µην αποκόπτονται κάποια τµήµατα τα οποία έχουν ολοκληρωθεί. Για να επιτευχθεί κάτι τέτοιο θα πρέπει να έχουµε µελετήσει πολύ καλά τις επιλογές παραµετροποίησης
του kernel και να τις έχουµε προσαρµόσει στις απατήσεις του συστήµατός µας εξ’ αρχής.
Αφού έχει πια αποφασιστεί η παραµετροποίηση του kernel, µπορεί να ακολουθήσει η δηµιουργία του.
Παράλληλα µε το χειρισµό των διαφόρων θεµάτων του πυρήνα, µπορούµε να προχωρήσουµε στην δηµιουργία του κεντρικού συστήµατος αρχείων (root filesystem). Το κεντρικό σύστηµα αρχείων ενός ενσωµατωµένου συστήµατος είναι παρόµοιο µε αυτό ενός κανονικού
υπολογιστή που τρέχει Linux, µε τη διαφορά ότι περιλαµβάνει ένα πολύ µικρότερο σύνολο
εφαρµογών, βιβλιοθηκών και αρχείων που απαιτούνται για τη λειτουργία του συστήµατος.
Στη συνέχεια ακολουθεί η επιλογή του λογισµικού εκκίνησης (bootloader). Η επιλογή εξαρτάται άµεσα από την αρχιτεκτονική του συστήµατος. Υπάρχουν διάφοροι bootloaders που
γράφονται ο καθένας τους ειδικά για κάποιο σύστηµα. Ακόµα και bootloaders οι οποίοι αναπτύσσονται για την ίδια αρχιτεκτονική µπορεί να διαφέρουν αρκετά µεταξύ τους. Η µεθοδολογία του πακεταρίσµατος και της εκκίνησης ενός συστήµατος µοιάζει αρκετά µεταξύ των
διαφορετικών αρχιτεκτονικών αλλά µπορεί να διαφέρει αρκετά σε σχέση µε τη συσκευή µόνιµης αποθήκευσης από την οποία το σύστηµα εκκινεί.
Η εγκατάσταση και παραµετροποίηση των συσκευών αποθήκευσης και του λογισµικού εκκίνησης (bootloader), είναι οι τελικές εργασίες που αποµένουν για τη ολοκλήρωση της δηµιουργίας του συστήµατός µας. Κατά τη διάρκεια αυτών των βηµάτων τα διαφορετικά στοιχεία
(δηλαδή ο bootloader, το σύστηµα αρχείων root και ο kernel) συνενώνονται προκειµένου να
αποτελέσουν το λογισµικό ενός πλήρους ενσωµατωµένου συστήµατος Linux.
Ιστότοπος εργασίας: MyThesis.org
29
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
1.7 Εργαλεία ανάπτυξης και αποσφαλµάτωσης
Σε προηγούµενο κεφάλαιο που ασχοληθήκαµε µε το firmware των ενσωµατωµένων συστηµάτων αναφέραµε το µοντέλο host – target. Υπάρχουν δύο πτυχές σε αυτό το µοντέλο, η ανάπτυξη και η αποσφαλµάτωση.
Πριν δοκιµάσουµε να εκτελέσουµε λογισµικό στο σύστηµα target θα πρέπει να έχουµε δηµιουργήσει µια σύνδεση µεταξύ αυτού και του συστήµατος host. Η σύνδεση θα λειτουργεί
σαν οµφάλιος λώρος µέσω του οποίου θα µπορούµε να αλληλεπιδρούµε µε το target σύστηµα και να εξακριβώνουµε εάν οι εφαρµογές που αναπτύσσει λειτουργούν όπως προβλέπεται
(debugging).
Η απόκτηση ενός τέτοιου περιβάλλοντος απαιτεί την µεταγλώττιση των εφαρµογών και των
βιβλιοθηκών του συστήµατος target. Αυτό επιτυγχάνεται παραµετροποιώντας ή χτίζοντας
τους διάφορους compilers και τα υπόλοιπα εργαλεία ανάπτυξης για διασταυρωµένη ανάπτυξη (cross development). Χρησιµοποιώντας αυτά τα βοηθητικά προγράµµατα, µπορούµε να
δηµιουργήσουµε εφαρµογές για το target σύστηµά µας και ένα περιβάλλον για περαιτέρω
ανάπτυξη. Στη συνέχεια µπορούµε να επιλέξουµε κάποιο IDE το οποίο θα µας βοηθήσει να
αναπτύξουµε το project µας ευκολότερα. Επίσης θα µας δώσει τη δυνατότητα να χρησιµοποιήσουµε συστήµατα διαχείρισης εκδόσεων λογισµικού, όπως το CVS (Concurrent Versions System) , το Subversion και το GIT.
Λόγω των υψηλών δυνατοτήτων που διαθέτουν ορισµένα ενσωµατωµένα συστήµατα, µερικοί προγραµµατιστές επιλέγουν να ολοκληρώσουν όλη την ανάπτυξη στο σύστηµα target. Σε
αυτή τη διαµόρφωση όλα τα εργαλεία µεταγλώττισης και ανάπτυξης βρίσκονται στο σύστηµα
αυτό. Έτσι το µοντέλο host – target συνδυάζεται σε ένα και µόνο σύστηµα, παρέχοντας το
άµεσο πλεονέκτηµα της ταχύτερης ανάπτυξης αφού στην ουσία δεν χρειάζεται να στηθεί κάποιο host σύστηµα.
Όποιο σύστηµα ανάπτυξης και αν επιλέξουµε, κάποια στιγµή θα χρειαστεί να κάνουµε αποσφαλµάτωση στο σύστηµά µας. Αυτό µπορεί να επιτευχθεί τόσο µε τη βιβλιοθήκη gdb
που είναι η πιο κοινώς χρησιµοποιούµενη για αποσφαλµάτωση γενικού σκοπού (general
purpose debugging), όσο και µε µια απλή συνάρτηση της βιβλιοθήκης της C όπως είναι για
παράδειγµα, η εµφάνιση κάποιων τιµών µέσω της συνάρτησης printf(). Κάποια προβλήµατα όµως που απαιτούν περισσότερη εσωτερική ανάλυση των λειτουργιών που τρέχουν
κατά το χρόνο εκτέλεσης, µπορούν να εντοπιστούν µόνο µέσω συµβολικής αποσφαλµάτωσης (symbolic debugging). Η συµβολική αποσφαλµάτωση µπορεί να είναι πιο λεπτοµερής.
Μπορεί να υποστηρίζει αποµακρυσµένη αποσφαλµάτωση µέσω της σειριακής επικοινωνίας,
αποσφαλµάτωση του kernel, και εργαλεία για hardware debugging όπως είναι το JTAG και
το BDM.
Παρ’ όλα αυτά, ακόµα και η συµβολική αποσφαλµάτωση µπορεί να είναι ανεπαρκής σε κάποιες περιπτώσεις. Όταν παρουσιάζονται προβληµατικές κλήσεις συστήµατος από κάποια
εφαρµογή, ή όταν πρέπει να επιλυθούν προβλήµατα συγχρονισµού, είναι καλύτερα να χρησιµοποιούνται εργαλεία ανίχνευσης όπως τα εργαλεία strace και LTT (Linux Trace Toolkit).
Για προβλήµατα απόδοσης, υπάρχουν εργαλεία που είναι πιο προσαρµοσµένα στην διεργασία, όπως τα gprof και gcov. Όταν όµως όλα αυτά που αναφέραµε αποτυγχάνουν, τότε το
καλύτερο που έχουµε να κάνουµε είναι να µελετήσουµε καλύτερα τη λειτουργία του kernel και
τους συνηθέστερους λόγους για τους οποίους κάποιες φορές καταρρέει.
Επικοινωνία: [email protected]
30
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
1.8 Οι τύποι ανάπτυξης
Υπάρχουν τρεις βασικοί τύποι host – target ανάπτυξης ενσωµατωµένων συστηµάτων
Linux:
∆ιασυνδεµένος (Linked setup)
Αφαιρούµενου αποθηκευτικού µέσου (Removable Storage setup)
Αυτόνοµος (Standalone setup)
Στον διασυνδεδεµένο τύπο, τα συστήµατα target και host είναι, όπως φαίνεται και στην επόµενη εικόνα, µόνιµα συνδεδεµένα µεταξύ τους µε κάποιο φυσικό µέσο Το µέσο αυτό είναι
συνήθως κάποιο σειριακό καλώδιο ή κάποιο καλώδιο Ethernet.
Εικόνα 1. ∆ιασυνδεδεµένος τύπος ανάπτυξης ενσωµατωµένων συστηµάτων Linux
H κύρια ιδιότητα αυτού του τύπου είναι ότι δεν υπάρχει κάποιο µέσο αποθήκευσης που να
παρεµβάλλεται µεταξύ του host και του target. Όλες οι µεταφορές γίνονται µέσω του καλωδίου που ενώνει τα δύο αυτά συστήµατα. Όπως βλέπουµε και στην εικόνα, το σύστηµα host
περιλαµβάνει το cross-platform περιβάλλον ανάπτυξης, ενώ το target, έναν κατάλληλο bootloader, έναν λειτουργικό kernel και ένα κεντρικό σύστηµα αρχείων (root filesystem).
Εναλλακτικά, µπορούµε να χρησιµοποιήσουµε αποµακρυσµένα στοιχεία για την ανάπτυξή
του target. Ο πυρήνας θα µπορούσε για παράδειγµα να είναι διαθέσιµος µέσω του πρωτοκόλλου TFTP (Trivial File Transfer Protocol) από τον host. Το root σύστηµα αρχείων θα
µπορούσε επίσης να φορτώνεται µέσω του πρωτοκόλλου NFS αντί να βρίσκεται αποθηκευµένο σε κάποια µνήµη του target. Η χρήση ενός root συστήµατος αρχείων που φορτώνεται
µέσω του NFS είναι µια πολύ καλή τακτική κατά τη διάρκεια της ανάπτυξης, γιατί έτσι αποφεύγουµε την συνεχή µεταφορά και αντιγραφή του τροποποιηµένου κώδικα από το σύστηµα
host στο target. Θα δούµε αργότερα µε περισσότερη λεπτοµέρεια όλους τους δυνατούς τύπους εκκίνησης (boot configurations).
Ο διασυνδεδεµένος τύπος ανάπτυξης είναι ο πιο συνηθισµένος (και είναι κατά κύριο λόγο ο
τύπος µε τον οποίο αναπτύχθηκε το λογισµικό του router σε αυτή την εργασία). Το καλώδιο
που υπάρχει σε αυτό τον τύπο ανάπτυξης και συνδέει το target σύστηµα µε το host, µπορεί
να χρησιµοποιηθεί και για debugging (αποσφαλµάτωση). Πολλά ενσωµατωµένα συστήµατα
παρέχουν ταυτόχρονα δυνατότητες σύνδεσης Ethernet και RS232 (σειριακή). Συνήθως η
πρώτη χρησιµοποιείται λόγω της µεγάλης ταχύτητας µεταγωγής της, για το κατέβασµα του
εκτελέσιµου image, του kernel, του root συστήµατος αρχείων και άλλων µεγάλων σε όγκο
αντικειµένων, ενώ η σειριακή επικοινωνία χρησιµοποιείται για debugging (πχ µέσω κονσόλας
µε την εφαρµογή Putty ή µε το Hyper Terminal των Windows).
Σε καινούριους υπολογιστές πολλές φορές παραλείπεται η ενσωµάτωση σειριακή θύρας.
Αυτό λύνεται εύκολα µε κάποιον USB to Serial προσαρµογέα (adaptor). Τον προσαρµογέα
µπορούµε είτε να τον αγοράσουµε, είτε να τον σχεδιάσουµε και να τον κατασκευάσουµε πολύ εύκολα οι ίδιοι. Ο προσαρµογέας αυτός, παρέχει µια εικονική σειριακή θύρα (Virtual COM
Ιστότοπος εργασίας: MyThesis.org
31
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
Port) µέσω της οποίας µπορεί τελικά να υπάρξει επικοινωνία. Βέβαια σε περιπτώσεις που
θέλουµε να κάνουµε πραγµατικό σειριακό debugging, η σειριακή θύρα είναι απαραίτητη.
Ας περάσουµε όµως στον επόµενο τύπο ανάπτυξης, τον τύπο αφαιρούµενου αποθηκευτικού µέσου (Removable Storage Setup). Σε αυτή την περίπτωση δεν υπάρχει κάποιο καλώδιο
που να συνδέει το σύστηµα host µε το σύστηµα target. Αντί αυτού, υπάρχει κάποια συσκευή
αποθήκευσης η οποία γράφεται από το host:
Εικόνα 2. Ανάπτυξη ενσωµατωµένων συστηµάτων Linux µε αφαιρούµενο αποθηκευτικό µέσο
Έπειτα µεταφέρεται στο target και χρησιµοποιείται για την εκκίνηση της συσκευής. Όπως
και µε τον προηγούµενο τύπο ανάπτυξης (Linked Setup), έτσι κι εδώ, το σύστηµα host έχει
εγκατεστηµένο το cross-platform περιβάλλον ανάπτυξης. Παρ’ όλα αυτά, το σύστηµα target
περιλαµβάνει και έναν πολύ µικρό bootloader για να µπορεί να διαβάζει από την συσκευή
αποθήκευσης. Το υπόλοιπο λογισµικό (που έχει δηµιουργηθεί από το σύστηµα host) βρίσκεται αποθηκευµένο σε κάποια αφαιρούµενη συσκευή (πχ CompactFlash, MMC Card, και πιο
σπάνια σε CD, DVD κλπ).
Στην πραγµατικότητα το σύστηµα target είναι δυνατόν να µην περιλαµβάνει καµία µόνιµη
µνήµη (εκτός από µια ελάχιστη ενσωµατωµένη flash για τον bootloader). Μπορεί να υπάρχει
κάποια θύρα (socket) όπου κάποια αποσπώµενη µνήµη flash θα µπορεί να τοποθετείται και
να αφαιρείται. Η µνήµη αυτή θα προγραµµατίζεται από κάποιον flash programmer στην µεριά
του host και έπειτα θα τοποθετείται στη θύρα του target για κανονική λειτουργία.
Αυτός ο τύπος ανάπτυξης ενσωµατωµένων συστηµάτων Linux, είναι πολύ δηµοφιλής κατά
τις αρχικές φάσεις ανάπτυξης ενσωµατωµένων συστηµάτων. Μετά από τα αρχικά στάδια της
ανάπτυξης ίσως είναι πιο πρακτικό να χρησιµοποιούµε τον πρώτο τύπο (Linked Setup), έτσι
ώστε να αποφύγουµε την µεταφορά του αποθηκευτικού µέσου µεταξύ του host και του target
κάθε φορά που κάνουµε αλλαγές στον kernel ή στο σύστηµα αρχείων root.
Ο τρίτος τύπος ανάπτυξης (Standalone setup) ξεφεύγει λιγάκι από τα ενσωµατωµένα συστήµατα και από τα πλαίσια της εργασίας. Γι’ αυτό απλά θα αναφέρουµε µόνο τα πολύ βασικά. Εδώ υπάρχει µόνο ένα σύστηµα, το σύστηµα target. Το σύστηµα αυτό λειτουργεί ως ένα
αυτόνοµο σύστηµα ανάπτυξης. Περιλαµβάνει όλο το απαραίτητο software για την εκκίνηση
(boot), την λειτουργία και τα επιπρόσθετα εργαλεία που είναι απαραίτητα για την περαιτέρω
ανάπτυξή του. Στην ουσία, αυτός ο τύπος είναι παρόµοιος µε έναν κανονικό προσωπικό υπολογιστή, µε τη διαφορά ότι το υλικό του δεν είναι συµβατικό υλικό για PC:
Επικοινωνία: [email protected]
32
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
Εικόνα 3. Αυτόνοµος τύπος ανάπτυξης ενσωµατωµένων συστηµάτων Linux
Σε αντίθεση µε τους άλλους τύπους ανάπτυξης, αυτός ο τύπος δεν απαιτεί επικοινωνία µε
κάποιο άλλο σύστηµα, ούτε κάποιο cross-platform περιβάλλον ανάπτυξης, αφού όλα τα εργαλεία που απαιτούνται υπάρχουν στο σύστηµα target.
Kαι οι τρεις τύποι ανάπτυξης που αναφέραµε, µπορούν να χρησιµοποιηθούν συνδυαστικά
ή και όλοι µαζί, κατά την ανάπτυξη ενός ενσωµατωµένου συστήµατος Linux.
1.9 Οι τύποι αποσφαλµάτωσης
Υπάρχουν τρεις βασικοί τύποι διεπαφών τους οποίους χρησιµοποιούν οι προγραµµατιστές
για να συνδέσουν το σύστηµα target µε το host για αποσφαλµάτωση:
Σειριακά (serial link)
∆ικτυακά (network interface)
Με ειδικό υλικό αποσφαλµάτωσης (hardware debugging)
Κάθε τύπος έχει τα δικά του πλεονεκτήµατα και περιορισµούς. Επίσης κάθε τύπος είναι κατάλληλος για συγκεκριµένες περιπτώσεις. Ο πιο απλός από αυτούς είναι η σειριακή σύνδεση.
Αυτό συµβαίνει επειδή, το υλικό και το λογισµικό γι’ αυτή τη µορφή επικοινωνίας, είναι πολύ
απλό και βρίσκεται σχεδόν πάντα υλοποιηµένο στους µικροελεγκτές. Υπάρχουν όµως δύο
βασικοί περιοριστικοί παράγοντες. Ο ένας είναι η χαµηλή ταχύτητα και ο άλλος, ότι αν υπάρχει µόνο µια σειριακή θύρα στο ενσωµατωµένο µας σύστηµα, και η θύρα αυτή είναι ο µοναδικός διαθέσιµος τρόπος επικοινωνίας µε τον έξω κόσµο, είναι αδύνατο να κάνουµε
ταυτόχρονα και debugging, αλλά και να επιβλέπουµε το σύστηµά µας µέσω κάποιου προσοµοιωτή τερµατικού (terminal emulator). Παρ’ όλα αυτά η χρήση ενός terminal δεν είναι πάντοτε απαραίτητη. Για παράδειγµα όταν κάνουµε debugging κατά την εκκίνηση του kernel µε τη
χρήση κάποιου remote kernel debugger, δεν χρειάζεται να χρησιµοποιήσουµε κάποιου είδους terminal αφού ακόµη δεν έχει φορτωθεί ο φλοιός (shell) του kernel.
Ας περάσουµε όµως στον δεύτερο τύπο debugging. Η χρήση µιας διεπαφής δικτύου όπως
είναι το Ethernet, παρέχει πολύ υψηλότερες ταχύτητες από την σειριακή σύνδεση. Επιπλέον,
το σύστηµα host µπορεί να δηµιουργήσει περισσότερες από µια συνδέσεις µε το σύστηµα
target, µέσω της ίδιας γραµµής επικοινωνίας. Έτσι µπορούµε να συνεχίσουµε να αλληλεπιδρούµε µαζί του, ενώ την ίδια στιγµή κάνουµε debugging σε αυτό. Μπορούµε επίσης να συνδεθούµε ταυτόχρονα και µε τη σειριακή επικοινωνία. Για την δικτυακή επικοινωνία όµως
απαιτείται και µια στοίβα πρωτοκόλλων δικτύωσης (networking stack). Η στοίβα αυτή περιλαµβάνεται στον Linux kernel. Όµως αφού η στοίβα αυτή βρίσκεται µέσα στον ίδιο τον
kernel, είναι δύσκολο να κάνουµε debugging στο ενσωµατωµένο µας σύστηµα χρησιµοποιώντας την. Είναι σαν να προσπαθούµε να µετακινήσουµε ένα αντικείµενο ενώ στεκόµαστε
Ιστότοπος εργασίας: MyThesis.org
33
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
επάνω του. Για το λόγο αυτό τις περισσότερες φορές το debugging πραγµατοποιείται µέσω
της σειριακής σύνδεσης.
Οι δύο τύποι debugging που αναφέραµε, απαιτούν την ύπαρξη έστω και ενός ελάχιστου
λογισµικού που θα αναγνωρίζει τις δοµικές µονάδες εισόδου – εξόδου (primitive I/O hardware) του target συστήµατος , για να επιτευχθεί είτε σειριακή, είτε δικτυακή επικοινωνία µε το
host. Σε κάποιες περιπτώσεις όµως, όπως για παράδειγµα κατά την ανάπτυξη ενός συστήµατος από το µηδέν ή κατά το debugging του ίδιου του kernel, το λογισµικό αυτό δεν είναι
διαθέσιµο. Για το λόγο αυτό απαιτείται µια διεπαφή αποσφαλµάτωσης που να παρέχει άµεσο
έλεγχο µέσω hardware.
Οι περισσότεροι µηχανικοί προκειµένου να επιτύχουν απευθείας έλεγχο µέσω υλικού, χρησιµοποιούν JTAG debuggers. Κατά την ανάπτυξη του router αυτής της εργασίας χρησιµοποιήθηκε η συσκευή JTAGICE mkII (programmer – debugger – emulator) της εταιρείας
Atmel.
1.10 Η αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux
Tα συστήµατα Linux απαρτίζονται από πολλά και διαφορετικά συστατικά. Ας ρίξουµε µια
µατιά στη γενική αρχιτεκτονική (generic architecture) ενός τέτοιου συστήµατος. Αυτό θα µας
επιτρέψει να οριοθετήσουµε το κάθε ένα από αυτά τα συστατικά σε ένα πλαίσιο, να κατανοήσουµε τον τρόπο αλληλεπίδρασης µεταξύ τους και να εκµεταλλευτούµε τη δοµή τους. Στην
εικόνα βλέπουµε ένα γενικό σχεδιάγραµµα της αρχιτεκτονικής ενός ενσωµατωµένου συστήµατος Linux:
Εικόνα 4. Η αρχιτεκτονική ενός ενσωµατωµένου συστήµατος Linux
Παρά το γεγονός του ότι η εικόνα περιλαµβάνει µεγάλο ποσοστό αφαίρεσης, είναι αρκετή
για να µπορέσουµε σε αυτό το αρχικό στάδιο να αναλύσουµε αρκετά πράγµατα. Μπορούµε
για παράδειγµα να πούµε ότι δεν υπάρχει µεγάλη διαφορά ανάµεσα σε ένα ενσωµατωµένο
σύστηµα Linux και σε ένα PC που τρέχει Linux.
Tα χαρακτηριστικά του υλικού που πρέπει να ικανοποιούνται γενικά από ένα ενσωµατωµένο σύστηµα έτσι ώστε να µπορεί να εκτελείται µε επιτυχία σε αυτό ο πυρήνας του Linux είναι:
Επικοινωνία: [email protected]
34
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
Μικροελεγκτής 32bit µε µονάδα διαχείρισης µνήµης (MMU – Memory Management Unit)
Επαρκής RAM
∆υνατότητες επικοινωνίας µέσω µονάδων εισόδου – εξόδου, για αλληλεπίδραση µε
το περιβάλλον και για να είναι δυνατή η πραγµατοποίηση debugging
Ο πυρήνας πρέπει να µπορεί να φορτώσει το root σύστηµα αρχείων σε κάποιας
µορφής µόνιµη µνήµη, ή να µπορεί να το προσπελάσει µέσω δικτύου.
Όπως βλέπουµε και στο σχεδιάγραµµα πιο πάνω, ακριβώς επάνω από το hardware βρίσκεται ο kernel. Ο σκοπός του είναι να διαχειρίζεται το υλικό ενώ ταυτόχρονα παρέχει οικείο
περιβάλλον λογισµικού χρήστη (όπως το POSIX API και τα υπόλοιπα standard Application
Interfaces ή APIs, επάνω στα οποία γράφονται οι διάφορες εφαρµογές). Ο kernel οδηγεί τις
συσκευές, διαχειρίζεται τις µονάδες εισόδου – εξόδου, διαχειρίζεται το χρονοπρογραµµατισµό των διαφόρων λειτουργιών, ελέγχει το διαµοιρασµό της µνήµης, χειρίζεται σήµατα, και
γενικότερα αναλαµβάνει κάθε διαχειριστικό καθήκον των πόρων του συστήµατος.
Στον kernel υπάρχουν δύο µεγάλες κατηγορίες διαστρωµατωµένων υπηρεσιών (layered
services) οι οποίες παρέχουν τη λειτουργικότητα που απαιτείται από τις εφαρµογές. Οι χαµηλού επιπέδου διεπαφές (low – level interfaces) είναι υπεύθυνες για τη διαµόρφωση του υλικού στο οποίο εκτελείται ο kernel και παρέχουν άµεσο έλεγχο προς τα ανώτερα στρώµατα
για τη διαχείριση των πόρων, χρησιµοποιώντας ένα API ανεξάρτητο από το υλικό. Με λίγα
λόγια το low – level interface, χειρίζεται το υλικό του συστήµατος αλλά ταυτόχρονα παρέχει
και στα ανώτερα στρώµατα µια διαφανή επικοινωνία µε αυτό. Αυτό είναι κάτι απολύτως απαραίτητο αν σκεφτούµε ότι αλλιώς χειρίζεται τους καταχωρητές ή τις σελίδες της µνήµης ένας
µικροελεγκτής αρχιτεκτονικής ARM και αλλιώς ένας AVR32. Αν θέλουµε να µιλήσουµε ακόµα
πιο τεχνικά, µπορούµε να πούµε ότι τα low – level Interfaces χειρίζονται εντολές µικροελεγκτή, ενέργειες στη µνήµη, σχεδόν ανεξάρτητα από την αρχιτεκτονική, και επίσης αποτελούν
βασική διεπαφή για τις συσκευές. Όλα αυτά στη συνέχεια προωθούνται στα υψηλότερα επίπεδα µέσω κεφαλίδων (headers), µακροεντολών (macros) και συναρτήσεων (wrapper functions).
Πάνω από τα χαµηλά στρώµατα του πυρήνα, άλλα, υψηλότερου επιπέδου στρώµατα παρέχουν τη διαφάνεια για λειτουργίες που είναι κοινές σε όλα τα Linux συστήµατα. Τέτοιες λειτουργίες αφορούν διεργασίες, αρχεία, sockets, και σήµατα. Εφόσον τα χαµηλού επιπέδου
APIs που παρέχονται από τον kernel είναι κοινά µεταξύ των διαφορετικών αρχιτεκτονικών, ο
κώδικας που ενσωµατώνουν τα υψηλότερου επιπέδου APIs είναι σχεδόν ίδιος σε κάθε µια
από αυτές τις αρχιτεκτονικές. Φυσικά πάντα υπάρχουν κάποιες εξαιρέσεις.
Μεταξύ αυτών των δύο επιπέδων (low και high) o kernel χρειάζεται κάποιες φορές, διερµηνευτές (interpreters) για την κατανόηση µηνυµάτων που µεταφέρονται από και προς τις συσκευές. Τα διάφορα συστήµατα αρχείων (πχ JFFS) και τα πρωτόκολλα δικτύωσης (πχ
ΤCP/IP), είναι παραδείγµατα τέτοιων µηνυµάτων που ο kernel προσπαθεί να µεταφράσει έτσι ώστε να παρέχει πρόσβαση από και προς τα δεδοµένα τους.
Οι σκληροί δίσκοι είναι οι κατεξοχήν συσκευές αποθήκευσης για τα δεδοµένα των προσωπικών υπολογιστών. Στα ενσωµατωµένα συστήµατα τον ρόλο αυτό έχουν οι µνήµες flash. ο
χώρος τους και το περιεχόµενό τους είναι διευθυνσιοδοτούµενο, και κάθε διεύθυνση αντιστοιχεί σε κάποιο block. Για να µπορούν να χρησιµοποιούνται από διαφορετικές αρχιτεκτονικές συστηµάτων, έχουν την ελάχιστη δυνατή µορφοποίηση (format). Όµως αφού το επίπεδο
της διαµόρφωσης είναι το ελάχιστο δυνατό, είναι ταυτόχρονα ασαφές και ανεπαρκές όταν
θέλουµε να οµαδοποιήσουµε δεδοµένα σε αρχεία. Για να επιτύχουµε την πρόσβαση σε επίπεδο αρχείου λοιπόν, θα πρέπει να εισάγουµε περισσότερη λογική και οργάνωση στα δεδοµένα αυτά. Θα πρέπει τα αρχεία και οι κατάλογοι να είναι αποθηκευµένα µε τέτοιο τρόπο
ώστε να µπορούµε να τα προσπελαύνουµε κάθε φορά µε τον ίδιο τρόπο και χωρίς να αλλοι-
Ιστότοπος εργασίας: MyThesis.org
35
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
ώνονται κατά την προσπέλαση αυτή. Αυτός ακριβώς είναι ο σκοπός ενός συστήµατος αρχείων (File System).
Ο kernel προκειµένου να µπορεί να φιλοξενήσει τα διάφορα συστήµατα αρχείων, περιλαµβάνει έναν αριθµό µηχανών συστήµατος αρχείων (filesystem engines) οι οποίες µπορούν να
αναγνωρίσουν την δοµή που έχει ένας δίσκος και να ανακτήσουν ή να προσθέσουν αρχεία
και καταλόγους από και προς τη δοµή αυτή αντίστοιχα. Όλες αυτές οι µηχανές συστηµάτων
αρχείων, παρέχουν το ίδιο API στα ανώτερα στρώµατα του πυρήνα διαµέσου του εικονικού
συστήµατος αρχείων (VFS – Virtual File System), έτσι ώστε η πρόσβαση στα διαφορετικά
συστήµατα αρχείων να είναι ευκολότερη.
Κατά τη διάρκεια της κανονικής του λειτουργίας, ο kernel απαιτεί την ύπαρξη τουλάχιστον
ενός συστήµατος αρχείων. Του κεντρικού συστήµατος αρχείων (root filesystem). Από αυτό
φορτώνει και την πρώτη εφαρµογή που θα εκτελεστεί στο σύστηµα. Επίσης βασίζεται σε αυτό και για περεταίρω ενέργειες, όπως την φόρτωση διάφορων modules και την παροχή ενός
καταλόγου εργασίας (working directory) σε κάθε διεργασία που εκτελείται. Το σύστηµα αρχείων root µπορεί είτε να είναι αποθηκευµένο και να εκτελείται από µια µνήµη µόνιµης αποθήκευσης είτε να φορτώνεται στη RAM κατά τη διάρκεια της εκκίνησης του συστήµατος και
έπειτα να εκτελείται από εκεί (κάπως έτσι λειτουργούν και τα LiveCD στους υπολογιστές). Η
πρώτη περίπτωση αποθήκευσης είναι και η πιο συχνή.
θα ήταν ίσως αναµενόµενο, ότι ακριβώς επάνω από τον kernel θα βρίσκαµε κανονικές εφαρµογές και άλλα βοηθητικά προγράµµατα (utilities), όµως οι υπηρεσίες που παρέχονται
από τον kernel δεν είναι ακόµη κατάλληλες για να χρησιµοποιηθούν από εφαρµογές. Για το
λόγο αυτό, έχουν δηµιουργηθεί βιβλιοθήκες (libraries) και ειδικά προγράµµατα συστήµατος
(daemons). Η κύρια βιβλιοθήκη που χρησιµοποιείται από τις περισσότερες εφαρµογές Linux
είναι η βιβλιοθήκη GNU της γλώσσας C µε την ονοµασία glibc. Για τα ενσωµατωµένα συστήµατα Linux µπορούν να χρησιµοποιηθούν υποκατάστατα αυτής της βιβλιοθήκης έτσι ώστε να αντισταθµιστεί το βασικό της µειονέκτηµα που είναι το µέγεθός της. Εν τω µεταξύ,
σηµαντικές διεργασίες του συστήµατος (daemons), παρέχουν υπηρεσίες οι οποίες αξιοποιούνται από τις διάφορες εφαρµογές. Για παράδειγµα, ο διαχειριστής συστήµατος αρχείων
συσκευών (device filesystem manager) udev, διαχειρίζεται συσκευές του καταλόγου /dev
(πχ όταν USB συσκευές αποθήκευσης, προσθέτονται ή αφαιρούνται από το σύστηµα).
Οι βιβλιοθήκες συνήθως συνδέονται δυναµικά (dynamic linking) µε τις εφαρµογές. ∆ηλαδή
δεν είναι µέρος του εκτελέσιµου της εφαρµογής αλλά φορτώνονται στην περιοχή µνήµης της
εφαρµογής κατά την εκκίνησή της. Αυτό επιτρέπει σε πολλές εφαρµογές να χρησιµοποιούν
την ίδια έκδοση µιας βιβλιοθήκης χωρίς η κάθε µία τους να χρειάζεται ένα δικό της αντίγραφο. Η βιβλιοθήκη της C για παράδειγµα η οποία βρίσκεται στο σύστηµα αρχείων ενός συστήµατος, φορτώνεται µόνο µία φορά στη RAM του συστήµατος αυτού και διαµοιράζεται σε
όσες εφαρµογές την χρειαστούν.
Παρ’ όλα αυτά, σε κάποιες περιπτώσεις στα ενσωµατωµένα συστήµατα όπου οι βιβλιοθήκες είναι µέρος του εκτελέσιµου της εφαρµογής, η στατική σύνδεση (static linking) προτιµάται. Αυτό συµβαίνει γιατί εάν η εφαρµογή µας χρειάζεται µόνο ένα τµήµα της βιβλιοθήκης της
C είναι προτιµότερο να φορτωθεί µόνο το τµήµα αυτό ώστε να µην δεσµευτούν επιπλέον
πόροι που όπως γνωρίζουµε είναι αρκετά περιορισµένοι στα ενσωµατωµένα συστήµατα.
1.11 Εκκίνηση συστήµατος
Κατά την εκκίνηση ενός συστήµατος (startup ή boot) συµµετέχουν τρία βασικά στοιχεία: ο
bootloader, ο kernel και η διεργασία init. Ο bootloader (εκκινητής) είναι το πρώτο τµήµα
λογισµικού που εκτελείται και εξαρτάται σε µεγάλο βαθµό από την αρχιτεκτονική του µικροελεγκτή του target συστήµατος αλλά και από το υπόλοιπο hardware. Έχουν γραφτεί αρκετοί
Επικοινωνία: [email protected]
36
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
bootloaders για Linux (Lilo, GRUB, loadlin, Coreboot, U-Boot, RedBoot κλπ) αλλά στην παρούσα εργασία θα χρησιµοποιήσουµε τον U-Boot. Ο bootloader εκτελεί την αρχικοποίηση
του υλικού (low-level initialization) και µεταπηδά στον κώδικα εκκίνησης του kernel.
Ο αρχικός κώδικας εκκίνησης του kernel διαφέρει πάρα πολύ µεταξύ διαφορετικών αρχιτεκτονικών και έτσι πραγµατοποιεί και αυτός µε τη σειρά του αρχικοποίηση υλικού πριν εγκαθιδρύσει το κατάλληλο περιβάλλον. Εφόσον γίνουν όλα αυτά, ο kernel περνά τον έλεγχο
στην συνάρτηση start_kernel() η οποία είναι ανεξάρτητη αρχιτεκτονικής. Η συνάρτηση
αυτή µε τη σειρά της αρχικοποιεί το υψηλό επίπεδο (high-level initialization) του kernel, φορτώνει το κεντρικό σύστηµα αρχείων (root filesystem) και εκκινεί την διεργασία init. Κατά την
αρχικοποίηση του υψηλού επιπέδου του kernel γίνονται επίσης και κάποιες άλλες εργασίες
όπως είναι για παράδειγµα η χαρτογράφηση µνήµης (memory mapping) και οι συναρτήσεις
σειριακής επικοινωνίας για debugging.
Το υπόλοιπο της εκκίνησης του συστήµατος διεξάγεται στο χώρο του χρήστη (user space)
από την διεργασία init και τα προγράµµατα εκκίνησης (startup scripts).
1.11.1 Τύποι εκκίνησης
Ο τύπος της εκκίνησης που θα επιλέξουµε για το target σύστηµά µας θα επηρεάσει την επιλογή του bootloader που θα χρησιµοποιήσουµε, την παραµετροποίησή του, καθώς και το
υλικό και το λογισµικό του συστήµατος ανάπτυξης host. Για παράδειγµα, αν επιλέξουµε δικτυακή εκκίνηση του συστήµατός µας, το σύστηµα host θα πρέπει να εξασφαλίσουµε ότι θα
παρέχει κάποιες δικτυακές υπηρεσίες προς το σύστηµα target. Έτσι θα πρέπει να εντοπίσουµε την απαιτούµενη διαµόρφωση των παραµέτρων της εκκίνησης που απαιτούνται και
κατά τη διάρκεια της σχεδίασης αλλά και στο τελικό προϊόν που θα κατασκευάσουµε. Έπειτα
πρέπει να επιλέξουµε τον bootloader ο οποίος θα φροντίζει για τους διαφορετικούς τύπους
εκκίνησης που θα χρησιµοποιούµε.
Πριν προχωρήσουµε στην ανάλυση των τύπων εκκίνησης ας δούµε κάποια βασικά που
αφορούν την εκκίνηση. Όλοι οι επεξεργαστές βρίσκουν και εκτελούν την πρώτη - πρώτη τους
εντολή από µια διεύθυνση µνήµης που συνήθως είναι προκαθορισµένη από τον κατασκευαστή τους. Κάθε σύστηµα το οποίο έχει αναπτυχθεί γύρω από µια CPU διαθέτει κάποια ενσωµατωµένη µνήµη στερεάς κατάστασης (solid state). Η µνήµη αυτή είναι υπεύθυνη για την
εκκίνηση του συστήµατος. Το επίπεδο πολυπλοκότητας του λογισµικού εκκίνησης και ο βαθµός στον οποίο αυτό χρησιµοποιείται στη συνέχεια, εξαρτώνται από το είδος του συστήµατός
µας.
Στους περισσότερους υπολογιστές το λογισµικό εκκίνησης (BIOS) είναι υπεύθυνο µόνο για
τη φόρτωση του λειτουργικού συστήµατος από το δίσκο και για την παροχή δυνατότητας παραµετροποίησης του υλικού από τον χρήστη. Αντίθετα, στα ενσωµατωµένα συστήµατα, το
λογισµικό εκκίνησης µπορεί να χρησιµοποιηθεί για οποιοδήποτε σκοπό και κάποιες φορές
µάλιστα είτε δεν υπάρχει, είτε είναι το µόνο υπαρκτό λογισµικό του συστήµατος. Έτσι σε κάποιες περιπτώσεις µπορεί να εκτελείται ακόµη και καθ’ όλη τη διάρκεια λειτουργίας του ενσωµατωµένου συστήµατος. Αυτό συµβαίνει επειδή ένα ενσωµατωµένο σύστηµα
χρησιµοποιείται για πάρα πολλούς και διαφορετικούς σκοπούς. Ορισµένες άλλες λειτουργίες
του λογισµικού εκκίνησης είναι το debugging, η φόρτωση άλλου λογισµικού εκκίνησης, η αναβάθµιση του λογισµικού που υπάρχει στο ενσωµατωµένο σύστηµα κ.α.
Τα ενσωµατωµένα συστήµατα Linux χαρακτηρίζονται από την απαίτηση που έχουν στο να
φορτώσουν τον kernel και το κεντρικό σύστηµα αρχείων. Όπως αναφέραµε ο τρόπος φόρτωσής τους και η λειτουργία τους εξαρτάται από τις απαιτήσεις του συστήµατος και τον τύπο
ανάπτυξής του.
Ιστότοπος εργασίας: MyThesis.org
37
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
Υπάρχουν τρεις διαφορετικοί τρόποι για την εκκίνηση ενός ενσωµατωµένου συστήµατος
Linux: η εκκίνηση από µνήµη στερεάς κατάστασης, η εκκίνηση από δίσκο και η εκκίνηση από
το δίκτυο. Ο κάθε ένας από αυτούς τους τύπους εκκίνησης έχει τις δικές του ρυθµίσεις και
χρησιµοποιείται για διαφορετικό σκοπό.
Εκκίνηση από µνήµη στερεάς κατάστασης
Όταν η εκκίνηση πραγµατοποιείται από κάποια µνήµη στερεάς κατάστασης, στη µνήµη αυτή βρίσκονται αποθηκευµένα, ο αρχικός bootloader, οι παράµετροι ρυθµίσεων (configuration
parameters), ο kernel και το σύστηµα αρχείων root. Στην εικόνα βλέπουµε την πιο κοινή περίπτωση διάταξης µιας τέτοιας µνήµης:
Εικόνα 5. ∆ιάταξη µνήµης στερεάς κατάστασης
Σκόπιµα δεν παρουσιάζονται κάποιες διευθύνσεις µνήµης επειδή σε κάθε σύστηµα το εύρος το διευθύνσεων διαφέρει αρκετά από κάθε άλλο σύστηµα. Οι τιµές των διευθύνσεων είναι µικρότερες στα αριστερά και µεγαλώνουν καθώς κινούµαστε δεξιά. Σε κάποιες
περιπτώσεις ισχύσει το αντίθετο και έτσι ο bootloader βρίσκεται στην κορυφή του εύρους διευθύνσεων της συσκευής αποθήκευσης. Για το λόγο αυτό πολλές µνήµες flash παρέχονται
µε υποστήριξη και για τις δυο περιπτώσεις (top – boot και bottom – boot). Ανάλογα µε τη διαµόρφωση, η περιοχή της µνήµης flash όπου βρίσκεται ο bootloader συχνά προστατεύεται
από ειδικούς µηχανισµούς προστασίας έτσι ώστε να µην καταστρέφεται όταν γίνει κάποια
λάθος εγγραφή στη µνήµη.
Μπορεί βέβαια να συναντήσουµε και διαφορετικές µορφοποιήσεις ως προς τον αριθµό των
τµηµάτων της µνήµης. Ενώ για παράδειγµα στην προηγούµενη εικόνα παρουσιάζονται τέσσερα τµήµατα, υπάρχουν περιπτώσεις που οι παράµετροι εκκίνησης και ο bootloader βρίσκονται στο ίδιο διαµέρισµα (partition). Ο kernel µπορεί επίσης να βρίσκεται στο ίδιο
διαµέρισµα µε το root σύστηµα αρχείων (αυτό προϋποθέτει την ικανότητα του bootloader να
διαβάζει το κεντρικό το root σύστηµα αρχείων). Επίσης ο kernel και το root σύστηµα αρχείων
θα µπορούσαν να βρίσκονται πακεταρισµένα σε ένα ενιαίο αρχείο (image) το οποίο θα αποσυµπιέζεται στη µνήµη RAM πριν χρησιµοποιηθεί.
Ανάλογα µε τις δυνατότητες του bootloader που έχουµε στη διάθεσή µας, µπορούν να δηµιουργηθούν και άλλες διαµορφώσεις στη µνήµη, κάθε µία µε τα δικά της πλεονεκτήµατα και
µειονεκτήµατα. Μια διαµόρφωση µπορεί να κατηγοριοποιηθεί λαµβάνοντας υπ’ όψιν τέσσερα
κριτήρια: τη χρήση της µνήµης flash, τη χρήση της RAM, την ευκολία αναβάθµισης και το
χρόνος εκκίνησης (bootup time).
Τα µέσα αποθήκευσης του λογισµικού εκκίνησης αρχικά προγραµµατίζονται µε κάποιον
programmer (JTAG ή BDM). Αφού ολοκληρωθεί ο αρχικός προγραµµατισµός, µπορεί να επιτευχθεί ο επαναπρογραµµατισµός µέσω του bootloader αυτή τη φορά (εάν φυσικά ενσωµατώνει αυτή τη δυνατότητα), ή χρησιµοποιώντας το MTD (Memory Technology Device)
υποσύστηµα του Linux.
Επικοινωνία: [email protected]
38
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
Εκκίνηση από σκληρό δίσκο
Εδώ ο kernel και το σύστηµα αρχείων root, βρίσκονται σε ένα σκληρό δίσκο. Ο bootloader
έχει συνήθως περιορισµό µεγέθους τα 512 bytes ώστε να χωρά στον τοµέα εκκίνησης (boot
sector). Ο σκοπός του είναι, είτε να φορτώνει έναν µεγαλύτερο και πιο ισχυρό δευτερεύον
(secondary) bootloader, είτε να εκτελεί τον ίδιο τον kernel, απευθείας από το δίσκο. Ένα από
τα συστήµατα αρχείων στο δίσκο, χρησιµοποιείται έπειτα ως το root σύστηµα αρχείων. Αν
και δε συµβαίνει συχνά, αυτός ο τύπος εκκίνησης είναι βολικός αν θέλουµε για κάποιο λόγο
να έχουµε σκληρό δίσκο ή κάποια CompactFlash στο ενσωµατωµένο µας σύστηµα.
Εκκίνηση µέσω δικτύου
Ο τελευταίος τύπος εκκίνησης ολοκληρώνεται µέσω δικτύου. Η φόρτωση του συστήµατος
αρχείων root ή/και του kernel, επιτυγχάνεται µέσω µιας γραµµής που διασυνδέει κάποιο
server µε την πλακέτα µας. Εποµένως υπάρχουν τρεις περιπτώσεις φόρτωσης:
Σύστηµα αρχείων root και kernel – Θα πρέπει να υπάρχει bootloader που να υποστηρίζει τα πρωτόκολλα TFTP (Trivial File Transfer Protocol) και NFS (Network File
System). Η περίπτωση αυτή είναι σπάνια.
Μόνο ο kernel – Απαίτηση µόνο του πρωτοκόλλου TFTP από τον bootloader.
Μόνο το σύστηµα αρχείων root – Σε αυτή την περίπτωση στη µνήµη του target υπάρχει ο kernel και αφού εκκινηθεί από τον bootloader, φορτώνει µέσω του πρωτοκόλλου
NFS το σύστηµα αρχείων root.
Στις περιπτώσεις που αναφέραµε υποθέτουµε ότι το σύστηµα host έχει εγκατεστηµένο λογισµικό για NFS και TFTP server. Για να αυτοµατοποιήσει ο bootloader την εύρεση της τοποθεσίας του server µπορεί να κάνει χρήση των πρωτοκόλλων BOOTP/DHCP. Σε αυτή την
περίπτωση το target σύστηµά δε χρειάζεται να έχει κάποια στατική IP έτσι ώστε να επικοινωνήσει µε τον TFTP και τον NFS server.
Η εκκίνηση µέσω δικτύου είναι πολύ πρακτική στα αρχικά στάδια της ανάπτυξης ή κατά τη
διάρκεια του debugging, επειδή µας επιτρέπει να διαµοιραζόµαστε δεδοµένα πολύ γρήγορα
µεταξύ του συστήµατος host και του συστήµατος target. Το µειονέκτηµα είναι ότι απαιτείται
λογισµικό server και σωστή ρύθµισή των παραµέτρων του.
1.12 Μονάδα διαχείρισης µνήµης (MMU)
Για την καλύτερη χρήση των διαθέσιµων πόρων, είναι σηµαντικό να κατανοήσουµε την διάταξη της µνήµης του συστήµατος και τις διαφορές µεταξύ του φυσικού χώρου διευθύνσεων
(physical address map) και του χώρου εικονικών διευθύνσεων (virtual address map) του kernel. Κάτι επίσης πολύ σηµαντικό είναι ότι πολλές περιφερειακές συσκευές είναι προσβάσιµες
µέσω του φυσικού χώρου διευθύνσεων του συστήµατος αλλά έχουν περιορισµένη ή καθόλου
πρόσβαση µέσω του χώρου εικονικών διευθύνσεων.
Η γνώση της φυσικής χαρτογράφησης της µνήµης (memory mapping) του συστήµατός µας,
είναι σηµαντική γιατί µας παρέχει πληροφορίες στο πώς να διαµορφώσουµε τον kernel. Μας
βοηθά να αναπτύξουµε τους δικούς µας drivers όταν έχουµε να κάνουµε µε χαρτογραφηµένες συσκευές (memory – mapped devices) και να παρέχουµε πληροφορίες στον bootloader
σχετικά µε τις συσκευές που πρέπει να φορτώσει κατά την εκκίνηση.
Πριν όµως απ’ οτιδήποτε άλλο, ας εξετάσουµε τις έννοιες των φυσικών και εικονικών διευθύνσεων στα ενσωµατωµένα συστήµατα Linux. Μια φυσική διεύθυνση χρησιµοποιείται για να
δώσει ένα όνοµα σε ένα συγκεκριµένο κελί (cell) της φυσικής µνήµης του συστήµατός µας.
Ιστότοπος εργασίας: MyThesis.org
39
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
Έτσι, είµαστε σε θέση να αλληλεπιδρούµε µε τη θέση αυτή γράφοντας, διαβάζοντας, εκτελώντας ή σβήνοντας τα περιεχόµενά της. Οι φυσικές διευθύνσεις αναπαρίστανται από έναν
προσηµασµένο ή µη-προσηµασµένο ακέραιο των 32 bit (ή των 8 bit αν έχουµε κάποιον οκτάµπιτο µικροελεγκτή).
Μια εικονική ή γραµµική (linear) διεύθυνση είναι ένας µη-προσηµασµένος (unsigned) ακέραιος των 32 bit ο οποίος µπορεί να χρησιµοποιηθεί για την αναπαράσταση χώρου µέχρι
4GB (4,294,967,296 cells). Οι εικονικές διευθύνσεις συνήθως αναπαρίστανται σε δεκαεξαδική (hexadecimal) µορφή. Οι τιµές αυτών των διευθύνσεων έχουν εύρος, από 0x00000000
µέχρι και 0xffffffff. Στην εικόνα βλέπουµε ένα παράδειγµα χάρτη µνήµης και τη µετάφραση των εικονικών του διευθύνσεων σε φυσικές:
Εικόνα 6. Χάρτης µνήµης και µετάφραση εικονικών διευθύνσεων σε φυσικές
Υπάρχουν πάρα πολλοί λόγοι για τους οποίους η χρήση εικονικών διευθύνσεων είναι χρήσιµη. Ο σηµαντικότερος προκύπτει από τον περιορισµένο διαθέσιµο χώρο της φυσικής µνήµης. Όπως ξέρουµε η φυσική µνήµη αποτελείται από διαδοχικές περιοχές των 32bit. Κάθε
τέτοια περιοχή ονοµάζεται λέξη (word) και έχει τη δική της διεύθυνσή στο υλικό. Αν η µνήµη
έχει µέγεθος Ν λέξεων, τότε πολύ γενικά µπορούµε να πούµε ότι η πρώτη λέξη έχει διεύθυνση 0, η δεύτερη διεύθυνση 1, η τρίτη 2 και η τελευταία Ν-1. ∆ηλαδή ο αριθµός αυτός είναι
πεπερασµένος. Όταν όµως οι διεργασίες που θέλουµε να εκτελούνται στο σύστηµά µας ξεπερνούν σε απαιτήσεις αυτό τον αριθµό, τότε η λύση είναι οι εικονικές διευθύνσεις. Εποµένως ο χώρος των εικονικών διευθύνσεων, θεωρητικά είναι µεγαλύτερος σε µέγεθος από
εκείνο των φυσικών, έτσι ώστε όλες οι διεργασίες να «θεωρούν» ότι έχουν ελεύθερο χώρο
στη διάθεσή τους και να εκτελούνται αναπόσπαστα (Τον χειρισµό των εικονικών διευθύνσεων τον αναλαµβάνει το Λ.Σ.).
Η µετατροπή µιας εικονικής διεύθυνσης σε φυσική γίνεται από τη µονάδα διαχείρισης µνήµης (MMU – Memory Management Unit) που διαθέτει ο µικροελεγκτής µας. Σε κάποιους παλαιότερους µικροελεγκτές, η µονάδα αυτή δεν υπήρχε και το ρόλο αυτό αναλάµβανε κάποια
εξειδικευµένη βιβλιοθήκη λογισµικού.
Επικοινωνία: [email protected]
40
Ανάπτυξη Ενσωµατωµένων Συστηµάτων Linux - Κεφάλαιο 1
Όταν πραγµατοποιείται µια πρόσβαση στη µνήµη (µετά από αίτηµα της CPU), η MMU µεταφράζει την εικονική διεύθυνση που ζητήθηκε σε µια φυσική διεύθυνση, ενώ πριν έχει ελέγξει τα δικαιώµατα πρόσβασης στη θέση αυτή. Αν συµβεί κάποιο σφάλµα ή το λειτουργικό
σύστηµα διακόψει αυτή τη διαδικασία, προκαλείται µια εξαίρεση (exception), επιτρέποντας
έτσι το πρόβληµα να λυθεί µέσω λογισµικού.
Η αρχιτεκτονική MMU χρησιµοποιεί σελιδοποίηση για να χαρτογραφήσει µια εικονική διεύθυνση των 32bit σε µια φυσική. Τα µεγέθη των σελίδων είναι 1, 4, 64, KB και 1MB. Κάθε σελίδα έχει τα δικά της δικαιώµατα πρόσβασης.
Οι πληροφορίες που χρειάζονται προκειµένου να εκτελέσουµε την χαρτογράφηση εικονικών
διευθύνσεων σε φυσικές, βρίσκονται σε έναν εξωτερικό πίνακα σελίδων (page table). Αυτός
ο πίνακας περιέχει επίσης πληροφορίες προστασίας και άλλα δεδοµένα που απαιτούνται κατά τη διαδικασία της µετάφρασης των διευθύνσεων. Ο πίνακας σελίδων χρησιµοποιείται για
κάθε πρόσβαση στη µνήµη προκειµένου να διαβάζονται οι πληροφορίες χαρτογράφησης για
κάθε σελίδα.
Για να επιταχυνθεί η διαδικασία µετάφρασης χρησιµοποιείται µια κρυφή µνήµη που ονοµάζεται TLB (Translation Lookaside Buffer). Η µνήµη TLB περιέχει τις n πιο πρόσφατα χρησιµοποιούµενες εγγραφές του πίνακα σελίδων. Ο αριθµός n εξαρτάται από την υλοποίηση του
συστήµατος κάθε φορά. Η αρχιτεκτονική AVR32 του µικροελεγκτή AP7000 για παράδειγµα,
παρέχει 2 TLBs µε µέχρι 64 εγγραφές η καθεµία, Μπορούν να χρησιµοποιηθούν ταυτόχρονα, η µία για πρόσβαση στη µνήµη και η άλλη για εντολές. Στην εικόνα βλέπουµε ένα γενικό
διάγραµµα των όσων έχουµε πει έως τώρα:
Εικόνα 7. ∆ιάγραµµα µονάδας διαχείρισης µνήµης MMU
1.13 ∆ιαχείριση δευτερεύουσας µνήµης
Οι εικονικές διευθύνσεις που δεν αντιστοιχίζονται σε φυσικές, συνήθως αντιστοιχίζονται σε
κάποια δευτερεύουσα µνήµη. Οι βασικότεροι µέθοδοι αντιστοίχισης είναι δύο: η κατάτµηση
και η σελιδοποίηση, ή ο συνδυασµός τους, η κατατµηµένη σελιδοποίηση.
Κατά τη σελιδοποίηση, η εικονική µνήµη διαιρείται σε ίσα και συνεχόµενα µέρη που λέγονται σελίδες. Με τον ίδιο τρόπο η φυσική µνήµη χωρίζεται σε ενότητες. Το µέγεθος ενότητας
και σελίδας είναι το ίδιο. Το Λ.Σ. διατηρεί πίνακα αντιστοίχισης σελίδων και ενοτήτων. Για κάθε σελίδα, φαίνεται στον πίνακα η ενότητα και οι διευθύνσεις της φυσικής µνήµης στην οποία
Ιστότοπος εργασίας: MyThesis.org
41
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητή (Router Implementation)
αντιστοιχεί. Αν δεν αντιστοιχεί σε ενότητα σηµαίνει ότι βρίσκεται στη δευτερεύουσα µνήµη. Το
κυριότερο µειονέκτηµα είναι ότι κάθε διεργασία καταλαµβάνει περισσότερο χώρο από ότι
χρειάζεται. Η τελευταία σελίδα κάθε διεργασίας έχει ένα τµήµα µικρότερο ή µεγαλύτερο που
είναι άχρηστο. Αυτό ονοµάζεται εσωτερικός κατακερµατισµός
Η µέθοδος της κατάτµησης προσπαθεί να αποφύγει τον εσωτερικό κατακερµατισµό δίνοντας σε κάθε διεργασία όση µνήµη χρειάζεται. Χωρίζει τη µνήµη σε τµήµατα διαφορετικών
µεγεθών και για κάθε ένα κρατά την αρχική διεύθυνση και µέγεθος. Από την άλλη, Η µέθοδος
της κατατµηµένης σελιδοποίησης, συνδυάζει την εργασία σε τµήµατα σταθερού µεγέθους.
Κάθε σελίδα αποτελείται µόνο από µία λέξη.
Αυτό που πρέπει να πούµε πριν το κλείσιµο αυτού του κεφαλαίου είναι ότι µετά τη φόρτωση
του Linux Kernel από τον bootloader, όλα τα προγράµµατα τα οποία εκτελούνται, χρησιµοποιούν εικονικές διευθύνσεις µνήµης.
Επικοινωνία: [email protected]
42
ΚΕΦΑΛΑΙΟ
2
Εργαλεία Ανάπτυξης
Ενσωµατωµένων Συστηµάτων Linux
Εισαγωγή
Όπως είναι ήδη γνωστό, τα εργαλεία ανάπτυξης ενσωµατωµένων συστηµάτων διαφέρουν
από εκείνα που χρησιµοποιούνται συνήθως για την ανάπτυξη εφαρµογών σε PCs. Η διαφορά τους είναι ότι ενώ εκτελούνται σε κάποια συγκεκριµένη πλατφόρµα (πχ x86), δηµιουργούν
εφαρµογές για µια άλλη (πχ AVR32). Για το λόγο αυτό ονοµάζονται και εργαλεία ανάπτυξης
και µεταγλώττισης cross – platform.
Γενικά υπάρχουν δύο τρόποι για να αποκτήσουµε τα εργαλεία αυτά. Μπορούµε να κατεβάσουµε δωρεάν τον πηγαίο κώδικά τους από το internet και να τον µεταγλωττίσουµε από την
αρχή (build from scratch), να τα προµηθευτούµε µέσω κάποιας εταιρείας επί πληρωµή, κάποιου αντιπροσώπου ή κάποιου online project στο Internet.
Σε αυτό το κεφάλαιο θα αναλύσουµε τα πιο σηµαντικά εργαλεία ανάπτυξης ενσωµατωµένων συστηµάτων. Η ανάλυση θα λειτουργήσει και σαν µια εισαγωγή για τα αντίστοιχα εργαλεία που χρησιµοποιήθηκαν στο πρακτικό µέρος αυτής της εργασίας, για την ανάπτυξη του
Router NGW100. Τα θέµατα µε τα οποία θα ασχοληθούµε είναι τα ακόλουθα:
Αλυσίδα εργαλείων µεταγλώττισης
Έτοιµες αλυσίδες εργαλείων µεταγλώττισης
Πακέτο υποστήριξης συστήµατος
∆ηµιουργία της αλυσίδας µεταγλώττισης cross
Αυτοµατοποιηµένα συστήµατα
Παραµετροποίηση uClibc, kernel και BusyBox µέσω Buildroot
Γραµµή εντολών
Βασικές εντολές φλοιού
Προσοµοιωτές τερµατικών
IDEs για Linux
2.1 Έτοιµες αλυσίδες εργαλείων ανάπτυξης
Οι περισσότεροι κατασκευαστές αναπτυξιακών πλακετών προσφέρουν δωρεάν κάποιες
αλυσίδες εργαλείων ανάπτυξης, έτοιµες για χρήση, µαζί µε τα προϊόντα τους. Συνήθως σε
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
αυτή την περίπτωση, εκτός από την αλυσίδα εργαλείων µεταγλώττισης συµπεριλαµβάνεται
και κάποιο λογισµικό IDE. Επίσης µπορεί να παρέχονται και πρόσθετα (plug-ins) που επεκτείνουν τις δυνατότητες αυτού του IDE.
Η αξία µιας έτοιµης αλυσίδας εργαλείων η οποία έχει ήδη µεταγλωττιστεί, αποσφαλµατωθεί
και δοκιµαστεί ειδικά για ένα συγκεκριµένο σύστηµα, είναι µεγάλη, και αυτό µπορεί να το καταλάβει κανείς µόνο στην πράξη. Παρ’ όλο που όλα τα εργαλεία ανάπτυξης τα οποία απαιτούνται για την υλοποίηση ενός ενσωµατωµένου συστήµατος Linux είναι ανοικτού κώδικα και
µπορούµε να τα κατεβάσουµε δωρεάν από το Internet, η διαδικασία ενσωµάτωσης, µεταγλώττισης και δοκιµής είναι χρονοβόρα, απαιτεί γνώσεις, και κάποιες φορές δεν ολοκληρώνεται ποτέ λόγω σφαλµάτων και ασυµβατοτήτων. Έτσι µια έτοιµη αλυσίδα εργαλείων η οποία
έχει δηµιουργηθεί από κάποιον άλλο για εµάς, µπορεί να µας γλιτώσει αρκετό χρόνο και
χρήµα. Αυτό θα µας επιτρέψει αφενός να ολοκληρώσουµε µε επιτυχία την ανάπτυξη του συστήµατός µας και αφετέρου να ασχοληθούµε περισσότερο µε την εφαρµογή µας.
2.2 Πακέτο υποστήριξης συστήµατος
Τα ολοκληρωµένα που βρίσκονται συγκολληµένα στο PCB ενός ενσωµατωµένου συστήµατος Linux, συµπεριλαµβανοµένου και του µικροελεγκτή, πριν χρησιµοποιηθούν από τις εφαρµογές µας, θα πρέπει πρώτα να έχουν αρχικοποιηθεί και καταχωρηθεί όπως απαιτείται.
Αυτό συνήθως γίνεται αρχικά από το λογισµικό εκκίνησης και στη συνέχεια από το Linux.
Η αρχικοποίηση των ηλεκτρονικών στοιχείων (πχ µνήµες, Ethernet chips κλπ) επιτυγχάνεται από εξειδικευµένο κώδικα ο οποίος αναπτύσσεται από την κατασκευάστρια εταιρεία και
µοιράζεται συνήθως δωρεάν, µε τη µορφή ενός ολοκληρωµένου πακέτου. Το πακέτο αυτό
είναι γνωστό και ως BSP (Board Support Package).
Στα ενσωµατωµένα συστήµατα Linux, ένα πακέτο BSP (ή LSP – Linux Support Package),
είναι λογισµικό που απευθύνεται σε κάποιο συγκεκριµένο υλικό και εκτελείται σε συγκεκριµένο λειτουργικό σύστηµα. Σε ορισµένες περιπτώσεις µπορεί να παρέχεται µε κάποια χρηµατική επιβάρυνση αλλά τις περισσότερες φορές είναι δωρεάν και περιλαµβάνεται ως
παρελκόµενο (σε µορφή CD, DVD κλπ) από τον προµηθευτή. Επίσης µπορεί να διατίθεται
και για κατέβασµα από το internet.
Σε ένα πακέτο BSP υπάρχει ένα σύνολο καταλόγων µέσα στους οποίους βρίσκονται όλα τα
εργαλεία που χρειαζόµαστε για το σύστηµα που αναπτύσσουµε. Ένα από αυτά είναι και η
κατάλληλη αλυσίδα εργαλείων (GNU και cross). Εκτός των άλλων, περιλαµβάνονται τροποποιήσεις του kernel και του bootloader οι οποίες έχουν σκοπό να προσαρµόσουν τα δύο αυτά τµήµατα λογισµικού, στα ιδιαίτερα χαρακτηριστικά του υλικού του συστήµατός µας.
Επίσης περιλαµβάνονται τροποποιήσεις για τη χαρτογράφηση της µνήµης, των διακοπών
και κάποιοι βασικοί drivers όπως είναι αυτός της σειριακής επικοινωνίας, του δικτύου και της
µνήµης flash. Σε ένα BSP περιλαµβάνεται επίσης και η απαραίτητη γραπτή τεκµηρίωση.
2.3 Αλυσίδα εργαλείων µεταγλώττισης
Ουσιαστικά µια αλυσίδα εργαλείων µεταγλώττισης (toolchain), διεκπεραιώνει την διαδικασία
µετατροπής πηγαίου κώδικα σε εκτελέσιµο. Απλά στην περίπτωσή των ενσωµατωµένων
συστηµάτων Linux, το εκτελέσιµο αυτό θα πρέπει να δηµιουργηθεί µε βάση τις ιδιαιτερότητες
του Linux kernel καθώς και της αρχιτεκτονικής του εκάστοτε µικροελεγκτή. Πρέπει επίσης να
πούµε, ότι και ο ίδιος ο kernel είναι κώδικας που θα πρέπει να γίνει εκτελέσιµος µέσω της
αλυσίδας.
Επικοινωνία: [email protected]
44
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Η βιβλιοθήκη C είναι διαµοιραζόµενη (shared) και λειτουργεί σαν περιτύλιγµα (wrapper) γύρω από το περιβάλλον διεπαφής του πυρήνα (Linux kernel API). Χρησιµοποιείται σαν διαµεσολαβητής από κάθε εφαρµογή που εκτελείται σε ένα σύστηµα Linux. Σε κάποιες αλυσίδες
εργαλείων υπάρχουν και επιπρόσθετες βιβλιοθήκες λογισµικού (όπως είναι η βιβλιοθήκη
zlib η οποία παρέχει υπηρεσίες συµπίεσης) καθώς και πολλά άλλα συµπληρωµατικά εργαλεία όπως:
Debuggers
Profilers
Memory checkers
Αφού ορίσαµε γενικά την αλυσίδα θα εξετάσουµε τώρα την αλυσίδα GNU Cross – Platform,
ή εν συντοµία, την αλυσίδα cross. Μια τέτοια αλυσίδα δηµιουργείται έτσι ώστε να εκτελείται
σε κάποια συγκεκριµένη πλατφόρµα (πχ x86) αλλά να παράγει εκτελέσιµο κώδικα για κάποια
άλλη πλατφόρµα (πχ AVR32).
Η αλυσίδα cross που θα δούµε στη συνέχεια περιλαµβάνει εκτελέσιµες εφαρµογές όπως
είναι ο ld linker, o gas assembler ο gcc compiler, ο ar archiver καθώς και η βιβλιοθήκη
glibc ή κάποια εναλλακτική της. Τα περισσότερα στοιχεία της αλυσίδας αποτελούν µέρος
του GNU project και µπορούµε να τα κατεβάσουµε από τη διεύθυνση ftp.gnu.org/gnu.
2.4 ∆ηµιουργία της αλυσίδας µεταγλώττισης cross
Η παραµετροποίηση και δηµιουργία της κατάλληλης αλυσίδας cross είναι µια απαιτητική
διαδικασία η οποία προαπαιτεί την κατανόησή µας σε ότι αφορά τις εξαρτήσεις (dependencies) που υπάρχουν µεταξύ των διαφόρων πακέτων λογισµικού, τον ρόλο αυτών των πακέτων, τις ασυµβατότητες που προκύπτουν από τις διάφορες εκδόσεις τους αλλά και τον
συνολικό χρόνο που απαιτείται. Επίσης απαιτούνται γνώσεις σχετικά µε:
Τα διάφορα patches
Την ειδική διαµόρφωση των εργαλείων λογισµικού για την πλατφόρµα του συστήµατος target
Αν κάποιος επιθυµεί να δηµιουργήσει ο ίδιος την cross αλυσίδα, υπάρχει ένα ειδικό project
που ονοµάζεται: “Cross Linux From Scratch ” και µπορούµε να το επισκεφτούµε εδώ:
trac.cross-lfs.org.
2.4.1 Binutils
Ένα σηµαντικό τµήµα της αλυσίδας είναι και το πακέτο binutils (binary utilities). Το πακέτο
αυτό περιλαµβάνει βοηθητικά προγράµµατα τα οποία χρησιµοποιούνται συχνά για την διαχείριση των δυαδικών object αρχείων. Τα δύο κυριότερα προγράµµατα του πακέτου binutils
είναι ο GNU assembler (as) και ο linker (ld). Στον πίνακα που ακολουθεί περιλαµβάνονται
όλα τα βοηθητικά προγράµµατα του πακέτου binutils:
Πρόγραµµα
Λειτουργία
as
GNU assembler
ld
GNU linker
gasp
GNU assembler pre-processor
Ιστότοπος εργασίας: MyThesis.org
45
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
ar
∆ηµιουργεί και διαχειρίζεται αρχειοθετηµένο περιεχόµενο (archive)
nmu
Παραθέτει σε λίστα τα περιεχόµενα ενός object αρχείου
objcopy
Αντιγράφει και µεταφράζει object αρχεία
objdump
Εµφανίζει πληροφορίες σχετικά µε το περιεχόµενο object αρχείων
ranlib
∆ηµιουργεί ένα ευρετήριο µε τα περιεχόµενα ενός αρχείου αρχειοθέτησης
readelf
Εµφανίζει πληροφορίες για ένα object αρχείο µορφής ELF
size
Παραθέτει τα µεγέθη των τµηµάτων µέσα σε ένα object αρχείο
strings
Εκτυπώνει συµβολοσειρές εκτυπώσιµων χαρακτήρων σε αρχεία object
strip
Αφαιρεί σύµβολα από object αρχεία
Μετατρέπει ετικέτες assembly που προκύπτουν από υπερφόρτωση συναρτήσεων C++ σε αντίστοιχά ονόµατα επιπέδου χρήστη (user-level)
Μετατρέπει διευθύνσεις µνήµης σε αριθµούς γραµµής πηγαίου κώδικα
c++filt
Addr2line
Πίνακας 1. Τα προγράµµατα του πακέτου binutils
2.4.2 Οι κεφαλίδες του Linux kernel
Ένα ακόµη από τα στοιχεία που απαιτούνται για την δηµιουργία µιας αλυσίδας είναι το σετ
κεφαλίδων του kernel (Linux Kernel Headers). Λόγω του ότι η βιβλιοθήκη C (η οποία είναι
µέρος της αλυσίδας) λειτουργεί σαν περιτύλιγµα που παρέχει µια πιο εύκολη προγραµµατιστική διεπαφή για τις άµεσες κλήσεις που γίνονται προς τον kernel από τις εφαρµογές µας,
κατά τη µεταγλώττισή της απαιτείται ένα υποσύνολο κεφαλίδων το οποίο περιγράφει το API
του kernel.
Από τον κατάλογο του πηγαίου κώδικα του kernel µπορούµε να εκτελέσουµε τις ακόλουθες
εντολές προκειµένου να εγκατασταθούν οι κεφαλίδες µας:
$ make ARCH=avr32 headers_check
$ make ARCH=avr32 INSTALL_HDR_PATH=headers/ headers_install;
2.4.3 Η βιβλιοθήκη C
Μία από τις σηµαντικότερες αποφάσεις που πρέπει να παρθούν όταν θέλουµε να δηµιουργήσουµε µια αλυσίδα είναι το ποια βιβλιοθήκη C θα χρησιµοποιήσουµε. Η standard GNU βιβλιοθήκη της C είναι αυτή που χρησιµοποιείται πιο συχνά σε συστήµατα Linux. Η ονοµασία
της είναι glibc και είναι ακρωνύµιο των: GNU Library C. Τα πλεονεκτήµατα της είναι η εύκολη µεταφερσιµότητά (portability) της, η υψηλή της απόδοση και η συµβατότητά της µε τα
περισσότερα standards (ISO C 99, POSIX, Unix98 κλπ). Μπορούµε να κατεβάσουµε τον πηγαίο κώδικα από τον ιστότοπο gnu.org/software/libc.
Οι πλατφόρµες που υποστηρίζει η standard GNU βιβλιοθήκη της C, τη στιγµή που γράφεται
αυτή η εργασία, είναι οι παρακάτω:
Intel ix86
Motorola 680x0
DEC Alpha
PowerPC (32 και 64 bit)
Sparc
Επικοινωνία: [email protected]
46
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Sparc64
ARM
MIPS (kernel > 2.2.15)
Intel IA64 (kernel > 2.4.0)
IBM S/390 (32 και 64 bit)
SH
CRIS
AMD x86-64
Εύκολα µπορεί να παρατηρήσει κάποιος ότι από την παραπάνω λίστα λείπει η πλατφόρµα
AVR32. Αυτό δεν αποτελεί πρόβληµα καθώς υπάρχουν όπως θα δούµε στη συνέχεια, αρκετές ποιοτικές εναλλακτικές βιβλιοθήκες C, που έχουν γραφτεί για ενσωµατωµένα συστήµατα
Linux και υποστηρίζουν την πλατφόρµα AVR32.
Η βιβλιοθήκη glibc είναι πολύ πλούσια σε χαρακτηριστικά και όπως αναφέραµε έχει πολύ
καλές επιδόσεις. Αρχικά όµως δε σχεδιάστηκε για ενσωµατωµένα συστήµατα µε περιορισµένους πόρους και µικρές χωρητικότητες µνήµης.
Η ελάχιστη χωρητικότητα που απαιτείται για την βιβλιοθήκη αυτή από ένα σύστηµα, είναι
2MB. Αυτό όµως είναι µόνο ένα µέρος του προβλήµατος. Αν σκεφτούµε ότι κάθε πρόγραµµα
που παράγεται από αυτή κατά τη µεταγλώττιση, ενσωµατώνει και κάποια αρχεία κεφαλής
της, αυτόµατα επηρεάζεται και το µέγεθος αυτών των προγραµµάτων. Έτσι έχουν δηµιουργηθεί εναλλακτικές βιβλιοθήκες της glibc οι οποίες παράγουν εκτελέσιµα που απαιτούν έως
και τη µισή χωρητικότητα και χρησιµοποιούν λιγότερη RAM. Οι πιο κοινώς χρησιµοποιούµενες είναι οι παρακάτω:
Bionic – χρησιµοποιείται στο Android
Dietlibc – χρησιµοποιείται γενικά σε ενσωµατωµένα συστήµατα
uClibc – χρησιµοποιήθηκε στην παρούσα εργασία
2.4.4 Η βιβλιοθήκη νηµάτων
Τα νήµατα (threads) είναι µια τεχνική προγραµµατισµού κατά την οποία πολλές ασύγχρονες
εργασίες (tasks) υπάρχουν στον ίδιο χώρο µνήµης κάποιας διεργασίας. Για την υποστήριξη
νηµάτων από τον Linux kernel έχουν δηµιουργηθεί κάποιες βιβλιοθήκες νηµάτων (threading
libraries). Η πιο γνωστή από αυτές είναι η βιβλιοθήκη LinuxThreads και αρχικά περιλαµβανόταν σαν πρόσθετο στην βιβλιοθήκη glibc. Λόγω κάποιων προβληµάτων όµως που
αντιµετώπιζε δηµιουργήθηκε µια νέα βιβλιοθήκη νηµάτων µε το όνοµα NPTL (New POSIX
Threading Library) η οποία είναι πια µέρος της glibc.
Επειδή όµως, η βιβλιοθήκη NPTL χρησιµοποιείται µε kernels έκδοσης 2.6 και πάνω, είναι
αρκετά συνηθισµένο σε κάποια ενσωµατωµένα συστήµατα Linux που χρειάζεται να βασίζονται σε παλαιότερες εκδόσεις kernel και παρουσιάζουν περιορισµένη χρήση νηµάτων, να
χρησιµοποιείται ακόµη η βιβλιοθήκη LinuxThreads.
Για να ελέγξουµε ποια έκδοση βιβλιοθήκης νηµάτων χρησιµοποιεί το σύστηµά µας κατά τον
χρόνο εκτέλεσής του, µπορούµε να χρησιµοποιήσουµε σε µια µικρή εφαρµογή την συνάρτηση confstr():
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
int main(void)
Ιστότοπος εργασίας: MyThesis.org
47
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
{
char name[128];
confstr(_CS_GNU_LIBPTHREAD_VERSION, name, sizeof(name));
printf("Threads library is: %s\n", name);
return 0;
}
2.4.5 Εκδόσεις πακέτων λογισµικού και διαχείριση
Για την δηµιουργία µιας αλυσίδας η επιλογή του κάθε πακέτου λογισµικού που θα χρησιµοποιηθεί (GCC, glibc και binutils) είναι µία ακόµα απόφαση που θα πρέπει να παρθεί. Λόγω
του ότι αυτά τα πακέτα έχουν αναπτυχθεί ξεχωριστά, δεν είναι πάντα συµβατά µεταξύ τους.
Ακόµα και αν χρησιµοποιήσουµε την τελευταία έκδοση του καθενός τους, δεν είναι σίγουρο
ότι δεν θα συναντήσουµε προβλήµατα.
Θα πρέπει να δοκιµάσουµε ένα συνδυασµό προσαρµοσµένο τόσο στο host, όσο και στο
target σύστηµά µας. Μπορούµε να ξεκινήσουµε από την τελευταία έκδοση του κάθε πακέτου
και µέχρι να πετύχουµε το επιθυµητό αποτέλεσµα, να την αντικαθιστούµε µε κάποια παλαιότερη. Πρέπει παρ’ όλα αυτά να προσέξουµε όσο το δυνατόν περισσότερο, να µην χρησιµοποιήσουµε πολύ παλιές εκδόσεις επειδή από ένα σηµείο και µετά θα υπάρχει ο κίνδυνος να
µην είναι συµβατές µε τις νεότερες εκδόσεις των υπόλοιπων πακέτων που µεταγλωττίζονται
επιτυχώς. Με λίγα λόγια πρέπει να επιτύχουµε τη «χρυσή τοµή».
Αν παρ’ όλα αυτά και πάλι δεν καταφέρνουµε να δηµιουργήσουµε επιτυχώς µια αλυσίδα,
µπορούµε να εφαρµόσουµε κάποιο patch (µπάλωµα) στα πακέτα που δεν µεταγλωττίζονται.
Τα patches αυτά µπορούµε να τα βρούµε στις ιστοσελίδες των κατασκευαστών που µας
προµηθεύουν το αναπτυξιακό µας σύστηµα ή τον µικροελεγκτή για τον οποίο θέλουµε να
δηµιουργήσουµε την αλυσίδα. Σε πολλές περιπτώσεις εκεί θα βρούµε και το σωστό συνδυασµό των εκδόσεων των πακέτων λογισµικού ή ακόµη και κάποια ήδη µεταγλωττισµένη αλυσίδα.
Πρέπει να πούµε ότι η µεταγλώττιση µιας αλυσίδας, η οποία θα µας δίνει τη δυνατότητα να
µεταγλωττίζουµε εφαρµογές για το target σύστηµά µας, ακόµη και αν είναι επιτυχής, σε κάποιες περιπτώσεις µπορεί να παράγει εσφαλµένα αποτελέσµατα. Αυτό µας δείχνει ότι πρόκειται για µια αρκετά περίπλοκη διαδικασία και µας βάζει συχνά στον πειρασµό να
επιλέξουµε κάποια έτοιµη λύση.
Κλείνοντας, και αφού αναφέραµε τον όρο patch, θα δώσουµε έναν ορισµό κι ένα παράδειγµα έτσι ώστε να γίνει κατανοητός. Ο λόγος που δηµιουργήθηκε αυτός ο µηχανισµός, είναι η
εκ των υστέρων τροποποίηση ενός ήδη υπαρκτού τµήµατος λογισµικού. Κάτι τέτοιο είναι άκρως αναγκαίο από τη στιγµή που το λογισµικό αυτό το µοιράζονται πολλοί χρήστες και θέλουµε όλοι να έχουν την δυνατότητα να ενηµερώσουν οι ίδιοι το λογισµικό τους.
Αρχικά πρέπει να πούµε ότι υπάρχουν δύο είδη patch, τα οποία είναι τα εξής:
∆υαδικού αρχείου (source code patch)
Πηγαίου κώδικα (binary patch)
Ένα binary patch είναι ένα εκτελέσιµο πρόγραµµα το οποίο έχει σχεδιαστεί για να τροποποιεί κάποιο άλλο πρόγραµµα. Οι τροποποιήσεις που γίνονται, συνήθως αφορούν αδυναµίες
που έχουν διαπιστωθεί κατά τη χρήση του προγράµµατος που πρέπει να τροποποιηθεί. Οι
αδυναµίες αυτές µπορεί να αφορούν την ασφάλεια, την απόδοση και πολλές φορές ακόµη
και την επιτυχή εκτέλεσή του. Με λίγα λόγια ένα patch χρησιµοποιείται σαν ένα είδος ενηµέ-
Επικοινωνία: [email protected]
48
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
ρωσης (update). Ένα κακοσχεδιασµένο patch από την άλλη, µπορεί να δηµιουργήσει νέα
προβλήµατα ή να επιδεινώσει αυτά που ήδη υπάρχουν.
Ένα source code patch στο Linux, είναι ένα πρόγραµµα που ενηµερώνει αρχεία κειµένου
σύµφωνα µε οδηγίες που δίνονται σε ένα άλλο αρχείο (patch file ή patch). Το αρχείο patch
είναι επίσης αρχείο κειµένου που περιέχει µια λίστα διαφορών και προκύπτει από την εκτέλεση ενός ειδικού προγράµµατος µε την ονοµασία diff και µε παραµέτρους το αρχικό και το
ενηµερωµένο αρχείο:
$ diff -u palio_filename neo_filename > diafores.diff
Το diff είναι ένα βοηθητικό πρόγραµµα σύγκρισης αρχείων που δίνει σαν έξοδο τις διαφορές µεταξύ δυο αρχείων. Το πρόγραµµα δείχνει τις αλλαγές που έγιναν ανά γραµµή (για
τα αρχεία κειµένου). Σύγχρονες υλοποιήσεις υποστηρίζουν και δυαδικά αρχεία. Η έξοδος του
diff είναι ένα patch.
Για την εφαρµογή ενός patch µπορεί να χρησιµοποιηθεί η εξής εντολή:
$ patch < diafores.diff
Αυτή η εντολή λέει στο εργαλείο patch να εφαρµόσει τις διαφορές που περιγράφονται στο
αρχείο diafores.diff. Αν πρόκειται να τροποποιηθούν και αρχεία σε υποφακέλους, τότε
χρειάζεται η παράµετρος -pArithmos, όπου o Arithmos ισούται µε 1 αν ο φάκελος βάσης
του δέντρου του πηγαίου κώδικα περιλαµβάνεται στις διαφορές, ή 0 αν δεν περιλαµβάνεται.
Τα patches µπορούν να αναιρεθούν µε την παράµετρο '-R':
$ patch -R < diafores.diff
Συχνά θεωρείται σαν εργαλείο πηγαίου κώδικα, ενώ στην πραγµατικότητα µπορεί να χρησιµοποιηθεί σε οποιοδήποτε κείµενο. Όταν αναφερόµαστε σε αυτή την εργασία σε κάποιο
patch θα εννοούµε πάντα την πρώτη περίπτωση.
Ακολουθεί παράδειγµα patch (ngw100-change-spi-clock-on-dataflash.patch) µε
το οποίο µπορούµε να τροποποιήσουµε την ταχύτητα του ρολογιού SPI για την ανάγνωση
της dataflash µνήµης της πλακέτας µας:
Index: linux-2.6.18/arch/avr32/boards/atngw/setup.c
===================================================================
--- linux-2.6.18.orig/arch/avr32/boards/atngw/setup.c 2011-12-19 14:15:02.000000000 +0200
+++ linux-2.6.18/arch/avr32/boards/atngw/setup.c
2011-12-19 14:15:11.000000000 +0200
@@ -29,7 +29,7 @@
{
.modalias
= "mtd_dataflash",
.controller_data = (void *)GPIO_PIN_PA(3),
.max_speed_hz = 66000000,
+
.max_speed_hz = 10000000,
.bus_num
= 0,
.chip_select
= 0,
},
Ουσιαστικά τροποποιείται η τιµή του µέλους .max_speed_hz της αντίστοιχης struct που
βρίσκεται στο αρχείο setup.c (που υπάρχει για το setup της πλακέτας του Router NGW100
στον κατάλογο arch\avr32\boards\atngw100 του kernel), από 66MHz σε 10MHz. Η
ταχύτητα αυτή, είναι κατάλληλη για την επικοινωνία του µικροελεγκτή µας µε την σειριακή
µνήµη δεδοµένων flash, µέσω του πρωτοκόλλου SPI.
Ιστότοπος εργασίας: MyThesis.org
49
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Κάτι που επίσης επιτυγχάνεται µε αυτό το patch, είναι να µπορεί ακόµα και κάποιος που
δεν καταλαβαίνει αρκετά την λειτουργία του κώδικα, να επιτύχει την τροποποίηση της ταχύτητας του SPI ρολογιού.
Τα diff files (αρχεία διαφορών) που αποτελούν την είσοδο του εργαλείου patch, είναι απλά
αρχεία κειµένου. Εκτός από το πρόγραµµα diff, αρχεία διαφορών µπορούν να παραχθούν
και από αρκετά άλλα προγράµµατα που ανήκουν στην κατηγορία των συστηµάτων διαχείρισης εκδόσεων (versioning systems), όπως το Subversion, το CVS, το RCS, το Mercurial και
το Git. Το τελευταίο µάλιστα είναι και το σύστηµα το οποίο προτείνει και ταυτόχρονα χρησιµοποιεί για την διαχείριση των εκδόσεων του Linux kernel, ο Linus Torvalds.
2.4.6 Επισκόπηση δηµιουργίας της αλυσίδας cross
Στο σύστηµα host στο οποίο θέλουµε να εγκαταστήσουµε την cross αλυσίδα ανάπτυξης, θα
πρέπει να υπάρχει επίσης εγκατεστηµένη µια «ντόπια» (native) αλυσίδα έτσι ώστε να µεταγλωττίσουµε τον πηγαίο κώδικα της πρώτης. Αν δεν υπάρχει, θα πρέπει να εγκατασταθεί.
Αυτό είναι πολύ λογικό αν σκεφτούµε ότι η cross-platform αλυσίδα είναι και αυτή ένα σύνολο
προγραµµάτων που εκτελούνται στον υπολογιστή host και εποµένως ο πηγαίος κώδικάς
τους θα πρέπει να µετατραπεί σε εκτελέσιµο τον οποία θα αντιλαµβάνεται το συγκεκριµένο
σύστηµα, που όπως είπαµε θα είναι ένας προσωπικός υπολογιστής µε κάποια διανοµή
Linux.
Στο σηµείο αυτό ας κάνουµε µια επισκόπηση των βηµάτων µεταγλώττισης που απαιτούνται
για την δηµιουργία της cross αλυσίδας:
1.
2.
3.
4.
5.
Binary utilities περιλαµβάνουν τον assembler και τον linker
Bootstrap compiler ή cross-compiler υποστήριξη µόνο της γλώσσας C
Linux headers απαιτούνται για τη µεταγλώττιση της C library
C library η glibc απαιτείται για τη λειτουργία του Full Compiler
Full cross-compiler υποστηρίζει όλες τις γλώσσες της GCC
Παρατηρούµε ότι ο cross-compiler µεταγλωττίζεται δύο φορές. Μία στο δεύτερο βήµα και
µία στο τελευταίο. Αυτό είναι φυσιολογικό γιατί κάποιες γλώσσες οι οποίες υποστηρίζονται
από τoν GCC, όπως είναι για παράδειγµα η C++, απαιτούν την υποστήριξή τους από τη
glibc. Έτσι ο bootstrap compiler δηµιουργείται αρχικά µε υποστήριξη µόνο για κώδικα C. Στη
συνέχεια και αφού µεταγλωττιστεί η C library (glibc), προκύπτει ο τελικός, ολοκληρωµένος
compiler (GCC).
Κάθε ένα από τα παραπάνω βήµατα απαιτεί επίσης κάποια στάδια για να ολοκληρωθεί και
αυτά είναι συνήθως τα εξής:
1.
2.
3.
4.
Εξαγωγή του πακέτου λογισµικού (extract)
Παραµετροποίηση του πακέτου για cross-platform development (configure)
∆ηµιουργία του πακέτου (build)
Εγκατάσταση του πακέτου (install)
2.5 Αυτοµατοποιηµένα συστήµατα
Παρά την εκπαιδευτική αξία που παρουσιάζει η δηµιουργία µιας αλυσίδας εργαλείων από το
µηδέν, τις περισσότερες φορές είναι προτιµότερο να χρησιµοποιούµε για την ανάπτυξη του
συστήµατός µας κάποιο αυτοµατοποιηµένο σύστηµα cross αλυσίδας. Οι λόγοι για τους οποίους κάτι τέτοιο είναι προτιµότερο είναι οι ακόλουθοι:
Επικοινωνία: [email protected]
50
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Λόγω του ότι η ανάπτυξη θα γίνεται σε αυτοµατοποιηµένο περιβάλλον, θα µπορεί να
επαναλαµβάνεται µε πανοµοιότυπο τρόπο κι έτσι θα µας δίνεται η δυνατότητα να διορθώνουµε λάθη του κώδικά µας απλά εκτελώντας από την αρχή την αλυσίδα και
χωρίς να υπάρχει κίνδυνος να παραλείψουµε κάποιο σηµαντικό βήµα.
Στα περισσότερα αυτοµατοποιηµένα συστήµατα γίνεται χρήση αρχείων παραµετροποίησης έτσι ώστε να διαµορφώνονται τα χαρακτηριστικά της δηµιουργίας της cross
αλυσίδας, ως προς τις εκδόσεις του λογισµικού, των στοιχείων που την απαρτίζουν
καθώς και άλλων χαρακτηριστικών που σχετίζονται µε την δηµιουργία της. Αυτό παρέχει την λεγόµενη, εκτελέσιµη τεκµηρίωση (executable documentation), η οποία
προσωπικά µου φάνηκε εξαιρετικά χρήσιµη γιατί εκτός της ευελιξίας που παρέχει,
βοηθά τον προγραµµατιστή να κατανοεί περισσότερο τον κώδικά του και να τον χειρίζεται ευκολότερα.
Με βάση τα δύο αυτά πλεονεκτήµατα µπορούµε εύκολα να συµπεράνουµε και ένα τρίτο.
Εφόσον η διαδικασία δηµιουργίας της αλυσίδας µπορεί να πραγµατοποιηθεί µέσω ενός αρχείου παραµετροποίησης, αρκεί να µοιραστούµε µόνο το αρχείο αυτό µε άλλους προγραµµατιστές µε τους οποίους συνεργαζόµαστε έτσι ώστε να δουλεύουµε επάνω στο ίδιο
αντικείµενο.
Υπάρχουν αρκετά έτοιµα αυτοµατοποιηµένα συστήµατα δηµιουργίας cross αλυσίδων. Τα
κυριότερα από αυτά είναι τα ακόλουθα:
Buildroot
Ptxdist
Crosstool
Τα δύο πρώτα συστήµατα ενσωµατώνουν την βιβλιοθήκη glibc ενώ το τρίτο χρησιµοποιεί
την εναλλακτική βιβλιοθήκη uClibc. Στα πλαίσια αυτής της εργασίας χρησιµοποιήθηκε το σύστηµα Buildroot.
2.5.1 Εναλλακτικές βιβλιοθήκες C
Όπως αναφέρθηκε ήδη, η βιβλιοθήκη glibc (GNU C library) δε σχεδιάστηκε για ενσωµατωµένα συστήµατα µε περιορισµένους πόρους και µικρές χωρητικότητες µνήµης. Για το λόγο
αυτό αναφέραµε εναλλακτικές βιβλιοθήκες οι οποίες έχουν επαρκή λειτουργικότητα και το
µέγεθός τους είναι µικρότερο. Μία από αυτές είναι και η uClibc.
Η βιβλιοθήκη uClibc προέρχεται από το uClinux project το οποίο παρείχε τη δυνατότητα
εκτέλεσης του Linux σε µικροελεγκτές που δεν διέθεταν µονάδα MMU (Memory Management
Unit). Στη συνέχεια έγινε από µόνη της ανεξάρτητο project και αργότερα ενσωµατώθηκε στον
kernel. Άρχισε επίσης να υποστηρίζει και µικροελεγκτές που διαθέτουν µονάδα MMU.
Αν και δε βασίζεται στη βιβλιοθήκη glibc, η uClibc παρέχει παρόµοια λειτουργικότητα. Οι
λειτουργίες που υπάρχουν και χρησιµοποιούνται ελάχιστα στη βιβλιοθήκη glibc έχουν αφαιρεθεί από την uClibc. Παρ’ όλα αυτά οι περισσότερες εφαρµογές οι οποίες µεταγλωττίζονται
µε την glibc, µεταγλωττίζονται και µε την uClibc. Μπορούµε να κατεβάσουµε τη βιβλιοθήκη
uClibc µε µια επίσκεψη στο uclibc.org.
2.5.2 Το αυτοµατοποιηµένο σύστηµα Buildroot
Εφόσον η βιβλιοθήκη uClibc είναι µια εναλλακτική βιβλιοθήκη C που έχει δηµιουργηθεί για
ενσωµατωµένα συστήµατα, η χρήση της προϋποθέτει την δηµιουργία και την ύπαρξη, µιας
Ιστότοπος εργασίας: MyThesis.org
51
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
ειδικά προσαρµοσµένης αλυσίδας. Όπως και µε τη βιβλιοθήκη glibc, ο καλύτερος τρόπος για
να δηµιουργήσουµε µια cross αλυσίδα είναι να χρησιµοποιήσουµε κάποιο αυτοµατοποιηµένο
σύστηµα το οποίο θα αναλάβει την επίπονη αυτή διαδικασία. Για την βιβλιοθήκη uClibc έχει
αναπτυχθεί ειδικά ένα τέτοιο σύστηµα µε την ονοµασία Buildroot.
Ουσιαστικά το Buildroot είναι ένα σύνολο από Makefiles και patches τα οποία είναι υπεύθυνα για το κατέβασµα, την παραµετροποίηση και την µεταγλώττιση λογισµικού µε τις σωστές
ρυθµίσεις. Τα makefiles, όπως και τα patches έχουν τη δική τους γλώσσα προγραµµατισµού.
Σε αντίθεση όµως µε αυτά, τα makefiles χρησιµοποιούνται για να παρέχουν πληροφορίες
στον compiler που αφορούν τον τρόπο µε τον οποίο θα µεταγλωττιστεί ένα στοιχείο λογισµικού. Ένα makefile µπορεί να δηµιουργείται αυτόµατα από κάποιο βοηθητικό πρόγραµµα ή
να γράφεται εξ’ ολοκλήρου από εµάς. Σε περίπτωση που αναπτύσσουµε ένα module µε το
IDE AVR32 Studio για παράδειγµα, το απαιτούµενο makefile µπορεί να δηµιουργηθεί αυτόµατα αν το επιθυµούµε.
Το σύστηµα Buildroot µας δίνει τη δυνατότητα να δηµιουργήσουµε εύκολα µια cross αλυσίδα, ένα root σύστηµα αρχείων και ένα εκτελέσιµο image του kernel για το target σύστηµά
µας. Το σύστηµα Buildroot µπορεί να χρησιµοποιηθεί ανεξάρτητα για κάθε µία από αυτές τις
εργασίες ή ταυτόχρονα για όλες µαζί. Υποστηρίζει µικροελεγκτές µε ή και χωρίς µονάδα
MMU, και επιπλέον, µε κάποιες τροποποιήσεις µπορεί να συνεργαστεί και µε τη βιβλιοθήκη
glibc.
Για να µελετήσουµε και να προµηθευτούµε το αυτοµατοποιηµένο σύστηµα Buildroot, µπορούµε να επισκεφτούµε τον ιστότοπο buildroot.uclibc.org. Στην παρούσα εργασία
χρησιµοποιήθηκε (µετά από αρκετές διορθώσεις) το ειδικά διαµορφωµένο σύστηµα Buildroot
που παρέχει η εταιρεία ATMEL µέσω του ιστότοπού της. Στο πακέτο αυτό είχαν ενσωµατωθεί οι κατάλληλοι drivers και υπήρχαν έτοιµες κάποιες πολύ βασικές ρυθµίσεις. Αυτός είναι
και ο πιο ενδεδειγµένος τρόπος όταν αναπτύσσουµε ένα σύστηµα. Πρέπει να χρησιµοποιούµε σε καίρια σηµεία τα εργαλεία που προτείνει ο κατασκευαστής γιατί έτσι θα είµαστε βέβαιοι
όταν προκύπτει κάποιο πρόβληµα, ότι ευθύνεται η δική µας δουλειά και όχι κάποια άλλη αόριστη παράµετρος που θα είναι δύσκολο να εντοπίσουµε.
Μπορούµε επίσης να κατεβάσουµε το Buildroot µέσα από κάποιο terminal του συστήµατος
host στο οποίο εκτελείται η διανοµή Linux που έχουµε επιλέξει (πχ Ubuntu), εκτελώντας την
παρακάτω εντολή:
$ wget http://buildroot.uclibc.org/downloads/snapshots/buildroot-snapshot.tar.bz2
Όταν ολοκληρωθεί η λήψη αποσυµπιέζουµε το αρχείο που λήφθηκε και πιθανότατα βρίσκεται στον κατάλογο home, και εισερχόµαστε σε αυτόν µε την εντολή cd. Οι αντίστοιχες εντολές
αποσυµπίεσης και αλλαγής τρέχοντος καταλόγου εργασίας είναι οι παρακάτω:
$ tar jxvf buildroot-snapshot.tar.bz2
$ cd buildroot
Καθ’ όλη την διάρκεια της εργασίας µας µε το σύστηµα Buildroot θα πρέπει να υπάρχει µια
ενεργή σύνδεση Internet έτσι ώστε να υπάρχει η δυνατότητα κατεβάσµατος των απαραίτητων πακέτων λογισµικού. Αν για κάποιο λόγο θέλουµε να κάνουµε offline build, δηλαδή να
κατεβάσουµε ότι απαιτείται στον υπολογιστή µας και στη συνέχεια να αποσυνδεθούµε, µπορούµε να χρησιµοποιήσουµε την ακόλουθη εντολή:
$ make source
Στη συνέχεια µέσω της εντολής make και της παραµέτρου menuconfig εισερχόµαστε στο
περιβάλλον παραµετροποίησης του αυτοµατοποιηµένου συστήµατος buildroot:
Επικοινωνία: [email protected]
52
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
$ make menuconfig
Για να εκτελεστεί επιτυχώς αυτή η εντολή θα πρέπει προηγουµένως να έχουν εγκατασταθεί
όλα τα πακέτα λογισµικού τα οποία προαπαιτούνται. Συνήθως ένα από αυτά τα πακέτα είναι
το libncurses-dev. Αυτό γίνεται και µέσα από το γραφικό περιβάλλον εγκατάστασης Ubuntu Software Center:
Εικόνα 8. Το περιβάλλον Ubuntu Software Center
Όταν τελικά είναι όλα στη θέση τους, το παράθυρο διαλόγου που θα εµφανιστεί µετά την
εντολή make menuconfig θα µοιάζει µε το ακόλουθο:
Εικόνα 9. Περιβάλλον παραµετροποίησης του αυτοµατοποιηµένου συστήµατος buildroot
Ιστότοπος εργασίας: MyThesis.org
53
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Γενικά η παραµετροποίηση του Buildroot αφορά τρεις κύριες κατηγορίες. Το υλικό, τη διαδικασία µεταγλώττισης και το λογισµικό. Όπου το λογισµικό µπορεί να χωριστεί σε τρεις υποκατηγορίες. Τον kernel, την αλυσίδα και τα πακέτα.
Αν δεν θέλουµε να εµβαθύνουµε πολύ, µπορούµε να χρησιµοποιήσουµε κάποιο έτοιµο αρχείο παραµετροποίησης που πιθανόν παρέχεται από τον προµηθευτή του συστήµατός µας,
και περιλαµβάνει τις βασικές, αρχικές ρυθµίσεις το οποίο µπορούµε να το βρούµε συνήθως
σε κάποιο κατάλογο του buildroot (πχ στον κατάλογο configs) ή στο BSP που παρέχει ο
προµηθευτής. Για να υποδείξουµε στο Buildroot που θα βρει αυτό το αρχείο αρκεί να µεταβούµε στην επιλογή “Load an Alternate Configuration File” και να πληκτρολογήσουµε εκεί τη διαδροµή του αρχείου παραµετροποίησης που θέλουµε. Αυτό µας δείχνει στην
πράξη το πλεονέκτηµα της εκτελέσιµης τεκµηρίωσης, των αυτοµατοποιηµένων συστηµάτων
δηµιουργίας cross αλυσίδας, που αναφέραµε και νωρίτερα. Το ίδιο ακριβώς αποτέλεσµα
µπορούµε να επιτύχουµε και χωρίς να εισέλθουµε στο menu παραµετροποίησης εκτελώντας
την παρακάτω εντολή:
$ make onoma-target-systimatos_defconfig
Αν όµως θέλουµε να εµβαθύνουµε περισσότερο και να προσθέσουµε ή να αφαιρέσουµε
κάποιες λειτουργίες, θα πρέπει να κατανοήσουµε και να µάθουµε όλο το περιβάλλον του
Buildroot. Μπορούµε να λαµβάνουµε πληροφορίες για την κάθε επιλογή του µενού επιλέγοντάς το και πατώντας το πλήκτρο ?. Οι πληροφορίες πλοήγησης στο menu είναι απλές και
όπως είδαµε και στην εικόνα, υπάρχουν γραµµένες στο παράθυρο διαλόγου του περιβάλλοντος παραµετροποίησης. Το κυρίως µενού του Buildroot περιλαµβάνει συνήθως τις ακόλουθες επιλογές:
Target Architecture – µας επιτρέπει να ορίσουµε την αρχιτεκτονική του target
συστήµατός (πχ AVR32) µας για το οποίο η cross αλυσίδα θα παράγει εκτελέσιµα
αρχεία.
Target Architecture Variant (optional) – εδώ καθορίζεται η οικογένεια
του µικροελεγκτή του συστήµατός µας (πχ AP7000).
Target ABI – αυτό το υποµενού υποστηρίζεται µόνο από την αρχιτεκτονική MIPS
και αν έχουµε επιλέξει κάποια άλλη αρχιτεκτονική, παύει να εµφανίζεται και στο
menu.
Target options – σε αυτό το υποµενού υπάρχουν ρυθµίσεις που αφορούν µόνο
το περιβάλλον Buildroot και δεν επηρεάζουν καθόλου τη µεταγλώττιση της cross αλυσίδας.
Build options – εδώ µπορούµε να ρυθµίσουµε διάφορες επιλογές σχετικά µε την
διαδικασία δηµιουργίας της cross αλυσίδας. Οι ρυθµίσεις αυτές αφορούν τα εξής:
⇒ Τις εντολές που χρησιµοποιούνται για να πραγµατοποιήσουν εργασίες όπως
είναι για παράδειγµα το κατέβασµα κάποιου αρχείου µέσω ftp ή µέσω κάποιου
ιστότοπου, την αναζήτηση πηγαίου κώδικα µέσω των συστηµάτων Subversion και Git, την αποσυµπίεση αρχείων Gzip, Bzip2 και tar µέσω γραµµής εντολών.
⇒ Servers και τοποθεσίες λήψης χρήσιµων στοιχείων όπως είναι ο kernel, το
GNU λογισµικό (GCC, binutils, πακέτα GDB) καθώς επίσης και τα διάφορα
επιπλέον πακέτα που απαιτούνται.
Επικοινωνία: [email protected]
54
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
⇒ Τον κατάλογο στον οποίο θα εγκατασταθούν η cross αλυσίδα και οι κεφαλίδες. Μπορούµε να τροποποιήσουµε αυτή την επιλογή εισάγοντας τη διαδροµή
που επιθυµούµε.
⇒ Η κατάληξη _nofpu για τα ονόµατα των εκτελέσιµων που είναι συµβατά µε
υλικό το οποίο δεν υποστηρίζει µονάδα πράξεων κινητής υποδιαστολής.
⇒ Το πρόθεµα (prefix) και το επίθεµα (suffix) που θέλουµε να έχουν οι κατάλογοι
για την δηµιουργία αλυσίδων που υποστηρίζουν πολλαπλές αρχιτεκτονικές.
Αυτή η λειτουργία δε συνίσταται να χρησιµοποιηθεί
⇒ Ένα προαιρετικό προσωποποιηµένο επίθεµα για να δώσουµε κάποια ονοµασία στην cross αλυσίδα που θα δηµιουργηθεί. Μπορούµε να βάλουµε την επωνυµία µας, το όνοµα της επιχείρησής µας ή ότι άλλο επιθυµούµε.
⇒ Μια έκδοση της µικροεφαρµογής strip και την νέα της έκδοση µε όνοµα
sstrip. Μπορούµε να επιλέξουµε την νεότερη εκτός και αν παρουσιαστούν
θέµατα ασυµβατότητας. Επίσης µπορούµε να επιλέξουµε να µην χρησιµοποιηθεί καµία (none).
⇒ Επιλογή για ρύθµιση της cross αλυσίδας έτσι ώστε να κάνει χρήση στατικών
βιβλιοθηκών αντί για δυναµικές.
Σε κάθε νέα (ή παλιότερη) έκδοση του Buildroot οι παραπάνω επιλογές αλλά και
όσες θα αναλύσουµε στη συνέχεια, µπορεί να διαφέρουν (οι νέες λειτουργίες συνήθως συµβολίζονται µε την ένδειξη NEW). Αυτό όµως δεν είναι εµπόδιο για εµάς,
αφού µετά από εξοικείωση µε την χρήση µιας έκδοσης µπορούµε εύκολα να προσαρµοζόµαστε στις ιδιαιτερότητες των υπολοίπων.
Toolchain – αυτό το υποµενού διαχειρίζεται κάποιες βασικές ρυθµίσεις παραµετροποίησης για αλυσίδες που υποστηρίζονται από το Buildroot. Οι ρυθµίσεις αυτές
είναι:
⇒ Buildroot Toolchain – Επιλογή για το αν θέλουµε να χρησιµοποιήσουµε
µια εξωτερική αλυσίδα ή να δηµιουργήσουµε µια νέα. Είναι προτιµότερο να
επιλέξουµε “Buildroot Toolchain”.
⇒ Kernel Headers – Επιλογή έκδοσης κεφαλίδων (πχ: 3.1.x). Η έκδοση
που θα επιλέξουµε εξαρτάται από την έκδοση του kernel που θέλουµε να τρέχει στο target σύστηµά µας. Θα πρέπει να είναι ίδιες µεταξύ τους.
⇒ uClibc Options – Επιλογή έκδοσης της βιβλιοθήκης uClibc. Η καλύτερη
επιλογή είναι η πιο πρόσφατη έκδοση (και όχι η daily snapshot). Επίσης µπορούµε να ορίσουµε το αρχείο παραµετροποίησης (πχ: uClibc0.9.32.config) της uClibc που επιθυµούµε και αν θα υπάρχουν κάποια έτοιµα δοκιµαστικά προγράµµατα για να επιβεβαιώσουµε την ορθή λειτουργία
της βιβλιοθήκης uClibc.
⇒ Binutils Options – Επιλογή έκδοσης του πακέτου Binutils. Η πιο πρόσφατη έκδοσή είναι και η προτιµότερη (πχ: 2.18-avr32-1.0.1).
⇒ GCC Options – Επιλογή έκδοσης του GCC compiler. Και πάλι η πιο πρόσφατη έκδοση είναι η καλύτερη (πχ: 4.2.2-avr32-2.1.5), εκτός και αν θέ-
Ιστότοπος εργασίας: MyThesis.org
55
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
λουµε να εξοικονοµήσουµε χώρο στη µνήµη του target συστήµατός µας, όποτε σε αυτή την περίπτωση επιλέγουµε κάποια παλαιότερη. Ένα άλλο σηµαντικό χαρακτηριστικό που θα µπορούµε να ενεργοποιήσουµε είναι η χρήση µιας
µια διαµοιραζόµενης βιβλιοθήκης (libgcc).
⇒ GDB Options – Επιλογή δηµιουργίας και εγκατάστασης των λειτουργιών
αποσφαλµάτωσης (GNU GDB debugger). Εδώ µπορούµε να αποφασίσουµε
για το αν θα υπάρχει κάποιος gdb server στο target σύστηµά µας αλλά και το
αν θα υπάρχει gdb server/client στο host σύστηµά µας.
⇒ Common Toolchain Options – Εδώ µπορούµε να επιλέξουµε αν θα παρέχεται υποστήριξη για αρχεία µεγαλύτερα από 2GB, αν θα υπάρχει υποστήριξη
από την βιβλιοθήκη uClibc για τα πρωτόκολλα IPv6 και RPC, αν θα υποστηρίζονται µεγάλου εύρους χαρακτήρες (WCHAR – wide characters) οι οποίοι απαιτούνται από κάποια πακέτα λογισµικού καθώς και άλλες λεπτοµέρειες που
αφορούν την υποστήριξη C++ και την βιβλιοθήκη νηµάτων που θα χρησιµοποιηθεί (πχ LinuxThreads ή NPTL).
Στην επόµενη εικόνα βλέπουµε το υποµενού Toolchain καθώς και κάποιες
από τις ρυθµίσεις και τα χαρακτηριστικά του συστήµατός µας:
Επικοινωνία: [email protected]
56
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Εικόνα 10. Το υποµενού Toolchain του Buildroot
System Configuration – Σε αυτό το υποµενού µπορούµε να ρυθµίσουµε τη διαχείριση των συσκευών (/dev management) για το αν θα καθορίζεται από κάποιο
στατικό πίνακα ή δυναµικά µέσων των devtmpfs, udev και mdev. Μπορούµε να καθορίσουµε κάποιες διαδροµές αρχείων πινάκων που περιέχουν πληροφορίες δικαιω-
Ιστότοπος εργασίας: MyThesis.org
57
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
µάτων πρόσβασης αλλά και διαδροµές που αφορούν πίνακες διαχείρισης συσκευών.
Επίσης µπορούµε να επιλέξουµε την ταχύτητα (baudrate) της σειριακής επικοινωνίας
καθώς και κάποιες άλλες λεπτοµέρειες που αφορούν το σύστηµα αρχείων και κάποια
προσωπικά scripts που θα θέλαµε να εκτελούνται.
Package Selection for the target – Αυτό το υποµενού παρέχει πάρα πολλές επιλογές που αφορούν πακέτα λογισµικού εφαρµογών που θα είναι διαθέσιµα
στο target σύστηµά µας. Για παράδειγµα µπορούµε να επιλέξουµε αν θα υποστηρίζεται και σε ποια έκδοσή του, το πακέτο µικροεφαρµογών BusyBox. Επίσης υπάρχει
δυνατότητα ρύθµισης µιας σειράς άλλων παραµέτρων που αφορούν τη συµπίεση αρχείων, την υποστήριξη ήχου και γραφικών µέσω δηµοφιλών βιβλιοθηκών, την υποστήριξη scripting προγραµµατισµού (PHP, Lua, microperl, tcl, haserl κλπ),
βιβλιοθήκες συµπίεσης και κρυπτογράφησης, εφαρµογές δικτύου, διαχειριστές πακέτων, real-time δυνατότητες (µέσω xenomai), κειµενογράφοι και άλλα.
Filesystem images – Εδώ επιλέγουµε τον τύπο του root συστήµατος αρχείων
που θέλουµε να υποστηρίζει το target σύστηµά µας (πχ JFFS) και το αν αυτό θα είναι
πακεταρισµένο (πχ: tar).
Bootloaders – Σε αυτό το υποµενού καλούµαστε να επιλέξουµε το λογισµικό εκκίνησης που θα εκκινεί το target σύστηµά µας.
Kernel – Τέλος, στο υποµενού αυτό µας δίνεται η δυνατότητα να επιλέξουµε την έκδοση του kernel, τον τύπο της δυαδικής του µορφής (πχ uImage), τις real time δυνατότητες, αλλά και κάποιες άλλες λεπτοµέρειες που αφορούν πιο εξεζητηµένα
χαρακτηριστικά.
Αφού έχουµε ολοκληρώσει τις ρυθµίσεις του Buildroot, τις αποθηκεύουµε και βγαίνουµε
από το περιβάλλον παραµετροποίησης. Έπειτα εκτελούµε την εντολή make ακολουθουµένη
από το όνοµα του αρχείου παραµετροποίησης του target συστήµατός µας και στη συνέχεια
εκτελούµε ξανά την εντολή make χωρίς καµία παράµετρο αυτή τη φορά. Το Buildroot θα κατεβάσει, θα παραµετροποιήσει και θα εγκαταστήσει την cross αλυσίδα στον κατάλογο που
του έχουµε ορίσει. Οι εντολές make που χρησιµοποιήθηκαν για το σύστηµά µας είναι οι ακόλουθες:
$ make atngw100_defconfig
$ make
Αν µετά την εκτέλεση της τελευταίας make εµφανιστούν σφάλµατα, τότε πιθανότατα υπάρχει πρόβληµα µε κάποια dependencies και ανάλογα µε την υπόδειξη που παίρνουµε ως
feedback από το terminal θα πρέπει να προβούµε στην εγκατάσταση αυτών των πακέτων.
Αν όλα πάνε καλά τότε στον κατάλογο dl του συστήµατος Buildroot θα υπάρχουν τα αρχεία
που φαίνονται στην επόµενη εικόνα (οι εκδόσεις τους µπορεί να διαφέρουν):
Επικοινωνία: [email protected]
58
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Εικόνα 11. Τα περιεχόµενα του καταλόγου dl του συστήµατος Buildroot
Πρέπει επίσης να υπενθυµίσουµε ότι αν και αρχικά υποθέσαµε πως η native αλυσίδα του
συστήµατος host είναι ήδη εγκατεστηµένη, στην πράξη σχεδόν πάντοτε κάτι λείπει, και αυτό
το κάτι θα πρέπει να το εγκαταστήσουµε χειροκίνητα. Ένας τρόπος για να το επιτύχουµε είναι να έχουµε βρει την λίστα των εφαρµογών που απατούνται. Ένας άλλος τρόπος είναι να
εκτελούµε την εντολή make dependencies και κάθε φορά να εγκαθιστούµε τα πακέτα που
µας υποδεικνύονται. Η διαδικασία αυτή πρέπει να επαναληφθεί µέχρι το αποτέλεσµα της εκτέλεσης της εντολής αυτής να είναι το κενό. ∆ηλαδή µέχρι να µην υπάρχει κάποιο άλλο dependency.
$ make dependencies
Μια ενδεικτική λίστα των dependencies (δηλαδή των εξαρτήσεων λογισµικού) που µπορεί
να απαιτηθούν για την λειτουργία του συστήµατος Buildroot και την µεταγλώττιση της cross
αλυσίδας είναι η και η ακόλουθη:
Bison – Parser συµβατός µε τον συντακτικό αναλυτή YACC
G++ – GNU C++ compiler
Flex – Λεξικός αναλυτής
Gettext – Εφαρµογές για παροχή πακέτων ξένων γλωσσών
Ιστότοπος εργασίας: MyThesis.org
59
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Texinfo – Σύστηµα online τεκµηρίωσης για προβολή πληροφοριών βοήθειας
Patch – Χειρίζεται αρχεία diff για να εφαρµόσει τα απαιτούµενα patches
Εφόσον τελικά είναι όλα στη θέση τους και αφού έχει εκτελεστεί και η τελευταία make, θα
αρχίσει η αυτόµατη διαδικασία δηµιουργίας της αλυσίδας αλλά και κάποιων άλλων βασικών
εργαλείων. Η διαδικασία µπορεί να διαρκέσει από µερικά λεπτά έως και πάνω από µία ώρα,
ανάλογα και µε τις δυνατότητες του host συστήµατός µας.
2.6 Παραµετροποίηση uClibc, kernel και BusyBox µέσω Buildroot
Στην προηγούµενη παράγραφο χρησιµοποιήσαµε το αυτοµατοποιηµένο σύστηµα Buildroot
για να δηµιουργήσουµε µια cross αλυσίδα βασισµένη στη C βιβλιοθήκη, uClibc, χρησιµοποιώντας τις default ρυθµίσεις από το αρχείο παραµετροποίησης που υπάρχει στον κατάλογο
configs (atngw100_defconfig).
Συνήθως η παραµετροποίηση αυτή είναι αρκετή για τη δηµιουργία ενός τυπικού ενσωµατωµένου συστήµατος Linux, όµως υπάρχουν περιπτώσεις στις οποίες θα θέλαµε να κάνουµε
τροποποιήσεις. Οι τροποποιήσεις αυτές τις περισσότερες φορές αφορούν την προσθήκη
κάποιων επιπλέων λειτουργιών ή την αφαίρεση κάποιων ήδη υπαρχόντων, για εξοικονόµηση
πόρων. Επειδή αυτό δε συµβαίνει συχνά θα αναφέρουµε ονοµαστικά µόνο, τις επιλογές παραµετροποίησης. Η παραµετροποίηση της uClibc θα γίνει και πάλι µέσω του Buildroot. Για
να εισέλθουµε στο γραφικό περιβάλλον αρκεί να πληκτρολογήσουµε στο terminal του συστήµατος host, την παρακάτω εντολή:
$ make uclibc-menuconfig
To παράθυρο διαλόγου που θα εµφανιστεί αν όλα έχουν πάει καλά φαίνεται στην εικόνα:
Εικόνα 12. Γραφικό περιβάλλον παραµετροποίησης της uClibc 0.9.30
Επικοινωνία: [email protected]
60
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Αν δεν εµφανιστεί και λάβουµε κάποιο µήνυµα σφάλµατος (πχ: No rule to make target …), τότε ή έχουµε παραλείψει κάποιο βήµα ή έχουµε πληκτρολογήσει λάθος την εντολή.
Μπορούµε να χρησιµοποιήσουµε κι εδώ κάποιο έτοιµο αρχείο παραµετροποίησης, αλλά θα
πρέπει κάποιος να µας το παρέχει διαφορετικά θα πρέπει να κάνουµε τις ρυθµίσεις µόνοι
µας. Ονοµαστικά λοιπόν, οι ρυθµίσεις που αφορούν τη βιβλιοθήκη uClibc είναι οι εξής:
Target Architecture
Target Architecture Features and Options
General Library Settings
Advanced Library Settings
Networking Support
String and Stdio Support
Big and Tall
Library Installation Options
Security Options
uClibc development/debugging options
Αφού ολοκληρωθεί η παραµετροποίηση της βιβλιοθήκης uClibc σύµφωνα µε τις ανάγκες
µας, θα πρέπει να αντιγράψουµε το αρχείο .config το οποίο περιλαµβάνει τις ρυθµίσεις
µας, στον κατάλογο του Buildroot toolchain/uclibc. Στη συνέχεια εκτελούµε εκ νέου τις
παρακάτω εντολές:
$ make clean
$ make
Αυτό θα καταστήσει µόνιµες τις νέες ρυθµίσεις και θα ισχύουν κάθε φορά που θα εργαζόµαστε στο Buildroot, µέχρι να θελήσουµε να τις αλλάξουµε και πάλι. Τα ίδια ισχύουν και για
τις ρυθµίσεις του kernel αλλά και για τις ρυθµίσεις του BusyBox.
Στη συνέχεια θα αναφερθούµε επίσης επιγραµµατικά, και σε ότι αφορά την παραµετροποίηση του kernel. Για να εισέλθουµε στο menu επιλογών του kernel εκτελούµε σε γραµµή εντολών την παρακάτω εντολή:
$ make linux26-menuconfig
To παράθυρο διαλόγου που θα εµφανιστεί, φαίνεται στην εικόνα:
Ιστότοπος εργασίας: MyThesis.org
61
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 13. Γραφικό περιβάλλον παραµετροποίησης του Linux Kernel 2.6.27.6
Ονοµαστικά οι ρυθµίσεις που αφορούν τον kernel είναι οι εξής:
General setup
Enable loadable module support
Enable the block layer
System type and features
Power management options
Bus options
Executable file formats
Networking support
Device Drivers
File systems
Kernel hacking
Security options
Cryptographic API
Library routines
Αφού ολοκληρωθεί και η παραµετροποίηση του kernel συνεχίζουµε µε αυτή του BusyBox.
Όπως και στις προηγούµενες δύο περιπτώσεις η εντολή που θα εκτελέσουµε είναι παρόµοια:
$ make busybox-menuconfig
Στην εικόνα βλέπουµε το µενού επιλογών του BusyBox:
Επικοινωνία: [email protected]
62
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Εικόνα 14. Γραφικό περιβάλλον παραµετροποίησης του BusyBox 1.13.1
Ονοµαστικά οι ρυθµίσεις που αφορούν το BusyBox είναι οι εξής:
Busybox Settings
---Applets--Archival Utilities
Coreutils
Console Utilities
Debian Utilities
Editors
Finding Utilities
Init Utilities
Login/Password Management Utilities
Linux Ext2 FS Progs
Linux Module Utilities
Linux System Utilities
Miscellaneous Utilities
Networking Utilities
Ιστότοπος εργασίας: MyThesis.org
63
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Print Utilities
Mail Utilities
Process Utilities
Runit Utilities
Shells
System Logging Utilities
Απ’ ότι παρατηρούµε το menu του BusyBox χωρίζεται ουσιαστικά σε δύο κατηγορίες. Στις
ρυθµίσεις (settings) και στις εφαρµογές (applets). Τα settings του BusyBox που µπορούµε να
τροποποιήσουµε είναι τα εξής:
General Configuration
Build Options
Debugging Options
Installation Options (“make install” behavior)
Busybox Library Training
2.7 Γραµµή εντολών
Η διεπαφή γραµµής εντολών (CLI – Command Line Interface) όπως αναφέραµε είναι ένας
µηχανισµός που µας επιτρέπει να αλληλεπιδρούµε µε το λειτουργικό σύστηµα. Μπορούµε
επίσης να καλούµε άλλες εφαρµογές του ίδιου υπολογιστή ή να συνδεόµαστε στην γραµµή
εντολών ενός αποµακρυσµένου ενσωµατωµένου συστήµατος που υποστηρίζει τη διεπαφή
αυτή. Η διαδικασία είναι γενικά πολύ απλή. Υπάρχει κάποιο σύνολο διαθέσιµων εντολών
από το οποίο επιλέγουµε κάθε φορά εκείνη την οποία είναι κατάλληλη για να ολοκληρωθεί η
διεργασία που επιθυµούµε.
Οι εντολές είναι και αυτές προγράµµατα τα οποία υπάρχουν συνήθως µέσα στον κατάλογο
της εγκατάστασης bin ή σε άλλους καταλόγους του συστήµατος αρχείων. Όταν εµφανίζεται
το command prompt (παρότρυνση πληκτρολόγησης εντολής ή δροµέας) αµέσως µετά το
σύµβολο $, πληκτρολογούµε την εντολή µας και στη συνέχεια πατάµε το πλήκτρο Enter.
Αυτό έχει ως άµεσο αποτέλεσµα το κέλυφος να αναζητήσει στο διαθέσιµο σύστηµα αρχείων
το πρόγραµµα το οποίο θα έχει το ίδιο όνοµα µε την εντολή µας, προκειµένου να την εκτελέσει.
Αφού ολοκληρωθεί η εκτέλεση µιας εντολής, το σύστηµα επιστρέφει σε µορφή γραµµών
κειµένου, το αποτέλεσµα της εκτέλεσης. Το αποτέλεσµα συνήθως είναι κάποια απάντηση
στην ερώτηση που κάναµε µέσω της εντολής µας, µια νέα διαθέσιµη γραµµή εντολών αν η
εντολή µας δεν απαιτούσε να εµφανιστεί κάτι, ή κάποιο µήνυµα σφάλµατος που µας ενηµερώνει ότι πληκτρολογήσαµε εντολή που δεν υποστηρίζεται ή ότι απαιτείται κάποια περεταίρω
ενέργεια.
Τις εντολές µπορούµε να τις πληκτρολογούµε και να τις εκτελούµε µία – µία πατώντας το
πλήκτρο Enter (carriage return), ή µπορούµε να τις οµαδοποιούµε σε ένα αρχείο έτσι ώστε
να λειτουργούν σαν ένα ενιαίο πρόγραµµα (script ή shell script).
2.8 Βασικές εντολές φλοιού
Πριν αναλύσουµε τους προσοµοιωτές τερµατικού θα αφιερώσουµε µια σύντοµη παράγραφο προκειµένου να παραθέσουµε κάποιες βασικές εντολές οι οποίες χρησιµοποιούνται συχνότερα στον φλοιό (shell) του Linux. Όλες οι εντολές που παρουσιάζονται αφορούν την
διανοµή Ubuntu:
Επικοινωνία: [email protected]
64
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Εντολές Linux
Εντολή
Περιγραφή
Χρήσιµες παράµετροι
ls <κατάλογος>
εµφανίζει τα περιεχόµενα
του τρέχοντος καταλόγου
-l (εµφάνιση περιεχοµένων σε µορφή λίστας)
-a (εµφάνιση όλων των αρχείων)
cd <κατάλογος>
αλλαγή καταλόγου
<χωρίς παράµετρο> (επιστροφή στον κατάλογο home)
.. (ένα επίπεδο επάνω)
- (επιστροφή στον τελευταίο κατάλογο)
mv <από> <σε>
µετακίνηση αρχείου
cp <από> <σε>
αντιγραφή αρχείου
-a (διατήρηση των χαρακτηριστικών του αρχείου)
-r (αντιγραφή καταλόγου µε περιεχόµενα)
rm <αρχείο>
διαγραφή αρχείου ή άδειου
καταλόγου
-r (διαγραφή καταλόγου µε περιεχόµενα)
cat <αρχείο>
grep <κείµενο>
<αρχείο>
συνένωση αρχείων και εµφάνιση του αποτελέσµατος
στην βασική µονάδα εξόδου
εµφάνιση γραµµών κειµένου
που ικανοποιούν κάποιο
κριτήριο αναζήτησης
find
αναζήτηση αρχείων
du
εµφάνιση κατάστασης χρήσης της µονάδας αποθήκευσης
pwd
εµφάνιση του τρέχοντος
καταλόγου εργασίας
chmod xxx <αρχείο>
αλλαγή δικαιωµάτων πρόσβασης ενός αρχείου
chown user:group
<αρχείο>
αλλαγή ιδιοκτήτη αρχείου
make
εκτέλεση του makefile που
υπάρχει στον τρέχον κατάλογο
less <αρχείο>
ανάγνωση αρχείου
echo <κείµενο>
εµφάνιση µιας γραµµής κειµένου
man <εντολή>
εγχειρίδιο εντολής
wc
καταµέτρηση λέξεων, γραµµών, χαρακτήρων και bytes
sudo
εκτέλεση αρχείου ως διαχειριστής (super user ή root)
-n (εµφάνιση αριθµού γραµµής που βρέθηκε το κείµενο)
-e ‘<κείµενο>’ (εµφάνιση αποτελεσµάτων που περιέχουν το κείµενο κλειδί ακριβώς όπως το ζητάµε)
--max-depth X (εµφάνιση υποκαταλόγων σε βάθος
που ορίζει το X)
- x (καταµέτρηση µόνο των πραγµατικών αρχείων)
- h (εµφάνιση αποτελεσµάτων σε αναγνώσιµη µορφή)
- ne “\x00\x00\x00\x00” (δεκαεξαδική µορφή)
-l (καταµέτρηση γραµµών)
-w (καταµέτρηση λέξεων)
-c (καταµέτρηση bytes)
-m (καταµέτρηση χαρακτήρων)
Πίνακας 2. Εντολές Linux
Ιστότοπος εργασίας: MyThesis.org
65
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Ορισµένες από τις παραπάνω εντολές θα εµφανίσουν το αποτέλεσµά στη βασική µονάδα
εξόδου (standard output) του συστήµατός µας. Μπορούµε αντί γι’ αυτό να αποθηκεύσουµε
αυτά τα αποτελέσµατα σε ένα αρχείο προσθέτοντας το σύµβολο > µετά την εντολή, καθώς
και το όνοµα του αρχείου στο οποίο θέλουµε να γίνει η αποθήκευση:
cat > test.txt
Μετά την εκτέλεση της παραπάνω εντολής θα είµαστε σε θέση να εισάγουµε το κείµενό µας.
Όταν ολοκληρώσουµε την εισαγωγή µπορούµε µε τον συνδυασµό πλήκτρων Ctrl+D να
βγούµε από τον κειµενογράφο αποθηκεύοντας ταυτόχρονα τα όσα πληκτρολογήθηκαν, στο
αρχείο test.txt.
Κάποιες φορές όµως είναι χρήσιµο να στείλουµε το αποτέλεσµα µιας εντολής σαν είσοδο σε
µια άλλη (pipelining). Αυτό επιτυγχάνεται µε τον χαρακτήρα διασωλήνωσης | (pipe):
εντολή1 | εντολή2 | εντολή3 |...
Θα µπορούσαµε να πάρουµε ως παράδειγµα τις εντολές grep και wc. Αν υποθέσουµε ότι
θέλουµε να καταµετρήσουµε τις γραµµές ενός αρχείου οπού περιέχεται µια συγκεκριµένη λέξη, η αντίστοιχη εντολή θα έµοιαζε µε την παρακάτω:
grep <λέξη> <όνοµα αρχείου> | wc <παράµετροι>
Φυσικά δεν είναι δυνατό να θυµόµαστε συνέχεια όλες τις εντολές του Linux και τις παραµέτρους τους µε την κάθε λεπτοµέρειά τους. Για το λόγο αυτό, σε κάθε εντολή έχει ενσωµατωθεί ένα µικρό κείµενο βοήθειας (manual) το οποίο εµφανίζεται µε την εντολή man. Για
παράδειγµα, αν θέλουµε να µάθουµε τη λειτουργία της εντολής tail αρκεί να εκτελέσουµε
στο terminal την παρακάτω εντολή:
man tail
Αφού εισέλθουµε στο εγχειρίδιο της εντολής και διαβάσουµε ότι µας ενδιαφέρει, µπορούµε
στη συνέχεια να εξέλθουµε πιέζοντας το πλήκτρο q.
2.9 Προσοµοιωτές τερµατικών
Ο πιο απλός και κοινός τρόπος για να επικοινωνήσουµε µε ένα ενσωµατωµένο σύστηµα
είναι να χρησιµοποιήσουµε έναν προσοµοιωτή τερµατικού (terminal emulator) στο σύστηµα
host και να συνδεθούµε µέσω κάποιας RS232 σειριακής θύρας.
Για να καταλάβουµε τι είναι ένας προσοµοιωτής τερµατικού θα πρέπει να θυµηθούµε τα
παλιά τερµατικά (dummy ή video terminals ή thin clients) ή κονσόλες (consoles), που χρησιµοποιούνταν για την πρόσβαση σε κάποιο ακριβό για την εποχή, κεντρικό υπολογιστή. Τα
τερµατικά αυτά αποτελούνταν µόνο από οθόνη και πληκτρολόγιο και δεν διέθεταν σκληρό
δίσκο και επεξεργαστή. Χρησιµοποιούσαν εξ’ ολοκλήρου τους πόρους του κεντρικού υπολογιστή στον οποίο συνήθως υπήρχε εγκατεστηµένο το λειτουργικό σύστηµα UNIX. Αυτό γινόταν κυρίως για λόγους οικονοµίας και αρχικά είχε εφαρµοστεί µόνο σε πανεπιστήµια,
τράπεζες και κρατικούς φορείς. Αργότερα αναπτύχθηκαν και τερµατικά που διέθεταν κάποια
επεξεργαστική ισχύ (smart terminals ή fat clients).
Ο προσοµοιωτής τερµατικού είναι ένα πρόγραµµα που εξοµοιώνει τη λειτουργία της κονσόλας. Η βασική του λειτουργία είναι να επιτρέπει την πρόσβαση των χρηστών στο κέλυφος ή
αλλιώς, στην γραµµή εντολών (command line) του λειτουργικού συστήµατος στο οποίο βρί-
Επικοινωνία: [email protected]
66
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
σκεται εγκατεστηµένος. Ο standard προσοµοιωτής τερµατικού στο GNU/Linux είναι ο xterm
που εγκαθίσταται συνήθως µαζί µε τον Xserver.
Το κέλυφος (shell) είναι ένα πρόγραµµα το οποίο παίρνει τις εντολές που πληκτρολογούµε
στη γραµµή εντολών και τις δίνει στο λειτουργικό σύστηµα για να εκτελεστούν. Παλαιότερα
αυτός ήταν και ο µόνος τρόπος επικοινωνίας µε έναν υπολογιστή που έτρεχε Linux ή Unix.
Στα περισσότερα συστήµατα Linux το shell που χρησιµοποιείται είναι bash το οποίο αποτελεί
µετεξέλιξη του sh.
Παρ’ όλο που υπάρχουν αρκετοί προσοµοιωτές τερµατικού για Linux, δεν είναι όλοι αποτελεσµατικοί. Για παράδειγµα κάποιοι έχουν πρόβληµα επικοινωνίας µε τον bootloader κατά τη
διάρκεια µεταφοράς αρχείων, κάποιοι άλλοι µε την κωδικοποίηση των χαρακτήρων που πληκτρολογούνται ή/και εµφανίζονται, και κάποιοι µε τους USB to Serial µετατροπείς που χρησιµοποιούνται όταν το σύστηµα host δε διαθέτει κάποια σειριακή θύρα. Σε αυτή την περίπτωση
αρκετές φορές ευθύνονται και οι drivers που υπάρχουν διαθέσιµοι στο σύστηµα host για τον
µετατροπέα. Οι πιο κοινώς χρησιµοποιούµενοι προσοµοιωτές τερµατικού για Linux είναι οι
παρακάτω:
Minicom
C-Kermit
PuTTY
HyperTerminal
Στα Windows τα πράγµατα είναι πιο εύκολα αφού οι drivers που υπάρχουν για τους µετατροπείς είναι περισσότερο δοκιµασµένοι και οι εφαρµογές είναι επίσης πιο σταθερές απ’ ότι
στο Linux. Για παράδειγµα η εφαρµογή Putty σε συνδυασµό µε κάποιον USB σε Serial µετατροπέα της Prolific είναι ένας αξιόπιστος τρόπος επικοινωνίας µε σταθερή λειτουργία.
2.9.1 Ο προσοµοιωτής τερµατικού C-Kermit
Η εφαρµογή C-Kermit έχει αναπτυχθεί από το πανεπιστήµιο Columbia και είναι µέρος του
έργου µε την ονοµασία Kermit. Παρέχει έναν ενοποιηµένο περιβάλλον για δικτυακές λειτουργίες και υποστηρίζει µεγάλο αριθµό από διαφορετικές πλατφόρµες. Μπορούµε να την εγκαταστήσουµε στο σύστηµά µας µε τη βοήθεια της εντολής:
$ sudo apt-get install ckermit
Με την εντολή kermit µπορούµε να αρχίσουµε να χρησιµοποιούµε την εφαρµογή. Σε αντίθεση µε τον προσοµοιωτή Minicom, ο Kermit δεν παρέχει κάποιο οπτικοποιηµένο menu εντολών αλλά µπορούµε να µάθουµε τις εντολές του διαβάζοντας το εγχειρίδιο χρήσης του,
είτε κατεβάζοντάς το από τη διεύθυνση columbia.edu/kermit/ckututor.pdf, είτε
χρησιµοποιώντας την εντολή:
$ man kermit
Ο C-kermit παρέχει κάποια εργαλεία και κάποιους τρόπους επικοινωνίας µε το target σύστηµα στο οποίο θέλουµε να συνδεθούµε. Τα βασικότερα στοιχεία που υποστηρίζει είναι τα
εξής:
Προγραµµατισµό µέσω scripts
Σειριακή επικοινωνία (άµεση ή µέσω κλήσης)
Αυτόµατη κλήση modem
Συνδέσεις TCP/IP
Ιστότοπος εργασίας: MyThesis.org
67
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
⇒
⇒
⇒
⇒
⇒
⇒
Telnet
SSH
Rlogin
FTP
HTTP 1.0
Internet Kermit Service
Για να χρησιµοποιήσουµε τον C-Kermit στο σύστηµα host θα πρέπει πρώτα να έχουµε καθορίσει τις παραµέτρους σύνδεσης µε το σύστηµα target. Για να το επιτύχουµε αυτό θα πρέπει να δηµιουργήσουµε ένα αρχείο παραµετροποίησης µε την επέκταση .kermrc το οποίο
θα αντιγράψουµε στον κατάλογο που προτείνει η τεκµηρίωση του C-Kermit. Ένα παράδειγµα
του κώδικα που θα περιλαµβάνεται στο αρχείο αυτό είναι και το ακόλουθο:
; Ιδιότητες γραµµής
set modem type none
set line /dev/ttyS0
set speed 115200
set carrier-watch off
set handshake none
set flow-control none
;
;
;
;
;
;
Direct connection
Device file
Line speed
No carrier expected
No handshaking
No flow control
; Ιδιότητες επικοινωνίας
robust
set receive packet-length 1000
set send packet-length 1000
set window 10
;
;
;
;
Most robust transfer settings macro
Max pack len remote system should use
Max pack len local system should use
Nbr of packets to send until ack
; Ιδιότητες µεταφοράς αρχείων
set file type binary
set file names literal
; All files transferred are binary
; Don't modify filenames during xfers
Αφού έχουµε δηµιουργήσει το αρχείο ρυθµίσεων µπορούµε να χρησιµοποιήσουµε τον CKermit εκτελώντας την παρακάτω εντολή στο terminal του host συστήµατός µας:
$ Kermit -c
Αν όλα έχουν πάει καλά, θα δούµε το εξής µήνυµα:
Connecting to /dev/ttyS0, speed 115200
Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by ? to see other options.
Παρά το ότι δε διατίθεται γραφικό περιβάλλον, µε τον C-Kermit µπορούµε να επικοινωνήσουµε µε το ενσωµατωµένο µας σύστηµα µέσω γραµµής εντολών και να κάνουµε ότι και µε
τους υπόλοιπους προσοµοιωτές τερµατικού, αλλά ταυτόχρονα περιλαµβάνονται και κάποια
µοναδικά χαρακτηριστικά. Για παράδειγµα, όταν εκκινούµε κάποια µεταφορά αρχείου µε τη
βοήθεια του bootloader του target συστήµατός µας, ο bootloader περιµένει µέχρι να λάβει το
αρχείο που θα του σταλεί από το σύστηµα host µέσω της κατάλληλης εντολής αποστολής
αρχείου που διαθέτει ο C-Kermit. Στο target σύστηµα της εργασίας όπως έχουµε αναφέρει
και όπως θα δούµε και αργότερα, ο bootloader που χρησιµοποιήθηκε είναι ο U-Boot. Για να
λάβουµε κάποιο αρχείο µέσω του C-Kermit αρκεί να εισέλθουµε στο περιβάλλον του bootloader και να εκτελέσουµε την εντολή loadb. Το αποτέλεσµα θα είναι το target σύστηµά µας
και πιο συγκεκριµένα ο bootloader να τεθεί σε αναµονή λήψης αρχείου όπως φαίνεται και
στην παρακάτω εικόνα:
Επικοινωνία: [email protected]
68
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Εικόνα 15. Εκτέλεση της εντολής loadb σε περιβάλλον Uboot
Για να σταλεί το αρχείο σειριακά η µε οποιοδήποτε άλλο τρόπο, θα πρέπει στο σύστηµα
host να υπάρχει εγκατεστηµένος ο προσοµοιωτής C-Kermit. Στη συνέχεια αφού έχουµε αποφασίσει για το αρχείο που θέλουµε να στείλουµε στο target σύστηµά µας, µέσω της γραµµής εντολών του C-Kermit εκτελούµε την κατάλληλη εντολή µεταφοράς αρχείων που είναι η
send.
2.9.2 Ο προσοµοιωτής τερµατικού PuTTY
Η εφαρµογή PuTTY είναι ένας δωρεάν και ανοικτού κώδικα προσοµοιωτής τερµατικού, ο
οποίος παρέχει υποστήριξη, και µπορεί να λειτουργεί ως client, για τα πρωτόκολλα SSH,
Telnet, Rlogin, raw TCP καθώς επίσης υποστηρίζει και συνδέσεις µέσω σειριακής επικοινωνίας, λειτουργώντας σαν σειριακή κονσόλα (serial console).
∆ηµιουργήθηκε από το πανεπιστήµιο MIT σε γλώσσα C και αρχικά είχε γραφτεί για να εκτελείται µόνο σε υπολογιστές που είχαν σαν λειτουργικό τους σύστηµα τα Windows. Σήµερα
υπάρχουν εκδόσεις για Linux, Unix, Mac, αλλά και για λειτουργικά κινητών όπως Symbian,
Android και Windows Mobile.
Κάποιες από τις σηµαντικότερες λειτουργίες που περιλαµβάνει η εφαρµογή PuTTY είναι οι
ακόλουθες:
Αποθήκευση των sessions και των ρυθµίσεων για µελλοντική χρήση
Υποστήριξη για συνδέσεις µέσω των τοπικών σειριακών θυρών
Υποστήριξη Telnet
Κρυπτογραφηµένη επικοινωνία µέσω SSH
Γραµµή εντολών για SCP (secure copy) και SFTP (SSH FTP) clients που υποστηρίζεται από τα εκτελέσιµα αρχεία pscp.exe και psftp.exe αντίστοιχα.
Έλεγχος µέσω port forwarding (τοπικά, αποµακρυσµένα ή δυναµικά) µε το πρωτόκολλο SSH
Υποστήριξη IPv6
Υποστήριξη αλγόριθµων κρυπτογράφησης AES, DES κ.α.
Πιστοποίηση δηµόσιου κλειδιού
Στα Windows η εφαρµογή PuTTY είναι αυτόνοµη (standalone), δηλαδή δεν χρειάζεται εγκατάσταση. Υπάρχει ένα εκτελέσιµο αρχείο (putty.exe) το οποίο εκτελούµε µε διπλό κλικ του
ποντικιού. Το παράθυρο διαλόγου που εµφανίζεται είναι αυτό που φαίνεται στην επόµενη
εικόνα:
Ιστότοπος εργασίας: MyThesis.org
69
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 16. Παράθυρο διαλόγου παραµετροποίησης του τερµατικού Putty
Αν θέλουµε να συνδεθούµε σειριακά στο σύστηµα target τότε θα πρέπει να ρυθµίσουµε κάποιες παραµέτρους οι οποίες απαιτούνται. Για να το κάνουµε αυτό, στο αριστερό τµήµα του
παραθύρου (Category), στην κατηγορία Connection, επιλέγουµε Serial. Θα εµφανιστεί
το παράθυρο ρυθµίσεων των τοπικών σειριακών θυρών του συστήµατος host:
Εικόνα 17. Ρυθµίσεις σειριακής επικοινωνίας του τερµατικού Putty
Επικοινωνία: [email protected]
70
Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux – Κεφάλαιο 2
Η λειτουργία της εφαρµογής στο Linux είναι σχεδόν πανοµοιότυπη. Για να την κατεβάσουµε, να την εγκαταστήσουµε και να την εκκινήσουµε, εκτελούµε σε κάποιο terminal τις παρακάτω εντολές:
$ sudo apt-get install putty
$ putty
Στη συνέχεια, µε τη βοήθεια ενός σειριακού καλωδίου συνδέουµε τη σειριακή θύρα του target συστήµατος µε εκείνη του host και κάνουµε κλικ στο κουµπί Open για να συνδεθούµε.
Στην εικόνα βλέπουµε το περιβάλλον γραµµής εντολών του BusyBox και επίσης βλέπουµε
να έχει εκτελεστεί η εντολή εµφάνισης περιεχοµένων ls.
Εικόνα 18. Εκτέλεση της εντολής ls σε περιβάλλον γραµµής εντολών BusyBox
2.10 IDEs για Linux
Όπως γνωρίζουµε, τα εργαλεία ανάπτυξης για τα ενσωµατωµένα συστήµατα Linux είναι
ουσιαστικά ένα σύνολο εφαρµογών οι οποίες παρέχουν ως διεπαφή τους µια γραµµή εντολών. Για καιρό η ανάπτυξη γινόταν µε έναν απλό κειµενογράφο και τον φλοιό (shell) του λειτουργικού συστήµατος. Παρ’ όλα αυτά, όλο και περισσότερο η µέθοδος αυτή τείνει να
καταργηθεί, καθώς τα συστήµατα IDE εξελίσσονται και γίνονται πιο πρακτικά και πιο δηµοφιλή για τους προγραµµατιστές.
Τα συστήµατα IDE, ουσιαστικά προσφέρουν ένα γραφικό περιβάλλον διεπαφής για όλα τα
εργαλεία (ή τις εφαρµογές) ανάπτυξης. Έτσι αντί να γράφουµε την εφαρµογή µας σε κάποιο
κειµενογράφο και έπειτα να την εκτελούµε µέσω γραµµής εντολών, χρησιµοποιούµε ένα παραθυρικό περιβάλλον το οποίο είναι πιο φιλικό και πιο γρήγορο. Στην εργασία αυτή χρησιµοποιήθηκε το AVR32 Studio.
2.10.1 Το IDE AVR32 Studio
Το AVR32 Studio είναι ένα ολοκληρωµένο γραφικό περιβάλλον ανάπτυξης που παρέχεται
δωρεάν από την εταιρεία ATMEL και είναι βασισµένο στο ανοικτού λογισµικού IDE µε την
ονοµασία Eclipse.
Το Eclipse παρέχει µια ανοικτή πλατφόρµα ανάπτυξης η οποία αποτελείται από επεκτάσιµα
πλαίσια εργασίας (frameworks) και εργαλεία, για τη δηµιουργία, την ανάπτυξη και τη διαχείριση λογισµικού. Επειδή είναι γραµµένο σε Java µπορεί να εκτελείται σε οποιοδήποτε σύστηµα host (Windows, Linux, Mac).
Τα IDE που είναι βασισµένα σε Eclipse µπορεί να µας επιτρέπουν ακόµα και την παραµετροποίηση του συστήµατος αρχείων root καθώς και του ίδιου του kernel, µέσω ενός γραφικού περιβάλλοντος το οποίο είναι βασισµένο σε JAVA.
Ιστότοπος εργασίας: MyThesis.org
71
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Το AVR32 Studio λοιπόν, είναι ένα IDE για τη δηµιουργία AVR32 εφαρµογών. Παρέχει ένα
σύνολο εργαλείων όπως διαχείριση έργων (project management), διαχείριση εκδόσεων λογισµικού (CVS – Code Versioning System), επεξεργαστή κειµένου για κώδικα C/C++ µε συντακτικό µαρκάρισµα κώδικα (code highlighting) και συµπλήρωση κώδικα (code completion).
Επίσης παρέχεται ενσωµατωµένος debugger µε δυνατότητες για stepping και breakpoints σε
επίπεδο κώδικα (source level) ή σε επίπεδο εντολών µηχανής (instruction level). Μέσω του
AVR32 Studio µπορούµε να έχουµε πλήρη εποπτεία του υλικού του µικροελεγκτή. Για παράδειγµα µπορούµε να γνωρίζουµε ανά πάσα στιγµή το περιεχόµενο των καταχωρητών, την
κατάσταση της µνήµης και να έχουµε µια εικόνα για τις εισόδους και εξόδους του µικροελεγκτή µας.
Το AVR32 Studio υποστηρίζει όλους τους 32bit µικροελεγκτές της ATMEL. ∆ίνει τη δυνατότητα για ανάπτυξη και αποσφαλµάτωση, για αυτόνοµες (δηλαδή χωρίς λειτουργικό σύστηµα)
εφαρµογές άλλα και για εφαρµογές Linux (για την οικογένεια µικροελεγκτών AP7000). Για να
επιτευχθεί η επικοινωνία του µε το σύστηµα target, θα πρέπει να µεσολαβεί ανάµεσα στο
target και το host σύστηµα. κάποιος emulator ή/και κάποιος programmer (πχ: JTAGICE mkII,
AVR ONE!, AVR dragon).
Μέσω των βοηθητικών εφαρµογών avr32program και avr32gdbproxy το AVR32
Studio, µπορεί να επιτύχει τον προγραµµατισµό και την αποσφαλµάτωση εφαρµογών. Οι
βοηθητικές εφαρµογές που περιλαµβάνονται, µας βοηθούν επίσης να τροποποιήσουµε κάποιες σηµαντικές παραµέτρους του συστήµατός µας όπως η τάση λειτουργίας του και ο χρονισµός του.
Επικοινωνία: [email protected]
72
ΚΕΦΑΛΑΙΟ
3
Το υλικό που υποστηρίζει το
ενσωµατωµένο Linux
Εισαγωγή
Στο προηγούµενο κεφάλαιο καλύψαµε oορισµένα βασικά θέµατα που αφορούν τα εργαλεία
ανάπτυξης λογισµικού για ενσωµατωµένα συστήµατα Linux. Σε αυτό το κεφάλαιο θα αναλύσουµε το υλικό το οποίο υποστηρίζεται από το Linux. Πιο συγκεκριµένα θα ασχοληθούµε µε
τα εξής:
Αρχιτεκτονικές µικροελεγκτών
Οδηγοί συσκευών και Linux Kernel
Παράδειγµα ανάπτυξης module
∆ίαυλοι και διεπαφές
Είσοδοι και Έξοδοι (I/Os)
Modem
Επικοινωνία µε τη µνήµη
Υλικό δικτύωσης
Παρά το ότι θα αναλύσουµε αρκετά στοιχεία του υλικού που υποστηρίζει το Linux, θα παραλείψουµε κάποια άλλα τα οποία δεν κρίνονται αναγκαία για την υλοποίηση του συστήµατός µας καθώς και όλα αυτά που δεν έχουν ευρεία εφαρµογή (τουλάχιστον προς το παρόν)
στα ενσωµατωµένα συστήµατα. Επίσης όταν κρίνεται χρήσιµο για την καλύτερη κατανόηση
ενός όρου του κειµένου, θα παρατίθεται και το αντίστοιχο θεωρητικό υπόβαθρο.
Φυσικά, θα ήταν αδύνατο στα πλαίσια µιας εργασίας όλα τα παραπάνω να αναλυθούν σε
τέτοιο επίπεδο ώστε να µπορεί κάποιος µετά από µια απλή ανάγνωση να προχωρήσει και
στην υλοποίησή τους. Αποτελούν όµως, µέρος µιας εικόνας που όσο πιο ολοκληρωµένη είναι τόσο πιο εύκολα µπορούµε να καταλάβουµε µε τι ασχολούµαστε και τι θέλουµε να κάνουµε.
Σε αυτό το κεφάλαιο υπάρχουν ορισµένα παραδείγµατα ανάπτυξης και µεταγλώττισης κώδικα τα οποία πραγµατοποιούνται µέσω του συστήµατος Buildroot. Για να µπορούν να γίνουν κατανοητά θα πρέπει να συνδυαστούν µε το πρακτικό µέρος της εργασίας αλλά και µε
το κεφάλαιο “Εργαλεία Ανάπτυξης Ενσωµατωµένων Συστηµάτων Linux” του θεωρητικού µέρους.
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
3.1 Αρχιτεκτονικές µικροελεγκτών
Το Linux εκτελείται σε ένα µεγάλο και συνεχώς αυξανόµενο αριθµό διαφορετικών αρχιτεκτονικών, αλλά δε χρησιµοποιούνται όλες αυτές οι αρχιτεκτονικές στα ενσωµατωµένα συστήµατα. Μια γρήγορη µατιά στον υποκατάλογο arch του Linux kernel, µας δείχνει
τουλάχιστον 24 αρχιτεκτονικές οι οποίες υποστηρίζονται από τον επίσηµο πυρήνα, ενώ παράλληλα ετοιµάζονται και άλλες οι οποίες θα ενσωµατώνονται σε µελλοντικές εκδόσεις.
Εικόνα 19. Οι αρχιτεκτονικές που υποστηρίζονται από τον Linux Kernel
Στη συνέχεια παραθέτουµε µια λίστα των οκτώ πιο γνωστών αρχιτεκτονικών που υποστηρίζονται από το Linux. Από αυτές θα αναφέρουµε σύντοµα µόνο τις πρώτες τέσσερις, οι οποίες
χρησιµοποιούνται περισσότερο στα ενσωµατωµένα συστήµατα:
AVR32 (Atmel)
ARM (ARM Holdings)
PowerPC (Apple, IBM, Motorola)
MIPS (MIPS Technologies)
Intel x86 (Intel)
M32R (RENESAS)
Motorola 68000 (Motorola)
SuperH (Hitachi)
Η αρχιτεκτονική AVR32 της εταιρείας ATMEL, η οποία κατασκευάζει και τους µικροελεγκτές
8bit AVR για ενσωµατωµένα συστήµατα χαµηλών απαιτήσεων, είναι η πιο νέα στην αγορά
των µικροελεγκτών 32bit.
Η αρχιτεκτονική AVR32 συνδυάζει πολλές άλλες υπό-αρχιτεκτονικές και µπορεί να υποστηρίξει εντολές DSP καθώς και κύκλωµα βελτιστοποίησης Java εντολών (Java Hardware Acceleration). Η αρχιτεκτονική AVR32 παρέχει αρκετούς τύπους λειτουργίας µικροελεγκτών, µε
υποστήριξη για 16bit εντολές σταθερού µήκους και 32bit εντολές εκτεταµένου µήκους. Κατά
κάποιο τρόπο, η µορφή εντολών 16bit είναι παρόµοια στο σκοπό µε το σετ εντολών της αρχιτεκτονικής ARM Thumb που θα δούµε και αµέσως µετά.
Το αρχικό port (µεταφορά) του Linux kernel για AVR32 ανακοινώθηκε το 2006. Τη στιγµή
αυτή υποστηρίζεται µόνο η οικογένεια µικροελεγκτών AT32AP (AP7000, AP7001, AP7002)
Επικοινωνία: [email protected]
74
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
καθώς και αρκετές αναπτυξιακές πλακέτες όπως η ATNGW100 που χρησιµοποιήθηκε στα
πλαίσια αυτής της εργασίας.
Η οικογένεια µικροελεγκτών ARM (Advanced RISC Machine), αναπτύσσεται από την εταιρεία ARM Holdings Ltd. Σε αντίθεση µε άλλους κατασκευαστές ολοκληρωµένων, όπως είναι
η Intel, η Freescale και η Atmel, η εταιρεία ARM Holdings δεν κατασκευάζει τους δικούς της
µικροελεγκτές. Αντί αυτού, σχεδιάζει για τους πελάτες της πλήρεις πυρήνες επεξεργαστών οι
οποίοι είναι βασισµένοι στην αρχιτεκτονική ARM και τους χρεώνει µόνο για τον σχεδιασµό
και την άδεια να ενσωµατώνουν τον πυρήνα αυτόν, επιτρέποντάς τους έτσι να δηµιουργήσουν τους δικούς τους ολοκληρωµένους µικροελεγκτές. Ένα τέτοιο παράδειγµα είναι και οι
νέοι µικροελεγκτές της Atmel: SAM 3, 4, 7 και 9.
Όλοι οι µικροελεγκτές που βασίζονται στον πυρήνα ARM υποστηρίζουν το ίδιο σετ εντολών
(instruction set). Αυτό είναι ένα τεράστιο πλεονέκτηµα αφού ο κώδικας που έχει γραφτεί για
έναν µικροελεγκτή µε πυρήνα ARM κάποιας εταιρείας, είναι απόλυτα συµβατός µε έναν µικροελεγκτή ίδιου πυρήνα, που έχει κατασκευαστεί από µια άλλη εταιρεία. Αυτό φυσικά ισχύει
κυρίως για πηγαίο κώδικα που είναι γραµµένος σε assembly. Προ στιγµής υποστηρίζονται
από τον Linux kernel τουλάχιστον 40 διαφορετικοί µικροελεγκτές µε πυρήνα ARM.
Η αρχιτεκτονική PowerPC (PPC) είναι αποτέλεσµα συνεργασίας των εταιρειών Apple, IBM
και Motorola. Συµπεριλαµβάνει ιδέες από την εργασία των τριών αυτών εταιρειών και ιδιαίτερα την βελτιστοποίηση απόδοσης µε την ενισχυµένη RISC αρχιτεκτονική της εταιρείας IBM
που υπάρχει ακόµα και χρησιµοποιείται πολύ στους 64bit servers της. Η αρχιτεκτονική PPC
αρχικά ήταν περισσότερο γνωστή για τη χρήση της στους υπολογιστές MAC της Apple αλλά
τώρα χρησιµοποιείται και από άλλους προµηθευτές υπολογιστών, καθώς επίσης και στα ενσωµατωµένα συστήµατα.
Σε σχέση µε τις υπόλοιπες αρχιτεκτονικές (i386, ARM, AVR32), η αρχιτεκτονική PPC έχει
την καλύτερη υποστήριξη από τον πυρήνα του Linux. Αυτό οφείλεται κυρίως στο πλήθος των
συσκευών Linux που βασίζονται σε αυτή. Ένας άλλος παράγοντας είναι και η ενσωµάτωσή
της από µεγάλες εταιρείες του ενσωµατωµένου Linux, όπως είναι για παράδειγµα η εταιρεία
MontaVista.
Η αρχιτεκτονική MIPS έχει ενσωµατωθεί σε πολλές παιχνιδοµηχανές (Nintendo 64bit, Playstation κ.α.) και σε αρκετές άλλες καταναλωτικές ηλεκτρονικές συσκευές. Η εταιρεία έχει παρόµοια φιλοσοφία µε την ARM. ∆ηλαδή σχεδιάζει τον πυρήνα και στη συνέχεια των πουλά σε
κατασκευαστές µικροελεγκτών. Η κύρια διαφορά τους είναι ότι η αρχιτεκτονική MIPS δεν υποστηρίζει το ίδιο σετ εντολών σε όλες τις υλοποιήσεις της. Οι πυρήνες MIPS έχουν ενσωµατωθεί από πολλούς µεγάλους κατασκευαστές µικροελεγκτών 32bit (πχ NXP από την Philips)
και 64bit (πχ Broadcom, Toshiba κλπ). Επίσης η αρχιτεκτονική MIPS έχει ενσωµατωθεί και
σε FPGA (Field Programmable Gate Area) συσκευές. Η υποστήριξη της αρχιτεκτονικής από
το Linux είναι πιο περιορισµένη από τις υπόλοιπες που αναφέραµε.
Η επιλογή της αρχιτεκτονικής AVR32 της εταιρείας ATMEL στην παρούσα εργασία, έγινε
λόγω της πολύ βολικής αναπτυξιακής πλακέτας ATNGW100 και λόγω της ήδη υπάρχουσας
καλής εµπειρίας µε την εν λόγω εταιρεία και τους 8bit µικροελεγκτές της. Αυτό µπορεί να
µοιάζει µε υπεραπλούστευση της έρευνας για την επιλογή αναπτυξιακής πλακέτας όµως
χρειάστηκαν τουλάχιστον δύο µήνες µελέτης για να παρθεί αυτή η απόφαση.
Μπορεί θεωρητικά η σχεδίαση ενός ενσωµατωµένου συστήµατος Linux να έχει κάποια στάδια ώστε να καταλήξουµε στο τελικό σύστηµα, όµως στην πράξη επιλέγεται συνήθως κάποια
λύση (αναπτυξιακή πλακέτα) στην οποία υπάρχει ήδη ένα έτοιµο κοµµάτι δουλειάς (κώδικας
και PCB) που είναι ανοικτό και τεκµηριωµένο από τον προµηθευτή της. Αυτό διευκολύνει πολύ, ιδιαίτερα σε περιπτώσεις που προκύπτουν σφάλµατα. Σε αυτές τις περιπτώσεις µπορούµε να είµαστε σίγουροι ότι δεν ευθύνεται κάποιος παράγοντας που προκύπτει από
Ιστότοπος εργασίας: MyThesis.org
75
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
λανθασµένη υλοποίηση του υλικού, και έτσι µπορούµε να γλιτώσουµε χρόνο αναζητώντας το
σφάλµα µόνο σε ότι προσθέσαµε εµείς. Όταν πια έχουµε προτυποποιήσει το σύστηµά µας
και η εφαρµογή µας λειτουργεί σωστά, µπορούµε να το αντιγράψουµε εφαρµόζοντας τις απαραίτητες τροποποιήσεις στο υλικό ή/και στο λογισµικό και να το αναπαράγουµε ως ένα
νέο ανεξάρτητο προϊόν.
3.2 Οδηγοί συσκευών και Linux Kernel
Σε ένα σύστηµα Linux µπορούµε να αλληλεπιδράσουµε µε το υλικό µέσα από το περιβάλλον του χρήστη (user space) και µέσα από το περιβάλλον του πυρήνα (Kernel space). Για να
επιτύχουµε κάτι τέτοιο, στην πρώτη περίπτωση γράφουµε µια εφαρµογή, ενώ στη δεύτερη
γράφουµε έναν driver. Ο χειρισµός του υλικού µέσω του Kernel space είναι γενικά ασφαλέστερος, ταχύτερος και πιο αποτελεσµατικός. Η επιλογή εξαρτάται κάθε φορά από την περίπτωση που καλούµαστε να αντιµετωπίσουµε. Παρ’ όλα αυτά ορισµένες φορές η δεύτερη
περίπτωση είναι και η µοναδική επιλογή (το αντίθετο δεν ισχύει).
Πριν ξεκινήσουµε την ανάλυση των οδηγών συσκευών του Linux πρέπει πρώτα να αναφέρουµε για ποιες συσκευές γράφονται αυτοί οι οδηγοί. Οι συσκευές για τις οποίες γράφονται οι
οδηγοί στο Linux χωρίζονται σε τρεις κλάσεις:
Συσκευές χαρακτήρων (char devices)
Συσκευές τµηµάτων (block devices)
∆ιεπαφές δικτύωσης (network interfaces)
Στο Linux όλες οι συσκευές ενώνονται µε κάποιο δίαυλο (bus). Ο δίαυλος αυτός µπορεί να
είναι φυσικός (υλικό) ή ιδεατός (λογισµικό). Ο πρωτεύον σκοπός της ύπαρξης των διαύλων
είναι η συνένωση παρόµοιων συσκευών, ο συντονισµός της αρχικοποίησης τους (initialization), ο τερµατισµός της λειτουργίας τους και η διαχείριση της τροφοδοσίας τους.
Όταν µια συσκευή βρεθεί να ταιριάζει µε κάποιο driver, συνενώνονται µεταξύ τους. Ο τρόπος που θα πραγµατοποιηθεί αυτή η συνένωση εξαρτάται από τον δίαυλο που χρησιµοποιεί
η συσκευή. Τις περισσότερες φορές το λογισµικό που είναι υπεύθυνο για τη διαχείριση του
διαύλου διατηρεί και κάποιο πίνακα µε τις ονοµασίες όλων των συνδεδεµένων σε αυτόν συσκευών καθώς και των διαθέσιµων drivers. Συγκρίνοντας τις ονοµασίες των συσκευών µε
εκείνες των drivers συµπεραίνονται και οι συνενώσεις που µπορούν να γίνουν. Για να ολοκληρωθεί η συνένωση µιας συσκευής µε κάποιον driver, καλείται η συνάρτηση probe() του
driver η οποία µε τη σειρά της περνά ως όρισµα ένα δείκτη προς τη συσκευή αυτή. Από το
σηµείο αυτό και µετά, είναι ευθύνη του driver να αρχικοποιήσει και να καταχωρήσει τη συσκευή στα κατάλληλα υποσυστήµατα του Linux Kernel.
Αν πρόκειται για συσκευή που µπορεί να συνδέεται και να αποσυνδέεται κατά τη λειτουργία
του συστήµατος (hotplug) ή αν πρόκειται για κάποιο module θα πρέπει πρώτα να καλείται η
συνάρτηση remove() προκειµένου να γίνεται ασφαλής κατάργηση.
Οι οδηγοί συσκευών ή drivers, είναι γενικά το σηµείο στο οποίο ο Linux kernel συναντά το
υλικό και επικοινωνεί µε αυτό. Ο ρόλος τους είναι να κρύβουν τις λεπτοµέρειες λειτουργίας
της συσκευής για την οποία έχουν γραφτεί και ταυτόχρονα να οδηγούν τις κλήσεις των εφαρµογών µας σε συγκεκριµένες λειτουργίες της συσκευής αυτής. Σε περίπτωση που δεν γράφουµε απλά µια εφαρµογή αλλά αναπτύσσουµε εµείς οι ίδιοι ένα ενσωµατωµένο σύστηµα
Linux, οι drivers πρέπει να γραφτούν στο µεγαλύτερο µέρος τους από εµάς ή να τους προµηθευτούµε από κάποια εταιρεία ή οργανισµό.
Τα είδη των drivers χωρίζονται ανάλογα µε τον σκοπό και τη λειτουργία τους, σε τρεις κύριες κατηγορίες:
Επικοινωνία: [email protected]
76
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Οδηγοί χαρακτήρων (char drivers) – Γράφονται για συσκευές χαρακτήρων (char devices). Οι συσκευές αυτές είναι προσβάσιµες µέσω ακολουθιών χαρακτήρων (bytes).
Παραδείγµατα τέτοιων συσκευών είναι τα αρχεία και οι κονσόλες.
Οδηγοί τµηµάτων (block drivers) – Γράφονται για συσκευές µόνιµης αποθήκευσης
όπως είναι οι µνήµες Flash και οι οπτικοί δίσκοι. Οι συσκευές αυτές είναι προσβάσιµες µέσω του καταλόγου /dev του κεντρικού συστήµατος αρχείων (root filesystem).
Οδηγοί δικτύου (network drivers) – Οι οδηγοί δικτύου αφού δηλώσουν (register) τον
εαυτό τους στον kernel µέσω κατάλληλων δοµών δεδοµένων (structs) µπορούν στη
συνέχεια να εµπλακούν στη λήψη και την αποστολή πακέτων, από και προς το δίκτυο
αντίστοιχα.
Οι drivers είναι επίσης και ένα καλό σηµείο εκκίνησης για την κατανόηση του kernel. Αν κάποιος είναι σε θέση να δηµιουργήσει έναν driver ή αν αντιλαµβάνεται την λειτουργία του, τότε
θα είναι σε θέση να κατανοήσει σε µεγάλο βαθµό και τη λειτουργία του kernel. Ένα άλλο σηµείο εκκίνησης είναι η ανάπτυξη εφαρµογών µε την χρήση του API που παρέχει ο Kernel.
Μέσω της εντολής make linux26-menuconfig του γραφικού περιβάλλοντος παραµετροποίησής του Kernel, στην ενότητα Device Drivers, µπορούµε να επιλέξουµε ποιοι
drivers (και πως) θα υποστηρίζονται :
Ιστότοπος εργασίας: MyThesis.org
77
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 20. Περιβάλλον παραµετροποίησης Linux Kernel – Υποµενού: Device Drivers
Φυσικά για να εµφανίζεται στο παραπάνω menu ένας driver θα πρέπει είτε να υπάρχει ήδη
υλοποιηµένος στον Kernel, είτε να τον έχουµε γράψει εµείς και να τον έχουµε εντάξει επιτυχώς στο περιβάλλον παραµετροποίησης. Οι οδηγοί που γράφουµε εµείς ανήκουν στον εξειδικευµένο κώδικα (board – specific code) του ενσωµατωµένου συστήµατος Linux που
αναπτύσσουµε.
Επικοινωνία: [email protected]
78
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
3.2.1 Linux kernel
Ο πυρήνας του Linux επωµίζεται το έργο της διαχείρισης των διαθέσιµων πόρων µε τον
αποτελεσµατικότερο δυνατό τρόπο. Ο Linux kernel αποτελείται από εκατοντάδες χιλιάδες
γραµµές κώδικα και δεν είναι δυνατόν να αναλυθεί στα πλαίσια αυτής της εργασίας. Εξάλλου
για το σκοπό αυτό υπάρχει πλούσια και αξιόλογη βιβλιογραφία (στα αγγλικά). Υπάρχει όµως
η δυνατότητα να επισηµάνουµε το πώς µπορεί να κατηγοριοποιηθεί ανάλογα µε την λειτουργικότητά του. Μπορούµε λοιπόν να πούµε ότι ολόκληρος ο κώδικας του kernel αποτελείται
από τα εξής τµήµατα:
∆ιαχείριση επεξεργασίας (Process management)
∆ιαχείριση µνήµης (Memory management)
Συστήµατα αρχείων (Filesystems)
Έλεγχος συσκευών (Device control)
∆ικτύωση (Networking)
Ουσιαστικά αυτή η κατηγοριοποίηση είναι πολύ λογική αν σκεφτούµε ότι σε ένα σύστηµα
συνήθως θα θέλουµε να επεξεργαστούµε δεδοµένα (επεξεργασία), να αποθηκεύσουµε κάπου (µνήµη) τα αποτελέσµατα σε αυστηρά ορισµένη µορφή (σύστηµα αρχείων), να τα παρουσιάσουµε σε κάποια οθόνη ή κάποια άλλη περιφερειακή συσκευή εξόδου (µέσω char ή
block driver) και κάποια στιγµή να τα αποστείλουµε και σε άλλα συστήµατα του δικτύου (δικτύωση).
Τα τµήµατα αυτά µπορούµε να τα δούµε σχηµατικά πως λειτουργούν µέσα στον Kernel,
στην παρακάτω εικόνα:
Εικόνα 21. Ανατοµία του Linux Kernel
Ιστότοπος εργασίας: MyThesis.org
79
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Στην εικόνα µπορούµε επίσης να δούµε και κάτι άλλο πολύ σηµαντικό. Για τη διαχείριση της
CPU και της κύριας µνήµης (πχ RAM), απαιτείται εξειδικευµένο λογισµικό (board specific
code) και όχι κάποιος char ή block driver. Το λογισµικό αυτό συνήθως παρέχεται από τον
προµηθευτή της µνήµης και της CPU στο πακέτο BSP.
Το τµήµα του κώδικα που ασχολείται µε τον έλεγχο των συσκευών είναι αυτό που µας ενδιαφέρει περισσότερο όταν θέλουµε να αναπτύξουµε drivers για τις συσκευές µας. Επίσης το
τµήµα της δικτύωσης είναι αυτό που ενσωµατώνει την στοίβα TCP/IP καθώς και τα πρωτόκολλα δροµολόγησης. Ουσιαστικά αυτά είναι και τα σηµαντικότερα τµήµατα για την ανάπτυξη
ενός Router όπως είναι ο NGW100.
3.2.2 Modules
Ένα από τα ισχυρότερα χαρακτηριστικά του Linux είναι η δυνατότητα που παρέχει για επέκταση ή και µείωση των λειτουργιών και των δυνατοτήτων του Kernel κατά το χρόνο εκτέλεσης. Έτσι η κάθε νέα λειτουργία που θέλουµε να προσθέσουµε δεν χρειάζεται να
µεταγλωττιστεί στατικά µέσα στον kernel.
Κάθε κοµµάτι κώδικα που µπορεί να προστεθεί στον Kernel κατά τον χρόνο εκτέλεσης ονοµάζεται module. Οι τύποι των modules που υποστηρίζονται είναι αρκετοί και ένας από αυτούς είναι και οι drivers των συσκευών.
Κάθε module είναι ένα εκτελέσιµο αρχείο το οποίο δεν µπορεί να εκτελείται αυτόνοµα αλλά
φορτώνεται δυναµικά στον kernel µέσω του προγράµµατος insmod (install module) και αφαιρείται δυναµικά µέσω του προγράµµατος rmmod (remove module). Η φόρτωση ή κατάργηση ενός module είναι εφικτή µόνο από τον root (administrator) του συστήµατος. Για να
δούµε ποια modules υπάρχουν φορτωµένα στο σύστηµά µας χρησιµοποιούµε την εντολή
lsmod (list modules).
Για να υποστηρίζεται ο µηχανισµός των modules από τον Kernel θα πρέπει πριν τη µεταγλώττισή του να έχει ενεργοποιηθεί (µέσω της εντολής make linux26-menuconfig) η αντίστοιχη επιλογή (Enable Loadable Module Support) από το γραφικό περιβάλλον
παραµετροποίησής του:
Εικόνα 22. Ενεργοποίηση υποστήριξης modules από τον Linux Kernel
Επικοινωνία: [email protected]
80
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Εφόσον ένα module µπορεί να είναι τύπου driver module µπορεί να ανήκει και αυτό σε τρεις
κλάσεις. Είναι οι εξής:
char module (για τη φόρτωση char driver)
block module (για τη φόρτωση block driver)
network module (για τη φόρτωση network driver)
Παρ’ όλα αυτά ο kernel µας δίνει τη δυνατότητα να δηµιουργούµε modules µε συνδυασµούς
κλάσεων.
3.3 Παράδειγµα ανάπτυξης module
Επειδή στο σύστηµά µας γίνεται χρήση modules για την φόρτωση ορισµένων drivers θα
παραθέσουµε εδώ συνοπτικά τα στάδια ανάπτυξης ενός module. Θα δείξουµε επίσης πως
φορτώνεται κατά την λειτουργία του Kernel του συστήµατός µας και πως καταργείται.
Αρχικά πρέπει να δηµιουργήσουµε ένα αρχείο C. Ας υποθέσουµε ότι το όνοµα του αρχείου
αυτού είναι rousis_module.c. Και ο κώδικάς του, είναι για το παράδειγµά µας ο παρακάτω:
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_DESCRIPTION("Test module");
MODULE_AUTHOR("Rousis Dimitrios – [email protected]");
MODULE_ALIAS("test");
int rousis_init_module(void)
{
printk(KERN_INFO "Hello world! \n");
return 0;
}
module_init(rousis_init_module);
void rousis_cleanup_module(void)
{
printk(KERN_INFO "Goodbye world! \n");
}
module_exit(rousis_cleanup_module);
Η return 0; θα επιστρέψει µηδέν εάν εκτελεστεί επιτυχώς, διαφορετικά θα επιστραφεί
κάποια αρνητική τιµή που όπως και σε άλλες περιπτώσεις στο Linux, έχει γίνει σύµβαση να
θεωρείται σφάλµα. Τους κώδικες σφαλµάτων µπορούµε να τους εντοπίσουµε στα αρχεία κεφαλίδων errno-base.h και errno.h που βρίσκονται στον κατάλογο include/asmgeneric του πηγαίου κώδικα του Linux.
Αφού ολοκληρώσαµε τον κώδικα του module, στη συνέχεια θα πρέπει να δώσουµε οδηγίες
στον cross compiler για το πώς να µεταγλωττίσει τον κώδικα. Αυτό επιτυγχάνεται µε τη δηµιουργία ενός αρχείου µε την ονοµασία Makefile:
obj-m := rousis_module.o
KERNELDIR := /rousis/buildroot/project_build_avr32/atngw100/linux-2.6.27.6/
all:
Ιστότοπος εργασίας: MyThesis.org
81
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
make ARCH=avr32 CROSS_COMPILE=avr32-linux- -C $(KERNELDIR) M=$(shell pwd) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
Οι γραµµές µετά τις ετικέτες all και clean, θα πρέπει να περιέχουν ένα tab, διαφορετικά
κατά τη µεταγλώττιση θα προκύπτει σφάλµα (missing separator). Στη συνέχεια ενηµερώνουµε τις µεταβλητές περιβάλλοντος (environment variables) για το που µέσα στο σύστηµα buildroot βρίσκεται ο GCC compiler:
export PATH=$PATH:/rousis/buildroot/build_avr32/staging_dir/bin
Και τα δύο αρχεία που δηµιουργήσαµε είναι καλό να βρίσκονται µέσα στον ίδιο κατάλογο.
Αφού είναι έτοιµα µε την εντολή cd εισερχόµαστε σε αυτόν και εκτελούµε την εντολή:
make
Αν ολοκληρωθεί επιτυχώς η µεταγλώττισή θα προκύψουν αρκετά νέα αρχεία. Ένα από αυτά θα είναι και το αρχείο rousis_module.ko το οποίο θα φορτώσουµε στη συνέχεια στο
target σύστηµά µας µέσω της εντολής insmod. Στην επόµενη εικόνα βλέπουµε και τα υπόλοιπα αρχεία που προέκυψαν µετά την εκτέλεση της εντολής make:
Εικόνα 23. Παράδειγµα ανάπτυξης module
Αφού µεταφέρουµε το αρχείο στον Router NGW100 µε τον ftp client Filezilla, και ενώ βρίσκεται σε λειτουργία, εκτελούµε την παρακάτω εντολή έτσι ώστε ο kernel να φορτώσει και
στη συνέχεια να εκτελέσει το module που δηµιουργήσαµε:
insmod rousis_module.ko
Κατά την δοκιµή ενός module καλό είναι να θέτουµε το επίπεδο καταγραφής της κονσόλας
(console log level) του συστήµατός µας host σε 8 έτσι ώστε να εµφανίζονται µηνύµατα για
debugging. Αυτό µπορεί να γίνει µε την εντολή:
echo 8 4 1 7 > /proc/sys/kernel/printk
Ως εναλλακτική λύση υπάρχει και η εντολή dmesg η οποία εµφανίζει τα µηνύµατα κατάστασης που υπάρχουν αποθηκευµένα σε µια ειδική µνήµη (message buffer) του kernel.
Κλείνοντας πρέπει να πούµε ότι σε περίπτωση που το αρχείο rousis_module.c έπαιζε
το ρόλο ενός driver ο οποίος ενσωµατώνεται στον Kernel και δεν φορτώνεται µε την µορφή
module, δε θα χρειαζόταν καµία τροποποίηση. Η µακροεντολή module_init() το µόνο
που θα είχε να κάνει, θα ήταν να ελέγξει εάν κατά την εκκίνηση του λειτουργικού συστήµατος
εκτελέστηκε η συνάρτηση rousis_init_module(), ενώ η µακροεντολή module_exit()
δε θα εκτελούνταν καθόλου.
Επικοινωνία: [email protected]
82
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
3.4 ∆ίαυλοι και διεπαφές
Οι δίαυλοι (Buses) και οι διεπαφές (Interfaces) είναι οι συνδετικοί κρίκοι µεταξύ του µικροελεγκτή και των περιφερειακών του συστήµατός µας. Κάθε δίαυλος και κάθε διεπαφή έχει κάποιες ιδιοµορφίες, και το επίπεδο υποστήριξης που παρέχει ο Linux kernel ποικίλει ανάλογα
µε αυτές.
Όταν σχεδιάζουµε ένα νέο ενσωµατωµένο σύστηµα Linux από την αρχή, µπορεί για ορισµένες συσκευές να µην έχουµε καµία αριθµήσιµη διάρθρωση διαύλων ανώτερου επιπέδου.
Οι συσκευές αυτές µπορεί να βρίσκονται εντός της χαρτογραφηµένης µνήµης της CPU
(memory – mapped devices). Το Linux παρέχει υποστήριξη ειδικά γι’ αυτού του είδους τις
συσκευές, µέσω της χρήσης των συσκευών πλατφόρµας (platform devices). Αυτό επιτρέπει
στον kernel να µπορεί να υποστηρίξει συσκευές που δεν µπορεί να απαριθµήσει
(enumerate) όταν αναζητά την τοπολογία διαύλων κατά την εκκίνησή του. Αυτές οι συσκευές
εντοπίζονται είτε µε τη χρήση εξειδικευµένου κώδικα που γράφεται ειδικά για µια συγκεκριµένη πλατφόρµα, είτε αναφέρονται στην διεπαφή µεταξύ του kernel και του bootloader. Για περισσότερη κατανόηση επί του θέµατος, απαιτείται η µελέτη σχετικά µε τη συγγραφή
προγραµµάτων οδήγησης συσκευών (drivers) για το Linux.
Ας ρίξουµε όµως µια γρήγορη µατιά σε κάποιες από τις διεπαφές και τους δίαυλους που θα
εξετάσουµε στη συνέχεια αυτής της παραγράφου:
USB (Universal Serial Bus)
I2C (Inter – Integrated Circuit) η TWI (Two Wire Interface)
SPI (Serial Protocol Interface)
3.4.1 USB
Η υποστήριξη που παρέχει ο Linux kernel για συνδεσιµότητα USB είναι πάρα πολύ καλή
και όλο και περισσότερα IDs κατασκευαστών προστίθενται συνεχώς (µια λίστα υπάρχει κι
εδώ: linux-usb.org). Το κύριο συστατικό που παρέχει ο kernel για υποστήριξη USB είναι
η στοίβα USB. Επίσης υποστηρίζει δύο είδη drivers:
USB Host drivers – Εγκαθίστανται σε υπολογιστές για την υποστήριξη και τον έλεγχο
συσκευών που συνδέονται σε αυτούς. Τέτοια παραδείγµατα είναι οι Web κάµερες, το
ποντίκι, το πληκτρολόγιο κλπ.
USB Device (ή gadget) drivers – Σε αυτή την περίπτωση ο driver βρίσκεται φορτωµένος στη µνήµη µιας συσκευής και φροντίζει µόνο για την επικοινωνία αυτής της συσκευής µε συστήµατα που διαθέτουν host drivers. Για παράδειγµα ένα router που
διαθέτει USB χρειάζεται drivers µόνο για να επικοινωνεί µε κάποιον υπολογιστή και
όχι για να συνδέονται άλλες συσκευές επάνω του.
Η ενεργοποίηση για υποστήριξη USB από τον Kernel µπορεί να ενεργοποιηθεί µέσω του
γραφικού περιβάλλοντός του επιλέγοντας: Device Drivers
USB Support. Από το
παράθυρο διαλόγου που εµφανίζεται επιλέγουµε USB Gadget Support αν θέλουµε το σύστηµά µας να λειτουργεί σαν συσκευή USB:
Ιστότοπος εργασίας: MyThesis.org
83
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 24. Ενεργοποίηση υποστήριξης USB από τον Linux Kernel
Οι USB drivers υπάρχουν ανάµεσα σε ορισµένα υποσυστήµατα του Kernel (πχ: block, net,
char κλπ) και στους ελεγκτές του υλικού USB (Host Controllers). Το βασικό (core) λογισµικό
USB που υπάρχει ενσωµατωµένο, παρέχει µια προγραµµατιστική διεπαφή για τους USB
drivers ή οποία είναι ανεξάρτητη υλικού. Στην εικόνα µπορούµε να δούµε µια γραφική αναπαράσταση των όσων είπαµε:
Εικόνα 25. Γραφική αναπαράσταση της επικοινωνίας USB στον Linux Kernel
Επικοινωνία: [email protected]
84
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Αν θέλουµε να γράψουµε κάποιους drivers για το ενσωµατωµένο µας σύστηµα θα πρέπει
να έχουµε µελετήσει τον τρόπο ανάπτυξής τους για το Linux. Μια καλή αρχή είναι να επισκεφτούµε το επίσηµο site της οµάδας USB-IF που είναι το www.usb.org.
Σε ένα σύστηµα Linux µπορούν να είναι συνδεδεµένες ταυτόχρονα µέχρι και 127 συσκευές.
Ο ριζικός διανοµέας είναι υπεύθυνος για όλες τις συσκευές που συνδέονται σε αυτόν, είτε
άµεσα, είτε µέσω κάποιου δευτερεύοντος USB hub.
3.4.2 I2C Linux Framework
Σε αυτή την παράγραφο θα εξετάσουµε την υποστήριξη που παρέχει το Linux για το δίαυλο
I2C (nxp.com). Επίσης θα δούµε πως οι εντολές του διαύλου SMBus (System Management
Bus) µπορούν να δροµολογηθούν µέσω του Linux API σε συσκευές συµβατές µε το I2C.
Στον µικροελεγκτή AP7000 ο δίαυλος I2C (ή TWI) µπορεί να ελεγχθεί και µέσω των πολύ
ευέλικτων σηµάτων GPIO. Εποµένως θα εξετάσουµε και αυτή την περίπτωση.
Ο ενσωµατωµένος Linux driver για το I2C
Ο driver που παρέχει το Linux για το I2C αποτελείται από αρκετά µέρη. Ας δούµε κάποιες
ορολογίες που χρησιµοποιούνται:
∆ίαυλος υλικού (Hardware bus): Πρόκειται για υλικό το οποίο έχει συγκεκριµένη διεπαφή χειρισµού µεταδόσεων. Στην αρχιτεκτονική AVR32 για παράδειγµα, το υλικό
αυτό είναι το TWI ή ένα σύνολο σηµάτων GPIO.
Προσαρµογέας (Adapter): Ο προσαρµογέας εξυπηρετεί την επικοινωνία µεταξύ του
I2C και του TWI.
Αλγόριθµος (Algorithm driver): Συνεργάζεται µε τον προσαρµογέα για την επίτευξη
της επικοινωνίας. Η ύπαρξή του είναι απαραίτητη µόνο όταν το πρωτόκολλο επικοινωνίας I2C δεν είναι ενσωµατωµένο στο υλικό.
Οδηγός (I2C driver): Πρόκειται για driver που υπάρχει υλοποιηµένος στον Kernel. Σε
περίπτωση που η συσκευή ελέγχεται µέσω ειδικής διεπαφής (I2C Device Interface)
που υπάρχει για τις εφαρµογές οι οποίες εκτελούνται στο user space, ο οδηγός αυτός
δεν είναι απαραίτητος.
∆ιεπαφή συσκευής (I2C Device Interface): Πρόκειται για τη διεπαφή I2C η οποία υπάρχει για την εξυπηρέτηση εφαρµογών στο user space οι οποίες θέλουν να επικοινωνήσουν µε συσκευές I2C.
Τα µέρη που αναφέραµε µπορούµε να τα δούµε και σχηµατικά στο πιο κάτω διάγραµµα:
Ιστότοπος εργασίας: MyThesis.org
85
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 26. Γραφική αναπαράσταση των µερών του Linux driver I2C
Μπορούµε να δούµε περισσότερες πληροφορίες και στην τεκµηρίωση του Kernel που υπάρχει για το I2C στον κατάλογο documentation/i2c.
Παραµετροποίηση του Kernel
Για να µπορούµε να επικοινωνήσουµε µέσω TWI και I2C στο Linux θα πρέπει πρώτα να
έχουµε ενεργοποιήσει ορισµένα τµήµατα του Kernel. Αυτό όπως ήδη γνωρίζουµε γίνεται µέσω του εξειδικευµένου γραφικού περιβάλλοντος παραµετροποίησης του Kernel. Οι ρυθµίσεις
που µας αφορούν βρίσκονται στο µενού Device Drivers
I2C support:
Επικοινωνία: [email protected]
86
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Εικόνα 27. Ενεργοποίηση υποστήριξης I2C από τον Linux Kernel
I2C µέσω GPIO
Προκειµένου να δηµιουργήσουµε την µονάδα προσαρµογέα (adapter module) και την µονάδα αλγορίθµου (algorithm module) οι οποίες απαιτούνται για την παραµετροποίηση GPIO,
πρέπει να επιλέξουµε Device Drivers -> I2C support -> I2C Hardware bus support
Το module µε την ονοµασία GPIO-based bitbanging I2C, είναι αυτό που µας ενδιαφέρει και το ενεργοποιούµε (<Μ>) µε το space του πληκτρολογίου:
Εικόνα 28. Ενεργοποίηση υποστήριξης I2C µέσω GPIO από τον Linux Kernel
Ιστότοπος εργασίας: MyThesis.org
87
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Στη συνέχεια θα πρέπει να προσθέσουµε τη συσκευή µε την οποία θέλουµε να επικοινωνήσουµε. Για να γίνει αυτό θα πρέπει να αντιστοιχίσουµε κάποιους ακροδέκτες GPIO του µικροελεγκτή µας µε τη διεπαφή TWI την οποία αυτός διαθέτει. Στον Router NGW100, οι ίδιοι
ακροδέκτες του µικροελεγκτή που χρησιµοποιούνται για την µονάδα TWI µπορούν να ρυθµιστούν µέσω του Kernel ώστε να λειτουργούν σαν δίαυλος I2C – GPIO.
Οι ρυθµίσεις για τον δίαυλο I2C – GPIO περνιούνται στον προσαρµογέα από τα δεδοµένα
πλατφόρµας (platform-data). Τα δεδοµένα αυτά καθορίζονται από µια δοµή δεδοµένων η
οποία βρίσκεται στο αρχείο κεφαλής include/linux/i2c-gpio.h και περιλαµβάνει τον
παρακάτω κώδικα:
struct i2c_gpio_platform_data {
unsigned int
sda_pin;
unsigned int
scl_pin;
int
udelay;
int
timeout;
unsigned int
sda_is_open_drain:1;
unsigned int
scl_is_open_drain:1;
unsigned int
scl_is_output_only:1;
};
Στον Router NGW100 η αρχικοποίηση της δοµής που είδαµε γίνεται στο αρχείο setup.c
που βρίσκεται στον κατάλογο arch/avr32/boards/atngw100 του πηγαίου κώδικα του
Kernel. Στο ίδιο αρχείο βρίσκεται και ένα στιγµιότυπο της δοµής platform_device το οποίο ουσιαστικά αντιπροσωπεύει τη πραγµατική συσκευή µε την οποία θέλουµε να επικοινωνήσουµε µέσω του διαύλου I2C – GPIO:
static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin
= GPIO_PIN_PA(6),
.scl_pin
= GPIO_PIN_PA(7),
.sda_is_open_drain
= 1,
.scl_is_open_drain
= 1,
.udelay
= 2, /* ~100 kHz */
};
static struct platform_device i2c_gpio_device = {
.name
= "i2c-gpio",
.id
= 0,
.dev
= {
.platform_data
= &i2c_gpio_data,
},
};
Το επόµενο βήµα που θα πρέπει να γίνει είναι να αρχικοποιήσουµε τους απαραίτητους ακροδέκτες του µικροελεγκτή για το I2C. Όλες οι απαραίτητες συναρτήσεις για να γίνει κάτι τέτοιο βρίσκονται στο αρχείο κεφαλής portmux.h το οποίο βρίσκεται µε τη σειρά του στον
κατάλογο του πηγαίου κώδικα του Linux Kernel include/asm/arch. Μία από αυτές στην
περίπτωση του Router NGW100 είναι η ακόλουθη:
at32_select_gpio(unsigned int pin, unsigned long flags)
Και είναι η µόνη που χρειαζόµαστε για να ρυθµίσουµε ένα σήµα GPIO. Ο ακέραιος αριθµός
pin µπορεί να βρεθεί χρησιµοποιώντας ειδικές µακροεντολές που υπάρχουν στο αρχείο
at32ap7000.h. Για παράδειγµα, προκειµένου να επιλέξουµε την γραµµή εισόδου – εξόδου
0, του ελεγκτή (PIO controller) Β, χρησιµοποιούµε την µακροεντολή GPIO_PIN_PB(0).
Επικοινωνία: [email protected]
88
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Τα διαθέσιµα flags για τη συνάρτηση at32_select_gpio, καθώς και η λειτουργία τους,
παρατίθενται στον πίνακα που ακολουθεί:
Λειτουργία
Flag
AT32_GPIOF_PULLUP
Ενεργοποίηση pull-up αν το σήµα GPIO λειτουργεί σαν είσοδος
AT32_GPIOF_OUTPUT
Ρύθµιση ενός σήµατος GPIO να λειτουργεί σαν έξοδος
AT32_GPIOF_HIGH
Θέτει το pin εξόδου σε λογικό HIGH
AT32_GPIOF_DEGLITCH
Ενεργοποιεί το glitch-filter όταν το GPIO λειτουργεί σαν είσοδος
AT32_GPIOF_MULTIDRV
∆ίνει τη δυνατότητα των drivers εξόδου να µπορούν να λειτουργούν σαν open drain (ανοικτός αγωγός) ούτως ώστε να υποστηρίζει πολλαπλούς εξωτερικούς drivers στο ίδιο pin.
Πίνακας 3. Flags και λειτουργία της συνάρτησης at32_select_gpio
Το παράδειγµα που ακολουθεί ρυθµίζει κατάλληλα τους GPIO ακροδέκτες του µικροελεγκτή
AP7000 και καταχωρεί µια συσκευή I2C-GPIO. Έχει χρησιµοποιηθεί στον εξειδικευµένο κώδικα που γράφτηκε για τον Router NGW100 έτσι ώστε να υποστηρίζεται από τον Kernel.
at32_select_gpio(i2c_gpio_data.sda_pin, AT32_GPIOF_MULTIDRV |
AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
at32_select_gpio(i2c_gpio_data.scl_pin, AT32_GPIOF_MULTIDRV |
AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
platform_device_register(&i2c_gpio_device);
Στη συνέχεια πρέπει να προβούµε σε δύο ενέργειες. Την εγκατάσταση του driver για το TWI
και την ενεργοποίηση του περιβάλλοντος διεπαφής συσκευής I2C για την υποστήριξη εφαρµογών στο user space. Μετά την επιλογή του driver προσθέτουµε την παρακάτω γραµµή στο
στο αρχείο setup.c:
at32_add_device_twi(unsigned int id)
Για να εγκαταστήσουµε τον driver για το TWI, από το γραφικό περιβάλλον του Kernel επιλέγουµε: Device Drivers -> I2C support -> I2C Hardware bus support ->
Atmel Two-Wire Interface (TWI). Προκειµένου να ενεργοποιήσουµε το I2C device
interface, επιλέγουµε: Device Drivers -> I2C support -> I2C device interface.
Εγκατάσταση των I2C modules
Μετά την εκκίνηση του Router NGW100 θα πρέπει να φορτώνονται κάθε φορά, και όσα
modules είναι απαραίτητα. Για την φόρτωση του TWI module θα πρέπει να εκτελεστεί η παρακάτω εντολή, είτε χειροκίνητα από εµάς, είτε από κάποιο εξειδικευµένο script που θα έχουµε επιλέξει να εκτελείται κατά την εκκίνηση:
modprobe i2c-atmeltwi
Ιστότοπος εργασίας: MyThesis.org
89
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Κάποια άλλα modules τα οποία είναι απαραίτητα, είναι τα i2c-gpio και i2c-algo-bit,
τα οποία µπορούν επίσης να φορτωθούν µε την πιο πάνω εντολή.
Το µόνο που µένει είναι να ρυθµίσουµε το I2C device interface έτσι ώστε να µπορούµε στη
συνέχεια να το χρησιµοποιήσουµε µέσω των εφαρµογών µας για την επικοινωνία µε τις συσκευές I2C. Όπως ήδη γνωρίζουµε ό Kernel παρέχει ένα περιβάλλον διεπαφής γι’ αυτές. Ουσιαστικά πρόκειται για ένα driver όπου οι εφαρµογές (clients) αντιστοιχούνται µε αριθµηµένες
συσκευές οι οποίες βρίσκονται επάνω σε ένα δίαυλο (bus). Η διεπαφή επικοινωνίας µε τον
δίαυλο αυτό είναι µια συσκευή χαρακτήρων (character device) η οποία επιτρέπει σε µια user
space εφαρµογή να επιλέξει κάποια συγκεκριµένη συσκευή του διαύλου, να ορίσει τις ρυθµίσεις της αλλά και να γράψει σε αυτή και να διαβάσει. Για να φορτωθεί η συσκευή θα πρέπει
να εκτελεστεί η εντολή:
modprobe i2c-dev
Σε κάθε δίαυλο I2C αντιστοιχείται ένας κόµβος /dev/i2c-n όπου n είναι ο αριθµός του
διαύλου αυτού. Αυτό στον Router NGW100 γίνεται αυτόµατα µέσω της εφαρµογής mdev η
οποία είναι εγκατεστηµένη στο σύστηµα. Αν αυτό δεν ίσχυε ο κόµβος θα έπρεπε να δηµιουργηθεί χειροκίνητα µέσω της εντολής mknod. Οι κόµβοι συσκευών (device nodes) είναι συσκευές χαρακτήρων. Έχουν όνοµα, αριθµό (major - minor) και µπορούµε να τους
αντιστοιχούµε δικαιώµατα όπως και σε ένα απλό αρχείο. Με την εντολή που ακολουθεί µπορούµε να δούµε σε µορφή λίστας τις συσκευές που υπάρχουν στο σύστηµά µας:
ls -l /dev/i2c-0
Περισσότερες πληροφορίες υπάρχουν και στην τεκµηρίωση του Linux Kernel στον κατάλογο Documentation/i2c, στο αρχείο dev-interface. Στον ίδιο κατάλογο υπάρχει και λεπτοµερής ανάλυση της χρήσης της διεπαφής I2C που θα εξετάσουµε και στη συνέχεια.
Χρήση της διεπαφής I2C
Υπάρχουν δύο τρόποι για να επιτευχθεί επικοινωνία. Η διεπαφή εγγραφής / ανάγνωσης και
η διεπαφή ioctl. Ανεξάρτητα όµως από το ποια θα επιλέξουµε θα πρέπει πρώτα να ανοίξουµε τη συσκευή ως εξής:
int device_file;
char filename[10] = "/dev/i2c-0";
if ((device_file = open(filename,O_RDWR)) < 0) {
/* Error */
return -1;
}
Αυτό θα µας επιτρέψει να δούµε αν όλα πάνε καλά και αν η συσκευή µας έχει φορτωθεί και
καταχωρηθεί σωστά.
Αν επιλέξουµε την επικοινωνία µέσω της διεπαφής εγγραφής / ανάγνωσης, πρέπει πιο πριν
να δώσουµε µια διεύθυνση στην συσκευή (slave) την οποία θέλουµε να χρησιµοποιήσουµε.
Αυτό µπορεί να γίνει ως εξής:
int slave_address = 0x12; /* I2C address */
if (ioctl(device_file,I2C_SLAVE,slave_address) < 0) {
/* Error */
return -1;
Επικοινωνία: [email protected]
90
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
}
Στη συνέχεια δηµιουργούµε ένα buffer στο οποίο θα αποθηκεύονται δεδοµένα:
buffer[0] = i2c_slave_register;
buffer[1] = 0x11;
buffer[2] = 0x48;
Σε αυτό το σηµείο η συσκευή µας έχει µια διεύθυνση και υπάρχει δεσµευµένη µια περιοχή
στη µνήµη η οποία αντιπροσωπεύει τη µνήµη αυτής της συσκευής. Εποµένως µπορούµε να
κάνουµε µια εγγραφή σε αυτή. ∆ηλαδή να της στείλουµε δεδοµένα µέσω εφαρµογής που εκτελείται στο user space:
if ( write(device_file,buffer,3) != 3) {
/* Error */
return -1;
}
Για να κάνουµε ανάγνωση, δηλαδή να λάβουµε δεδοµένα από την συσκευή µας, µπορεί να
χρησιµοποιηθεί ο ακόλουθος κώδικας:
if (read(device_file,buffer,1) != 1) {
/* Error */
} else {
/* buffer[0] */
}
Η θέση 0 του πίνακα buffer περιέχει το byte που διαβάστηκε.
Αν επιλέξουµε να επικοινωνήσουµε µε την I2C slave συσκευή µας, µέσω της διεπαφής ioctl
θα πρέπει επίσης να επιλέξουµε αν θα χρησιµοποιήσουµε το πρωτόκολλο I2C ή το πρωτόκολλο SMBus, µιας και τα υποστηρίζει και τα δύο. Και στις δύο περιπτώσεις ο προσαρµογέας (adapter) που είναι όπως είπαµε, ένα από τα τµήµατα του I2C driver που παρέχει το
Linux, θα πρέπει να ελεγχτεί για να διαπιστωθεί εάν είναι πλήρως λειτουργικός.
Αν επιλέξουµε το πρωτόκολλο I2C θα πρέπει να καταλάβουµε πρώτα τα δύο είδη µηνυµάτων που θα χρειαστούµε. Το πρώτο µήνυµα είναι το βασικό µήνυµα (standard message) και
περιγράφεται στο αρχείο κεφαλής i2c-dev.h που υπάρχει στον κατάλογο linux. Ουσιαστικά πρόκειται για την παρακάτω δοµή:
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
Το δεύτερο µήνυµα είναι ένα µήνυµα I2C και η δοµή του περιγράφεται στο αρχείο κεφαλής
i2c.h που επίσης υπάρχει στον κατάλογο linux :
struct i2c_msg {
__u16 addr;
__u16 flags;
__u16 len;
__u8 *buf;
};
/* slave address*/
/* msg length */
/* pointer to msg data */
Τα πεδία της δοµής και οι σηµασία τους παρατίθενται παρακάτω:
Ιστότοπος εργασίας: MyThesis.org
91
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
addr – η διεύθυνση της συσκευής I2C (slave) που ελέγχουµε.
flags – παίρνουν τιµές οι οποίες ενηµερώνουν αν πρόκειται για λειτουργία ανάγνωσης ή εγγραφής. Άλλες τιµές που µπορούν να πάρουν είναι αν πρόκειται για 10-bit
addressing ή για 7-bit. Όλες αυτές οι σηµαίες αλλά και κάποιες επιπλέον, περιγράφονται και στο αρχείο κεφαλής i2c.h.
len – ο αριθµός των bytes που θα διαβαστούν οι θα γραφτούν.
buf – δείκτης που δείχνει στο buffer που είδαµε νωρίτερα.
Η αρχικοποιηµένη δοµή της δοµής i2c_msg περνά τελικά ως όρισµα για µια κλήση ioctl.
Με τον όρο “αρχικοποιηµένη” εννοούµε το στιγµιότυπο της δοµής i2c-msg που θα δηµιουργήσουµε στον κώδικα της εφαρµογής µας. Σε περίπτωση που θέλουµε να στείλουµε ή να
λάβουµε περισσότερα του ενός bytes ταυτόχρονα, µπορούµε να χρησιµοποιήσουµε την µακροεντολή I2C_RDWR :Το ακόλουθο παράδειγµα µεταφέρει 3 bytes στη συσκευή slave. Τα 3
bytes µεταφέρουν µια διεύθυνση καταχωρητή και δύο bytes δεδοµένων:
struct i2c_rdwr_ioctl_data work_queue;
uint8_t msg_data[2] = {0,0};
work_queue.nmsgs = 1;
work_queue.msgs = (struct i2c_msg*) malloc(work_queue.nmsgs *
sizeof(struct i2c_msg));
work_queue.msgs[0].len = 2;
work_queue.msgs[0].flags = 0;
work_queue.msgs[0].addr = 0x1; /* slave address */
msg_data[0] = 0x1; /* register address*/
msg_data[1] = 0xA; /* data */
msg_data[2] = 0xB; /* data */
work_queue.msgs[0].buf = msg_data;
if( ioctl(message.device_handle, I2C_RDWR,
(unsigned long) &work_queue) < 0)
{
/* Error*/
}
Αν αντί για το I2C, επιλέξουµε το πρωτόκολλο SMBus για την επικοινωνία µας µέσω της διεπαφής ioctl, µε την slave συσκευή, χρειαζόµαστε την εξής δοµή:
struct i2c_smbus_ioctl_data {
__u8 read_write;
__u8 command;
__u32 size;
union i2c_smbus_data *data;
};
Η σηµασία των µελών της δοµής i2c_smbus_ioctl_data είναι η εξής:
read_write – καθορίζει το αν η πρόσβαση στη συσκευή θα αφορά εγγραφή ή ανάγνωση. Υπάρχουν επίσης και κάποιες µακροεντολές στο αντίστοιχο αρχείο κεφαλής.
command – είναι το πρώτο byte που µεταφέρεται και συνήθως περιέχει τη διεύθυνση
του καταχωρητή.
size – καθορίζει το µήκος µεταφοράς δεδοµένων σε bytes.
data – είναι δείκτης που δείχνει στην περιοχή που αποθηκεύονται τα δεδοµένα.
Για τη διευκόλυνση πρόσβασης µέσω byte ή word χρησιµοποιείται η συνένωση (union)
i2c_smbus_data:
Επικοινωνία: [email protected]
92
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
union i2c_smbus_data {
__u8 byte;
__u16 word;
__u8 block[I2C_SMBUS_BLOCK_MAX + 2];
/* block[0] is used for length and one more for PEC */
};
Μία µεταφορά του ενός byte θα µπορούσε να είναι και η ακόλουθη:
struct i2c_smbus_ioctl_data args;
args.read_write = I2C_SMBUS_WRITE;
args.command = 0x01;
args.size = I2C_SMBUS_BYTE;
args.data = NULL;
ioctl(device_file,I2C_SMBUS,&args);
Ανάπτυξη I2C Linux driver
Ο χειρισµός των συσκευών I2C µπορεί όπως γνωρίζουµε να γίνει και από την περιοχή του
Kernel µέσω ενός driver. Πριν ξεκινήσουµε να γράφουµε τον δικό µας driver µπορούµε να
ψάξουµε στο Internet για να δούµε αν κάποιος άλλος το έχει κάνει ήδη. Μια καλή πηγή την
οποία µπορούµε να εκµεταλλευτούµε είναι και ο ιστότοπος lm-sensors.org.
Αν τελικά δεν βρεθεί κάποιος έτοιµος driver για τη συσκευή µας, τότε είµαστε αναγκασµένοι
να τον δηµιουργήσουµε εµείς οι ίδιοι. Τα συγγράµµατα που υπάρχουν διαθέσιµα στο εµπόριο, η τεκµηρίωση που υπάρχει στον Linux Kernel (Documenttion/i2c), το datasheet του
µικροελεγκτή µας αλλά και η τεκµηρίωση (πχ: application notes) που παρέχει ο προµηθευτής
του, είναι υπεραρκετά για την επιτυχή έκβαση του εγχειρήµατος αυτού.
3.4.3 SPI
Οι περισσότεροι µικροελεγκτές που χρησιµοποιούνται στα ενσωµατωµένα συστήµατα Linux
έχουν ενσωµατωµένα κάποια ΙΟ interfaces τύπου SPI. Έτσι µπορούν να επικοινωνούν µε
µνήµες SD ή MMC χωρίς να είναι απαραίτητη η διαµεσολάβηση κάποιου εξειδικευµένου controller.
Αν και το βασικό (core) υποσύστηµα SPI που υπάρχει ενσωµατωµένο στον Kernel παρέχει
κάποιες συναρτήσεις για την προσθήκη συσκευών SPI κατά το χρόνο εκτέλεσης του λειτουργικού, είναι καλύτερο να µην τις χρησιµοποιούµε. Ο λόγος είναι πως οι συναρτήσεις αυτές
θεωρούν ότι έχουν ήδη διευθετηθεί όλες οι εξειδικευµένες παραµετροποιήσεις της πλατφόρµας που χρησιµοποιούµε (platform – specific setup) όπως είναι για παράδειγµα η πολυπλεξία των pins του µικροελεγκτή που οµαδοποιούνται σε θύρες (port multiplexing). Εποµένως
είναι καλύτερα να αποφεύγουµε την χρήση τους. Έτσι ο απαιτούµενος κώδικας θα πρέπει να
βρίσκεται µέσα στον εξειδικευµένο κώδικα που αφορά την πλακέτα µας (setup.c). Εκεί θα
πρέπει να περιγράφονται όλες οι συσκευές SPI που υπάρχουν καθώς και ο τρόπος µε τον
οποίο αυτές συνδέονται. Όπως θα δούµε αναλυτικότερα και στη συνέχεια, για κάθε συσκευή
(master) στην οποία συνδέονται άλλες συσκευές, θα πρέπει να υπάρχει ένας πίνακας ο οποίος θα περιλαµβάνει πληροφορίες για ορισµένα χαρακτηριστικά τους. Το αρχείο κεφαλής
<linux/spi/spi.h> είναι µια καλή αρχή ώστε να ξεκινήσουµε την µελέτη µας για το SPI
καθώς και για τις πληροφορίες αυτές.
Στο γραφικό περιβάλλον παραµετροποίησης του Kernel µπορούµε να επιλέξουµε πριν την
SPI Support):
µεταγλώττιση ποια υποστήριξη SPI θα υπάρχει (Device Drivers
Ιστότοπος εργασίας: MyThesis.org
93
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 29. Ενεργοποίηση υποστήριξης SPI από τον Linux Kernel
Τα αιτήµατα SPI πάντοτε τοποθετούνται αρχικά σε ουρές εισόδων / εξόδων (I/O queues)
και εκτελούνται µε κάποιο αλγόριθµο FIFO (First In First Out). ∆ηλαδή εκτελείται πάντα το
αίτηµα που φτάνει πρώτο (δοµή ουράς). Αυτό γίνεται ασύγχρονα (δηλαδή χωρίς ρολόι) µε τη
χρήση αιτηµάτων ολοκλήρωσης (completion callbacks). Για απλές µεταφορές δεδοµένων
υπάρχει τρόπος τα αιτήµατα αυτά να συγχρονίζονται.
Γενικά τα είδη των drivers για SPI είναι δύο:
Controller drivers (οδηγοί ελεγκτών) οι οποίοι µπορούν να ενσωµατώνονται σε µικροελεγκτές SoC και συνήθως υποστηρίζουν και τους δύο τύπους επικοινωνίας (master
και slave). Οι drivers αυτοί χρησιµοποιούν τους καταχωρητές του hardware και µπορούν να χρησιµοποιούν κανάλια DMA.
Protocol drivers (οδηγοί πρωτοκόλλου). Οι drivers αυτοί περνούν µηνύµατα µέσω
κάποιου controller driver έτσι ώστε να επικοινωνήσουν µε κάποια master ή slave συσκευή στο άλλο άκρο της επικοινωνίας SPI.
Μια δοµή struct spi_device ενθυλακώνει την διεπαφή του master µεταξύ των δύο αυτών τύπων drivers. Σε αυτή την περίπτωση δεν υπάρχει προγραµµατιστικό περιβάλλον για
την πλευρά του slave.
Υπάρχει µια ελάχιστη διεπαφή προγραµµατισµού SPI που βασίζεται περισσότερο σε drivers κάνοντας χρήση εξειδικευµένου κώδικα που παρέχεται από τον κατασκευαστή κάθε συγκεκριµένου συστήµατος. Το SPI εµφανίζεται στο sysfs σε διάφορα σηµεία. Κάποια από
αυτά είναι και τα ακόλουθα:
/sys/devices/.../CTLR
Επικοινωνία: [email protected]
φυσικό επίπεδο ενός συγκεκριµένου ελεγκτή SPI.
94
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
/sys/devices/.../CTLR/spiB.C
spi_device στον δίαυλο B, Chip select C,
addressing µέσω CTLR.
/sys/bus/spi/devices/spiB.C
symlink (symbolic link) προς την φυσική συσκευή.
/sys/devices/.../CTLR/spiB.C/modalias
αναγνωρίζει τον driver που θα
πρέπει να χρησιµοποιηθεί µε την συγκεκριµένη συσκευή (για hotplug / coldplug).
/sys/bus/spi/drivers/D
driver για µία ή περισσότερες συσκευές SPI.
/sys/class/spi_master/spiB
symlink ή πραγµατική συσκευή που µπορεί να
περιέχει πληροφορίες κατάστασης σχετικά ελεγκτή που χειρίζεται τον δίαυλο B. Όλες
οι spiB.* συσκευές µοιράζονται έναν κοινό τοµέα διαύλου SPI µε σήµατα SCLK, MOSI,
και MISO.
Ο Linux kernel χρειάζεται αρκετές πληροφορίες έτσι ώστε να ρυθµίσει σωστά τις συσκευές
SPI. Οι πληροφορίες αυτές του παρέχονται από εξειδικευµένο κώδικα που παρέχονται στο
BSP. Το πρώτο είδος πληροφορίας που χρειάζεται, είναι µια λίστα µε τους SPI controllers
που υποστηρίζονται από το σύστηµα που αναπτύσσεται. Για πλακέτες που βασίζονται σε
SoC (System on Chip) θα υπάρχουν συνήθως συσκευές που υποστηρίζονται από την τρέχουσα πλατφόρµα (platform devices) και θα απαιτούνται συνήθως κάποια δεδοµένα της
πλατφόρµας αυτής (platform_data) προκειµένου όλα να λειτουργήσουν σωστά. Η struct
platform_device θα περιέχει πληροφορίες όπως η φυσική διεύθυνση του πρώτου καταχωρητή του SPI controller καθώς και η αντίστοιχη IRQ (Interrupt Request).
Οι διάφορες πλατφόρµες που υπάρχουν συχνά τοποθετούν τη διαδικασία δήλωσης (register) SPI controller µαζί µε εκείνη της διαµόρφωσης των ακροδεκτών (pin configuration), έτσι
ώστε τα αρχεία τύπου arch/.../mach-*/board-*.c των διάφορων πλατφορµών να
µπορούν να µοιράζονται τον ίδιο κώδικα εγκατάστασης. Αυτό συµβαίνει επειδή τα συστήµατα
SoC διαθέτουν πολλούς SPI controllers και µόνο εκείνοι που είναι πραγµατικά χρήσιµοι για
το σύστηµα πρέπει να εγκαθίστανται και να δηλώνονται.
Έτσι για παράδειγµα στα αρχεία arch/.../mach-*/board-*.c µπορεί να περιέχεται
κώδικας όπως ο παρακάτω:
#include <mach/spi.h>
//
mysoc_spi_data
/* αν η υποδοµή mach-* δεν υποστηρίζει kernels που µπορούν να
εκτελεστούν σε πολλαπλές πλακέτες, η pdata δεν θα µπορούσε να
επωφεληθεί από την __init.
*/
static struct mysoc_spi_data __initdata pdata = { ... };
static __init board_init(void)
{
...
// αυτή η πλακέτα χρησιµοποιεί τον SPI controller #2
mysoc_register_spi(2, &pdata);
...
}
Επίσης ο κώδικας για κάποιο συγκεκριµένο SoC µπορεί να µοιάζει µε τον ακόλουθο:
#include <mach/spi.h>
static struct platform_device spi2 = { ... };
Ιστότοπος εργασίας: MyThesis.org
95
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
void mysoc_register_spi(unsigned n, struct mysoc_spi_data *pdata)
{
struct mysoc_spi_data *pdata2;
pdata2 = kmalloc(sizeof *pdata2, GFP_KERNEL);
*pdata2 = pdata;
...
if (n == 2)
{
spi2->dev.platform_data = pdata2;
register_platform_device(&spi2);
}
...
}
Ακόµα και αν χρησιµοποιείται το ίδιο SoC σε δύο διαφορετικές πλακέτες ο κώδικας
(platform_data) µπορεί να διαφέρει µεταξύ τους. Αυτό µπορεί να γίνει εύκολα κατανοητό
αν σκεφτούµε ότι στο ένα σύστηµα µπορεί το SPI να κάνει χρήση ενός εξωτερικού ρολογιού,
ενώ στο άλλο να χρησιµοποιείται ένα κεντρικό ρολόι (master clock).
Το δεύτερο είδος πληροφορίας που χρειάζεται ο kernel ώστε να ρυθµίσει σωστά τις συσκευές SPI ενός ενσωµατωµένου συστήµατος Linux είναι µια λίστα µε όλες τις slave συσκευές που υπάρχουν στο target σύστηµα και κάποιες φορές κάποια επιπλέον δεδοµένα του
συστήµατος αυτού έτσι ώστε ο SPI driver να λειτουργήσει σωστά.
Συνήθως τα αρχεία arch/.../mach-*/board-*.c παρέχουν µια λίστα σχετικά µε τις
SPI συσκευές που υπάρχουν σε κάθε πλακέτα. Ο κώδικας τους µπορεί να είναι παρόµοιος
µε τον παρακάτω:
static struct ads7846_platform_data ads_info =
{
.vref_delay_usecs = 100,
.x_plate_ohms
= 580,
.y_plate_ohms
= 410,
};
static struct spi_board_info spi_board_info[] __initdata =
{
{
.modalias
= "ads7846",
.platform_data
= &ads_info,
.mode
= SPI_MODE_0,
.irq
= GPIO_IRQ(31),
.max_speed_hz
= 120000
.bus_num
= 1,
.chip_select
= 0,
},
};
Συγκεκριµένα στην περίπτωση του Router NGW100 της παρούσας εργασίας, ο κώδικας
αυτός βρίσκεται στο αρχείο arch\avr32\boards\atngw100\setup.c και η δεύτερη
struct είναι γραµµένη ως εξής:
static struct spi_board_info spi0_board_info[] __initdata =
{
{
.modalias
= "mtd_dataflash",
.max_speed_hz
= 8000000,
Επικοινωνία: [email protected]
96
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
.chip_select
= 0,
},
};
Στον κώδικα είδαµε πως παρέχονται εξειδικευµένες πληροφορίες της πλακέτας. Οι πληροφορίες αυτές αφορούν την ταχύτητα του ρολογιού (.max_speed_hz), ή τον τρόπο που ένας
ακροδέκτης .irq συνδέεται. Επίσης αφορούν περιορισµούς των SPI συσκευών (chip –
specific constraints) όπως είναι για παράδειγµα µια σηµαντική καθυστέρηση (delay) που
αλλάζει µέσω της χωρητικότητας (capacitance) ενός ακροδέκτη.
Οι πληροφορίες πλακέτας (board_info) θα πρέπει να παρέχουν αρκετές πληροφορίες έτσι
ώστε το σύστηµα να δουλεύει χωρίς να χρειάζεται να φορτωθεί κάποιος οδηγός.
Στη συνέχεια ο κώδικας αρχικοποίησης της πλακέτας καταχωρεί τον πίνακα που προκύπτει
απ’ όλα τα παραπάνω στοιχεία µαζί µε την υποδοµή SPI έτσι ώστε να χρησιµοποιηθούν αργότερα κατά την καταχώρηση του SPI master controller:
spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
Η αντίστοιχη συνάρτηση η οποία βρίσκεται στο αρχείο setup.c στον Router NGW100, είναι η παρακάτω:
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
Όπως ίσως είναι ήδη κατανοητό, το SPI παρ’ όλο που απλοποιηµένα αναφέρεται ως διεπαφή, για την υλοποίησή του χρειάζεται να ασχοληθούµε µε αρκετές λεπτοµέρειες. Οι κυριότερες από αυτές αφορούν τα ηλεκτρικά χαρακτηριστικά, τη φυσική συνδεσµολογία των
ολοκληρωµένων, το πρωτόκολλο επικοινωνίας , αλλά και τον κώδικα του master controller.
Σε ένα ενσωµατωµένο σύστηµα Linux όλα αυτά υλοποιούνται επάνω από (user-space), ή
µέσα, στον πυρήνα του Linux (kernel-space).
Ας δούµε όµως πως µπορούµε να γράψουµε έναν οδηγό πρωτοκόλλου (protocol driver) για
SPI. Αν και υπάρχουν drivers που είναι γραµµένοι για το user – space, οι περισσότεροι γράφονται για την περιοχή του kernel. Ένα τέτοιο παράδειγµα θα δούµε κι εδώ:
static struct spi_driver CHIP_driver =
{
.driver =
{
.name
= "CHIP",
.owner
= THIS_MODULE,
},
.probe
= CHIP_probe,
.remove
= __devexit_p(CHIP_remove),
.suspend
= CHIP_suspend,
.resume
= CHIP_resume,
};
Ο πυρήνας (core) του SPI driver (που υπάρχει ήδη στον kernel) θα προσπαθήσει να δεσµεύσει τον παραπάνω driver που γράψαµε εµείς µε οποιοδήποτε ολοκληρωµένο του οποίου ο κώδικας board_info παρέχει ένα modalias για το CHIP. Επίσης ο κώδικας probe()
θα µοιάζει µε τον ακόλουθο:
static int __devinit CHIP_probe(struct spi_device *spi)
{
struct CHIP
*chip;
struct CHIP_platform_data
*pdata;
Ιστότοπος εργασίας: MyThesis.org
97
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
// υποθέτωντας ότι ο οδηγός απαιτεί board-specific δεδοµένα
pdata = &spi->dev.platform_data;
if (!pdata)
return -ENODEV;
// εκχώρηση µνήµης για το ολοκληρωµένο µέσω του driver
chip = kzalloc(sizeof *chip, GFP_KERNEL);
if (!chip)
return -ENOMEM;
spi_set_drvdata(spi, chip);
... etc
return 0;
}
Από τη στιγµή που εκτελείται ο κώδικας probe() από τον driver, ο δεύτερος µπορεί να αποστείλει αιτήσεις I/O στην SPI συσκευή µέσω της struct spi_message. Γενικά ένα µήνυµα
SPI (spi_message) είναι µια ακολουθία ενεργειών του πρωτοκόλλου που εκτελείται σαν µια
ενιαία ακολουθία. Οι έλεγχοι που γίνονται από τον SPI driver αφορούν την κατεύθυνση ροής
των δεδοµένων, τους I/O buffers που χρησιµοποιούνται, τα διαστήµατα των παύσεων µεταξύ
των µεταδόσεων, την ενεργοποίηση / απενεργοποίηση του chipselect κ.α..
Τώρα ας δούµε και ένα παράδειγµα κώδικα για master controller driver. Ο κύριος σκοπός
αυτού του driver είναι να παρέχει έναν spi_master. Για να προσδιορίσουµε τον master
µπορούµε να χρησιµοποιήσουµε την συνάρτηση spi_alloc_master() και για να διαβάσουµε τα δεδοµένα που τον αφορούν (private data) την spi_master_get_devdata():
struct spi_master *master;
struct CONTROLLER *c;
master = spi_alloc_master(dev, sizeof *c);
if (!master)
return -ENODEV;
c = spi_master_get_devdata(master);
Αφού αρχικοποιηθεί ο spi_master θα πρέπει να καταχωρηθεί µέσω της συνάρτησης
spi_register_master() ώστε να γίνει γνωστός και στο υπόλοιπο σύστηµα. Από ‘κει και
µετά οι SPI συσκευές µπορούν να χρησιµοποιηθούν κανονικά. Σε περίπτωση που θέλουµε
να αφαιρέσουµε τον SPI controller driver µπορούµε να το κάνουµε µέσω της παρακάτω συνάρτησης:
spi_unregister_master()
// αντίστροφη της spi_register_master()
Καλό είναι επίσης να πούµε δύο λόγια και για την αριθµοδότηση διαύλου (bus numbering),
καθώς και για τις µεθόδους (methods) SPI.
Η αριθµοδότηση διαύλου είναι σηµαντική αφού έτσι αναγνωρίζει ο Linux kernel ένα δίαυλο
SPI. Οι έγκυροι αριθµοί διαύλου ξεκινούν µε µηδέν. Στα SoC συστήµατα οι αριθµοί διαύλου
Επικοινωνία: [email protected]
98
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
θα πρέπει να ταιριάζουν µε αυτούς που καθορίζονται από τον κατασκευαστή τους. Για παράδειγµα ο controller SPI2 θα πρέπει να έχει αριθµό διαύλου 2 και η spi_board_info θα
πρέπει να χρησιµοποιεί αυτό τον αριθµό για συσκευές που συνδέονται σε αυτόν (τον SPI2).
Αν δεν υπάρχει κάποιος τέτοιος αντιστοιχισµένος αριθµός µπορούµε να χρησιµοποιούµε
κάποια αρνητική τιµή διαύλου. Αυτός ο αρνητικός αριθµός θα αντικατασταθεί δυναµικά στη
συνέχεια από έναν άλλο αριθµό που θα επιλεγεί από το σύστηµα.
Οι µέθοδοι SPI είναι οι παρακάτω:
master->setup(struct spi_device *spi) – καθορίζει τον ρυθµό του ρολογιού (clock rate) της συσκευής, τον τύπο (mode) SPI και το µέγεθος των λέξεων (word
sizes).
master->transfer(struct spi_device *spi, struct spi_message
*message) – είναι υπεύθυνη για την έναρξη και την ολοκλήρωση της µεταφοράς
master->cleanup(struct spi_device *spi) – απελευθερώνει την κατάσταση που προκύπτει από την κλήση spi_device.controller_state.
3.5 Είσοδοι και Έξοδοι (I/Os)
Όπως και µε τα άλλα λειτουργικά συστήµατα, ο Linux kernel υποστηρίζει ένα µεγάλο εύρος
συσκευών εισόδου – εξόδου. ∆εν πρόκειται να αναλύσουµε όλες αυτές τις συσκευές, αλλά
µόνο όσες κρίνεται χρήσιµο για την τεκµηρίωση της εργασίας αυτής. Για µια εις βάθος ανάλυση υπάρχει το Linux Documentation Project ή LDP (tldp.org).
Το απαραίτητο θεωρητικό υπόβαθρο που θα αναλυθεί πριν την ανάλυση των I/Os είναι:
Η διεπαφή tty
Ας δούµε τώρα πως υποστηρίζεται η σειριακή επικοινωνία από τον Linux kernel. Για να το
επιτύχουµε αυτό θα πρέπει να ασχοληθούµε µε τη σειριακή διεπαφή χαµηλού επιπέδου (Low
Level Serial API) και µε τον driver του σειριακού hardware.
Ο σειριακός driver χαµηλού επιπέδου (Low Level Serial Hardware Driver) είναι υπεύθυνος
στο να παρέχει πληροφορίες σχετικά µε τη θύρα UART (uart_port) καθώς και ένα σύνολο
µεθόδων ελέγχου (uart_ops) προς τον βασικό σειριακό οδηγό (core serial driver). Ο driver
χαµηλού επιπέδου είναι υπεύθυνος επίσης και για τον χειρισµό διακοπών της θύρας UART
καθώς και για την υποστήριξη εντολών κονσόλας (console).
Ως προς την υποστήριξη κονσόλας, o βασικός σειριακός driver παρέχει έναν αριθµό χρήσιµων συναρτήσεων που αφορούν την αναγνώριση της σωστής δοµής της θύρας
(uart_get_console), και την αποκωδικοποίηση τον ορισµάτων (παραµέτρων) της γραµµής εντολών (uart_parse_options).
Υπάρχει επίσης µια πολύ χρήσιµη συνάρτηση (uart_write_console) που εκτελεί εγγραφή χαρακτήρα προς χαρακτήρα µεταφράζοντας τις νέες γραµµές (newlines) σε ακολουθίες CRLF (Carriage Return, Line Feed – χρήσιµο για συστήµατα που βασίζονται σε ASCII
κωδικοποίηση).
Ο σειριακός driver χαµηλού επιπέδου είναι επίσης υπεύθυνος για το κλείδωµα της σειριακής θύρας. Υπάρχουν τρεις τύποι κλειδώµατος (port->lock) οι οποίοι είναι οι εξής:
spinlock
Ιστότοπος εργασίας: MyThesis.org
99
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
tmpbuf semaphore
overall semaphore
Από την µεριά του core driver επιτυγχάνεται το κλείδωµα των ακόλουθων δεδοµένων (µπορεί να χρησιµοποιηθεί και από τον οδηγό χαµηλού επιπέδου):
port->mctrl
port->icount
info->xmit.head (circ->head)
info->xmit.tail (circ->tail)
Ο σειριακός driver χαµηλού επιπέδου συνδέεται µε τον σειριακό core driver µέσω της διεπαφής uart_ops η οποία περιλαµβάνει όλες τις µεθόδους µέσω των οποίων µπορούµε να
χειριστούµε το hardware. Οι κυριότερες µέθοδοι είναι οι παρακάτω:
tx_empty(port)
set_mctrl(port, mctrl)
get_mctrl(port)
stop_tx(port)
start_tx(port)
stop_rx(port)
enable_ms(port)
break_ctl(port,ctl)
startup(port)
shutdown(port)
flush_buffer(port)
set_termios(port,termios,oldtermios)
pm(port,state,oldstate)
type(port)
release_port(port)
request_port(port)
config_port(port,type)
verify_port(port,serinfo)
ioctl(port,cmd,arg)
Επίσης υπάρχουν και οι συναρτήσεις:
uart_update_timeout(port,cflag,baud)
uart_get_baud_rate(port,termios,old,min,max)
uart_get_divisor(port,baud)
uart_match_port(port1,port2)
uart_write_wakeup(port)
uart_register_driver(drv)
uart_unregister_driver()
uart_suspend_port()
uart_resume_port()
uart_add_one_port()
uart_remove_one_port()
Μπορούµε εύκολα να αντιληφθούµε την λειτουργικότητα των µεθόδων και των συναρτήσεων που παρατέθηκαν από την ονοµατολογία τους, από τον κώδικα που περιλαµβάνεται
στους uart drivers του kernel καθώς και από το documentation που περιλαµβάνεται σε αυτόν. Θα ήταν άσκοπο να τις εξηγήσουµε µία προς µία, αφού αυτό που µας ενδιαφέρει περισσότερο είναι µια γενική µατιά στο uart hardware που υποστηρίζει ο kernel.
Επικοινωνία: [email protected]
100
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
3.5.1 Το υποσύστηµα tty
Το υποσύστηµα tty χρησιµοποιείται από το Linux για την υποστήριξη πληκτρολόγησης στην
γραµµή εντολών κάποιου τερµατικού ή για τη χρήση κάποιας σειριακής σύνδεσης. Οι συσκευές tty µπορεί να είναι σειριακές θύρες, USB σε serial µετατροπείς καθώς και κάποια
modem που απαιτούν ειδική επεξεργασία για να λειτουργήσουν κανονικά (όπως είναι για
παράδειγµα οι συσκευές Winmodem).
Κάθε tty driver πρέπει να δηµιουργεί µια struct tty_driver η οποία περιγράφει τον
εαυτό του και καταχωρείται στο tty layer. Η δοµή tty_driver καθορίζεται στο αρχείο
include/linux/tty_driver.h του πηγαίου κώδικα του kernel και µοιάζει µε την ακόλουθη:
struct tty_driver
{
int
magic;
/* magic number for this structure */
const char *driver_name;
const char *name;
int
name_base;
/* offset of printed name */
short
major;
/* major device number */
short
minor_start;
/* start of minor device number*/
short
num;
/* number of devices */
short
type;
/* type of tty driver */
short
subtype;
/* subtype of tty driver */
struct termios
init_termios;
/* Initial termios */
int
flags;
/* tty driver flags */
int
*refcount;
/* for loadable tty drivers */
struct proc_dir_entry
*proc_entry;
/* /proc fs entry */
struct tty_driver *other;
/* only used for the PTY driver */
/*
* Pointer to the tty data structures
*/
struct tty_struct **table;
struct termios **termios;
struct termios **termios_locked;
void *driver_state;
/* only used for the PTY driver */
/*
* Interface routines from the upper tty layer to the tty
* driver.
*/
int (*open)(struct tty_struct *tty, struct file *filp);
void (*close)(struct tty_struct *tty, struct file *filp);
int (*write)(struct tty_struct *tty, int from_user,
const unsigned char *buf, int count);
void (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct termios *old);
void (*throttle)(struct tty_struct *tty);
void (*unthrottle)(struct tty_struct *tty);
void (*stop)(struct tty_struct *tty);
void (*start)(struct tty_struct *tty);
void (*hangup)(struct tty_struct *tty);
void (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
Ιστότοπος εργασίας: MyThesis.org
101
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
void
void
void
int
int
(*set_ldisc)(struct tty_struct *tty);
(*wait_until_sent)(struct tty_struct *tty, int timeout);
(*send_xchar)(struct tty_struct *tty, char ch);
(*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
(*write_proc)(struct file *file, const char *buffer,
unsigned long count, void *data);
/*
* linked list pointers
*/
struct tty_driver *next;
struct tty_driver *prev;
};
Το πρώτο µέλος λοιπόν της δοµής tty_driver είναι το µέλος magic πρέπει πάντα να
αρχικοποιείται µε τιµή TTY_DRIVER_MAGIC έτσι ώστε το επίπεδο tty να γνωρίζει ότι πρόκειται για έναν πραγµατικό tty driver.
Τα µέλη driver_name και name περιγράφουν τον driver και καλό είναι το πρώτο εξ’ αυτών
να αρχικοποιείται σε κάτι περιγραφικό µιας και θα εµφανίζεται στον κατάλογο
/proc/tty/drivers. Το µέλος name χρησιµοποιείται για να καθορίσει πιο θα είναι το βασικό όνοµα του driver (στο /dev ή στο udev). Ως ένα παράδειγµα µπορούµε να φέρουµε και
τον serial driver που υπάρχει στον kernel όπου το µέλος driver_name αρχικοποιείται σε
serial.
Το µέλος name_base είναι απαραίτητο µόνο όταν η συσκευή µας δεν ξεκινά µε ελάχιστο
αριθµό (minor number) το µηδέν. Σχεδόν για όλους τους drivers που γράφονται, η τιµή αυτού
του µέλους πρέπει να αρχικοποιείται µε µηδέν.
Τα µέλη major, minor_start και num περιγράφουν τον µέγιστο και τον ελάχιστο αριθµό
απ’ όπου τελειώνει και ξεκινά η αρίθµηση των drivers στο επίπεδο tty. Το µέλος major θα
πρέπει να παίρνει την τιµή που έχει αντιστοιχηθεί στον µέγιστο αριθµό του driver που έχουµε
γράψει. Αν βρισκόµαστε στη διαδικασία συγγραφής ενός νέου driver µπορούµε να διαβάσουµε το αρχείο devices.txt που βρίσκεται στον κατάλογο documentation του πηγαίου
κώδικα του kernel ώστε να βρούµε τον major (ή τον minor) αριθµό για τον driver αυτό. Το
αρχείο αυτό είναι επίσης χρήσιµο και για όσους θέλουν να γνωρίζουν ποια ζεύγη major / minor αριθµών χρησιµοποιούνται και από ποιες συσκευές. Το µέλος minor_start ορίζεται για να
προσδιορίζει που βρίσκεται ο πρώτος minor αριθµός για την συσκευή µας. Αν έχουµε αντιστοιχίσει εξ’ ολοκλήρου έναν major αριθµό στον driver που δηµιουργήσαµε, τότε ο minor_start πρέπει να τίθεται µηδέν. Τέλος το µέλος num περιγράφει πόσοι διαφορετικοί
minor αριθµοί έχουν αντιστοιχηθεί από εµάς στον συγκεκριµένο driver.
Έτσι, αν για παράδειγµα έχουµε αντιστοιχίσει σε κάποιον driver όλους τους major αριθµούς
στο 188, τότε ο driver αυτός θα πρέπει να αρχικοποιεί τα µέλη που αναφέραµε πριν, ως εξής:
major
minor_start
num
188
0
255
Τα µέλη type και subtype περιγράφουν τι είδους tty driver είναι ο driver που γράψαµε στο
επίπεδο tty. Το µέλος type µπορεί να παίρνει τις παρακάτω τιµές:
TTY_DRIVER_TYPE_SYSTEM: χρησιµοποιείται εσωτερικά από το υποσύστηµα tty έτσι ώστε να γίνεται αντιληπτό πως πρόκειται για έναν εσωτερικό tty driver. Αν χρησι-
Επικοινωνία: [email protected]
102
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
µοποιηθεί η τιµή αυτή τότε η τιµή του µέλους subtype πρέπει να τεθεί σε
SYSTEM_TYPE_TTY, SYSTEM_TYPE_CONSOLE, SYSTEM_TYPE_SYSCONS ή σε
SYSTEM_TYPE_SYSPTMX. Αυτός ο τύπος δε θα πρέπει να χρησιµοποιείται από έναν
απλό tty driver.
TTY_DRIVER_TYPE_CONSOLE: Ο τύπος αυτός θα πρέπει να χρησιµοποιείται µόνο
από τον console driver.
TTY_DRIVER_TYPE_SERIAL: Η τιµή αυτή είναι η συνηθέστερη που παίρνει το µέλος
type. Αν χρησιµοποιείται αυτή η τιµή, τότε το µέλος subtype θα πρέπει να τεθεί σε
SERIAL_TYPE_NORMAL ή σε SERIAL_TYPE_CALLOUT, αναλόγως µε τον τύπο του
driver. Μπορεί να χρησιµοποιηθεί από οποιονδήποτε serial driver.
TTY_DRIVER_TYPE_PTY: Αν το µέλος type παίρνει αυτή την τιµή, τότε το µέλος subtype µπορεί να τίθεται είτε σε PTY_TYPE_MASTER,είτε σε PTY_TYPE_SLAVE. Χρησιµοποιείται από την διεπαφή ψευδό-τερµατικού (PTY – Pseudo Terminal Interface).
Το µέλος init_termios χρησιµοποιείται για να αρχικοποιήσει τις ρυθµίσεις της σειριακής
γραµµής και τις ταχύτητες επικοινωνίας της συσκευής όταν αυτή δηµιουργείται για πρώτη
φορά.
Το µέλος flags τίθεται σε µια ποικιλία τιµών bit ανάλογα µε τις ανάγκες του driver:
TTY_DRIVER_INSTALLED: ο driver δεν µπορεί να καταχωρήσει τον εαυτό του στο
επίπεδο tty, έτσι καλό είναι να µην χρησιµοποιούµε αυτή την τιµή.
TTY_DRIVER_RESET_TERMIOS: όταν η τιµή αυτού του bit ενεργοποιείται (δηλαδή γίνεται 1) προκαλεί τον επαναπροσδιορισµό των ρυθµίσεων termios µετά την εκτέλεση και της τελευταίας διεργασίας της συσκευής. Αυτό είναι χρήσιµο σε περιπτώσεις
drivers κονσόλας και pty.
TTY_DRIVER_REAL_RAW: αν αυτό το bit είναι ενεργοποιηµένο σηµατοδοτεί ότι ο
driver υποστηρίζει ανίχνευση σφαλµάτων και άλλες βελτιστοποιήσεις επικοινωνίας.
TTY_DRIVER_NO_DEVFS: η ενεργοποίηση αυτού του bit αποτρέπει την δηµιουργία
καταχώρησης στο devfs µετά την κλήση της tty_register_function. Αυτό είναι
χρήσιµο για drivers που δηµιουργούν και καταργούν δυναµικά συσκευές ανάλογα µε
το πότε αυτές υπάρχουν φυσικά ή όχι. Παραδείγµατα drivers που ενεργοποιούν το
συγκεκριµένο bit είναι οι µετατροπείς USB σε serial, οι USB modem drivers και οι
drivers USB Bluetooth tty.
Συνεχίζοντας την ανάλυση της δοµής tty_driver εντοπίζουµε το µέλος refcount. Χρησιµοποιείται από το επίπεδο tty για τον χειρισµό της σωστής καταµέτρησης και αναφοράς
του driver.
Το µέλος proc_entry δεν θα πρέπει να τροποποιείται από τον tty driver. Αν ο tty driver
ενσωµατώνει τις συναρτήσεις write_proc ή read_proc, τότε το µέλος proc_entry θα περιέχει την καταχώρηση του οδηγού που δηµιουργήθηκε από εµάς.
Το µέλος other χρησιµοποιείται µόνο από τον pty driver και δε θα πρέπει να χρησιµοποιείται από κάποιον άλλο tty driver.
Στη συνέχεια υπάρχουν κάποιοι δείκτες (pointers) που δείχνουν σε άλλες δοµές tty. Το µέλος table είναι ένας δείκτης πίνακα που περιέχει δείκτες της tty_struct. Τα δύο µέλη
termios και termios_locked, είναι δείκτες σε έναν πίνακα που περιέχει δείκτες της δοµής termios. Όλοι αυτοί οι πίνακες θα πρέπει να έχουν τον ίδιο αριθµό πεδίων µε τον αριθµό του µέλους minor που είδαµε πιο πριν. Χρησιµοποιούνται από το επίπεδο tty για τον
χειρισµό των minor συσκευών και δε θα πρέπει να τροποποιούνται από τον tty driver που
γράφουµε.
Ιστότοπος εργασίας: MyThesis.org
103
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Το µέλος driver_state χρησιµοποιείται µόνο από τον pty driver και δε θα πρέπει να
χρησιµοποιείται από κανένα άλλο tty driver.
Υπάρχει µια αρκετά µεγάλη λίστα µε διάφορους δείκτες συναρτήσεων στην δοµή
tty_driver. Αυτοί οι δείκτες χρησιµοποιούνται από το επίπεδο tty για την επικοινωνία µε
τον tty driver όταν αυτή είναι απαιτείται για την πραγµατοποίηση κάποιας ενέργειας.
Η συνάρτηση open καλείται από το επίπεδο tty όταν η open (2) καλείται από τη συσκευή
στην οποία έχει αντιστοιχηθεί ο tty driver που έχουµε γράψει. Το επίπεδο tty επιτυγχάνει αυτή την κλήση µέσω ενός δείκτη ο οποίος δείχνει στην δοµή tty_struct καθώς και µέσω
ενός δείκτη αρχείου που έχει αντιστοιχηθεί στη συσκευή.
Ίσως όλα τα παραπάνω, αλλά και αυτά που θα ακολουθήσουν, να είναι αρκετά πολύπλοκα
και να µπερδεύουν ως ένα βαθµό. Όµως όταν κάποιος προσπαθήσει να τα υλοποιήσει στην
πράξη, τα πράγµατα αρχίζουν σταδιακά να ξεκαθαρίζουν και όλα αποκτούν µεγαλύτερο νόηµα. Απαιτείται υποµονή, επιµονή και εφαρµογή.
Η συνάρτηση close καλείται από το επίπεδο tty όταν η release (2) καλείται από τον δείκτη που δείχνει στο αρχείο ο οποίος δηµιουργήθηκε προηγουµένως µέσω της κλήσης της
open (2). Αυτό σηµαίνει ότι η συσκευή θα πρέπει να κλείσει.
Η συνάρτηση write καλείται από το επίπεδο tty όταν κάποια τα δεδοµένα πρόκειται να
αποσταλούν στην tty συσκευή µας. Τα δεδοµένα αυτά µπορεί να προέρχονται είτε από την
περιοχή χρήστη (user space), είτε από την περιοχή του πυρήνα (kernel space). Το µέλος
from_user θα ενεργοποιηθεί αν τα δεδοµένα έρχονται από την περιοχή χρήστη. Η συνάρτηση write θα πρέπει να επιστρέψει τον αριθµό των bytes που γράφτηκαν τελικά στη συσκευή. Η συνάρτηση αυτή πρέπει να καθορίζεται για έναν tty driver.
Η συνάρτηση put_char καλείται από το επίπεδο tty όταν ένας και µόνο χαρακτήρας πρέπει να γραφεί στη συσκευή. Αν δεν υπάρχει αρκετός χώρος γι’ αυτή την εγγραφή, ο χαρακτήρας που εστάλη µπορεί να αγνοηθεί. Αν ένας tty driver δεν καθορίζει αυτή τη συνάρτηση
τότε για την εγγραφή ενός απλού χαρακτήρα θα καλείται η συνάρτηση write.
Η συνάρτηση flush_chars καλείται όταν το επίπεδο tty έχει στείλει ένα αριθµό χαρακτήρων στον tty driver καλώντας την συνάρτηση put_char. Ο tty driver θα πρέπει να ενηµερώσει τη συσκευή ότι πρέπει να αποστείλει όλα τα δεδοµένα που αποµένουν σε αυτή, µέσω
της σειριακής γραµµής (serial line).
Η συνάρτηση write_room καλείται από το επίπεδο tty όταν αυτό θέλει να γνωρίζει πόσο
ελεύθερο χώρο έχει ο tty driver στον καταχωρητή εγγραφής (write buffer) του. Αυτός ο αριθµός µεταβάλλεται µε το χρόνο καθώς οι καταχωρητές εγγραφής θα αδειάζουν.
Η συνάρτηση chars_in_buffer καλείται όταν το επίπεδο tty θέλει να γνωρίζει πόσοι χαρακτήρες αποµένουν για αποστολή από τον καταχωρητή εγγραφής του tty driver.
Η συνάρτηση ioctl καλείται από το επίπεδο tty όταν ή ioctl (2) καλείται από τη συσκευή. Η συνάρτηση αυτή επιτρέπει στον tty driver να ενσωµατώσει συναρτήσεις ioctl εξειδικευµένες προς τη συσκευή. Αν η συνάρτηση ioctl που ζητείται δεν υποστηρίζεται από
τον driver επιστρέφεται η τιµή –ENOIOCTLCMD.
Η συνάρτηση set_termios καλείται από το επίπεδο tty όταν οι ρυθµίσεις termios της συσκευής έχουν αλλάξει. Σε τέτοια περίπτωση ο tty driver θα πρέπει να αλλάξει τις ρυθµίσεις
Επικοινωνία: [email protected]
104
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
των φυσικών χαρακτηριστικών της συσκευής ανάλογα µε τα διάφορα µέλη που υπάρχουν
στην δοµή termios.
Οι συναρτήσεις throttle και unthrottle χρησιµοποιούνται για τον έλεγχο της υπερχείλισης των καταχωρητών εισόδου του tty επιπέδου. Η συνάρτηση throttle καλείται όταν οι
καταχωρητές εισόδου του επιπέδου tty είναι έτοιµοι να γεµίσουν. Ο tty driver θα πρέπει να
ειδοποιήσει τη συσκευή ότι δεν µπορούν να σταλθούν άλλοι χαρακτήρες. Όταν οι καταχωρητές εισόδου αδειάσουν κάποια στιγµή και µπορούν να ληφθούν νέα δεδοµένα, τότε καλείται η
συνάρτηση unthrottle. Έτσι ο tty driver ενηµερώνει τη συσκευή ότι µπορεί να συνεχίσει
να στέλνει την αποστολή δεδοµένων.
Οι συναρτήσεις start και stop µοιάζουν µε τις δύο προηγούµενες που είδαµε αλλά ο tty
driver θα πρέπει να σταµατήσει να στέλνει δεδοµένα στη συσκευή και στη συνέχεια να συνεχίσει την αποστολή από εκεί που σταµάτησε.
Η συνάρτηση hangup καλείται όταν ο tty driver πρέπει να διακόψει την επικοινωνία µε την
tty συσκευή.
Η συνάρτηση break_ctrl καλείται όταν ο tty driver πρόκειται να ενεργοποιήσει ή να απενεργοποιήσει την κατάσταση (state) BREAK της θύρας RS-232. Αν η κατάσταση έχει την τιµή
-1, τότε η κατάσταση BREAK θα πρέπει να ενεργοποιηθεί. Αν έχει την τιµή µηδέν τότε θα
πρέπει να συµβεί το αντίθετο δηλαδή να απενεργοποιηθεί. Αν η συνάρτηση break_ctrl
είναι ενσωµατωµένη από τον tty driver τότε, το επίπεδο tty θα πρέπει να χειριστεί τα ioctls:
TCSBRK, TCSBRKP, TIOCSBRK και TIOCCBRK. ∆ιαφορετικά θα πρέπει αυτά να σταλούν στην
συνάρτηση ioctl του tty driver.
Η συνάρτηση flush_buffer καλείται όταν ο tty driver θέλει να αδειάσει τα δεδοµένα που
υπάρχουν ακόµα στους καταχωρητές εγγραφής του. Αυτό σηµαίνει ότι τα δεδοµένα που αποµένουν σε αυτούς τους καταχωρητές δε θα αποσταλούν στη συσκευή.
Η συνάρτηση ser_ldisc καλείται όταν το επίπεδο tty αλλάζει την διαµόρφωση της σύνδεσης (line discipline) του tty driver. Παρ’ όλα αυτά η συνάρτηση αυτή δε χρησιµοποιείται πια
και δεν θα πρέπει να την χρησιµοποιούµε ούτε εµείς.
Η συνάρτηση wait_until_sent καλείται όταν το επίπεδο tty θέλει να ενηµερωθεί για όλα
τα εναποµείναντα δεδοµένα που βρίσκονται σε εκκρεµότητα (pending data) αποστολής προς
τη συσκευή από τον tty driver. Η συνάρτηση wait_until_sent δε θα πρέπει να επιστρέψει
(return) καµία τιµή µέχρι να ολοκληρώσει την εργασία της και γι’ αυτό επιτρέπεται να τεθεί
σε κατάσταση sleep αν χρειαστεί να περιµένει για κάποιο διάστηµα.
Η συνάρτηση send_xchar χρησιµοποιείται για την αποστολή ενός χαρακτήρα υψηλής
προτεραιότητας XON ή XOFF στη συσκευή tty.
Οι συναρτήσεις read_proc και write_proc χρησιµοποιούνται όταν ο driver χρειάζεται να
ενσωµατώσει µια καταχώρηση /proc/tty/driver/<onoma>. Το onoma θα εισαχθεί από
το µέλος name που είδαµε νωρίτερα.
Τέλος, τα µέλη next και prev, χρησιµοποιούνται από το επίπεδο tty για να διασυνδέσει
όλους τους tty drivers µαζί. Στα µέλη αυτά δε θα πρέπει να έχει καµία πρόσβαση ο tty driver.
Αφού είδαµε όλα τα παραπάνω µέλη αυτά τα οποία είναι άκρως απαραίτητα για τη δηµιουργία του ελάχιστου tty driver που όµως θα λειτουργεί και θα εκτελεί κάποιες βασικές εργασίες. Ο ακόλουθος κώδικας είναι ένα τέτοιο παράδειγµα:
Ιστότοπος εργασίας: MyThesis.org
105
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
#define TINY_TTY_MAJOR 240
#define TINY_TTY_MINORS 255
/* experimental range */
/* use the whole
major up */
static int tty_refcount;
static struct tty_struct *tiny_tty[TINY_TTY_MINORS];
static struct termios *tiny_termios[TINY_TTY_MINORS];
static struct termios
*tiny_termios_locked[TINY_TTY_MINORS];
static struct tty_driver tiny_tty_driver {
magic:
TTY_DRIVER_MAGIC,
driver_name:
"tiny_tty",
#ifdef CONFIG_DEVFS_FS
name:
"tts/ttty%d",
#else
name:
"ttty",
#endif
major:
TINY_TTY_MAJOR,
num:
TINY_TTY_MINORS,
type:
TTY_DRIVER_TYPE_SERIAL,
subtype:
SERIAL_TYPE_NORMAL,
flags:
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_NO_DEVFS,
refcount:
table:
termios:
termios_locked:
&tiny_refcount,
tiny_tty,
tiny_termios,
tiny_termios_locked,
open:
close:
write:
write_room:
tiny_open,
tiny_close,
tiny_write,
tiny_write_room,
};
static int __init tiny_init (void)
{
/* register the tty driver */
tiny_tty_driver.init_termios = tty_std_termios;
tiny_tty_driver.init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
if (tty_register_driver (&tiny_tty_driver)) {
printk (KERN_ERR "failed to register
tiny tty driver");
return -1;
return 0;
}
static void __exit tiny_exit (void)
{
tty_unregister_driver (&tiny_tty_driver);
}
module_init (tiny_init);
module_exit (tiny_exit);
Για την καλύτερη κατανόηση της λειτουργίας του πυρήνα (core) του υποσυστήµατος TTY,
πολύ χρήσιµη είναι και η περιγραφή ενός tty driver. Ένας tty driver είναι ένας character driver
ο οποίος ελέγχει τη ροή και τη µορφή των δεδοµένων σε µια συσκευή tty. Για τον έλεγχο της
ροής των δεδοµένων υπάρχει ένας αριθµός κανόνων ή ελέγχων σύνδεσης (line disciplines) ο
οποίος µπορεί να ενσωµατωθεί εικονικά σε κάθε συσκευή tty. Αυτό επιτυγχάνεται µέσω διαΕπικοινωνία: [email protected]
106
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
φορετικών drivers ελέγχου σύνδεσης. Όπως βλέπουµε και στην επόµενη εικόνα, ο πυρήνας
tty παίρνει τα δεδοµένα τα οποία θέλει ένας χρήστης να στείλει σε µια tty συσκευή και τα
προωθεί στον driver ελέγχου σύνδεσης (tty line discipline) ο οποίος µε τη σειρά του τα προωθεί στον tty driver. Έπειτα ο τελευταίος, µετατρέπει τα δεδοµένα που έλαβε σε µια µορφή
κατανοητή για το υλικό:
Εικόνα 30. Γραφική αναπαράσταση της λειτουργίας του υποσυστήµατος TTY
3.5.2 RS-232
Εφόσον το RS232 είναι µια διεπαφή υλικού (chip), ο kernel δε χρειάζεται να το υποστηρίζει
ο ίδιος. Έτσι περιλαµβάνει κυρίως drivers για ολοκληρωµένα που υλοποιούν την επικοινωνία
RS232 (πχ: MAX232). Ο βασικός driver για την σειριακή (UART) επικοινωνία στον kernel
είναι το αρχείο serial.c και βρίσκεται στον κατάλογο drivers. Κάποιες αρχιτεκτονικές
όπως η AVR32 έχουν τους δικούς τους drivers (atmel_serial.c) για να υποστηρίξουν το
υλικό τους. Παρ’ όλα αυτά, οι σειριακές συσκευές του Linux είναι προσβάσιµες σαν τερµατικές συσκευές, όπως συµβαίνει και στα συστήµατα Unix, ανεξάρτητα από το υποκείµενο υλικό και τα σχετικά προγράµµατα οδήγησης.
Οι καταχωρήσεις των σειριακών συσκευών στο Linux ξεκινούν µε /dev/ttyS0 και µπορούν να φτάσουν µέχρι και /dev/ttyS0191 (δηλαδή τουλάχιστον 190 συσκευές). Στις περισσότερες των περιπτώσεων όµως οι συσκευές που υπάρχουν σε ένα σύστηµα είναι
ελάχιστες.
Τα βασικά για τη σειριακή επικοινωνία, τη διαµόρφωση, την εγκατάστασή της αλλά και τον
προγραµµατισµό, σε ότι αφορά το Linux, περιλαµβάνονται στον αντίστοιχο online οδηγό του
LDP (tldp.org/HOWTO/pdf/Serial-HOWTO.pdf).
3.5.3 GPIO
Τα σήµατα εισόδου – εξόδου γενικού σκοπού, GPIO (General Purpose Input/Output) είναι
ευέλικτα ψηφιακά σήµατα τα οποία ελέγχονται µέσω λογισµικού. Κάθε ένα τέτοιο σήµα αναπαριστά ένα bit το οποίο είναι αντιστοιχισµένο µε ένα συγκεκριµένο pin του µικροελεγκτή.
Ανάλογα µε το υλικό, τα σήµατα GPIO µπορούν να επιτελούν διάφορες λειτουργίες. Για παράδειγµα, στον µικροελεγκτή της εργασίας µας παρέχονται τα εξής:
Ιστότοπος εργασίας: MyThesis.org
107
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
∆ιακοπή που ανιχνεύει µεταβολή εισόδου (input change interrupt) και µπορεί να κάνει
δυνατή την ανίχνευση αλλαγής επιπέδου (level change detection) σε οποιαδήποτε είσοδο.
Φίλτρο απόρριψης (glitch filter) παλµών που είναι χαµηλότεροι από το µισό ενός κύκλου ρολογιού, για την αποφυγή σφαλµάτων από απότοµες µεταβολές.
Έλεγχο pull-up για γραµµές εισόδου – εξόδου.
∆ιαχείριση των εισόδων και των εξόδων
Η υποστήριξη GPIO µπορεί να ρυθµιστεί από το γραφικό περιβάλλον παραµετροποίησης
του Kernel (Device drivers
GPIO Support). Στην εικόνα µπορούµε να δούµε τις
δυνατότητες που παρέχονται:
Εικόνα 31. Ενεργοποίηση υποστήριξης GPIO από τον Linux Kernel
Το Linux παρέχει ένα επίπεδο λογισµικού το οποίο διαχειρίζεται την παραµετροποίηση και
τις διεργασίες εισόδου – εξόδου των σηµάτων GPIO. Έτσι εξασφαλίζεται η ασφάλεια των ενεργειών που πραγµατοποιούνται, η µεταφερσιµότητα του κώδικα σε διαφορετικά συστήµατα, καθώς και ο ευκολότερος χειρισµός του υλικού που βρίσκεται από κάτω. Η πρόσβαση σε
ένα σήµα GPIO είναι εφικτή από δύο σηµεία του Linux:
Περιβάλλον χρήστη (user space)
Περιβάλλον πυρήνα (Kernel space)
Τα σήµατα GPIO θα πρέπει να καθορίζονται στον κώδικα που ρυθµίζει την πλακέτα µας
(board setup code) ο οποίος βρίσκεται σε επίπεδο Kernel space. Αυτό είναι αναγκαίο γιατί
από αυτό το σηµείο µπορεί να υπάρχει πλήρης έλεγχος για τις ρυθµίσεις όλων των ακροδεκτών του µικροελεγκτή µας. Για µια εφαρµογή επιπέδου user αλλά και για ένα module, δεν
είναι δυνατή η τροποποίηση δύο εκ των τεσσάρων λειτουργιών που αναφέραµε αρχικά ότι
επιτελούνται από τα σήµατα GPIO:
Επικοινωνία: [email protected]
108
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Ο έλεγχος pull-up για γραµµές εισόδου – εξόδου
Η ρύθµιση του φίλτρου
Όλες οι συναρτήσεις και οι λεπτοµέρειες που θα πρέπει να ρυθµιστούν για να ενεργοποιήσουµε τα σήµατα GPIO στην πλακέτα µας, βρίσκονται στο αρχείο κεφαλής portmux.h που
υπάρχει στον κατάλογο του kernel include/asm/arch.
Η συνάρτηση at32_select_gpio(unsigned int pin, unsigned long flags),
είναι ότι χρειαζόµαστε για την παραµετροποίηση των GPIO. Ο ακέραιος αριθµός pin µπορεί
βρεθεί χρησιµοποιώντας ειδικές µακροεντολές που υπάρχουν στο αρχείο at32ap7000.h.
Για παράδειγµα, προκειµένου να επιλέξουµε την γραµµή εισόδου – εξόδου 0, του ελεγκτή
(PIO controller) Β, χρησιµοποιούµε την µακροεντολή GPIO_PIN_PB(0).
Τα διαθέσιµα flags (σηµαίες) που υπάρχουν για τη συνάρτηση at32_select_gpio και τα
τα είδαµε στο µεγαλύτερο µέρος τους όταν ασχοληθήκαµε µε τον δίαυλο I2C-GPIO, στον πίνακα 2 (σελίδα 106).
Υπάρχουν παραδείγµατα παραµετροποίησης των pins στον κώδικα διαµόρφωσης (setup
code) που παρέχει η Atmel για τις πλακέτες της στον κατάλογο arch/avr32/boards του
Linux Kernel. Σε αυτό τον κώδικα υπάρχουν δύο επιπλέον συναρτήσεις για την ρύθµιση
GPIO pins:
at32_select_periph(unsigned int pin, unsigned int periph, unsigned long flags)
at32_reserve_pin(unsigned int pin)
Η πρώτη µπορεί να ρυθµίσει κάποιο pin να είναι συνδεδεµένο µε ένα module που βρίσκεται
ενσωµατωµένο (on-chip) στον µικροελεγκτή, όπως είναι για παράδειγµα το SPI και το I2C.
Με λίγα λόγια τα σήµατα GPIO µπορούν να υποστηρίξουν επικοινωνία SPI και I2C. Αυτό βέβαια εξαρτάται από τον µικροελεγκτή. Εποµένως θα πρέπει να συµβουλευόµαστε κάθε φορά
και το αντίστοιχο datasheet.
Η δεύτερη συνάρτηση δεσµεύει ένα pin για µετέπειτα χρήση και αυτό κάνει το συγκεκριµένο
pin µη τροποποιήσιµο. Και στις δύο συναρτήσεις, τα pins που δεσµεύονται δεν µπορούν να
τροποποιηθούν από άλλους παράγοντες του λογισµικού. Αυτό καθιστά αδύνατη την κατά
λάθος τροποποίηση ενός σήµατος GPIO και προσφέρει αξιοπιστία.
Μέχρι αυτή τη στιγµή µελετήσαµε τον έλεγχο των σηµάτων GPIO από το Kernel space. Στη
συνέχεια θα δούµε πως µπορούµε να χειριστούµε σήµατα GPIO µέσω εφαρµογών από το
user space. Για επιτύχουµε κάτι τέτοιο µπορούµε να χρησιµοποιήσουµε τη διεπαφή /dev.
Χρήση της διεπαφής /dev
Η διεπαφή /dev κάνει χρήση του configfs προκειµένου να µπορεί να µπορεί να ρυθµιστεί
ένα σήµα GPIO από το user space. Το configfs είναι ένα σύστηµα αρχείων το οποίο διαχειρίζεται αντικείµενα (objects) του Kernel. Αυτό το σύστηµα αρχείων υπάρχει µόνο στη RAΜ και
είναι άδειο µέχρι να φορτωθούν modules που πιθανόν χρειάζονται κατά τη λειτουργία του
συστήµατος. Ένας GPIO driver θα µπορούσε να είναι ένα τέτοιο module. Καταχωρεί τον εαυτό του στο configfs και στη συνέχεια είναι ορατό σαν ένας υποκατάλογος στον κατάλογο
/configfs/gpio. Το αρχείο για το κάθε GPIO δηµιουργείται από το πρόγραµµα mdev.
Εάν το πρόγραµµα αυτό δεν είναι διαθέσιµο θα δηµιουργηθεί από το πρόγραµµα mknod.
Έτσι, µπορούµε εύκολα από το user space να δηµιουργούµε ή να καταργούµε σήµατα GPIO
µε απλές εντολές UNIX, όπως είναι για παράδειγµα η mkdir και η rmdir. Βέβαια η κατάρ-
Ιστότοπος εργασίας: MyThesis.org
109
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
γηση µπορεί να πραγµατοποιηθεί µόνο αν δεν υπάρχει κάποιο symlink προς το GPIO που
θέλουµε να καταργήσουµε διαφορετικά κάτι τέτοιο θα αποτραπεί άµεσα από τον Kernel.
Αφού δηµιουργήσουµε ένα σήµα GPIO µε την εντολή mkdir, αυτόµατα µέσα στον κατάλογό του θα δηµιουργηθούν επίσης και ορισµένα αρχεία. Τα αρχεία αυτά θα αποτελούν τις ιδιότητές (attributes) του σήµατος και θα µπορούν να τροποποιηθούν από εφαρµογές ή από
εντολές shell, µε απλές αναγνώσεις και εγγραφές σαν να είναι απλά αρχεία κειµένου.
Το σύστηµα αρχείων configfs και η δυνατότητα GPIO στο /dev θα πρέπει είτε να έχουν µεταγλωττιστεί µαζί µε τη µορφή ενός module, είτε να έχουν µεταγλωττιστεί µέσα στον Kernel,
έτσι ώστε να είναι δυνατή η δηµιουργία σηµάτων GPIO από το user space. Επίσης θα πρέπει η δυνατότητα αυτή να έχει φορτωθεί κατά την εκκίνηση του συστήµατος από τα startup
scripts. Εάν δεν έχει φορτωθεί θα πρέπει να το κάνουµε χειροκίνητα εκτελώντας σε γραµµή
εντολών τις παρακάτω εντολές:
mkdir /config
mount –t configfs config /config
Αν ο κατάλληλος driver GPIO για το /dev είναι διαθέσιµος στον Kernel, τότε στον κατάλογο
/config θα βρούµε έναν υποκατάλογο gpio.
Σε αυτό το σηµείο µπορούµε να δηµιουργήσουµε ένα νέο σήµα GPIO. Για παράδειγµα µπορούµε να χειριζόµαστε ένα LED στην πλακέτα µας για την προειδοποίηση του χρήστη όταν
συµβαίνει κάποιο γεγονός. Ένα τέτοιο γεγονός σε ένα Router θα µπορούσε να είναι η ύπαρξη ή όχι, σύνδεσης µε κάποιο τοπικό δίκτυο (Local Network Status LED) ή η ένδειξη της κατάστασης της ασύρµατης δικτύωσης (WiFi Status LED). Με την παρακάτω εντολή
δηµιουργούµε έναν κατάλογο στον οποίο θα υπάρχουν LEDs τα οποία θα ελέγχονται µέσω
σηµάτων GPIO:
mkdir /config/gpio/leds
Τώρα όλες οι ιδιότητες του αντικειµένου GPIO που δηµιουργήσαµε θα βρίσκονται όπως είδαµε και νωρίτερα, µέσα στον κατάλογο leds µε τη µορφή αρχείων. Τα αρχεία αυτά δέονται
ως είσοδο ακολουθίες χαρακτήρων (strings) ASCII και κατά την ανάγνωσή τους διαβάζονται
ακολουθίες χαρακτήρων της ίδιας κωδικοποίησης. Οι αριθµοί µπορούν να γράφονται είτε σε
δεκαδική (πχ: 255), είτε σε δεκαεξαδική µορφή (πχ: 0xFF).
Τα αρχεία ρυθµίσεων που προκύπτουν είναι τα εξής:
gpio_id – Επιλέγει τον παράλληλο ελεγκτή εισόδου – εξόδου (PIO – Parallel I/O controller).
Γράφοντας µηδέν (0) στο αρχείο, επιλέγεται ο PIOA, γράφοντας 1, ο PIOB κλπ.
pin_mask – Επιλέγει τα pins του PIO controller που αναφέρεται στο αρχείο
gpio_id. Κάθε PIO controller έχει 32 προγραµµατιζόµενες γραµµές. Εποµένως τα
pins του µικροελεγκτή που θέλουµε να συµπεριφέρονται σαν σήµατα GPIO, συµβολίζονται µε έναν δεκαεξαδικό αριθµό µήκους 32 bit. Για παράδειγµα αν θέλουµε η
γραµµή 1 να λειτουργεί σαν GPIO θα πρέπει να γράψουµε την τιµή 0x00000001 (ή
0x1 ή απλά 1) στο αρχείο pin_mask. Πριν από αυτή την ενέργεια όµως θα πρέπει
πρώτα να έχουµε ελέγξει µέσω κατάλληλης συνάρτησης αν η γραµµή 1 είναι ελεύθερη για χρήση.
oe_mask – Καθορίζει το αν ένα σήµα GPIO θα λειτουργεί σαν είσοδος ή σαν έξοδος.
Αφού έχουµε καταχωρήσει επιτυχώς µια γραµµή µέσω του αρχείου pin_mask, µπορούµε να κανονίσουµε την λειτουργία της µέσω του αρχείου oe_mask. Η ρύθµιση
Επικοινωνία: [email protected]
110
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
που υπάρχει εξ αρχής (default) για ένα GPIO pin (γραµµή) είναι αυτή της εισόδου. Αν
θέλουµε να λειτουργεί ως έξοδος, αποθηκεύουµε την τιµή 0x00000001 στο αρχείο
oe_mask.
enabled – Ενεργοποιεί το αντικείµενο gpio που είδαµε νωρίτερα όταν µιλήσαµε για
τη διεπαφή /dev. Γράφοντας την τιµή 1 στο αρχείο enabled ενεργοποιούνται οι
ρυθµίσεις παραµετροποίησης gpio_id, pin_mask και oe_mask. Αυτό θα έχει ως
αποτέλεσµα τη δηµιουργία του αρχείου /dev/gpio0, δηλαδή της συσκευής gpio0.
Βέβαια εάν πιο πριν έχουν δηµιουργηθεί και άλλες συσκευές GPIO το όνοµα µπορεί
να διαφέρει (πχ: gpio3).
Όταν επιλέγουµε να έχουµε πρόσβαση µέσω του userspace σε ένα σήµα GPIO, υπάρχουν
τρεις τρόποι να το κάνουµε.
Μέση εντολών shell
Με ένα shell script
Μέσω µιας εφαρµογής
Ας δούµε ένα παράδειγµα πρόσβασης µέσω εντολών shell. Υποθέτοντας ότι θέλουµε τα
pins του PIOB, 0-3 να λειτουργούν σαν έξοδοι και τα pins 4-7 ως είσοδοι. Θα πρέπει να εκτελέσουµε διαδοχικά τις παρακάτω εντολές:
echo
echo
echo
echo
1
255
15
1
>
>
>
>
/config/gpio/leds/gpio_id
/config/gpio/leds/pin_mask
/config/gpio/leds/oe_mask
/config/gpio/leds/enabled
#
#
#
#
ή 0x1 (χρήση του PIOB)
ή 0xff (pins 0-7)
ή 0x0f (έξοδοι:0-3,είσοδοι:4-7)
δηµιουργία της συσκευής
Αν οι παραπάνω εντολές αποθηκευτούν σε ένα αρχείο dimiourgia_syskevis_gpio.sh
επιτυγχάνουµε τον δεύτερο τρόπο πρόσβασης, που είναι η πρόσβαση µέσω shell script. H
εκτέλεσή του είναι πολύ απλή:
chmod 755 dimiourgia_syskevis_gpio.sh
./ dimiourgia_syskevis_gpio.sh
Πρέπει να πούµε ότι υπάρχει και η δυνατότητα να αντιστοιχίζουµε µια ολόκληρη συσκευή
(gpio object) σε ένα και µόνο pin εφόσον απαιτείται µεγαλύτερη ανεξαρτησία.
Αν θέλουµε να χειριστούµε σήµατα GPIO µέσω εφαρµογής και όχι µέσω των δύο άλλων
τρόπων που περιγράψαµε, θα πρέπει να λάβουµε υπ’ όψιν τα εξής: Το σύστηµα αρχείων
configfs απαιτεί µια κλήση εγγραφής (write call) προκειµένου να αποθηκεύσει ολόκληρο το
αρχείο ιδιοτήτων (attribute file). Για το λόγο αυτό θα πρέπει πρώτα να διαβάζει ολόκληρο το
αρχείο, να το τροποποιεί και στη συνέχεια να το αποθηκεύει. Το µέγιστο επιτρεπόµενο µέγεθος ενός τέτοιου αρχείου δεν θα πρέπει να υπερβαίνει το µέγεθος µιας σελίδας της µνήµης.
Για να γνωρίζουµε κάθε φορά πιο είναι αυτό το µέγεθος µπορούµε να χρησιµοποιούµε τη
συνάρτηση getpagesize() ή κάποια παρόµοια. Στην περίπτωση του Router NGW100, το
µέγεθος της σελίδας ορίζεται από την αρχιτεκτονική AVR32 και είναι 4096 bytes (512 KB).
Είσοδος και έξοδος σηµάτων GPIO
Αφού έχουµε δηµιουργήσει τελικά το αντικείµενο gpio και έχουµε ολοκληρώσει την παραµετροποίησή του µπορούµε πλέον να το χρησιµοποιούµε για την είσοδο και έξοδο σηµάτων.
Σε αυτή την περίπτωση δεν µπορούµε πλέον να στέλνουµε χαρακτήρες ASCII αλλά µόνο
δυαδικά (binary) ψηφία. Φυσικά αυτό το αναλαµβάνει ο φλοιός. Έτσι χρησιµοποιώντας την
Ιστότοπος εργασίας: MyThesis.org
111
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
εντολή echo σε κατάλληλη µορφή µπορούµε να εκτελέσουµε και πάλι τις εντολές που είδαµε
νωρίτερα, µε τον εξής τρόπο:
echo –ne "\x00\x00\x00\x0F" > /dev/gpio0
Ουσιαστικά µε την εντολή αυτή γράψαµε 4 bytes. Αν θέλουµε να διαβάσουµε τα 4 bytes
χρησιµοποιούµε την εξής εντολή:
dd bs=4 count=1 if=/dev/gpio0 2> /dev/zero | hexdump
Το πρόγραµµα dd διαβάζει τα τέσσερα bytes (bs = αριθµός bytes, count = πόσες φορές
να διαβαστούν τα bs bytes) από τη συσκευή gpio0, αποθηκεύει τυχόν σφάλµατα στο
/dev/zero και περνά τα δεδοµένα στο πρόγραµµα hexdump. Το hexdump θα τυπώσει τα 4
bytes µε τη µορφή δεκαεξαδικής τιµής.
Όσα είδαµε αφορούν το περιβάλλον του shell. Στη συνέχεια θα δούµε πως όλα αυτά επιτυγχάνονται και µέσω εφαρµογής. Συνήθως αυτή είναι και η συνηθέστερη περίπτωση ανάγνωσης και εγγραφής των GPIO. Σε µια εφαρµογή µπορούµε να χρησιµοποιήσουµε
διάφορες µεθόδους εισόδου – εξόδου σε ένα αρχείο GPIO:
Blocking – Γίνεται ανάγνωση του αρχείου της συσκευής GPIO ανεξάρτητα από το αν
έχει τροποποιηθεί. Η µέθοδος αυτή είναι και η βασική µέθοδος ανοίγµατος αρχείων
στο Linux.
Non-Blocking – Γίνεται ανάγνωση του αρχείου µόνο εάν αυτό έχει αλλάξει. Η µέθοδος
αυτή µπορεί να χρησιµοποιηθεί σε συνδυασµό µε τη διεπαφή Poll του Linux έτσι ώστε να υπάρχει η δυνατότητα όταν δεν χρησιµοποιείται, να πέφτει σε κατάσταση
sleep.
Asynchronous – Σε αυτή την περίπτωση η µέθοδος εισόδου – εξόδου βασίζεται στο
σύστηµα σηµατοδοσίας (signaling) του Linux και στο GPIO framework που υπάρχει.
Έτσι η εφαρµογή µας εναποθέτει στο λειτουργικό σύστηµα την παρακολούθηση των
αλλαγών κατάστασης του GPIO που ελέγχουµε. Κάθε φορά που το Linux αντιλαµβάνεται µια αλλαγή, ενηµερώνει άµεσα την εφαρµογή µας.
Έλεγχος GPIO µέσω module
Η χρήση και ο έλεγχος των σηµάτων GPIO σε έναν driver είναι η πιο άµεση περίπτωση. Αν
δηµιουργήσουµε µε τη µορφή module έναν driver χειρισµού GPIO τότε όπως γνωρίζουµε θα
µπορούµε να τον φορτώνουµε κατά τη διάρκεια λειτουργίας του συστήµατος µας µε την εντολή insmod. Το Linux παρέχει µια εξειδικευµένη διεπαφή για ανάπτυξη τέτοιων drivers η
οποία περιγράφεται στο αρχείο κεφαλής include/asm/arch/gpio.h. ∆εν θα πρέπει όµως να το εισάγουµε (include) όµως άµεσα στον κώδικά µας αλλά µέσω του αρχείου κεφαλής include/asm/gpio.h. Στο αρχείο Documentation/gpio.txt που υπάρχει στους
καταλόγους του πηγαίου κώδικα του Linux, περιλαµβάνεται η απαραίτητη τεκµηρίωση.
Linux LED Framework
Το Linux παρέχει ειδικό κώδικα για την οδήγηση των LED. Το framework αυτό µπορεί όµως
να χρησιµοποιηθεί και για τον έλεγχο άλλων περιπτώσεων µέσω GPIO. Για να είµαστε σε
θέση να χρησιµοποιήσουµε το LED framework του Linux θα πρέπει να κάνουµε ορισµένες
αλλαγές σε δύο σηµεία. Η µία αλλαγή θα πρέπει να γίνει στον εξειδικευµένο κώδικα που έχει
γραφτεί για τον χειρισµό της πλακέτας µας (board specific code) και η δεύτερη στον Linux
Επικοινωνία: [email protected]
112
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Kernel. Στην εικόνα βλέπουµε τις επιλογές που υπάρχουν διαθέσιµες µέσω του γραφικού
περιβάλλοντος παραµετροποίησης του Kernel (Device Drivers
Led Devices):
Εικόνα 32. Ενεργοποίηση του Linux LED Framework
Όταν ένα LED συνδέεται µε ένα pin του µικροελεγκτή και θέλουµε να το ελέγχουµε µέσω
του Linux LED Framework, τότε αυτό θα πρέπει να το δηλώσουµε στον εξειδικευµένο κώδικα
που αφορά την πλακέτα µας. Η διεπαφή που θα πρέπει να χρησιµοποιηθεί περιγράφεται στο
αρχείο κεφαλής include/linux/leds.h. Γενικά ένα LED έχει κάποια χαρακτηριστικά και
αυτό σε επίπεδο υλικολογισµικού περιγράφεται στην παρακάτω δοµή δεδοµένων:
struct gpio_led {
const char *name;
/*
char *default_trigger; /*
unsigned gpio;
/*
u8 active_low;
/*
};
/* Άνω του ενός LED απαιτείται η
Led name */
Trigger name if used */
Number of the GPIO line */
Set to 1 if active low */
δηµιουργία πίνακα δοµών gpio_led */
Το επόµενο βήµα είναι να δηλώσουµε την δοµή gpio_led_platform_data η οποία θα
έχει µέλη της τον αριθµό των LED και τη διεύθυνση µνήµης τους:
struct gpio_led_platform_data {
int num_leds;
/* Number of LEDs in our array*/
struct gpio_led *leds;
/* Start address of LED array */
};
Η τελευταία δοµή που χρειαζόµαστε είναι η platform_device ή οποία καταχωρεί όλα τα
LED σαν µια συσκευή platform. Ο ορισµός αυτής της δοµής δεδοµένων υπάρχει στο αρχείο
κεφαλής include/linux/platform_device.h:
Ιστότοπος εργασίας: MyThesis.org
113
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
struct platform_device {
const char *name;
u32 id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
Τα πεδία της platform_device τα οποία θα πρέπει να αρχικοποιηθούν από εµάς είναι το
name, id και platform_data που ορίζεται στη δοµή device. Η περιγραφή αυτής της δοµής υπάρχει και στο αρχείο κεφαλής include/linux/device.h. Το όνοµα που θα επιλέξουµε θα εµφανίζεται στη συνέχεια στο σύστηµα αρχείων /sys σαν ένας απλός
υποκατάλογος µέσα στον κατάλογο class/leds/ και θα πρέπει να είναι το gpio-leds. Αν
θέλουµε να δηµιουργήσουµε µόνο ένα στιγµιότυπο της συσκευής (platform_device), δίνουµε την τιµή 0 στο id. Αν χρειαζόµαστε περισσότερα, το καθένα θα πρέπει να έχει την δική του µοναδική τιµή id. Το µέλος platform_data αρχικοποιείται µε τη διεύθυνση της
δοµής gpio_led_platfrom_data.
Πριν καταχωρήσουµε την συσκευή µας στο αντίστοιχο σύστηµα του Linux καλώντας τη συνάρτηση platform_device_register, πρέπει να σωστά τις γραµµές εισόδου – εξόδου.
Στον σύστηµα της εργασίας µας, αυτό γίνεται στο αρχείο setup.c το οποίο ανήκει στον εξειδικευµένο κώδικα (board specific code) του Router NGW100 και βρίσκεται στον κατάλογο
arch/avr32/boards/atngw100 του πηγαίου κώδικα του Linux.
Χρήση του LED Framework στο user-space
Μέχρι τώρα είδαµε πως µπορούµε µέσω του LED Framework να δηµιουργήσουµε τις συσκευές µας και ποιον εξειδικευµένο κώδικα θα πρέπει να παρέχουµε στο Linux έτσι ώστε να
µπορεί να κατανοεί την πλακέτα µας. Στη συνέχεια θα εξετάσουµε τον τρόπο επικοινωνίας µε
αυτές. Γενικά υπάρχουν κι εδώ δύο τρόποι να επικοινωνήσουµε. Είτε µέσω κάποιου driver
από τον Kernel, είτε µέσω κάποιας εφαρµογής από το user-space.
Στον Router NGW100 υπάρχουν τρία LED: a, b και sys (system). Βρίσκονται σε οµώνυµους υποκαταλόγους του κατάλογου /sys/class/leds. Τα a και b είναι βοηθητικά ενώ το
sys είναι δεσµευµένο για να υποδεικνύει το πότε έχει ολοκληρωθεί µε επιτυχία η διαδικασία
εκκίνησης.
Μέσα σε καθέναν από τους υποκαταλόγους a, b και sys που προαναφέραµε, υπάρχουν
δύο αρχεία τα οποία µπορούν επίσης να χρησιµοποιηθούν για τον έλεγχο των LED:
brightness – Μπορούµε να αποθηκεύουµε µη µηδενικές τιµές στο εύρος 0 – 255
για να ρυθµίζουµε τη φωτεινότητα. Επειδή όµως τα περισσότερα LED δεν παρέχουν
αυτό το χαρακτηριστικό, ουσιαστικά δίνοντας την τιµή 0 σβήνουµε το LED και µε οποιαδήποτε άλλη τιµή στο εύρος 1 – 255 ενεργοποιούµε το LED.
trigger – Πρόκειται για µια λειτουργία η οποία ενεργοποιεί και απενεργοποιεί ένα
LED µε συγκεκριµένο ρυθµό. Αυτό βοηθά στο να αναπαριστούµε µε εύκολο τρόπο
στον χρήστη τη συσκευής µας το τι συµβαίνει σε µια δεδοµένη στιγµή σε κάποιο υποσύστηµα που έχει νόηµα γι’ αυτόν. Για παράδειγµα αν θέλουµε να δείξουµε ότι ο
Router NGW100 έχει συνδεθεί επιτυχώς στο τοπικό δίκτυο θα µπορούσαµε να αναβοσβήνουµε ένα από τα βοηθητικά του LED µε ρυθµό καρδιακού παλµού:
echo heartbeat > /sys/class/leds/a/trigger
Επικοινωνία: [email protected]
114
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Σε αυτό το σηµείο µπορούµε να πούµε ότι έχουµε αναφέρει τα σηµαντικότερα στοιχεία που
αφορούν τα σήµατα GPIO. Η ανάλυση έπρεπε να είναι εκτενής µιας και τα σήµατα GPIO είναι πολύ σηµαντικά και ευέλικτα στο Linux σχεδόν για οποιαδήποτε συσκευή. Το Linux LED
Framework αναλύεται περισσότερο και στον υποκατάλογο leds που υπάρχει στον κατάλογο
documentation του Kernel.
3.6 Modem
Τα modem στο Linux αντιµετωπίζονται σαν σειριακές συσκευές (οπότε ότι είπαµε πριν για
τη σειριακή επικοινωνία ισχύει κι εδώ), κάτι που συµβαίνει και σε άλλα λειτουργικά συστήµατα. Κάθε σειριακή συσκευή έχει τη δική της καταχώρηση στον κατάλογο /dev και ελέγχεται
από τον ίδιο driver που υπάρχει και για το κύκλωµα UART.
Πολλές νεότερες συσκευές modem αποτελούνται από απλούστερα και πιο φθηνά κυκλώµατα. Τα modem αυτά είναι γνωστά ως Linmodems και περιέχουν µόνο το ελάχιστο υλικό που
απαιτείται από µια συσκευή modem. Μπορούν να παρέχουν τις υπηρεσίες τους καθαρά λόγω της ύπαρξης του λειτουργικού συστήµατος, δηλαδή µέσω λογισµικού και όχι µέσω του
υλικού που απαιτείται για να λειτουργήσει αυτόνοµα ένα modem.
Για να παρέχεται υποστήριξη και γι’ αυτές τις συσκευές, η κοινότητα του Linux έχει αρχίσει
να δηµιουργεί διάφορα projects ανάπτυξης των αναγκαίων πακέτων λογισµικού. Η κεντρική
αρχή που ελέγχει και διαχειρίζεται αυτά τα project µπορεί να βρεθεί στον ιστότοπο
linmodems.org. Επίσης, µια καλή θεωρητική ανάλυση για τα modems στο Linux, καθώς
και για την παραµετροποίησή τους, γίνεται στον ιστότοπο του LDP (tldp.org).
3.7 Επικοινωνία µε τη µνήµη
Σε ένα ενσωµατωµένο σύστηµα Linux αλλά και σε οποιοδήποτε άλλο υπολογιστικό σύστηµα το οποίο επεξεργάζεται δεδοµένα, υπάρχουν δύο βασικά τµήµατα που παίζουν τον σηµαντικότερο ρόλο από το οτιδήποτε άλλο. Ο µικροελεγκτής και η µνήµη. Σε αυτή την
παράγραφο θα µας απασχολήσει η µνήµη.
Αρχικά είναι χρήσιµο να εξηγήσουµε τι είναι ένα block. Πρόκειται για µια περιοχή µνήµης µε
προκαθορισµένο (fixed) και σταθερό µέγεθος που διευθετείται από τον Kernel. Συνήθως το
µέγεθός του είναι 4096 bytes αλλά η τιµή αυτή εξαρτάται κυρίως από την αρχιτεκτονική και το
σύστηµα αρχείων που χρησιµοποιείται κάθε φορά.
Σε προηγούµενη παράγραφο, όταν ασχοληθήκαµε µε τους drivers, τους κατηγοριοποιήσαµε
σε τρία είδη. Ένα από αυτά ήταν και οι block drivers. Ένας block driver δηµιουργείται για να
παρέχει πρόσβαση σε συσκευές που µεταφέρουν δεδοµένα τα οποία µπορεί να βρίσκονται
αποθηκευµένα σε τυχαίες θέσεις. Αυτό συµβαίνει συχνά, µιας και όταν ένα αρχείο δεν µπορεί
να χωρέσει σε µια συνεχή ελεύθερη περιοχή της µνήµης, το λειτουργικό σύστηµα το διασπά
σε µικρότερα τµήµατα τα οποία στη συνέχεια µπορούν να αποθηκεύονται και σε µη γειτονικές περιοχές.
Οι block drivers είναι το λογισµικό µέσο επικοινωνίας µεταξύ της κύριας και της δευτερεύουσας µνήµης. Για το λόγο αυτό µπορούν να θεωρηθούν και µέρος του υποσυστήµατος της
εικονική µνήµης.
Στον Router NGW100, όπως θα δούµε και στο πρακτικό µέρος της εργασίας, υπάρχουν
διάφορα είδη µνήµης:
Ιστότοπος εργασίας: MyThesis.org
115
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
SDRAM
Parallel flash
Serial DataFlash
SD/MMC
Η µνήµη που αφορά το user space στο οποίο υπάρχουν όλες οι εφαρµογές και τα δεδοµένα
του Router NGW100, είναι η DataFlash. Σε αυτή την παράγραφο θα εξετάσουµε τη διαδικασία της ρύθµισης που πρέπει να γίνει στον Linux Kernel, την εγκατάσταση ενός καναλιού επικοινωνίας SPI, την φόρτωση τα απαραίτητων modules, τη δηµιουργία συστήµατος αρχείων
και την φόρτωση της DataFlash στο σύστηµα αρχείων του Linux.
Όπως γνωρίζουµε, το SPI υποστηρίζει σειριακή επικοινωνία µε εξωτερικές συσκευές (δηλαδή άλλα ολοκληρωµένα που συνδέονται στον µικροελεγκτή) και µνήµες, όπως είναι στην
περίπτωσή µας και η DataFlash. Το SPI αποτελείται από δύο γραµµές δεδοµένων και δύο
γραµµές ελέγχου:
MOSI (Master Out Slave In)
MISO (Master In Slave Out)
SPCK (Serial Clock)
NSS (Slave Select)
Η DataFlash µπορεί να συνδεθεί στο SPI του µικροελεγκτή όπως φαίνεται στην εικόνα που
ακολουθεί:
Εικόνα 33. Σύνδεση DataFlash µε µικροελεγκτή µέσω SPI
3.7.1 ∆ηµιουργία του συστήµατος αρχείων root
Η δηµιουργία του root filesystem απαιτεί να υπάρχει εγκατεστηµένο στο σύστηµα host το
πρόγραµµα mtd-tools και το δυαδικό αρχείο mkfs.jffs2. Όπως γνωρίζουµε όµως, αυτό
το αναλαµβάνει το αυτοµατοποιηµένο σύστηµα Buildroot.
Παράµετροι µνήµης flash
Όλες οι συσκευές flash έχουν καθορισµένο µέγεθος διαγραφής (delete size) και καθορισµένο µέγεθος σελίδας (page size). Οι τιµές των συγκεκριµένων µεγεθών θα πρέπει να είναι
γνωστές καθώς το σύστηµα αρχείων θα δηµιουργηθεί σε blocks που θα εξαρτώνται από αυτές.
Επικοινωνία: [email protected]
116
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Πριν µπορέσει ένα block της µνήµης flash να προγραµµατιστεί, θα πρέπει πρώτα να σβηστεί. Το µέγεθος της διαγραφής δίνεται από το µέγεθος του block διαγραφής (erase block) το
οποίο αντιπροσωπεύει τη µικρότερη δυνατή µονάδα διαγραφής. Η µικρότερη µονάδα εγγραφής είναι η σελίδα (page) και καθορίζεται από το µέγεθος σελίδας που αναφέραµε και πιο
πάνω.
Το σύστηµα αρχείων JFFS2
Σε αυτό το σηµείο µας δίνεται η δυνατότητα να πούµε λίγα πράγµατα για το σύστηµα αρχείων JFFS2 (Journaled Flash File System version2). Το JFFS2 έχει δηµιουργηθεί ειδικά για
µνήµες flash σαν αυτές που χρησιµοποιούνται συνήθως στα ενσωµατωµένα συστήµατα. Το
πλεονέκτηµά του είναι ότι χρησιµοποιείται ταυτόχρονα και σαν RAM. Οι κυριότεροι λόγοι για
τους οποίους επιλέγουµε το JFFS για τα ενσωµατωµένα συστήµατα είναι:
Είναι βελτιστοποιηµένο για µνήµες flash
Μπορεί να φορτωθεί µέσω του U-Boot bootloader
Επιτρέπει συµπίεση
∆εν χρειάζεται να φορτωθεί πρώτα σε κάποια RAM για να χρησιµοποιηθεί
Φυσικά το JFFS2 έχει και περιορισµούς. Ο κυριότερος και κοινός για όλα τα παρεµφερή
συστήµατα αρχείων, αφορά τη φύση των µνηµών flash. Όπως γνωρίζουµε ήδη, οι µνήµες
αυτές είναι οργανωµένες σε blocks. Κάθε block έχει περιορισµένο αριθµό κύκλων εγγραφής /
σβησίµατος. Εποµένως θα πρέπει σε περιπτώσεις που απαιτούνται τέτοιου είδους ενέργειες
πολύ συχνά, να χρησιµοποιούµε και µια βοηθητική µνήµη.
Το εργαλείο mkfs.jffs2
Το εργαλείο mkfs.jffs2 περιλαµβάνεται στο πακέτο λογισµικού mtd-utils. Χρησιµοποιείται για την δηµιουργία της εικόνας του κεντρικού συστήµατος αρχείων (rootfs.img),
αλλά και για την εγγραφή του στην παράλληλη µνήµη (parallel flash) του Router NGW100.
Για να λειτουργήσει σωστά θα πρέπει να του παρέχουµε τις εξής πληροφορίες:
Όνοµα και διαδροµή καταλόγου για να αποθηκεύσει την εικόνα rootfs.img.
∆ιαδροµή προς τον κατάλογο root (/).
Τύπος endian (little ή big). Η αρχιτεκτονική AVR32 χρησιµοποιεί big endian.
Μέγεθος της σελίδας (pagesize) της µνήµης flash
Μέγεθος block διαγραφής (eraseblock)
∆ιαµόρφωση και εγκατάσταση
Ο Linux Kernel διαθέτει πολλούς drivers οι οποίοι µπορούν να φορτωθούν κατά την εκκίνηση ή να µεταγλωττιστούν σαν modules και να φορτωθούν κατά τη διάρκεια λειτουργίας του
συστήµατος. Το τι απ’ όλα αυτά θα επιλέξουµε, εξαρτάται µόνο από τις ανάγκες µας.
Για να ενεργοποιήσουµε στον Kernel την υποστήριξη για συσκευές MTD θα πρέπει να εισέλθουµε στο γραφικό περιβάλλον παραµετροποίησής του και από την ενότητα Device
Drivers. Αφού ρυθµίσουµε την ενότητα SPI Support (έχουµε ήδη αναφερθεί σε αυτό όταν αναλύσαµε το SPI), στη συνέχεια περνάµε στην ρύθµιση της Memory Technology
Devices (MTD):
Ιστότοπος εργασίας: MyThesis.org
117
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 34. Ενεργοποίηση υποστήριξης συσκευών MTD από τον Linux Kernel
Αµέσως µετά επιλέγουµε και ρυθµίζουµε την ενότητα RAM/ROM/Flash chip drivers:
Επικοινωνία: [email protected]
118
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
Εικόνα 35. Ενεργοποίηση CFI driver για την ανάγνωση µνηµών Flash
Και αφού επιστρέψουµε στο µενού Device Drivers, επιλέγουµε την Self-contained MTD
device drivers:
Εικόνα 36. Ενεργοποίηση υποστήριξης µνηµών AT45xxx της Atmel από τον Linux Kernel
Ιστότοπος εργασίας: MyThesis.org
119
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Τέλος, από το αρχικό παράθυρο διαλόγου παραµετροποίησης του Linux Kernel, επιλέγουµε
και ρυθµίζουµε την ενότητα File Systems
Miscellaneous File Systems
Journaling Flash File System v2 (JFFS2) Support, για να ενεργοποιήσουµε και
να ρυθµίσουµε την υποστήριξη του συστήµατος αρχείων JFFS2:
Εικόνα 37. Ενεργοποίηση υποστήριξης συστήµατος αρχείων JFFS2 από τον Linux Kernel
SPI modules
Για να επικοινωνήσουµε µε τη DataFlash του Router NGW100 χρειάζεται αρχικά να εγκατασταθεί ο SPI controller, να επιλεγεί η συσκευή slave (δηλαδή η DataFlash), να ρυθµιστεί η
συχνότητα λειτουργίας του ρολογιού και να επιλεγεί ο driver στον οποίο θα στέλνονται τα δεδοµένα.
Όπως ήδη έχουµε αναφέρει νωρίτερα κατά την ανάλυση του SPI, ο κώδικας ο οποίος είναι
υπεύθυνος και πρέπει να διαµορφωθεί κατάλληλά βρίσκεται στο αρχείο setup.c στον κατάλογο arch/avr32/boards/avr32/atngw100. Για να ρυθµίσουµε τα χαρακτηριστικά του
SPI αρκεί να τροποποιήσουµε τις µεταβλητές της παρακάτω δοµής δεδοµένων:
Επικοινωνία: [email protected]
120
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux – Κεφάλαιο 3
static struct spi_board_info spi0_board_info[] __initdata = {
{
.modalias
= "mtd_dataflash",
.max_speed_hz
= 8000000,
.chip_select
= 0,
},
};
Μεταγλώττιση και πρόσβαση
Αφού έχουµε ολοκληρώσει όλες τις απαραίτητες τροποποιήσεις και προσθήκες στο σύστηµά µας θα πρέπει να µεταγλωττίσουµε τον Kernel έτσι ώστε να περιλαµβάνει τα νέα χαρακτηριστικά. Για να το κάνουµε αυτό, µέσα από τον κατάλογο του Buildroot εκτελούµε την
παρακάτω εντολή:
make ARCH=avr32-linux CROSS_COMPILE=avr32-linux-
Αν ολοκληρωθεί µε επιτυχία, στον κατάλογο arch/avr32/boot/images θα έχουµε το
νέο δυαδικό αρχείο uImage, το οποίο θα παρέχει υποστήριξη για την µνήµη DataFlash του
Router NGW100.
Προκειµένου να έχουµε πρόσβαση στη DataFlash και να επικοινωνούµε µε αυτή είναι απαραίτητο να δηµιουργηθούν ορισµένα αρχεία (ή αλλιώς, κόµβοι – nodes) που απαιτεί η τεχνολογία MTD και να υπάρχουν στον κατάλογο που θα αντιπροσωπεύει τη συσκευή. Αυτό
γίνεται από το πρόγραµµα mdev κατά την εκκίνηση.
Τέλος, για να είµαστε σε θέση να δηµιουργούµε, να διαβάζουµε και να διαγράφουµε αρχεία
στην DataFlash, χρειάζεται πρώτα να φορτωθούν ένα ή περισσότερα διαµερίσµατα της. Στον
Router NGW100 η συνολική µνήµη flash (Parallel flash + DataFlash) χωρίζεται σε τρία διαµερίσµατα (partitions) τα οποία περιλαµβάνουν συνήθως τα τρία κύρια µέρη ενός οποιουδήποτε ενσωµατωµένου συστήµατος Linux:
Bootloader
Root filesystem
/usr
Η διαµέριση επιτυγχάνεται στο αρχείο flash.c που υπάρχει αποθηκευµένο στον κατάλογο
arch/avr32/boards/avr32/atngw100 και πιο συγκεκριµένα στην δοµή δεδοµένων.
mtd_partition flash_parts[]. Η εντολή µε την οποία µπορεί να φορτωθεί το διαµέρισµα της DataFlash το οποίο χρειάζεται ένα χρήστης για να διαχειρίζεται τα δεδοµένα του είναι η εξής:
mount -t jffs2 /dev/mtdblock0 /mnt-directory
Μετά και από αυτό το βήµα, µπορούµε πια πολύ απλά να εκτελέσουµε για παράδειγµα την
παρακάτω εντολή δηµιουργίας αρχείου κειµένου:
touch rousis.txt
3.8 Υλικό δικτύωσης
Ολόκληρη η εργασία είναι ένα σύνολο βηµάτων που οδηγούν στην ανάπτυξη ενός ενσωµατωµένου συστήµατος Linux το οποίο είναι αφοσιωµένο στην δροµολόγηση πακέτων αλλά και
τη δικτύωση και ∆ιαδικτύωση υπολογιστικών συστηµάτων. Εποµένως είναι πολύ δύδκολο
Ιστότοπος εργασίας: MyThesis.org
121
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
µέσα σε µία παράγραφο να περιγραφεί το οτιδήποτε αφορά την δικτύωσή του. Γι’ αυτό θα
αφιερωθεί ένα ολόκληρο ξεχωριστό κεφάλαιο καθώς και ένα ειδικό παράρτηµα που θα αφορούν όλα όσα χρειάζεται ο Router NGW100 για να επικοινωνήσει µε τοπικά αλλά και µε αποµακρυσµένα δίκτυα.
Επικοινωνία: [email protected]
122
ΚΕΦΑΛΑΙΟ
4
∆ικτύωση και ∆ροµολόγηση στα
ενσωµατωµένα συστήµατα Linux
Εισαγωγή
Οι βασικές λειτουργίες ενός Router είναι να επικοινωνεί µε δίκτυα και να δροµολογεί πακέτα
δεδοµένων, όσο το δυνατόν πιο γρήγορα και πιο αξιόπιστα. Αυτή είναι µια αρκετά πολύπλοκη διαδικασία η οποία απαιτεί τη συνεργασία πολλών υποσυστηµάτων. Η πολυπλοκότητα
αφορά τόσο το λογισµικό της συσκευής όσο και το υλικό, και δεν περιορίζεται µόνο σε ότι
αφορά το πρωτόκολλο TCP/IP.
Σε αυτό το κεφάλαιο θα γίνει µια πολύ συνοπτική περιγραφή των στοιχείων που αφορούν
τη δικτύωση και τη δροµολόγηση πακέτων δεδοµένων στα ενσωµατωµένα συστήµατα Linux.
Ο Router NGW100 που είναι και το αντικείµενο της παρούσας εργασίας, είναι ένα ενσωµατωµένο σύστηµα Linux, αφοσιωµένο στη δροµολόγηση πακέτων και πάνω στη λειτουργία
του θα βασιστεί ολόκληρο το κεφάλαιο.
Πιο συγκεκριµένα, τα θέµατα που θα µας απασχολήσουν είναι:
Το TCP/IP στα ενσωµατωµένα συστήµατα Linux
Linux Sockets
∆ροµολόγηση πακέτων
Τα πρωτόκολλα ARP, ICMP και IGMP
Οδηγοί δικτύου
Απόδοση δικτύωσης του µικροελεγκτή AP7000
4.1 Το TCP/IP στα ενσωµατωµένα συστήµατα Linux
Πριν χρησιµοποιηθεί ευρέως το TCP/IP (Transmission Control Protocol / Internet Protocol)
στα ενσωµατωµένα συστήµατα, οι εφαρµογές που γραφόταν γι’ αυτά ήταν συνήθως αυτόνοµες και δεν εκτελούνταν επάνω από κάποιο λειτουργικό σύστηµα. Ακόµα και αν υπήρχε κάποιο ελάχιστο λειτουργικό σύστηµα, δε διέθετε καµία προγραµµατιστική διεπαφή. Το γεγονός
αυτό, καθιστούσε αρκετά δύσκολη την ενσωµάτωση κάποιου πρωτοκόλλου επικοινωνίας.
Κατά καιρούς υπήρξαν αρκετές αξιόλογες προσπάθειες ανάπτυξης στοιβών για ενσωµατωµένα συστήµατα των 8 αλλά και των 32 bit (πχ: uIP και lwIP). Οι στοίβες αυτές συνήθως κα-
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
λούνται µέσα από την main() κάποιας αυτόνοµης εφαρµογής η οποία αποτελεί και την µοναδική εφαρµογή του ενσωµατωµένου συστήµατος. Η σχεδίασή τους βασίζεται στο ότι, σπάνια σε ένα ενσωµατωµένο σύστηµα απαιτούνται όλες οι λειτουργίες και τα πρωτόκολλα του
TCP/IP. Εποµένως αν αφαιρεθούν περιττά χαρακτηριστικά µπορεί να προκύψει µια πιο ανάλαφρη (lightweight) στοίβα η οποία θα έχει σηµαντικά λιγότερες απαιτήσεις µνήµης και επεξεργαστικής ισχύος. Οι αυτόνοµες στοίβες δεν θα µας απασχολήσουν περισσότερο σε αυτή
την εργασία. Αναφέρθηκαν απλά για να γίνει κατανοητό ότι το TCP/IP µπορεί να εκτελείται
και χωρίς την παρουσία κάποιου λειτουργικού συστήµατος. Στη συνέχεια θα εξετάσουµε το
TCP/IP σε σχέση µε τα ενσωµατωµένα λειτουργικά συστήµατα και ειδικότερα σε σχέση µε το
ενσωµατωµένο Linux.
4.1.1 Το TCP/IP και το µοντέλο αναφοράς OSI
Είναι αρκετά σηµαντικό να διαχωρίσουµε την θεωρητική έννοια ενός πρωτόκολλου επικοινωνίας από την έννοια της εφαρµογής του πρωτοκόλλου αυτού στο υλικό και το λογισµικό
ενός υπαρκτού υπολογιστικού συστήµατος.
Θεωρητικά, το πρωτόκολλο επικοινωνίας είναι µια προδιαγραφή για µια καθορισµένη αλληλουχία ανταλλαγής δεδοµένων µεταξύ δύο ή περισσοτέρων υπολογιστικών συστηµάτων.
∆ηλαδή ένα θεωρητικό µοντέλο που περιγράφει κάποιες λειτουργίες και κάποια βήµατα. Ένα
τέτοιο µοντέλο είναι και το µοντέλο αναφοράς Ανοικτής ∆ιασύνδεσης Συστηµάτων OSI
(el.wikipedia.org/wiki/Μοντέλο_αναφοράς_OSI). Από την άλλη, η πρακτική εφαρµογή ενός πρωτοκόλλου καθορίζει το πώς το λογισµικό ή το υλικό εκτελεί τις λειτουργίες και
τα βήµατα µέσα σε κάποιο σύστηµα. Ένα τέτοιο πρωτόκολλο είναι και το TCP/IP.
Το πρωτόκολλο TCP/IP, όπως και το OSI, χωρίζεται σε λογικά επίπεδα έτσι ώστε να διευκολύνεται η ανάπτυξη του κώδικα του πρωτοκόλλου. Τα επίπεδα αυτά, αρχίζοντας από το
ανώτερο και καταλήγοντας στο πιο χαµηλό, είναι τα παρακάτω:
Εφαρµογής (Application Layer)
Μεταφοράς (Transfer Layer)
∆ικτύου (Network ή Internet Layer)
Φυσικό (Physical Layer)
4.1.2 Οι Απαιτήσεις του TCP/IP από το ενσωµατωµένο Linux
Όπως γνωρίζουµε, τα περισσότερα πρωτόκολλα επικοινωνίας λειτουργούν ασύγχρονα. Το
ίδιο ισχύει και για το TCP/IP. Η υλοποίηση του πρωτοκόλλου είναι γραµµική (linear) αλλά
προσανατολισµένη σε συµβάντα (event oriented). Έτσι, η επεξεργασία ενός πακέτου αρχίζει
µόνο τη στιγµή κατά την οποία αυτό παραλαµβάνεται. Κάθε πακέτο ταξιδεύει µεταξύ των επιπέδων µέσα στη στοίβα ως ένα ξεχωριστό και ανεξάρτητο, νήµα (thread) επεξεργασίας.
Επιπροσθέτως, υπάρχουν παράλληλες δραστηριότητες οι οποίες θα πρέπει ταυτόχρονα µε
την λειτουργία τους να παρακολουθούν και κάποια χρονικά όρια (timeouts) που προβλέπονται από τις απαιτήσεις του πρωτοκόλλου.
Βασιζόµενοι σε όλες τις παραπάνω πληροφορίες, µπορούµε να παραθέσουµε µια λίστα µε
τις ιδιότητες που θα πρέπει να έχει ένα ενσωµατωµένο λειτουργικό σύστηµα έτσι ώστε να
είναι σε θέση να φιλοξενήσει µε επιτυχία την στοίβα TCP/IP:
∆υνατότητες χρονισµού (Timers): Σχεδόν σε όλα τα πρωτόκολλα επικοινωνίας απαιτούνται χρονιστές για τυχόν αναµεταδόσεις προβληµατικών πακέτων καθώς και για
έλεγχο των χρονικών ορίων σύνδεσης. Σε πιο απλά λειτουργικά συστήµατα που χρη-
Επικοινωνία: [email protected]
124
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
σιµοποιούνται στα ενσωµατωµένα συστήµατα, αυτή η δυνατότητα είτε δεν υπάρχει,
είτε δεν παρέχει κάποια σταθερή και εύχρηστη προγραµµατιστική διεπαφή (API).
Ταυτοχρονισµό και πολυδιεργασία (Concurrency & Multitasking): Η προγραµµατιστική διεπαφή socket καθώς και άλλες παρόµοιες διεπαφές, θα πρέπει να επιτρέπουν
την ύπαρξη πολλαπλών, ταυτόχρονα συνδεδεµένων χρηστών. Επίσης η στοίβα
TCP/IP θα πρέπει να είναι πολυνηµατική (multithread). Φυσικά ο ταυτοχρονισµός
απαιτεί κλείδωµα κάποιων πόρων και κάποιων σηµαντικών τµηµάτων του κώδικα έτσι ώστε να µην προσπαθούν δύο χρήστες ταυτόχρονα να τροποποιήσουν τα ίδια
δεδοµένα ή δεδοµένα στα οποία δε θα έπρεπε να έχουν πρόσβαση. Η αντιµετώπιση
αυτών των ζητηµάτων επιτυγχάνεται συνήθως, µέσω κατάλληλου κλειδώµατος σηµατοφόρων σε επίπεδο καταχωρητή.
∆ιαχείριση καταχωρητών (Buffer Management): Το πρωτόκολλο TCP/IP όπως και τα
περισσότερα πρωτόκολλα είναι πιο αποτελεσµατικά όταν παρέχουν σύστηµα καταχωρητών σταθερού µήκους (fixed-length buffer system). Οι καταχωρητές εκχωρούνται δυναµικά όταν κάποιο νέο πακέτο παραληφθεί ή όταν δηµιουργείται ένα νέο
εξερχόµενο πακέτο στο επίπεδο των sockets. Πρέπει να πούµε ότι οι καταχωρητές
δικτύωσης του Linux ονοµάζονται και socket buffers. Οι socket buffers εκχωρούνται
από µια µικρή περιοχή µνήµης, την slab cache η οποία επιλύει και θέµατα κατακερµατισµού (fragmentation) µεγάλων PDU (Protocol Data Unit) που ξεπερνούν το µέγιστο όριο µετάδοσης (MTU – Maximum Transmission Unit). Ένα άλλο πλεονέκτηµα
της µνήµης αυτής είναι και η επεκτασιµότητά της καθώς δεν έχει κάποιο προκαθορισµένο ανώτατο όριο µεγέθους, αλλά µπορεί να µεγαλώνει δυναµικά ανάλογα µε τις
τρέχουσες απαιτήσεις.
∆υνατότητα συνένωσης επιπέδων (Layer Linking): Σε περίπλοκες υλοποιήσεις πρωτοκόλλων, όπως είναι και αυτή του TCP/IP, απαιτείται ένας µηχανισµός προσθήκης
επιπέδων (κάποιες φορές και ολόκληρων πρωτοκόλλων) κάτω από το επίπεδο IP και
επάνω από την προγραµµατιστική διεπαφή του οδηγού δικτύου. Καλό είναι επίσης να
υπάρχει και κάποιος µηχανισµός προσθήκης πρωτοκόλλων ο οποίος θα λειτουργεί
έτσι ώστε να µην απαιτείται καµία τροποποίηση του IP κώδικα. Τέτοια πρωτόκολλα
µπορεί να είναι για παράδειγµα το πρωτόκολλο NAT (Network Address Translation),
το PPP (Point-to-Point Protocol), η γεφύρωση µέσω λογισµικού (software based
bridging και η δυνατότητα µεταγωγής (switching).
Χαµηλή καθυστέρηση (Low Latency): Το λειτουργικό σύστηµα δεν θα πρέπει να προσθέτει καµία επιπλέον καθυστέρηση από εκείνη που είναι ήδη απαραίτητη για την ελάχιστη επεξεργασία η οποία απαιτείται κατά τη διάρκεια µιας διακοπής (interrupt
time) για την αποστολή ή την λήψη ενός πλαισίου στο φυσικό επίπεδο. Ο στόχος του
λειτουργικού συστήµατος θα πρέπει να είναι η ελαχιστοποίηση των context switches
(wikipedia.org/wiki/Context_switch) κατά τη διάρκεια επεξεργασίας ενός
πακέτου από την στοίβα TCP/IP. Το Linux χρησιµοποιεί τα softirqs κατά το µεγαλύτερο µέρος της εσωτερικής του επεξεργασίας. Επίσης παρέχονται fast paths
(wikipedia.org/wiki/Fast_path) για την αποστολή και λήψη πακέτων µε σκοπό την περεταίρω µείωση της καθυστέρησης.
Ελάχιστη αντιγραφή δεδοµένων (Minimal Data Copying): Στα ενσωµατωµένα συστήµατα είναι αρκετά επιθυµητό να µειώνεται στο ελάχιστο το µέγεθος της αντιγραφής
δεδοµένων κατά τη διάρκεια µεταφοράς ενός πακέτου από το επίπεδο εφαρµογής
στο φυσικό επίπεδο της στοίβας. Τα ενσωµατωµένα συστήµατα και οι εφαρµογές
τους, θα πρέπει να αναπτύσσονται µε γνώµονα την µέγιστη απόδοση και γι’ αυτό θα
πρέπει η υλοποίηση της στοίβας δικτύωσής τους να µην επιτρέπει αντιγραφές καταχωρητών στο επίπεδο των drivers, παρέχοντας ταυτόχρονα την επιλογή εξάλειψης
αντιγραφών στo επίπεδο των sockets.
Ιστότοπος εργασίας: MyThesis.org
125
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Όλα τα παραπάνω ικανοποιούνται απόλυτα από το Linux. Το Linux υποστηρίζει επίσης και
ορισµένα επιπλέον χαρακτηριστικά τα οποία αν και δεν απαιτούνται από το TCP/IP, βελτιώνουν σηµαντικά την απόδοση της επικοινωνίας. Ένα τέτοιο παράδειγµα είναι και η µείωση
των προβληµάτων καθυστέρησης µέσω του µηχανισµού δηµιουργίας νηµάτων softirq
που υπάρχει υλοποιηµένος στον kernel. Το Linux έχει την δυνατότητα αναβολής διακοπών
που προκύπτουν από ορισµένες διεργασίες µε σκοπό την µείωση των καθυστερήσεων. Τα
νήµατα softirq ουσιαστικά είναι ένας µηχανισµός διακοπών λογισµικού (software interrupts) που χρησιµοποιείται από τους οδηγούς συσκευών προκειµένου να είναι σε θέση να
επεξεργαστούν κάτι που βρίσκεται εκτός του χειριστή διακοπής υλικού (hardware interrupt
handler) όσο το δυνατόν ταχύτερα, ούτως ώστε να µπορούν να επανενεργοποιούνται και
πάλι οι διακοπές. Με λίγα λόγια, είναι ένας µηχανισµός παύσης και επανέναρξης διακοπών.
4.1.3 Η στοίβα TCP/IP στο Linux
Ο πηγαίος κώδικας της στοίβας TCP/IP που υπάρχει ενσωµατωµένη στον Linux Kernel,
βρίσκεται στον κατάλογο net. ∆εν θα είχε κάποιο νόηµα στα πλαίσια αυτής της εργασίας να
αναλύσουµε γραµµή προς γραµµή τον κώδικα αυτό καθώς υπάρχει πολύ καλή διαθέσιµη
βιβλιογραφία για το σκοπό αυτό. Ούτως ή άλλως, οι εφαρµογές του Router NGW100 κάνουν
χρήση του socket API όταν χρειάζεται να στείλουν ή να λάβουν δεδοµένα στο δίκτυο µέσω
της στοίβας TCP/IP. Παρ’ όλα αυτά θα παρατεθούν κάποιες γενικές πληροφορίες που είναι
καλό να γνωρίζουµε.
Η επόµενη εικόνα παρουσιάζει σχηµατικά και µε µεγάλο επίπεδο αφαίρεσης, τη διαστρωµάτωση της στοίβας TCP/IP στο Linux:
Εφαρµογής
Μεταφοράς
∆ικτύου
Φυσικό
(PHY)
Εικόνα 38. Η ενσωµατωµένη στοίβα TCP/IP του Linux Kernel
Επικοινωνία: [email protected]
126
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
Ουσιαστικά το πρωτόκολλο TCP/IP στο Linux, αποτελείται από τρία επίπεδα. Το Μεταφοράς το ∆ικτύου και το Φυσικό. Επάνω από το επίπεδο µεταφοράς δεν υπάρχει κανένα πρωτόκολλο δικτύωσης. Υπάρχει µόνο το επίπεδο της προγραµµατιστικής διεπαφής των sockets
για τα οποία θα εξετάσουµε αναλυτικά.
Κάθε επίπεδο λειτουργεί ανεξάρτητα από τα υπόλοιπα. Αυτό επιτυγχάνεται µέσω του µηχανισµού ενθυλάκωσης (encapsulation) αλλά και µε τη βοήθεια της προαπαιτούµενης υποδοµής που συσχετίζεται µε την στοίβα TCP/IP η οποία περιλαµβάνει συναρτήσεις και
µακροεντολές για την εξαγωγή και την προσθήκη επικεφαλίδων (headers), αλλά και για τον
συνδυασµό και τη συνένωση πακέτων. Επιπρόσθετα, ο Linux Kernel παρέχει κάποια επιπλέον υποδοµή προκειµένου η στοίβα TCP/IP να µπορεί να λειτουργήσει. Η υποδοµή αυτή
αφορά τα εξής:
Χρονιστές (timers)
Νηµάτωση (threading)
∆ιεργασίες (tasks)
Καταχώρηση πρωτοκόλλων (protocol registration)
Προγραµµατιστική διεπαφή για οδηγούς δικτύου (network driver interface)
Σύστηµα προσωρινής καταχώρησης δεδοµένων (buffering scheme)
Αρχικοποίηση της στοίβας TCP/IP στον Router NGW100
Η αρχικοποίηση (initialization) της στοίβας TCP/IP στο Linux, είναι µια αρκετά πολύπλοκη
διαδικασία η οποία περιλαµβάνει τα εξής:
Αρχικοποίηση του επιπέδου των sockets
Καταχώρηση πρωτοκόλλων
∆ηµιουργία εγγραφών στο σύστηµα αρχείων /proc
Λόγω της φύσης της στοίβας TCP/IP του Linux, είναι δύσκολο να διαχωρίσουµε την βασική
αρχικοποίησή της από την αρχικοποίηση του επιπέδου των sockets. Γενικά όµως η δεύτερη
προηγείται καθώς το επίπεδο socket θα πρέπει να βρίσκεται στη θέση του όταν η AF_INET
καταχωρηθεί σε αυτό, προκειµένου να µπορούν να λαµβάνονται και να αποστέλλονται πακέτα IP.
Η καταχώρηση των πρωτοκόλλων χωρίζεται σε τρία µέρη. Το πρώτο αφορά την καταχώρηση των πρωτοκόλλων του επιπέδου δικτύου που είναι γνωστά και ως χειριστές πακέτων
(packet handlers ή taps). Αυτό δίνει την δυνατότητα να λαµβάνονται αλλά και να αποστέλλονται πακέτα από και προς τους οδηγούς συσκευών δικτύου αντίστοιχα. ∆ηλαδή αυτό είναι
το σηµείο όπου το υλικό δικτύωσης (drivers - PHY) συναντά το λογισµικό δικτύωσης
(TCP/IP). Η καταχώρηση αλλά και κατάργηση (de-registration) των ορισµάτων των χειριστών
πακέτων δηλώνονται στο αρχείο netdevice.h που βρίσκεται στον πηγαίο κώδικα του Kernel, στον κατάλογο include/linux/. Επίσης οι αντίστοιχες συναρτήσεις καθορίζονται στο
αρχείο dev.c που βρίσκεται στον κατάλογο net/core/. Το δεύτερο, αφορά την καταχώρηση των πρωτοκόλλων του επιπέδου µεταφοράς µαζί µε το επίπεδο δικτύου, IP, έτσι ώστε να
µπορούν να αποσταλούν δεδοµένα µέσω των πρωτοκόλλων TCP και UDP. Και το τρίτο την
καταχώρηση των πρωτοκόλλων µαζί µε το επίπεδο των sockets.
Η συνάρτηση inet_init ουσιαστικά φέρει εις πέρας όλη την αρχικοποίηση της στοίβας
TCP/IP. Η συνάρτηση αυτή ορίζεται στο αρχείο af_inet.c το οποίο βρίσκεται στον κατάλογο net/ipv4/. Αφού η συνάρτηση ολοκληρώσει την καταχώρηση του επιπέδου socket, καλούνται οι συναρτήσεις αρχικοποίησης των πρωτοκόλλων του TCP/IP. Η πρώτη από αυτές
είναι η arp_init η οποία αρχικοποιεί το πρωτόκολλο ARP. Στη συνέχεια καλείται η
Ιστότοπος εργασίας: MyThesis.org
127
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
ip_init για την αρχικοποίηση του πρωτοκόλλου IP και ακολουθεί η tcp_v4_init η οποία δηµιουργεί την slab cache για το TCP. Η επόµενη κλήση αφορά την icmp_init για την
αρχικοποίηση του πρωτοκόλλου ICMP. Αν στο σύστηµά µας έχουµε επιλέξει να υποστηρίζεται δροµολόγηση multicast τότε επιπρόσθετα καλείται και η συνάρτηση ip_mr_init. Αφού
έχουν ολοκληρωθεί επιτυχώς όλες οι κλήσεις των συναρτήσεων αλλά και η αρχικοποίηση
των επιθυµητών πρωτοκόλλων, γίνονται και οι απαραίτητες εγγραφές στο ψευδό-σύστηµα
αρχείων /proc.
Στο σηµείο αυτό είναι χρήσιµο να παραθέσουµε κάποιες πληροφορίες σχετικά µε τους όρους slab και /proc που αναφέρθηκαν νωρίτερα. Κάθε λειτουργικό σύστηµα, όπως και κάθε
άλλο πρόγραµµα, είναι απαραίτητο να δεσµεύει µνήµη για τις διάφορες λειτουργίες του. Για
το λόγο αυτό αναπτύσσεται εξειδικευµένος κώδικας ο οποίος χαρακτηρίζεται ως σύστηµα
δέσµευσης µνήµης (allocation memory system). Στο Linux το σύστηµα αυτό ονοµάζεται “slab
allocation” και χρησιµοποιείται για κάθε ανάγκη. Μια από τις χρήσεις του slab είναι και η δέσµευση µνήµης για δικτύωση (networking buffers). Το σύστηµα slab οργανώνεται σε caches
οι οποίες αντιστοιχούν µια σε κάθε κύρια λειτουργία του Kernel. Για το TCP/IP δηµιουργούνται αρκετές caches, εκ των οποίων η σηµαντικότερη είναι η skbuff_head_cache και αφορά τα socket buffers. Τα ονόµατα των caches για το TCP/IP βρίσκονται στο σύστηµα
αρχείων /proc στον κατάλογο slabinfo.
Το procfs (processes file system) ή /proc, είναι ένα ειδικό σύστηµα αρχείων το οποίο
αναπαριστά πληροφορίες που αφορούν τις διεργασίες που εκτελούνται σε ένα σύστηµα
Linux και τις παρουσιάζει σε µια ιεραρχική δοµή όµοια µε αυτή που υπάρχει για την αναπαράσταση των αρχείων και των καταλόγων. Έτσι παρέχεται µια πιο βολική µέθοδος δυναµικής
πρόσβασης στα δεδοµένα των διαφόρων διεργασιών, χωρίς να απαιτείται άµεση προσπέλαση της µνήµης του kernel από τις εφαρµογές που γράφουµε. Το σύστηµα αρχείων /proc
στον Router NGW100, όπως και στα περισσότερα συστήµατα Linux, φορτώνεται κατά την
εκκίνηση.
4.2 Linux Sockets
Ουσιαστικά ένα socket είναι ο συνδυασµός µιας IP διεύθυνσης µε έναν αριθµό θύρας (port
number) ή απλά πιο απλά, µε µια θύρα (port). Σε αυτή την ενότητα θα εξετάσουµε τα περισσότερα θέµατα που αφορούν τα sockets καθώς είναι ένα πάρα πολύ σηµαντικό χαρακτηριστικό για την λειτουργία του Router NGW100 αλλά και για κάθε συσκευή που απαιτείται να
συνδέεται σε δίκτυο.
4.2.1 Τί είναι η διεπαφή socket
Η διεπαφή (API) socket είναι ο συνδετικός κρίκος του επιπέδου µεταφοράς µε το επίπεδο
εφαρµογής της στοίβας TCP/IP που βρίσκεται υλοποιηµένη µέσα στον Linux Kernel. Παρέχει
µια εξειδικευµένη προγραµµατιστική διεπαφή την οποία χρησιµοποιούν οι προγραµµατιστές
για να αναπτύξουν εφαρµογές που µπορούν να εκµεταλλευτούν τις δυνατότητες δικτύωσης
και ∆ιαδικτύωσης του Kernel. Επίσης χρησιµοποιείται και από τον Kernel προκειµένου αυτός
να είναι σε θέση να “ζητήσει” κάτι από µια εφαρµογή. Η διεπαφή socket είναι ανεξάρτητη
πρωτοκόλλου. ∆ηλαδή ο προγραµµατιστής που δηµιουργεί µια δικτυακή εφαρµογή, δεν
χρειάζεται να γνωρίζει τα πρωτόκολλα TCP/IP και τις εσωτερικές τους λεπτοµέρειες.
Η διεπαφή socket µπορεί να χαρακτηριστεί ως το “παράθυρο” του TCP/IP προς τον έξω
κόσµο. Ο σκοπός των sockets είναι να επιτύχουν τη µεταφορά δεδοµένων, την διαχείριση
των συνδέσεων TCP και να ελέγχουν ή να βελτιώνουν την λειτουργία των πρωτοκόλλων του
Επικοινωνία: [email protected]
128
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
Kernel. Ο µηχανισµός των Linux sockets υποστηρίζει πολλές οικογένειες πρωτοκόλλων, µε
πιο γνωστή την AF_INET στην οποία ανήκει το πρωτόκολλο TCP/IP.
Η διεπαφή socket αποτελείται από δύο τµήµατα. Από ένα σύνολο συναρτήσεων που έχουν
γραφτεί ειδικά για το δίκτυο και έναν µηχανισµό αποθήκευσης και χαρτογράφησης αιτηµάτων
τα οποία στέλνουν οι εφαρµογές των χρηστών προκειµένου να φέρουν εις πέρας τις δικτυακές τους απαιτήσεις.
4.2.2 Οι βασικότερες δοµές διαχείρισης sockets
Η βασικότερη δοµή δεδοµένων είναι η sk_buff ή οποία αντιπροσωπεύει ένα socket buffer
και καθορίζεται στο αρχείο include/linux/sk_buff.h. Τα socket buffers είναι δοµές
(δηλαδή ενιαίες περιοχές στη µνήµη) στις οποίες αποθηκεύονται τα δεδοµένα των πακέτων.
Συνήθως ένα socket buffer είναι προσβάσιµο µέσω της µεταβλητής δείκτη skb.
Η δεύτερη δοµή είναι η socket η οποία ορίζεται στο αρχείο include/linux/net.h. Σε
αυτή τη δοµή καταγράφονται πληροφορίες για όλες τις ενεργές συνδέσεις µε τις διάφορες
εφαρµογές που υπάρχουν έτσι ώστε να είναι διαθέσιµες όταν αυτό απαιτείται. Γενικά, κάθε
στιγµιότυπο µιας δοµής socket, αντιστοιχεί σε ένα ανοικτό socket το οποίο έχει δηµιουργηθεί µέσω των κλήσεων που παρέχονται από τη διεπαφή επιπέδου socket. Συνήθως η δοµή
socket προσπελαύνεται µέσω της µεταβλητής δείκτη, sock.
Η τρίτη και αρκετά σηµαντική δοµή είναι η sock και ορίζεται στο αρχείο sock.h που υπάρχει στον κατάλογο include/net. Είναι αρκετά περίπλοκη δοµή η οποία διατηρεί πληροφορίες που αφορούν τις ανοικτές συνδέσεις. Είναι προσβάσιµη µέσω της στοίβας TCP/IP και
κυρίως µέσω του πρωτοκόλλου TCP, ενώ συνήθως αναφέρεται µέσω µιας µεταβλητής δείκτη µε την ονοµασία sk.
Όπως γίνεται εύκολα αντιληπτό, οι ονοµασίες στην υλοποίηση της διεπαφής των sockets
στον Linux Kernel µοιάζουν αρκετά η µία µε την άλλη. Αυτό δηµιουργεί σύγχυση στον προγραµµατιστή και θα ήταν καλό σε νέες εκδόσεις του Kernel να διορθωθεί.
4.2.3 Οικογένειες πρωτοκόλλων
Μια οικογένεια πρωτοκόλλων (protocol family) είναι απλά ένας αριθµός ο οποίος αντιστοιχεί
στο όρισµα domain της κλήσης συστήµατος socket().κάποιες φορές µια οικογένεια πρωτοκόλλων µπορεί να αναφέρεται και ως οικογένεια διευθύνσεων (address family). Κάθε οικογένεια έχει ένα όνοµα. Για παράδειγµα το όνοµα της οικογένειας πρωτοκόλλων του TCP/IP
είναι AF_INET και ο αριθµός που της αντιστοιχεί είναι το 2 (εποµένως domain = 2):
#define AF_INET
2
/* Internet IP Protocol */
Εποµένως όταν λέµε AF_INET είναι σα να λέµε TCP/IP. Στον Linux Kernel (έκδοση 2.6)
υπάρχουν 32 υποστηριζόµενες οικογένειες πρωτοκόλλων οι οποίες ορίζονται στο αρχείο
include/linux/socket.h.
Όπως συµβαίνει και µε τα περισσότερα στοιχεία λογισµικού σε ένα σύστηµα Linux, για να
είµαστε σε θέση να χρησιµοποιήσουµε µια οικογένεια πρωτοκόλλων θα πρέπει πρώτα να
την αρχικοποιήσουµε. Η αρχικοποίηση ουσιαστικά ενηµερώνει το επίπεδο των sockets για
την ύπαρξη της οικογένειας αυτής.
Ιστότοπος εργασίας: MyThesis.org
129
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Τέλος, αν κρίνεται αναγκαίο υπάρχει η δυνατότητα να γράψουµε το δικό µας πρωτόκολλο
και να το φορτώσουµε κατά τη λειτουργία του συστήµατος µε τη µορφή module. Για να δηµιουργήσουµε όµως ένα νέο όνοµα οικογένειας πρωτοκόλλων (πχ AF_ROUSIS), θα πρέπει να
υπερφορτώσουµε (override) κάποια ήδη υπάρχουσα η οποία δε χρησιµοποιείται από το σύστηµά µας:
# ifndef AF_ROUSIS
# define AF_ROUSIS AF_SNA /*override*/
# endif
Θα πρέπει επίσης να αντιστοιχίσουµε την οικογένεια διευθύνσεων µε την οικογένεια πρωτοκόλλων έτσι ώστε να σηµαίνουν το ίδιο πράγµα:
# ifndef PF_ROUSIS
# define PF_ROUSIS AF_ROUSIS
# endif
Οι δύο παραπάνω προσθήκες κώδικα αφορούν το αρχείο socket.h που αναφέραµε νωρίτερα. Φυσικά υπάρχουν και άλλα βήµατα που πρέπει να γίνουν τα οποία όµως δεν κρίνεται
αναγκαίο να αναφερθούν στα πλαίσια αυτής της εργασίας.
4.2.4 Αρχικοποίηση επιπέδου socket
Αναφέραµε νωρίτερα σε αυτό το κεφάλαιο, ότι είναι δύσκολο να διαχωρίσουµε την αρχικοποίηση της στοίβας TCP/IP από την αρχικοποίηση του επιπέδου των sockets. Και ότι η δεύτερη, προηγείται, αφού το επίπεδο socket θα πρέπει να βρίσκεται στη θέση του όταν η
οικογένεια πρωτοκόλλων AF_INET καταχωρηθεί σε αυτό, προκειµένου να µπορούν να λαµβάνονται και να αποστέλλονται πακέτα IP. Σε αυτή την παράγραφο θα παραθέσουµε πληροφορίες για τον τρόπο και τη σειρά που ακολουθείται έτσι ώστε να αρχικοποιηθεί σωστά το
επίπεδο socket και η οικογένεια AF_INET.
Η πρώτη συνάρτηση που καλείται είναι η sock_init. Η συνάρτηση αυτή ορίζεται στο αρχείο net/socket.c:
static int __init sock_init(void)
{
sk_init(); /* Initialize sock SLAB cache */
skb_init(); /* Initialize skbuff SLAB cache */
/* Initialize the protocols module. */
init_inodecache();
register_filesystem(&sock_fs_type);
sock_mnt = kern_mount(&sock_fs_type);
#ifdef CONFIG_NETFILTER
netfilter_init();
#endif
return 0;
}
Καλείται πριν από την αρχικοποίηση του TCP/IP για τους λόγους που έχουµε αναφέρει ήδη.
Εφόσον το επίπεδο socket αποτελείται από πολλές λειτουργίες και µπορεί να χρησιµοποιείται ταυτόχρονα από πολλά διαφορετικά πρωτόκολλα και δη οικογένειες πρωτοκόλλων, απαι-
Επικοινωνία: [email protected]
130
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
τείται η ύπαρξη ενός πίνακα. Ο σκοπός του θα είναι να αντιστοιχίζει τα επεξεργασµένα πακέτα των διάφορων πρωτοκόλλων µε τα sockets των εφαρµογών στις οποίες ανήκουν, και στις
οποίες τελικά θα πρέπει να σταλούν τα επεξεργασµένα πακέτα. Αυτή η διαδικασία χαρακτηρίζεται ως αποπολύπλεξη (socket de-multiplexing). O κύριος µηχανισµός που παρέχει ο
Linux Kernel για την αποπολύπλεξη των socket είναι ο πίνακας µεταγωγής πρωτοκόλλων
(switching protocol table).
Η αρχικοποίηση του πίνακα µεταγωγής πρωτοκόλλων γίνεται µέσω των συναρτήσεων
inet_register_protosw που ορίζεται στο αρχείο net/ipv4/af_inet.c, ενώ η αντίθετη διαδικασία επιτυγχάνεται µέσω της inet_unregister_protosw που ορίζεται στο ίδιο
αρχείο.
Αφού αρχικοποιηθεί ο πίνακας θα πρέπει τα πρωτόκολλα που θα περιέχει να καταχωρηθούν στα πεδία του. Αυτό πραγµατοποιείται από δύο συναρτήσεις. Την inet_init και την
inet_protosw, οι οποίες ορίζονται στο αρχείο net/ipv4/af_inet.c.
Το τελευταίο βήµα που θα πρέπει να γίνει προκειµένου να ολοκληρωθεί η αρχικοποίηση
του επιπέδου socket είναι η καταχώρηση των πρωτοκόλλων στο επίπεδο socket. Οι συναρτήσεις που θα αναφερθούν στη συνέχεια, βρίσκονται υλοποιηµένες στο αρχείο socket.c
του καταλόγου net και δηλώνονται στο αρχείο κεφαλίδας include/linux/net.h.
Η συνάρτηση που καταχωρεί µια οικογένεια πρωτοκόλλων στο επίπεδο socket είναι η
sock_register. Αυτό γίνεται για κάθε οικογένεια η οποία θα χρειαστεί στο σύστηµά µας,
ενώ η αντίθετη διαδικασία πραγµατοποιείται από την συνάρτηση sock_unregister.
4.2.5 Πρωτόκολλο IP και sockets
Στην αρχή αυτής της ενότητας αναφέραµε ότι ένα socket είναι ο συνδυασµός µιας IP διεύθυνσης µε έναν αριθµό θύρας. Επειδή αυτός είναι ένας απλουστευµένος ορισµός, σε αυτή
την παράγραφο θα προσθέσουµε κάποιες επιπλέον πληροφορίες.
Γενικά, όταν χρησιµοποιείται η διεπαφή socket οι διευθύνσεις δικτύου αποθηκεύονται σε µια
δοµή δεδοµένων µε όνοµα sockaddr_in η οποία ορίζεται στο αρχείο in.h και είναι η εξής:
struct sockaddr_in {
sa_family_t
unsigned short int
struct in_addr
sin_family; /* Address family
sin_port;
/* Port number
sin_addr;
/* Internet address
*/
*/
*/
/* Pad to size of `struct sockaddr'. */
unsigned char
__pad[__SOCK_SIZE__ - sizeof(short int) sizeof(unsigned short int) - sizeof(struct in_addr)];
};
Το αρχείο κεφαλής in.h βρίσκεται στον κατάλογο include/linux και αποτελεί την υλοποίηση INET (linux.die.net/man/3/inet) του πρωτοκόλλου TCP/IP που είναι συµβατή µε τα BSD sockets (wikipedia.org/wiki/Berkeley_sockets):
Τα µέλη της δοµής sin_family, sin_port, και sin_addr αφορούν την οικογένεια διευθύνσεων (AF_INET για το IP), τη θύρα, και τη διεύθυνση IP του συστήµατος στο οποίο εκτελείται η εφαρµογή. Ο πίνακας __pad αφορά τον υπολογισµό του µήκους της διεύθυνσης
που χρησιµοποιείται κάθε φορά. Το µήκος πρέπει να υπολογίζεται εκ νέου κάθε φορά που
αποστέλλονται δεδοµένα γιατί η διεπαφή socket υποστηρίζει πολλά διαφορετικά πρωτόκολ-
Ιστότοπος εργασίας: MyThesis.org
131
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
λα και έτσι µια διεύθυνση δεν είναι πάντοτε IP. Εποµένως για το Linux, socket είναι ο συνδυασµός µιας οποιασδήποτε διεύθυνσης πρωτοκόλλου µε έναν αριθµό θύρας.
4.2.6 Η διεπαφή Socket
Πριν προχωρήσουµε στην ανάλυσή µας θα αναφέρουµε ορισµένες βασικές λεπτοµέρειες. Η
διεπαφή socket διαχειρίζεται κυρίως διευθύνσεις δικτύου και θύρες εφαρµογών. Επίσης, το
πρωτόκολλο TCP/IP απαιτεί τα στοιχεία αυτά να περνιούνται µέσω της διεπαφής socket µε
σειρά οκτάδων δικτύου (network byte order
wikipedia.org/wiki/Endianness). Υπάρχουν δύο τύποι sockets, ο ένας είναι ο SOCK_DGRAM και είναι κατάλληλος για µεταφορά
ανεξάρτητων πακέτων UDP και ο άλλος ονοµάζεται SOCK_STREAM και είναι κατάλληλος για
ακολουθίες bytes του TCP.
Σε αυτή την παράγραφο θα αναφέρουµε συναρτήσεις και κλήσεις προς το επίπεδο socket
καθώς και εξειδικευµένα sockets που χρησιµοποιούνται από δικτυακές εφαρµογές τις οποίες
γράφουµε για το Linux. Σε αυτούς τους ίδιους µηχανισµούς βασίζονται και οι εφαρµογές που
έχουν αναπτυχθεί για τον Router NGW100.
Για να είναι σε θέση ένας προγραµµατιστής να δηµιουργήσει µια εφαρµογή η οποία θα χρησιµοποιεί τη στοίβα TCP/IP του Router NGW100, θα πρέπει πρώτα να δηµιουργήσει ένα νέο
socket, καλώντας την συνάρτηση socket, της διεπαφής socket:
int socket(int domain, int type, int protocol);
Ας δούµε ένα παράδειγµα δηµιουργίας νέου socket για σύνδεση εφαρµογής µέσω TCP:
int socket(AF_INET, SOCK_STREAM, 0); /* protocol zero is for TCP or UDP */
Το δεύτερο βήµα που θα πρέπει να εκτελεστεί είναι η κλήση bind προκειµένου να αντιστοιχηθεί η τοπική διεύθυνση της εφαρµογής, που είναι ένας αριθµός θύρας (port number)
και αποτελεί το όνοµα (name) του socket που δηµιουργήσαµε πριν. Η κλήση bind γράφεται
ως εξής:
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
Μέσω της bind, µια εφαρµογή η οποία λειτουργεί σαν server, ενηµερώνει το επίπεδο
socket σχετικά µε το ποια θύρα θα χρησιµοποιεί για να λαµβάνει δεδοµένα. Με αυτό τον
τρόπο δηµιουργείται ένα τερµατικό σηµείο (endpoint) που χαρακτηρίζεται από µια διεύθυνση
IP και έναν αριθµό θύρας. Τα στοιχεία αυτά είναι προσβάσιµα µέσω του δείκτη myaddr ο
οποίος δείχνει στη περιοχή µνήµης που βρίσκεται η δοµή sockaddr. Το τερµατικό σηµείο
που δηµιουργήθηκε θα το χρησιµοποιούν εφαρµογές client προκειµένου να εξυπηρετούνται
ανταλλάσοντας δεδοµένα.
Για να µπορεί όµως µια εφαρµογή server να ικανοποιεί τα αιτήµατα των clients απαιτείται
προηγουµένως να εκτελεστεί η κλήση listen. Αυτό γίνεται µέσω της SOCK_STREAM ή µέσω
ενός TCP server, για να ενηµερωθεί το επίπεδο socket ότι η εφαρµογή είναι έτοιµη να λάβει
αιτήµατα στο socket µε όνοµα, s:
int listen(int s, int backlog);
Το όρισµα backlog αντιπροσωπεύει το µήκος της ουράς των αιτηµάτων σύνδεσης που
εκκρεµούν ενώ ο server περιµένει τη λήξη της εκτέλεσης της κλήσης accept. Η συγκεκριµένη κλήση γίνεται από την εφαρµογή όταν είναι έτοιµη να ικανοποιήσει αιτήµατα συνδέσεων.
Επικοινωνία: [email protected]
132
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
Η διεύθυνση IP του client που αιτείται τη σύνδεση τοποθετείται στο δοµή sockaddr και ταυτόχρονα περνιέται προς αυτή τη ο δείκτης addr. Ο δείκτης addrlen θα πρέπει να δείχνει σε
µια µεταβλητή η οποία θα περιέχει το µέγεθος της δοµής sockaddr και αυτό θα πρέπει να
γίνεται πριν κληθεί η accept. Αφού ολοκληρωθεί η εκτέλεση της accept ο δείκτης
addrlen θα δείχνει στη µεταβλητή µήκους της νέας διεύθυνσης µνήµης του δείκτη addr:
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
Από την πλευρά της εφαρµογής client που θέλει να συνδεθεί στον server µέσω µιας αξιόπιστης σύνδεσης TCP χρησιµοποιείται η κλήση connect:
int connect(int s const struct sockaddr *serv_addr, socklen_t addrlen);
Ο δείκτης serv_addr καθορίζει τη διεύθυνση και τη θύρα του server µε τον οποίο ο client
θέλει να συνδεθεί και η µεταβλητή addrlen περιέχει το µήκος της δοµής sockaddr.
Στην εικόνα που ακολουθεί φαίνεται µε γραφικό τρόπο, το πως οι κλήσεις που αναφέραµε
εκτελούνται σε ένα µοντέλο client – server:
Εικόνα 39. Το µοντέλο επικοινωνίας client – server
Συνεχίζοντας την ανάλυση της διεπαφής socket θα παραθέσουµε τρεις ακόµη συναρτήσεις,
τις δοµές που συνδέονται µε αυτές καθώς και ορισµένες ακόµη κλήσεις socket που χρησιµοποιούνται από τους προγραµµατιστές δικτυακών εφαρµογών.
Οι συναρτήσεις send, sendto και sendmsg χρησιµοποιούνται για την αποστολή αυτόνοµων πακέτων UDP (datagrams). Τα πρωτότυπά τους είναι τα παρακάτω:
int send(int s, const void *msg, size_t len, int flags);
int sendto(int s, const void *msg, size_t len, int flags
const struct sockaddr *to, sockle_t tolen);
int sendmsg(int s, const struct msghdr *msg, int flags);
Ιστότοπος εργασίας: MyThesis.org
133
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η sendmsg συχνά χρησιµοποιείται για την επικοινωνία µεταξύ του kernel και του περιβάλλοντος χρήστη. Επίσης χρησιµοποιείται συχνά στα netlink sockets που θα εξετάσουµε αργότερα. Το όρισµα flags παίρνει τιµές οι οποίες ορίζονται στο αρχείο socket.h:
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
MSG_OOB
MSG_PEEK
MSG_DONTROUTE
MSG_TRYHARD
MSG_CTRUNC
MSG_PROBE
MSG_TRUNC
MSG_DONTWAIT
MSG_EOR
MSG_WAITALL
MSG_FIN
MSG_SYN
MSG_CONFIRM
MSG_RST
MSG_ERRQUEUE
MSG_NOSIGNAL
MSG_MORE
1
2
4
4
/* Synonym for MSG_DONTROUTE for DECnet */
8
0x10 /*Do not send.Only probe path f.e. for MTU*/
0x20
0x40
/* Nonblocking io
*/
0x80
/* End of record */
0x100
/* Wait for a full request */
0x200
0x400
0x800
/* Confirm path validity */
0x1000
0x2000
/* Fetch message from error queue */
0x4000
/* Do not generate SIGPIPE */
0x8000
/* Sender will send more */
Το όρισµα msg στην κλήση sendmsg χρησιµοποιείται για να της επιτρέπει να περνά µηνύµατα προς τον kernel και ουσιαστικά είναι ένας δείκτης προς τη δοµή msghdr η οποία ορίζεται στο αρχείο socket.h. Η δοµή msghdr περιλαµβάνει µε τη σειρά της, άλλη µία σηµαντική
δοµή, την iovec. Η δοµή αυτή ορίζεται στο αρχείο include/linux/uio.h και χρησιµοποιείται για να δεσµεύει µνήµη για την µετάφραση διευθύνσεων µεταξύ του Kernel και του
περιβάλλοντος χρήστη.
Κλείνοντας την ανάλυσή µας για τη διεπαφή socket θα περιγράψουµε τη λειτουργία ορισµένων ακόµη βασικών κλήσεων. Οι πρώτες τρεις που θα µας απασχολήσουν είναι η recv, η
recvfrom και η recvmsg. Η κλήση recvmsg χρησιµοποιείται για να ληφθεί ένα µήνυµα
από κάποιο socket ενός client. Όπως και µε την κλήση send, η recv χρησιµοποιείται για
συνδεδεµένα socket σε TCP επικοινωνία, ενώ η recvfrom µπορεί να χρησιµοποιηθεί και µε
επικοινωνία UDP ώστε να µπορεί να λαµβάνει πακέτα από οποιοδήποτε σύστηµα του δικτύου. Τα πρωτότυπά τους είναι τα ακόλουθα:
int recv(int s, void *buf, size_t len, int flags);
int recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen);
int recvmsg(int s, struct msghdr *msg, int *flags);
Τα ορίσµατα from και fromlen, όταν ολοκληρωθεί επιτυχώς η εκτέλεση της κλήσης
recvfrom, περιέχουν την διεύθυνση του αποστολέα και το µήκος της αντίστοιχα. Οι τρεις
κλήσεις που µόλις αναφέραµε, συχνά χρησιµοποιούνται σε συνδυασµό µε άλλες έτσι ώστε
να είναι πιο αποτελεσµατικές.
Τέλος, θα αναφέρουµε δύο κλήσεις οι οποίες χρησιµοποιούνται για να επιτρέπουν στους
προγραµµατιστές και στις εφαρµογές τους, την παραµετροποίηση των πρωτοκόλλων επικοινωνίας που βρίσκονται κάτω από το επίπεδο socket και τη διεπαφή socket. Οι κλήσεις αυτές
είναι η getsockopt και setsockopt:
int getsockopt(int s, int level, int optname, void *optval,
socklen_t *optlen);
Επικοινωνία: [email protected]
134
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
int setsockopt(int s, int level, int optname, const void *optval,
socklen_t optlen);
Το όρισµα level παίρνει τιµές (που καθορίζονται από τον οργανισµό iana.org) οι οποίες
φαίνονται πιο κάτω:
#define
#define
#define
#define
#define
#define
#define
SOL_IP
SOL_SOCKET
SOL_TCP
SOL_UDP
SOL_IPV6
SOL_ICMPV6
SOL_RAW
0
1
6
17
41
58
255
Το όρισµα optname παίρνει τιµές οι οποίες για τον Router NGW100 καθορίζονται στο αρχείο arch/avr32/include/asm/socket.h.
Το επίπεδο socket κάθε φορά που επιχειρείται η τροποποίηση τιµών, ελέγχει αν η εφαρµογή που αιτήθηκε τις τροποποιήσεις αυτές έχει τα απαραίτητα δικαιώµατα προκειµένου έτσι να
παρέχεται και ένα επίπεδο ασφάλειας. Τα δικαιώµατα αυτά ονοµάζονται capabilities
(παρόµοια µε τις λίστες ACL άλλων λειτουργικών) και για τον µηχανισµό αυτό υπάρχει αναλυτική τεκµηρίωση στον ιστότοπο linux.die.net/man/7/capabilities.
4.2.7 Socket buffers
Ο Linux Kernel αποθηκεύει όλες τις πληροφορίες που αφορούν ένα πακέτο σε µια δοµή δεδοµένων µε όνοµα skbuff (ή SKB εν συντοµία) η οποία χαρακτηρίζεται ως ένα socket
buffer. Η δοµή αυτή ορίζεται στο αρχείο include/linux/skbuff.h:
struct skb_frag_struct {
struct page *page;
__u16 page_offset;
__u16 size;
};
4.2.8 Τα είδη των sockets
Αυτή η παράγραφος λειτουργεί συµπληρωµατικά µε την προηγούµενη. Εδώ θα εξετάσουµε
τα ειδικά sockets που µας παρέχει το Linux. Τα sockets αυτά χρησιµοποιούνται για εσωτερική µεταφορά µηνυµάτων και για άµεση πρόσβαση σε πρωτόκολλα. Στην εικόνα µπορούµε
να δούµε µια γραφική αναπαράσταση της χρήσης τους µέσω εφαρµογών στο Linux καθώς
και της σχέσης τους µε το πρωτόκολλο TCP/IP το οποίο υπάρχει υλοποιηµένο στον Kernel:
Ιστότοπος εργασίας: MyThesis.org
135
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 40. Γραφική αναπαράσταση της χρήσης Sockets από εφαρµογες Linux
Packet Sockets
Είναι προσβάσιµα από εφαρµογές όταν το πεδίο family της κλήσης socket τίθεται σε
AF_PACKET:
ps = socket(PF_PACKET, int type, int protocol);
Το πεδίο type µπορεί να πάρει την τιµή SOCK_RAW ή SOCK_DGRAM. Το πεδίο Protocol
παίρνει την ίδια τιµή µε το πρωτόκολλο που χρησιµοποιείται, η οποία µπορεί να είναι ίδια µε
τον αριθµό πρωτοκόλλου που υπάρχει στην κεφαλίδα IP ή κάποιος άλλος έγκυρος αριθµός
πρωτοκόλλου. Περισσότερες πληροφορίες για τα Packet Sockets µπορούν να βρεθούν και
στη σελίδα linux.die.net/man/7/packet.
Raw Sockets
Επιτρέπουν σε εφαρµογές χρήστη να αποστείλουν ή να παραλάβουν πακέτα επιπέδου δικτύου:
rs = socket(PF_INET, SOCK_RAW, int protocol);
Το πεδίο protocol παίρνει την τιµή του πρωτοκόλλου µέσω του οποίου η εφαρµογή θέλει
να επικοινωνήσει. Ένα παράδειγµα χρήσης Raw Socket είναι και η εντολή ping για την οποία µπορούµε να βρούµε πληροφορίες στη σελίδα linux.die.net/man/8/ping (Επί-
Επικοινωνία: [email protected]
136
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
σης: linux.die.net/man/7/raw). Κατά την εκτέλεση της εντολής ping το πεδίο protocol παίρνει την τιµή IPPROTO_ICMP.
Netlink Sockets και πρωτόκολλο Netlink
Το Linux προκειµένου να µπορεί να υποστηρίξει την πολυπλοκότητα των σύγχρονων δικτύων αλλά και τις απαιτήσεις παραµετροποίησης που έχει ένας router, παρέχει πολλαπλούς
πίνακες δροµολόγησης και πολλαπλές µνήµες cache. Μπορεί επίσης να παρέχει τη δυνατότητα δηµιουργίας κανόνων δροµολόγησης (routing rules) οι οποίοι συνδέονται µε τους πίνακες δροµολόγησης και ταξινοµούνται σε µορφή βάσης δεδοµένων. Όλα αυτά συνήθως
επιτυγχάνονται από εφαρµογές που γράφουµε ή που υπάρχουν ήδη έτοιµες και οι οποίες
επικοινωνούν µε τον Kernel µέσω της διεπαφής Netlink Sockets:
ns = socket(AF_NETLINK, int type, int netlink_family);
Η παράµετρος type µπορεί να πάρει την τιµή SOCK_DGRAM, ή την τιµή SOCK_STREAM. Η
παράµετρος netlink_family µπορεί να πάρει τιµές οι οποίες καθορίζονται στο αρχείο
include/linux/netlink.h (πχ: NETLINK_FIREWALL).
Τα Νetlink Sockets οφείλουν την ονοµασία τους στο εσωτερικό πρωτόκολλο επικοινωνίας
Netlink. Σκοπός του πρωτοκόλλου αυτού, είναι η µεταφορά και η λήψη πακέτων µεταξύ των
εφαρµογών και των διαφόρων πρωτοκόλλων που υπάρχουν στον Linux Kernel. Η οικογένεια
διευθύνσεων του Netlink είναι η AF_NETLINK. Το Netlink υποστηρίζει τις περισσότερες συναρτήσεις της διεπαφής socket και η λειτουργικότητά του µπορεί να εµπλουτιστεί µέσω της
επέκτασης Rtnetlink.
Η πιο κοινή χρήση του Netlink είναι από εφαρµογές που θέλουν να ανταλλάξουν πληροφορίες δροµολόγησης µε τον εσωτερικό πίνακα δροµολόγησης του Kernel. Ένα Netlink Socket
είναι προσβάσιµο όπως και οποιοδήποτε άλλο socket.
Το πρωτόκολλο Netlink βρίσκεται υλοποιηµένο στο αρχείο af_netlink.c το οποίο υπάρχει στον κατάλογο net/netlink του πηγαίου κώδικα του Linux Kernel. Ουσιαστικά είναι
σαν οποιοδήποτε άλλο πρωτόκολλο της στοίβας TCP/IP µε τη διαφορά ότι υπάρχει για την
ανταλλαγή µηνυµάτων µεταξύ διεργασιών που εκτελούνται σε επίπεδο χρήστη (user-level ή
user-space processes) και εσωτερικών οντοτήτων του Kernel. Επίσης είναι όµοιο µε το UDP
και το TCP µε την έννοια ότι και αυτό πρέπει να καθορίσει τη δοµή δεδοµένων proto_ops
προκειµένου να συνδέσει τις εσωτερικές κλήσεις µε τις κλήσεις των sockets οι οποίες πραγµατοποιούνται µέσω της AF_NETLINK.
Περισσότερες πληροφορίες για το Netlink και τη δηµιουργία εφαρµογών που βασίζονται σε
αυτό, υπάρχουν στις σελίδες: linux.die.net/man/7/netlink, linuxfoundation.org
και infradead.org/~tgr/libnl.
Routing Sockets
Τα sockets δροµολόγησης καθορίζονται από την οικογένεια AF_ROUTE. Στο Linux τα sockets δροµολόγησης είναι πανοµοιότυπα µε τα netlink sockets.
Ιστότοπος εργασίας: MyThesis.org
137
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Rtnetlink Sockets
Τα sockets αυτά επεκτείνουν τα netlink sockets. Αυτό το επιτυγχάνουν προσθέτοντας κάποιους επιπλέον τύπους µηνυµάτων που έχουν περισσότερες ιδιότητες και είναι συµβατά µε
τα netlink sockets. Τα Rtnetlink sockets χρησιµοποιούνται από εφαρµογές που πρέπει να
έχουν πρόσβαση στους πίνακες δροµολόγησης του Kernel. Περισσότερες πληροφορίες υπάρχουν κι εδώ: linux.die.net/man/7/rtnetlink. Και ένα παράδειγµα χρήσης µακροεντολών Rtnetlink, εδώ: linux.die.net/man/3/rtnetlink.
4.2.9 Το πρόγραµµα netstat
Το πρόγραµµα – εντολή netstat (wikipedia.org/wiki/Netstat), είναι ένα δωρεάν
και στις περισσότερες περιπτώσεις, προεγκατεστηµένο εργαλείο γραµµής εντολών, το οποίο
µπορούµε να χρησιµοποιούµε σε περιβάλλοντα Linux. Το πρόγραµµα netstat χρησιµεύει
στην ανάπτυξη εφαρµογών (και κυρίως στο debugging) που η λειτουργία τους βασίζεται και
στην χρήση sockets.
Όταν εκτελείται χωρίς την προσθήκη παραµέτρων, εµφανίζει σε µια λίστα όλες τις πληροφορίες για τα συνδεδεµένα sockets των εφαρµογών που εκτελούνται την τρέχουσα χρονική
στιγµή στο σύστηµα.
4.2.10 ∆ιεπαφή socket και IPv6
Η νέα έκδοση του πρωτοκόλλου IP, υποστηρίζεται πλήρως από τον Linux Kernel. Το πρωτόκολλο IPv6 ανήκει στην οικογένεια AF_INET6 η οποία ορίζεται στο αρχείο socket.h του
καταλόγου include, µαζί µε τις υπόλοιπες διευθύνσεις που έχουµε αναφέρει ως τώρα.
Για να υποστηρίζεται καλύτερα από τον kernel, το IPv6 διαθέτει τη δική του µορφή διεύθυνσης socket η οποία ονοµάζεται sockaddr_in6 και ορίζεται στο αρχείο in6.h του καταλόγου include/linux.
Επίσης, για την ανεξαρτησία και τη διευκόλυνση των προγραµµατιστών από τα πολλά και
διαφορετικά πρωτόκολλα, το Linux παρέχει µια βιβλιοθήκη συναρτήσεων, προκειµένου να
είναι εφικτή η µετατροπή µεταξύ διευθύνσεων IPv4 και IPv6. Οι συναρτήσεις αυτές είναι η
getaddrinfo, η freeaddrinfo και η getnameinfo.
4.3 ∆ροµολόγηση πακέτων
Σύµφωνα µε το µοντέλο αναφοράς OSI, η δροµολόγηση και η διευθυνσιοδότηση των πακέτων πραγµατοποιείται από το επίπεδο ∆ικτύου δηλαδή από το πρωτόκολλο IP. Ο Router
NGW100 είναι ένα ενσωµατωµένο σύστηµα στο οποίο έχουµε εγκαταστήσει το λειτουργικό
σύστηµα Linux. Εποµένως οι λειτουργίες δροµολόγησής του βασίζονται στο πρωτόκολλο IP
που υπάρχει υλοποιηµένο στην στοίβα TCP/IP του Kernel. Στο Linux το IP είναι υπεύθυνο
για αρκετές διεργασίες. Μία από τις σηµαντικότερες είναι και η διαχείριση του πίνακα (ή των
πινάκων) δροµολόγησης (routing table) που θα εξετάσουµε και στη συνέχεια.
Επικοινωνία: [email protected]
138
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
4.3.1 Πίνακες δροµολόγησης
Σε έναν πίνακα δροµολόγησης αποθηκεύονται πληροφορίες που εξυπηρετούν τη λειτουργία του IP. Για να λειτουργούν όλα σωστά, ένας τέτοιος πίνακας θα πρέπει να παρέχει τις
παρακάτω δυνατότητες:
Λήψη και παροχή πληροφοριών από και προς ένα εξωτερικό πρωτόκολλο αντίστοιχα
Ταχεία αναζήτηση στα πεδία που τον απαρτίζουν
Υποστήριξη στατικής και δυναµικής δροµολόγησης
Χρονιστής για την λήξη δροµολογήσεων που δεν ισχύουν πια
Μετρητή χρήσης δροµολογήσεων
∆ιαφοροποίηση δροµολογήσεων ανάλογα µε το είδος τους
Υποστήριξη πολλαπλών διεπαφών δικτύου
Αποθήκευση επόµενου βήµατος πακέτων (next hop) αλλά και διευθύνσεων άλλων
δροµολογητών
Η υλοποίηση του πίνακα δροµολόγησης στο Linux περιλαµβάνει όλες τις δυνατότητες που
αναφέρθηκαν. Ένας πίνακας δροµολόγησης στο Linux απαρτίζεται από την route cache και
από την βάση δεδοµένων RPDB (Routing Policy Database).
Route cache
Tο Linux διαθέτει µια µνήµη δροµολόγησης γνωστή και ως route cache η οποία αποτελεί
όπως αναφέραµε, το ένα από τα δύο κύρια µέλη του πίνακα δροµολόγησης και επιταχύνει τις
αποφάσεις προώθησης των πακέτων χρησιµοποιώντας προ-αποθηκευµένες (cached) δροµολογήσεις που είναι ήδη γνωστές.
Πιο συγκεκριµένα, όταν µια δροµολόγηση έχει αποφασιστεί, τοποθετείται στην route cache
για µελλοντική, γρήγορη και εύκολη πρόσβαση. Αυτό σηµαίνει ότι τα πακέτα τα οποία στέλνονται µέσω της ίδιας δροµολόγησης, µπορούν να προωθούνται άµεσα και χωρίς καθυστερήσεις που θα προέκυπταν από περεταίρω ελέγχους στην βάση FIB της RPDB. Αυτό
βελτιώνει την απόδοση του συστήµατος, ιδιαίτερα όταν υπάρχει µεγάλος όγκος πακέτων και
πολλά ταυτόχρονα ανοικτά sockets.
Η route cache θεωρείται ως το frontend της βάσης FIB που θα εξετάσουµε αργότερα. Ουσιαστικά κληρονοµεί την λειτουργικότητα της υλοποίησης cache που υπάρχει ήδη στον Linux
Kernel. Αποτελείται µε τη σειρά της, από έναν πίνακα κατακερµατισµού (hash table) στον
οποίο αποθηκεύονται εγγραφές δροµολόγησης. Ο πίνακας αυτός είναι σχεδιασµένος για ταχύτατη προσπέλαση και αναζήτηση µε ένα απλό κλειδί.
Η υλοποίηση της route cache στον Linux Kernel αποτελείται από κάποιες δοµές δεδοµένων
(rt_hash_table, rt_hash_bucket, rtable και flowi) και κάποιες συναρτήσεις
(ipv4_dst_destroy, ipv4_dst_ifdown, ipv4_negative_advise, ip_rt_put,
rt_binf_peer, ip_route_connect, rt_intern_hash και rt_set_nexthop) οι οποίες
πραγµατοποιούν όλη τη λειτουργικότητα της θεωρίας που παραθέσαµε σε αυτή την παράγραφο. ∆εν κρίνεται όµως απαραίτητο να αναλυθεί εδώ ο κώδικάς τους καθώς µπορεί να
βρεθεί αυτούσιος στο αρχείο net/ipv4/route.c.
RPDB
Η υλοποίηση του IP στο Linux ουσιαστικά διαχειρίζεται έναν πίνακα δροµολόγησης. Οι
πληροφορίες δροµολόγησης καθώς και η απαραίτητη πολιτική δροµολόγησης, περιέχονται
στην βάση RPDB. Τα δύο κυριότερα τµήµατα της RPDB είναι η βάση FIB (Forwarding Infor-
Ιστότοπος εργασίας: MyThesis.org
139
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
mation Base) και οι κανόνες (rules) FIB. Η βάση FIB είναι ο πυρήνας της δροµολόγησης στο
Linux. Σε αρκετές χρήσεις του Linux Kernel δεν υπάρχει ανάγκη δροµολόγησης που να είναι
βασισµένη σε κανόνες. Αυτό ισχύει και για τα περισσότερα ενσωµατωµένα συστήµατα Linux.
Η RPDB µπορεί να υποστηρίζει στατική αλλά και δυναµική δροµολόγηση ταυτόχρονα. Η
απόφαση για το είδος της δροµολόγησης λαµβάνεται συνήθως από την κάθε εφαρµογή του
χρήστη. Στη στατική δροµολόγηση η RPDB ενηµερώνεται χειροκίνητα από τον χρήστη µέσω
ειδικών προγραµµάτων παραµετροποίησης. Στον Router NGW100 για παράδειγµα αυτό επιτυγχάνεται µέσω του προγράµµατος route το οποίο µπορεί να χρησιµοποιείται και σε συνδυασµό µε το πρόγραµµα ifconfig. Με µια γρήγορη µατιά µέσω της γραµµής εντολών
που προσφέρει το BusyBox που υπάρχει στον Router NGW100 µπορούµε να πληροφορηθούµε για τις βασικές λειτουργίες του προγράµµατος route:
Εικόνα 41. Η εντολή route στον Router NGW100
Το ίδιο µπορούµε να κάνουµε και για το πρόγραµµα ifconfig:
Εικόνα 42. Η εντολή ifconfig στον Router NGW100
Από την άλλη, η δυναµική δροµολόγηση χρησιµοποιεί εξωτερικά πρωτόκολλα δροµολόγησης, όπως είναι τα OSPF και BGP, που βασίζονται σε περίπλοκους αλγόριθµους δροµολόγησης (πχ: αλγόριθµος Dijkstra), τα οποία ενηµερώνουν δυναµικά την RPDB αφού πρώτα
επικοινωνήσουν και ανταλλάξουν ορισµένες απαραίτητες πληροφορίες δροµολόγησης µε
γειτονικούς routers. Εποµένως είναι εύκολο κανείς να συµπεράνει ότι η στατική δροµολόγη-
Επικοινωνία: [email protected]
140
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
ση χρησιµοποιείται από οικιακούς routers ενώ η δυναµική, από τηλεπικοινωνιακούς παρόχους και εταιρείες µε προχωρηµένες απαιτήσεις δικτύωσης.
Η βάση FIB αναλυτικά
Στη βάση FIB αποθηκεύονται οι πληροφορίες δροµολόγησης, ενώ οι κανόνες FIB που αποτελούν και την πολιτική δροµολόγησης, χρησιµοποιούνται για την επιλογή ενός πίνακα δροµολόγησης όταν υπάρχουν περισσότεροι του ενός. Η βάση FIB είναι το βασικό εσωτερικό
σηµείο αποθήκευσης και αναζήτησης ενός πίνακα δροµολόγησης. Μπορεί να χρησιµοποιηθεί για τη δροµολόγηση εισερχοµένων αλλά και εξερχοµένων πακέτων. Η βάση FIB είναι αυτή η οποία παρέχει τη δυνατότητα σε εφαρµογές που βρίσκονται εκτός του Kernel να
ανακτήσουν πληροφορίες για δροµολογήσεις που πραγµατοποιούνται µέσα στον Kernel µέσω των sockets δροµολόγησης.
Σε ένα σύστηµα Linux υπάρχει δυνατότητα υποστήριξης πολλαπλών πινάκων FIB αλλά
από προεπιλογή υποστηρίζονται µόνο δύο. Ο τοπικός (local table) που περιέχει δροµολογήσεις τοπικών διευθύνσεων IP (και τη διεύθυνση loopback), και ο κύριος πίνακας (main table) περιέχει δροµολογήσεις προς εξωτερικά συστήµατα που βρίσκονται σε άλλα δίκτυα. Οι
δύο αυτοί πίνακες είναι προσβάσιµοι µέσω δύο global δεικτών. Και οι δύο δηλώνονται στο
αρχείο fib_frontend.c που βρίσκεται στον κατάλογο net/ipv4 του πηγαίου κώδικα του
Linux Kernel. Οι δηλώσεις αυτές είναι οι παρακάτω:
struct fib_table *ip_fib_local_table;
struct fib_table *ip_fib_main_table;
Σε περίπτωση που χρειάζεται να υπάρχουν πολλαπλοί πίνακες FIB, δηµιουργείται επίσης
και ένας πίνακας δεικτών FIB µε αρίθµηση από το 1 έως το 256 (FIB index). Ο πίνακας αυτός λειτουργεί ως ευρετήριο. Μπορούµε να αναφερόµαστε σε κάθε πίνακα δροµολόγησης
µέσω δύο διαφορετικών ID. Το ένα για τον πίνακα local και το άλλο για τον πίνακα
main.Τα οποία αποθηκεύονται στις δύο τελευταίες θέσεις του πίνακα. Επίσης υπάρχει και ο
πίνακας default για τον οποίο δεσµεύεται επίσης ένα ID. Αυτό µπορούµε να το δούµε µε
µεγαλύτερη λεπτοµέρεια και στο τµήµα κώδικα που ακολουθεί
/* Reserved table identifiers */
enum rt_class_t {
RT_TABLE_UNSPEC
=
0,
/* User defined values */
RT_TABLE_COMPAT
=
252,
RT_TABLE_DEFAULT =
253,
RT_TABLE_MAIN
=
254,
RT_TABLE_LOCAL
=
255,
RT_TABLE_MAX
=
0xFFFFFFFF /* 256 */
};
Οι τοποθεσίες των πινάκων FIB καθορίζονται στο αρχείο include/linux/rtnetlink.h.
Όταν κάποια εφαρµογή (πχ ένας daemon δροµολόγησης) δηµιουργεί δροµολογήσεις, αυτό
που κάνει ουσιαστικά είναι να περνά µηνύµατα σε κάποια FIB µέσω των netlink sockets. Καθώς δηµιουργείται µια νέα FIB, θα παίρνει τιµές µεταξύ του 1 και του 252:
struct fib_table *fib_tables[RT_TABLE_MAX+1]
Οι εσωτερικές δοµές µιας FIB είναι η fib_table, η fib_info και η fib_nh.
Ιστότοπος εργασίας: MyThesis.org
141
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Κλείνοντας την παράγραφο αυτή θα ασχοληθούµε λίγο περισσότερο µε την βάση FIB και τις
ιδιαιτερότητές της. Γνωρίζουµε ότι οι κανόνες FIB (net/ipv4/fib_rules.c) είναι µέρος
της FIB και όπως ήδη αναφέραµε, αποτελούν την πολιτική δροµολόγησης όταν υπάρχουν
πολλαπλοί πίνακες FIB. Ουσιαστικά κάθε πίνακας FIB λειτουργεί σαν ένας εικονικός router.
Πρακτικά λοιπόν, οι κανόνες FIB είναι ένας τρόπος επιλογής πινάκων FIB. Όταν έχουµε
πολλαπλές FIB οι πίνακες main και local συνεχίζουν να υφίστανται αλλά η προσπέλαση
των υπόλοιπων γίνεται µέσω πρόσβασης στους κανόνες FIB.
Μια βάση FIB αποτελείται από την δοµή fib_rule, τα στιγµιότυπα (instances) της δοµής
αυτής, και τις συναρτήσεις που χειρίζονται τη βάση των κανόνων. Τα στιγµιότυπα (default
rule, main_rule και local_rule) αφορούν την υλοποίηση ενός από τους τρεις βασικούς
πίνακες (default, main και local, αντίστοιχα). Επίσης, µερικές από τις συναρτήσεις είναι
η inet_rtm_delrule, η inet_rtm_newrule, η fib_rules_tclass, η fib_lookup
και η fib_select_default.
Η βάση FIB όπως και οι περισσότεροι µηχανισµοί του Linux, πρέπει να αρχικοποιηθεί µαζί
µε το πρωτόκολλο IPv4 πριν να είναι σε θέση να χρησιµοποιηθεί. Η αρχικοποίηση αυτή επιτυγχάνεται µέσω της συνάρτησης ip_fb_init (καθορίζεται στο αρχείο fib_frontend.c
το οποίο βρίσκεται στον κατάλογο net/ipv4). Η αρχικοποίηση του κάθε ξεχωριστού πίνακα
FIB γίνεται µέσω της συνάρτησης fib_hash_init.
Οι προγραµµατιστικές διεπαφές της FIB
Η βάση FIB παρέχει δύο προγραµµατιστικές διεπαφές για επικοινωνία µε τις εφαρµογές
επιπέδου χρήστη αλλά και µε τον Kernel. Όπως αναφέραµε και νωρίτερα, η επικοινωνία των
εφαρµογών χρήστη και των διάφορων daemons δροµολόγησης, επιτυγχάνεται µέσω της διεπαφής των netlink sockets. Γενικά στο Linux, όταν µια εφαρµογή δηµιουργεί ή καταργεί µια
δροµολόγηση, χρησιµοποιεί την δοµή rtmsg προκειµένου να στείλει αντίστοιχο µήνυµα δηµιουργίας ή διαγραφής µέσω ενός rtnetlink socket στη βάση FIB, η οποία εκτελείται σε
επίπεδο Kernel. Επίσης γίνεται χρήση της δοµής rtentry η οποία καθορίζεται στο αρχείο
include/linux/route.h.
Η διεπαφή της FIB προς τον Kernel έχει σκοπό να επιτρέψει σε κάποιες εσωτερικές συναρτήσεις του Kernel να προσπελαύνουν ορισµένες πληροφορίες δροµολόγησης που τους είναι
απαραίτητες. Αυτό συµβαίνει για παράδειγµα όταν το πρωτόκολλο IP πρέπει να εκτελέσει
κάποιες λειτουργίες δροµολόγησης ή όταν κάποια γνωστή δροµολόγηση πρέπει να µεταφερθεί στην route cache προκειµένου να µπορεί να επιταχυνθεί η ανάκτησή της.
4.3.2 ∆ροµολογητές και δροµολόγηση IP
Όπως γνωρίζουµε, δροµολόγηση είναι η απόφαση η οποία αφορά την διεύθυνση IP πού θα
προωθηθεί ένα πακέτο. Για το λόγο αυτό έχουν δηµιουργηθεί οι συσκευές router. Μια τέτοια
συσκευή είναι και ο Router NGW100.
Τα πακέτα που µπορεί να λάβει ο Router NGW100 χωρίζονται σε εισερχόµενα (incoming
traffic) και σε εξερχόµενα (outgoing traffic). Με τους όρους εισερχόµενα και εξερχόµενα εννοούµε πακέτα που προέρχονται από το WAN ή από το LAN αντίστοιχα.
Το πρωτόκολλο IP είναι υπεύθυνο επίσης και για µια σειρά άλλων ζητηµάτων όπως είναι
για παράδειγµα ο κατακερµατισµός και η ανακατασκευή (re-assembly) πακέτων που ξεπερνούν το µέγιστο επιτρεπτό µήκος (MTU) το οποίο καθορίζεται κάθε φορά από τους φυσικούς
περιορισµούς του υλικού µετάδοσης. Ένα άλλο ζήτηµα µε το οποίο ασχολείται το πρωτόκολ-
Επικοινωνία: [email protected]
142
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
λο IP είναι και ο χειρισµός του χρονικού ορίου µετάδοσης TTL (Time To Live) που εξασφαλίζει ότι ένα πακέτο δε θα δροµολογείται επ’ άπειρο µέσα στο Internet. Αν έχει επιλεγεί σε ένα
σύστηµα να υποστηρίζεται multicast µετάδοση τότε το IP συνεργάζεται µε το πρωτόκολλο
ICMP (ή το IGMP) προκειµένου αυτό να επιτευχθεί.
Όπως είπαµε νωρίτερα, δροµολόγηση είναι η απόφαση που αφορά το που θα σταλεί ένα
πακέτο. Αυτή η απόφαση βασίζεται στην διεύθυνση προορισµού (destination address) του
πακέτου. Φυσικά στο σύγχρονο κόσµο του Internet η δροµολόγηση µπορεί ορισµένες φορές
να είναι µια υπερβολικά περίπλοκη υπόθεση και να βασίζεται σε πολύ περισσότερες παραµέτρους από την διεύθυνση προορισµού. Οι παράµετροι αυτοί βρίσκονται στην κεφαλίδα (IP
header) που προσθέτει το πρωτόκολλο IP όταν ένα πακέτο εξέρχεται από το επίπεδο ∆ικτύου της στοίβας TCP/IP προς το Φυσικό επίπεδο.
∆ροµολόγηση εισερχόµενων πακέτων (LAN
WAN)
Όταν το πρωτόκολλο TCP στον Router NGW100, λάβει κάποια κλήση µέσω των sockets
accept ή connect για την παραλαβή ενός έγκυρου πακέτου, στέλνει µια αίτηση δροµολόγησης στο IP. Στη συνέχεια ο χειριστής εισερχοµένων πακέτων του IP αποφασίζει τι θα κάνει
µε αυτό. Υπάρχουν δύο στάδια κατά την απόφαση της δροµολόγησης. Το πρώτο στάδιο χαρακτηρίζεται ως σύντοµη διαδικασία δροµολόγησης (fast path routing) ενώ το δεύτερο ως
αργή διαδικασία δροµολόγησης (slow path routing). Κατά το πρώτο στάδιο γίνεται απλά ένας
έλεγχος στη route cache για να διαπιστωθεί αν η ίδια δροµολόγηση για το πακέτο που λήφθηκε είναι ήδη φορτωµένη λόγω κάποιας πρόσφατης χρήσης της. Αν δεν βρεθεί κάτι στη
route cache τότε εκτελείται το δεύτερο στάδιο που είναι πιο χρονοβόρο και κατά το οποίο ελέγχεται η βάση FIB.
Η συνάρτηση που χρησιµοποιείται στο πρώτο στάδιο είναι η ip_route_input και ορίζεται
στο αρχείο net/ipv4/route.c. Στο δεύτερο στάδιο, δηλαδή αν δεν βρεθεί εγγραφή στην
route cache, χρησιµοποιείται η συνάρτηση ip_route_input_slow. Η συνάρτηση αυτή καλείται από την ip_route_input.
∆ροµολόγηση εξερχόµενων πακέτων (LAN
WAN)
Όταν ο Router NGW100 λάβει ένα πακέτο καλεί το πρωτόκολλο IP προκειµένου να αποφασίσει που θα το προωθήσει. Αν το πακέτο αφορά το τοπικό δίκτυο τότε όλα είναι απλά και το
πακέτο προωθείται στην αντίστοιχη διεύθυνση υλικού MAC, που έχει χαρτογραφηθεί νωρίτερα από το πρωτόκολλο ARP (Address Resolution Protocol). Πρέπει να πούµε, ότι η προσθήκη της κεφαλίδας MAC σε κάθε πλαίσιο (frame) που δηµιουργείται, είναι ευθύνη του
driver δικτύωσης (στην περίπτωσή µας ο driver ονοµάζεται MACB). Το πρωτόκολλο IP χωρίς
να γνωρίζει τις πληροφορίες του κάθε πλαισίου απλά περνά ένα δείκτη προς τη διεύθυνση
προορισµού η οποία καταχωρείται στην RPDB.
Αν το πακέτο αφορά κάποια διεύθυνση που βρίσκεται εκτός LAN, καλείται και πάλι το πρωτόκολλο IP και στη συνέχεια το πακέτο αυτό προωθείται στο ανάλογο hardware interface
(WAN) για να µεταδοθεί στο ∆ιαδίκτυο. Tο IP θα πρέπει επίσης να αποφασίσει ποιο θα είναι
το επόµενο hop του πακέτου.
Σε περίπτωση που το επιλεγµένο πρωτόκολλο επικοινωνίας είναι το TCP, πριν την αποστολή του πακέτου εγκαθίσταται µια σύνοδος (session) µεταξύ του Router NGW100 και του
παραλήπτη. Αυτό επιτυγχάνεται µε την λεγόµενη τριπλή χειραψία (three way handshake) του
TCP. Το TCP καλεί το IP για τη διαδικασία της δροµολόγησης µόνο όταν κληθεί το socket µε
την ονοµασία connect, από κάποια εφαρµογή της περιοχής χρήστη. Το TCP κάνει χρήση
µόνο της route cache γιατί η δροµολογήσεις του είναι προκαθορισµένες.
Ιστότοπος εργασίας: MyThesis.org
143
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Αντίθετα το UDP δεν είναι βασισµένο στην σύνδεση. Έτσι ο Router NGW100 για κάθε πακέτο (datagram ή δεδοµενόγραµµα) UDP που έχει να στείλει, αιτείται εκ νέου την δροµολόγησή του από το IP.
Ανεξάρτητα από το εάν χρησιµοποιείται το πρωτόκολλο TCP ή το UDP για την επικοινωνία,
η κύρια συνάρτηση η οποία χειρίζεται και αποφασίζει για τις δροµολογήσεις των εξερχόµενων πακέτων, είναι η ip_route_connect και ορίζεται στο αρχείο include/net/route.h
. Επίσης η συνάρτηση ip_route_output_flow που ορίζεται στο αρχείο route.c (βρίσκεται στον κατάλογο net/ipv4), φροντίζει για µετατροπές της δροµολόγησης υπό κάποιες
συνθήκες (πχ αν γίνεται χρήση NAT).
Για το fast path των εξερχόµενων πακέτων (δηλαδή για δροµολόγηση µέσω της route
cache) χρησιµοποιείται η συνάρτηση __ip_route_output_key. Ενώ για το slow path (αναζήτηση στη FIB), η συνάρτηση ip_route_output_slow. Όπως και µε τις αντίστοιχες
συναρτήσεις της δροµολόγησης εισερχοµένων πακέτων ο ορισµός των συναρτήσεων που
αναφέραµε πραγµατοποιείται στο αρχείο net/ipv4/route.c.
Η κεφαλίδα IP
Στα πλαίσια αυτής της εργασίας, και µε τη βοήθεια του αναλυτή πακέτων Wireshark και της
εφαρµογής Putty, έγινε καταγραφή ενός πακέτου που στάλθηκε από τον Router NGW100
µέσω της εφαρµογής ping που υπάρχει ενσωµατωµένη στο BusyBox. Η εφαρµογή ping
βασίζεται στο πρωτόκολλο ICMP. Στην εικόνα που ακολουθεί µπορούµε να δούµε τα αιτήµατα ping καθώς και τα στατιστικά αποτελέσµατα:
Εικόνα 43. Η εντολή ping στον Router NGW100
Στη συνέχεια, όπως φαίνεται και στην εικόνα που ακολουθεί, επιλέγοντας το “Internet Protocol” µέσα από το Wireshark µπορούµε να δούµε όλες τις πληροφορίες της κεφαλίδας IP
ενός αιτήµατος (request) από τα τρία που στάλθηκαν συνολικά:
Επικοινωνία: [email protected]
144
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
Εικόνα 44. Ανάλυση κεφαλίδας IP µέσω του αναλυτή πακέτων Wireshark
Αν και η όλη διαδικασία πραγµατοποιήθηκε σε τοπικό επίπεδο, µπορούµε να διακρίνουµε
όλα τα σηµαντικά πεδία της κεφαλίδας IP. Η δροµολόγηση ενός πακέτου µπορεί να βασιστεί
στα περισσότερα από αυτά. Όπως είναι για παράδειγµα η διεύθυνση αποστολέα (source IP)
και το πεδίο ToS (Type of Service). Επίσης η δροµολόγηση µπορεί να βασιστεί στη διεπαφή
υλικού (πχ Ethernet, WiFi, MODEM κλπ). Σε πολλές περιπτώσεις µπορεί να µεσολαβεί NAT
(Network Address Translation) προκειµένου να αλλάζει δυναµικά η διεύθυνση των πακέτων
και να επιτυγχάνεται ασφαλής προώθηση πακέτων χωρίς να απαιτείται το άνοιγµα κάποιας
θύρας (port forwarding) του router.
Εκτός από το Wireshark ένα άλλο πολύ χρήσιµο εργαλείο ανάλυσης πακέτων και πρωτοκόλλων είναι το tcpdump το οποίο λειτουργεί σε περιβάλλον γραµµής εντολών και τις περισσότερες φορές βρίσκεται προεγκατεστηµένο σε κάθε έκδοση Linux.
Αποστολή και λήψη πακέτων µέσω του πρωτοκόλλου IP
Σε αυτή την παράγραφο, όπως και σε άλλες παραγράφους αυτής της εργασίας, δεν περιγράφεται ολόκληρος ο πηγαίος κώδικας αλλά παρατίθενται απλά οι κυριότερες συναρτήσεις
του καθώς και µια σύντοµη περιγραφή για την καθεµιά τους. Υπάρχουν πολύ αξιόλογα συγγράµµατα (στα αγγλικά) που αναλύουν λεπτοµερώς τον πηγαίο κώδικα ολόκληρης της στοίβας TCP/IP και οι τίτλοι κάποιων από αυτά, αναφέρονται και στη βιβλιογραφία αυτής της
εργασίας. Εδώ, θα ασχοληθούµε απλά µε τις συναρτήσεις που χρησιµοποιούνται για την
αποστολή πακέτων, την λήψη πακέτων µέσω του πρωτοκόλλου IP στο Linux. Επίσης θα α-
Ιστότοπος εργασίας: MyThesis.org
145
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
ναφέρουµε και τις συναρτήσεις που χρησιµοποιούνται για την προώθηση των πακέτων σε
υψηλότερα στρώµατα της στοίβας TCP/IP.
Η αποστολή πακέτων µέσω IP επιτυγχάνεται ουσιαστικά µέσω δύο συναρτήσεων. Οι συναρτήσεις αυτές είναι η ip_append_data και η ip_append_page. Χρησιµοποιούνται για
να ετοιµάσουν τα δεδοµένα που θα αποσταλούν καθώς και για την προώθησή των δεδοµένων αυτών στον driver δικτύωσης. Ορίζονται στο αρχείο net/ipv4/ip_output.c.
Η λήψη πακέτων µέσω του IP επιτυγχάνεται από έναν αριθµό συναρτήσεων που φροντίζουν να παραλάβουν πλαίσια από τον driver δικτύωσης και αφού τα επεξεργαστούν (και δεν
απορριφθούν) στην συνέχεια να τα προωθήσουν σε ανώτερα επίπεδα (αν αυτό κρίνεται απαραίτητο) µε την µορφή πακέτων. Για την λήψη χρησιµοποιούνται οι συναρτήσεις ip_rcv
και ip_rcv_finish.
Αφού ολοκληρωθεί και η λειτουργία της ip_rcv_finish, καλούνται διαδοχικά ακόµη δύο
συναρτήσεις προκειµένου να αποφασιστεί, τα πακέτα που παρελήφθησαν, σε ποια ανωτέρα
επίπεδα πρέπει να προωθηθούν. Οι συναρτήσεις αυτές όπως και όλες οι προηγούµενες, ορίζονται στο αρχείο net/ipv4/ip_output.c και είναι η ip_local_deliver που αποφασίζει το επίπεδο προώθησης, και η ip_local_deliver_finish φέρει εις πέρας όλα τα
υπόλοιπα.
4.4 Τα πρωτόκολλα ARP, ICMP και IGMP
Αν και δεν κρίνεται απαραίτητο για τους σκοπούς αυτής της εργασίας, είναι καλό να µιλήσουµε για τρία πρωτόκολλα που παίζουν σηµαντικό στην δικτύωση υπολογιστικών συστηµάτων και δη ενός ενσωµατωµένου συστήµατος Linux όπως είναι ο Router NGW100. Αυτό θα
µας βοηθήσει να έχουµε µια πιο πλήρη εικόνα του τι πραγµατικά συµβαίνει στον πηγαίο κώδικα της δικτύωσης και δροµολόγησης που παρέχει το Linux.
4.4.1 ARP
Γενικά το πρωτόκολλο ARP αντιστοιχίζει λογικές διευθύνσεις IP σε διευθύνσεις υλικού MAC
και έχει δηµιουργηθεί για να χρησιµοποιείται από το πρωτόκολλο Ethernet σε τοπικά δίκτυα
LAN. Όταν πρόκειται να µεταδοθεί ένα πακέτο η κατάλληλη ρουτίνα εξόδου, του προσθέτει
την απαιτούµενη επικεφαλίδα η οποία αντιπροσωπεύει το φυσικό επίπεδο (ή το επίπεδο
γραµµής δεδοµένων, στο OSI). Για να επιτευχθεί όµως κάτι τέτοιο, ο αποστολέας θα πρέπει
να διαθέτει στη µνήµη του ένα πίνακα που θα περιλαµβάνει την IP του παραλήπτη η οποία
θα είναι αντιστοιχισµένη µε την διεύθυνση MAC του παραλήπτη. Ο πίνακας αυτός ονοµάζεται
ARP cache. Αν η αναζήτηση στην ARP cache δεν έχει αποτέλεσµα, τότε πιθανόν ο παραλήπτης δεν έχει χαρτογραφηθεί ακόµα. Έτσι, στέλνεται ένα αίτηµα ARP προς όλα (broadcast)
τα συνδεδεµένα συστήµατα του LAN. Όταν επιστραφεί απάντηση τότε ενηµερώνεται αυτόµατα και η ARP cache.
Η υλοποίηση του TCP/IP στο Linux απαιτεί να υπάρχουν και η ARP cache αλλά και ο πίνακας δροµολόγησης που αναφέραµε νωρίτερα. Ο πηγαίος κώδικας του ARP βρίσκεται στο
αρχείο net/ipv4/arp.c.
Η αρχικοποίηση του ARP αφορά κάποιες δοµές δεδοµένων οι οποίες αρχικοποιούνται κατά
τη διάρκεια της µεταγλώττισης του Kernel και όχι κατά την εκκίνησή του. Οι δοµές αυτές είναι
οι παρακάτω:
arp_packet_type
Επικοινωνία: [email protected]
146
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
arp_netdev_notifier
arp_init
arp_table
arp_generic_ops
arp_hh_ops
arp_direct_opts
arp_broken_arps
Όπως και κάθε άλλο πρωτόκολλο που ανήκει σε οικογένεια πρωτοκόλλων, το ARP διαθέτει
µια συνάρτηση λήψης πακέτων. Η συνάρτηση αυτή είναι η arp_rcv. Επίσης διαθέτει και µια
συνάρτηση για την επεξεργασία των πακέτων που λαµβάνει, την arp_process.
4.4.2 ICMP
Το πρωτόκολλο ICMP (Internet Control Message Protocol) χειρίζεται πολλές λειτουργίες
του IPv4 µε αποτέλεσµα να θεωρείται σε αρκετές περιπτώσεις, τµήµα του πρωτοκόλλου IP.
Τα µηνύµατα ICMP µεταφέρονται µέσα σε πακέτα IP. Η πιο γνωστή χρήση του πρωτοκόλλου
ICMP είναι µέσω της λειτουργίας ping (Packet Internet Groper) κατά την οποία στέλνονται
πακέτα αιτηµάτων που λειτουργούν σαν την ηχώ (echo request) και επιστρέφουν στον αποστολέα τους πολλαπλές φορές µε την µορφή απαντήσεων (echo reply ή pong). Αυτό γίνεται
για να είµαστε σε θέση να διαπιστώνουµε αν κάποιο σύστηµα είναι συνδεδεµένο και διαθέσιµο στο τοπικό δίκτυο ή στο Internet. Υπάρχουν διάφοροι τύποι πακέτων ICMP, καθένας εκ
των οποίων χρειάζεται διαφορετική αντιµετώπιση και επεξεργασία. Το πρωτόκολλο ICMP
στο Linux ορίζεται στο αρχείο net/ipv4/icmp.c.
Για τον χειρισµό των πακέτων που λαµβάνονται το ICMP διαθέτει την δοµή
icmp_control. Επίσης, στο αρχείο include/linux/icmp.h περιλαµβάνονται εκτός των
άλλων και οι τύποι µηνυµάτων του ICMP. Το τµήµα αυτό είναι το ακόλουθο:
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
ICMP_ECHOREPLY
ICMP_DEST_UNREACH
ICMP_SOURCE_QUENCH
ICMP_REDIRECT
ICMP_ECHO
ICMP_TIME_EXCEEDED
ICMP_PARAMETERPROB
ICMP_TIMESTAMP
ICMP_TIMESTAMPREPLY
ICMP_INFO_REQUEST
ICMP_INFO_REPLY
ICMP_ADDRESS
ICMP_ADDRESSREPLY
0
3
4
5
8
11
12
13
14
15
16
17
18
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
Echo Reply
Destination Unreachable
Source Quench
Redirect (change route)
Echo Request
Time Exceeded
Parameter Problem
Timestamp Request
Timestamp Reply
Information Request
Information Reply
Address Mask Request
Address Mask Reply
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
Για τον χειρισµό και τη λειτουργία του ICMP υπάρχουν εξειδικευµένες συναρτήσεις οι οποίες ορίζονται επίσης στο αρχείο net/ipv4/icmp.c. Οι κυριότερες από αυτές είναι η
icmp_rcv, η icmp_unreach, η icmp_redirect, η icmp_echo και η icmp_timestamp.
Για την αποστολή πακέτων ICMP χρησιµοποιούνται οι συναρτήσεις icmp_reply και
icmp_push_reply.
4.4.3 IGMP
Το πρωτόκολλο IGMP (Internet Group Management Protocol) υπάρχει για να ανταλλάσσει
µηνύµατα διαχείρισης δροµολόγησης πολλαπλών παραληπτών (multicast routing) και µετάδοσης µηνυµάτων. Ουσιαστικά ο σκοπός του είναι να αντιστοιχίσει µια οµάδα διευθύνσεων
Ιστότοπος εργασίας: MyThesis.org
147
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
(unicast) σε µια διεύθυνση (multicast) κλάσης D. Η ανταλλαγή πληροφοριών που αφορούν
αυτές τις διευθύνσεις γίνεται ανάµεσα σε συστήµατα που βρίσκονται συνδεδεµένα στο δίκτυο
και σε routers.
Υπάρχουν τρεις εκδόσεις του πρωτοκόλλου IGMP. Η έκδοση 1, η 2 και η 3. Κάθε έκδοση
επιτυγχάνει το δικό της συγκεκριµένο σκοπό.
Επειδή το Linux δεν υποστηρίζει αυτόµατη ενηµέρωση των πινάκων δροµολόγησης κατά τη
λήψη αναφορών IGMP, έτσι ώστε να µπορεί να πραγµατοποιηθεί δροµολόγηση multicast,
γράφονται ειδικές εφαρµογές προκειµένου κάτι τέτοιο να είναι δυνατό. Μία από τις πιο γνωστές είναι και η εφαρµογή mrouted.
Για τη λειτουργία του πρωτοκόλλου IGMP στο Linux, γίνεται χρήση δύο δοµών δεδοµένων.
Της ip_mreqn (αίτηση για multicast) που ορίζεται στο αρχείο include/linux/in.h και
της ip_mc_socklist (multicast socket list) η οποία ορίζεται στο αρχείο igmp.h που βρίσκεται στον ίδιο κατάλογο.
Επίσης χρησιµοποιούνται και κάποιες συναρτήσεις για την υλοποίηση συγκεκριµένων διεργασιών λήψης όπως η igmp_rcv (κύρια συνάρτηση λήψης), η igmp_heard_query (επεξεργασία εισερχόµενων αιτηµάτων), η igmp_heard_report (ελέγχει για εισερχόµενες
αναφορές IGMP). Οι συναρτήσεις αυτές ορίζονται στο αρχείο net/ipv4/igmp.c.
Τέλος, για την προσθήκη οµάδων διευθύνσεων αλλά και για την έξοδο από αυτές, υπάρχουν οι συναρτήσεις ip_mc_join_group και ip_mc_leave_group αντίστοιχα.
4.5 Οδηγοί δικτύου
Μέχρι στιγµής έχουµε ασχοληθεί µε την υλοποίηση του TCP/IP στον Linux Kernel και τον
τρόπο επικοινωνίας του επιπέδου εφαρµογής µε τα επίπεδα µεταφοράς και δικτύου µέσω
της διεπαφής socket. Επίσης αναφέραµε ότι τα πρωτόκολλα επιπέδου δικτύου που είναι
γνωστά ως χειριστές πακέτων (packet handlers), είναι το σηµείο “συγκόλλησης” του πρωτοκόλλου TCP/IP µε το υλικό δικτύωσης. ∆ηλαδή µε τους οδηγούς των ολοκληρωµένων που
έχουν γραφτεί έτσι ώστε να µεταφέρονται πακέτα από το φυσικό επίπεδο στο επίπεδο δικτύου.
Σε προηγούµενο κεφάλαιο είχαµε ασχοληθεί µε τις συσκευές για τις οποίες γράφονται οδηγοί στο Linux και τις είχαµε κατατάξει σε τρεις κλάσεις εκ των οποίων η µία είναι οι διεπαφές
δικτύου (network interfaces). Επίσης είχαµε χωρίσει τους οδηγούς συσκευών σε τρία είδη, εκ
των οποίων το ένα είναι οι οδηγοί δικτύου (network drivers). Αν συνδυάσουµε τις έννοιες διεπαφή δικτύου και οδηγός δικτύου, βγάζουµε έναν ακόµη πιο ακριβή όρο που είναι ο οδηγός
διεπαφής δικτύου (network interface driver). Αυτό µας δείχνει ότι ουσιαστικά, εκτός από την
διεπαφή socket που παρέχεται “πάνω” από τον Kernel για τις εφαρµογές, παρέχεται επίσης
και µια διεπαφή “κάτω” από αυτόν, για τους οδηγούς δικτύου.
Σε αυτή την ενότητα θα αναφερθούµε πολύ συνοπτικά στους οδηγούς δικτύου και στην διεπαφή για την ανάπτυξη οδηγών δικτύου που παρέχει ο Linux Kernel. Όλα αυτά θα βοηθήσουν στην καλύτερη κατανόηση του οδηγού δικτύου MACB, του Router NGW100.
4.5.1 H διεπαφή δικτύου
Όπως έχουµε ήδη πει, η διεπαφή δικτύου είναι η τρίτη κλάση συσκευών του Linux. Ο ρόλος
της είναι παρόµοιος µε εκείνον µιας συσκευής block η οποία καταχωρεί τις συσκευές αποθήκευσης για τις οποίες είναι υπεύθυνη, έτσι ώστε στη συνέχεια να στέλνει και να λαµβάνει δε-
Επικοινωνία: [email protected]
148
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
δοµένα µε τη µορφή blocks. Η διεπαφή δικτύου θα πρέπει αρχικά να είναι σε θέση να καταχωρήσει τον εαυτό της µέσω συγκεκριµένων δοµών δεδοµένων του Kernel, προκειµένου στη
συνέχεια να είναι σε θέση να συµµετέχει στην λήψη και την αποστολή πακέτων στο τοπικό
δίκτυο ή στο Internet.
Η κυριότερη διαφορά µιας συσκευής αποθήκευσης µε µια διεπαφή δικτύου είναι ότι ενώ ένας σκληρός δίσκος για παράδειγµα, βρίσκεται καταχωρηµένος στον κατάλογο /dev, µια
διεπαφή δικτύου δεν παρέχει τέτοιο σηµείο πρόσβασης. Εποµένως σε αυτή την περίπτωση
δεν ισχύει και ο κανόνας, ότι τα πάντα στο Linux είναι αρχεία, καθώς σε µια διεπαφή δικτύου
δεν υπάρχουν εγγραφές, αναγνώσεις ή άλλου είδους ενέργειες οι οποίες συνήθως χαρακτηρίζουν ένα αρχείο. Μια άλλη σηµαντική διαφορά είναι ότι ένας οδηγός block απαντά µόνο σε
κλήσεις που προέρχονται από τον Kernel, ενώ ένας οδηγός δικτύου λαµβάνει (ασύγχρονα)
πακέτα από το δίκτυο.
4.5.2 Ανάπτυξη οδηγού δικτύου
Οι οδηγοί δικτύου θα πρέπει να είναι σχεδιασµένοι έτσι ώστε να µπορούν να υποστηρίξουν
ένα σύνολο εργασιών διαχείρισης. Μερικές από αυτές είναι και ο καθορισµός της διεύθυνσης
IP του συστήµατος, η τροποποίηση των παραµέτρων επικοινωνίας, και η διατήρηση στατιστικών (statistics) που αφορούν την κίνηση εισερχόµενων και εξερχόµενων πακέτων αλλά
και τα σφάλµατα κατά τη µετάδοση ή τη λήψη.
Όταν ξεκινάµε την ανάπτυξη ενός οδηγού δικτύου µπορούµε να χρησιµοποιήσουµε ορισµένα έτοιµα παραδείγµατα από ήδη υλοποιηµένους οδηγούς, όπως είναι ο εικονικός οδηγός
loopback.c που ουσιαστικά δεν υποστηρίζει κάποια πραγµατική συσκευή αλλά τον προσαρµογέα localhost, και ο οδηγός e100.c που αφορά µια γενική υλοποίηση για το
100Mbps Ethernet. Τις περισσότερες φορές βέβαια οι οδηγοί είτε γράφονται από την κοινότητα ανοικτού κώδικα του Linux είτε από τους κατασκευαστές των µικροελεγκτών και των
Ethernet PHY chips (η όποιου άλλου φυσικού πρωτοκόλλου επικοινωνίας χρησιµοποιείται).
Αυτό ισχύει και για την περίπτωση του Router NGW100 και τον οδηγό µε την ονοµασία
MACB ο οποίος έχει γραφτεί για τον µικροελεγκτή AP7000 και τους δύο ελεγκτές Ethernet
(MACB0 και MACB1) που υπάρχουν στο σύστηµα οι οποίοι περιγράφονται στο πρακτικό µέρος της εργασίας καθώς και σε αντίστοιχο datasheet.
4.5.3 Ο οδηγός δικτύου MACB
Ο οδηγός δικτύου MACB (ΠΑΡΑΡΤΗΜΑ B) αναπτύχθηκε ειδικά για το υποσύστηµα του ελεγκτή Ethernet (MACB Interface) που διαθέτει ο µικροελεγκτής AP7000. Μέσω του οδηγού
MACB, ο AP7000 επικοινωνεί µε τη στοίβα TCP/IP του Kernel αλλά και µε το επίπεδο
Socket. Στη συνέχεια, µέσω του ολοκληρωµένου DP83848I που χειρίζεται τις φυσικές απαιτήσεις (PHY) του πρωτοκόλλου IEEE 802.3, επικοινωνεί µε το δίκτυο, προκειµένου να δροµολογεί τα πακέτα των υπολογιστικών συστηµάτων µε τα οποία συνδέεται άµεσα ή έµµεσα
(πχ µέσω switch).
Ορισµένες πολύ πρακτικές υπηρεσίες οι οποίες παρέχονται στον συγκεκριµένο οδηγό δικτύου είναι και οι παρακάτω:
NAPI (New API)
ethtool API
Στατιστικά
Promiscuous mode
Ιστότοπος εργασίας: MyThesis.org
149
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Έλεγχος σφαλµάτων
NAPI
Το NAPI είναι µια τροποποίηση του µηχανισµού επεξεργασίας πακέτων του οδηγού δικτύου
MACB. Σχεδιάστηκε για να βελτιώνει την απόδοση του Router NGW100 σε δίκτυα υψηλών
ταχυτήτων. Αυτό επιτυγχάνεται µέσω δύο µηχανισµών:
Ελαχιστοποίηση διακοπών (interrupt mitigation): Στα δίκτυα υψηλών ταχυτήτων δηµιουργούνται χιλιάδες διακοπές λόγω λήψης ή αποστολής πακέτων. Εποµένως για κάθε ένα πακέτο θα µπορούσε να προκύπτει µια ξεχωριστή διαδικασία ενεργοποίησης
και απενεργοποίησης διακοπής µε αποτέλεσµα να απαιτείται µεγάλη επεξεργαστική
ισχύς και να δηµιουργούνται καθυστερήσεις που πολλές φορές οδηγούν ακόµη και
στην αναγκαστική απόρριψη πακέτων. Το NAPI αποτρέπει την ύπαρξη αυτών των
συνθηκών µε το να χειρίζεται µε πιο έξυπνο τρόπο τις διακοπές. Αυτό το πετυχαίνει
χρησιµοποιώντας την µέθοδο Polling κατά την οποία ελέγχει περιοδικά για την έλευση νέων πακέτων. Η µέθοδος αυτή ενεργοποιείται µόνο αν προκύψει υπερφόρτωση,
διαφορετικά χρησιµοποιείται ο βασικός µηχανισµός στον οποίο όπως γνωρίζουµε, για
κάθε πακέτο προκύπτει και µια διακοπή.
Μπλοκάρισµα πακέτων (packet throttling): Όταν το σύστηµα υπερφορτώνεται και
πρέπει αναγκαστικά να απορρίψει πακέτα είναι προτιµότερο αυτό να συµβεί πριν αρχίσει καν η επεξεργασία τους ώστε να εξοικονοµηθούν κύκλοι επεξεργασίας του µικροελεγκτή. Το σύστηµα µπλοκαρίσµατος πακέτων κάνει ακριβώς αυτή την δουλειά.
Εµποδίζει τα πακέτα από το να φτάσουν στη στοίβα TCP/IP όταν υπάρχει υπερφόρτωση και τα απορρίπτει άµεσα χωρίς καµία επεξεργασία.
ethtool API
Η διεπαφή ethtool χρησιµοποιείται σε επίπεδο εφαρµογής, µέσω γραµµής εντολών για την
παρουσίαση ή την τροποποίηση των παραµέτρων του υποσυστήµατος υλικού δικτύωσης,
γνωστό στους υπολογιστές και ως NIC (Network Interface Card ή Network adapter ή LAN
adapter). Στην περίπτωση του Router NGW100 το αντίστοιχο υποσύστηµα δικτύωσης ονοµάζεται Ethernet controller και είναι ενσωµατωµένο στον µικροελεγκτή AP7000.
Παρ’ όλα αυτά στον Router NGW100 χρησιµοποιείται το πρόγραµµα ifconfig καθώς υπάρχει ήδη ενσωµατωµένο στο BusyBox. Η εντολή ethtool δεν είναι ενεργοποιηµένη εξ
αρχής αλλά µπορεί αν χρειαστεί να ενεργοποιηθεί εκ των υστέρων.
Στατιστικά
Ο οδηγός MACB κατά την αποστολή και τη λήψη πακέτων διατηρεί στατιστικά στοιχεία τα
οποία ορίζονται ως ένα σύνολο πεδίων στη δοµή δεδοµένων macb_stats που υπάρχει στο
αρχείο κεφαλής macb.h:
rx_pause_frames
tx_ok
tx_single_cols
tx_multiple_cols
rx_ok
rx_fcs_errors
rx_align_errors
Επικοινωνία: [email protected]
150
∆ικτύωση και ∆ροµολόγηση στα ενσωµατωµένα συστήµατα Linux – Κεφάλαιο 4
tx_deferred
tx_late_cols
tx_excessive_cols
tx_underruns
tx_carrier_errors
rx_resource_errors
rx_overruns
rx_symbol_errors
rx_oversize_pkts
rx_jabbers
rx_undersize_pkts
sqe_test_errors
rx_length_mismatch
tx_pause_frames
Ο κώδικας του οδηγού, σχεδόν σε κάθε συµβάν που προκύπτει από την επικοινωνία του
Router NGW100 µε το δίκτυο, τροποποιεί την τιµή του αντίστοιχου στατιστικού στοιχείου (πεδίου) και ταυτόχρονα παρέχει ένα µηχανισµό µετάδοσης αυτών των στοιχείων προς τις εφαρµογές του χρήστη. Έτσι, µπορεί για παράδειγµα µια εφαρµογή να ρωτήσει τον οδηγό
δικτύου και να ενηµερωθεί για το ποσοστό των πακέτων που λήφθηκαν, που στάλθηκαν,
που απορρίφθηκαν κλπ.
Promiscuous mode
Με αυτό τον µηχανισµό ο Router NGW100 µπορεί να αναλύει τα µη κρυπτογραφηµένα δεδοµένα όλων των πακέτων του δικτύου που δροµολογεί, είτε τον αφορούν είτε όχι (packet
sniffing). Τα δεδοµένα αυτά µπορούν να επεξεργαστούν αργότερα και από κάποια εφαρµογή
η οποία µπορεί να βρίσκεται ακόµα και σε κάποιο άλλο σύστηµα του δικτύου. Φυσικά το σύστηµα αυτό θα πρέπει να έχει τα απαραίτητα δικαιώµατα.
Ο τύπος λειτουργίας Promiscuous mode µπορεί επίσης να φανεί χρήσιµος σε περιπτώσεις
που θέλουµε να γεφυρώσουµε (bridge) δύο διαφορετικά δίκτυα η να κάνουµε διαγνωστικούς
ελέγχους σύνδεσης.
Έλεγχος σφαλµάτων
Ο οδηγός MACB είναι σε θέση να ελέγχει για σφάλµατα στα πλαίσια που λαµβάνει µέσω
ελέγχων CRC (Cyclic Redundancy Check), ελέγχων υπερβολικού µήκους πλαισίου, ακατάλληλων πλαισίων κλπ.
Ό έλεγχος σφαλµάτων σε τόσο χαµηλό επίπεδο βοηθά στο να µην απασχολείται η CPU του
µικροελεγκτή AP7000, αφού ένα πλαίσιο που παρουσιάζει σφάλµατα δεν θα προωθηθεί στα
ανώτερα επίπεδα της στοίβας TCP/IP. Έτσι εξοικονοµείται χρόνος και αποφεύγονται περιττοί κύκλοι επεξεργασίας.
Όλες οι παραπάνω υπηρεσίες του οδηγού χρησιµοποιούνται από εφαρµογές προκειµένου
να δώσουν στον χρήστη τη δυνατότητα να διαχειρίζετια τις διεπαφές δικτύου Ethernet. Ένα
τέτοιο παράδειγµα είναι και η εφαρµογή ethtool που θα εξετάσουµε στο πρακτικό µέρος αυτής της εργασίας.
Ιστότοπος εργασίας: MyThesis.org
151
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
4.6 Απόδοση δικτύωσης του µικροελεγκτή AP7000
Για να ελέγξουµε την απόδοση του Router NGW100 θα πρέπει να εξετάσουµε την απόδοση
του µικροελεγκτή AP7000 κατά την επεξεργασία πακέτων. Για το λόγο αυτό χρειαζόµαστε
ένα πρόγραµµα που θα εκτελείται στο επίπεδο εφαρµογής περιβάλλοντος χρήστη (user
space), και το οποίο θα είναι σε θέση να επικοινωνεί µε τον οδηγό δικτύου που αναπτύξαµε.
Ένα πολύ απλό και γνωστό πρόγραµµα είναι και το iperf.
Το iperf είναι ουσιαστικά ένα εργαλείο µέτρησης εύρους ζώνης. Μπορεί να επικοινωνεί
µέσω των πρωτοκόλλων TCP και UDP αλλά χρησιµοποιείται και για αξιολόγηση του φυσικού
επιπέδου (που στην περίπτωσή µας είναι ο οδηγός δικτύου).
Ο πιο συνηθισµένος τρόπος χρήσης του iperf είναι να εκτελείται ταυτόχρονα σε δύο διαφορετικά συνδεδεµένα υπολογιστικά συστήµατα και στο ένα να λειτουργεί ως server ενώ στο
άλλο, ως client. Αν θέλουµε για παράδειγµα να ελέγξουµε την απόδοση λήψης πακέτων (Rx)
του AP7000 και του οδηγού δικτύου MACB εκτελούµε στη γραµµή εντολών του Router
NGW100 την παρακάτω εντολή:
iperf –s
Ενώ σε κάποιο άλλο σύστηµα (πχ το σύστηµα host) που βρίσκεται συνδεδεµένο µε τον
Router NGW100, εκτελούµε την εντολή:
iperf –c <IP του Router NGW100>
Μετά από αυτή την εκτέλεση ο Router NGW100 που θα λειτουργεί σαν server θα λάβει για
περίπου 10 δευτερόλεπτα, ένα σύνολο πακέτων από το άλλο σύστηµα και όταν αυτή η διαδικασία ολοκληρωθεί, θα εµφανιστούν τα στατιστικά αποτελέσµατα της επικοινωνίας τους. Αν
θέλουµε να εξετάσουµε την απόδοση της αποστολής πακέτων απλά αντιστρέφουµε τις δύο
εντολές και ο Router NGW100 συµπεριφέρεται πλέον ως server.
Επικοινωνία: [email protected]
152
ΠΡΑΚΤΙΚΟ ΜΕΡΟΣ
Εισαγωγή πρακτικού µέρους
Στο θεωρητικό µέρος της εργασίας, παρουσιάστηκε το ελάχιστο θεωρητικό υπόβαθρο που
αφορά τα ενσωµατωµένα συστήµατα Linux. Tα θέµατα που µας απασχόλησαν ήταν τα ακόλουθα:
Ανάπτυξη ενσωµατωµένων συστηµάτων Linux
Εργαλεία ανάπτυξης ενσωµατωµένων συστηµάτων Linux
Το υλικό που υποστηρίζει το ενσωµατωµένο Linux
Η δροµολόγηση στο Linux µέσω της ενσωµατωµένης στοίβας TCP/IP
Όλα τα παραπάνω θα είναι χρήσιµα σαν σηµεία αναφοράς κατά τη διάρκεια του πρακτικού
µέρους. Έτσι, θα υπάρχει η δυνατότητα να αναφέρονται κάποιες βασικές θεωρητικές έννοιες
χωρίς να χρειάζεται να εξηγούνται εκ νέου.
Στο πρακτικό µέρος της παρούσας εργασίας και στα κεφάλαια που θα ακολουθήσουν, θα
αναλυθούν τα στοιχεία του υλικού και του λογισµικού από τα οποία αποτελείται ο Router
NGW100. Τα θέµατα που θα µας απασχολήσουν είναι:
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100
Προγραµµατισµός και εκκίνηση του Router NGW100
Οι εφαρµογές του Router NGW100
ΚΕΦΑΛΑΙΟ
5
Ηλεκτρικά και ηλεκτρονικά
χαρακτηριστικά του Router NGW100
Εισαγωγή
Σε αυτό το κεφάλαιο θα παρουσιαστεί το υλικό του Router NGW100 το οποίο απαρτίζεται
από τρία κύρια µέρη:
Ηλεκτρονικά στοιχεία
Ηλεκτρικά στοιχεία
Πλακέτα τυπωµένου κυκλώµατος PCB
Ειδικότερα τα θέµατα που θα αναλυθούν είναι τα παρακάτω:
Περιγραφή και λογικό διάγραµµα του Router NGW100
Ο µικροελεγκτής AP7000
∆ιαθέσιµη µνήµη
Ethernet PHY και MAC
Συνδεσιµότητα RS232
Ελεγκτής πλακέτας – Board Controller
∆ιεπαφές προγραµµατισµού JTAG και NEXUS
Σύστηµα χρονισµού
Κύκλωµα επαναφοράς (reset)
Σύστηµα τροφοδοσίας
∆ιαστάσεις πλακέτας
Σχέδιο συναρµολόγησης
Σχηµατικά και PCB του Router NGW100
Επέκταση δυνατοτήτων υλικού
5.1 Περιγραφή και λογικό διάγραµµα του Router NGW100
Ξεκινώντας µε την παρουσίαση των ηλεκτρικών και ηλεκτρονικών στοιχείων του Router
NGW100 θα παραθέσουµε πρώτα τα βασικότερα χαρακτηριστικά του:
Μικροελεγκτής AP7000 32bit
∆ύο θύρες Ethernet
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
32MB SDRAM
16MB on-board flash
∆υνατότητα επέκτασης της µνήµης µέσω SD ή MMC καρτών µνήµης
Θύρα USB
JTAG για debugging και για προγραµµατισµό της µνήµης flash
Υποδοχές επέκτασης (expansion connectors) µε 63 IOs γενικού σκοπού ή σύνδεσης
περιφερειακών του µικροελεγκτή AP7000
Σύστηµα τροφοδοσίας και LED ενδείξεων κατάστασης του Router
∆ύο LED που µπορούν να είναι προσβάσιµα από τον προγραµµατιστή µέσω λογισµικού
Σε αυτό το σηµείο θα πρέπει να πούµε ότι στο εξής όταν περιγράφουµε κάποιο στοιχείο του
συστήµατός µας, όπου είναι απαραίτητο, θα προτιµάται έναντι της ελληνικής, η αγγλική ορολογία, µιας και αυτή έχει επικρατήσει και χρησιµοποιείται περισσότερο από τις εταιρείες και
τους οργανισµούς παγκόσµια. Τόσο στην ανάπτυξη λογισµικού όσο και στην ανάπτυξη υλικού.
Πριν παραθέσουµε το µπλοκ διάγραµµα του Router NGW100 ας πούµε µερικά πράγµατα
για τη λίστα των χαρακτηριστικών που είδαµε πιο πριν. Ο Router NGW100 είναι ένα πλήρες
ενσωµατωµένο υπολογιστικό σύστηµα. ∆ιαθέτει µονάδα τροφοδοσίας µε επιτρεπόµενη είσοδο τάση από 9 έως 15 Volt DC. Οι µετατροπείς DC/DC που βρίσκονται ενσωµατωµένοι (on
board) στο PCB, δηµιουργούν την κατάλληλη τάση για την λειτουργία του µικροελεγκτή αλλά
και για όλο το υπόλοιπο σύστηµα. Οπότε οποιοδήποτε τροφοδοτικό πρίζας, ικανοποιεί αυτά
τα χαρακτηριστικά είναι κατάλληλο. Θα αναλύσουµε περεταίρω το σύστηµα τροφοδοσίας σε
αντίστοιχη παράγραφο του κεφαλαίου αυτού.
Ο Router NGW100 διαθέτει 16MB συνολική µνήµη Flash και 32MB SDRAM. Η µνήµη µπορεί να επεκταθεί µέσω της θύρας SD/MMC µε τη χρήση καρτών µνήµης SD (µέχρι και 2GB)
ή MMC. Μέσω αυτών των µνηµών µπορούµε να µεταφέρουµε εύκολα δεδοµένα από το σύστηµα host (δηλαδή τον υπολογιστή µας) στο target σύστηµα (δηλαδή στον Router
NGW100), χωρίς να χρειαζόµαστε κάποιο καλώδιο. Μπορούµε ακόµα και να ρυθµίσουµε τον
bootloader να εκκινεί το Linux από µια τέτοια κάρτα.
Οι διαθέσιµες διεπαφές επικοινωνίας (communication interfaces) του Router NGW100 είναι
τρεις. Η σειριακή διεπαφή RS232 είναι κατάλληλη για χαµηλού επιπέδου (low level) debugging, όπως είναι για παράδειγµα η επικοινωνία µας µε τον bootloader. Η διεπαφή Ethernet
που είναι και η πιο σηµαντική για τη λειτουργία του συστήµατος ως Router, δίνει δυνατότητες
δροµολόγησης των πακέτων των υπολογιστών που συνδέονται στην θύρα LAN του Router,
τόσο στο τοπικό δίκτυο όσο και σε αποµακρυσµένα δίκτυα, µέσω της θύρας WAN. Επίσης,
µας δίνεται η δυνατότητα επικοινωνίας µε τον NGW100 µέσω FTP, SSH, TELNET και άλλων
πρωτοκόλλων επικοινωνίας. Τέλος η θύρα USB δίνει επιπλέον δυνατότητες συνδεσιµότητας
και επιτρέπει πιο εύκολη παραµετροποίηση του Router NGW100 από τους χρήστες του
(στην παρούσα εργασία δεν αναπτύχθηκε η USB επικοινωνία αλλά θα µπορούσε να αποτελέσει µια µελλοντική προσθήκη).
Πριν ξεκινήσουµε την ανάλυση του Router ας δούµε το µπλοκ διάγραµµα (block diagram)
της πλακέτας του (τα αχνά σηµεία δεν έχουν συγκολληθεί):
Ιστότοπος εργασίας: MyThesis.org
155
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 45. Μπλοκ διάγραµµα του υλικού του Router NGW100
Επικοινωνία: [email protected]
156
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
5.2 Ο µικροελεγκτής AP7000
Το κυριότερο στοιχείο του Router είναι η Κεντρική Μονάδα Επεξεργασίας του, δηλαδή ο µικροελεγκτής AP7000. Μέσα στο κείµενό µας όταν θα λέµε µικροελεγκτής ή microcontroller, ή
CPU, ή µικροελεγκτής, θα εννοούµε πάντα τον AP7000.
Τα κυριότερά του χαρακτηριστικά όπως αυτά αναφέρονται στο συνοδευτικό datasheet της
κατασκευάστριας εταιρείας, είναι τα ακόλουθα:
Interrupt Controller
– Individually maskable Interrupts
– Each interrupt request has a programmable priority and autovector address
System Functions
– Power and Clock Manager
– Crystal Oscillator with Phase-Lock-Loop (PLL)
– Watchdog Timer
– Real-time Clock
6 Multifunction timer/counters
– Three external clock inputs, I/O pins, PWM, capture and various counting
capabilities
4 Universal Synchronous/Asynchronous Receiver/Transmitters (USART)
– 115.2 kbps IrDA Modulation and Demodulation
– Hardware and software handshaking
3 Synchronous Serial Protocol controllers
– Supports I2S, SPI and generic frame-based protocols
Two-Wire Interface
– Sequential Read/Write Operations, Philips’ I2C© compliant
Liquid Crystal Display (LCD) interface
– Supports TFT displays
– Configurable pixel resolution supporting QCIF/QVGA/VGA/SVGA configurations.
Image Sensor Interface
– 12-bit Data Interface for CMOS cameras
Universal Serial Bus (USB) 2.0 High Speed (480 Mbps) Device
– On-chip Transceivers with physical interface
2 Ethernet MAC 10/100 Mbps interfaces
– 802.3 Ethernet Media Access Controller
– Supports Media Independent Interface (MII) and Reduced MII (RMII)
16-bit stereo audio bitstream DAC
– Sample rates up to 50 kHz
On-Chip Debug System
– Nexus Class 3
– Full speed, non-intrusive data and program trace
– Runtime control and JTAG interface
Package/Pins
– AT32AP7000: 256-ball CTBGA 1.0 mm pitch/160 GPIO pins
Power supplies
– 1.65V to1.95V VDDCORE
– 3.0V to 3.6V VDDIO
Ο AP7000 είναι ένα πλήρες σύστηµα SoC (System on Chip) µε πυρήνα AVR32 RISC (Reduced Instruction Set Computing) και απόδοση 210 DMIPS (Dhrystone MIPS) στα 150 MHz.
Ο πυρήνας AVR32 είναι ένας υψηλής απόδοσης, 32-bit RISC, µικροελεγκτής. Παρουσιάζει
χαµηλή κατανάλωση, υψηλή πυκνότητα κώδικα (high code density – δηλαδή εκτελέσιµα µε
µειωµένες απαιτήσεις χωρητικότητας) και µεγάλη απόδοση στην εκτέλεση εφαρµογών. Με
αυτές τις δυνατότητες είναι σε θέση να εκτελεί ένα πλήρες, ενσωµατωµένο λειτουργικό σύ-
Ιστότοπος εργασίας: MyThesis.org
157
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
στηµα Linux µε αρκετή άνεση. Στην εικόνα µπορούµε να δούµε το package του AP7000 στις
δύο του απόψεις:
κάτω όψη
256-ball CTBGA
1.0 mm pitch
άνω
όψη
Εικόνα 46. Το το package του µικροελεγκτή AP7000
Ο AP7000 περιλαµβάνει µονάδα MMU (Memory Management Unit) και έναν ευέλικτο ελεγκτή διακοπών (interrupt controller), υποστηρίζοντας έτσι σύγχρονα λειτουργικά συστήµατα
αλλά και λειτουργικά συστήµατα πραγµατικού χρόνου (RTOS – Real Time Operating
System). Επίσης περιλαµβάνεται ένα πλούσιο σετ εντολών DSP (Digital Signal Processing)
και SIMD (Single Instruction Multiple Data) για την υποστήριξη πολυµεσικών και δικτυακών
εφαρµογών.
∆ιαθέτει ενσωµατωµένη 32 KB µνήµη SRAM (Static RAM) για γρήγορη και ασφαλή πρόσβαση σε καίρια δεδοµένα. Για εφαρµογές οι οποίες απαιτούν περισσότερη µνήµη, υπάρχει
δυνατότητα για υποστήριξη εξωτερικής (in-chip) SRAM. Επιπρόσθετα, υποστηρίζεται µέσω
SDRAM controller και εξωτερική (off-chip) επέκταση SDRAM µνήµης, η οποία µπορεί να είναι πτητική και µη-πτητική. Οι κυριότερες τεχνολογίες µη-πτητικών µνηµών που υποστηρίζονται είναι: Compact Flash, MMC (Multimedia Card), SDRAM (Secure Digital RAM),
SmartCard, NAND Flash και Atmel DataFlash™.
Ο DMA (Direct Memory Access) controller που υπάρχει ενσωµατωµένος στον AP7000 δίνει
τη δυνατότητα σε κάθε σειριακό του περιφερειακό να µεταφέρει δεδοµένα σε µνήµες, χωρίς
να απαιτείται η µεσολάβηση του ίδιου. Αυτό µειώνει τη συµφόρηση του όταν µεταφέρονται
µεγάλες ακολουθίες δεδοµένων µεταξύ περιφερειακών εντός της MCU (Micro Controller
Unit).
Οι µονάδες MAC (Ethernet 10/100), MII (Media Independent Interface) και RMII (Reduced
Media Independent Interface) του AP7000, παρέχουν µια ενσωµατωµένη (on-chip) λύση, για
σύνδεση µε δικτυακές συσκευές. Επίσης, οι σύγχρονοι σειριακοί ελεγκτές (Synchronous Serial Controllers), παρέχουν εύκολη πρόσβαση σε σειριακά πρωτόκολλα επικοινωνίας και
πρωτόκολλα πλαισίων (frame based protocols).
Γενικά ο AP7000 είναι ένας πλούσιος σε χαρακτηριστικά µικροελεγκτής ο οποίος παρέχει
ευελιξία συνδεσιµότητας και επικοινωνίας. Για παράδειγµα επιτρέπει τη σύνδεση έγχρωµης ή
απλής LCD οθόνης, µπορεί να λειτουργήσει σαν δικτυακή κάµερα, σαν mp3 player και πολλά
άλλα τα οποία στην παρούσα εργασία δεν κρίνεται αναγκαίο να αναπτύξουµε περισσότερο.
Επικοινωνία: [email protected]
158
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
5.3 ∆ιαθέσιµη µνήµη
Το Router NGW100 διαθέτει τρεις τύπους µνήµης. Την µνήµη SDRAM (Synchronous Dynamic Random Access Memory ή Synchronous Dynamic RAM), την παράλληλη µνήµη και
την σειριακή. Στην εικόνα που ακολουθεί µπορούµε να αναγνωρίσουµε και οπτικά τις µνήµες
αυτές όπως βρίσκονται συγκολληµένες στο PCB της πλακέτας:
σειριακή
(DataFlash)
SDRAM
παράλληλη
(NOR Flash)
Εικόνα 47. Οπτική αναγνώριση των µνηµών του Router NGW100
Ας εξετάσουµε τα χαρακτηριστικά και τον σκοπό της κάθε µιας µνήµης από αυτές ξεχωριστά. Αρχικά θα ασχοληθούµε µε την παράλληλη (parallel flash). Ο τύπος µνήµης αυτός, ανήκει στην κατηγορία µη-πτητικών (non volatile) µνηµών, πράγµα που σηµαίνει ότι σε αντίθεση
µε ότι συµβαίνει στις πτητικές (volatile) µνήµες, µπορεί να συγκρατεί δεδοµένα ακόµα και όταν δεν τροφοδοτείται από κάποια τάση ρεύµατος.
Στον Router NGW100 η µνήµη αυτή φιλοξενεί το λογισµικό εκκίνησης U-Boot (το οποίο είναι υπεύθυνο για την εκκίνηση του λειτουργικού συστήµατος αλλά και για τη διαχείριση του
υλικού του NGW100) καθώς και ένα ενσωµατωµένο περιβάλλον Linux (Embedded Linux Environment) ή αλλιώς root filesystem (κεντρικό σύστηµα αρχείων). Η χωρητικότητά της είναι
8MB, ενώ ο δίαυλος επικοινωνίας µε τον µικροελεγκτή έχει εύρος 16Bit.
Πιο συγκεκριµένα το ολοκληρωµένο που χρησιµοποιείται είναι το AT49BV642D-70TU
(NOR flash) και κατασκευάζεται από την ATMEL. Η τροφοδοσία λειτουργίας της µνήµης είναι
2,7 Volt. Τα κυριότερα χαρακτηριστικά της είναι:
Single Voltage Operation Read/Write: 2.65V - 3.6V
2.7V - 3.6V Read/Write
Access Time – 70 ns
Sector Erase Architecture
– One Hundred Twenty-seven 32K Word Main Sectors with Individual Write Lockout
– Eight 4K Word Sectors with Individual Write Lockout
Fast Word Program Time – 10 µs
Typical Sector Erase Time: 32K Word Sectors – 500 ms; 4K Word Sectors – 100 ms
Suspend/Resume Feature for Erase and Program
– Supports Reading and Programming Data from Any Sector by Suspending Erase
of a Different Sector
– Supports Reading Any Word by Suspending Programming of Any Other Word
Low-power Operation
Ιστότοπος εργασίας: MyThesis.org
159
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
– 10 mA Active
– 15 µA Standby
Data Polling and Toggle Bit for End of Program Detection
VPP Pin for Write Protection and Accelerated Program Operations
RESET Input for Device Initialization
Sector Lockdown Support
TSOP Package
Top or Bottom Boot Block Configuration Available
128-bit Protection Register
Common Flash Interface (CFI)
Green (Pb/Halide-free) Packaging
Ο όρος «παράλληλη µνήµη» έχει να κάνει µε τον τρόπο σύνδεσης και επικοινωνίας της µνήµης µε τον µικροελεγκτή. Η παράλληλη σύνδεση στα ηλεκτρονικά σχεδόν πάντα επιτυγχάνει
µεγαλύτερες ταχύτητες διαµεταγωγής και επεξεργασίας δεδοµένων. κάτι που είναι απόλυτα
επιθυµητό για το λογισµικό εκκίνησης και για το λειτουργικό σύστηµα (η root filesystem) ενός
ενσωµατωµένου συστήµατος Linux. Στην παρακάτω εικόνα βλέπουµε την επάνω όψη του
package της µνήµης:
Εικόνα 48. Η παράλληλη µνήµη AT49BV642D-70TU
Η σειριακή µνήµη (DataFlash) του Router NGW100 κατασκευάζεται και αυτή από την ίδια
εταιρεία και η κωδική της ονοµασία είναι AT45DB642D. Τα κυριότερα χαρακτηριστικά όπως
αυτά παρουσιάζονται στο αντίστοιχο datasheet της κατασκευάστριας εταιρείας είναι τα εξής:
Single 2.7V - 3.6V Supply
Dual-interface Architecture
– RapidS Serial Interface: 66 MHz Maximum Clock Frequency
SPI Compatible Modes 0 and 3
– Rapid8 8-bit Interface: 50 MHz Maximum Clock Frequency
User Configurable Page Size
– 1024 Bytes per Page
– 1056 Bytes per Page
– Page Size Can Be Factory Pre-configured for 1024 Bytes
Page Program Operation
– Intelligent Programming Operation
– 8192 Pages (1024/1056 Bytes/Page) Main Memory
Flexible Erase Options
– Page Erase (1 Kbyte)
– Block Erase (8 Kbytes)
– Sector Erase (256 Kbytes)
– Chip Erase (64 Mbits)
Two SRAM Data Buffers (1024/1056 Bytes)
– Allows Receiving of Data while Reprogramming the Flash Array
Continuous Read Capability through Entire Array
– Ideal for Code Shadowing Applications
Επικοινωνία: [email protected]
160
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Low-power Dissipation
– 10 mA Active Read Current Typical – Serial Interface
– 10 mA Active Read Current Typical – 8-bit Interface
– 25 µA Standby Current Typical
– 15 µA Deep Power Down Typical
Hardware and Software Data Protection Features
– Individual Sector
Permanent Sector Lockdown for Secure Code and Data Storage
– Individual Sector
Security: 128-byte Security Register
– 64-byte User Programmable Space
– Unique 64-byte Device Identifier
JEDEC Standard Manufacturer and Device ID Read
100,000 Program/Erase Cycles Per Page Minimum
Data Retention – 20 Years
Green (Pb/Halide-free/RoHS Compliant) Packaging Options
Temperature Range
– Industrial: -40°C to +85°C
Ανήκει στην κατηγορία των µη-πτητικών µνηµών και βρίσκεται συνδεδεµένη στο SPI interface (CS0) του µικροελεγκτή. Στο σύστηµά µας, είναι δεσµευµένη για να φιλοξενεί το σύστηµα αρχείων του Linux στο οποίο υπάρχουν όλα τα δεδοµένα του χρήστη (userspace) και των
προγραµµάτων που απαιτούνται για τη λειτουργία του Router. Το package της συσκευής
φαίνεται στην επόµενη εικόνα:
Εικόνα 49. Η σειριακή µνήµη AT45DB642D
Η µνήµη SDRAM που χρησιµοποιήθηκε στον Router NGW100 κατασκευάζεται από την εταιρεία Micron και ανήκει στην κατηγορία των πτητικών (volatile) µνηµών, πράγµα που όπως
γνωρίζουµε, σηµαίνει ότι µπορεί να συγκρατεί δεδοµένα µόνο όταν τροφοδοτείται από τάση
ρεύµατος. Η µνήµη αυτή µπορεί να χρησιµοποιηθεί µε τον ίδιο τρόπο που χρησιµοποιείται
και η µνήµη RAM ενός PC. Η κωδική της ονοµασία είναι MT48LC16M16A2 και το package
της φαίνεται στην εικόνα:
Εικόνα 50. Η µνήµη SDRAM MT48LC16M16A2
Η SDRAM στον Router NGW100 έχει χωρητικότητα 32MB, και 16bit δίαυλο επικοινωνίας
(bus) µε τον AP7000. Οι παράµετροι της µνήµης SDRAM φαίνονται στον παρακάτω πίνακα:
Ιστότοπος εργασίας: MyThesis.org
161
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
NGW100 SDRAM parameters
Columns
512 (9 bit)
Rows
8k
(13 bit)
Banks
4
(2 bit)
Latency (CAS)
2
Refresh rate (RAS)
15.6 µs
Recovery time (Rt)
2ck
Πίνακας 4. Παράµετροι λειτουργίας της µνήµης SDRAM
Αν και η σύνδεση της SDRAM µε τον µικροελεγκτή AP7000 παρουσιάζεται αρκετά καλά στο
σχηµατικό του Router NGW100, πιο κάτω µπορούµε να πάρουµε µια πρώτη ιδέα για τη σύνδεση SDRAM µνήµης στην οικογένεια µικροελεγκτών AVR32 στην οποία φυσικά ανήκει και ο
ίδιος:
Εικόνα 51. ∆ιασύνδεση µνήµης SDRAM µε µικροελεγκτή αρχιτεκτονικής AVR32
Η ιεραρχία της µνήµης του Router NGW100 και τα σηµεία φόρτωσης του Linux (mount
points) φαίνονται στο παρακάτω µπλοκ διάγραµµα. Όταν λέµε σηµεία φόρτωσης εννοούµε
τα σηµεία στα οποία η κάθε µνήµη µπορεί να είναι ορατή από το Linux.
Επικοινωνία: [email protected]
162
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Εικόνα 52. Η ιεραρχία µνήµης του Router NGW100 και τα σηµεία φόρτωσης του Linux
Ιστότοπος εργασίας: MyThesis.org
163
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
5.3.1 Χάρτης φυσικών διευθύνσεων
O χάρτης φυσικών διευθύνσεων ενός συστήµατος είναι συνήθως διαθέσιµος σε κάποιο
datasheet της τεχνικής τεκµηρίωσης που συνοδεύει το υλικό του συστήµατός µας Στην περίπτωσή µας οι πληροφορίες αυτές βρίσκονται στη σελίδα 73 του datasheet του µικροελεγκτή
AP7000 (doc32003.pdf) που µπορούµε να βρούµε στον ιστότοπο της ATMEL. Η µνήµη η
οποία υποστηρίζεται από τον µικροελεγκτή µας είναι η παρακάτω:
Πίνακας 5. Χάρτης φυσικών διευθύνσεων του AP7000
Οι φυσικές διευθύνσεις που φαίνονται στον πίνακα αντιστοιχούν σε διαφορετικές συσκευές
µνήµης οι οποίες µπορούν να προσπελαστούν από τη CPU. Το ακρωνύµιο EBI (External
Bus Interface) σηµαίνει διασύνδεση εξωτερικού διαύλου. Μπορούµε επίσης να δούµε ότι οι
δύο εσωτερικές µνήµες SRAM (Static Random – Access Memory) των 16K, µπορούν να
προσπελαστούν µέσω των φυσικών διευθύνσεων 0x2400_0000 και 0x2400_4000.
Ο Router NGW100 δεν διαθέτει τόση πολλή µνήµη, γι’ αυτό ο µικροελεγκτής έχει κάποιες
υποδοχές (slots) στις οποίες δεν έχει πρόσβαση αφού καµία συσκευή δεν είναι συνδεδεµένη
σε αυτές. Έτσι στην πραγµατικότητα ηδιαθέσιµη µνήµη είναι η παρακάτω:
Πίνακας 6. Η διαθέσιµη µνήµη του Router NGW100
Παρατηρούµε ότι θα µπορούσαµε να προσθέσουµε περισσότερη µνήµη flash ή SRAM στο
δίαυλο εξωτερικής διασύνδεσης EBI. Ο Router NGW100 περιλαµβάνει επίσης 8 MB σειριακής flash όµως δεν είναι διαθέσιµη µέσω του EBI. Είναι συνδεδεµένη στον SPI (Serial Peripheral Interface). Ο Router NGW100 διαθέτει δύο διαύλους SPI, η σειριακή flash βρίσκεται
Επικοινωνία: [email protected]
164
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
συνδεδεµένη στον δίαυλο 0 (SPI0). Έτσι προκειµένου να µπορούµε να προσπελάσουµε αυτή τη µνήµη θα πρέπει να γράψουµε έναν driver (ευτυχώς κάτι τέτοιο δεν ήταν απαραίτητο
γιατί υπήρχε έτοιµος στο internet). Η σειριακή dataflash µπορεί να θεωρηθεί ως ο σκληρός
δίσκος του συστήµατος σε αυτή την περίπτωση.
5.4 Ethernet PHY και MAC
Εφόσον το λογισµικό και τα πρωτόκολλα επικοινωνίας (στοίβα TCP/IP) που απαιτούνται για
την επίτευξη της ανταλλαγής πακέτων στο δίκτυο είναι διαθέσιµα και λειτουργούν σωστά, το
τελευταίο τµήµα της επικοινωνίας (Φυσικό επίπεδο) που θα πρέπει να διευθετηθεί είναι η
προσαρµογή στα ιδιαιτέρα χαρακτηριστικά που προβλέπονται από το πρότυπο Ethernet
(IEEE 802.3). Ουσιαστικά στο στάδιο αυτό υλοποιούνται δύο βασικές λειτουργίες. Τα πακέτα
µετατρέπονται σε πλαίσια (frames) και τα ηλεκτρικά σήµατα διαµορφώνονται κατάλληλα για
την µετάδοσή τους στο φυσικό µέσο το οποίο είναι συνήθως ο χαλκός. Φυσικά υπάρχει και η
περίπτωση κατά την οποία λαµβάνουµε πλαίσια από το δίκτυο στις θύρες Ethernet του συστήµατός µας, όπου και εκτελείται η ακριβώς αντίστροφη διαδικασία.
Για τις λειτουργίες αυτές απαιτείται ειδικό υποσύστηµα το οποίο κάποιες φορές βρίσκεται
ενσωµατωµένο στην µονάδα επεξεργασίας του συστήµατος που αναπτύσσεται, ενώ στις περισσότερες των περιπτώσεων, το υποσύστηµα αυτό υπάρχει σε ένα ξεχωριστό ολοκληρωµένο (Ethernet controller ή Ethernet PHY). Η κωδική ονοµασία (Device ID) του
ολοκληρωµένου που χρησιµοποιήθηκε στο σύστηµά µας είναι DP83848I. Το package της
συσκευής αυτής φαίνεται στην επόµενη εικόνα:
Εικόνα 53. Το ολοκληρωµένο DP83848I (Ethernet PHY)
Στο σύστηµά µας υπάρχουν δύο θύρες Ethernet, οπότε υπάρχουν και δύο Ethernet controllers. Η σύνδεσή τους µε τον µικροελεγκτή και η χρήση τους, φαίνεται στον πίνακα που ακολουθεί:
AP7000 peripheral
NGW schematic
PHY ID
Linux usage
MACB0
ETH_0
00001 (01h)
WAN
MACB1
ETH_1
00011 (03h)
LAN
Πίνακας 7. Λεπτοµέρειες σύνδεσης των Ethernet PHYs
Στην επόµενη εικόνα µπορούµε να δούµε τις δύο θύρες Ethernet, τους Ethernet controllers,
καθώς και τον µικροελεγκτή, όπως αυτά βρίσκονται τοποθετηµένα στην πλακέτα του Router
NGW100:
Ιστότοπος εργασίας: MyThesis.org
165
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
AP7000
Θύρα
Ethernet
WAN
WAN
Ethernet
controller
Θύρα
Ethernet
LAN
WAN
Ethernet
controller
Εικόνα 54. θύρες LAN και WAN, Ethernet controllers και ο µικροελεγκτής AP7000
Οι δύο θύρες Ethernet κατασκευάζονται από την εταιρεία Pulse Electronics µε κωδικό προϊόντος J3026G01DNL, και διαθέτουν φωτεινές ενδείξεις κατάστασής µε πορτοκαλί και πράσινο led. Σε αντίστοιχο τεχνικό εγχειρίδιο που παρέχει η εταιρεία υποδεικνύονται τα τεχνικά
χαρακτηριστικά στα οποία πρέπει να βασιστούµε προκειµένου να συγκολλήσουµε και να
συνδέσουµε τις θύρες αυτές στο PCB της πλακέτας µας. Στην εικόνα που ακολουθεί βλέπουµε µια τέτοια θύρα:
Πράσινο
LED
Κίτρινο
LED
Εικόνα 55. Η θύρα Ethernet J3026G01DNL
Ο µικροελεγκτής AP7000 συνδέεται και επικοινωνεί µε τους δύο Ethernet controllers µέσω
της διεπαφής MII που αναφέραµε και νωρίτερα όταν παραθέσαµε τα σηµαντικότερα χαρακτηριστικά του. Η διεπαφή MII υποστηρίζεται τόσο από τον µικροελεγκτή όσο και από τους
Ethernet controllers. Στο διάγραµµα βλέπουµε ένα παράδειγµα σύνδεσης του controller
(Ethernet PHY) µε τον µικροελεγκτή:
Επικοινωνία: [email protected]
166
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Εικόνα 56. Σύνδεση του ολοκληρωµένου DP83848I (Ethernet PHY) µε τον µικροελεγκτή AP7000
Τα pins που διατίθενται για σύνδεση MII περιγράφονται επίσης σε αντίστοιχα datasheets
(του µικροελεγκτή και του Ethernet controller). Η διάταξη των ακροδεκτών (pin layout ή pinout) φαίνεται στο παρακάτω διάγραµµα:
Ιστότοπος εργασίας: MyThesis.org
167
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 57. Η διάταξη των ακροδεκτών (pinout) του ολοκληρωµένου DP83848I (Ethernet PHY)
Στο παράρτηµα που παρουσιάζεται το σχηµατικό διάγραµµα του συστήµατός µας µπορεί
κανείς να δει ακριβώς τον τρόπο σύνδεσης των δύο Ethernet controllers µε τον µικροελεγκτή
AP7000.
Η φυσική διεύθυνση (MAC) των δύο Ethernet controllers προκύπτει από µια καταχωρηµένη
από την εταιρεία, βάση MAC, που είναι η 00:00:04:25:1C:50:00 σε συνδυασµό µε το
σειριακό αριθµό του κάθε controller. Oι φυσικές διευθύνσεις του συστήµατός µας στην εργασία αυτή είναι οι εξής:
AP7000 peripheral
NGW schematic
MAC
Linux usage
MACB0
ETH_0
00:04:25:1C:82:7C
WAN
MACB1
ETH_1
00:04:25:1C:82:7D
LAN
Πίνακας 8. Οι MAC διευθύσεις του Router NGW100
Όπως αναφέραµε και πιο πάνω, περισσότερες και ακριβέστερες λεπτοµέρειες σχετικά µε
την σύνδεση όλων των ηλεκτρικών και ηλεκτρονικών στοιχείων του Router NGW100 µπορούµε να βρούµε και στο παράρτηµα του πλήρους σχηµατικού του Router NGW100.
5.5 Συνδεσιµότητα RS232
Η σειριακή επικοινωνία όσον αφορά το υλικό του Router NGW100, επιτυγχάνεται µέσω των
ακροδεκτών USART_1_TXD 1(PA18) και USART_1_RXD 1 (PA17) του µικροελεγκτή. Η µε-
Επικοινωνία: [email protected]
168
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
τατροπή της TTL στάθµης σε στάθµη RS232 πραγµατοποιείται από το ολοκληρωµένο
MAX3232ECAE+. Η συνδεσµολογία του µε τον µικροελεγκτή φαίνεται και στο αντίστοιχο παράρτηµα (σχηµατικό Router NGW100). Το package του MAX3232ECAE+ είναι το ακόλουθο:
Εικόνα 58. Το ολοκληρωµένο MAX3232ECAE+
Επίσης, σε σχετικό παράρτηµα υπάρχουν οδηγίες και για την προσκόµιση του datasheet το
οποίο διανέµεται από την κατασκευάστρια εταιρεία. Στην επόµενη εικόνα µπορούµε να δούµε
το pinout της συσκευής:
Εικόνα 59. Η διάταξη των ακροδεκτών του ολοκληρωµένου MAX3232ECAE+
5.6 Ελεγκτής πλακέτας – Board Controller
Στην πλακέτα του Router NGW100 υπάρχει κι ένας ελεγκτής πλακέτας (board controller).
Σκοπός του είναι να κρατά πληροφορίες που αφορούν το ID του κατασκευαστή, το όνοµα της
πλακέτας και άλλα στοιχεία. Οι πληροφορίες αυτές µπορούν να διαβάζονται και από άλλα
συστήµατα που επικοινωνούν µε την πλακέτα. Για παράδειγµα σε ένα τοπικό δίκτυο οι υπολογιστές που θα συνδέονται µε τον Router NGW100 θα µπορούν να γνωρίζουν το όνοµά
του, τον κατασκευαστή του και όποια άλλη πληροφορία κρίνεται χρήσιµο να διαµοιραστεί κάθε φορά. Επίσης, ο ελεγκτής πλακέτας είναι σε θέση να γνωρίζει τις τάσεις λειτουργίας και τη
θερµοκρασία του συστήµατος και να αναφέρει τα αποτελέσµατα στον µικροελεγκτή. Έτσι
µπορούν να γίνονται συνεχείς διαγνωστικοί έλεγχοι και να παίρνονται όπου κρίνεται απαραίτητο, οι ανάλογες αποφάσεις.
Ουσιαστικά πρόκειται για τον µικροελεγκτή ATtiny24-20SSU της εταιρείας ATMEL. Οι µικροελεγκτές της οικογένειας tinyAVR προσφέρονται για περιπτώσεις που απαιτείται οικονοµία χώρου και τάσης λειτουργίας (µπορούν να λειτουργήσουν µε τάση 0.7 Volt!). Το
package του ATtiny24 φαίνεται στην ακόλουθη εικόνα:
Εικόνα 60. Ο µικροελεγκτής ATtiny24-20SSU (board controller)
Ιστότοπος εργασίας: MyThesis.org
169
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η επικοινωνία του board controller µε τον µικροελεγκτή επιτυγχάνεται µέσω του προτύπου
PMbus (powersig.org). Το πρότυπο αυτό προτιµήθηκε λόγω του ότι χρησιµοποιείται σε αρκετά γνωστά εµπορικά προϊόντα (πχ PC motherboards) κι έτσι µπορούν να ευκολότερα να
βρεθούν παραδείγµατα κώδικα που το χρησιµοποιούν. Στην επόµενη εικόνα µπορούµε να
δούµε το pinout του ATtiny24:
Εικόνα 61. Η διάταξη των ακροδεκτών του µικροελεγκτή ATtiny24-20SSU
Επίσης, στο µπλοκ διάγραµµα που ακολουθεί, παρουσιάζεται η κυκλωµατική συνδεσµολογία του ATtiny24 µε τον µικροελεγκτή:
Εικόνα 62. Η συνδεσµολογία του ATtiny24 µε τον µικροελεγκτή AP7000
Οι αντιστάσεις R82 και R83 είναι 4K η κάθε µια τους και λειτουργούν σαν pullup αφού ο δίαυλος TWI (Two Wires Interface) απαιτεί την ύπαρξή τους.
Επικοινωνία: [email protected]
170
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Η χαρτογράφηση του board controller στην µνήµη έχει την τιµή 0x0B. Τα µηνύµατα απαντήσεων του PMbus είναι της µορφής:
<µήκος><databyte0><databyte1>...<databyteN>
Στον πίνακα µπορούµε να δούµε ποια µηνύµατα υποστηρίζονται:
Εντολή
Τιµή
Επιστρεφόµενη τιµή
TWI_CMD_MFR_ID
0x99
atmel.no (ascii)
TWI_CMD_MFR_MODEL
0x9A
NGW100 (ascii)
TWI_CMD_MFR_SERIAL
0x9E
TWI_CMD_READ_TEMP_1
0x9D
Serial number του
NGW100 (ascii)
Θερµοκρασία σε Kelvin (unsigned short int)
Πίνακας 9. Μηνύµατα απόκρισης του PMbus
Υπάρχει και άλλη µία εντολή, η TWI_CMD_MFR_REVISION (τύπου unsigned char), την
οποία δεν θα αναλύσουµε εκτενώς. Απλά θα αναφέρουµε ότι πρόκειται για ένα σύστηµα διαχείρισης εκδόσεων – τροποποιήσεων του υλικού (hardware revision ή versioning). Όπως έχουµε δει και στο θεωρητικό µέρος της εργασίας, παρόµοιοι µηχανισµοί υπάρχουν και για τη
διαχείριση εκδόσεων του λογισµικού (πχ: SVN, GIT κλπ).
Ο προγραµµατισµός του ελεγκτή πλακέτας ATtiny24, προϋποθέτει ότι το ολοκληρωµένο
έχει αποκολληθεί από την πλακέτα και έχει καθαριστεί πρώτα η µνήµη του (chip erase). Αυτό
σηµαίνει επίσης ότι είναι δύσκολο κάποιος να αλλάξει την ψηφιακή ταυτότητα που εµείς ως
κατασκευαστές, έχουµε δώσει στην πλακέτα µας.
5.7 ∆ιεπαφές προγραµµατισµού JTAG και NEXUS
Ο Router NGW100 διαθέτει δύο διεπαφές για προγραµµατισµό και debugging, την διεπαφή
JTAG και την διεπαφή NEXUS. Στην εργασία αυτή έγινε χρήση µόνο της πρώτης, δηλαδή
της διεπαφής JTAG. Φυσικά όταν λέµε ότι ο Router NGW100 υποστηρίζει JTAG, εννοούµε
ότι ο µικροελεγκτής AP7000 παρέχει αυτή τη δυνατότητα.
Μέσω της διεπαφής µπορούµε να πάρουµε στα χέρια µας τον πλήρη έλεγχο του υλικού του
Router NGW100 έτσι ώστε µέσω του συστήµατος host να µπορούµε να προγραµµατίζουµε
την εξωτερική µνήµη Flash και να κάνουµε debugging στα προγράµµατα που τρέχουν στον
AP7000 χωρίς να απαιτείται η ύπαρξη κάποιου bootloader στον Router.
Στο PCB του Router υπάρχουν δύο θέσεις (footprints) για τη συγκόλληση ακροδεκτών
JTAG. Η πρώτη η οποία και χρησιµοποιήθηκε σε αυτή την εργασία, υποστηρίζει trough hole
headers και η απόσταση του ενός pin από το άλλο είναι 100 mil (ή 100 thou), ενώ η δεύτερη
είναι επιφανειακής στήριξης (SMD) και 50 mil. Το 1 mil είναι το ένα χιλιοστό της ίντσας και
πρόκειται για µονάδα µέτρησης µήκους που χρησιµοποιείται από τους µηχανικούς κατά την
σχεδίαση πλακετών (PCB).
Ιστότοπος εργασίας: MyThesis.org
171
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η διάταξη των ακροδεκτών JTAG που υπάρχουν στον Router ακολουθεί το πρότυπο JTAG
της ATMEL. Μπορούµε να δούµε τη διάταξη αυτών στην επόµενη εικόνα:
Εικόνα 63. Η διάταξη των ακροδεκτών JTAG
Το header που χρησιµοποιήθηκε (10 pin Header) είναι ένα απλό header 10 ακροδεκτών και
µπορούµε να το δούµε πιο κάτω:
Εικόνα 64. 10 pin Header για σύνδεση JTAG
Επίσης πιο κάτω παρατίθεται ένα τµήµα του σχηµατικού του Router ώστε να φανεί όσο καλύτερα γίνεται και η σύνδεση του header µε τον µικροελεγκτή:
Εικόνα 65. Σχηµατικό σύνδεσης του 10 pin Header µε τον µικροελεγκτή AP7000
Οι ονοµασίες AP7000_1 και AP7000_2 στο σχηµατικό του Router NGW100 υπάρχουν για
να φαίνεται ότι η συνδεσµολογία του µικροελεγκτή δεν ολοκληρώνεται σε µια σελίδα Α4 του
µηχανικού σχεδίου αλλά συνεχίζεται και σε δεύτερη. Αυτό είναι συχνό φαινόµενο στη σχεδίαση µεγάλων συστηµάτων όπου υπάρχουν µικροελεγκτές µε εκατοντάδες ακροδέκτες. Ο χώρος είναι περιορισµένος οπότε οι µηχανικοί αναγκάζονται να χωρίζουν την CPU σε λογικές
µονάδες (στην περίπτωσή µας U1A, U1B και U1C) που περιγράφονται σε ξεχωριστές σελίδες.
Με αυτό τον τρόπο προκύπτει πάντα ένα πιο ευανάγνωστο αποτέλεσµα.
Επικοινωνία: [email protected]
172
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
5.8 Σύστηµα χρονισµού
Ο µικροελεγκτής AP7000 διαθέτει τρεις πηγές χρονισµού (clocks). ∆ύο κρυστάλλους, τους
XC1 και XC2, µε συχνότητες λειτουργίας 12MHz και 20MHz αντίστοιχα. Και τον κρύσταλλο
XC3 µε συχνότητα λειτουργίας 32KHz που είναι κατάλληλος για συστήµατα πραγµατικού
χρόνου. Πιο κάτω βλέπουµε το σχηµατικό σύνδεσης του εξωτερικού ρολογιού (external
clock) µε τον µικροελεγκτή:
Εικόνα 66. Σχηµατικό σύνδεσης του εξωτερικού ρολογιού (external clock) µε τον µικροελεγκτή AP7000
Μέσω των κρυστάλλων XC1 και XC2 µπορούµε να «οδηγήσουµε» την λειτουργία ορισµένων µονάδων του AP7000. Έτσι οι µονάδες PLL (Phase-locked loop), PLL0 και PLL1 «οδηγούνται» αντίστοιχα από τους δύο αυτούς κρυστάλλους. Με σκοπό να ορίσουµε την µέγιστη
και την ελάχιστη συχνότητα λειτουργίας του Router NGW100. Ουσιαστικά λοιπόν πρόκειται
για ένα σύστηµα φιλτραρίσµατος (PLL low-pass filter) συχνοτήτων. Πιο κάτω µπορούµε να
δούµε αντιπροσωπευτικό διάγραµµα:
Εικόνα 67. Χαµηλοπερατό σύστηµα φιλτραρίσµατος συχνοτήτων (PLL low-pass filter)
Στο datasheet του AP7000 υπάρχει λεπτοµερής ανάλυση των µονάδων PLL. Στον πίνακα
που ακολουθεί µπορούµε να δούµε τη διαµόρφωση των δύο φίλτρων PLL για την περίπτωσή
του Router NGW100:
Ιστότοπος εργασίας: MyThesis.org
173
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
DIV
MUL
Fn
(PLL bandwidth)
20MHz
2
13
30KHz
130MHz
R18=430R
C7=1.8nF
C14=18nF
20MHz
4
16
30KHz
80MHz
R17=150R
C6=5.6nF
C15=56nF
Filter
Fosc
PLL0
PLL1
Fout
R17/R18
C6/C7
C14/C15
Πίνακας 10. Η διαµόρφωση των φίλτρων PLL
Η συχνότητα εξόδου (Fout) υπολογίζεται ως εξής:
Fout = (Fosc / DIV) * MUL
5.9 Κύκλωµα επαναφοράς (reset)
Ο Router NGW100 διαθέτει δύο κυκλώµατα reset. Το ένα κύκλωµα χρησιµοποιείται για τον
µικροελεγκτή και τον board controller, και το άλλο για τους Ethernet controllers και την παράλληλη µνήµη (DataFlash).
Και τα δύο κυκλώµατα τίθενται σε χαµηλή στάθµη (low) από τον ίδιο διακόπτη (reset
button). Κάθε φορά που γίνεται κάποιο reset, γίνεται πρώτα στη µνήµη και µετά στον µικροελεγκτή. Αυτό επιτυγχάνεται µε τη βοήθεια του κυκλώµατος καθυστέρησης το οποίο υλοποιείται από δύο αντιστάσεις (R15, R16) και δύο πυκνωτές (C1, C2) που έχουν διαφορετικά
χαρακτηριστικά έτσι ώστε να επιτυγχάνονται και διαφορετικές καθυστερήσεις. Αυτό φαίνεται
και στο διάγραµµα του κυκλώµατος reset που µπορούµε να δούµε παρακάτω:
Εικόνα 68. Το κύκλωµα επαναφοράς (reset) του Router NGW100
Ο διακόπτης για το reset (SKHUAF010) στον Router NGW100 είναι επιφανειακής στήριξης
(SMD) και µπορούµε να τον δούµε στην παρακάτω εικόνα:
Εικόνα 69. Ο διακόπτης reset SKHUAF010
Επικοινωνία: [email protected]
174
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
5.10 Σύστηµα τροφοδοσίας
Για να λειτουργήσει το Router και να εκτελέσει µε επιτυχία το λογισµικό του, θα πρέπει να
τροφοδοτείται από ενέργεια. Την ενέργεια την παρέχει κάποια πηγή. Η παρεχόµενη τάση της
πηγής (power supply) θα πρέπει να είναι 9-15 V DC και η ένταση 0.5 A, έτσι ώστε να υπάρχει αρκετή ισχύς στο κύκλωµα µετατροπής που υπάρχει εσωτερικά στον Router.
Η τάση και η ένταση του οικιακού δικτύου (∆ΕΗ) είναι ακατάλληλές για τροφοδοσία οικιακών
ηλεκτρονικών συσκευών και για το λόγο αυτό θα πρέπει να µεσολαβεί κάποιο κύκλωµα µετατροπής (power converter) ή πιο απλά, ένα κατάλληλο τροφοδοτικό. Το στοιχείο αυτό µπορεί
να είναι είτε εσωτερικό, είτε εξωτερικό. Στην περίπτωσή µας είναι εξωτερικό. Για τις ανάγκες
αυτής της εργασίας και για λόγους οικονοµίας, χρησιµοποιήθηκε ένα παροπλισµένο τροφοδοτικό από κάποιον ανενεργό router της εταιρείας Netgear που υπήρχε διαθέσιµο. Το βλέπουµε στην εικόνα:
Εικόνα 70. Το τροφοδοτικό του Router NGW100
Τα χαρακτηριστικά του κρίθηκαν αποδεκτά για τις ανώτερες και κατώτερες επιτρεπτές στάθµες λειτουργίας του Router NGW100 και επιβεβαιώθηκαν και καθ’ όλη τη διάρκεια της ανάπτυξης του λογισµικού. Ας δούµε ποια είναι αυτά:
input: AC 220 – 240V ~ 50/60Hz 0.2A (εναλλασσόµενο)
output: DC 12V 1A (συνεχές)
Το σύστηµα τροφοδοσίας (power system) αποτελείται από τρία κύρια µέρη. Το πρώτο το
περιγράψαµε ήδη και δεν βρίσκεται συγκολληµένο στην πλακέτα του Router. Τα επόµενα
δύο µέρη που θα περιγραφούν βρίσκονται ενσωµατωµένα στο PCB. Ουσιαστικά το ένα από
αυτά τα δύο µέρη είναι παθητικό και το µόνο που κάνει είναι να ενώνει την έξοδο του µετατροπέα µε την είσοδο του συστήµατος µετατροπής του Router. Πρόκειται για µια θύρα
(RASM722P) των 2.1 mm που είναι και το πρώτο στοιχείο το οποίο φέρνει σε επαφή την
πλακέτα µε την παροχή ρεύµατος. Την βλέπουµε στην εικόνα:
Εικόνα 71. Η θύρα τροφοδοσίας RASM722P
Ιστότοπος εργασίας: MyThesis.org
175
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Το τρίτο και σηµαντικότερο µέρος του συστήµατος τροφοδοσίας του Router είναι το εσωτερικό κύκλωµα µετατροπής τάσης. Στο διάγραµµα που ακολουθεί µπορούµε να το δούµε περιληπτικά:
Εικόνα 72. Το εσωτερικό κύκλωµα µετατροπής τάσης
Το ολοκληρωµένο DF10S είναι µια πλήρης γέφυρα ανόρθωσης τεσσάρων διόδων η οποία
αναλαµβάνει να µετατρέψει το σύνολο της κυµατοµορφής εισόδου (input) σε µία από τις δύο
(θετική ή αρνητική) σταθερές πολικότητες. Στην εικόνα βλέπουµε το DF10S σαν συσκευή:
Εικόνα 73. Η γέφυρα ανόρθωσης τεσσάρων διόδων DF10S
Εφόσον γειώνουµε το πλην της γέφυρας στην είσοδο, επιλέγουµε την θετική πολικότητα
στην έξοδό της. Στο σχήµα που ακολουθεί βλέπουµε µια θεωρητική γραφική αναπαράσταση:
Εικόνα 74. θεωρητική γραφική αναπαράσταση της λειτουργίας µιας γέφυρας ανόρθωσης
Το δεύτερο σηµαντικό βήµα που πραγµατοποιείται στο κύκλωµα µετατροπής του Router
είναι η έξοδος της γέφυρας ανόρθωσης να γίνει είσοδος στο ολοκληρωµένο LM2717 το οποίο βλέπουµε και στην εικόνα:
Επικοινωνία: [email protected]
176
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Εικόνα 75. Το ολοκληρωµένο LM2717 (DC/DC converter)
Πρόκειται για έναν DC/DC converter ο οποίος µετατρέπει την DC είσοδο των 12V που λαµβάνει από την γέφυρα ανόρθωσης DF10S και την υποβιβάζει σε δύο άλλα επίπεδα τάσης
των 3.3 (τροφοδοσία CPU) και 1.8 Volt (ρυθµιζόµενη). Η διάταξη των ακροδεκτών του είναι η
εξής:
Εικόνα 76. Η διάταξη των ακροδεκτών του ολοκληρωµένου LM2717
Τα χαρακτηριστικά του, όπως αυτά υπάρχουν στο datasheet που παρέχει η κατασκευάστρια εταιρεία είναι τα ακόλουθα:
Fixed 3.3V output buck converter with a 2.2A, 0.16Ω, internal switch
Adjustable buck converter with a 3.2A, 0.16Ω, internal switch
Operating input voltage range of 4V to 20V
Input undervoltage protection
300kHz to 600kHz pin adjustable operating frequency
Over temperature protection
Small 24-Lead TSSOP package
Από τη στιγµή που όλα έχουν γίνει σωστά, ανάβει το πράσινο LED (EL15-21UGC) που υποδεικνύει ότι η πλακέτα τροφοδοτείται σωστά και µπορεί να λειτουργήσει.
Ιστότοπος εργασίας: MyThesis.org
177
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
5.11 ∆ιαστάσεις πλακέτας
Στο παρακάτω µηχανικό σχέδιο παρουσιάζονται λεπτοµέρειες όπως, το µέγεθος της πλακέτας, η τοποθέτηση και το µέγεθος των οπών στήριξης (mounting holes), και η τοποθέτηση
των κεφαλών επέκτασης (expansion headers):
Εικόνα 77. Το µηχανικό σχέδιο του PCB του Router NGW100
5.12 Σχέδιο συναρµολόγησης
Το σχέδιο συναρµολόγησης (assembly drawing) είναι απαραίτητο για κάθε προϊόν το οποίο
κατασκευάζεται και αποτελείται από πολλά µέρη. Είναι ένας πρόχειρος αλλά χρήσιµος οδηγός συναρµολόγησης:
Επικοινωνία: [email protected]
178
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Εικόνα 78. Το σχέδιο συναρµολόγησης του Router NGW100
Κάθε στοιχείο που υπάρχει επάνω στο σχέδιο συναρµολόγησης έχει µια κωδική ονοµασία η
οποία υπάρχει και στο σχηµατικό της πλακέτας µας. Αυτό µας δίνει τη δυνατότητα να γνωρίζουµε τι θα συγκολληθεί σε κάθε σηµείο της. Φυσικά το ρόλο αυτό µπορεί να παίξει και το
silkscreen (µεταξοτυπία) που θα έχει τυπωθεί όπως εµείς έχουµε υποδείξει στα µηχανικά
σχέδια που στείλαµε στο εργοστάσιο το οποίο τύπωσε τις πλακέτες µας.
Ιστότοπος εργασίας: MyThesis.org
179
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
5.13 Σχηµατικά και PCB του Router NGW100
Όλα τα σχηµατικά της πλακέτας αυτής της εργασίας, όπως και όλα τα τεχνικά έγγραφα
(datasheets) των ηλεκτρονικών στοιχείων που χρησιµοποιήθηκαν, περιλαµβάνονται στον
ιστότοπο στο CD που συνοδεύει την εργασία. Έτσι αν κάτι είναι ελλιπές ή δυσνόητο στην
ανάλυση του υλικού που παρατέθηκε σε αυτό το πρακτικό µέρος, µπορεί να βρεθεί εκεί. Στο
παράρτηµα C υπάρχουν περισσότερες πληροφορίες.
Το λογισµικό CAD (Computer Aided Design) που χρησιµοποιήθηκε για την ανάπτυξη των
σχηµατικών αλλά και της πλακέτας του Router είναι το orCad. Μέσω του ίδιου λογισµικού
δηµιουργήθηκαν και τα αντίστοιχα Gerber files τα οποία απαιτούνται κατά το στάδιο κατασκευής (PCB manufacturing) της πλακέτας.
5.14 Επέκταση δυνατοτήτων υλικού
Σε αυτή την παράγραφο είναι πολύ χρήσιµο να ορίσουµε τι είναι και τι δεν είναι ο Router
NGW100 προκειµένου να διαφανούν οι περεταίρω βελτιώσεις του υλικού που θα µπορούσαν
να γίνουν. Αυτό ίσως να δείχνει περιττό αρχικά, εφόσον λέµε ότι πρόκειται για έναν δροµολογητή. Όµως σε πολλές περιπτώσεις η έννοια συγχέεται µε τους σύγχρονους δροµολογητές οι
οποίοι ουσιαστικά είναι πολλές συσκευές σε µία. Ας δούµε όµως ποιες είναι αυτές οι συσκευές:
Modem
Router
Switch
Bridge
Access Point
Wireless
κλπ
Ο Router NGW100 υλοποιήθηκε κατά κύριο λόγο για την δροµολόγηση πακέτων. ∆εν διαθέτει κάποιο PSTN ή ISDN modem και έτσι χρειάζεται να συνδεθεί µέσω της θύρας WAN σε
κάποιο, προκειµένου να είναι σε θέση να δροµολογήσει πακέτα στο Internet. Επίσης, διαθέτει µόνο µία θύρα LAN και εποµένως για να συνδεθούν περισσότεροι του ενός υπολογιστές,
θα πρέπει να µεσολαβεί ένα switch. Ο Router NGW100 µπορεί να λειτουργήσει σαν γέφυρα
(Bridge). ∆εν µπορεί να λειτουργήσει σαν Access Point ή να συνδεθούν σε αυτόν, υπολογιστές µέσω WiFi καθώς δε διαθέτει το απαιτούµενο υλικό.
Οι βελτιώσεις που µπορούν να γίνουν µελλοντικά στον Router NGW100 είναι πολλές και θα
επηρεάσουν εξίσου και το υλικό αλλά και το λογισµικό. Στο διάγραµµα της εικόνας που ακολουθεί, µπορούµε να δούµε σε µεγάλο επίπεδο αφαίρεσης τις βελτιώσεις αυτές:
Επικοινωνία: [email protected]
180
Ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100 – Κεφάλαιο 5
Εικόνα 79. Επέκταση δυνατοτήτων υλικού του Router NGW100
Βέβαια, τώρα πια τα πράγµατα θα είναι ευκολότερα, καθώς υπάρχει υλοποιηµένος ο βασικός πυρήνας που είναι ο επεξεργαστής AP7000, το ειδικά διαµορφοµένο Buildroot και οι απαραίτητοι οδηγοί συσκευών.
Ιστότοπος εργασίας: MyThesis.org
181
ΚΕΦΑΛΑΙΟ
6
Προγραµµατισµός και εκκίνηση
του Router NGW100
Εισαγωγή
Έχοντας αναλύσει το υλικό του Router NGW100, µπορούµε πλέον να ασχοληθούµε µε το
λογισµικό του. Σε αυτό το κεφάλαιο θα παρουσιαστούν τα βήµατα που έγιναν έτσι ώστε Ο
Router NGW100 να καταστεί µια πλήρως λειτουργική συσκευή, η οποία θα µπορεί να αλληλεπιδρά τόσο µε έναν προγραµµατιστή, όσο και µε τον απλό χρήστη. Τα θέµατα που θα αναλυθούν είναι τα ακόλουθα:
Το σύστηµα ανάπτυξης host
Το πακέτο υποστήριξης συστήµατος Atmel Linux BSP 3.0
∆ηµιουργία της εικονικής µηχανής Ubuntu 9.04
Το περιβάλλον ανάπτυξης AVR32
Βοηθητικό λογισµικό
∆ιαµέριση µνήµης
Η συσκευή JTAGICE mkII
Σύνδεση JTAGICE mkII µε το σύστηµα host
Εγγραφή U-Boot στην παράλληλη µνήµη
Εγγραφή Linux Kernel στην παράλληλη µνήµη
Εγγραφή συστήµατος αρχείων /usr
∆ιαδικασία εκκίνησης
6.1 Το σύστηµα ανάπτυξης host
Για το σύστηµα ανάπτυξης host, στο οποίο αναπτύχθηκε και παραµετροποιήθηκε το λογισµικό του Router NGW100, χρησιµοποιήθηκε ένας προσωπικός υπολογιστής µε επεξεργαστή Intel Pentium 4, κύρια µνήµη RAM 2GB και σκληρό δίσκο 500GB. Σε αυτόν
εγκαταστάθηκε µια καθαρή έκδοση των αγγλικών Windows XP Professional SP3, και η εφαρµογή VMware προκειµένου να µπορεί στη συνέχεια να δηµιουργηθεί µια εικονική µηχανή
Linux.
Οι κυριότεροι λόγοι για τους οποίους προτιµήθηκε αυτή η διαµόρφωση στο σύστηµα host,
είναι:
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Ευελιξία και µεταφερσιµότητα της εικονικής µηχανής: Όπως θα δούµε και στη συνέχεια, µια εικονική µηχανή αποτελείται ουσιαστικά από δύο αρχεία. Τα αρχεία αυτά
µπορούµε να τα µεταφέρουµε από υπολογιστή σε υπολογιστή και να λειτουργούν µε
τον ίδιο τρόπο, απλά αντιγράφοντάς τα. Αυτό δε θα µπορούσε να συµβεί τόσο εύκολα
σε περίπτωση που το λειτουργικό σύστηµα ήταν εγκατεστηµένο εξ ολοκλήρου στον
υπολογιστή µας.
Προστασία της δουλειάς µας: Εφόσον µια εικονική µηχανή αποτελείται µόνο από απλά αρχεία, µπορούµε πολύ εύκολα να δηµιουργούµε αντίγραφα ασφαλείας. Αυτό
µας βοηθά στο να µην χάνουµε την δουλειά µας σε περίπτωση αστοχίας υλικού αλλά
και να µπορούµε να την επαναφέρουµε σε προγενέστερα σηµεία αναφοράς, αν εµείς
οι ίδιοι, κάνουµε κάποιο λάθος.
Περισσότερες δυνατότητες δοκιµών: ∆εδοµένου του ότι οι χωρητικότητες των σκληρών δίσκων είναι µεγάλες και το κόστος τους όλο και χαµηλότερο, έχουµε τη δυνατότητα να δηµιουργούµε πολλαπλές εικονικές µηχανές. Με αυτό τον τρόπο µπορούµε
να κάνουµε δοκιµές σε διαφορετικές συνθήκες ώστε στο τέλος να επιλέξουµε την βέλτιστη περίπτωση.
6.2 Το πακέτο υποστήριξης συστήµατος Atmel Linux BSP 3.0
Ένα πακέτο BSP περιλαµβάνει, όπως αναφέραµε και σε αντίστοιχο κεφάλαιο του θεωρητικού µέρους της εργασίας αυτής, σχεδόν ότι χρειαζόµαστε για τη δηµιουργία του λογισµικού
που απαιτείται για την ανάπτυξη ενός ενσωµατωµένου συστήµατος Linux. Το αντίστοιχο πακέτο για τον Router NGW100 είναι το Atmel Linux BSP 3.0 και παρέχεται δωρεάν µε µια απλή επίσκεψη στον αντίστοιχο σύνδεσµο λήψης, του επίσηµου ιστότοπου της εταιρείας
Atmel: www.atmel.com/Images/AVR32_Linux_BSP_reduced_Image_3.0.0.zip.
Μετά την εξαγωγή των περιεχοµένων του συµπιεσµένου αρχείου ZIP, προκύπτει το αρχείο
AVR32_Linux_BSP_reduced_Image_3.0.0.iso το οποίο µε τη σειρά του περιλαµβάνει
τα παρακάτω:
Εικόνα 80. Τα περιεχόµενα του πακέτου Atmel Linux BSP 3.0
Οι ονοµασίες των καταλόγων είναι χαρακτηριστικές και αµέσως µας παρέχουν µια πρώτη
πληροφόρηση για το περιεχόµενό τους.
Ο κατάλογος appnotes (application notes) περιλαµβάνει οδηγίες για τη δηµιουργία του
συστήµατος host και την εγκατάσταση των απαραίτητων εφαρµογών. Επίσης περιλαµβάνονται κάποιες οδηγίες για την ανάπτυξη και εκτέλεση εφαρµογών Linux.
Ιστότοπος εργασίας: MyThesis.org
183
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Στον κατάλογο avr32studio υπάρχει το IDE AVR32 Studio το οποίο είναι βασισµένο σε
eclipse. Μας παρέχει τη δυνατότητα να µεταγλωττίζουµε τις εφαρµογές που αναπτύσσουµε
για τον Router NGW100 σε ένα πιο φιλικό και άνετο γραφικό περιβάλλον.
Ο κατάλογος datasheets θεωρητικά θα έπρεπε να περιέχει όλα τα τεχνικά εγχειρίδια των
ηλεκτρονικών στοιχείων. Όµως αυτό για άγνωστους λόγους, δε συνέβαινε. Στον συγκεκριµένο κατάλογο βρέθηκαν µόνο τα datasheets άλλων αναπτυξιακών πλακετών της Atmel, ενώ
για την πλακέτα atngw100 υπήρχε απλά ένας κενός κατάλογος.
Ο κατάλογος gnu_toolchain περιλαµβάνει την τοπική (native) αλυσίδα µεταγλώττισης
GNU AVR32 που θα εγκατασταθεί στο σύστηµα host προκειµένου να µεταγλωττιστεί η cross
toolchain του Buildroot αλλά και ότι άλλο ζητηθεί από τα makefiles του Buildroot. Επίσης περιλαµβάνει κάποιες χρήσιµες εφαρµογές της Atmel όπως είναι για παράδειγµα το πρόγραµµα avr32program το οποίο θα χρησιµοποιηθεί αργότερα για να επικοινωνήσουµε µε τη
συσκευή programmer JTAGICE mkII.
Ο κατάλογος buildroot περιλαµβάνει ένα κατάλληλα τροποποιηµένο αντίγραφο του αυτοµατοποιηµένου συστήµατος ανάπτυξης Buildroot και θα µας βοηθήσει µέσω της cross
toolchain να δηµιουργήσουµε τα δυαδικά αρχεία (images) του λογισµικού εκκίνησης, του
Linux Kernel και του συστήµατος αρχείων χρήστη /usr. Είναι ίσως το βασικότερο τµήµα λογισµικού του περιβάλλοντος ανάπτυξης AVR32 καθώς µέσω αυτού θα επιτυγχάνονται και µια
σειρά άλλων σηµαντικών ενεργειών ανάπτυξης, όπως είναι η µεταγλώττιση εφαρµογών για
τον Router NGW100 και η τροποποίηση των ρυθµίσεων του Linux Kernel, του BusyBox και
της βιβλιοθήκης uClibc.
Τέλος, στον κατάλογο documentation υπάρχει σε µορφή .html εγγράφων, µια πρόχειρη
τεκµηρίωση η οποία αφορά το υλικό και το λογισµικό της αναπτυξιακής πλακέτας που έχουµε επιλέξει.
6.2.1 Τροποποίηση του πακέτου υποστήριξης Atmel Linux BSP 3.0
Αφού ολοκληρώθηκε η λήψη και η εξαγωγή του πακέτου BSP, σειρά είχε η δοκιµαστική εγκατάσταση της αλυσίδας GNU AVR32 και του αυτοµατοποιηµένου συστήµατος Buildroot σε
µια προσωρινή εικονική µηχανή Linux. ∆ηλαδή η δοκιµαστική εγκατάσταση του περιβάλλοντος ανάπτυξης AVR32.
Στον κατάλογο gnu_toolchain του BSP, υπήρχε υποστήριξη για τις διανοµές Linux, Fedora, SuSE και Ubuntu. Επιλέχθηκε η τελευταία λόγω προηγούµενης εµπειρίας. Η νεότερη
έκδοση Ubuntu η οποία υποστηριζόταν από την αλυσίδα µεταγλώττισης GNU AVR32, ήταν η
8.04 (Ηardy Ηeron). Ακόµη όµως και για την έκδοση αυτή, η υποστήριξη ήταν ελλιπής.
Χρειάστηκε να γίνουν αρκετές τροποποιήσεις και να βρεθούν ορισµένες εφαρµογές της αλυσίδας GNU AVR32, που είτε έλειπαν, είτε η έκδοσή τους δεν ήταν η απαιτούµενη. Για το λόγο αυτό ο κατάλογος gnu_toolchain χρησιµοποιήθηκε µόνο σαν σηµείο αναφοράς.
Όλα τα παραπάνω οδήγησαν στο λογικό συµπέρασµα, ότι αφού θα έπρεπε να γίνει όλη
αυτή η διαδικασία από την αρχή, θα ήταν καλύτερο να χρησιµοποιηθεί ταυτόχρονα, και µια
νεότερη έκδοση της διανοµής Ubuntu. Επιλέχθηκε η 9.04 (Jaunty Jackalope).
Για την ολοκλήρωση όλων των παραπάνω ελέγχων χρησιµοποιήθηκαν αρκετά προσωρινά
περιβάλλοντα που δηµιουργήθηκαν σε εικονικές µηχανές (virtual machines) Linux. ∆εν θα
αναφερθούν καθώς δεν κρίνεται σκόπιµο.
Επικοινωνία: [email protected]
184
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Τελικά η όλη διαδικασία τυποποιήθηκε προκειµένου να µπορεί να επαναλαµβάνεται όσες
φορές χρειαστεί. Η τυποποίηση αυτή είχε ως αποτέλεσµα την δηµιουργία των αρχείων:
Εικόνα 81. Τα αρχεία εγκατάστασης του περιβάλλοντος ανάπτυξης
Ο κώδικας του αρχείου installer.sh θα εξεταστεί σε επόµενη παράγραφο.
Το αρχείο rousis_buildroot.tar.gz αποτελεί απλά τη συµπιεσµένη µορφή του καταλόγου buildroot που υπάρχει στο BSP της Atmel. Ενώ τα περιεχόµενα του αρχείου
rousis_toolchain.tar.gz τα οποία αποτελούν την τροποποιηµένη αλυσίδα GNU
AVR32, φαίνονται στην εικόνα που ακολουθεί:
Εικόνα 82. Τα περιεχόµενα του αρχείου rousis_toolchain.tar.gz
Ο κατάλογος partial και το αρχείο lock είναι κενά, αλλά χρειάζεται να υπάρχουν κατά
την εξαγωγή των περιεχοµένων του αρχείου rousis_toolchain.tar.gz στον κατάλογο
της εικονικής µηχανής Ubuntu, /var/cache/apt/archives.
6.3 ∆ηµιουργία της εικονικής µηχανής Ubuntu 9.04
Υπάρχουν αρκετά προγράµµατα δηµιουργίας εικονικών µηχανών. Στην παρούσα εργασία
επιλέχθηκε το VMware Player. Όπως ήδη αναφέραµε, η έκδοση της Ubuntu που εγκαταστάθηκε είναι η 9.04. Η επιλογή της έγινε µε γνώµονα την συµβατότητα των εκδόσεων των διαθέσιµων προγραµµάτων της αλυσίδας GNU AVR32 και των χαµηλών απαιτήσεων σε
Ιστότοπος εργασίας: MyThesis.org
185
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
πόρους συστήµατος που παρουσιάζει. Για τον εικονικό δίσκο της µηχανής παραχωρήθηκαν
10GB και για την εικονική RAM, 512MB. Στην εικόνα που ακολουθεί βλέπουµε την εφαρµογή
VMware µε εγκατεστηµένη την εικονική µας µηχανή:
Εικόνα 83. Η εφαρµογή VMware µε εγκατεστηµένη την εικονική µηχανή Ubuntu 9.04 (jaunty) + AVR32
Ουσιαστικά τα αρχεία από τα οποία αποτελείται µια εικονική µηχανή στο VMware Player
είναι δύο. Το αρχείο .vmx που περιέχει όλες τις ρυθµίσεις της µηχανής και το αρχείο .vmdk
που είναι ο εικονικός σκληρός δίσκος. Στην εικόνα βλέπουµε τα δύο αυτά αρχεία που δηµιουργήθηκαν κατά την ανάπτυξη του συστήµατός µας:
Εικόνα 84. Τα αρχεία από τα οποία αποτελείται µια εικονική µηχανή στο VMware Player
Επίσης, στην εικόνα που ακολουθεί φαίνεται η επιφάνεια εργασίας του τελικού εικονικού
συστήµατος host που δηµιουργήθηκε για τις απαιτήσεις ανάπτυξης αυτής της εργασίας:
Επικοινωνία: [email protected]
186
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Εικόνα 85. Η επιφάνεια εργασίας του τελικού εικονικού συστήµατος ανάπτυξης host
Για να υπάρχει η δυνατότητα αντιγραφής αρχείων µε απλό drag n drop, από την εικονική
µηχανή στα Windows και το αντίστροφο, χρειάστηκε να εγκατασταθούν τα VMware tools για
Linux (google.gr/#q=vmware+tools+for+linux).
6.3.1 Login µε δικαιώµατα root
Στο Linux υπάρχουν διάφοροι λογαριασµοί χρηστών (user accounts) ο καθένας µε τα δικά
του δικαιώµατα πρόσβασης. Ο χρήστης που έχει τον υψηλότερο βαθµό πρόσβασης είναι ο
root. Κάτι παρόµοιο µε τον Administrator των Windows.
Ο χρήστης root τις περισσότερες φορές είναι κρυµµένος από τον κανονικό χρήστη, αλλά
αρκετές λειτουργίες µπορούν να εκτελεστούν µε το βαθµό του, κάνοντας χρήση της εντολής
sudo ή su. Η εντολή αυτή προϋποθέτει ότι γνωρίζουµε το username (όνοµα χρήστη) και το
password (κωδικό πρόσβασης) του root.
Για να µην είµαστε αναγκασµένοι συνεχώς να πληκτρολογούµε τα στοιχεία αυτά, µπορούµε
να αποκτήσουµε δικαιώµατα root µόνιµα.
Αρχικά εκτελούµε την παρακάτω εντολή:
Ιστότοπος εργασίας: MyThesis.org
187
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
sudo passwd root
∆ίνουµε το password του root και εκτελούµε:
sudo gdm setup
Στο παράθυρο διαλόγου που θα ανοίξει, πηγαίνουµε στην καρτέλα “Security” και τσεκάρουµε το “Allow local administrator login”. Κλείνουµε το παράθυρο, κάνουµε
logoff και ξανά login χρησιµοποιώντας τώρα πια, ως username το root και ως password τον αυτόν που δώσαµε µετά την εκτέλεση της πρώτης εντολής.
6.3.2 ∆ηµιουργία του κεντρικού κατάλογου εργασίας /rousis
Για να υπάρχει ένα σηµείο αναφοράς στο οποίο θα αποθηκεύεται το λογισµικό και η τεκµηρίωση του περιβάλλοντος ανάπτυξης AVR32, αλλά και οτιδήποτε άλλο χρησίµευσε στην ανάπτυξη του Router NGW100 δηµιουργήθηκε στην εικονική µηχανή, ένα σύνολο
υποκαταλόγων κάτω από ένα κεντρικό κατάλογο µε την ονοµασία /rousis:
mkdir /rousis /rousis/buildroot /rousis/avr32studio /rousis/misc
Η κάθετος στο Linux (/) συµβολίζει τον κεντρικό κατάλογο (root folder) κάτω από τον οποίο
τοποθετούνται όλοι οι υπόλοιποι κατάλογοι του συστήµατος.
Οι υποκατάλογοι των υποκαταλόγων buildroot, avr32studio και misc, θα αναφέρονται στη συνέχεια, όποτε και εφόσον αυτό κρίνεται απαραίτητο.
6.4 Το περιβάλλον ανάπτυξης AVR32
Στο κεφάλαιο “Εργαλεία ανάπτυξης ενσωµατωµένων συστηµάτων Linux” του θεωρητικού
µέρους, έγινε η περιγραφή ορισµένων βασικών θεµάτων όπως είναι για παράδειγµα, η διαδικασία δηµιουργίας της αλυσίδας GNU, το αυτοµατοποιηµένο σύστηµα buildroot, το IDE
AVR32 Studio της ATMEL και η εφαρµογή Putty.
Σε αυτή την παράγραφο θα δούµε πως όλα αυτά εγκαταστάθηκαν στην εικονική µηχανή
Ubuntu απαρτίζοντας το ολοκληρωµένο περιβάλλον ανάπτυξης AVR32, το οποίο δίνει την
δυνατότητα δηµιουργίας εκτελέσιµου κώδικα και εφαρµογών για τον Router NGW100.
6.4.1 Εγκατάσταση Buildroot και αλυσίδας GNU AVR32
Αφού δηµιουργήθηκε η εικονική µηχανή Ubuntu και έγινε είσοδος σε αυτή µε µόνιµα δικαιώµατα root, σειρά είχε η εγκατάσταση του λογισµικού που προετοιµάστηκε κατά τη διαδικασία τροποποίησης του πακέτου υποστήριξης Atmel Linux BSP 3.0. Η πρώτη ενέργεια
αφορούσε την αντιγραφή των αρχείων (µε απλό drag n drop) στον ριζικό κατάλογο της Ubuntu:
Εικόνα 86. Τα αρχεία εγκατάστασης του περιβάλλοντος ανάπτυξης
Επικοινωνία: [email protected]
188
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Ο ριζικός κατάλογος στη διανοµή Ubuntu µπορεί να εντοπιστεί εύκολα µέσω του γραφικού
περιβάλλοντος της Ubuntu, από την µπάρα εργασίας: “Places > Computer > Filesystem”. Έπειτα µε drag n drop αντιγράφουµε τα τρία αρχεία.
Οι εντολές που έπρεπε να εκτελεστούν στη συνέχεια για να εκτελεστεί ο κώδικας του αρχείου installer.sh είναι:
chmod 755 installer.sh
./installer.sh
Το αρχείο installer.sh είναι ένα shell script που µπορεί να λειτουργεί σαν αυτοµατοποιηµένος εγκαταστάτης και αναπτύχθηκε ειδικά για τις ανάγκες αυτής της εργασίας. Ο πηγαίος του κώδικας είναι αρκετά απλός:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
#
# INSTALLER FOR THE ROUSIS AVR32 DEVELOPMENT ENVIRONMENT #
#
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#!/bin/sh
directory="/rousis"
if
[ -d $directory ]; then
echo Installation target directory is $directory
else
mkdir $directory
echo Directory $directory just created!
fi
mv rousis_toolchain.tar.gz
cd rousis
rousis_buildroot.tar.gz /rousis
echo
echo
echo Extracting Rousis Toolchain tar-ball to /var/cache/apt/archives
sleep 3
echo
tar xvzf rousis_toolchain.tar.gz
.......
echo
echo
echo Unpacking deb files in /var/cache/apt/archives/
sleep 3
echo
dpkg --unpack /var/cache/apt/archives/*deb
echo
echo
echo Extracting Buildroot tar-ball to /buildroot
sleep 3
echo
tar xvzf rousis_buildroot.tar.gz
.......
echo
echo
echo Installing AVR32 components ........
sleep 3
echo
apt-get -y install avr32program avr32gdbproxy avr32trace avrfwupgrade libavr32ocd
libavrtools libelfdwarfparser
echo
Ιστότοπος εργασίας: MyThesis.org
189
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
echo
echo Configure buildroot for Router NGW100 ...
sleep 3
echo
cd /rousis/buildroot
make ARCH=avr32 CROSS_COMPILE=avr32-linux- atngw100_defconfig
echo
echo
echo Creating buildroot, this will take several hours!!
echo
sleep 3
echo
# mporei na diarkesei mexri kai 3 ores analoga me to systima mas
make
echo
echo
echo Appending /rousis/buildroot/build_avr32/staging_dir/usr/bin to PATH
sleep 3
echo
echo "export PATH=$PATH:/buildroot-avr32-v2.3.0/build_avr32/staging_dir/usr/bin" >>
/root/.bashrc
export PATH=$PATH:/rousis/buildroot/build_avr32/staging_dir/usr/bin
# Uncomment to backup original installation files
#mkdir /rousis/misc/original-files
#mv /rousis/rousis_toolchain.tar.gz /rousis/misc/original-files
#mv /rousis/rousis_buildroot.tar.gz /rousis/misc/original-files
#mv /rousis/installer.sh /rousis/misc/original-files
echo
echo Done. Please logout and login again.
echo
Με απλή ανάγνωση του κώδικα είναι πολύ εύκολο να καταλάβει κανείς την χρησιµότητα και
το σκοπό του κάθε βήµατος που εκτελείται. Παρ’ όλα αυτά, η διαδικασία µπορεί να διαρκέσει
µέχρι και τρεις ώρες (ανάλογα µε το σύστηµά µας). Αυτό συµβαίνει επειδή στην ουσία γίνονται πολύ περισσότερα πράγµατα από µια απλή εγκατάσταση. Οι βασικότερες ενέργειες που
εκτελούνται είναι οι εξής:
Εξαγωγή των πακέτων .dep στον κατάλογο archives.
Εγκατάσταση των πακέτων .dep από τον κατάλογο archives.
Παραµετροποίηση του Buildroot για το σύστηµά µας (atngw100_defconfig) και
δηµιουργία cross toolchain, root filesystem, U-BOOT και target linux image.
Ενηµέρωση των µεταβλητών περιβάλλοντος για τη θέση του cross compiler
Όταν ολοκληρωθούν όλες οι διαδικασίες, στον κατάλογο rousis/buildroot/binaries
θα έχουν δηµιουργηθεί όλα τα αρχεία που είναι απαραίτητα για να λειτουργήσει ο Router
NGW100:
Επικοινωνία: [email protected]
190
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Εικόνα 87. Τα περιεχόµενα του καταλόγου binaries του συστήµατος Buidroot
Τα αρχεία rootfs.avr32.jffs2-root και rootfs.avr32.jffs2-root, περιλαµβάνουν τον Linux Kernel και το περιβάλλον χρήστη (/usr) αντίστοιχα. Το αρχείο u-boot.bin
περιλαµβάνει το λογισµικό εκκίνησης U-Boot. Το αρχείο rootfs.avr32.tar.bz2 περιλαµβάνει ένα πλήρες σύστηµα αρχείων αλλά δηµιουργείται για συστήµατα αρχείων που δεν
είναι πλέον δηµοφιλή και δεν υποστηρίζονται επαρκώς όπως είναι για παράδειγµα το yaffs2.
Για να δηµιουργηθεί το αρχείο rootfs.avr32.tar.bz2 θα πρέπει µέσα από το περιβάλλον του συστήµατος Buildroot να ενεργοποιήσουµε το “tar the root filesystem”. ∆ύο
άλλοι λόγοι για να χρησιµοποιήσουµε το αρχείο αυτό είναι όταν θέλουµε να φορτώσουµε το
root σύστηµα αρχείων µέσω δικτύου ή να εξάγουµε τα περιεχόµενά του σε ένα αποσπώµενο
µέσο αποθήκευσης όπως είναι για παράδειγµα µια κάρτα SD/MMC. Αυτό ακριβώς έγινε και
στην παρούσα εργασία κατά τη διαδικασία εγγραφής του συστήµατος αρχείων /usr στη σειριακή µνήµη Flash του Router NGW100. Ας δούµε όµως ποιοι είναι οι κατάλογοι που περιλαµβάνονται:
Ιστότοπος εργασίας: MyThesis.org
191
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 88. Τα περιεχόµενα του συµπιεσµένου αρχείου rootfs.avr32.tar.bz2
Το αρχείο linuxrc θα χρησιµοποιηθεί κατά την εκκίνηση. Αφού φορτωθεί ένα τυπικό σύστηµα αρχείων ο kernel θα εκτελέσει το linuxrc σαν την πρώτη του διεργασία. Μόλις ολοκληρωθεί και επιστρέψει τιµή επιτυχούς εκτέλεσης ο kernel θα θεωρήσει ότι έχει φορτωθεί το
ριζικό σύστηµα αρχείων και θα συνεχίσει µε την /sbin/init για να ξεκινήσει η διαδικασία
εκκίνησης του περιβάλλοντος χρήστη (user space).
Μετά την ολοκλήρωση των λειτουργιών του αρχείου installer.sh έγιναν κάποιες αλλαγές και κάποιες προσθήκες εφαρµογών. Οι εντολές παραµετροποίησης για το buildroot που
χρησιµοποιήθηκαν και τις οποίες έχουµε δει και σε προηγούµενο κεφάλαιο είναι:
make menuconfig
Για τον Kernel:
make linux26-menuconfig
Για την βιβλιοθήκη uClibc:
make uclibc-menuconfig
Και για το BusyBox:
make busybox-menuconfig
Επικοινωνία: [email protected]
192
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Οι εντολές αυτές θα χρειάζονται κάθε φορά που θα τροποποιούµε το λογισµικό συστήµατος
και εφαρµογών του Router NGW100. Όταν όλες οι αλλαγές είναι έτοιµες εκτελούµε την εντολή make για να ξεκινήσει η µεταγλώττισή.
6.4.2 Το εξειδικευµένο λογισµικό του Router NGW100
Προηγουµένως αναφέρθηκε ότι τα ολοκληρωµένα του Router NGW100, πριν χρησιµοποιηθούν θα πρέπει πρώτα να αρχικοποιηθούν. Για να επιτευχθεί κάτι τέτοιο απαιτείται εξειδικευµένος κώδικας που θα είναι σε θέση να συνδέσει το λογισµικό εκκίνησης αλλά και τον Kernel
µε το κάθε ολοκληρωµένο. Ο κατάλογος που αφορά τον εξειδικευµένο κώδικα του Router
NGW100 είναι ο ακόλουθος:
/rousis/buildroot/project_build_avr32/atngw100/linux-2.6.27.6/arch/avr32/boards/atngw100
Σε αυτό το σηµείο θα πρέπει να πούµε ότι ο πηγαίος κώδικας του Linux Kernel βρίσκεται
στον παρακάτω κατάλογο του συστήµατος host:
/rousis/buildroot/project_build_avr32/atngw100/linux-2.6.27.6/
Έτσι κάθε φορά που θα αναφερόµαστε σε ένα αρχείο που υπάρχει στον πηγαίο κώδικα του
Linux Kernel που χρησιµοποιήθηκε, θα εννοείται ως πρόθεµα η πιο πάνω διαδροµή.
Η διαδικασία αρχικοποίησης στον Router NGW100 πραγµατοποιείται από τον Kernel ο οποίος µε τη σειρά του παραµετροποιείται από το αρχείο setup.c που βρίσκεται στον κατάλογο arch/avr32/boards/atngw100.
Εκτός από τα ηλεκτρονικά στοιχεία που βρίσκονται συγκολληµένα στο PCB του Router
NGW100, υπάρχουν και άλλα που βρίσκονται ενσωµατωµένα στον µικροελεγκτή AP7000 και
ονοµάζονται περιφερειακά (peripherals). Τα περιφερειακά του AP7000 πρέπει να αρχικοποιηθούν και αυτά από εξειδικευµένο κώδικα. Η Atmel για το σκοπό αυτό παρέχει το αρχείο
arch/avr32/mach-at32ap/at32ap7000.c. Σε αυτό το αρχείο καθορίζονται τα ενσωµατωµένα περιφερειακά του µικροελεγκτή AP7000 τα οποία υποστηρίζονται από το Linux.
Τέλος θα πρέπει να αναφέρουµε και έναν ακόµη κατάλογο του αυτοµατοποιηµένου συστήµατος Buildroot που περιλαµβάνει εξειδικευµένο κώδικα για το λογισµικό εκκίνησης U-Boot:
/rousis/buildroot/project_build_avr32/atngw100/u-boot-1.3.4/board/atmel/atngw100
Στον κατάλογο αυτό υπάρχει το αρχείο atngw100.c αλλά και άλλος εξειδικευµένος κώδικας όπως οδηγοί συσκευών και βιβλιοθήκες. Ουσιαστικά το λογισµικό εκκίνησης U-Boot είναι
ένας mini kernel.
6.4.3 Εγκατάσταση του AVR32 Studio
Για την εγκατάσταση του AVR32Studio προαπαιτείται ύπαρξη του περιβάλλοντος ανάπτυξης της JAVA (JDK), µιας και πρόκειται για IDE που είναι βασισµένο στο eclipse. Στην εικόνα
βλέπουµε το παράθυρο διαλόγου που προέκυψε µετά την εγκατάσταση:
Ιστότοπος εργασίας: MyThesis.org
193
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 89. Παράθυρο διαλόγου µετά την εγκατάσταση της µηχανής JAVA
Στον κατάλογο εργασίας, /rousis της εικονικής µηχανής, αντιγράφηκε ολόκληρος ο κατάλογος avr32studio που υπάρχει στο BSP. Για να είναι σε θέση να λειτουργεί το AVR32
Studio, αρχικά έπρεπε το εκτελέσιµο που το εκκινεί να έχει τα απαραίτητα δικαιώµατα:
cd /rousis/avr32studio
chmod 755 avr32studio
Επίσης έπρεπε να συνδεθεί µε κάποιο τρόπο µε τον cross compiler avr32-linux-gcc.
Αυτό είναι απαραίτητο καθώς το AVR32 Studio για Linux δεν περιλαµβάνει κάποιον ενσωµατωµένο compiler. Για να επιτευχθεί κάτι τέτοιο προστέθηκε αντίστοιχη εγγραφή στην ειδική
µεταβλητή περιβάλλοντος (environment variable) PATH:
export PATH=$PATH:/rousis/buildroot/build_avr32/staging_dir/bin
Η εκτέλεση της εφαρµογής AVR32 Studio γίνεται απλά µε την παρακάτω εντολή. Η παράµετρος & είναι προαιρετική:
./avr32studio &
Μετά την εκτέλεση της εντολής εµφανίζεται η οθόνη φόρτωσης:
Εικόνα 90. Η αρχική οθόνη φόρτωσης του AVR32 Studio
Επικοινωνία: [email protected]
194
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Και στη συνέχεια εµφανίζεται ένα παράθυρο διαλόγου για να επιλέξουµε τον κατάλογο εργασίας του AVR32 Studio:
Εικόνα 91. Παράθυρο διαλόγου για την επιλογή καταλόγου εργασίας του AVR32 Studio
Τέλος εµφανίζεται το κεντρικό περιβάλλον εργασίας το οποίο είναι έτοιµο για την ανάπτυξη
εφαρµογών που θα τρέχουν στον Router NGW100:
Εικόνα 92. Tο κεντρικό περιβάλλον εργασίας του AVR32 Studio
Ιστότοπος εργασίας: MyThesis.org
195
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η εγκατάσταση του AVR32 Studio θα µπορούσε να ενσωµατωθεί σε εκείνη του Buildroot
και της αλυσίδας GNU AVR32, προσθέτοντας απλά ένα ακόµη συµπιεσµένο αρχείο. Ουσιαστικά το αρχείο αυτό θα περιλάµβανε τα περιεχόµενα του καταλόγου avr32studio. Έπειτα
θα έπρεπε να προστεθούν και οι αντίστοιχες γραµµές ενεργειών στον κώδικα του εγκαταστάτη installer.sh ώστε να γίνεται έλεγχος για την JAVA και να δηµιουργείται κατάλληλη
µεταβλητή περιβάλλοντος ώστε να συνδέεται το AVR32 Studio µε τον cross compiler του
συστήµατος Buildroot.
6.5 Βοηθητικό λογισµικό
Στο σύστηµα host ήταν απαραίτητο να υπάρχουν διαθέσιµα ορισµένα βοηθητικά προγράµµατα προκειµένου να είµαστε σε θέση να φέρουµε εις πέρας βασικές διαδικασίες κατά την
ανάπτυξη του συστήµατός µας. Τα κυριότερα εξ’ αυτών είναι:
FileZilla FTP client, για µεταφορά αρχείων από και προς τον Router NGW100
Putty terminal, για διαχείριση και debugging του Router NGW100
Standard Linux terminal, για την εκτέλεση εντολών στον φλοιό της Ubuntu
Τα προγράµµατα FileZilla και Putty, δε χρειάστηκε να εγκατασταθούν µόνο στην εικονική
µηχανή Ubuntu αλλά και στα Windows. Αυτό έγινε γιατί το VMware ορισµένες φορές δηµιουργεί εικονικές θύρες και συσκευές, που υπό κάποιες συνθήκες δε λειτουργούν σωστά.
Η διαδικασία εγκατάστασης στα Windows έγινε εκτελώντας τα αντίστοιχα εκτελέσιµα αρχεία
(setup.exe), ενώ στην εικονική µηχανή της διανοµής Ubuntu µέσω της παρακάτω εντολής:
apt-get install <onoma-programmatos>
Το AVR32 Studio του οποίου η εγκατάσταση αναλύθηκε στην προηγούµενη παράγραφο,
θεωρείται και αυτό έως ένα βαθµό, βοηθητικό πρόγραµµα. Οι εφαρµογές του Router
NGW100 είναι δυνατό να αναπτύσσονται και σε έναν απλό κειµενογράφο, ενώ η µεταγλώττιση µπορεί να γίνει µέσω γραµµής εντολών. Παρ’ όλα αυτά ένα IDE όπως το AVR32 Studio
θεωρείται πλέον βασικό λογισµικό κατά την ανάπτυξη κώδικα.
Το AVR32 Studio δεν χρειάστηκε να εγκατασταθεί στα Windows µιας και σε αυτή την περίπτωση θα ήταν δυνατό να εξάγει µόνο ανεξάρτητα (standalone) προγράµµατα για τον µικροελεγκτή AP7000 τα οποία θα µπορούσαν να εκτελούνται µόνο αυτόνοµα και όχι σαν
εφαρµογές Linux.
6.6 ∆ιαµέριση µνήµης
Πριν περιγράψουµε τη διαδικασία µεταφοράς λογισµικού στον Router NGW100 είναι χρήσιµο να αναφερθούν σύντοµα ορισµένες λεπτοµέρειες που αφορούν την διαµέριση (partitioning) της µνήµης.
Η µνήµη στον Router NGW100 αποτελείται από τρεις κατατµήσεις (partitions). Αυτό επιτυγχάνεται από το αρχείο arch/avr32/boards/atngw100/flash.c µέσω της δοµής δεδοµένων flash_parts. H δοµή αυτή για τον Router NGW100 έχει ως ακολούθως:
static struct mtd_partition flash_parts[] = {
{
.name
= "u-boot",
.offset
= 0x00000000,
.size
= 0x00020000,
.mask_flags
= MTD_WRITEABLE,
Επικοινωνία: [email protected]
/* mtd0 */
/* 128 KiB */
196
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
},
{
.name
.offset
.size
= "root",
= 0x00020000,
= 0x007d0000,
/* mtd1 */
.name
.offset
.size
.mask_flags
=
=
=
=
/* mtd2 */
},
{
"env",
0x007f0000,
0x00010000,
MTD_WRITEABLE,
},
};
Στη δοµή flash_parts του αρχείου flash.c καθορίζονται οι κατατµήσεις /dev/mtd0,
/dev/mtd1 και /dev/mtd2 οι οποίες αφορούν την παράλληλη µνήµη (AT49BV642D-70TU)
και χρησιµοποιούνται για την αποθήκευση των εξής στοιχείων λογισµικού:
mtd0
mtd1
mtd2
U-Boot
Linux Kernel (root filesystem ή /root)
∆ιαµοιραζόµενες πληροφορίες ανάµεσα σε U-Boot και Kernel (IP, MAC κλπ)
Το διαµέρισµα mtd2 ονοµάζεται και U-Boot environment (env) καθώς οι διαµοιραζόµενες
µεταβλητές – πληροφορίες που υπάρχουν αποθηκευµένες σε αυτό, διαχειρίζονται από το
λογισµικό εκκίνησης U-Boot.
Στη δοµή flash_parts δεν καθορίζεται mtd3 καθώς το περιβάλλον χρήστη (userspace ή
/usr) βρίσκεται στην σειριακή µνήµη (AT45DB642D).
6.7 Η συσκευή JTAGICE mkII
Η συσκευή JTAGICE mkII προτιµήθηκε λόγω του ότι είναι πλήρως συµβατή µε την αλυσίδα
εργαλείων ανάπτυξης GNU καθώς και µε τον µικροελεγκτή του Router NGW100, AP7000. Οι
τύποι προγραµµατισµού του µικροελεγκτή και επικοινωνίας µε αυτόν, που υποστηρίζονται
από τη συσκευή JTAGICE mkII, είναι οι ακόλουθοι:
SPI (Serial Peripheral Interface)
JTAG (Join Test Action Group)
PDI (Passive Direct Interface)
aWire
Debugging µέσω των ακόλουθων interfaces:
DebugWIRE (one wire)
JTAG
PDI
aWire
Τα κυριότερα χαρακτηριστικά που υποστηρίζει είναι:
Τουλάχιστον 3 hardware breakpoints ή ένα data breakpoint (ανάλογα µε την µονάδα
OCD του AVR µικροελεγκτή).
Συµβολικό debugging σύνθετων τύπων δεδοµένων µε πληροφορίες για το εύρος
(scope) τους.
Μέχρι και 128 software (program) breakpoints.
Πλήρης υποστήριξη για assembly αλλά και γλώσσες υψηλού επιπέδου (πχ C).
Ιστότοπος εργασίας: MyThesis.org
197
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Emulation για όλες τις αναλογικές και ψηφιακές λειτουργίες του µικροελεγκτή.
Περιλαµβάνει 512KB SRAM για γρήγορη βηµατική εκτέλεση (statement-level
stepping).
Μετατροπή επιπέδου τάσης από τα 1.8 έως τα 5.5 volt.
Γρήγορο upload που φτάνει τα 256Kb κώδικα σε 30 sec.
Συµβατότητα µε Full – speed USB 2.0 (12ΜΒ/s) και RS-232.
Firmware upgradable (µέσω AVR32 Studio) για την υποστήριξη νέων µικροελεγκτών.
Λειτουργεί µε εξωτερική (9 – 12 volt) ή µε USB τροφοδοσία.
Λειτουργία NanoTrace (ανάλογα µε την µονάδα OCD του µικροελεγκτή).
Περιλαµβάνει adaptors για να συνδέεται στα διάφορα διαθέσιµα hardware interfaces.
Ελέγχεται από το IDE του AVR32 Studio.
Η συσκευή JTAGICE mkII φαίνεται στην εικόνα:
Εικόνα 93. Η συσκευή programmer - emulator JTAGICE mkII της Atmel
6.8 Σύνδεση JTAGICE mkII µε το σύστηµα host
Μέχρι αυτή τη στιγµή έχει δηµιουργηθεί το σύστηµα host και το περιβάλλον ανάπτυξης
AVR32 για τη µεταγλώττιση πηγαίου κώδικα C σε εκτελέσιµα προγράµµατα που θα είναι
συµβατά µε τον µικροελεγκτή AP7000 και την αρχιτεκτονική AVR32. Επίσης, µετά την εκτέλεση του αρχείου installer.sh δηµιουργήθηκαν τα εκτελέσιµα του λογισµικού εκκίνησης
U-Boot, του Linux Kernel και του συστήµατος αρχείων χρήστη.
Το επόµενο που έπρεπε να γίνει, ήταν να µεταφερθεί στην παράλληλη µνήµη το λογισµικό
εκκίνησης. Σε αυτό το εγχείρηµα χρησιµοποιήθηκε το πρόγραµµα avr32program το οποίο
είναι ένα από τα προγράµµατα που εγκαταστάθηκαν νωρίτερα στο το περιβάλλον ανάπτυξης
AVR32.
Ο λόγος που επιλέχθηκε ο παράλληλος τύπος µνήµης είναι οι υψηλές ταχύτητες εγγραφής
– ανάγνωσης που αυτή προσφέρει. Η εκκίνηση του Router NGW100 έπρεπε να είναι όσο το
δυνατόν συντοµότερη προκειµένου να είναι άµεσα διαθέσιµος µετά από κάθε επανεκκίνηση ή
ενεργοποίησή του.
Το avr32program είναι ένα πρόγραµµα γραµµής εντολών το οποίο όταν χρησιµοποιηθεί
σε συνδυασµό µε τον programmer JTAGICE mkII της Atmel, µας δίνει τη δυνατότητα να µεταφέρουµε το πρόγραµµά µας στην µνήµη του συστήµατός µας.
Μέσω του προγράµµατος avr32program και του programmer JTAGICE mkII ανακτήθηκε
ο πλήρης έλεγχος του µικροελεγκτή AP7000 καθώς υπήρχε η δυνατότητα έναρξης και τερµα-
Επικοινωνία: [email protected]
198
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
τισµού εκτέλεσης, δυνατότητα reset αλλά και δυνατότητα ανάγνωσης των τιµών όλων των
καταχωρητών του.
Η συσκευή JTAGICE mkII, βασίζεται στην εξειδικευµένη λειτουργικότητα JTAG που βρίσκεται ενσωµατωµένη στην αρχιτεκτονική του µικροελεγκτή AP7000. Συνδέοντάς την µε τον
AP7000 παίρνουµε τον πλήρη έλεγχό του στα χέρια µας. Αυτό σηµαίνει ότι είµαστε σε θέση
να ελέγχουµε τα παρακάτω στοιχεία:
Μνήµη Flash, EEPROM και SRAM
Αρχείο καταχωρητών (register file)
Μετρητή προγράµµατος (Program Counter)
Fuse και lock bits
Μονάδες εισόδου – εξόδου (I/O modules)
Για τη φυσική σύνδεση του JTAGICE mkII µε τον Router NGW100, συνδέουµε το άκρο της
καλωδιοταινίας στα ελεύθερα pins του JTAG hardware interface που υπάρχει στην πλακέτα.
Η καλωδιοταινία σύνδεσης ονοµάζεται JTAG probe και φαίνεται στην παρακάτω εικόνα:
JTAGICE
mkII
probe
Εικόνα 94. Η καλωδιοταινία σύνδεσης JTAG probe
Στο silkscreen (µεταξοτυπία) της πλακέτας µπορούµε να διακρίνουµε και το κείµενο jtag
που µας ενηµερώνει ότι τα δέκα διαθέσιµα pins που υπάρχουν, προσφέρονται για σύνδεση
JTAG:
JTAG
hardware
interface
Εικόνα 95. Η διεπαφή υλικού JTAG του Router NGW100
Στην εικόνα φαίνεται η σύνδεση της συσκευής JTAGICE mkII µε τον Router NGW100, µέσω
του JTAG probe:
Ιστότοπος εργασίας: MyThesis.org
199
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
JTAGICE
mkII
probe
AP7000
Εικόνα 96. Σύνδεση της συσκευής JTAGICE mkII µε τον Router NGW100
Οι τρόποι επικοινωνίας µε υπολογιστή που υποστηρίζονται από την συσκευή JTAGICE
mkII είναι: USB και RS232. Στην πρώτη περίπτωση δεν χρειάζεται να χρησιµοποιήσουµε έξτρα τροφοδοσία καθώς παρέχεται από τον δίαυλο, στην δεύτερη περίπτωση η εξωτερική
πρόσθετη τροφοδοσία, είναι απαραίτητη.
Στην εικόνα βλέπουµε τις δύο θύρες, USB και RS232 που υπάρχουν στο πίσω µέρος του
JTAGICE mkII:
RS232
POWER
USB
ON/OFF
Εικόνα 97. Θύρες, USB, RS232 και τροφοδοσίας στο πίσω µέρος της συσκευής JTAGICE mkII
∆ιαγραµµατικά η σύνδεση του host συστήµατός µας µε τον Router NGW100, µέσω του
JTAGICE mkII, θα µπορούσε να παρουσιαστεί διαγραµµατικά ως εξής:
Εικόνα 98. ∆ιάγραµµα σύνδεσης του συστήµατός host µε τον Router NGW100
Επικοινωνία: [email protected]
200
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Η σύνδεση του JTAGICE mkII µε το σύστηµα host έγινε µέσω USB. Για την αναγνώριση της
συσκευής από το λειτουργικό σύστηµα δεν απαιτήθηκε η εγκατάσταση drivers µιας και αυτοί
υπήρχαν διαθέσιµοι στο AVR32 Studio αλλά και στο avr32program.
Για να γίνει διάγνωση της σωστής λειτουργίας της συσκευής JTAGICE mkII αλλά και της
επικοινωνίας της µε το σύστηµα host, εκτελέστηκαν ορισµένες απλές εντολές µέσω του προγράµµατος avr32program. Η πρώτη εντολή που εκτελέστηκε είναι η cpuinfo –F η οποία
επιστρέφει τα κυριότερα χαρακτηριστικά του µικροελεγκτή AP7000 και της συσκευής
JTAGICE mkII:
Εικόνα 99. Εκτέλεση της εντολής cpuinfo –F µέσω του προγράµµατος avr32program και του JTAGICE mkII
Έπειτα έγινε εκτέλεση της readregs η οποία επέστρεψε µια λίστα µε καταχωρητές του
AP7000 και τις αντίστοιχες διευθύνσεις της εσωτερικής του µνήµης:
Ιστότοπος εργασίας: MyThesis.org
201
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 100. Εκτέλεση της εντολής readregs µέσω του προγράµµατος avr32program και του JTAGICE mkII
6.9 Εγγραφή U-Boot στην παράλληλη µνήµη
Αφού επιβεβαιώθηκε ότι όλα λειτουργούν σωστά στη συνέχεια έπρεπε να αντιγραφεί στον
Router NGW100 το πρώτο τµήµα λογισµικού που είναι το λογισµικό εκκίνησης U-Boot και
πιο συγκεκριµένα το εκτελέσιµο αρχείο uboot.bin. Αρχικά έγινε εκκαθάριση της παράλληλης µνήµης Flash:
avr32program erase -fcfi@0
Η εκκαθάριση έγινε υποχρεωτικά διότι σε διαφορετική περίπτωση η διαδικασία εγγραφής
της, αποτύγχανε. Στην εικόνα βλέπουµε τα µηνύµατα που εµφανίστηκαν στην κονσόλα:
Εικόνα 101. Eκκαθάριση της παράλληλης µνήµης Flash µέσω του JTAGICE mkII
Ακολούθησε η µεταφορά και εγγραφή του αρχείου uboot.bin. χωρίς να καθοριστεί κάποια
συγκεκριµένη διεύθυνση µνήµης, για να ξεκινήσει η εγγραφή από την πρώτη θέση που είναι
η 0x00000000:
cd /rousis/buildroot/binaries/atngw100
avr32program program -F bin -vfcfi@0 uboot.bin
Στην εικόνα βλέπουµε τα µηνύµατα που εµφανίστηκαν στην κονσόλα:
Εικόνα 102. Εγγραφή του λογισµικού εκκίνησης στην παράλληλη µνήµη µέσω του JTAGICE mkII
Επικοινωνία: [email protected]
202
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Σε αυτό το σηµείο η συσκευή JTAGICE mkII αποσυνδέθηκε και ο Router NGW100 απενεργοποιήθηκε για να συνδεθούµε µέσω κονσόλας στο περιβάλλον γραµµής εντολών του UBoot. Αυτό έγινε για να διαπιστωθεί ότι όλα έχουν γίνει σωστά µέχρι εκείνη τη στιγµή και ότι
υπάρχει ένας λειτουργικός bootloader στο σύστηµά µας. Ουσιαστικά αυτή είναι και η πρώτη
φορά που µπορούσε να γίνει έλεγχος ως προς τα αποτελέσµατα που έδωσε το αυτοµατοποιηµένο σύστηµα Buildroot στον κατάλογο /rousis/buildroot/binaries/atngw100.
Επίσης σε αυτό το σηµείο ελέγχθηκε ταυτόχρονα και η ορθότητα της λειτουργίας των ηλεκτρονικών στοιχείων του Router NGW100.
Η σύνδεση του Router NGW100 µε το σύστηµα host έγινε σειριακά (πρωτόκολλο RS232,
βύσµα DB9) µέσω του καλωδίου που βλέπουµε στην εικόνα:
Εικόνα 103. Καλώδιο σειριακής επικοινωνίας RS232
Από την πλευρά του συστήµατος host χρησιµοποιήθηκε η εφαρµογή Putty. Οι ρυθµίσεις της
σειριακής επικοινωνίας φαίνονται στο παράθυρο διαλόγου παραµετροποίησης στην εικόνα
που ακολουθεί:
Εικόνα 104. Παράµετροι σειριακής επικοινωνίας της εφαρµογής PuTTY
Ιστότοπος εργασίας: MyThesis.org
203
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η συσκευή /dev/ttyS0 στο Linux είναι αντίστοιχη της θύρας COM1 στα Windows.
Επιλέγοντας την κατηγορία Session
Open και ενεργοποιώντας την τροφοδοσία του
Router NGW100, εµφανίστηκαν τα πρώτα µηνύµατα του λογισµικού εκκίνησης U-Boot. Επειδή όµως το δυαδικό αρχείο του Kernel (uImage) δεν υπήρχε ακόµη στην µνήµη, το U-Boot
εµφάνιζε ορισµένα αναµενόµενα (και επιθυµητά) µηνύµατα σφάλµατος. Τελικά, το command
prompt του U-Boot εµφανίστηκε κανονικά:
Εικόνα 105. Το command prompt του U-Boot
Εκτελώντας την εντολή help στο U-Boot παρουσιάζεται µια λίστα µε τις διαθέσιµες εντολές
και µια µικρή περιγραφή που αφορά την λειτουργία της κάθε µιας από αυτές:
Επικοινωνία: [email protected]
204
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Εικόνα 106. Εκτλελεση της εντολής help στο U-Boot
Εκτελώντας την εντολή flinfo εµφανίζεται ο χάρτης της παράλληλης µνήµης όπου µε R0
συµβολίζονται οι χαρτογραφηµένες διευθύνσεις του αντίστοιχου καταχωρητή ο οποίος είναι
ουσιαστικά και αυτός που χρησιµοποιείται πρώτος κατά την εκκίνηση του Router NGW100:
Ιστότοπος εργασίας: MyThesis.org
205
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 107. Εκτλελεση της εντολής flinfo στο U-Boot
Η µνήµη διαβάζεται από αριστερά προς τα δεξιά όπως ακριβώς και σε ένα κείµενο. Ο καταχωρητής R0 έχει µήκος 40 bytes, ενώ η πρώτη και τελευταία του διεύθυνση υποδηλώνει την
αρχή και το τέλος αντίστοιχα, της παράλληλης µνήµης. Το µέγεθος του κάθε µπλοκ (block
size ή bs) είναι 1024 bits (ή 128 bytes).
Αυτή είναι η πρώτη φορά που ο Router NGW100 απέκτησε επαφή µε το περιβάλλον και
παρείχε κάποιου είδους αλληλεπίδραση. Αυτό που αποµένει είναι η φόρτωση του συστήµατος αρχείων Linux root (Kernel) και του userspace.
6.10 Εγγραφή Linux Kernel στην παράλληλη µνήµη
Με τον ίδιο τρόπο περίπου πραγµατοποιήθηκε και η εγγραφή του Linux Kernel:
avr32program program -F bin -vfcfi@0 -O 0x20000 rootfs.avr32.jffs2-root
Εφόσον οι πρώτες θέσεις µνήµης 0x00000000 έως 0x00010000 δεσµεύονται από τον
καταχωρητή R0 και το λογισµικό εκκίνησης U-Boot, ο Kernel έπρεπε να ξεκινά από την αµέσως επόµενη θέση, 0x00020000 (ή αλλιώς 0x20000). Στην εικόνα βλέπουµε τα µηνύµατα
που εµφανίστηκαν στην κονσόλα µετά την εκτέλεση της εντολής:
Εικόνα 108. Εγγραφή Linux Kernel στην παράλληλη µνήµη µέσω του JTAGICE mkII
Επικοινωνία: [email protected]
206
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
6.11 Εγγραφή συστήµατος αρχείων /usr
Στο στάδιο αυτό µεταφέρθηκε και γράφτηκε στην µνήµη Flash του Router NGW100 το αρχείο rootfs.avr32.jffs2-usr (περιβάλλον χρήστη /usr). Η µεταφορά αυτή έγινε µε τη
βοήθεια του λογισµικού εκκίνησης U-Boot:
Το U-Boot υποστηρίζει πολλούς τρόπους µέσω των οποίων θα µπορούσε να ολοκληρωθεί
η διαδικασία µεταφοράς:
Με φορητή µνήµη SD-card
Μέσω δικτύου
Σειριακά (πρωτόκολλο Kermit)
Επιλέχθηκε ο πρώτος τρόπος επειδή κρίθηκε πιο άµεσος και σύντοµος. Για το σκοπό αυτό
χρησιµοποιήθηκε µια MMC/SD-card χωρητικότητας 2GB της εταιρείας SanDisk, η οποία φαίνεται και στην εικόνα:
Εικόνα 109. SanDisk MMC/SD-card
Αρχικά η SD-card συνδέθηκε µέσω ενός ειδικού προσαρµογέα (MEM-Flex, TMS-CRMF10R της εταιρίας takeMS) σε µια θύρα USB του συστήµατος host προκειµένου να διαµορφωθεί µε το σύστηµα αρχείων ext2. Θα µπορούσε να χρησιµοποιηθεί η θύρα USB σε συνδυασµό µε τον SD-card reader που υπάρχουν ενσωµατωµένα στον Router NGW100 αλλά
δεν επιλέχθηκε αυτός ο τρόπος για λόγω ορισµένων δυσλειτουργιών των αντίστοιχων USB
drivers. Οι εντολές που εκτελέστηκαν για τη διαµόρφωση της SD-card είναι οι παρακάτω:
umount /dev/sdb1
/sbin/mke2fs /dev/sdb1
/sbin/e2fsck /dev/sdb1
mkdir /sd
mount /dev/sdb1 /sd
cd /sd
Στη συνέχεια έπρεπε να γίνουν οι απαραίτητες ενέργειες για να µπορεί ο Router NGW100
να εκκινήσει από την SD-card. Αρχικά µεταφέρθηκε σε αυτή το δυαδικό αρχείο
/rousis/buildroot/binaries/atngw100/rootfs.avr32.jffs2-usr, και έγινε εξαγωγή του αρχείου rootfs.avr32.tar.bz2 µέσω της εντολής:
tar xjvf /rousis/buildroot/binaries/atngw100/rootfs.avr32.tar.bz2
Μετά την ολοκλήρωση της εξαγωγής, έπρεπε να γίνει µια µικρή τροποποίηση του αρχείου
/sd/etc/fstab προκειµένου να µην γίνει εκκίνηση από λάθος σηµείο της µνήµης. Αυτό
Ιστότοπος εργασίας: MyThesis.org
207
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
απαιτούσε την εισαγωγή µιας συγκεκριµένης γραµµής σε σχόλια (βάζοντας ως πρόθεµα το
χαρακτήρα #), έτσι ώστε να µην είναι εκτελέσιµη κατά την εκκίνηση:
#mtd3
/usr
jffs2
defaults
0
0
Σε αυτό το σηµείο η SD-card αφαιρέθηκε από το σύστηµα host για να συνδεθεί στον Router
NGW100. Για την ασφαλή κατάργηση της συσκευής εκτελέστηκαν οι πιο κάτω εντολές:
cd /
umount /sd
Το επόµενο βήµα αφορούσε την εκκίνηση του Router NGW100 και την εισαγωγή µας σε
περιβάλλον U-Boot. Το λογισµικό εκκίνησης πρέπει να γνωρίζει πως θα εκκινήσει το σύστηµα. ∆ηλαδή σε ποια διεύθυνση µνήµης βρίσκεται ο Kernel. Στην περίπτωσή µας η διεύθυνση
αυτή βρισκόταν στην SD-card:
Uboot>
Uboot>
Uboot>
Uboot>
set bootargs 'console=ttyS0 root=/dev/mmcblk0p1 rootwait'
set bootcmd 'mmcinit; ext2load mmc 0:1 0x10400000 /boot/uImage; bootm'
saveenv
boot
Η εκτέλεση των παραπάνω εντολών είχε ως αποτέλεσµα να αλλάξει το φυσικό µέσο εκκίνησης και ταυτόχρονα να γίνει εκκίνηση του Linux. Η σηµασία της κάθε εντολής έχει ως εξής:
mmcinit Αρχικοποίηση της SD-card
ext2load mmc 0:1 0x10300000 /boot/uImage
Φόρτωση του αρχείου uImage από την SD-Card στην διεύθυνση µνήµης 0x10300000
bootm Εκκίνηση από την µνήµη
Οι εντολές που ακολουθούν εκτελέστηκαν για να γίνει καθαρισµός της µνήµης flash του
Router NGW100 και στη συνέχεια να εγγραφεί σε αυτή το δυαδικό αρχείο του περιβάλλοντος
χρήστη /usr:
~# flash_eraseall /dev/mtd3
~# dd if=/rootfs.avr32.jffs2-usr of=/dev/mtd3 bs=1056
~# reboot
Η εντολή flash_eraseall διαγράφει το διαµέρισµα mtd3 (δηλαδή όλη τη σειριακή Flash)
και η dd αντιγράφει το δυαδικό αρχείο rootfs.avr32.jffs2-usr στο διαµέρισµα αυτό.
Το µέγεθος block της µνήµης είναι 1056 bits (ή 132 bytes). Στην εικόνα βλέπουµε την εκτέλεση της εντολής dd:
Εικόνα 110. Εγγραφή συστήµατος αρχείων /usr από την SD-card µέσω της εντολής dd
Τέλος, σε περιβάλλον U-boot έγιναν οι αντίστροφες αλλαγές προκειµένου ο Router
NGW100 να εκκινεί από την µνήµη flash και όχι από την SD-card:
Uboot> set bootargs 'root=/dev/mtdblock1 rootfstype=jffs2 rootwait'
Uboot> set bootcmd 'fsload /boot/uImage;bootm'
Επικοινωνία: [email protected]
208
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Uboot> saveenv
Uboot> boot
6.12 ∆ιαδικασία εκκίνησης
Σε αυτό το σηµείο είναι χρήσιµο να περιγράψουµε τη διαδικασία εκκίνησης του Router
NGW100 ώστε να γίνει περισσότερο κατανοητός ο λόγος ύπαρξης όλων όσων έχουν πραγµατοποιηθεί έως τώρα. Η διαδικασία αυτή γίνεται καλύτερα αντιληπτή και µε τη βοήθεια του
σχηµατικού του Router NGW100 που παρατίθεται και σε αντίστοιχο παράρτηµα. Επίσης, ακόµη µεγαλύτερη κατανόηση επιτυγχάνεται και µέσω των µηνυµάτων που εµφανίζονται στο
τερµατικό Putty αν συνδεθούµε σειριακά στον Router NGW100 κατά τη διαδικασία εκκίνησης.
Για το λόγο αυτό, σχεδόν σε κάθε βήµα που θα περιγράφεται παρακάτω, θα υπάρχει και η
αντίστοιχη εικόνα (screenshot).
Η διαδικασία εκκίνησης θα µπορούσε να συνοψιστεί στα 5 παρακάτω βασικά κύρια στάδια:
Reset του µικροελεγκτή AP7000 και εκτέλεση του bootloader U-Boot
Ο U-Boot φορτώνει και εκτελεί τον Kernel
Ο Kernel εκτελεί και εκκινεί την διεργασία init
Η διεργασία init εκτελεί και εκκινεί το script rcS
Το script rcS καλεί ένα σύνολο άλλων scripts για να αρχικοποιήσει το σύστηµα και να
εκκινήσει την γραµµή εντολών στο φλοιό του kernel (shell ή sh bash)
Επειδή όµως η κατανόησή της διαδικασίας εκκίνησης µπορεί να µας δώσει µια πολύ καλή
εικόνα για τη δοµή και τη λειτουργία του Router NGW100, είναι χρήσιµο να την περιγράψουµε πιο αναλυτικά.
Ο βασικότερος παράγοντας που εµπλέκεται στη διαδικασία εκκίνησης είναι ο µικροελεγκτής
AP7000, στους ακροδέκτες του οποίου βρίσκονται συνδεδεµένα, και ελέγχονται όλα τα ηλεκτρονικά υποσυστήµατα του Router NGW100.
Όταν ο AP7000 τροφοδοτείται για πρώτη φορά µε την απαιτούµενη τάση και ένταση ρεύµατος, τίθεται σε κατάσταση POR (Power-On Reset). Σε αυτό το στάδιο επιβεβαιώνεται ότι όλα
τα κρίσιµα υποσυστήµατά του µεταβαίνουν στην κατάλληλη κατάσταση λειτουργίας. Αµέσως
µετά ο AP7000 χρησιµοποιεί τον ακροδέκτη XIN0 ως πηγή χρονισµού.
Αφού ολοκληρωθεί το reset, ο AP7000 προσκοµίζει την πρώτη εντολή από την εσωτερική
του µνήµη και πιο συγκεκριµένα από τη διεύθυνση 0xA000_0000 (reset address). Η διεύθυνση αυτή αντιστοιχεί στον τοµέα P2 που βρίσκεται µόνιµα χαρτογραφηµένος στην περιοχή
διευθύνσεων 0x0000_0000 έως 0x2000_0000, της φυσικής µνήµης του AP7000. Αυτό σηµαίνει ότι η εντολή που προσκοµίζεται από την εικονική διεύθυνση 0xA000_0000, ουσιαστικά προσκοµίζεται από την φυσική διεύθυνση 0x0000_0000 (R1). Σε αυτή τη διεύθυνση
βρίσκεται ο ακροδέκτης EBI SRAM CS0 στον οποίο συνδέεται η εξωτερική µνήµη
AT49BV642D-70TU όπου βρίσκεται αποθηκευµένο το λογισµικό εκκίνησης U-Boot (partition
mtd0). Το λογισµικό U-Boot αναζητά και φορτώνει τον Linux Kernel από το αρχείο uImage
που βρίσκεται και αυτό στην παράλληλη µνήµη AT49BV642D-70TU. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Ιστότοπος εργασίας: MyThesis.org
209
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 111. ∆ιαδικασία εκκίνησης στάδιο 1
Ο Linux Kernel του Router NGW100 ξεκινά µε την εκτέλεση της συνάρτησης
start_kernel η οποία βρίσκεται στο αρχείο init/main.c. Το βασικότερο αρχείο πηγαίου κώδικα που φροντίζει για να συµβεί αυτό, είναι το αρχείο head.S (που είναι γραµµένο σε
assembly), το οποίο βρίσκεται στον κατάλογο arch/avr32/boot/u-boot και επικοινωνεί
µε τον U-Boot. Η συνάρτηση start_kernel αρχικοποιεί τους task schedulers και εµποδίζει
να εκτελεστεί οποιαδήποτε άλλη λειτουργία, µέσω της συνάρτησης preempt_disable, µέχρις ότου να µπορέσουν να χαρτογραφηθούν οι απαραίτητες διακοπές του µικροελεγκτή
AP7000. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Επικοινωνία: [email protected]
210
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Εικόνα 112. ∆ιαδικασία εκκίνησης στάδιο 2
Στη συνέχεια ο Kernel αρχικοποιεί και καταχωρεί τις υπηρεσίες του συστήµατος, όπως για
παράδειγµα τη στοίβα TCP/IP, και τους οδηγούς των συσκευών για τα περιφερειακά
USARTs, Ethernet controller, MMC (SD card controller), USB κλπ. Μετά την καταχώρηση και
την αρχικοποίηση, αντιστοιχεί τις αναγκαίες διακοπές. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 113. ∆ιαδικασία εκκίνησης στάδιο 3
Έπειτα αφού ελέγξει τον αριθµό των µνηµών CFI που υπάρχουν (µέσω του αρχείου
drivers/mtd/maps/physmap_of.c), πραγµατοποιεί διαµέριση της παράλληλης µνήµης
και φορτώνει το partition mtd1, µε το σύστηµα αρχείων root για να γίνει εκτέλεση του
/sbin/init. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Ιστότοπος εργασίας: MyThesis.org
211
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 114. ∆ιαδικασία εκκίνησης στάδιο 4
Σειρά έχει η χαρτογράφηση κάποιων επιπλέον καταχωρητών και διακοπών που αφορούν
την επικοινωνία USB (που όµως δε µας αφορά στην παρούσα εργασία) το RTC (Real Time
Clock) και το WDT (Watch Dog Timer) του AP7000, αλλά και τον ελεγκτή MCI της Atmel
(Multimedia Card Interface). Επίσης γίνεται η καταχώρηση των σηµάτων GPIO των τριών
LEDs SYS, A και B. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 115. ∆ιαδικασία εκκίνησης στάδιο 5
Φορτώνεται και καταχωρείται το cubic TCP (wikipedia.org/wiki/CUBIC_TCP) και οι
υπηρεσίες του. Και τέλος, γίνονται κάποιες ρυθµίσεις της συχνότητας λειτουργίας του
AP7000 καθώς και της ζώνης ώρας του λειτουργικού συστήµατος Linux. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 116. ∆ιαδικασία εκκίνησης στάδιο 6
Σε αυτό το σηµείο η φόρτωση του Linux Kernel και του root filesystem έχει ολοκληρωθεί. Η
υπόλοιπη διαδικασία εκκίνησης πραγµατοποιείται από προγράµµατα του περιβάλλοντος
χρήστη (userspace) τα οποία είναι υπεύθυνα και τη φόρτωση του συστήµατος αρχείων
/usr.
Η διεργασία Init είναι η πρώτη λειτουργία που εκτελείται σε ένα ενσωµατωµένο σύστηµα
Linux και είναι ο γονέας (parent) όλων των υπόλοιπων διεργασιών που θα εκτελεστούν µετά
από αυτή. ∆ηλαδή έχει PID (Process IDentifier) την µονάδα. Η Init διαβάζει το αρχείο
Επικοινωνία: [email protected]
212
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
linuxrc το οποίο εκκινεί το πρόγραµµα BusyBox. Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 117. ∆ιαδικασία εκκίνησης στάδιο 7
Αµέσως µετά γίνεται ανάγνωση του αρχείου /etc/inittab προκειµένου να αποφασιστεί
µέσω της οδηγίας ::sysinit: ποιες θα είναι οι επόµενες ενέργειες που θα εκτελεστούν:
# Run the rcS script after kernel is booted.
::sysinit:/etc/init.d/rcS
# Run a shell on the first serial port. Comment out if you want a getty instead.
ttyS0::respawn:-/bin/sh
# Run a shell on the g_serial port (USB gadget device)? This shell will spawn
# error message if the device is not connected.
#ttygserial::respawn:-/bin/sh
# Uncomment this to run a getty on the first serial port.
#ttyS0::respawn:/sbin/getty -L ttyS0 115200 vt100
# Run a script on shutdown.
::shutdown:/etc/init.d/rcK
Οι ενέργειες αυτές περιλαµβάνονται συνήθως σε κάποια αρχεία κώδικα εκκίνησης (boot
scripts ή startup scripts) τα οποία χαρακτηρίζονται και από έναν αύξων αριθµό προκειµένου
να εκτελούνται µε την σωστή σειρά. Στον Router NGW100 το πρώτο από αυτά τα αρχεία που
εκτελείται (λόγω της ::sysinit:) είναι το αρχείο rcS το οποίο βρίσκεται στον κατάλογο
/etc/init.d του συστήµατος αρχείων root. Ο κώδικας του αρχείου εκκίνησης rcS (run
commands Start) είναι ο ακόλουθος:
#!/bin/sh
for s in /etc/init.d/S*; do
if [ -x $s ]; then
$s start
fi
done
echo
echo
echo
echo
echo
echo
echo
" * * * * * * * * * * * * * * * * * * * "
" *
* "
" * Rousis Network Gateway is Ready!
* "
" *
* "
" * * * * * * * * * * * * * * * * * * * "
Ο παραπάνω κώδικας εκτελεί όλα τα εκτελέσιµα αρχεία του καταλόγου /etc/init.d, που
περιέχουν κώδικα εκκίνησης και ξεκινούν από τον χαρακτήρα S. Το πρώτο από αυτά είναι το
S00mountvirtfs που φορτώνει ορισµένα πολύ χρήσιµα εικονικά συστήµατα αρχείων. Τα
µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Ιστότοπος εργασίας: MyThesis.org
213
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 118. ∆ιαδικασία εκκίνησης στάδιο 8
Στη συνέχεια εκτελούνται άλλα επτά scripts:
S01hotplug
Ενεργοποιεί το σύστηµα /mdev το οποίο είναι υπεύθυνο για την
φόρτωση και την εµφάνιση των συνδεδεµένων συσκευών αλλά και για τη δυναµική
προσθήκη ή αφαίρεση συσκευών αποσπώµενων (πχ usb sticks) και εξωτερικών partitions µνήµης. Η επιτυχής εκτέλεση αυτού του script είναι πολύ σηµαντική!
S02hostname Ενεργοποιεί τον loopback adaptor (127.0.0.1 ή localhost) και
εντοπίζει το αρχείο hostname και ενηµερώνει τον DNS.
S05avahi-setup.sh Ενεργοποιεί την υπηρεσία αυτόµατης αναγνώρισης σύνδεσης νέων συσκευών στο τοπικό δίκτυο (παρόµοιο µε το bonjour της Apple).
S08syslog
S09klog
Ενεργοποιεί τα αρχεία καταγραφής κατάστασης συστήµατος.
Ενεργοποιεί τα αρχεία καταγραφής κατάστασης του Kernel.
S10modules-init
etc/modules.
Φορτώνει όλα τα modules που αναφέρονται στο αρχείο
S13portmap Μετατρέπει τους αριθµούς RPC των προγραµµάτων, σε θύρες TCP
και UDP (wikipedia.org/wiki/Portmap).
Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 119. ∆ιαδικασία εκκίνησης στάδιο 9
Σε αυτό το σηµείο εκτελείται το αρχείο S15localfs και φορτώνεται το σύστηµα αρχείων
/usr του περιβάλλοντος χρήστη, στην σειριακή µνήµη flash (AT45DB642D) που αντιπροσωπεύεται από το partition mtd3. Τo µήνυµα κατάστασης που εµφανίζεται στο τερµατικό
Putty είναι:
Επικοινωνία: [email protected]
214
Προγραµµατισµός και εκκίνηση του Router NGW100 – Κεφάλαιο 6
Εικόνα 120. ∆ιαδικασία εκκίνησης στάδιο 10
Μετά τη φόρτωση του συστήµατος αρχείων /usr εκτελείται το αρχείο S20network προκειµένου να ενεργοποιηθεί η δυνατότητα δικτύωσης του Router NGW100. Οι κυριότερες ενέργειες που πραγµατοποιούνται σε αυτό το στάδιο είναι η ενεργοποίηση των διεπαφών
Ethernet, eth0 και eth1 (macb0 και macb1) για τα WAN και LAN αντίστοιχα (µε τη βοήθεια
και του MACB driver). Σε αυτό το στάδιο αντιστοιχείται και µια στατική IP στη διεπαφή δικτύου
WAN. Αυτό γίνεται µέσω του DHCP client udhcpc.
Η εφαρµογή udhcp έπρεπε να εγκατασταθεί µιας και ο Router NGW100 δεν περιλαµβάνει
κάποιο modem ώστε να εκτελεί το πρωτόκολλο (PPP) για να συνδεθεί στον ISP. Εποµένως
η πρόσβασή του στο Internet εξαρτάται από την ύπαρξη κάποιου τοπικού modem gateway.
Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Εικόνα 121. ∆ιαδικασία εκκίνησης στάδιο 11
Αφού η ενεργοποίηση της υποδοµής του δικτύου έχει ολοκληρωθεί µε επιτυχία, έχει έρθει
πλέον η στιγµή να φορτωθούν οι υπηρεσίες δικτύου (σε αντίθετη περίπτωση αυτό είναι αδύνατον). ∆ηλαδή οι εφαρµογές που εκµεταλλεύονται το δίκτυο για λογαριασµό του χρήστη.
Αυτές οι εφαρµογές βρίσκονται ενσωµατωµένες στο πολυεργαλείο BusyBox και για να λειτουργήσουν απαιτείται η εκτέλεση ενός ακόµη συνόλου αρχείων script τα οποία είναι τα εξής:
S21dnsmasq DNS και DHCP server
S22iptables Τείχος προστασίας (firewall)
S40telnetd Telnet server
S41inetd ∆ιαχείριση των υπηρεσιών δικτύου (Telnet, FTP κλπ)
S42httpd Web Server µε υποστήριξη cgi-bin για δυναµικές σελίδες
S43ntpdate , S49ntp Ρύθµιση ώρας και ηµεροµηνίας µέσω Internet
S49netfs Σύστηµα αρχείων για παραµετροποίηση των ρυθµίσεων δικτύου
S50dropbear SSH server
S50proftpd FTP server
Τα µηνύµατα κατάστασης που εµφανίζονται στο τερµατικό Putty είναι:
Ιστότοπος εργασίας: MyThesis.org
215
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 122. ∆ιαδικασία εκκίνησης στάδιο 12
Εφόσον όλα τα παραπάνω εκτελέστηκαν επιτυχώς, η διαδικασία εκκίνησης του Router
NGW100 έχει πλέον ολοκληρωθεί. Είναι πλέον έτοιµος να συνδέεται στο Internet, να δροµολογεί τα πακέτα των υπολογιστικών συστηµάτων του τοπικού δικτύου, να παραµετροποιείται
µέσω γραµµής εντολών αλλά και µέσω του Web interface που διαθέτει. Στην εικόνα που ακολουθεί βλέπουµε την οθόνη καλωσορίσµατος, και το command prompt του BusyBox, που
εµφανίζει ο Router NGW100 µετά την ολοκλήρωση της εκκίνησής του:
Εικόνα 123. Ολοκλήρωση διαδικασίας εκκίνησης – έναρξη γραµµής εντολών BusyBox
Επικοινωνία: [email protected]
216
ΚΕΦΑΛΑΙΟ
7
Οι εφαρµογές του Router NGW100
Εισαγωγή
Οι περισσότερες ηλεκτρονικές συσκευές, όπως και ο Router NGW100, είναι παρόµοιες ως
προς το υλικό τους. Έχουν µνήµη για να αποθηκεύουν δεδοµένα, µονάδα επεξεργασίας για
να επεξεργάζονται δεδοµένα, και δίαυλους επικοινωνίας για να επικοινωνούν µεταφέροντας
δεδοµένα. Επίσης, για να είναι όλα αυτά εφικτά, συνδέονται µε κάποια πηγή τροφοδοσίας.
Αυτό όµως για το οποίο διαφοροποιείται πραγµατικά µια ηλεκτρονική συσκευή από µία άλλη,
είναι η εφαρµογή ή οι εφαρµογές που περιλαµβάνει.
Ο Router NGW100 είναι ένας δροµολογητής. Εποµένως οι κυριότερες διεργασίες που τον
αφορούν και τον διαφοροποιούν από άλλες συσκευές είναι κυρίως η δροµολόγηση και η ασφαλής προώθηση πακέτων στο τοπικό δίκτυο και στα δίκτυα ευρείας περιοχής (πχ:
Internet). Όπως έχουµε δει και στο θεωρητικό µέρος, οι διεργασίες αυτές βρίσκονται ενσωµατωµένες στον Linux Kernel. Για να τις εκµεταλλευτούµε δηµιουργούµε εφαρµογές οι οποίες
επικοινωνούν µε το API των διεργασιών αυτών. Σε αυτό το τελευταίο κεφάλαιο θα παρουσιάσουµε τις εφαρµογές αυτές αλλά και τις δυνατότητες αλληλεπίδρασης του χρήστη µε τον
Router NGW100. Πιο συγκεκριµένα θα ασχοληθούµε µε τα εξής:
Ανάπτυξη δοκιµαστικής εφαρµογής
Προσθήκη πακέτων λογισµικού στο Buildroot
Οι εφαρµογές του Router NGW100
Είναι χρήσιµο να αναφέρουµε εδώ, ότι ως προς το πρωτόκολλο TCP/IP, το κεφάλαιο 7 ασχολείται µε το επίπεδο εφαρµογής. Στα προηγούµενα κεφάλαια παρουσιάστηκαν τα πιο χαµηλά επίπεδα, µε το χαµηλότερο να αφορά το φυσικό επίπεδο (µέρος αυτού του επιπέδου
αποτελεί και το παράρτηµα B).
7.1 Ανάπτυξη δοκιµαστικής εφαρµογής
Πριν αναφερθούµε στις εφαρµογές που εγκαταστάθηκαν στον Router NGW100 καλό θα
είναι να δούµε ένα απλό παράδειγµα ανάπτυξης δοκιµαστικής εφαρµογής. Η εφαρµογή αυτή
αναπτύχθηκε στα πλαίσια της παρούσας εργασίας καθαρά για διαγνωστικούς λόγους.
Για την ανάπτυξη και τον έλεγχο επιτυχούς µεταγλώττισης της εφαρµογής, χρησιµοποιήθηκαν δύο τρόποι. Ο πρώτος περιλάµβανε έναν απλό κειµενογράφο και την γραµµή εντολών
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
της κονσόλας της Ubuntu, και ο δεύτερος, το IDE AVR32 Studio και τα προγράµµατα FileZilla
και PuTTY. Αυτό έγινε για να δοκιµαστεί επίσης και η ορθή λειτουργία των βοηθητικών εφαρµογών αλλά και ορισµένων πρωτοκόλλων επικοινωνίας.
Ο πηγαίος κώδικας της δοκιµαστικής εφαρµογής που αναπτύχθηκε, είναι ο ακόλουθος:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("Hello World!\n");
return 0;
}
Το όνοµα του αρχείου που περιλαµβάνει τον πηγαίο κώδικα είναι το hello.c και βρίσκεται
στον κατάλογο /rousis/misc/paradigm/application/hello.c. Επίσης το σύστηµα
host συνδέθηκε µε τον Router NGW100 µέσω Ethernet (θύρα LAN) και µέσω της σειριακής
θύρας. Για τη σειριακή σύνδεση χρησιµοποιήθηκε η εφαρµογή PuTTY.
Για τη σύνδεση µέσω Ethernet κατασκευάστηκε αθωράκιστο καλώδιο συνεστραµµένων ζευγών UTP (Unshielded Twisted Pair) cat5e (wikipedia.org/wiki/Category_5_cable)
µε συνδετήρες RJ45 (αρσενικούς) και διάταξη καλωδίων τύπου B. Στην εικόνα µπορούµε να
δούµε το συγκεκριµένο καλώδιο:
Εικόνα 124. Καλώδιο συνεστραµµένων ζευγών UTP cat5e
Για την κατασκευή του καλωδίου χρησιµοποιήθηκε ειδική τανάλια η οποία δεν κρίνεται απαραίτητο να αναφερθεί εδώ.
7.1.2 Με χρήση κειµενογράφου και γραµµής εντολών
Αρχικά, µε δεξί κλικ στον κατάλογο application, δηµιουργήθηκε ένα άδειο αρχείο
(Empty File) το οποίο µετονοµάστηκε σε hello.c, όπως φαίνεται στην παρακάτω εικόνα:
Επικοινωνία: [email protected]
218
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Εικόνα 125. ∆ηµιουργία άδειου αρχείου στην Ubuntu 9.04
Στη συνέχεια, µε διπλό κλικ, το αρχείο προσπελάστηκε προκειµένου να γραφτεί σε αυτό ο
πηγαίος κώδικας της εφαρµογής. Αφού ολοκληρώθηκε η συγγραφή, αποθηκεύτηκαν οι αλλαγές και το αρχείο έκλεισε για να πραγµατοποιηθεί το επόµενο βήµα. ∆ηλαδή η µεταγλώττισή του µέσω της αλυσίδας cross και του cross compiler avr32-linux-gcc, που είχε ήδη
δηµιουργηθεί νωρίτερα µέσω του αυτοµατοποιηµένου συστήµατος Buildroot.
Αρχικά εκτελέστηκε (σε µια γραµµή) η παρακάτω εντολή, στην κονσόλα της Ubuntu για να
δηµιουργηθεί το αρχείο object (αντικείµενος κώδικας):
/rousis/buildroot/build_avr32/staging_dir/usr/bin/avr32-linux-gcc
Wall -mcpu=ap7000 -D_GNU_SOURCE -c -o hello.o hello.c
-pipe
-O3
-g
-
Μετά την επιτυχή εκτέλεση της εντολής, στον κατάλογο application εµφανίστηκε ένα νέο
αρχείο µε το όνοµα hello.o. Αυτό που έµενε είναι η σύνδεσή του (µε βιβλιοθήκες κλπ) µέσω του linker προκειµένου να προκύψει το εκτελέσιµο αρχείο:
/rousis/buildroot/build_avr32/staging_dir/usr/bin/avr32-linux-gcc
Wall -mcpu=ap7000 -o hello hello.o
-pipe
-O3
-g
-
Εφόσον όλα λειτούργησαν σωστά, δηµιουργήθηκε το εκτελέσιµο αρχείο hello το οποίο
δεν περιλάµβανε καµία επέκταση. Στην εικόνα βλέπουµε τα αρχεία που δηµιουργήθηκαν τελικά στον κατάλογο application:
Εικόνα 126. Τα αρχεία του καταλόγου application µετά τη µεταγλώττιση του hello.c
Σε αυτό το σηµείο µπορούµε να διαπιστώσουµε και την έννοια του cross compiling (διασταυρούµενη µεταγλώττιση). Αν δοκιµάσουµε να εκτελέσουµε την εφαρµογή hello στην
Ubuntu θα λάβουµε ως απάντηση το µήνυµα “bash: ./hello: cannot execute
binary file”. Αυτό είναι απολύτως επιθυµητό καθώς το σύστηµα host που χρησιµοποιούµε είναι αρχιτεκτονικής i386 ενώ το αρχείο hello.c έχει µεταγλωττιστεί για την αρχιτεκτονική του µικροελεγκτή AP7000 που είναι η AVR32. Εποµένως για να εκτελεστεί η εφαρµογή
που δηµιουργήσαµε θα πρέπει πρώτα να µεταφερθεί στη µνήµη του Router NGW100.
Η µεταφορά της εφαρµογής στον Router NGW100 έγινε µέσω εντολών FTP (client) στην
κονσόλα της Ubuntu. Φυσικά από την πλευρά του Router NGW100 υπάρχει ο ProFTPD
Ιστότοπος εργασίας: MyThesis.org
219
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
server ο οποίος φρόντισε για την λήψη του αρχείου. Η εικόνα παρουσιάζει ολόκληρη την εν
λόγω διαδικασία:
Εικόνα 127. Μεταφορά της εφαρµογής hello στον Router NGW100 µέσω εντολών FTP
Το επόµενο βήµα που έπρεπε να γίνει είναι η εκτέλεση της εφαρµογής hello µέσω της
κονσόλας και του πρωτοκόλλου Telnet. Μετά την εκτέλεση εµφανίστηκε το µήνυµα Hello
World!. Αυτό απέδειξε ότι όλα πήγαν καλά και ότι πλέον υπήρχε διαθέσιµο ένα ολοκληρωµένο περιβάλλον ανάπτυξης εφαρµογών για τον Router NGW100. Η διαδικασία εκτέλεσης µέσω Telnet φαίνεται στην εικόνα:
Εικόνα 128. Εκτέλεση της δοκιµαστικής εφαρµογής hello µέσω Telnet
Επικοινωνία: [email protected]
220
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Επειδή στον Router NGW100 το Telnet βρίσκεται ενσωµατωµένο στο BusyBox, αφού συνδεθούµε εµφανίζεται πρώτα η αντίστοιχη ενηµέρωση και αµέσως µετά µπορούµε να εκτελέσουµε τις εντολές µας. Για την ίδια διαδικασία θα µπορούσε να χρησιµοποιηθεί το ασφαλές
πρωτόκολλο SSH που επίσης βρίσκεται ενσωµατωµένο στο BusyBox, ή το τερµατικό
PuTTY.
7.1.3 Μέσω του AVR32 Studio
Επειδή το AVR32 Studio παρουσίαζε κάποια δυσκολία ως προς τον εντοπισµό του cross
compiler avr32-linux-gcc, δηµιουργήθηκε ένα ειδικό shell script µε την ονοµασία
AVR32-Studio.sh. Ο κώδικάς του είναι ο ακόλουθος:
#!/bin/sh
export PATH=$PATH:/rousis/buildroot/build_avr32/staging_dir/bin
/rousis/avr32studio/avr32studio
Το αρχείο τοποθετήθηκε στη συνέχεια, στην επιφάνεια εργασίας της Ubuntu ώστε να είναι
εύκολα προσβάσιµο. Με διπλό κλικ επάνω του προέκυψε το παρακάτω παράθυρο διαλόγου:
Εικόνα 129. Παράθυρο διαλόγου µετά την εκτέλεση του αρχείου AVR32-Studio.sh µε διπλό κλικ
Επιλέγοντας Run in Terminal, το AVR32 Studio ανοίγει και είναι έτοιµο για την ανάπτυξη εφαρµογών:
Ιστότοπος εργασίας: MyThesis.org
221
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 130. Το κεντρικό περιβάλλον εργασίας του AVR32 Studio
Για την δηµιουργία νέου project ακολουθείται η διαδροµή File
New
Project… και
από το παράθυρο διαλόγου που εµφανίζεται επιλέγεται η επιλογή AVR32 C Project:
Εικόνα 131. AVR32 Studio - ∆ηµιουργία νέου C project – Βήµα 1
Επικοινωνία: [email protected]
222
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Με κλικ στο Next εµφανίστηκε το τελευταίο βήµα στο οποίο καθορίστηκε το όνοµα του project dokimastiki-efarmogi, ο µικροελεγκτής AP7000 και ο τύπος project, AVR32 Linux
Executable:
Εικόνα 132. AVR32 Studio - ∆ηµιουργία νέου C project – Βήµα 2
Ο λόγος για τον οποίο επιλέχτηκε ο συγκεκριµένος τύπος project (AVR32 Linux Executable) και όχι ο AVR32 Standalone Executable, είναι ότι η προς ανάπτυξη εφαρµογή,
θα έπρεπε µεν να εκτελείται στην αρχιτεκτονική του AP7000, αλλά ταυτόχρονα θα έπρεπε να
υπακούει και στο ιδιαίτερο οικοσύστηµα του Linux Kernel. Αν επρόκειτο για µια ανεξάρτητη
εφαρµογή η οποία δε θα εκτελούνταν επάνω από κάποιο λειτουργικό σύστηµα, τότε θα επιλέγαµε τον τύπο Standalone Executable. Κάτι αντίστοιχο ισχύει και σε περίπτωση ανάπτυξης βιβλιοθήκης, µε την εξαίρεση ότι σε µια ανεξάρτητη εφαρµογή δεν υπάρχει νόηµα να
δηµιουργηθεί διαµοιραζόµενη βιβλιοθήκη (Linux Shared Library), αφού σε ένα τέτοιο
σύστηµα (µονολιθικό), εκτελείται συνεχώς µία και µοναδική εφαρµογή.
Αφού ολοκληρώθηκε η δηµιουργία νέου project, προστέθηκε – δηµιουργήθηκε στο project
αυτό, ένα νέο αρχείο πηγαίου κώδικα C. Αυτό έγινε από το κεντρικό µενού του AVR32
Studio, επιλέγοντας File
New
Source File. Στην εικόνα βλέπουµε το παράθυρο
διαλόγου για την δηµιουργία νέου αρχείου πηγαίου κώδικα:
Ιστότοπος εργασίας: MyThesis.org
223
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 133. AVR32 Studio - ∆ηµιουργία νέου αρχείου πηγαίου κώδικα C
Μετά την προσθήκη - δηµιουργία του αρχείου πηγαίου κώδικα C µε την ονοµασία
hello.c, στο project dokimastiki-efarmogi, πληκτρολογήθηκε ο ίδιος κώδικας της δοκιµαστικής εφαρµογής που είδαµε και στην προηγούµενη παράγραφο. Αµέσως µετά από το
κεντρικό µενού επιλέγηκε Project
Build All για να δηµιουργηθεί το εκτελέσιµο αρχείο της εφαρµογής.
Το AVR32 Studio δηµιουργεί για κάθε νέο project έναν οµώνυµο κατάλογο. Στην περίπτωσή µας αυτός ήταν ο /rousis/avr32studio/workspace/dokimastiki-efarmogi.
Επίσης µετά από το Build του κάθε project, δηµιουργεί τον κατάλογο Debug (ή release)
µέσα στον οποίο τοποθετείται τελικά το τελικό εκτελέσιµο αρχείο το οποίο είναι της µορφής
.elf (wikipedia.org/wiki/Executable_and_Linkable_Format). Το αρχείο αυτό
παίρνει αυτόµατα το όνοµα του project. Στην εικόνα βλέπουµε τα περιεχόµενα του κατάλογο
Debug για το project dokimastiki-efarmogi:
Εικόνα 134. AVR32 Studio - Περιεχόµενα καταλόγου Debug για το project "dokimastiki-efarmogi"
Όπως και στην περίπτωση της προηγούµενης παραγράφου, έτσι κι εδώ, το εκτελέσιµο αρχείο έπρεπε να µεταφερθεί στον Router NGW100 για να επιβεβαιωθεί ότι όλα πήγαν καλά.
Αυτό πραγµατοποιήθηκε µέσω της βοηθητικής εφαρµογής FileZilla FTP client που είδαµε και
στο προηγούµενο κεφάλαιο. Στην εικόνα διακρίνεται ολόκληρη η διαδικασία:
Επικοινωνία: [email protected]
224
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Εικόνα 135. Μεταφορά αρχείου dokimastiki-efarmogi.elf στον Router NGW100 µέσω του FileZilla FTP client
Όπως εύκολα µπορεί να παρατηρήσει κανείς το αρχείο hello που προέκυψε από την µεταγλώττιση του hello.c µέσω γραµµής εντολών, υπάρχει ακόµα στον κατάλογο
/home/rousis του Router NGW100. Επίσης η διαφορά του µεγέθους του (5,468 bytes),
σε σχέση µε αυτό του dokimastiki-efarmogi.elf (29,032 bytes), είναι σχεδόν εξαπλάσια.
Ολοκληρώνοντας την διαδικασία για την εκτέλεση της εφαρµογής dokimastikiefarmogi.elf στον Router NGW100 έπρεπε πρώτα να δοθούν τα απαραίτητα δικαιώµατα.
Για το λόγο αυτό χρησιµοποιήθηκε το πρόγραµµα PuTTY και η σειριακή επικοινωνία. Οι εντολές που χρησιµοποιήθηκαν για την προσπέλαση του εκτελέσιµου αρχείου, την προσάρτηση κατάλληλων δικαιωµάτων και την εκτέλεσή του, είναι οι ακόλουθες:
Ιστότοπος εργασίας: MyThesis.org
225
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 136. Εκτέλεση της δοκιµαστικής εφαρµογής hello µέσω του τερµατικού PuTTY
7.2 Προσθήκη πακέτων λογισµικού στο Buildroot
Η δοκιµαστική εφαρµογή που αναπτύχθηκε στην προηγούµενη παράγραφο, ουσιαστικά δεν
κάνει τίποτα χρήσιµο. Η επιτυχηµένη της εκτέλεση όµως, είναι µια βάσιµη ένδειξη ότι έχει
πλέον δηµιουργηθεί µια πλήρης πλατφόρµα υλικού και λογισµικού. Σε αυτή θα µπορούν να
αναπτύσσονται εφαρµογές οι οποίες θα είναι σε θέση να χρησιµοποιούν τους πόρους του
Router NGW100, καθώς και τις διάφορες εισόδους και εξόδους του ώστε να επικοινωνούν µε
το περιβάλλον.
Ο Router NGW100, αναπτύχθηκε για να λειτουργεί ως δροµολογητής πακέτων υπολογιστικών συστηµάτων, εποµένως οι περισσότερες εφαρµογές του εξυπηρετούν µε τον ένα ή τον
άλλο τρόπο το σκοπό αυτό. Οι εφαρµογές αυτές, συνήθως δεν αποτελούνται από ένα και
µόνο ανεξάρτητο εκτελέσιµο, αλλά από πολλαπλά αρχεία που σε κάποιες περιπτώσεις
χρειάζεται να βρίσκονται σε διαφορετικούς καταλόγους του συστήµατος αρχείων (πχ: /etc,
/bin κλπ) του Router NGW100. Επίσης, µπορεί να απαιτούνται και κάποιες καταχωρήσεις
σε αρχεία ρυθµίσεων του συστήµατος (πχ: /etc/passwd).
Από όλα τα παραπάνω γίνεται εύκολα κατανοητό, το ότι κάποιες εφαρµογές δεν αλλάζουν
συχνά και είναι βασικές για τη λειτουργία του συστήµατός µας. Εποµένως σε κάθε µεταγλώττιση που γίνεται µε σκοπό την δηµιουργία (ή τροποποίηση) των δυαδικών αρχείων
rootfs.avr32.jffs2-root και rootfs.avr32.jffs2-usr, θα πρέπει να ενσωµατώνονται αυτόµατα έτσι ώστε να µεταφέρονται στη συνέχεια στον Router NGW100. Αυτό επιτυγχάνεται µέσω του αυτοµατοποιηµένου συστήµατος Buildroot και του ειδικού µηχανισµού
προσθήκης πακέτων λογισµικού που διαθέτει.
Η διαδικασία προσθήκης του πακέτου λογισµικού που περιλάµβανε την κάθε εφαρµογή του
Router NGW100, στο Buildroot, αποτελείται από τα εξής βήµατα:
∆ηµιουργία οµώνυµου της εφαρµογής, καταλόγου, στον κατάλογο
/rousis/buildroot/package
Προσθήκη του πακέτου της εφαρµογής στο σύστηµα παραµετροποίησης του Buildroot µέσω δηµιουργίας κατάλληλου αρχείου Config.in
∆ήλωση εξαρτήσεων (dependencies) του πακέτου αυτού από την ύπαρξη άλλων υποστηρικτικών πακέτων µέσω των οδηγιών select και depends on
Ενηµέρωση του global αρχείου /rousis/buildroot/package/Config.in για
την ύπαρξη του πακέτου που προστέθηκε
∆ηµιουργία ενός αρχείου - εγκαταστάτη Makefile (*.mk) για το πακέτο
Μετά από την ολοκλήρωση των παραπάνω βηµάτων και την εκτέλεση της εντολής make
menuconfig στο Buildroot, η εφαρµογή ήταν διαθέσιµη για επιλογή.
Η διαδικασία προσθήκης νέου πακέτου λογισµικού στο αυτοµατοποιηµένο σύστηµα Buildroot µπορεί να αυτοµατοποιηθεί και µέσω του ειδικού script add_new_package.wizard
Επικοινωνία: [email protected]
226
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
του λογισµικού autotools. Επίσης, σηµαντικός είναι και ο κατάλογος της κάθε εφαρµογής
που προστίθεται, καθώς περιλαµβάνει αρχεία βοήθειας και οδηγιών εγκατάστασης και παραµετροποίησής της. Αυτά είναι συνήθως αρχεία κειµένου και έχουν συγκεκριµένες ονοµασίες, όπως README και INSTALL.
7.2.1 Παράδειγµα προσθήκης εφαρµογής στο σύστηµα Buildroot
Σε αυτή την παράγραφο θα γίνει µια σύντοµη παρουσίαση της διαδικασίας προσθήκης µιας
εκ των εφαρµογών – πακέτων, του Router NGW100 στο σύστηµα Buildroot. Το όνοµά της
εφαρµογής είναι webif και είναι υπεύθυνη για την δηµιουργία του Web interface.
Αρχικά δηµιουργήθηκε ο κατάλογος /rousis/buildroot/package/webif. και αντιγράφηκαν σε αυτόν οι κατάλογοι source και files του πακέτου webif από το BSP. Το
αµέσως επόµενο βήµα που έπρεπε να γίνει (όπως είδαµε και στην προηγούµενη παράγραφο), ήταν να δηµιουργηθεί (µε τη βοήθεια του BSP) το αρχείο Config.in το οποίο ήταν
απαραίτητο από το σύστηµα παραµετροποίησης του Buildroot:
config BR2_PACKAGE_WEBIF
bool "webif - Status Console"
select BR2_PACKAGE_HASERL
help
A web interface for showing different network status. This package
requires awk support on the system, either the one provided by
Busybox or gawk.
The default login on the status web pages are root/root and
admin/admin. This can be changed in the etc/httpd.conf file.
config BR2_PACKAGE_WEBIF_INSTALL_INDEX_HTML
bool "instal index.html in /www which redirects to webif"
depends on BR2_PACKAGE_WEBIF
help
Installs a /www/index.html which redirects to the status console cgi
scripts.
config BR2_PACKAGE_WEBIF_LANGUAGES
bool "install language support"
depends on BR2_PACKAGE_WEBIF
help
This option installs support for other languages than english.
(Greek translation: Dimitrios A. Rousis)
Supported languages: gr, ca, cz, de, dk, ee, es, fr, hr, hu, it, nl, no,
pl, pt, ru and se.
Η συγγραφή του κώδικα του αρχείου Config.in βασίζεται στο σύστηµα παραµετροποίησης του Linux Kernel (Kconfig) και εποµένως αναπτύχθηκε µε τους ίδιους συντακτικούς
κανόνες (/rousis/buildroot/…/linux-2.6.27.6/Documentation/kbuild).
Για να εµφανιστούν τα αποτελέσµατα του παραπάνω κώδικα, ενηµερώθηκε στη συνέχεια το
global αρχείο Config.in του Buildroot (κάτω από το menu “Networking”) µε την προσθήκη της παρακάτω γραµµής:
source "package/webif/Config.in"
Ο κώδικας αυτός είχε ως αποτέλεσµα (µετά την εκτέλεση της εντολής make menuconfig)
την εµφάνιση των αντίστοιχων επιλογών στο Buildroot (Package selection for tarNetworking
webif – Status Console):
get
Ιστότοπος εργασίας: MyThesis.org
227
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 137. Buildroot – Πακέτο λογισµικού webif
Όµως αυτό δεν είναι αρκετό, καθώς γιατί µεταγλώττιση της εφαρµογής webif θα έπρεπε
να υπάρχει ένα ειδικό Makefile (webif.mk) του οποίου τον κώδικα βλέπουµε παρακάτω:
#############################################################
#
# webif
#
#############################################################
WEBIF_VERSION:=0.2
WEBIF_SOURCE:=package/webif
WEBIF_SITE:=https://svn.openwrt.org/openwrt/tags/whiterussian_0.9/package/webif
WEBIF_DIR:=$(BUILD_DIR)/webif-$(WEBIF_VERSION)
$(WEBIF_DIR)/.unpacked:
mkdir -p $(WEBIF_DIR)
touch $@
$(WEBIF_DIR)/.built: $(WEBIF_DIR)/.unpacked
$(TARGET_CC) $(TARGET_CFLAGS) -o $(WEBIF_DIR)/webif-page $(WEBIF_SOURCE)/src/webifpage.c
$(TARGET_CC) $(TARGET_CFLAGS) -o $(WEBIF_DIR)/bstrip $(WEBIF_SOURCE)/src/bstrip.c
$(STRIPCMD) $(STRIP_STRIP_UNNEEDED) $(WEBIF_DIR)/webif-page $(WEBIF_DIR)/bstrip
touch $@
$(TARGET_DIR)/www/webif.css: $(WEBIF_DIR)/.built
mkdir -p $(TARGET_DIR)/etc
mkdir -p $(TARGET_DIR)/usr/bin
mkdir -p $(TARGET_DIR)/usr/lib
mkdir -p $(TARGET_DIR)/www
cat $(WEBIF_SOURCE)/files/etc/httpd.conf >> $(TARGET_DIR)/etc/httpd.conf
cp -dpfr $(WEBIF_SOURCE)/files/usr/lib/webif $(TARGET_DIR)/usr/lib/
ifneq ($(BR2_PACKAGE_WEBIF_LANGUAGES),y)
rm -rf $(TARGET_DIR)/usr/lib/webif/lang
endif
$(INSTALL) -m0755 $(WEBIF_DIR)/webif-page $(TARGET_DIR)/usr/bin/
Επικοινωνία: [email protected]
228
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
$(INSTALL) -m0755 $(WEBIF_DIR)/bstrip $(TARGET_DIR)/usr/bin/
ifeq ($(BR2_PACKAGE_WEBIF_INSTALL_INDEX_HTML),y)
@if [ -f "$(TARGET_DIR)/www/index.html" ]; then
echo;
\
echo "webif WARNING:";
\
echo "There is already a $(TARGET_DIR)/www/index.html";
echo "webif might be replacing another package;"
\
echo;
\
echo "Sleeping for 10 seconds";
\
sleep 10;
\
fi
cp -dpf $(WEBIF_SOURCE)/files/www/index.html $(TARGET_DIR)/www/
endif
cp -dpfr $(WEBIF_SOURCE)/files/www/cgi-bin $(TARGET_DIR)/www/
cp -dpfr $(WEBIF_SOURCE)/files/www/webif.* $(TARGET_DIR)/www/
@if [ ! -f $(TARGET_DIR)/etc/banner ]; then
\
ln -sf issue $(TARGET_DIR)/etc/banner; \
fi
touch $@
\
\
webif: busybox $(TARGET_DIR)/www/webif.css
webif-clean:
rm -rf $(TARGET_DIR)/www/cgi-bin/webif* $(TARGET_DIR)/www/webif.*
rm -rf $(TARGET_DIR)/usr/lib/webif
rm -f $(TARGET_DIR)/usr/bin/bstrip $(TARGET_DIR)/usr/bin/webif-page
rm -r $(WEBIF_DIR)/bstrip $(WEBIF_DIR)/webif-page
webif-source:
webif-dirclean:
rm -rf $(WEBIF_DIR)
#############################################################
#
# Toplevel Makefile options
#
#############################################################
ifeq ($(BR2_PACKAGE_WEBIF),y)
TARGETS+=webif
endif
Ο κώδικας του Makefile webif.mk αναπτύχθηκε έτσι ώστε να περιλαµβάνει τους κανόνες
για το κατέβασµα, την παραµετροποίηση, τη µεταγλώττιση και την εγκατάσταση της εφαρµογής webif στο σύστηµα αρχείων που δηµιουργεί το Buildroot για τον Router NGW100.
Τελικά στον κατάλογο /rousis/buildroot/package/webif υπάρχουν τα εξής:
Εικόνα 138. Buildroot - Τα περιεχόµενα του καταλόγου package/webif
Μετά την εκτέλεση της εντολής make (και ενώ βρισκόµαστε µέσα τον κατάλογο του Buildroot) ο πηγαίος κώδικας του webif.mk εκτελείται εγκαθιστώντας το πακέτο webif στο σύστηµα αρχείων του Router NGW100.
Με παρόµοιο τρόπο προστέθηκαν και οι υπόλοιπες εφαρµογές του Router NGW100. ∆εν
κρίνεται σκόπιµο να αναφερθούν µία προς µία, µιας και το παράδειγµα που µόλις παρατέθηκε είναι αρκετό για την κατανόηση της όλης διαδικασίας.
Ιστότοπος εργασίας: MyThesis.org
229
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
7.3 Οι εφαρµογές του Router NGW100
Κατά την ανάλυση της διαδικασίας εκκίνησης του Router NGW100 σε προηγούµενο κεφάλαιο, αναφέρθηκαν ορισµένα script εκκίνησης τα οποία εκτελούνται προκειµένου να ενεργοποιήσουν την λειτουργία κάποιων εφαρµογών και κάποιων υπηρεσιών. Οι εφαρµογές αυτές
είτε αποτελούν µέρος του λογισµικού BusyBox είτε έχουν εγκατασταθεί ανεξάρτητα, καθεµία
ξεχωριστά. Κάτι αντίστοιχο ισχύει και για την εκκίνηση των εφαρµογών. Όσες ανήκουν στο
BusyBox εκκινούνται από το script εκκίνησής του, ενώ όσες είναι ανεξάρτητες εκκινούν από
ξεχωριστά scripts.
Εποµένως οι εφαρµογές του Router NGW100 µπορούν να χωριστούν σε δύο κύριες κατηγορίες:
Εφαρµογές που περιλαµβάνονται στο BusyBox
Ανεξάρτητες εφαρµογές
Για την εγκατάστασή τους, και στις δύο περιπτώσεις, ισχύει ότι είδαµε προηγουµένως στο
παράδειγµα προσθήκης εφαρµογής στο σύστηµα Buildroot.
Ο Router NGW100 είναι ένα ενσωµατωµένο σύστηµα Linux και όπως ήδη γνωρίζουµε έχει
περιορισµένους πόρους. Για το λόγο αυτό όλες οι εφαρµογές που έχουµε αναφέρει και θα
αναφέρουµε και στη συνέχεια, έχουν επιλεγεί µε κριτήρια το µικρό µέγεθος και τη µέγιστη δυνατή απόδοση και αξιοπιστία.
Οι εφαρµογές που κρίθηκαν οι πιο σηµαντικές για ανάλυση στην παρούσα εργασία είναι οι
ακόλουθες:
busybox 1.13.1
inetd
BusyBox
httpd
BusyBox
webif 0.9
haserl 0.9.24
awk
BusyBox
iptables 1.4.1
bridge 1.4
dnsmasq 2.46
udhcpc
BusyBox
ifconfig
BusyBox
ifup
BusyBox
ifdown
BusyBox
route
BusyBox
dropbear 0.52
telnet
BusyBox
ethtool 6
ntp 4.2.4p5
portmap 5beta
proFTPD 1.3.1
Οι εν λόγω εφαρµογές, αναφέρονται γιατί είναι κυρίως αυτές, οι οποίες βοηθούν στο να δοθεί στον Router NGW100 o χαρακτήρας µιας ολοκληρωµένης συσκευής δροµολογητή, όπως
αυτή είναι γνωστή στην αγορά σήµερα. Βέβαια απαιτούνται ορισµένες επιπλέον προσθήκες
για να καταστεί ο Router NGW100 εµπορικό προϊόν. Αυτό όµως δεν αποτελούσε σε καµία
περίπτωση τον στόχο αυτής της εργασίας.
Επικοινωνία: [email protected]
230
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Όσες εφαρµογές έχουν δεξιά τους το σύµβολο “
γράµµατα που είναι ενσωµατωµένα στο BusyBox.
BusyBox “ σηµαίνει ότι αποτελούν προ-
Η παραµετροποίησή σχεδόν όλων των εφαρµογών του Router NGW100 µπορεί να γίνει
είτε µέσω γραµµής εντολών (command line) από κάποιο διαχειριστή δικτύων, είτε µέσω δυναµικών ιστοσελίδων (Web interface), από έναν οποιοδήποτε χρήστη.
7.3.1 Πακέτο εφαρµογών BusyBox
Την εφαρµογή BusyBox (busybox.net) την εξετάσαµε και στο θεωρητικό µέρος της εργασίας στο δεύτερο κεφάλαιο. Εκεί παρουσιάσαµε την παραµετροποίησή του στο Buildroot και
είδαµε ότι το menu επιλογών του χωρίζεται σε δύο κατηγορίες, τις ρυθµίσεις και τα applets.
Επίσης, στο πρακτικό µέρος (κεφάλαιο 6) και κατά την ανάλυση της διαδικασίας εκκίνησης
του Router NGW100, αναφέρθηκε ότι η εκκίνηση του BusyBox γίνεται µέσω της init και του
αρχείου linuxrc. Το αρχείο αυτό ουσιαστικά είναι µια συντόµευση η οποία υπάρχει στο κεντρικό σύστηµα αρχείων και δείχνει προς το εκτελέσιµο του BusyBox (/bin/busybox). Οι
ρυθµίσεις των εφαρµογών που βρίσκονται ενσωµατωµένες στο BusyBox βρίσκονται συνήθως στον κατάλογο /etc.
Το BusyBox είναι πολύ ευέλικτο και µπορούµε κατά τη διαδικασία της µεταγλώττισής του να
του αφαιρούµε και να του προσθέτουµε εφαρµογές κατά βούληση. Προκειµένου να δει κάποιος, ποιες εφαρµογές υποστηρίζονται από την τρέχουσα εγκατάσταση του Busybox στον
Router NGW100 αρκεί να εκτελέσει στην γραµµή εντολών του την εντολή busybox. Επίσης
θα εµφανιστεί και µια µικρή περιγραφή σχετικά µε το τι είναι το BusyBox. Το αποτέλεσµα
φαίνεται στην εικόνα:
Ιστότοπος εργασίας: MyThesis.org
231
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Εικόνα 139. Εκτέλεση της εντολής busybox στον Router NGW100
Παρατηρώντας την παραπάνω εικόνα, είναι µια πολύ καλή ευκαιρία να δει κανείς και τις
υπόλοιπες εφαρµογές που είναι ενσωµατωµένες στο BusyBox στον Router NGW100. Για τον
ίδιο λόγο, αλλά και για επιπλέον εφαρµογές που δεν βρίσκονται ενσωµατωµένες στο BusyBox, µπορούν να εκτελεστούν και οι παρακάτω εντολές:
cd /bin
ls –l
cd /sbin
ls –l
Για επιπλέον µελέτη σε σχέση µε τις εφαρµογές που περιλαµβάνονται στο Busybox υπάρχει
και η ιστοσελίδα busybox.net/downloads/BusyBox.html.
Οι εφαρµογές του BusyBox εκκινούν χωρίς να χρειάζεται κάποιο script εκκίνησης. Αν όµως
επιθυµούµε να έχουν συγκεκριµένες ρυθµίσεις, τότε θα πρέπει να γράψουµε ένα. Ένα τέτοιο
παράδειγµα είναι και η εφαρµογή Webserver, httpd, την οποία θα εξετάσουµε και σε ειδική
παράγραφο.
Ο πηγαίος κώδικας του BusyBox και όλων των εφαρµογών που περιλαµβάνει, βρίσκεται
στον κατάλογο /rousis/buildroot/project_build_avr32/atngw100/busybox-1.13.1
της εικονικής µηχανής Ubuntu. Στη συνέχεια όποτε θα αναφέρεται η τοποθεσία του πηγαίου
Επικοινωνία: [email protected]
232
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
κώδικα µιας εφαρµογής του BusyBox, θα εννοείται ως πρόθεµα και η διαδροµή του καταλόγου αυτού.
7.3.2 Εφαρµογή inetd
Η εφαρµογή inetd (internet service daemon) στον Router NGW100, βρίσκεται ενσωµατωµένη στο BusyBox. Λειτουργεί σαν υπηρεσία και παίζει τον ρόλο του super server (wikipedia.org/wiki/Super-server). ∆ηλαδή εκκινεί άλλους servers όταν υπάρχει κάποιο
αντίστοιχο αίτηµα προς τις υπηρεσίες τους. Ένας από αυτούς είναι και Webserver httpd
που θα δούµε και στη συνέχεια.
Το πλεονέκτηµα της inetd είναι ότι αφού είναι υπεύθυνη για την κλήση των υπόλοιπων
servers, δεν χρειάζεται εκείνοι να δεσµεύουν πόρους του συστήµατος άσκοπα. Όταν προκύψει κάποιο αίτηµα θα ενηµερωθούν από την inetd.
Στο αρχείο networking/inetd.c βρίσκεται ο πηγαίος κώδικας της εφαρµογής. Στην εσωτερική τεκµηρίωση του ίδιου αρχείου υπάρχει και µια µικρή ανάλυση. Η εκκίνησή της γίνεται µέσω του Busybox και οι ρυθµίσεις βρίσκονται στο αρχείο /etc/inetd.conf. Εφόσον
λειτουργεί σαν υπηρεσία το όνοµά της θα πρέπει να υπάρχει στο /etc/services του συστήµατος αρχείων root.
7.3.3 Εφαρµογή httpd
Η συντοµογραφία httpd σηµαίνει Hypertext Transfer Protocol Daemon. ∆ηλαδή ∆αίµονας
Πρωτοκόλλου Μεταφοράς Υπερκειµένου. Ο όρος “δαίµονας” ή “daemon” µπορεί να γίνει κατανοητός κι από εδώ: wikipedia.org/wiki/Daemon_(computing).
Στον Router NGW100 η εφαρµογή httpd αποτελεί τµήµα του BusyBox. Πρόκειται για έναν
ελαφρύ και αποδοτικό Webserver, ο οποίος εκτελείται αδιάκοπα στο background του λογισµικού συστήµατος και σκοπός του είναι να φιλοξενεί το Web interface.
O server httpd παρέχει δυνατότητα προστασίας των ιστοσελίδων του µε όνοµα χρήστη
(username) και κωδικό πρόσβασης (password). Επίσης παρέχει υποστήριξη για δυναµικές
σελίδες και τον κατάλογο cgi-bin. Μια δυναµική σελίδα µπορεί να είναι γραµµένη σε γλώσσα C/C++ (.cgi), σε Perl, Lua, AWK, να είναι κάποιο shell script, αλλά και οποιοδήποτε εκτελέσιµο το οποίο έχει µεταγλωττιστεί για την αρχιτεκτονική AVR32 του µικροελεγκτή
AP7000.
Εφόσον ο server httpd µπορεί να εξυπηρετεί µέσω του πρωτοκόλλου HTTP, αιτήµατα
προς κάποιο εκτελέσιµο, δίνει τη δυνατότητα χειρισµού του υλικού του Router NGW100 µέσω Web. Έτσι µπορούµε για παράδειγµα να ανάβουµε και να σβήνουµε τα LED του PCB ή
να προκαλούµε εγγραφές στη µνήµη, ή ακόµα και την επανεκκίνηση του Linux Kernel.
Η εκκίνησή του server httpd (όπως είδαµε και στο προηγούµενο κεφάλαιο), γίνεται από το
script εκκίνησης /etc/init.d/S42httpd και οι ρυθµίσεις του βρίσκονται στο αρχείο
/etc/httpd.conf. Το εκτελέσιµο του αρχείο είναι το /usr/sbin/httpd.
Ιστότοπος εργασίας: MyThesis.org
233
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
7.3.4 Εφαρµογές για το Web interface
Η διαχείριση ενός δροµολογητή από έναν ειδικό στα θέµατα των δικτύων, µπορεί να γίνει
άνετα και αποτελεσµατικά, µέσω γραµµής εντολών, µε τη βοήθεια ενός τερµατικού (πχ:
PuTTY). Σε έναν οικιακό δροµολογητή όµως, ο χρήστης διαθέτει µικρή ή και καθόλου εµπειρία γύρω από τα δίκτυα και τις ορολογίες τους. Σε αυτές τις περιπτώσεις ένα γραφικό περιβάλλον παραµετροποίησης είναι η µόνη λύση. Ένα τέτοιο περιβάλλον µπορεί να υλοποιηθεί
συνήθως µε δύο τρόπους:
Παραθυρική εφαρµογή σε PC και σύνδεση USB
∆υναµική ιστοσελίδα – Web Interface και σύνδεση Ethernet (ή WiFi)
Η πρώτη περίπτωση αφορά πολύ αρχάριους χρήστες που δεν είναι σε θέση να συνδέσουν
καλώδιο Ethernet και να αναζητήσουν την IP του δροµολογητή. Χρειάζεται όµως να υπάρχει
κάποιος συνοδευτικός οπτικός δίσκος (CD/DVD), που θα περιέχει τους κατάλληλους USB
drivers για τη σύνδεση του δροµολογητή µε το PC. Εποµένως η ανάπτυξη του συστήµατος
µε αυτό τον τρόπο, ανεβάζει το κόστος παραγωγής. Άλλο ένα µειονέκτηµα είναι ότι ο υπολογιστής του χρήστη επιβαρύνεται µε µια επιπλέον εφαρµογή και επιπλέον drivers.
Η δεύτερη περίπτωση αφορά τον µέσο χρήστη. Ο οποίος έχει κάποιες πολύ βασικές γνώσεις που του επιτρέπουν να φέρει εις πέρας µια τέτοια διαδικασία. Σε αυτή την περίπτωση
δεν απαιτούνται ειδικοί drivers αφού η επικοινωνία γίνεται µέσω Ethernet και το περιβάλλον
διαχείρισης είναι ενσωµατωµένο στον δροµολογητή. Το µόνο που χρειάζεται να γνωρίζει ο
χρήστης, είναι την διεύθυνση IP του δροµολογητή έτσι ώστε να την πληκτρολογήσει σε κάποιο φυλλοµετρητή (Chrome, Firefox κλπ).
Στον Router NGW100 το Web interface υλοποιείται κατά κύριο λόγο, µέσω των εξής εφαρµογών:
awk
haserl
webif
Εφαρµογή haserl
Η εφαρµογή haserl (Html And Shell Embedded Runtime Language), είναι ένα πρόγραµµα
cgi το οποίο εκτελεί διερµηνευµένα scripts. Θα µπορούσαµε να πούµε ότι είναι η PHP των
ενσωµατωµένων συστηµάτων Linux. Συνδυάζει δύο πολύ σηµαντικά χαρακτηριστικά:
Αναλύει αιτήµατα POST και GET τοποθετώντας τα στοιχεία της αντίστοιχης φόρµας
σαν ζεύγη (πχ: name=value) έτσι ώστε να χρησιµοποιηθούν από κάποιο cgi script
(πέρασµα παραµέτρων και τιµών).
Εµφανίζει τα περιεχόµενα των αρχείων script σαν κώδικα HTML και υπό συγκεκριµένες περιστάσεις διερµηνεύει τον κώδικα – κείµενο που βρίσκεται ανάµεσα στα σύµβολα <%...%>.
Εφαρµογή awk
Η εφαρµογή awk είναι ουσιαστικά ο διερµηνευτής (interpreter) της γλώσσας scripting awk.
Οι χρήσεις της γλώσσας αυτής αφορούν κυρίως σάρωση (parsing) και εξαγωγή δεδοµένων.
Μπορεί επίσης να χρησιµοποιηθεί και σαν εργαλείο δηµιουργίας µορφοποιηµένων αναφορών (reports).
Επικοινωνία: [email protected]
234
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Στο Linux οι ρυθµίσεις των διαφόρων προγραµµάτων χρήστη, βρίσκονται σε αρχεία κειµένου µέσα στα οποία συνήθως υπάρχει και κάποια ορισµένη δοµή (pattern) διάταξης. Κάθε
φορά λοιπόν που θέλουµε να αλλάξουµε τις ρυθµίσεις ενός προγράµµατος θα πρέπει πρώτα
να ανοίξουµε και να διαβάσουµε το αντίστοιχο αρχείο ρυθµίσεων. Επειδή συνήθως η γραµµή
που θα θέλουµε να τροποποιήσουµε δεν θα είναι πάντα η πρώτη και δε θα χρειάζεται πάντα
να την αλλάξουµε ολόκληρη, ο κώδικάς µας θα πρέπει να µπορεί να κάνει αναζήτηση µέσα
στο κείµενο και να εντοπίζει µόνο τους χαρακτήρες ή τα σύµβολα που µας ενδιαφέρουν. Σε
ορισµένες περιπτώσεις επίσης, θα χρειάζεται ακόµα και η διαγραφή γραµµών ή η εισαγωγή
τους σε σχόλια ούτως ώστε να µην είναι πλέον εκτελέσιµες.
Όλα τα παραπάνω µπορούν να γίνουν γράφοντας ένα πρόγραµµα C αλλά επειδή η γλώσσα αυτή έχει αναπτυχθεί για άλλο σκοπό, θα χρειαστούν πολλές γραµµές κώδικα και πολύς
χρόνος. Εποµένως η γλώσσα awk είναι το κατάλληλο εργαλείο γι’ αυτές τις περιπτώσεις.
Στον Router NGW100 η γλώσσα awk εγκαθίσταται µαζί µε το BusyBox αφού αποτελεί µια
από τις ενσωµατωµένες του εφαρµογές. Μια ανεξάρτητη και πιο πλήρης, εναλλακτική λύση,
είναι και η εφαρµογή gawk η οποία δεν κρίθηκε αναγκαία για τις ανάγκες της παρούσας εργασίας.
Εφαρµογή webif
Η εφαρµογή webif είναι ένα σύστηµα διαχείρισης περιεχοµένου (CMS - Content Management System) και αποτελεί µέρος του OpenWrt (openwrt.org). Θα µπορούσαµε να πούµε
ότι είναι το Joomla των ενσωµατωµένων συστηµάτων Linux. Το σύστηµα webif µας δίνει τη
δυνατότητα να δηµιουργήσουµε ένα Web interface το οποίο θα βασίζεται σε ένα σύνολο shell
και awk scripts. Η επεξεργασία των φορµών µπορεί να γίνεται µέσω της εφαρµογής haserl.
Για να είναι όλα αυτά διαθέσιµα στον χρήστη, το σύστηµα webif χρησιµοποιεί τον httpd
Webserver ο οποίος όπως είδαµε και σε αντίστοιχη παράγραφο, είναι µέρος του BusyBox.
Σχεδόν όλες οι εφαρµογές του Router NGW100 µπορούν να παραµετροποιούνται µέσω του
Web interface που διαθέτει ο Router NGW100.
7.3.5 Eφαρµογές διαχείρισης των διεπαφών δικτύου
Στον Router NGW100 οι θύρες Ethernet, LAN και WAN, ονοµάζονται διεπαφές δικτύου
(network interfaces: wikipedia.org/wiki/Network_card) eth1 και eth0 αντίστοιχα.
Τα χαρακτηριστικά που συνήθως τις αφορούν, είναι η IP, η µάσκα δικτύου και η ενεργοποίηση ή η απενεργοποίησή τους. Σε αυτή την παράγραφο θα παρουσιαστούν οι εφαρµογές που
µας βοηθούν να διαχειριστούµε αυτά τα χαρακτηριστικά.
Εφαρµογή ifconfig
Η εφαρµογή ifconfig (interface configuration) βρίσκεται ενσωµατωµένη στο BusyBox.
Εκτελώντας την χωρίς παραµέτρους στον Router NGW100 παίρνουµε ως αποτέλεσµα όλες
τις λεπτοµέρειες των θυρών LAN, WAN καθώς και εκείνη του loopback adaptor. Αυτό φαίνεται και στην εικόνα που ακολουθεί:
Ιστότοπος εργασίας: MyThesis.org
235
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Για να εµφανίσουµε κάθε διεπαφή δικτύου χωριστά εκτελούµε αντίστοιχα τις παρακάτω εντολές:
ifconfig eth0
ifconfig eth1
ifconfig lo
Για την απενεργοποίηση ή την ενεργοποίηση µιας συγκεκριµένης διεπαφής δικτύου του
Router NGW100, όπως για παράδειγµα της διεπαφής του τοπικού LAN eth1, µπορούµε να
χρησιµοποιήσουµε την ifconfig ως εξής:
ifconfig eth1 down
Επίσης, µέσω της ίδιας εντολής µπορούµε να αποδώσουµε µια στατική IP:
ifconfig eth1 192.168.1.1 netmask 255.255.255.0 up
Και για να ισχύει η αλλαγή και µετά την επανεκκίνηση του Router NGW100:
ifconfig –a eth1
Ο πηγαίος κώδικας της εφαρµογής βρίσκεται στο αρχείο networking/ifconfig.c.
Εφαρµογές ifup και ifdown
Στον Linux Kernel οι διεπαφές δικτύου έχουν τη δυνατότητα να ενεργοποιούνται και να απενεργοποιούνται δυναµικά. Αυτό επιτυγχάνεται µέσω των εφαρµογών του BusyBox, ifup και
Επικοινωνία: [email protected]
236
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
ifdown. Κατά την εκκίνηση του Router NGW100 το script S20network φροντίζει για την
ενεργοποίησή τους εκτελώντας την εντολή /sbin/ifup:
#! /bin/sh
IFUP=/sbin/ifup
echo -n "Network interfaces: "
if ${IFUP} -a; then
echo "done"
else
echo "failed"
exit 1
fi
Ενώ κατά τον τερµατισµό (εντολές poweroff, halt ή reboot) το script K85network
φροντίζει για τον τερµατισµό τους εκτελώντας την εντολή /sbin/ifdown:
#!/bin/sh
IFDOWN=/sbin/ifdown
echo -n "Stopping networking: "
if ${IFDOWN} -a; then
echo "done"
else
echo "failed"
exit 1
fi
Οι παραπάνω εντολές µπορούν να εκτελούνται και µέσω γραµµής εντολών οποιαδήποτε
στιγµή είναι απαραίτητο.
7.3.6 Eφαρµογή route
Ο Router NGW100 είναι ένας δροµολογητής. Εποµένως η σηµαντικότερη λειτουργία που
επιτελεί είναι η δροµολόγηση πακέτων. Σε προηγούµενο κεφάλαιο του θεωρητικού µέρους
αναλύσαµε σε αρκετό βάθος τους µηχανισµούς δροµολόγησης που υπάρχουν ενσωµατωµένοι στον Linux Kernel. Επίσης αναλύσαµε και τη διεπαφή που παρέχεται για τη διαχείριση
µηχανισµών αυτών από τις εφαρµογές του επιπέδου χρήστη (user space apps). Σε αυτή την
παράγραφο θα παρουσιάσουµε συνοπτικά µια τέτοια εφαρµογή ή οποία ονοµάζεται route
και είναι µέρος του BusyBox.
Ο πηγαίος κώδικας της εφαρµογής route βρίσκεται στο αρχείο network/route.c. Tα
βασικά µέρη του πηγαίου κώδικα που περιλαµβάνεται στο αρχείο route.c, είναι οι οδηγίες
συµπερίληψης κεφαλίδων (#include):
#include <net/route.h>
#include <net/if.h>
/* katalogos ... include/net */
#include "libbb.h"
#include "inet_common.h"
/* ston katalogo tou arxeiou route.c */
Και η κύρια συνάρτηση main() η οποία περιλαµβάνει όλη τη λογική του αλγόριθµου δροµολόγησης του Router NGW100:
int route_main(int argc UNUSED_PARAM, char **argv)
{
unsigned opt;
Ιστότοπος εργασίας: MyThesis.org
237
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
int what;
char *family;
char **p;
/* First, remap '-net' and '-host' to avoid getopt problems. */
p = argv;
while (*++p) {
if (strcmp(*p, "-net") == 0 || strcmp(*p, "-host") == 0) {
p[0][0] = '#';
}
}
opt = getopt32(argv, "A:ne", &family);
if ((opt & ROUTE_OPT_A) && strcmp(family, "inet") != 0) {
#if ENABLE_FEATURE_IPV6
if (strcmp(family, "inet6") == 0) {
opt |= ROUTE_OPT_INET6;
/* Set flag for ipv6. */
} else
#endif
bb_show_usage();
}
argv += optind;
/* No more args means display the routing table. */
if (!*argv) {
int noresolve = (opt & ROUTE_OPT_n) ? 0x0fff : 0;
#if ENABLE_FEATURE_IPV6
if (opt & ROUTE_OPT_INET6)
INET6_displayroutes();
else
#endif
bb_displayroutes(noresolve, opt & ROUTE_OPT_e);
fflush_stdout_and_exit(EXIT_SUCCESS);
}
/* Check verb. At the moment, must be add, del, or delete. */
what = kw_lookup(tbl_verb, &argv);
if (!what || !*argv) {
/* Unknown verb or no more args. */
bb_show_usage();
}
#if ENABLE_FEATURE_IPV6
if (opt & ROUTE_OPT_INET6)
INET6_setroute(what, argv);
else
#endif
INET_setroute(what, argv);
return EXIT_SUCCESS;
}
Για να δούµε τις επιλογές που µας δίνονται αρκεί να πληκτρολογήσουµε στην γραµµή εντολών του Router NGW100 την παρακάτω εντολή:
route --help
Για να δούµε τον πίνακα δροµολόγησης του Kernel εκτελούµε την εντολή route χωρίς παραµέτρους:
route
Επικοινωνία: [email protected]
238
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Αν θέλουµε να προσθέσουµε έναν κανόνα δροµολόγησης στον πίνακα παρακάµπτοντας
την αυτόµατη διαδικασία, χρησιµοποιούµε την παράµετρο add. Για να καταργήσουµε τον κανόνα χρησιµοποιούµε την παράµετρο del.
Φυσικά όλα τα παραπάνω αποτελούν µια απλή σύνοψη της εφαρµογής route. Υπάρχουν
πολλές επιπλέον λειτουργίες, καθώς και πολλές δυνατότητες συνδυασµών µε άλλες εφαρµογές.
7.3.7 Εφαρµογή iptables
Στον Router NGW100 το ρόλο του Firewall και του NAT (Network Address Translator) παίζει η εφαρµογή iptables (wikipedia.org/wiki/Iptables).
Η εφαρµογή iptables εκκινεί από το αρχείο S22iptables. Το ίδιο αρχείο µπορεί να
χρησιµοποιηθεί και για την παραµετροποίηση της εφαρµογής, αλλά θα πρέπει κάθε φορά να
γίνεται επανεκκίνηση για να ισχύουν οι νέες ρυθµίσεις. Ο κώδικας του script εκκίνησης
S22iptables είναι ο παρακάτω:
#!/bin/sh
IPTABLES=`which iptables`
echo "Enable NAT:"
echo -n " IPv4 forwarding: "
if echo 1 > /proc/sys/net/ipv4/ip_forward; then
echo "done"
else
echo "failed"
return 1
fi
echo -n " iptables postrouting: "
if [ ! -x "${IPTABLES}" ]; then
echo "missing"
exit 1
fi
if ${IPTABLES} -t nat -A POSTROUTING -o eth0 -j MASQUERADE; then
echo "done"
else
echo "failed"
exit 1
fi
echo -n "
iptables incoming trafic: "
if ${IPTABLES} -A FORWARD -i eth0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT; then
echo "done"
else
echo "failed"
exit 1
fi
echo -n " iptables outgoung trafic: "
if ${IPTABLES} -A FORWARD -i eth1 -o eth0 -j ACCEPT; then
echo "done"
else
echo "failed"
exit 1
fi
exit 0
Ιστότοπος εργασίας: MyThesis.org
239
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Ουσιαστικά δίνει την δυνατότητα στο διαχειριστή του δικτύου να ρυθµίζει τους κανόνες φιλτραρίσµατος πακέτων (packet filtering ruleset) του Linux Kernel. Αυτό το επιτυγχάνει επικοινωνώντας µε το API του ενσωµατωµένου Firewall – Framework που υπάρχει στον Kernel
(Netfilter).
Το φιλτράρισµα των πακέτων αφορά τόσο την εισερχόµενη, όσο και την εξερχόµενη κίνηση.
Όταν το NAT είναι ενεργοποιηµένο, η εφαρµογή iptables αναλαµβάνει να φιλτράρει και
αυτά τα πακέτα. Το πακέτο λογισµικού iptables περιλαµβάνει υποστήριξη και για το IPv6
µέσω του προγράµµατος ip6tables.
Στον Router NGW100 το Firewall iptables περιορίζει τις θύρες της διεπαφής δικτύου
WAN, ενώ αφήνει ανοικτές όλες τις πόρτες στη διεπαφή LAN. Οι κανόνες του Firewall εµφανίζονται µε την εντολή:
iptables -v -L --line-numbers
7.3.8 Εφαρµογές για DNS και DHCP server
Ο Router NGW100 διαθέτει DNS server, DHCP server και DHCP client. Όλα αυτά επιτυγχάνονται µέσω των εφαρµογών dnsmasq και udhcp.
Εφαρµογή dnsmasq
Η εφαρµογή dnsmasq είναι ένας ελαφρύς και εύκολα παραµετροποιήσιµος DNS server και
DHCP server. Είναι σχεδιασµένη για µικρά δίκτυα αλλά µπορεί να υποστηρίξει ταυτόχρονα
µέχρι και 1000 συνδεδεµένους υπολογιστές.
Τα σηµαντικότερα χαρακτηριστικά που διαθέτει είναι τα παρακάτω:
Η παραµετροποίηση DNS των συστηµάτων που βρίσκονται πίσω από Firewall είναι
απλή και δεν εξαρτάται από τους DNS server του ISP.
Οι clients που προσπαθούν να διαβάσουν τις καταχωρήσεις DNS ενώ δεν υπάρχει
σύνδεση στο Internet, δεν καθυστερούν περιµένοντας άσκοπα, αφού προκαλείται άµεσα timeout.
Υποστηρίζει δυναµικές αλλά και στατικές αποδόσεις IP.
Περιλαµβάνει τα πρωτόκολλα BOOTP και TFTP για συστήµατα που δεν διαθέτουν
αποθηκευτικό µέσο και χρειάζεται να εκκινούν µέσω δικτύου.
Αποθηκεύει προσωρινά (caching) σε ειδική περιοχή της µνήµης, τις διευθύνσεις
Internet (A και AAAA records – wikipedia.org/wiki/List_of_DNS_record_types)
καθώς και τις διευθύνσεις που είναι αντιστοιχισµένες µε ονόµατα (address to name
mappings ή PTR records). Αυτό έχει ως αποτέλεσµα την µείωση των αιτηµάτων προς
εξωτερικούς servers και την βελτίωση της απόδοσης.
Μπορεί να ρυθµιστεί ώστε να λαµβάνει αυτόµατα τις διευθύνσεις των upstream name
servers (wikipedia.org/wiki/Upstream_server) από τα αρχεία παραµετροποίησης της εφαρµογής ppp ή από dhcp. Αλλά και να ενηµερώνεται αυτόµατα κάθε
φορά που γίνονται αλλαγές σε αυτά τα αρχεία.
Υποστηρίζει IPv6 και προώθηση πακέτων IPv4 προς IPv6 και το αντίστροφο.
Επικοινωνία: [email protected]
240
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Υποστηρίζει ιδιωτική λειτουργία DNS στέλνοντας αιτήµατα στους upstream servers τα
οποία αφορούν µόνο συγκεκριµένα domains (wikipedia.org/wiki/Domain_name).
Τέλος, υποστηρίζει εγγραφές MX και SRV. Επίσης µπορεί να ρυθµιστεί ώστε να επιστρέφει µόνο εγγραφές MX για µεµονωµένα ή για όλα τα τοπικά συστήµατα.
Στον Router NGW100 o DHCP server εκτελείται µόνο για τη θύρα LAN. Οι ρυθµίσεις βρίσκονται στο αρχείο /etc/dnsmasq.conf. Το script που τον εκκινεί είναι το S21dnsmasq
και το εκτελέσιµο της εφαρµογής το /usr/sbin/dnsmasq. Ο πηγαίος κώδικας βρίσκεται
στον κατάλογο /rousis/buildroot/build_avr32/dnsmasq-2.46/src.
Εφαρµογή udhcpc
Ο DHCP client udhcpc (wikipedia.org/wiki/Udhcpc), είναι ενσωµατωµένος στο
BusyBox και εκτελείται µόνο για τη θύρα WAN. Αυτό συµβαίνει καθώς, όπως έχουµε αναφέρει και στο κεφάλαιο 5, ο Router NGW100 χρειάζεται κάποιο modem για να είναι σε θέση να
δροµολογεί πακέτα στο Internet. Εποµένως θα πρέπει να λαµβάνει µια IP για τη θύρα WAN.
Η διαδικασία αυτή γίνεται κατά την εκκίνηση. Αν δε βρεθεί DHCP server τότε αυτόµατα αποδίδεται η προκαθορισµένη IP. Στον κατάλογο networking/udhcpc βρίσκεται ο πηγαίος
κώδικας της εφαρµογής.
Ο udhcp έχει τη δυνατότητα να ελέγχει µέσω του πρωτοκόλλου ARP αν η IP που του προσφέρεται είναι ίδια µε κάποια άλλη στο δίκτυο. Αν ισχύει κάτι τέτοιο, τότε η διεύθυνση αυτή
απορρίπτεται και η διαδικασία αρχίζει και πάλι από την αρχή. Αν δεν βρεθεί κανένας DHCP
server στην πρώτη αναζήτηση (Sending discover…), τότε γίνονται άλλες δύο προσπάθειες και αν δεν υπάρξει απόκριση αποδίδεται αυτόµατα µια διεύθυνση.
Στον Router NGW100 η εφαρµογή udhcpc εκκινείται από το script εκκίνησης
S20network, µέσω της εφαρµογής ifup, που είδαµε και νωρίτερα σε αντίστοιχη παράγραφο.
7.3.9 Εφαρµογή telnetd
Ο Router NGW100 µπορεί να παραµετροποιηθεί όπως γνωρίζουµε και µέσω δικτύου. Για
το σκοπό αυτό απαιτείται εκτός από τη φυσική σύνδεση, και µια εφαρµογή Telnet server η
οποία θα εκτελείται σε αυτόν και θα εξυπηρετεί αντίστοιχα αιτήµατα σύνδεσης. Στην περίπτωσή µας η εφαρµογή αυτή βρίσκεται ενσωµατωµένη στο BusyBox και το όνοµά της είναι
telnetd.
Η εφαρµογή telnetd (server – client) εκκινείται από το script S40telnetd του οποίου ο
κώδικας είναι ο παρακάτω:
#!/bin/sh
TELNETD=/usr/sbin/telnetd
echo -n "Starting telnetd: "
if [ ! -x "${TELNETD}" ]; then
echo "missing"
exit 1
fi
if ${TELNETD} -l /bin/sh; then
Ιστότοπος εργασίας: MyThesis.org
241
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
echo "done"
else
echo "failed"
exit 1
fi
Το Telnet δεν παρέχει κάποιο αλγόριθµο κρυπτογράφησης και εποµένως έχει κριθεί µη ασφαλές για δίκτυα µε κρίσιµα δεδοµένα. Επίσης δεν είναι ασφαλές και για αποµακρυσµένη
διαχείριση µέσω Internet. Σε τέτοιες περιπτώσεις είναι προτιµότερο να χρησιµοποιηθεί κάποια εφαρµογή που έχει αναπτυχθεί για το πρωτόκολλο SSH. Μια τέτοια εφαρµογή θα εξετάσουµε και στην αµέσως επόµενη παράγραφο.
Σε έναν δροµολογητή της αγοράς συνήθως το Telnet είναι απενεργοποιηµένο. Παρ’ όλα σε
περιβάλλοντα ανάπτυξης το Telnet προτιµάται γιατί δεν απαιτεί σύνδεση µε όνοµα χρήστη
και κωδικό.
7.3.10 Εφαρµογή dropbear
Η εφαρµογή dropbear (matt.ucc.asn.au/dropbear/dropbear.html) είναι ένας
µικρός SSH client – server ο οποίος εκτελείται σε γραµµή εντολής και στον Router NGW100
προσφέρει ασφαλή διαχείριση µέσω δικτύου. Επίσης υποστηρίζει τον ασύµµετρο αλγόριθµο
κρυπτογράφησης RSA. Αυτό σηµαίνει ότι υπάρχει δηµόσιο και ιδιωτικό κλειδί. Εποµένως κατά την εκκίνηση του server θα πρέπει να δηµιουργηθούν τα κλειδιά RSA και DSS. Η εκκίνηση
του dropbear γίνεται από το script S50dropbear:
#!/bin/sh
#
# Starts dropbear sshd.
#
# Make sure the dropbearkey progam exists
[ -f /usr/bin/dropbearkey ] || exit 0
start() {
echo -n "Starting dropbear sshd: "
# Make sure dropbear directory exists
if [ ! -d /etc/dropbear ] ; then
mkdir -p /etc/dropbear
fi
# Check for the Dropbear RSA key
if [ ! -f /etc/dropbear/dropbear_rsa_host_key ] ; then
echo -n "generating rsa key... "
/usr/bin/dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key >
/dev/null 2>&1
fi
# Check for the Dropbear DSS key
if [ ! -f /etc/dropbear/dropbear_dss_host_key ] ; then
echo -n "generating dsa key... "
/usr/bin/dropbearkey -t dss -f /etc/dropbear/dropbear_dss_host_key >
/dev/null 2>&1
fi
umask 077
start-stop-daemon -S -q -p /var/run/dropbear.pid --exec /usr/sbin/dropbear
echo "OK"
}
stop() {
echo -n "Stopping dropbear sshd: "
start-stop-daemon -K -q -p /var/run/dropbear.pid
echo "OK"
}
Επικοινωνία: [email protected]
242
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
restart
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
Τα κλειδιά RSA (dropbear_rsa_host_key) και DSS (dropbear_dss_host_key) που
θα δηµιουργηθούν θα βρίσκονται στον κατάλογο /etc/dropbear του συστήµατος αρχείων
του Router NGW100 προκειµένου να χρησιµοποιούνται όταν εγκαθιδρύεται µία σύνδεση
SSH.
7.3.11 Εφαρµογή ProFTPD
Στα πλαίσια ανάπτυξης της εργασίας αυτής, χρησιµοποιήθηκε αρκετά συχνά ο FTP client
Filezilla. Η εφαρµογή αυτή ήταν εγκατεστηµένη στην εικονική µηχανή Ubuntu, του συστήµατος host. ∆ιευκόλυνε σε µεγάλο βαθµό την µεταφορά αρχείων από και προς τον Router
NGW100 αλλά ταυτόχρονα χρησίµευε και για ταχύτατη επισκόπηση των περιεχοµένων του
συστήµατος αρχείων. Φυσικά, για να είµαστε σε θέση να το κάνουµε αυτό έπρεπε και από το
άλλο άκρο της επικοινωνίας να εκτελείται µια εφαρµογή FTP server. Το όνοµα της εφαρµογής αυτής είναι ProFTPD (wikipedia.org/wiki/ProFTPD).
Η εκκίνησή της γίνεται από το script S50proftpd. Ο κώδικάς του είναι ο εξής:
#!/bin/sh
DAEMON=/usr/sbin/proftpd
trap "" 1
trap "" 15
test -f $DAEMON || exit 0
[ ! -d /var/run/proftpd ] && mkdir /var/run/proftpd
[ ! -f /var/log/wtmp ] && touch /var/log/wtmp
start() {
echo -n "Starting ProFTPD: "
$DAEMON
if [ $? != 0 ]; then
echo "FAILED"
exit 1
else
echo "done"
fi
}
stop() {
echo -n "Stopping ProFTPD: "
Ιστότοπος εργασίας: MyThesis.org
243
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
killall proftpd
echo "done"
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: /etc/init.d/S50proftpd {start|stop|restart}"
exit 1
;;
esac
exit 0
Οι ρυθµίσεις του ProFTPD server στον Router NGW100 βρίσκονται στο αρχείο
/etc/proftpd.conf. Ο πηγαίος κώδικας της εφαρµογής βρίσκεται στον κατάλογο
/rousis/buildroot/build_avr32/proftpd-1.3.1. του συστήµατος host.
7.3.12 Εφαρµογή ethtool
Η εφαρµογή ethtool δίνει τη δυνατότητα διαχείρισης των διεπαφών δικτύου Ethernet,
eth0 και eth1. Οι σηµαντικότεροι λόγοι για να την χρησιµοποιήσουµε είναι οι εξής:
Αναγνώριση και διαγνωστικός έλεγχος των eth0 και eth1
Στατιστικά
Έλεγχος ταχύτητας µετάδοσης, αµφίδροµη µετάδοση duplex, αυτόµατη διαπραγµάτευση (auto-negotiation) και έλεγχος ροής
Έλεγχος σφαλµάτων (cheksum) σε χαµηλό επίπεδο
Έλεγχος µήκους DMA δακτυλίων και τροποποίηση διακοπών
∆ιαχείριση ουράς λήψης πλαισίων
Αναβάθµιση του firmware του Router NGW100
Για να είναι δυνατά όλα τα παραπάνω φυσικά, απαιτείται η ύπαρξη του οδηγού MACB τον
οποίο αναλύσαµε ενδελεχώς και σε αντίστοιχο παράρτηµα.
Ο πηγαίος κώδικας της εφαρµογής ethtool βρίσκεται στον κατάλογο της εικονικής
Ubuntu, /rousis/buildroot/build_avr32/ethtool-6.
Εκτελώντας την εντολή ethtool eth1, µπορούµε να δούµε τις λεπτοµέρειες της θύρας
LAN του Router NGW100:
Επικοινωνία: [email protected]
244
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
Εικόνα 140. Εκτέλεση της εντολής ethtool για τη διεπαφή eth1
7.3.13 Εφαρµογή portmap
Η εφαρµογή portmap στον Router NGW100 χρησιµεύει για να διατηρεί µε τις θύρες που
χρησιµοποιούν οι εφαρµογές (κυρίως daemons) που προσφέρουν υπηρεσίες RPC (Remote
Procedure Call - wikipedia.org/wiki/Remote_procedure_call).
Η εφαρµογή εκκινείται µετά τον Linux Kernel. Ο πηγαίος κώδικας της εφαρµογής βρίσκεται
στον κατάλογο /rousis/buildroot/build_avr32/portmap_5beta.
7.3.14 Εφαρµογή bridge
Ο Router NGW100 µπορεί να λειτουργήσει και ως γέφυρα µεταξύ των διεπαφών δικτύου
eth0 και eth1. Αυτό επιτυγχάνεται µέσω της εφαρµογής bridge.
Στον κατάλογο /rousis/buildroot/build_avr32/bridge-1.4/doc υπάρχει αρκετά
καλή τεκµηρίωση της εφαρµογής. Εποµένως εδώ θα παρατεθεί µόνο η βοήθεια που εµφανίζεται στη γραµµή εντολών όταν εκτελέσουµε την εντολή brctl (bridge control) µε την παράµετρο --help:
Εικόνα 141. Βοήθεια για την εντολή brctl της εφαρµογής bridge
Ιστότοπος εργασίας: MyThesis.org
245
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Ένα σηµαντικό χαρακτηριστικό της εφαρµογής bridge είναι ότι επιτρέπει να εκτελείται και
τείχος προστασίας κατά τη λειτουργία της. Κάτι όµως που όπως αναφέρει η τεκµηρίωση είναι
ταυτόχρονα χρήσιµο αλλά και εντελώς αντίθετο µε τη λογική του µοντέλου OSI.
7.3.15 Εφαρµογές ενηµέρωσης – εµφάνισης ώρας και ηµεροµηνίας
Η ρύθµιση και η ενηµέρωση της ώρας και της ηµεροµηνίας του Router NGW100 επιτυγχάνεται µέσω του πρωτοκόλλου NTP (Network Time Protocol) και των εφαρµογών ntpd και
ntpdate. Για την εκκίνησή τους εκτελούνται δύο scripts. To script S43ntpdate:
#!/bin/sh
NTPDATE=/usr/bin/ntpdate
if [ -f /etc/default/ntpdate ]; then
. /etc/default/ntpdate
else
echo "WARNING: missing /etc/default/ntpdate"
exit 1
fi
echo -n "Running ntpdate: "
if [ ! -x ${NTPDATE} ]; then
echo "missing"
echo -n " WARNING: could not syncronize clock, "
echo "edit NTPSERVERS in /etc/default/ntpdate."
exit 1
fi
if ${NTPDATE} $NTPOPTIONS $NTPSERVERS; then
echo "done"
else
echo "failed"
echo -n " WARNING: could not syncronize clock, "
echo "edit NTPSERVERS in /etc/default/ntpdate."
exit 1
fi
Και το script S49ntp:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="network time protocol daemon"
NAME=ntpd
DAEMON=/usr/sbin/$NAME
NTPDATE_BIN=/usr/bin/ntpdate
# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0
# Read config file if it is present.
if [ -r /etc/default/$NAME ]
then
. /etc/default/$NAME
fi
case "$1" in
start)
if test x$NTPDATE = xyes ; then
echo -n "Getting initial time via ntp"
$NTPDATE_BIN $NTPDATE_OPTS $NTPSERVERS > /dev/null 2>&1
echo "."
Επικοινωνία: [email protected]
246
Οι εφαρµογές του Router NGW100 – Κεφάλαιο 7
fi
if test x$NTPD = xyes ; then
echo -n "Starting $DESC: $NAME"
start-stop-daemon -S -q -x $DAEMON
echo "."
fi
;;
stop) echo -n "Stopping $DESC: $NAME"
start-stop-daemon -K -q -n $NAME
echo "."
;;
reload|force-reload) echo -n "Reloading $DESC configuration..."
start-stop-daemon -K -q -n $NAME -s 1
echo "done."
;;
restart) echo "Restarting $DESC: $NAME"
$0 stop
sleep 1
$0 start
;;
*) echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
exit 1
;;
esac
exit 0
Ο πηγαίος κώδικας των εφαρµογών ntp και ntpdate βρίσκεται στον κατάλογο
/rousis/buildroot/build_avr32/ntp-4.2.4p5 του συστήµατος host. Οι ρυθµίσεις
βρίσκονται στο αρχείο /etc/ntp.conf του συστήµατος αρχείων του Router NGW100.
Ιστότοπος εργασίας: MyThesis.org
247
ΠΑΡΑΡΤΗΜΑΤΑ
ΠΑΡΑΡΤΗΜΑ
A
Το σχηµατικό του Router NGW100
Εισαγωγή
Ένα από τα σηµαντικότερα στάδια ανάπτυξης ενός ενσωµατωµένου συστήµατος είναι η
δηµιουργία του σχηµατικού διαγράµµατος (schematic diagram), ή απλά του σχηµατικού. Κατά τη διάρκεια υλοποίησης της παρούσας εργασίας υπήρξε η ευκαιρία να συγκεντρωθούν
αρκετές σχετικές πληροφορίες. Αυτό έγινε τόσο µέσω του ∆ιαδικτύου, όσο και µε προσωπική
προσπάθεια. Οι πληροφορίες αυτές είναι προαιρετικές για την κατανόηση του παραρτήµατος
και µπορούν να παρακαµφθούν. Παραθέτονται εδώ κυρίως για εγκυκλοπαιδικούς λόγους.
Η ανάπτυξη του σχηµατικού
Το σχηµατικό πρέπει να σχεδιαστεί έτσι ώστε να δίνει κάθε λεπτοµέρεια µε ευκρίνεια, έχοντας πάντα υπ’ όψιν µας το σχέδιο PCB (Printed Circuit Board). Πριν αρχίσουµε να σχεδιάζουµε το PCB, πρέπει να έχουµε ένα πλήρες και ακριβές σχηµατικό διάγραµµα. Εάν δεν
υπάρχει ένα ακριβές σχηµατικό, το PCB θα καταλήξει πιθανότατα να σχεδιαστεί λάθος.
Ένα σχέδιο PCB είναι µια κατασκευασµένη έκδοση του σχηµατικού και είναι φυσικό να επηρεάζεται από αυτό. Αν το σχηµατικό µας είναι τακτοποιηµένο λογικά, και σαφώς σχεδιασµένο, τότε η δηµιουργία του σχεδίου PCB γίνεται ευκολότερη. Η ορθή πρακτική, θα έχει τα
σήµατα να ρέουν από τις εισόδους στα αριστερά µε φορά προς τις εξόδους στα δεξιά. Αφού
σχεδιαστούν σωστά τα σηµαντικά ηλεκτρικά και ηλεκτρονικά στοιχεία, το PCB που προκύπτει, είναι κατά πάσα πιθανότητα, σωστό.
Οι σηµειώσεις στο σχηµατικό βοηθούν στην σωστή απεικόνιση (layout) του PCB. Ακόµα κι
αν είµαστε εµείς που σχεδιάσαµε το κύκλωµα και τη σχηµατική αναπαράστασή του, οι σηµειώσεις όχι µόνο θα µας υπενθυµίζουν διάφορες λεπτοµέρειες, αλλά θα είναι χρήσιµες και
για τους ανθρώπους που θα αναθεωρήσουν το σχέδιο.
Κλείνοντας θα πρέπει να πούµε ότι το σχηµατικό ενός ενσωµατωµένου συστήµατος, ανάλογα µε την πολυπλοκότητα του, µπορεί να εκτείνεται σε περισσότερες της µίας, σελίδες. Σε
αυτή την περίπτωση ένα ολοκληρωµένο µπορεί να βρίσκεται σε διαφορετική σελίδα µε κάποιο άλλο. Εποµένως η σύνδεσή τους δεν είναι δυνατό να φαίνεται άµεσα. Σε τέτοιες περιπτώσεις γίνεται χρήση της ονοµασίας της γραµµής που τα συνενώνει. Αυτό ισχύει και για το
σχηµατικό του Router NGW100.
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Οι γραµµές του σχηµατικού, που ταξιδεύουν από µία σελίδα σε µια άλλη, έχουν στο ελεύθερο άκρο τους ένα διπλό βέλος. Τα βέλη που έχουν αριστερή διεύθυνση αφορούν τις γραµµές που πρέπει να συνδεθούν σε κάποιο άλλο στοιχείο. Τα βέλη που έχουν δεξιά διεύθυνση
αφορούν τις γραµµές που προέρχονται από άλλα ολοκληρωµένα και συνδέονται εκεί που
καταλήγουν. Αυτό γίνεται ευκολότερα αντιληπτό και µε µια πιο προσεκτική παρατήρηση.
Το σχηµατικό του Router NGW100
Το σχηµατικό του Router NGW100 αποτελείται από αρκετές σελίδες. Λόγω του µεγέθους
του έχει γίνει µια προσπάθεια, κάθε στοιχείο ή κάθε οµοειδής οµάδα στοιχείων, να καταλαµβάνει ξεχωριστή σελίδα. Αυτό έχει ως αποτέλεσµα να µειώνεται η πολυπλοκότητα και να διευκολύνεται η ανάγνωση.
Οι σελίδες αυτές είναι οι εξής:
AP7000_1 Το πρώτο τµήµα ακροδεκτών του µικροελεγκτή AP7000
AP7000_2 Το δεύτερο τµήµα ακροδεκτών του µικροελεγκτή AP7000
ETHERNET PORT 0 LAN Ethernet PHY controller
ETHERNET PORT 1 WAN Ethernet PHY controller
FLASH Μνήµες Flash, παράλληλη (NOR) και σειριακή (NAND)
SDRAM Η µνήµη SDRAM
SD/MMC Η θύρα (slot) για κάρτες µνήµης SD (SDCARD reader)
RS-232 / USB Θύρες RS-232 και USB
BOARD CONTROL Ο ελεγκτής της πλακέτας
GPIO Τα σήµατα GPIO
JTAG_NEXUS Η διεπαφές υλικού JTAG και NEXUS
POWER Το κύκλωµα τροφοδοσίας
NON Electrical Μηχανικές λεπτοµέρειες οπών
Επικοινωνία: [email protected]
250
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
251
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
252
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
253
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
254
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
255
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
256
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
257
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
258
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
259
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
260
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
261
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Επικοινωνία: [email protected]
262
Σχηµατικά του Router NGW100 – Παράρτηµα Α
Ιστότοπος εργασίας: MyThesis.org
263
ΠΑΡΑΡΤΗΜΑ
Β
Τεκµηρίωση ανάπτυξης
του οδηγού δικτύου MACB
Εισαγωγή
Επειδή δεν είναι δυνατό να παρουσιάσουµε γραµµή – γραµµή την λειτουργία του driver
MACB θα περιγράψουµε βήµα – βήµα τα στάδια ανάπτυξής του, και όπου είναι χρήσιµο θα
παραθέτουµε τµήµατα του πηγαίου κώδικα που βρίσκεται στα αρχεία macb.c και macb.h. Η
ανάλυση θα γίνει µε τέτοιο τρόπο ώστε να µπορεί να εφαρµοστεί και σε άλλες περιπτώσεις
ανάπτυξης οδηγών δικτύου.
Τα κυριότερα βήµατα που ακολουθήθηκαν για την ανάπτυξη του οδηγού δικτύου MACB, και
τα οποία µπορούν να εφαρµοστούν για οποιαδήποτε άλλη παρόµοια περίπτωση ανάπτυξης,
είναι τα εξής
Τεχνικά εγχειρίδια
Λήψη αποφάσεων ανάπτυξης
Το αρχείο κεφαλής drivers/net/macb.h
Το αρχείο macb.c
Καταχώρηση διεπαφής δικτύου
∆ηµιουργία συσκευής πλατφόρµας
Χαρτογράφηση των καταχωρητών εισόδου – εξόδου
Καταχώρηση IRQ
Ρύθµιση και ενεργοποίηση ρολογιού
Ανάκτηση της διεύθυνση υλικού MAC
Πρόσβαση στο ολοκληρωµένο DP83848I (PHY) µέσω του διαύλου MDIO
Συναρτήσεις πρόσβασης του διαύλου MDIO
Σύνδεση και επίβλεψη κατάστασης στο ολοκληρωµένο DP83848I
∆έσµευση των DMA buffers, αρχικοποίηση και καθαρισµός
Reset και αρχικοποίηση υλικού
Εκκίνηση και τερµατισµός λειτουργιών
Κλείδωµα οδηγού
Αποστολή πακέτων
Ολοκλήρωση της αποστολής
Λήψη πακέτων
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Τεχνικά εγχειρίδια
Καθ’ όλη τη διάρκεια της ανάπτυξης, θα πρέπει να συµβουλευόµαστε συνέχεια το datasheet
του µικροελεγκτή και των Ethernet controllers που θα χρησιµοποιηθούν καθώς και το σχηµατικό διάγραµµα της πλακέτας. Αυτό θα µας βοηθά να γνωρίζουµε τον τρόπο µε τον οποίο
συνδέονται τα σήµατα µεταξύ τους αλλά και τις ιδιότητες του κάθε σήµατος. Βάσει αυτών θα
είµαστε σε θέση να γράψουµε το αρχείο κεφαλής (mac.h) στο οποίο καθορίζονται
(#define) οι λεπτοµέρειες του υλικού που θέλουµε να “οδηγήσουµε”.
Λήψη αποφάσεων ανάπτυξης
Ένα από τα πρώτα πράγµατα που πρέπει να αποφασίσουµε όταν αναπτύσσουµε έναν οδηγό δικτύου είναι αν θέλουµε να φορτώνεται στο σύστηµά µας ως module κατά την εκκίνηση ή αν θα είναι ενσωµατωµένος στον Kernel. Στην περίπτωση του οδηγού MACB ισχύει το
πρώτο.
Για την λειτουργία των modules έχουµε µιλήσει σε προηγούµενο κεφάλαιο. Εποµένως δεν
χρειάζεται να γίνει κάποια επιπλέον ανάλυση εδώ.
Το αρχείο κεφαλής drivers/net/macb.h
Το αρχείο κεφαλής macb.h περιλαµβάνει πληροφορίες που θα χρειαστούν κατά την ανάπτυξη του οδηγού δικτύου. Για παράδειγµα, περιλαµβάνει οδηγίες #define για τον καθορισµό των λεπτοµερειών που αφορούν την αρχιτεκτονική του µικροελεγκτή AP7000 καθώς
επίσης, και τη δοµή macb που αντιπροσωπεύει την διεπαφή του δικτύου που θέλουµε να υλοποιήσουµε και να καταχωρίσουµε στον Kernel έτσι ώστε να µπορεί ο Router NGW100 να
επικοινωνεί µέσω των θυρών LAN (macb1) και WAN (macb0):
struct macb {
void __iomem
*regs;
unsigned int
struct dma_desc
void
rx_tail;
*rx_ring;
*rx_buffers;
unsigned int
struct dma_desc
struct ring_info
tx_head, tx_tail;
*tx_ring;
*tx_skb;
spinlock_t
struct platform_device
struct clk
struct clk
struct net_device
struct napi_struct
struct net_device_stats
struct macb_stats
lock;
*pdev;
*pclk;
*hclk;
*dev;
napi;
stats;
hw_stats;
dma_addr_t
dma_addr_t
dma_addr_t
rx_ring_dma;
tx_ring_dma;
rx_buffers_dma;
unsigned int
rx_pending, tx_pending;
struct mii_bus
mii_bus;
Ιστότοπος εργασίας: MyThesis.org
265
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
struct phy_device
unsigned int
unsigned int
unsigned int
*phy_dev;
link;
speed;
duplex;
};
Οι δοµές δεδοµένων που χρησιµοποιούνται από την macb ορίζονται µέσα σε διάφορα αρχεία του πηγαίου κώδικα C, του Linux Kernel:
dma_desc
ring_info
platform_device
clk
net_device
napi_struct
net_device_stats
macb_stats
mii_bus
phy_device
drivers/net/macb.h
drivers/net/s2io.h
include/linux/platform_device.h
include/linux/clk.h
include/linux/netdevice.h
include/linux/netdevice.h
include/linux/netdevice.h
drivers/net/macb.h
include/linux/phy.h
include/linux/phy.h
Η ανάπτυξη της δοµής macb θα αναλυθεί παράλληλα µε την ανάλυση της ανάπτυξης του
οδηγού δικτύου.
Το αρχείο macb.c
Σε αυτό το αρχείο περιέχεται η λογική και οι µηχανισµοί στους οποίους βασίζεται ο µικροελεγκτής AP7000 για να επικοινωνήσει µε τον Kernel και µε το ολοκληρωµένο DP83848I.
προκειµένου ο Router NGW100 να είναι σε θέση να επικοινωνήσει µε το δίκτυο. Φυσικά ο
κώδικας βασίζεται και σε έτοιµη υποδοµή που υπάρχει ήδη στον Kernel. Αυτό επιτυγχάνεται
κυρίως µε την συµπερίληψη των αρχείων κεφαλής που πραγµατοποιείται στις πρώτες γραµµές του κώδικα και τις οποίες βλέπουµε πιο κάτω:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<linux/clk.h>
<linux/module.h>
<linux/moduleparam.h>
<linux/kernel.h>
<linux/types.h>
<linux/slab.h>
<linux/init.h>
<linux/netdevice.h>
<linux/etherdevice.h>
<linux/dma-mapping.h>
<linux/platform_device.h>
<linux/phy.h>
#include <mach/board.h>
#include <mach/cpu.h>
#include "macb.h"
Στις επόµενες παραγράφους γίνεται ανάλυση του οδηγού δικτύου που αναπτύχθηκε για τον
Router NGW100. Η ανάλυση δεν γίνεται γραµµή – γραµµή αλλά τµήµα – τµήµα, για να βασίζεται στη φυσική ροή των διαδικασιών που πρέπει να ολοκληρωθούν ώστε το σύστηµά µας
να είναι σε θέση να ανταλλάξει δεδοµένα µε το δίκτυο και τις εφαρµογές του.
Επικοινωνία: [email protected]
266
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Καταχώρηση διεπαφής δικτύου
Εφόσον όλα τα βασικά εργαλεία ανάπτυξης είναι στη θέση τους, µπορούµε πλέον να δηµιουργήσουµε τον πηγαίο κώδικα του οδηγού δικτύου, macb.c.
Αρχικά, καταχωρούµε µια διεπαφή δικτύου (network interface registration). Αυτό πρέπει να
γίνει µέσα στην συνάρτηση αρχικοποίησης του module. Επίσης όπως είδαµε και σε προηγούµενο κεφάλαιο όταν αναλύαµε τα modules στο Linux, είναι απαραίτητο να γράψουµε και
µια συνάρτηση κατάργησης του module ώστε να απελευθερώνονται πόροι όταν δεν το χρειαζόµαστε πια.
Αρχικά χρησιµοποιούµε την συνάρτηση alloc_etherdev η οποία ουσιαστικά θα δηµιουργήσει τη δοµή net_device. Η δοµή αυτή καθορίζεται στο αρχείο netdevice.h που
βρίσκεται στον κατάλογο include/linux και είναι υπεύθυνη για τη δηµιουργία µιας νέας
διεπαφής δικτύου:
err = -ENOMEM;
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
goto err_out;
}
SET_NETDEV_DEV(dev, &pdev->dev);
Στη συνέχεια δηµιουργούµε και αρχικοποιούµε ένα στιγµιότυπο της δοµής ethtool_ops
µε όνοµα macb_ethtool_ops:
static struct ethtool_ops macb_ethtool_ops = {
.get_settings
= macb_get_settings,
.set_settings
= macb_set_settings,
.get_drvinfo
= macb_get_drvinfo,
.get_link
= ethtool_op_get_link,
};
Η καταχώρησή της διεπαφής που δηµιουργήσαµε επιτυγχάνεται µέσω της συνάρτησης
register_netdev και η κατάργησή της µέσω της macb_remove και των περιεχόµενων σε
αυτή, κλήσεων συναρτήσεων, unregister_netdev και free_netdev.
Αν όλα έχουν γίνει σωστά, µετά τη φόρτωση του module θα δηµιουργηθεί µια νέα διεπαφή
δικτύου µε το όνοµα eth0 (macb0) για το WAN. την οποία θα µπορούµε να δούµε στο σύστηµά µας άµεσα Στον Router NGW100 υπάρχει και eth1 (macb1) για το LAN. Πράγµα που
σηµαίνει ότι υπάρχουν δύο διεπαφές δικτύου. Συγκεκριµένα, οι διεπαφές αυτές χαρακτηρίζονται ως WAN και LAN αντίστοιχα. Χρησιµεύουν για σύνδεση στο τοπικό δίκτυο και το Internet.
Φυσικά αν αναπτύσσαµε ένα Router όπως αυτά που κυκλοφορούν στην αγορά, θα έπρεπε
να δηµιουργήσουµε και τα eth2, eth3 (αν ο µικροελεγκτής το υποστηρίζει) προκειµένου να
ενσωµατώσουµε µε αυτό τον τρόπο στον Router µας, ένα switch 4 θυρών.
Στη συνάρτηση κατάργησης του module που αναφέραµε πιο πάνω, προσθέτουµε τις συναρτήσεις unregister_netdev και free_netdev, ούτως ώστε όταν το module καταργηθεί να συµβεί το ίδιο και στη διεπαφή δικτύου που δηµιουργήθηκε από αυτό.
Ιστότοπος εργασίας: MyThesis.org
267
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
∆ηµιουργία συσκευής πλατφόρµας
Αν θέλουµε ο οδηγός που αναπτύσσουµε να µπορεί να ενσωµατωθεί στο δέντρο του πηγαίου κώδικα (source tree) του Kernel ως οδηγός πλατφόρµας, θα πρέπει να προσθέσουµε
επιπλέον κώδικα δηµιουργίας οδηγού πλατφόρµας και ενεργοποίησης της αντίστοιχης συσκευής πλατφόρµας. Αυτό γίνεται ούτως ώστε κατά την µεταγλώττιση του Kernel ο οδηγός
να µπορεί να ενσωµατωθεί στατικά σε αυτόν.
Για να το πετύχουµε αυτό θα πρέπει ο οδηγός µας να καταχωρηθεί ως συσκευή πλατφόρµας (platform device). Αυτό γίνεται ως εξής:
Καθορίζουµε µια δοµή platform_driver µε όνοµα macb_driver:
static struct platform_driver macb_driver = {
.remove
= __exit_p(macb_remove),
.suspend
= macb_suspend,
.resume
= macb_resume,
.driver
= {
.name
= "macb",
.owner
= THIS_MODULE,
},
};
∆ηµιουργούµε τη συνάρτηση macb_init:
static int __init macb_init(void)
{
return platform_driver_probe(&macb_driver, macb_probe);
}
Και την συνάρτηση macb_exit:
static void __exit macb_exit(void)
{
platform_driver_unregister(&macb_driver);
}
Εννοείται βέβαια ότι η συνάρτηση platform_driver_probe καθώς και η συνάρτηση platform_driver_unregister, βρίσκονται ήδη υλοποιηµένες στον Kernel
προκειµένου να αρχικοποιούν και να καταργούν αντίστοιχα, κάποιον οδηγό πλατφόρµας που θα τους ζητηθεί. Στην περίπτωσή µας αυτός είναι ο macb_driver (στιγµιότυπο της δοµής platform_driver).
∆ηµιουργούµε τη συνάρτηση macb_probe η οποία θα πραγµατοποιήσει µε τη σειρά
της άλλες δύο ενέργειες. Η πρώτη θα είναι να συνδέσει την συσκευή δικτύου µε την
συσκευή πλατφόρµας, µέσω της συνάρτησης SET_NETDEV_DEV:
SET_NETDEV_DEV(dev, &pdev->dev);
Όπου το όρισµα dev είναι ένα στιγµιότυπο της δοµής net_device και το pdev ένας
δείκτης που δείχνει στη δοµή platform_device. και το οποίο περνιέται και σαν όρισµα στην συνάρτηση macb_probe.
Και η δεύτερη θα είναι να αρχικοποιήσει τον δείκτη της συσκευής πλατφόρµας ώστε
να δείχνει στη συσκευή δικτύου:
Επικοινωνία: [email protected]
268
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
platform_set_drvdata(pdev, dev);
Υλοποιούµε την συνάρτηση macb_remove η οποία λειτουργεί παρόµοια µε την προηγούµενη συνάρτηση κατάργησης.
Χαρτογράφηση των καταχωρητών εισόδου – εξόδου
Η χαρτογράφηση των καταχωρητών εισόδου – εξόδου την µονάδας δικτύωσης του µικροελεγκτή, όπως είναι φυσικό υλοποιείται στη µνήµη του συστήµατος. Εποµένως πρέπει να δηµιουργηθεί µια περιοχή στην µνήµη όπου θα αποθηκεύουµε από ‘δω και στο εξής τέτοιου
είδους πληροφορίες. Αυτό µπορεί να γίνει δηµιουργώντας µια δοµή η οποία προς το παρόν
θα περιέχει µόνο ένα δείκτη προς τους καταχωρητές εισόδου – εξόδου:
struct macb
{
void __iomem *regs;
...
};
Αφού δηµιουργηθεί η δοµή macb µπορούµε να πραγµατοποιήσουµε την χαρτογράφηση µε
τη βοήθεια της συνάρτησης ioremap. Φυσικά χρειάζεται να κάνουµε µια προσθήκη στη συνάρτηση macb_probe για να γνωρίζει το µέγεθος της δοµής macb:
dev = alloc_etherdev(sizeof(*bp));
Καταχώρηση IRQ
Η καταχώρηση IRQ (el.wikipedia.org/wiki/Αίτηση_διακοπής) είναι παραπλήσια
µε την χαρτογράφηση των καταχωρητών εισόδου – εξόδου. Γίνεται από την συνάρτηση
macb_probe µέσω της κλήσης των συναρτήσεων:
platform_get_irq – Ανακτά τον αριθµό διακοπής IRQ του Ethernet controller.
Πρέπει να αποθηκεύεται στο πεδίο irq της δοµής net_device. Για να το κάνουµε
όµως αυτό θα πρέπει να χρησιµοποιήσουµε το στιγµιότυπο dev της δοµής
net_device που έχουµε δηµιουργήσει δυναµικά για τον οδηγό µας:
dev -> irq = platform_get_irq(pdev, 0);
request_irq – Προκειµένου να ολοκληρωθεί η διαδικασία καταχώρησης αριθµού
IRQ απαιτείται η δηµιουργία ενός χειριστή διακοπών (interrupt handler).
err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM,
dev->name, dev);
Φυσικά όπως και στις περισσότερες περιπτώσεις δέσµευσης πόρων, είναι καλό να αποδεσµεύουµε ότι δε χρειάζεται πια. Αυτό στην περίπτωση της κατάργησης IRQ επιτυγχάνεται
µέσω της συνάρτησης free_irq η οποία θα πρέπει να βρίσκεται µέσα στη συνάρτηση
macb_remove:
free_irq(dev->irq, dev);
Ιστότοπος εργασίας: MyThesis.org
269
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Ρύθµιση και ενεργοποίηση ρολογιού
Για την ρύθµιση του ρολογιού θα χρειαστούµε πρώτα ορισµένες διευθύνσεις και τιµές καταχωρητών του µικροελεγκτή AP7000. Όλα αυτά τα στοιχεία υπάρχουν στο αντίστοιχο datasheet (doc32003.pdf) και πιο συγκεκριµένα στην παράγραφο 31.7.2 (Network
Configuration Register). Έτσι κατά την ανάπτυξη του αρχείο κεφαλής macb.h, θα
πρέπει να προσθέσουµε την εξής οδηγία:
#define MACB_NCFGR
0x0004
Επίσης προσθέτουµε τις τιµές:
/* Constants for CLK */
#define MACB_CLK_DIV8
#define MACB_CLK_DIV16
#define MACB_CLK_DIV32
#define MACB_CLK_DIV64
0
1
2
3
Ο διαιρέτης του ρολογιού (clock divider ή MACB_CLK_DIV) καθορίζεται στο δέκατο και ενδέκατο bit του καταχωρητή NCFGR. Εποµένως χρειαζόµαστε άλλη µια οδηγία για το λόγο αυτό:
#define MACB_CLK_OFFSET
10
Σε αυτό το σηµείο, και µέσω της συνάρτησης macb_probe, µπορούµε πλέον να χρησιµοποιήσουµε τη διεπαφή ρολογιού (clock API) του Kernel η οποία περιλαµβάνει τις συναρτήσεις clk_get, clk_put, clk_enable, clk_disable και clk_get_rate. Οι χρονισµοί
του µικροελεγκτή AP7000 βρίσκονται στο αρχείο arch\avr32\mach-at32ap. Ο δείκτης
που επιστρέφεται από την συνάρτηση clk_get θα αποθηκευτεί στη συνέχεια στη δοµή
macb µέσω του δείκτη bp:
Αφού ενεργοποιηθεί το ρολόι, απλά πρέπει να ρυθµίσουµε τον διαιρέτη του Ethernet controller και πάλι µε βάση το datasheet του µικροελεγκτή:
bp->pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(bp->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
goto err_out_free_dev;
}
bp->hclk = clk_get(&pdev->dev, "hclk");
if (IS_ERR(bp->hclk)) {
dev_err(&pdev->dev, "failed to get hclk\n");
goto err_out_put_pclk;
}
clk_enable(bp->pclk);
clk_enable(bp->hclk);
Και πάλι στη συνάρτηση macb_remove θα πρέπει να προσθέσουµε κώδικα που να καταργεί το ρολόι που χρησιµοποιήσαµε:
clk_disable(bp->pclk);
clk_put(bp->pclk)
Επικοινωνία: [email protected]
270
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Ανάκτηση της διεύθυνση υλικού MAC
Το επόµενο βήµα αρχικοποίησης που είναι και το πρώτο το οποίο αφορά άµεσα τη δυνατότητα δικτύωσης, είναι να διαβάσουµε τη διεύθυνση MAC του υλικού και να ενηµερώσουµε για
την ύπαρξή της, την στοίβα TCP/IP. Σύµφωνα µε το datasheet η διεύθυνση MAC µπορεί να
διαβαστεί από δύο καταχωρητές:
#define MACB_SA1B
#define MACB_SA1T
0x0098
0x009c
Ο πρώτος καταχωρητής περιέχει τα 4 λιγότερο κατώτερα bytes και τα 2 ανώτερα, δηµιουργώντας έτσι τα 6 bytes που είναι απαραίτητα για την διεύθυνση MAC.
Για να µπορέσουµε να διαβάσουµε τη διεύθυνση MAC από τους καταχωρητές και στη συνέχεια να την περάσουµε στη στοίβα TCP/IP, απαιτείται η δηµιουργία µιας συνάρτησης η
οποία θα εκτελεί τα εξής:
∆ιαβάζει τη διεύθυνση MAC µέσω της συνάρτησης __raw_readl (ορίζεται στο αρχείο macb.h).
Αρχικοποιεί έναν πίνακα των 6 bytes µε τη MAC
Ελέγχει αν η MAC είναι έγκυρη, µέσω της συνάρτησης is_valid_ether_addr που
παρέχεται από τον Kernel. Αν είναι έγκυρη την αντιγράφει στο πεδίο dev_addr της
δοµής net_device. Αν δεν είναι, δηµιουργεί µια τυχαία διεύθυνση µέσω της συνάρτησης eth_hw_addr_random. η οποία παρέχεται επίσης από τον Kernel.
Όλα τα παραπάνω εκτελούνται από την συνάρτηση macb_get_hwaddr:
static void __init macb_get_hwaddr(struct macb *bp)
{
u32 bottom;
u16 top;
u8 addr[6];
bottom = macb_readl(bp, SA1B);
top = macb_readl(bp, SA1T);
addr[0]
addr[1]
addr[2]
addr[3]
addr[4]
addr[5]
=
=
=
=
=
=
bottom & 0xff;
(bottom >> 8) & 0xff;
(bottom >> 16) & 0xff;
(bottom >> 24) & 0xff;
top & 0xff;
(top >> 8) & 0xff;
if (is_valid_ether_addr(addr)) {
memcpy(bp->dev->dev_addr, addr, sizeof(addr));
} else {
dev_info(&bp->pdev->dev, "invalid hw address, using random\n");
random_ether_addr(bp->dev->dev_addr);
}
}
Στη συνέχεια, µέσα στην συνάρτηση macb_probe καλούµε την συνάρτηση ανάγνωσης
διεύθυνσης MAC:
macb_get_hwaddr(bp);
Ιστότοπος εργασίας: MyThesis.org
271
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Αν όλα πάνε καλά το αποτέλεσµα θα αποθηκευτεί στο πεδίο dev_addr της δοµής
net_device.
Πρόσβαση στο ολοκληρωµένο DP83848I (PHY) µέσω του διαύλου MDIO
Σε αυτό το στάδιο θέλουµε να επικοινωνήσει ο Ethernet controller του µικροελεγκτή AP7000
µε τον Ethernet controller του ολοκληρωµένου DP83848I. Το ολοκληρωµένο αυτό περιγράφεται αναλυτικότερα στο κεφάλαιο που αναλύονται τα ηλεκτρικά και ηλεκτρονικά χαρακτηριστικά του Router NGW100.
Η επικοινωνία αυτή µπορεί να γίνει µέσω του διαύλου MDIO (Management Data Input –
Output) ο οποίος υποστηρίζεται και από ειδικό framework που υπάρχει υλοποιηµένο στον
Kernel. Η πρώτη ενέργεια που πρέπει να γίνει λοιπόν είναι η αρχικοποίηση του MDIO. Αυτό
επιτυγχάνεται µε την συνάρτηση macb_mii_init. Η συνάρτηση αυτή εκτελεί τις παρακάτω
λειτουργίες:
∆εσµεύει µνήµη για τη δοµή mii_bus µέσω της συνάρτησης mdiobus_alloc
Αρχικοποιεί όλα τα µέλη της δοµής mii_bus:
bp->mii_bus.name = "MACB_mii_bus";
bp->mii_bus.read = &macb_mdio_read;
bp->mii_bus.write = &macb_mdio_write;
bp->mii_bus.reset = &macb_mdio_reset;
snprintf(bp->mii_bus.id, MII_BUS_ID_SIZE, "%x", bp->pdev->id);
bp->mii_bus.priv = bp;
bp->mii_bus.dev = &bp->dev->dev;
pdata = bp->pdev->dev.platform_data;
if (pdata)
bp->mii_bus.phy_mask = pdata->phy_mask;
bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
if (!bp->mii_bus.irq) {
err = -ENOMEM;
goto err_out;
}
for (i = 0; i < PHY_MAX_ADDR; i++)
bp->mii_bus.irq[i] = PHY_POLL;
platform_set_drvdata(bp->dev, &bp->mii_bus);
Το πεδίο read είναι ένας δείκτης προς τη συνάρτηση macb_mdio_read η οποία
χρησιµοποιείται για την επικοινωνία µέσω του διαύλου MDIO. Κάτι παρόµοιο ισχύει
και για το πεδίο write, µε τη διαφορά ότι η συνάρτηση macb_mdio_write στην
οποία δείχνει, δεν γράφει στον δίαυλο MDIO. Η συνάρτηση snprintf αρχικοποιεί το
πεδίο id. Επίσης, ο δείκτης priv δείχνει στη δοµή macb προκειµένου να µπορούµε
να έχουµε πρόσβαση στις read και write. Τέλος, το πεδίο irq της δοµής mii_bus
θα πρέπει να αρχικοποιηθεί µε τέτοιο τρόπο ώστε να ενηµερώνει ολόκληρη την υποδοµή MDIO του Kernel ότι δεν θα χρησιµοποιούνται διακοπές µεταξύ του ολοκληρωµένου DP83848I και του Ethernet controller.
Καταχωρεί την mii_bus µέσω της συνάρτησης mdiobus_register. Αν εκτελεστεί
µε επιτυχία, ο δίαυλος MDIO θα ζητήσει το id του ολοκληρωµένου DP83848I και θα
εντοπίσει τον κατάλληλο οδηγό. Επειδή στην περίπτωσή µας δεν υπάρχει, θα χρησι-
Επικοινωνία: [email protected]
272
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
µοποιήσει τελικά τον γενικό οδηγό drivers/net/phy/phy_device.c ο οποίος
υποστηρίζει τις βασικές λειτουργίες (generic ή core driver).
Συναρτήσεις πρόσβασης του διαύλου MDIO
Αφού έχουµε καταφέρει να επικοινωνεί ο Ethernet controller του µικροελεγκτή AP7000 µε το
ολοκληρωµένο DP83848I, πρέπει να υλοποιήσουµε τις συναρτήσεις πρόσβασης στο δίαυλο
MDIO:
static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
struct macb *bp = bus->priv;
int value;
macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
| MACB_BF(RW, MACB_MAN_READ)
| MACB_BF(PHYA, mii_id)
| MACB_BF(REGA, regnum)
| MACB_BF(CODE, MACB_MAN_CODE)));
/* wait for end of transfer */
while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
cpu_relax();
value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
return value;
}
Οι εγγραφές και οι αναγνώσεις επιτυγχάνονται διαµέσου του καταχωρητή διαχείρισης φυσικού επιπέδου (PHY Maintenance Register) MACB_MAN: ο οποίος καθορίζεται και στο αρχείο
κεφαλίδας macb.h:
#define MACB_MAN
0x0034
Οι πληροφορίες κατάστασης του διαύλου MDIO παρέχονται από τον καταχωρητή κατάστασης δικτύου (Network Status Register) MACB_NSR:
#define MACB_NSR
0x0008
Φυσικά στο αρχείο macb.h θα πρέπει να γραφτούν όλες οι οδηγίες που αφορούν τους αντίστοιχους καταχωρητές του AP7000 που χρησιµοποιούνται στις δυο συναρτήσεις που παραθέσαµε.
Αφού όλα είναι στη θέση τους και µπορούµε πια να γράφουµε και να διαβάζουµε στον δίαυλο MDIO θα πρέπει να προχωρήσουµε στην κύρια αρχικοποίηση. Αυτό θα πρέπει να γίνει
και πάλι µέσα από την συνάρτηση mac_probe του οδηγού µας. Αρχικά ενεργοποιούµε το
ρολόι και καθορίζουµε το αν θα χρησιµοποιήσουµε σύνδεση RMII ή MII µε το ολοκληρωµένο
DP83848I. Αυτό γίνεται µέσω του καταχωρητή MACB_USRIO.
#define MACB_USRIO
0x00c0
Έπειτα καλούµε την συνάρτηση macb_mii_init την οποία αναφέραµε και νωρίτερα κατά
την αρχικοποίηση του διαύλου MDIO. Φυσικά, κατά την εκτέλεση του driver η συνάρτηση αυτή εκτελείται µία φορά και φέρει εις πέρας όλες τις λειτουργίες που της έχουµε αναθέσει.
Ιστότοπος εργασίας: MyThesis.org
273
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Η επιλογή για RMII ή MII γίνεται κυρίως βασιζόµενη στα δεδοµένα της πλατφόρµας του µικροελεγκτή που χρησιµοποιούµε κάθε φορά. Στην περίπτωσή µας είναι η AVR32. Τα δεδοµένα αυτά µεταφέρονται µε τη µορφή δοµής δεδοµένων στον οδηγό που αναπτύσσουµε. Η
δοµή αυτή είναι η macb_platform_data και την τοποθετούµε µέσα στη συνάρτηση
macb_probe:
struct eth_platform_data *pdata;
pdata = pdev->dev.platform_data;
Σε αυτό το σηµείο θέτουµε το bit, CLKEN του καταχωρητή MACB_USRIO και το bit RMII αν
το πεδίο is_rmii από τα δεδοµένα πλατφόρµας, είναι αληθές. Τέλος καλούµε τη συνάρτηση macb_mii_init.
Σύνδεση και επίβλεψη κατάστασης στο ολοκληρωµένο DP83848I
Εφόσον ο δίαυλος MDIO έχει πια αρχικοποιηθεί, είµαστε πλέον σε θέση να συνδεθούµε µε
το ολοκληρωµένο DP83848I. Αυτό θα µας επιτρέψει να ενηµερωνόµαστε για κάθε αλλαγή
που γίνεται. Οι αλλαγές συνήθως αφορούν την κατάσταση της γραµµής, δηλαδή αν είναι ενεργή ή αν δεν αποκρίνεται, αν η µετάδοση είναι ηµι-αµφίδροµη ή πλήρως αµφίδροµη, αν η
ταχύτητα µετάδοσης είναι 100 ή 1000 Mbps κλπ.
Για να πραγµατοποιήσουµε όλα αυτά θα πρέπει να εισάγουµε επιπλέον κώδικα στη συνάρτηση macb:
struct phy_device
unsigned int
unsigned int
unsigned int
*phy_dev;
link;
speed;
duplex;
Με τον παραπάνω κώδικα έχουµε καταφέρει να περάσουµε ένα δείκτη στη δοµή
phy_device που αναπαριστά το ολοκληρωµένο DP83848I το οποίο και θα αναζητήσουµε
µέσω της συνάρτησης macb_mii_probe µε τον κώδικα: που ακολουθεί:
/* find the first phy */
for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
if (bp->mii_bus.phy_map[phy_addr]) {
phydev = bp->mii_bus.phy_map[phy_addr];
break;
}
}
if (!phydev) {
printk (KERN_ERR "%s: no PHY found\n", dev->name);
return -1;
}
Η δοµή phy_device ορίζεται στο αρχείο include/linux/phy.h.
Συνδέουµε τον Ethernet controller του AP7000 µε το ολοκληρωµένο DP83848I: και περνάµε µια την κλήση macb_handle_link_change (callback) η οποία θα ενεργοποιείται όταν
αλλάζει η κατάσταση της γραµµής:
/* attach the mac to the phy */
if (pdata && pdata->is_rmii) {
phydev = phy_connect(dev, phydev->dev.bus_id,
Επικοινωνία: [email protected]
274
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
&macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
} else {
phydev = phy_connect(dev, phydev->dev.bus_id,
&macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
}
Ενηµερώνουµε την δοµή phy_device µέσω του δείκτη phydev για τα διαθέσιµα χαρακτηριστικά και τις λειτουργίες του DP83848I και αρχικοποιούµε τα πεδία speed και duplex µε
τις σωστές τιµές που αφορούν την περίπτωσή µας:
/* mask with MAC supported features */
phydev->supported &= PHY_BASIC_FEATURES;
phydev->advertising = phydev->supported;
bp->link = 0;
bp->speed = 0;
bp->duplex = -1;
bp->phy_dev = phydev;
Σε αυτό το σηµείο η συνάρτηση macb_mii_probe έχει ολοκληρωθεί και την καλούµε µέσω
της macb_mii_init:
if (macb_mii_probe(bp->dev) != 0) {
goto err_out_unregister_bus;
}
Το τελευταίο βήµα που πρέπει να κάνουµε για να επιτύχουµε την σύνδεση και την επίβλεψη
µε το ολοκληρωµένο DP83848I , το οποίο φροντίζει για τη διαµόρφωση της σύνδεσης στις
απαιτήσεις του πρωτοκόλλου Ethernet (802.3), είναι να υλοποιήσουµε τη συνάρτηση
macb_handle_link_change.
Η πρώτη περίπτωση που πρέπει να χειριστούµε µέσω του κώδικα της συνάρτησης αυτής
είναι η ενηµέρωση του καταχωρητή NCFGR αν η γραµµή είναι ενεργή. Για να ελέγξουµε αν
είναι ενεργή, ελέγχουµε αν οι phydev->link, phydev->speed και phydev->duplex έχουν διαφορετικές τιµές από αυτές που υπάρχουν στην δοµή macb.
if (phydev->link) {
if ((bp->speed != phydev->speed) ||
(bp->duplex != phydev->duplex)) {
u32 reg;
reg = macb_readl(bp, NCFGR);
reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
if (phydev->duplex)
reg |= MACB_BIT(FD);
if (phydev->speed == SPEED_100)
reg |= MACB_BIT(SPD);
macb_writel(bp, NCFGR, reg);
bp->speed = phydev->speed;
bp->duplex = phydev->duplex;
status_change = 1;
}
}
Ιστότοπος εργασίας: MyThesis.org
275
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
∆ιαφορετικά, απλά επαναφέρουµε (reset) τις τιµές των πεδίων speed και duplex έτσι ώστε όταν η γραµµή ενεργοποιηθεί, να πάρουν τις σωστές τιµές, απελευθερώνουµε το
spinlock µέσω της spin_unlock_irqrestore και ενηµερώνουµε τις πληροφορίες κατάστασης του Kernel:
if (phydev->link != bp->link) {
if (!phydev->link) {
bp->speed = 0;
bp->duplex = -1;
}
bp->link = phydev->link;
status_change = 1;
}
spin_unlock_irqrestore(&bp->lock, flags);
if (status_change) {
if (phydev->link)
printk(KERN_INFO "%s: link up (%d/%s)\n",
dev->name, phydev->speed,
DUPLEX_FULL == phydev->duplex ? "Full":"Half");
else
printk(KERN_INFO "%s: link down\n", dev->name);
}
∆έσµευση των DMA buffers, αρχικοποίηση και καθαρισµός
Σε αυτό το σηµείο γράφουµε τρεις βοηθητικές συναρτήσεις οι οποίες θα χρησιµοποιηθούν
αργότερα. Η πρώτη είναι η macb_alloc_consistent και χρησιµοποιείται για δέσµευση
DMA buffers, η δεύτερη είναι η macb_free_consistent που κάνει ακριβώς το αντίθετο και
η τρίτη είναι η macb_init_rings, η οποία αρχικοποιεί δακτυλίους DMA.
Αφού συµβουλευτούµε το datasheet του AP7000 σχετικά µε τη συνεργασία DMA και
Ethernet controller, δηµιουργούµε δύο δακτυλίους DMA, ο ένας για τους buffers µετάδοσης
και ο άλλος για τους buffers λήψης. Το µήκος ρους πρέπει να είναι 8 bytes. 4 για τη διεύθυνση του DMA buffer και 4 για τις διάφορες σηµαίες ελέγχου. Αυτό επιτυγχάνεται µε την παρακάτω δοµή η οποία προστίθεται στο αρχείο κεφαλίδας macb.h:
struct dma_desc {
u32
addr;
u32
ctrl;
};
Για την λήψη χρειάζεται επίσης να δεσµεύσουµε τους καταχωρητές DMA. Σύµφωνα µε το
datasheet το µέγεθός τους είναι 128 bytes, ενώ για τον δακτύλιο λήψης αποφασίζουµε στην
τύχη να έχει µήκος 512 bytes:
#define RX_BUFFER_SIZE
#define RX_RING_SIZE
128
512
Εποµένως το µέγεθος της µνήµης που πρέπει να δεσµευθεί είναι:
#define RX_RING_BYTES
Επικοινωνία: [email protected]
(sizeof(struct dma_desc) * RX_RING_SIZE)
276
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Για την µετάδοση, τα buffers θα δεσµευθούν από τον Kernel αφού γεµίζονται µέσω των εφαρµογών µε τα δεδοµένα που στέλνουν (payload):
#define TX_RING_SIZE
#define DEF_TX_RING_PENDING
#define TX_RING_BYTES
128
(TX_RING_SIZE - 1)
(sizeof(struct dma_desc) * TX_RING_SIZE)
Επειδή θέλουµε να ξέρουµε ποιο πακέτο αποστέλλεται κάθε φορά δηµιουργούµε στο αρχείο macb.h τη δοµή ring_info η οποία δεν αφορά το υλικό:
struct ring_info {
struct sk_buff
dma_addr_t
};
*skb;
mapping;
Με τη βοήθειά της ring_info θα υπολογίσουµε αργότερα και τη µεταβλητή size της συνάρτησης macb_alloc_consistent. Η δοµή sk_buff είναι ένας δείκτης προς το πακέτο
που µεταδίδεται και η dma_addr_t είναι η διεύθυνση DMA στην οποία βρισκόταν χαρτογραφηµένα τα περιεχόµενα του πακέτου πριν ξεκινήσει η µετάδοση.
Στη συνέχεια χρειαζόµαστε ορισµένα ακόµα πεδία τα οποία θα προσθέσουµε στην δοµή
macb. Οι τρεις µεταβλητές που ακολουθούν αποθηκεύουν τιµές που αφορούν την κίνηση
των δακτυλίων DMA:
unsigned int
tx_head, rx_tail, tx_tail;
Η δοµή dma_desc αφορά τα περιεχόµενα του δακτυλίου λήψης:
struct dma_desc
*rx_ring;
Ο δείκτης προς το πεδίο rx_buffers της δοµής ring_info, δείχνει στη διεύθυνση µνήµης που βρίσκονται οι ίδιοι οι δακτύλιοι λήψης:
void
*rx_buffers;
Οι διευθύνσεις DMA του δακτυλίου λήψης, του δακτυλίου αποστολής και των buffers λήψης
αντίστοιχα:
dma_addr_t
dma_addr_t
dma_addr_t
rx_ring_dma;
tx_ring_dma;
rx_buffers_dma;
Σε αυτό το σηµείο και αφού οι απαιτούµενες δοµές βρίσκονται στη θέσης τους, δηµιουργούµε τη συνάρτηση macb_alloc_consistent προκειµένου να δεσµεύσουµε τη µνήµη
που απαιτείται. Στον κώδικά της θα πραγµατοποιούνται ορισµένες δεσµεύσεις µνήµης:
Για τον πίνακα της δοµής ring_info µέσω της kmalloc (εφόσον οι πληροφορίες αυτές
δεν θα χρησιµοποιηθούν από τον Ethernet controller)
Για τους DMA descriptors (αποστολής και λήψης), αλλά και για τους DMA buffers,
µέσω της dma_alloc_coherent
Μετά από τις παραπάνω δεσµεύσεις µνήµης θα έχουν αποκτήσει τιµές τα πεδία της δοµής
macb, tx_skb, tx_ring, rx_ring, rx_buffers, rx_ring_dma, tx_ring_dma και
rx_buffers_dma.
Ιστότοπος εργασίας: MyThesis.org
277
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Παρόµοια γράφουµε και την macb_free_consistent που κάνει ακριβώς τις αντίθετες
ενέργειες χρησιµοποιώντας τις συναρτήσεις kfree και dma_free_coherent.
Τέλος, γράφουµε την macb_init_rings προκειµένου να αρχικοποιήσουµε τους δακτυλίους µε βάση το datasheet του AP7000.
Για τον δακτύλιο λήψης αρχικοποιούµε κάθε DMA descriptor me την διεύθυνση του αντίστοιχου buffer. Ο τελευταίος χαρακτηρίζεται από το γεγονός ότι το WRAP bit του πεδίου addr:
είναι ενεργοποιηµένο:
addr = bp->rx_buffers_dma;
for (i = 0; i < RX_RING_SIZE; i++) {
bp->rx_ring[i].addr = addr;
bp->rx_ring[i].ctrl = 0;
addr += RX_BUFFER_SIZE;
}
bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
Για τον δακτύλιο αποστολής αρχικοποιούµε όλες τις διευθύνσεις µε την τιµή µηδέν αφού δεν
υπάρχουν ακόµα πακέτα προς αποστολή. Επίσης ενεργοποιούµε το bit USED του πεδίου
ctrl για να υποδηλώσουµε ότι αυτοί οι descriptors ανήκουν στον AP7000. Οµοίως ενεργούµε
και για τους descriptors λήψης
for (i = 0; i < TX_RING_SIZE; i++) {
bp->tx_ring[i].addr = 0;
bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
}
bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
Ολοκληρώνουµε την συνάρτηση αρχικοποίησης των δακτυλίων DMA µε τον επανακαθορισµό (reset) των πεδίων tx_head, tx_tail και rx_tail:
bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
Reset και αρχικοποίηση υλικού
Για την αρχικοποίηση του υλικού χρειαζόµαστε να προστεθεί ένα σύνολο διευθύνσεων και
οδηγιών #define στο αρχείο macb.h:
#define
#define
#define
#define
#define
#define
#define
MACB_TSR
MACB_RBQP
MACB_TBQP
MACB_RSR
MACB_ISR
MACB_IER
MACB_IDR
0x0014
0x0018
0x001c
0x0020
0x0024
0x0028
0x002c
/*
/*
/*
/*
/*
/*
/*
Transmit Status Register */
Receive Buffer Queue Pointer */
Transmit Buffer Queue Pointer */
Reception Status Register */
Interrupt Status Register */
Interrupt Enable Register */
Interrupt Disable Register */
Επιπροσθέτως χρειάζονται και οι ακόλουθες οδηγίες:
Για τον καταχωρητή δικτυακής διαµόρφωσης (Network Configuration Register) θέλουµε τα ψηφία του να ενεργοποιούν την λήψη και την µετάδοση:
#define MACB_RE_OFFSET
#define MACB_TE_OFFSET
Επικοινωνία: [email protected]
2
3
278
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Για τον καταχωρητή ενεργοποίησης διακοπών (Interrupt Enable Register) θέλουµε τα
ψηφία του να ενεργοποιούν διακοπές κατά την ολοκλήρωση της αποστολής και της
λήψης:
#define MACB_RCOMP_OFFSET
#define MACB_TCOMP_OFFSET
1
7
Τώρα είµαστε σε θέση να γράψουµε την συνάρτηση macb_reset_hw η οποία θα φροντίζει
για το reset και την αρχικοποίηση του υλικού. Οι λειτουργίες της εξηγούνται στα σχόλια της
εσωτερικής τεκµηρίωσης της συνάρτησης:
static void macb_reset_hw(struct macb *bp)
{
/* Make sure we have the write buffer for ourselves */
wmb();
/*
* Disable RX and TX (XXX: Should we halt the transmission
* more gracefully?)
*/
macb_writel(bp, NCR, 0);
/* Clear the stats registers (XXX: Update stats first?) */
macb_writel(bp, NCR, MACB_BIT(CLRSTAT));
/* Clear all status flags */
macb_writel(bp, TSR, ~0UL);
macb_writel(bp, RSR, ~0UL);
/* Disable all interrupts */
macb_writel(bp, IDR, ~0UL);
macb_readl(bp, ISR);
}
Επίσης χρειαζόµαστε µια ακόµη συνάρτηση macb_init_hw:
static void macb_init_hw(struct macb *bp)
{
u32 config;
macb_reset_hw(bp);
__macb_set_hwaddr(bp);
config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L);
config |= MACB_BIT(PAE);
/* PAuse Enable */
config |= MACB_BIT(DRFCS);
/* Discard Rx FCS */
if (bp->dev->flags & IFF_PROMISC)
config |= MACB_BIT(CAF);
/* Copy All Frames */
if (!(bp->dev->flags & IFF_BROADCAST))
config |= MACB_BIT(NBC);
/* No BroadCast */
macb_writel(bp, NCFGR, config);
/* Initialize TX and RX buffers */
macb_writel(bp, RBQP, bp->rx_ring_dma);
macb_writel(bp, TBQP, bp->tx_ring_dma);
/* Enable TX and RX */
macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
Ιστότοπος εργασίας: MyThesis.org
279
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
/* Enable interrupts */
macb_writel(bp, IER, (MACB_BIT(RCOMP)
| MACB_BIT(RXUBR)
| MACB_BIT(ISR_TUND)
| MACB_BIT(ISR_RLE)
| MACB_BIT(TXERR)
| MACB_BIT(TCOMP)
| MACB_BIT(ISR_ROVR)
| MACB_BIT(HRESP)));
}
Οι συναρτήσεις που παραθέσαµε θα κληθούν αργότερα µέσα από τον κώδικα του οδηγού
δικτύου MACB, που αναπτύσσουµε.
Εκκίνηση και τερµατισµός λειτουργιών
Οι συναρτήσεις εκκίνησης και τερµατισµού µιας λειτουργίας καλούνται αντίστοιχα όταν κάποια διεπαφή δικτύου ενεργοποιείται ή απενεργοποιείται. Αυτό µπορεί να συµβεί για παράδειγµα, όταν καλούµε την εντολή ifconfig από την γραµµή εντολών στο επίπεδο
εφαρµογής του χρήστη.
Για την υλοποίηση των συναρτήσεων εκκίνησης και τερµατισµού, αρχικά δηµιουργούµε δύο
άδειες συναρτήσεις οι οποίες θα επιστρέφουν µια ακέραια τιµή και θα παίρνουν σαν όρισµα
έναν δείκτη dev προς τη δοµή net_device:
static int macb_open(struct net_device *dev)
{
return 0;
}
static int macb_close(struct net_device *dev)
{
return 0;
}
Στη συνέχεια τις προσθέτουµε στην συνάρτηση macb_probe:
dev->open = macb_open;
dev->stop = macb_close;
Τώρα είµαστε έτοιµοι να αναπτύξουµε τις συναρτήσεις εκκίνησης και τερµατισµού. Ας αρχίσουµε πρώτα να περιγράφουµε τα βήµατα που έγιναν για την ανάπτυξη της macb_open:
∆εσµεύουµε µνήµη µέσω της συνάρτησης macb_alloc_consistent για τους DMA
buffers
Αρχικοποιούµε τους DMA buffers µέσω της συνάρτησης macb_init_rings
Αρχικοποιούµε το υλικό µέσω της macb_init_hw
Εκκινούµε την επικοινωνία µε το ολοκληρωµένο DP83848I (PHY) µέσω της συνάρτησης phy_start ούτως ώστε να ελέγχουµε την κατάσταση της γραµµής:
/* schedule a link state check */
phy_start(bp->phy_dev);
Καλούµε την netif_start_queue προκειµένου να ενηµερώσουµε τον Kernel ότι η
διεπαφή δικτύου που δηµιουργήσαµε είναι έτοιµη να λάβει πακέτα:
Επικοινωνία: [email protected]
280
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
netif_start_queue(dev);
Ακριβώς την αντίστροφη διαδικασία υλοποιούµε στην συνάρτηση macb_close:
Καλούµε την netif_stop_queue για να ενηµερώσουµε τον Kernel ότι η διεπαφή
δικτύου που δηµιουργήσαµε δεν θα λαµβάνει πλέον πακέτα
∆ιακόπτουµε τη λειτουργία του µέσω της phy_stop
Κάνουµε reset µέσω της macb_reset_hw για να απενεργοποιήσουµε τις διακοπές
αλλά και οποιονδήποτε άλλο πόρο έχει δεσµευθεί
Τέλος αποδεσµεύουµε τους DMA buffers µέσω της macb_free_consistent
Κλείδωµα οδηγού
Για να διασφαλίσουµε ότι δεν υπάρχει ανεπιθύµητη πρόσβαση στα δεδοµένα που µεταφέρονται πρέπει να υλοποιήσουµε κάποια µέθοδο κλειδώµατος του οδηγού. Αυτό επιτυγχάνεται µε ένα απλό spinlock το οποίο υλοποιούµε µε την δηµιουργία του στιγµιότυπου lock της
δοµής spinlock_t, στο αρχείο macb.h:
spinlock_t
lock;
Η αρχικοποίηση του spinlock που δηµιουργήσαµε γίνεται µε µια κλήση της συνάρτησης
spin_lock_init την οποία εισάγουµε στην συνάρτηση macb_probe:
spin_lock_init(&bp->lock);
Στη συνέχεια θα πρέπει να χρησιµοποιήσουµε το spinlock που δηµιουργήσαµε στα παρακάτω σηµεία:
Στη συνάρτηση macb_handle_link_change µαζί µε την spin_lock_irqsave
και την spin_unlock_irqrestore για την αποφυγή ταυτόχρονης εκτέλεσης του
χειριστή διακοπών
Στη συνάρτηση netdrv_close, και πάλι µαζί µε την spin_lock_irqsave και την
spin_lock_irqrestore για την αποφυγή ταυτόχρονης εκτέλεσης των διακοπών
και της διαδικασίας τερµατισµού της διεπαφής δικτύου. Όλα αυτά πρέπει να γίνουν
πριν τον τερµατισµό της ουράς πακέτων και του ολοκληρωµένου DP83848I
Αποστολή πακέτων
Πριν την υλοποίηση της αποστολής πακέτων απαιτούνται κάποιες οδηγίες #define:
Το bit TSTART του καταχωρητή ρύθµισης δικτύου NCR (Network Configuration Register) µέσω του οποίου γίνεται η εκκίνηση της µετάδοσης των πακέτων που βρίσκονται
στην ουρά µετάδοσης (Transmission Queue):
#define MACB_TSTART_OFFSET
9
Το bit ολοκλήρωσης µετάδοσης, του καταχωρητή TSR (Transmit Status Register):
#define MACB_COMP_OFFSET
Ιστότοπος εργασίας: MyThesis.org
5
281
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Το bit µετάδοσης DMA που στην περίπτωσή µας συµβολίζει ότι κάθε πακέτο µεταδίδεται σε έναν δικό του DMA buffer:
#define MACB_TX_LAST_OFFSET
15
Μια µακροεντολή η οποία υπολογίζει τον αριθµό των buffers που βρίσκονται στην
ουρά για µετάδοση:
#define TX_BUFFS_AVAIL(bp)
(((bp)->tx_tail <= (bp)->tx_head) ?
(bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head :
(bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp))
\
\
\
Μια µακροεντολή η οποία παίρνει ως είσοδό ένα δείκτη που δείχνει σε κάποιο DMA
buffer που βρίσκεται στην ουρά και επιστρέφει έναν δείκτη που δείχνει στο επόµενο:
#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1))
Το σηµείο εκκίνησης µετάδοσης στον οδηγό µας, είναι η συνάρτηση macb_start_xmit.
Σε αυτή πρέπει να υλοποιήσουµε µια σειρά λειτουργιών που θα επιτυγχάνουν την µετάδοση
πακέτων. Η συνάρτηση αυτή θα χειρίζεται και θα ελέγχει την ουρά των DMA buffer descriptors η οποία µε τη σειρά της θα τροποποιείται από τον χειριστή διακοπών. Για το λόγο αυτό
είναι απαραίτητη η χρήση κλειδώµατος που υλοποιήσαµε νωρίτερα ώστε µόνο µία λειτουργία
να έχει πρόσβαση κάθε φορά στην ουρά. Εποµένως µπορούν να χρησιµοποιηθούν οι συναρτήσεις spin_lock_irq και spin_unlock_irq.
Από τη στιγµή που έχουµε δηµιουργήσει κάποιο κλείδωµα, το πρώτο πράγµα που πρέπει
να ελέγξουµε, είναι εάν υπάρχει έστω και ένας DMA buffer descriptor για την αποστολή πακέτου. Αυτό µπορεί να γίνει µέσω της µακροεντολής TX_BUFFS_AVAIL. Αν δεν υπάρχει θα
πρέπει να διακόψουµε την ουρά µέσω της συνάρτησης netif_stop_queue, να απελευθερώσουµε το κλείδωµα και να επιστρέψουµε την τιµή 1 ώστε ο Kernel να ενηµερωθεί για το
σφάλµα.
Αν υπάρχει έστω και ένας DMA buffer descriptor διαθέσιµος, ο επόµενος µπορεί να βρεθεί
από τον δείκτη tx_head ο οποίος βρίσκεται στη δοµή macb του αρχείου κεφαλής macb.h.
Το επόµενο βήµα είναι να χαρτογραφήσουµε το πακέτο ώστε να µπορεί να σταλθεί µέσω
DMA. Αυτό µπορεί να γίνει µε την συνάρτηση dma_map_single η οποία παίρνει σαν όρισµα έναν δείκτη προς τη δοµή net_device, την περιοχή µνήµης που θα χαρτογραφηθεί
(skb->data), το µήκος (skb->length) και την κατεύθυνση της µεταφοράς DMA (στην περίπτωσή µας DMA_TO_DEVICE). Η συνάρτηση επιστρέφει µια διεύθυνση DMA του τύπου
dma_addr_t.
Στη συνέχεια ενηµερώνουµε τον εσωτερικό πίνακα tx_skb µε τη διεύθυνση DMA και τον
δείκτη προς την SKB. Αυτό θα µας χρειαστεί κατά την ολοκλήρωση της µετάδοσης.
Σε αυτό το σηµείο ας υπολογίσουµε την τιµή του πεδίου ctrl του DMA buffer descriptor:
Θα πρέπει να περιέχει το µήκος των δεδοµένων που θα αποσταλούν skb->len
Το bit MACB_TX_LAST_OFFSET θα πρέπει να ενεργοποιηθεί αφού όλα µας τα πακέτα θα στέλνονται σε ένα απλό buffer
Αν το buffer που χρησιµοποιούµε είναι το τελευταίο της ουράς, δηλαδή αν η τιµή του
tx_head είναι ίση µε την τιµή TX_RING_SIZE – 1, τότε αντίστοιχα, και το bit
MACB_TX_WRAP_OFFSET θα πρέπει να ενεργοποιηθεί
Επικοινωνία: [email protected]
282
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Έπειτα αρχικοποιούµε και το πεδίο addr της δοµής ring_info µε την διεύθυνση DMA
του DMA descriptor που βρήκαµε πιο πριν. Επίσης, αρχικοποιούµε το πεδίο ctrl της ίδιας
δοµής µε την τιµή που βρήκαµε νωρίτερα. Για να εµποδίσουµε την αλλαγή της σειράς αυτών
των εγγραφών µε την εγγραφή που θα εκκινήσει τη µετάδοση, τοποθετούµε ένα όριο εγγραφής µνήµης wmb(); (write memory barrier) µετά την ενεργοποίηση του DMA buffer descriptor.
Το επόµενο βήµα είναι να ενηµερώσουµε την tx_head µε το επόµενο διαθέσιµο buffer το
οποίο βρίσκεται στην ουρά προς µετάδοση. Για το σκοπό αυτό χρησιµοποιούµε την µακροεντολή NEXT_TX.
Αφού έχουν ολοκληρωθεί όλα τα παραπάνω, είµαστε έτοιµοι να εκκινήσουµε την πραγµατική µετάδοση ενεργοποιώντας το bit TSTART του καταχωρητή NCR:
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
Πριν το κλείσιµο της συνάρτησης macb_start_xmit θα πρέπει να ενηµερώσουµε τον
Kernel για το αν έχουµε άλλους DMA buffer descriptors να λάβουµε. Αν ισχύει κάτι τέτοιο, θα
πρέπει να χρησιµοποιήσουµε τη συνάρτηση netif_stop_queue:
if (TX_BUFFS_AVAIL(bp) < 1)
netif_stop_queue(dev);
Τέλος, θα πρέπει να προβούµε σε κάποιες τυπικές διαδικασίες οι οποίες φαίνονται και στον
κώδικα που ακολουθεί:
spin_unlock_irq(&bp->lock);
dev->trans_start = jiffies;
return 0;
Ολοκλήρωση της αποστολής
Η ολοκλήρωση της µετάδοσης θα επισηµαίνεται συνήθως µέσω κάποιας διακοπής. Εποµένως όταν προκύπτει µια διακοπή ελέγχουµε αν οφείλεται σε ολοκλήρωση κάποιας µετάδοσης. Αν συµβαίνει κάτι τέτοιο, απελευθερώνουµε τον DMA buffer που η είχαµε
χαρτογραφήσει γι’ αυτή την µετάδοση έτσι ώστε να είναι πλέον ξανά διαθέσιµος προς χρήση.
Επίσης, ενηµερώνουµε τον Kernel ότι είµαστε και πάλι έτοιµοι για µια νέα µετάδοση αν χρειαστεί.
Εποµένως το πρώτο πράγµα που κάνουµε είναι να χρησιµοποιήσουµε τη συνάρτηση
macb_interrupt. Αρχικά εξετάζουµε αν η διακοπή προέκυψε από τη συσκευή µας διαβάζοντας τον καταχωρητή διακοπών MACB_ISR (Interrupt Status Register) και αν είναι µηδέν
τότε απλά επιστρέφουµε στον Kernel την τιµή IRQ_NONE:
status = macb_readl(bp, ISR);
if (unlikely(!status))
return IRQ_NONE;
Ιστότοπος εργασίας: MyThesis.org
283
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
Σε διαφορετική περίπτωση, δηµιουργούµε ένα spinlock ούτως ώστε να αποτρέψουµε την
ταυτόχρονη πρόσβαση στον κώδικα που χειρίζεται τη διακοπή που προέκυψε. Αυτό γίνεται
µέσω των συναρτήσεων spin_lock και spin_unlock.
Έπειτα θα πρέπει να δηµιουργήσουµε ένα βρόχο ο οποίος να εκτελείται µέχρι ο καταχωρητής MACB_ISR να πάρει την τιµή µηδέν. Ο καταχωρητής αυτός µετά από κάθε ανάγνωση
που του γίνεται, παίρνει την τιµή µηδέν. Αυτό σηµαίνει ότι δε χρειάζεται κάθε φορά να εκτελούµε εµείς αυτό τον µηδενισµό αλλά ταυτόχρονα σηµαίνει ότι πρέπει να αποθηκεύουµε και
να χρησιµοποιούµε την αρχική τιµή που είχε ο καταχωρητής πριν συµβεί η διακοπή και η ανάγνωση από τον χειριστή διακοπών.
Επίσης, µέσα στο βρόχο χρειάζεται να ελέγχουµε µέσω της µακροεντολής MACB_BIT αν το
bit TCOMP του καταχωρητή IER είναι ενεργοποιηµένο γιατί αυτό είναι που σηµατοδοτεί και
την ολοκλήρωση µιας µετάδοσης. Αν ισχύει κάτι τέτοιο τότε καλούµε την συνάρτηση
macb_tx για να αναλάβει τον τερµατισµό της µετάδοσης αυτής:
if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND)))
macb_tx(bp);
Η υλοποίηση της συνάρτησης macb_tx αφορά την ικανοποίηση των παρακάτω λειτουργιών:
Επιβεβαίωση της ολοκλήρωσης µιας µετάδοσης µέσω του καταχωρητή TSR:
Ανάγνωση του καταχωρητή MACB_TSR και εγγραφή της τιµής που διαβάστηκε:
status = macb_readl(bp, TSR);
macb_writel(bp, TSR, status);
Έλεγχος του bit UND του καταχωρητή TSR για κατάσταση buffer underrun:
if (status & MACB_BIT(UND))
. . .
Έλεγχος όλων των DMA buffer descriptors. από την κεφαλή (head) µέχρι την ουρά
τους (tail). Για τον υπολογισµό της θέσης του κάθε επόµενου DMA descriptor χρησιµοποιούµε την NEXT_TX. Για κάθε descriptor κάνουµε τα εξής:
Χρησιµοποιούµε ένα εµπόδιο ανάγνωσης µνήµης (memory read barrier) ώστε
να εξασφαλίσουµε ότι αυτό που θα διαβάσουµε είναι αυτό που η συσκευή τοποθέτησε στον DMA descriptor:
rmb();
Ελέγχουµε το bit TX_USED του DMA descriptor. Αν δεν είναι ενεργοποιηµένο
θα πρέπει να διακόψουµε τον βρόχο ελέγχου των DMA descriptors γιατί σηµαίνει ότι εντοπίσαµε έναν DMA descriptor του οποίου η µετάδοση δεν έχει
ολοκληρωθεί ακόµα:
if (!(bufstat & MACB_BIT(TX_USED)))
break;
Επικοινωνία: [email protected]
284
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
Αποχαρτογραφούµε, απελευθερώνουµε και επανακαθορίζουµε τον δείκτη SKB
ενώ ταυτόχρονα ενηµερώνουµε και κάποια στατιστικά στοιχεία της δοµής
macb:
dev_dbg(&bp->pdev->dev, "skb %u (data %p) TX complete\n",
tail, skb->data);
dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
DMA_TO_DEVICE);
bp->stats.tx_packets++;
bp->stats.tx_bytes += skb->len;
rp->skb = NULL;
dev_kfree_skb_irq(skb);
Ενηµέρωση της tx_tail ώστε να δείχνει στον επόµενο DMA descriptor που θα αναλυθεί στην επόµενη διακοπή ολοκλήρωσης κάποιας µετάδοσης
bp->tx_tail = tail;
Τελικά εάν η ουρά έχει σταµατήσει και εφόσον έχουµε αρκετούς διαθέσιµους buffers
αποστολής, ενηµερώνουµε τον Kernel µέσω της συνάρτησης netif_wake_queue
για να αρχίσει νέα αποστολή:
if (netif_queue_stopped(bp->dev) &&
TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH)
netif_wake_queue(bp->dev);
Με την ολοκλήρωση της διαδικασίας ολοκλήρωσης µετάδοσης µπορούµε µέσω του Wireshark και ενώ κάνουµε ping από τον υπολογιστή host προς το ενσωµατωµένο σύστηµα
Linux που αναπτύσσουµε, να δούµε τις αιτήσεις ARP που θα προέρχονται από αυτό. Φυσικά
επειδή ακόµη δεν έχουµε ολοκληρώσει την διαδικασία ολοκλήρωσης λήψης, τα αιτήµατα ping
θα λήξουν.
Λήψη πακέτων
Το τελευταίο κοµµάτι του οδηγού δικτύου που αναπτύσσουµε είναι η υλοποίηση της λειτουργίας λήψης πακέτων η οποία και σε αυτή την περίπτωση γίνεται αντιληπτή από µία διακοπή. Εποµένως στον χειριστή διακοπών θα πρέπει να προσθέσουµε µια κλήση προς τη
συνάρτηση rx_macb. Η συνάρτηση αυτή, ελέγχει τους DMA descriptors και βρίσκει τα εύρη
αυτών που αντιστοιχούν σε κάποιο πακέτο. Για κάθε τέτοιο εύρος καλείται η συνάρτηση παραλαβής πλαισίου macb_rx_frame.
Σε αυτό το σηµείο θα πρέπει να τονίσουµε µια διαφορά που υπάρχει µεταξύ της αποστολής
και της λήψης πακέτων. Κατά τη µετάδοση κάθε πακέτο στέλνεται αποκλειστικά µέσω ενός
DMA buffer και ενός descriptor. Ενώ στη λήψη οι DMA buffers έχουν το όριο των 128 bytes
µε αποτέλεσµα για την λήψη ενός και µόνο πακέτου να χρειάζονται συνήθως πολλαπλοί
buffers.
Συνεχίζοντας θα ασχοληθούµε µε τις επιπλέον οδηγίες και µακροεντολές που θα πρέπει να
προστεθούν στο αρχείο macb.h και macb.c έτσι ώστε να µπορούµε να λαµβάνουµε πακέτα:
Οδηγίες για τους DMA buffer descriptors
Το bit MACB_RX_USED_OFFSET παίρνει από την συσκευή, την τιµή 1 στο πεδίο διεύθυνσης του DMA descriptor, όταν το DMA buffer γεµίσει µε δεδοµένα
Ιστότοπος εργασίας: MyThesis.org
285
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
#define MACB_RX_USED_OFFSET
0
Το bit MACB_RX_SOF_OFFSET παίρνει από την συσκευή την τιµή 1 στο πεδίο ελέγχου του DMA descriptor, όταν τα δεδοµένα του DMA buffer αποτελούν την αρχή ενός
πακέτου (SOF – Start Of Frame):
#define MACB_RX_SOF_OFFSET
14
Το bit MACB_RX_EOF_OFFSET παίρνει από την συσκευή την τιµή 1 στο πεδίο ελέγχου του DMA descriptor, όταν τα δεδοµένα του DMA buffer αποτελούν το τέλος ενός
πακέτου (EOF – End Of Frame):
#define MACB_RX_EOF_OFFSET
15
Καθώς η κεφαλίδα Ethernet έχει µήκος 14 bytes και για λόγους απόδοσης, είναι καλό
να την ευθυγραµµίζουµε (word aligned). Αυτό γίνεται προσθέτοντας δύο επιπλέον
byte σε κάθε πακέτο και µετακινώντας έτσι την κεφαλίδα κατά δύο bytes επίσης:
#define MACB_RX_OFFSET_SIZE
2
Η µακροεντολή NEXT_RX που είναι η αντίστοιχη της NEXT_TX για την αποστολή πακέτων:
#define NEXT_RX(n)
(((n) + 1) & (RX_RING_SIZE - 1))
Αφού φροντίσουµε για όλα τα παραπάνω προσθέτουµε κώδικά στον χειριστή διακοπών
ούτως ώστε µετά από τον έλεγχο που κάνει για την ολοκλήρωση κάποιας µετάδοσης, να κάνει το ίδιο και για την ολοκλήρωση λήψης (µέσω του bit MACB_RCOMP_OFFSET) και στη συνέχεια καλούµε την συνάρτηση macb_rx.
Στη συνάρτηση macb_rx προσπελαύνουµε µε τη σειρά όλους τους DMA descriptors ξεκινώντας από την ουρά λήψης (rx_tail) και εκτελούµε τις παρακάτω ενέργειες:
Καλούµε την rmb() ώστε να εξασφαλίσουµε ότι η ανάγνωσή µας θα είναι έγκυρη
Αν το bit MACB_RX_USED_OFFSET στον τρέχον DMA descriptor δεν είναι ενεργοποιηµένο τότε σηµαίνει ότι έχουµε φτάσει στο τελευταίο DMA buffer που λήφθηκε και εποµένως µπορούµε να διακόψουµε την επανάληψη
Αν το bit MACB_RX_SOF_OFFSET είναι ενεργοποιηµένο στο πεδίο ελέγχου (ctrl)
του τρέχοντος DMA descriptor, τότε αυτός περιέχει την αρχή ενός πακέτου. Εποµένως αποθηκεύουµε τον δείκτη του descriptor σε µια µεταβλητή ώστε να θυµόµαστε
ότι είναι ο πρώτος DMA buffer descriptor του τρέχοντος πακέτου.
Αν το bit MACB_RX_EOF_OFFSET είναι ενεργοποιηµένο στο πεδίο ελέγχου του τρέχοντος DMA descriptor, τότε το τρέχον buffer είναι το τέλος του τρέχοντος πακέτου. Εποµένως τώρα έχουµε τον δείκτη της αρχής του πακέτου που βρήκαµε πριν και τον
δείκτη του τέλους του πακέτου. Με αυτές τις δύο πληροφορίες είµαστε σε θέση να καλέσουµε τη συνάρτηση macb_rx_frame η οποία θα χειριστεί τη λήψη ενός ολόκληρου πακέτου. Επίσης µετά το βρόχο θα πρέπει να ενηµερώσουµε την rx_tail.
Κλείνοντας την ανάλυση του οδηγού δικτύου MACB θα εξετάσουµε την συνάρτηση
macb_rx_frame. Αυτή η συνάρτηση είναι υπεύθυνη για τη δέσµευση ενός SKB από την
Επικοινωνία: [email protected]
286
Τεκµηρίωση ανάπτυξης του οδηγού δικτύου MACB – Παράρτηµα Β
στοίβα δικτύου (TCP/IP) για το γέµισµά της µε δεδοµένα και την αποστολή της προς ανάλυση και πάλι από τη στοίβα δικτύου.
Στην αρχή της συνάρτησης υπολογίζουµε το µέγεθος του πακέτου που παραλαµβάνεται. Το
µήκος αυτό αποθηκεύεται στα 11 χαµηλότερης τάξεως bits του πεδίου ελέγχου του τελευταίου DMA descriptor που περιέχει το πακέτο.
Στη συνέχεια ζητάµε από τον Kernel να δεσµεύσει µια SKB χρησιµοποιώντας την συνάρτηση dev_alloc_skb. Η συνάρτηση αυτή παίρνει ως όρισµα ένα µήκος το οποίο πρέπει να
είναι το µήκος του πακέτου που παραλήφθηκε συν το RX_OFFSET που χρησιµοποιείται για
την ευθυγράµµιση (σε bytes) που αναφέραµε και νωρίτερα. Φυσικά πρέπει να κάνουµε και
έναν έλεγχο για το αν η δέσµευση ήταν επιτυχής. Αν δεν ήταν επιτυχής το πακέτο απλά απορρίπτεται. Μετά από ένα τέτοιο συµβάν θα πρέπει να χαρακτηρίσουµε τους DMA descriptors του πακέτου αυτού ως ελεύθερους θέτοντας σε µηδέν το bit MACB_RX_USED_OFFSET
από το πεδίο της διεύθυνσης.
Σε αυτό το σηµείο πρέπει να διαµορφώσουµε τo SKB ενηµερώνοντας τον Kernel για τα εξής:
Τα δύο πρώτα bytes του πακέτου πρέπει να αγνοηθούν:
skb_reserve(skb, RX_OFFSET)
∆εν έχει γίνει κάποιος έλεγχος checksum στα πακέτα:
skb->ip_summed = CHECKSUM_NONE;
Μέσω της συνάρτησης skb_put και µε παράµετρο το µήκος του πακέτου, ότι τα πακέτα θα τοποθετηθούν στο SKB:
skb_put(skb, len);
Αφού το SKB έχει διαµορφωθεί θα πρέπει να χειριστούµε όλους τους DMA buffers που περιέχουν τα πακέτα µας και να πραγµατοποιήσουµε σε καθέναν τους, τις παρακάτω ενέργειες:
Να υπολογίσουµε το µήκος των δεδοµένων που περιλαµβάνουν. Συνήθως το µήκος
αυτό ισούται µε το µέγεθος του buffer RX_BUFFER_SIZE (εκτός από το τελευταίο):
unsigned int frag_len = RX_BUFFER_SIZE
if (offset + frag_len > len) {
BUG_ON(frag != last_frag);
frag_len = len - offset;
}
Να αντιγράψουµε τα δεδοµένα από τον DMA buffer στο SKB χρησιµοποιώντας τη συνάρτηση skb_copy_to_linear_data_offset. Τα ορίσµατα της συνάρτησης αυτής είναι ο δείκτης SKB, το εύρος του SKB στο οποίο τα δεδοµένα θα αντιγραφούν, η
διεύθυνση µνήµης από την οποία θα αντιγραφούν τα δεδοµένα και το µήκος των δεδοµένων που θα αντιγραφούν:
skb_copy_to_linear_data_offset(skb, offset,
(bp->rx_buffers +
(RX_BUFFER_SIZE * frag)),
Ιστότοπος εργασίας: MyThesis.org
287
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
frag_len);
Να θέσουµε σε µηδέν την τιµή του bit MACB_RX_USED_OFFSET του DMA descriptor
ώστε να φαίνεται και πάλι διαθέσιµος για µελλοντικές λήψεις πακέτων:
bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
Στο τέλος της συνάρτησης macb_rx_frame βρίσκουµε το πρωτόκολλο του πακέτου που
λήφθηκε και το αποθηκεύουµε στο SKB:
skb->protocol = eth_type_trans(skb, bp->dev);
Αµέσως µετά ενηµερώνουµε τα στατιστικά της δοµής macb αποστέλλουµε στον Kernel το
πακέτο που λάβαµε χρησιµοποιώντας τη συνάρτηση netif_receive_skb:
bp->stats.rx_packets++;
bp->stats.rx_bytes += len;
bp->dev->last_rx = jiffies;
dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n",
skb->len, skb->csum);
netif_receive_skb(skb);
Σε αυτό το σηµείο η ανάπτυξη του οδηγού δικτύου MACB έχει ολοκληρωθεί και ο Ethernet
controller του µικροελεγκτή AP7000 είναι σε θέση να επικοινωνεί µε τον Kernel αλλά και µε
το ολοκληρωµένο DP83848I που παίζει το ρόλο του Ethernet PHY. Έτσι ο Router NGW100
είναι πια σε θέση να ανταλλάσσει πληροφορίες µε το δίκτυο δροµολογώντας ταυτόχρονα τα
πακέτα των υπολογιστικών συστηµάτων που βρίσκονται συνδεδεµένα σε αυτόν.
Επικοινωνία: [email protected]
288
ΠΑΡΑΡΤΗΜΑ
C
Το πακέτο RBSP
και o ιστότοπος
MyThesis.org
Εισαγωγή
Καθ’ όλη τη διάρκεια συγγραφής αυτής της εργασίας αποκόµισα κάποια γνώση και εµπειρία
την οποία νιώθω την ανάγκη να εµπλουτίσω ακόµα περισσότερο και να την µοιραστώ µε όσους ενδιαφέρονται για το ίδιο αντικείµενο. Έτσι δηµιούργησα τον ιστότοπο Mythesis.org.
Ο ιστότοπος MyThesis.org
Στο MyThesis.org θα υπάρχει διαθέσιµο όλο το υλικό της παρούσας εργασίας αλλά και
επιπλέον χρήσιµο περιεχόµενο που δεν ήταν δυνατόν να παρατεθεί εδώ. Από εκεί θα είναι
δυνατόν να προσκοµιστεί (download) και το πακέτο υποστήριξης, RBSP.
Το πακέτο υποστήριξης RBSP
Το πακέτο υποστήριξης RBSP (Rousis BSB), είναι το αποτέλεσµα της τροποποίησης και
προσαρµογής του πακέτου Atmel Linux BSP 3.0 ειδικά για τον Router NGW100, αλλά και
της προσθήκης επιπλέον χρήσιµων εργαλείων και λογισµικού. Περιλαµβάνει τα εξής:
Το αρχείο AVR32_Linux_BSP_reduced_Image_3.0.0.iso
Το λογισµικό Vmware Player
Αρχείο εικόνας iso της διανοµής Ubuntu 9.04
Τα αρχεία rousis_buildroot.tar.gz, rousis_toolchain.tar.gz και installer.sh
Datasheets που αφορούν το υλικό του Router NGW100
Αρχεία CAD του PCB του Router NGW100
Το πακέτο RBSP είναι ένας οπτικός δίσκος DVD µε γραφικό περιβάλλον (menu) το οποίο
είναι πολύ φιλικό προς το χρήστη. Παρέχει εύκολη πρόσβαση στο διαθέσιµο περιεχόµενο
καθώς και ορισµένες πληροφορίες για τη χρησιµότητα του κάθε στοιχείου. Ουσιαστικά αποτελεί µια offline έκδοση του ιστότοπου MyThesis.org.
Ιστότοπος εργασίας: MyThesis.org
289
∆ηµήτριος Α. Ρούσης – Υλοποίηση δροµολογητη (Router Implementation)
ΒΙΒΛΙΟΓΡΑΦΙΑ
[1]. Christopher Hallinan, “Embedded Linux Primer: A Practical Real-World Approach (2nd
Edition)”, Prentice Hall, 2010.
[2]. Robert Love, “Linux Kernel Development (3rd Edition)”, Pearson education, 2010.
[3]. Daniel P. Bovet, Marco Cesati, “Understanding the Linux Kernel, Third Edition”, O'Reilly,
2005.
[4]. Michael Kerrisk, “The Linux Programming Interface: A Linux and UNIX System Programming Handbook”, No Starch Press, 2010.
[5]. Sreekrishnan Venkateswaran, “Essential Linux Device Drivers”, Prentice Hall, 2008.
[6]. Christian Benvenuti, “Understanding Linux Network Internals”, O'Reilly, 2006.
[7]. Cameron Newham, “Learning the bash Shell: Unix Shell Programming (Third Edition)”,
O'Reilly, 2005.
[8]. Richard Blum, “Linux Command Line and Shell Scripting Bible, Second Edition”, Wiley
Publishing Inc., 2011.
[9]. www.atmel.com. Επίσηµη ιστοσελίδα της εταιρείας Atmel.
[10]. www.avrfreaks.net. Η µεγαλύτερη κοινότητα γύρω από τους µικροελεγκτές AVR της εταιρείας Atmel.
Επικοινωνία: [email protected]
290
Ονοµάζοµαι ∆ηµήτριος Ρούσης και είµαι απόφοιτος του τµήµατος Πληροφορικής και Τεχνολογίας Υπολογιστών του ΑΤΕΙ ∆υτικής Μακεδονίας. Αγαπώ την επιστήµη των υπολογιστών
και µε ενδιαφέρουν ταυτόχρονα τόσο το λογισµικό όσο και το υλικό. Πιστεύω ότι αυτά τα δύο
είναι αλληλένδετα. Όπως η σκέψη και το σώµα.
Τα τελευταία χρόνια ασχολούµαι µε την ανάπτυξη ενσωµατωµένων συστηµάτων Linux. Πρόκειται για ένα άκρως απαιτητικό αντικείµενο µε απεριόριστες δυνατότητες.
Κατά τη διάρκεια της φοίτησής µου δεν περιορίστηκα µόνο στο πρόγραµµα σπουδών της
σχολής. Προσπάθησα να αποκοµίσω γνώσεις που αφορούν πραγµατικές ανάγκες και έχουν
άµεσο πρακτικό αποτέλεσµα. Οι κυριότερες εξ’ αυτών είναι:
Γλώσσες προγραµµατισµού: C, VB.NET, PHP, MYSQL, JAVASCRIPT, HTML
Ανάπτυξη ενσωµατωµένων συστηµάτων µε µικροελεγκτή 8 ή 32 bit
Ανάπτυξη ιστοσελίδων µε CMS: Joomla, Drupal, Blogger
Βελτιστοποίηση ιστότοπων για τις µηχανές αναζήτησης (SEO)
Εγκατάσταση και παραµετροποίηση λειτουργικών συστηµάτων
Εγκατάσταση και παραµετροποίηση συστηµάτων βιντεοεπιτήρησης IP (CCTV)
Εγκατάσταση και παραµετροποίηση ηλεκτρονικών επιγραφών LED
Ανάπτυξη installer εφαρµογής και συστήµατος Internet update
Ανάπτυξη αλληλεπιδραστικής διαφηµιστικής παρουσίασης (CD,DVD ή USB stick)
Ανάπτυξη τεκµηρίωσης (documentation, wikis, video tutorials κλπ)
Προβολή προϊόντων µέσω κοινωνικών δικτύων
Επίσης µελέτησα αρκετά την αγορά της υψηλής τεχνολογίας σε παγκόσµιο επίπεδο και προσπάθησα να διδαχθώ και να παραδειγµατιστώ από τους καλύτερους. Σε αυτό µου το εγχείρηµα κύριο ρόλο έπαιξε το ∆ιαδίκτυο.
Άµεση επικοινωνία: 693 204 16 96