Robin Thoni 8 years ago
commit
fa7e29d0b4
100 changed files with 12525 additions and 0 deletions
  1. 12
    0
      COPYING
  2. 339
    0
      COPYING.GPLv2
  3. 59
    0
      COPYING.UBDL
  4. 8
    0
      README
  5. 9
    0
      contrib/README
  6. 1
    0
      contrib/errdb/.gitignore
  7. 109
    0
      contrib/errdb/errdb.pl
  8. 62
    0
      contrib/rom-o-matic/README
  9. 62
    0
      contrib/rom-o-matic/bottom.php
  10. 311
    0
      contrib/rom-o-matic/build.php
  11. 69
    0
      contrib/rom-o-matic/customize-flags.php
  12. 63
    0
      contrib/rom-o-matic/directions.php
  13. 1
    0
      contrib/rom-o-matic/doc/AUTOBOOT_CMD.html
  14. 1
    0
      contrib/rom-o-matic/doc/BANNER_TIMEOUT.html
  15. 3
    0
      contrib/rom-o-matic/doc/COMCONSOLE.html
  16. 1
    0
      contrib/rom-o-matic/doc/COMDATA.html
  17. 1
    0
      contrib/rom-o-matic/doc/COMPARITY.html
  18. 1
    0
      contrib/rom-o-matic/doc/COMPRESERVE.html
  19. 1
    0
      contrib/rom-o-matic/doc/COMSPEED.html
  20. 1
    0
      contrib/rom-o-matic/doc/COMSTOP.html
  21. 1
    0
      contrib/rom-o-matic/doc/CONFIG_CMD.html
  22. 1
    0
      contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html
  23. 1
    0
      contrib/rom-o-matic/doc/CONSOLE_SERIAL.html
  24. 1
    0
      contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html
  25. 1
    0
      contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html
  26. 1
    0
      contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html
  27. 1
    0
      contrib/rom-o-matic/doc/DHCP_CMD.html
  28. 1
    0
      contrib/rom-o-matic/doc/DNS_RESOLVER.html
  29. 1
    0
      contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html
  30. 1
    0
      contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html
  31. 1
    0
      contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html
  32. 1
    0
      contrib/rom-o-matic/doc/IFMGMT_CMD.html
  33. 1
    0
      contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html
  34. 1
    0
      contrib/rom-o-matic/doc/IMAGE_CMD.html
  35. 1
    0
      contrib/rom-o-matic/doc/IMAGE_ELF.html
  36. 1
    0
      contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html
  37. 1
    0
      contrib/rom-o-matic/doc/IMAGE_NBI.html
  38. 1
    0
      contrib/rom-o-matic/doc/IMAGE_PXE.html
  39. 1
    0
      contrib/rom-o-matic/doc/IMAGE_SCRIPT.html
  40. 1
    0
      contrib/rom-o-matic/doc/IWMGMT_CMD.html
  41. 1
    0
      contrib/rom-o-matic/doc/NMB_RESOLVER.html
  42. 1
    0
      contrib/rom-o-matic/doc/NVO_CMD.html
  43. 1
    0
      contrib/rom-o-matic/doc/ROUTE_CMD.html
  44. 1
    0
      contrib/rom-o-matic/doc/SANBOOT_CMD.html
  45. 531
    0
      contrib/rom-o-matic/flag-table.php
  46. 51
    0
      contrib/rom-o-matic/globals.php
  47. 47
    0
      contrib/rom-o-matic/index.php
  48. 41
    0
      contrib/rom-o-matic/top.php
  49. 684
    0
      contrib/rom-o-matic/utils.php
  50. 6
    0
      contrib/vm/.gitignore
  51. 7
    0
      contrib/vm/Makefile
  52. 15
    0
      contrib/vm/bochs-writable-ROM-patch
  53. 1131
    0
      contrib/vm/bochsrc.txt
  54. 49
    0
      contrib/vm/cow
  55. 278
    0
      contrib/vm/serial-console
  56. 190
    0
      contrib/vm/serial-console.1
  57. 4
    0
      src/.gitignore
  58. 211
    0
      src/Makefile
  59. 1485
    0
      src/Makefile.housekeeping
  60. 128
    0
      src/arch/i386/Makefile
  61. 18
    0
      src/arch/i386/Makefile.efi
  62. 6
    0
      src/arch/i386/Makefile.linux
  63. 101
    0
      src/arch/i386/Makefile.pcbios
  64. 197
    0
      src/arch/i386/README.i386
  65. 37
    0
      src/arch/i386/core/basemem_packet.c
  66. 175
    0
      src/arch/i386/core/cachedhcp.c
  67. 23
    0
      src/arch/i386/core/dumpregs.c
  68. 140
    0
      src/arch/i386/core/gdbidt.S
  69. 184
    0
      src/arch/i386/core/gdbmach.c
  70. 45
    0
      src/arch/i386/core/linux/linux_syscall.S
  71. 28
    0
      src/arch/i386/core/linux/linuxprefix.S
  72. 51
    0
      src/arch/i386/core/nulltrap.c
  73. 42
    0
      src/arch/i386/core/patch_cf.S
  74. 48
    0
      src/arch/i386/core/pci_autoboot.c
  75. 94
    0
      src/arch/i386/core/rdtsc_timer.c
  76. 138
    0
      src/arch/i386/core/relocate.c
  77. 269
    0
      src/arch/i386/core/runtime.c
  78. 64
    0
      src/arch/i386/core/setjmp.S
  79. 15
    0
      src/arch/i386/core/stack.S
  80. 15
    0
      src/arch/i386/core/stack16.S
  81. 113
    0
      src/arch/i386/core/video_subr.c
  82. 145
    0
      src/arch/i386/core/virtaddr.S
  83. 146
    0
      src/arch/i386/drivers/net/undi.c
  84. 87
    0
      src/arch/i386/drivers/net/undiisr.S
  85. 184
    0
      src/arch/i386/drivers/net/undiload.c
  86. 822
    0
      src/arch/i386/drivers/net/undinet.c
  87. 142
    0
      src/arch/i386/drivers/net/undionly.c
  88. 42
    0
      src/arch/i386/drivers/net/undipreload.c
  89. 235
    0
      src/arch/i386/drivers/net/undirom.c
  90. 51
    0
      src/arch/i386/firmware/pcbios/basemem.c
  91. 566
    0
      src/arch/i386/firmware/pcbios/bios_console.c
  92. 589
    0
      src/arch/i386/firmware/pcbios/e820mangler.S
  93. 98
    0
      src/arch/i386/firmware/pcbios/fakee820.c
  94. 235
    0
      src/arch/i386/firmware/pcbios/hidemem.c
  95. 343
    0
      src/arch/i386/firmware/pcbios/memmap.c
  96. 114
    0
      src/arch/i386/firmware/pcbios/pnpbios.c
  97. 117
    0
      src/arch/i386/hci/commands/pxe_cmd.c
  98. 141
    0
      src/arch/i386/image/bootsector.c
  99. 669
    0
      src/arch/i386/image/bzimage.c
  100. 0
    0
      src/arch/i386/image/com32.c

+ 12
- 0
COPYING View File

@@ -0,0 +1,12 @@
1
+In general iPXE files are licensed under the GPL.  For historical
2
+reasons, individual files may contain their own licence declarations.
3
+Most builds of iPXE do not contain all iPXE code (in particular, most
4
+builds will include only one driver), and so the overall licence can
5
+vary depending on what target you are building.
6
+
7
+The resultant applicable licence(s) for any particular build can be
8
+determined by using "make bin/xxxxxxx.yyy.licence"; for example:
9
+
10
+  make bin/rtl8139.rom.licence
11
+
12
+to determine the resultant licence(s) for the build bin/rtl8139.rom

+ 339
- 0
COPYING.GPLv2 View File

@@ -0,0 +1,339 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Lesser General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    <one line to give the program's name and a brief idea of what it does.>
294
+    Copyright (C) <year>  <name of author>
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License along
307
+    with this program; if not, write to the Free Software Foundation, Inc.,
308
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+Also add information on how to contact you by electronic and paper mail.
311
+
312
+If the program is interactive, make it output a short notice like this
313
+when it starts in an interactive mode:
314
+
315
+    Gnomovision version 69, Copyright (C) year name of author
316
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+    This is free software, and you are welcome to redistribute it
318
+    under certain conditions; type `show c' for details.
319
+
320
+The hypothetical commands `show w' and `show c' should show the appropriate
321
+parts of the General Public License.  Of course, the commands you use may
322
+be called something other than `show w' and `show c'; they could even be
323
+mouse-clicks or menu items--whatever suits your program.
324
+
325
+You should also get your employer (if you work as a programmer) or your
326
+school, if any, to sign a "copyright disclaimer" for the program, if
327
+necessary.  Here is a sample; alter the names:
328
+
329
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+  <signature of Ty Coon>, 1 April 1989
333
+  Ty Coon, President of Vice
334
+
335
+This General Public License does not permit incorporating your program into
336
+proprietary programs.  If your program is a subroutine library, you may
337
+consider it more useful to permit linking proprietary applications with the
338
+library.  If this is what you want to do, use the GNU Lesser General
339
+Public License instead of this License.

+ 59
- 0
COPYING.UBDL View File

@@ -0,0 +1,59 @@
1
+UNMODIFIED BINARY DISTRIBUTION LICENCE
2
+
3
+
4
+PREAMBLE
5
+
6
+The GNU General Public License provides a legal guarantee that
7
+software covered by it remains free (in the sense of freedom, not
8
+price).  It achieves this guarantee by imposing obligations on anyone
9
+who chooses to distribute the software.
10
+
11
+Some of these obligations may be seen as unnecessarily burdensome.  In
12
+particular, when the source code for the software is already publicly
13
+and freely available, there is minimal value in imposing upon each
14
+distributor the obligation to provide the complete source code (or an
15
+equivalent written offer to provide the complete source code).
16
+
17
+This Licence allows for the distribution of unmodified binaries built
18
+from publicly available source code, without imposing the obligations
19
+of the GNU General Public License upon anyone who chooses to
20
+distribute only the unmodified binaries built from that source code.
21
+
22
+The extra permissions granted by this Licence apply only to unmodified
23
+binaries built from source code which has already been made available
24
+to the public in accordance with the terms of the GNU General Public
25
+Licence.  Nothing in this Licence allows for the creation of
26
+closed-source modified versions of the Program.  Any modified versions
27
+of the Program are subject to the usual terms and conditions of the
28
+GNU General Public License.
29
+
30
+
31
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
32
+
33
+This Licence applies to any Program or other work which contains a
34
+notice placed by the copyright holder saying it may be distributed
35
+under the terms of this Unmodified Binary Distribution Licence.  All
36
+terms used in the text of this Licence are to be interpreted as they
37
+are used in version 2 of the GNU General Public License as published
38
+by the Free Software Foundation.
39
+
40
+If you have made this Program available to the public in both source
41
+code and executable form in accordance with the terms of the GNU
42
+General Public License as published by the Free Software Foundation;
43
+either version 2 of the License, or (at your option) any later
44
+version, then you are hereby granted an additional permission to use,
45
+copy, and distribute the unmodified executable form of this Program
46
+(the "Unmodified Binary") without restriction, including the right to
47
+permit persons to whom the Unmodified Binary is furnished to do
48
+likewise, subject to the following conditions:
49
+
50
+- when started running, the Program must display an announcement which
51
+  includes the details of your existing publication of the Program
52
+  made in accordance with the terms of the GNU General Public License.
53
+  For example, the Program could display the URL of the publicly
54
+  available source code from which the Unmodified Binary was built.
55
+
56
+- when exercising your right to grant permissions under this Licence,
57
+  you do not need to refer directly to the text of this Licence, but
58
+  you may not grant permissions beyond those granted to you by this
59
+  Licence.

+ 8
- 0
README View File

@@ -0,0 +1,8 @@
1
+iPXE README File
2
+
3
+Quick start guide:
4
+
5
+   cd src
6
+   make
7
+
8
+For any more detailed instructions, see http://ipxe.org

+ 9
- 0
contrib/README View File

@@ -0,0 +1,9 @@
1
+Most of the content that was previously in this directory has been
2
+moved to a separate git repository:
3
+
4
+    http://git.etherboot.org/?p=contrib.git;a=summary
5
+
6
+or the Etherboot Project wiki:
7
+
8
+    http://etherboot.org/
9
+

+ 1
- 0
contrib/errdb/.gitignore View File

@@ -0,0 +1 @@
1
+errors.db

+ 109
- 0
contrib/errdb/errdb.pl View File

@@ -0,0 +1,109 @@
1
+#!/usr/bin/perl -w
2
+
3
+=head1 NAME
4
+
5
+errdb.pl
6
+
7
+=head1 SYNOPSIS
8
+
9
+errdb.pl [options] ../../src/bin/errors
10
+
11
+Options:
12
+
13
+    -d,--database=db	Specify path to errors.db
14
+    -h,--help		Display brief help message
15
+    -v,--verbose	Increase verbosity
16
+    -q,--quiet		Decrease verbosity
17
+
18
+=cut
19
+
20
+use Getopt::Long;
21
+use Pod::Usage;
22
+use DBI;
23
+use strict;
24
+use warnings;
25
+
26
+# Parse command-line options
27
+my $verbosity = 0;
28
+my $errdb = "errors.db";
29
+Getopt::Long::Configure ( 'bundling', 'auto_abbrev' );
30
+GetOptions (
31
+  'database|d=s' => sub { shift; $errdb = shift; },
32
+  'verbose|v+' => sub { $verbosity++; },
33
+  'quiet|q+' => sub { $verbosity--; },
34
+  'help|h' => sub { pod2usage ( 1 ); },
35
+) or die "Could not parse command-line options\n";
36
+pod2usage ( 1 ) unless @ARGV >= 1;
37
+
38
+# Open database
39
+my $dbh = DBI->connect ( "dbi:SQLite:dbname=".$errdb, "", "",
40
+			 { RaiseError => 1, PrintError => 0 } );
41
+$dbh->begin_work();
42
+
43
+# Create errors table if necessary
44
+eval {
45
+  $dbh->selectall_arrayref ( "SELECT * FROM errors LIMIT 1" );
46
+};
47
+if ( $@ ) {
48
+  print "Creating errors table\n" if $verbosity >= 1;
49
+  $dbh->do ( "CREATE TABLE errors (".
50
+	     " errno char(8) NOT NULL,".
51
+	     " description text NOT NULL,".
52
+	     " PRIMARY KEY ( errno ) )" );
53
+}
54
+
55
+# Create xrefs table if necessary
56
+eval {
57
+  $dbh->selectall_arrayref ( "SELECT * FROM xrefs LIMIT 1" );
58
+};
59
+if ( $@ ) {
60
+  print "Creating xrefs table\n" if $verbosity >= 1;
61
+  $dbh->do ( "CREATE TABLE xrefs (".
62
+	     " errno char(8) NOT NULL,".
63
+	     " filename text NOT NULL,".
64
+	     " line integer NOT NULL,".
65
+	     " UNIQUE ( errno, filename, line ),".
66
+	     " FOREIGN KEY ( errno ) REFERENCES errors ( errno ) )" );
67
+  $dbh->do ( "CREATE INDEX xrefs_errno ON xrefs ( errno )" );
68
+}
69
+
70
+# Parse input file(s)
71
+my $errors = {};
72
+my $xrefs = {};
73
+while ( <> ) {
74
+  chomp;
75
+  ( my $errno, my $filename, my $line, my $description ) = split ( /\t/ );
76
+  $errno = substr ( $errno, 0, 6 ) unless $errno =~ /^7f/;
77
+  $errors->{$errno} = $description;
78
+  $xrefs->{$errno} ||= {};
79
+  $xrefs->{$errno}->{$filename} ||= {};
80
+  $xrefs->{$errno}->{$filename}->{$line} ||= 1;
81
+}
82
+
83
+# Ensure all errors are present in database
84
+my $error_update =
85
+    $dbh->prepare ( "UPDATE errors SET description = ? WHERE errno = ?" );
86
+my $error_insert = $dbh->prepare ( "INSERT INTO errors VALUES ( ?, ? )" );
87
+while ( ( my $errno, my $description ) = each %$errors ) {
88
+  print "Error ".$errno." is \"".$description."\"\n" if $verbosity >= 2;
89
+  if ( $error_update->execute ( $description, $errno ) == 0 ) {
90
+    $error_insert->execute ( $errno, $description );
91
+  }
92
+}
93
+
94
+# Replace xrefs in database
95
+$dbh->do ( "DELETE FROM xrefs" );
96
+my $xref_insert = $dbh->prepare ( "INSERT INTO xrefs VALUES ( ?, ?, ? )" );
97
+while ( ( my $errno, my $xref_errno ) = each %$xrefs ) {
98
+  while ( ( my $filename, my $xref_filename ) = each %$xref_errno ) {
99
+    foreach my $line ( keys %$xref_filename ) {
100
+      print "Error ".$errno." is used at ".$filename." line ".$line."\n"
101
+	  if $verbosity >= 2;
102
+      $xref_insert->execute ( $errno, $filename, $line );
103
+    }
104
+  }
105
+}
106
+
107
+# Close database
108
+$dbh->commit();
109
+$dbh->disconnect();

+ 62
- 0
contrib/rom-o-matic/README View File

@@ -0,0 +1,62 @@
1
+ROM-o-matic web interface for building iPXE ROMs
2
+------------------------------------------------
3
+
4
+This web application generates iPXE images and sends them to a web
5
+browser.
6
+
7
+Available as part of the iPXE source code distribution, which can be
8
+downlaoded from http://etherboot.org/
9
+
10
+Author:  Marty Connor <mdc@etherboot.org>
11
+License: GPLv2
12
+Support: http://etherboot.org/mailman/listinfo/ipxe
13
+         Please send support questions to the iPXE mailing list
14
+
15
+System Requirements
16
+-------------------
17
+- Apache web server
18
+- PHP 4+
19
+- Tools required to build iPXE installed on the server
20
+  - gcc, mtools, syslinux, perl, etc.
21
+
22
+Setup
23
+-----
24
+As distributed, it is expected that the rom-o-matic source code
25
+directory is in the contrib directory of a iPXE source distribution.
26
+
27
+The easiest way to do this is to simply put a iPXE source distribution
28
+in a web server accessible directory.
29
+
30
+If this is not the case, you will need to either edit the file
31
+
32
+    "globals.php"
33
+
34
+or create a file called
35
+
36
+    "local-config.php"
37
+
38
+containing the following lines:
39
+
40
+<?php
41
+$src_dir = "../../src";
42
+?>
43
+
44
+Then change the line beginning "$src_dir = " to the path of your iPXE
45
+source code tree.
46
+
47
+To make build times shorter, before you run rom-o-matic for the first time
48
+you should cd to the ipxe "src" directory and enter the following
49
+commands:
50
+
51
+  $ make
52
+  $ make bin/NIC
53
+
54
+This will pro-compile most object files and will make your rom-o-matic
55
+builds much faster.
56
+
57
+Running rom-o-matic from a web browser
58
+--------------------------------------
59
+Enter a URL like:
60
+
61
+   http://example.com/ipxe-1.x.x/contrib/rom-o-matic
62
+

+ 62
- 0
contrib/rom-o-matic/bottom.php View File

@@ -0,0 +1,62 @@
1
+<?php
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+?>
23
+<hr>
24
+<h4>
25
+Resources:
26
+</h4>
27
+<ul>
28
+  <li>
29
+    Source code for iPXE images is available at
30
+    <a href="http://www.ipxe.org/download" target="_blank">
31
+    http://www.ipxe.org/download</a>
32
+    <br><br>
33
+  </li>
34
+  <li>
35
+    For general information about using iPXE, please visit the
36
+    <a href="http://www.ipxe.org/" target="_blank">
37
+    iPXE Project Home Page</a>
38
+    <br><br>
39
+  </li>
40
+  <li>
41
+    For Email-based support for iPXE please join
42
+    <a href="http://www.ipxe.org/contact" target="_blank">
43
+    iPXE Project mailing lists.</a>
44
+    <br><br>
45
+  </li>
46
+  <li>
47
+    For real-time online iPXE support via IRC please visit the
48
+    <a href="irc://irc.freenode.net/%23ipxe"> #ipxe channel
49
+    of irc.freenode.net</a>.
50
+    <br><br>
51
+  </li>
52
+</ul>
53
+<hr>
54
+  <font size="-1">
55
+    <br>
56
+    Please email <a href="mailto:<?php echo "${webmaster_email}" ?>"><?php echo "${webmaster_email}"?></a>
57
+    with questions or comments about this website.
58
+  </font>
59
+  <br><br>
60
+<hr>
61
+</body>
62
+</html>

+ 311
- 0
contrib/rom-o-matic/build.php View File

@@ -0,0 +1,311 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+// Get utility functions and set globals
23
+require_once "utils.php";
24
+
25
+// Make sure at least $A (action)  was supplied
26
+if ( ! isset ( $_POST['A'] ) ) {
27
+
28
+    // Present user with form to customize build options
29
+    require_once "customize-flags.php";
30
+
31
+    exit ();
32
+
33
+// If user chose "Customize" option on form
34
+} else if ( $_POST['A'] == "Customize" ) {
35
+
36
+    // Present user with form to customize build options
37
+    require_once "customize-flags.php";
38
+
39
+    exit ();
40
+
41
+// The following conditional includes all other cases except "Get Image"
42
+// particularly the explicit ($A == "Start Over") case
43
+} else if ( $_POST['A'] != "Get Image" ) {
44
+
45
+    // Note that this method of redirections discards all the
46
+    // configuration flags, which is intentional in this case.
47
+
48
+    $dest = curDirURL ();
49
+    header ( "Location: $dest" );
50
+
51
+    // This next "echo" should normally not be seen, because
52
+    // the "header" statement above should cause immediate
53
+    // redirection but just in case...
54
+
55
+    echo "Try this link: <a href=\"$dest\">$dest</a>";
56
+
57
+    exit ();
58
+}
59
+
60
+// OK, we're going to try to use whatever options have been set
61
+// to build an image.
62
+
63
+// Make sure at least $nic was supplied
64
+if ( ! isset ( $_POST['nic'] ) ) {
65
+    die ( "No NIC supplied!" );
66
+}
67
+if ( isset ( $nics[$_POST['nic']] ) ) {
68
+    $nic = $nics[$_POST['nic']];
69
+} else {
70
+    die ( "Invalid NIC \"${_POST['nic']}\" supplied!" );
71
+}
72
+
73
+// Fetch flags
74
+$flags = get_flags ();
75
+
76
+// Get requested format
77
+$ofmt = isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "";
78
+$fmt_extension = isset ( $ofmts[$ofmt] ) ? $ofmts[$ofmt] : 'dsk';
79
+
80
+// Handle some special cases
81
+
82
+$pci_vendor_code = "";
83
+$pci_device_code = "";
84
+
85
+if ( $nic == 'undionly' && $fmt_extension == "pxe" ) {
86
+
87
+    // undionly.pxe can't work because it unloads the PXE stack
88
+    // that it needs to communicate with, so we set the extension
89
+    // to .kpxe, which has a chance of working. The extension
90
+    // .kkpxe is another option.
91
+
92
+    $fmt_extension = "kpxe";
93
+
94
+} else if ( $fmt_extension == "rom" ) {
95
+
96
+    if ( ! isset ( $_POST['pci_vendor_code'] )
97
+		 || ! isset ( $_POST['pci_device_code'] ) ) {
98
+		die ( "rom output format selected but PCI code(s) missing!" );
99
+	}
100
+
101
+	$pci_vendor_code = $_POST['pci_vendor_code'];
102
+	$pci_device_code = $_POST['pci_device_code'];
103
+
104
+    if ( $pci_vendor_code == ""
105
+		 || $pci_device_code == "" ) {
106
+		die ( "rom output format selected but PCI code(s) missing!" );
107
+	}
108
+
109
+	// Try to be forgiving of 0xAAAA format
110
+	if ( strtolower ( substr ( $pci_vendor_code, 0, 2 ) ) == "0x"
111
+		 && strlen ( $pci_vendor_code ) == 6 ) {
112
+		$pci_vendor_code = substr ( $pci_vendor_code, 2, 4 );
113
+	}
114
+	if ( strtolower ( substr ( $pci_device_code, 0, 2 ) ) == "0x"
115
+		 && strlen ( $pci_device_code ) == 6 ) {
116
+		$pci_device_code = substr ( $pci_device_code, 2, 4 );
117
+	}
118
+
119
+    // concatenate the pci codes to get the $nic part of the
120
+    // Make target
121
+    $pci_codes = strtolower (  $pci_vendor_code . $pci_device_code );
122
+
123
+    $nic = $pci_codes;
124
+    if ( ! isset ( $roms[$pci_codes] ) ) {
125
+        die (   "Sorry, no network driver supports PCI codes<br>"
126
+              . "${_POST['pci_vendor_code']}:"
127
+              . "${_POST['pci_device_code']}" );
128
+    }
129
+} else if ( $fmt_extension != "rom"
130
+            && ( $pci_vendor_code != "" || $pci_device_code != "" ) ) {
131
+    die (   "'$fmt_extension' format was selected but PCI IDs were"
132
+          . " also entered.<br>Did you mean to select 'rom' output format"
133
+          . " instead?" );
134
+}
135
+
136
+/**
137
+ * remove temporary build directory
138
+ *
139
+ * @return bool true if removal is successful, false otherwise
140
+ */
141
+function rm_build_dir ()
142
+{
143
+    global $build_dir;
144
+    global $keep_build_dir;
145
+
146
+    if ( $keep_build_dir !== true ) {
147
+        rm_file_or_dir ( $build_dir );
148
+    }
149
+}
150
+
151
+// Arrange for the build directory to always be removed on exit.
152
+$build_dir = "";
153
+$keep_build_dir = false;
154
+register_shutdown_function ( 'rm_build_dir' );
155
+
156
+// Make temporary copy of src directory
157
+$build_dir = mktempcopy ( "$src_dir", "/tmp", "MDCROM" );
158
+$config_dir = $build_dir . "/config";
159
+
160
+// Write config files with supplied flags
161
+write_ipxe_config_files ( $config_dir, $flags );
162
+
163
+// Handle a possible embedded script
164
+$emb_script_cmd = "";
165
+$embedded_script = isset ( $_POST['embedded_script'] ) ? $_POST['embedded_script'] : "";
166
+if ( $embedded_script != "" ) {
167
+    $emb_script_path = "$build_dir" . "/script0.ipxe";
168
+
169
+	if ( substr ( $embedded_script, 0, 5 ) != "#!ipxe" ) {
170
+		$embedded_script = "#!ipxe\n" . $embedded_script;
171
+	}
172
+
173
+    // iPXE 0.9.7 doesn't like '\r\n" in the shebang...
174
+    $embedded_script = str_replace ( "\r\n", "\n", $embedded_script );
175
+
176
+    write_file_from_string ( $emb_script_path, $embedded_script );
177
+    $emb_script_cmd = "EMBEDDED_IMAGE=${emb_script_path}";
178
+}
179
+
180
+// Make the requested image.  $status is set to 0 on success
181
+$make_target = "bin/${nic}.${fmt_extension}";
182
+$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null');
183
+if ($gitversion) {
184
+	$gitversion = "GITVERSION=$gitversion";
185
+}
186
+
187
+$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1";
188
+
189
+exec ( $make_cmd, $maketxt, $status );
190
+
191
+// Uncomment the following section for debugging
192
+
193
+/**
194
+
195
+echo "<h2>build.php:</h2>";
196
+echo "<h3>Begin debugging output</h3>";
197
+
198
+//echo "<h3>\$_POST variables</h3>";
199
+//echo "<pre>"; var_dump ( $_POST ); echo "</pre>";
200
+
201
+echo "<h3>Build options:</h3>";
202
+echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
203
+echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
204
+echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" .  "<br>";
205
+echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
206
+echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
207
+
208
+echo "<h3>Flags:</h3>";
209
+show_flags ( $flags );
210
+
211
+if ( $embedded_script != "" ) {
212
+    echo "<h3>Embedded script:</h3>";
213
+    echo "<blockquote>"."<pre>";
214
+    echo $embedded_script;
215
+    echo "</pre>"."</blockquote>";
216
+}
217
+
218
+echo "<h3>Make output:</h3>";
219
+echo "Make command: " . $make_cmd . "<br>";
220
+echo "Build status = <? echo $status ?>" . "<br>";
221
+echo "<blockquote>"."<pre>";
222
+echo htmlentities ( implode ("\n", $maketxt ) );
223
+echo "</pre>"."</blockquote>";
224
+// Uncomment the next line if you want to keep the
225
+// build directory around for inspection after building.
226
+$keep_build_dir = true;
227
+die ( "<h3>End debugging output</h3>" );
228
+
229
+**/ //   End debugging section
230
+
231
+// Send ROM to browser (with extreme prejudice)
232
+
233
+if ( $status == 0 ) {
234
+
235
+    $fp = fopen("${build_dir}/${make_target}", "rb" );
236
+    if ( $fp > 0 ) {
237
+
238
+        $len = filesize ( "${build_dir}/${make_target}" );
239
+        if ( $len > 0 ) {
240
+
241
+            $buf = fread ( $fp, $len );
242
+            fclose ( $fp );
243
+
244
+            // Delete build directory as soon as it is not needed
245
+            rm_build_dir ();
246
+
247
+            $output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}");
248
+
249
+            // Try to force IE to handle downloading right.
250
+            Header ( "Cache-control: private");
251
+            Header ( "Content-Type: application/x-octet-stream; " .
252
+                     "name=$output_filename");
253
+            Header ( "Content-Disposition: attachment; " .
254
+                     "Filename=$output_filename");
255
+            Header ( "Content-Location: $output_filename");
256
+            Header ( "Content-Length: $len");
257
+
258
+            echo $buf;
259
+
260
+            exit ();
261
+        }
262
+    }
263
+}
264
+
265
+/*
266
+ * If we reach this point, the build has failed, and we provide
267
+ * debugging information for a potential bug report
268
+ *
269
+ */
270
+
271
+// Remove build directory
272
+rm_build_dir ();
273
+
274
+// Announce failure if $status from make was non-zero
275
+echo "<h2>Build failed.  Status = " . $status . "</h2>";
276
+echo "<h2>build.php:</h2>";
277
+echo "<h3>Build options:</h3>";
278
+echo "<strong>Build directory is:</strong> $build_dir" . "<br><br>";
279
+echo "\$_POST['ofmt'] = " . "\"${_POST['ofmt']}\"" . "<br>";
280
+echo "\$_POST['nic'] = " . "\"${_POST['nic']}\"" .  "<br>";
281
+echo "\$_POST['pci_vendor_code'] = " . "\"${_POST['pci_vendor_code']}\"" . "<br>";
282
+echo "\$_POST['pci_device_code'] = " . "\"${_POST['pci_device_code']}\"" . "<br>";
283
+
284
+echo "<h3>Flags:</h3>";
285
+show_flags ( $flags );
286
+
287
+if ( $embedded_script != "" ) {
288
+    echo "<h3>Embedded script:</h3>";
289
+    echo "<blockquote>"."<pre>";
290
+    echo $embedded_script;
291
+    echo "</pre>"."</blockquote>";
292
+}
293
+
294
+echo "<h3>Make output:</h3>";
295
+echo "Make command: " . $make_cmd . "<br>";
296
+echo "<blockquote>"."<pre>";
297
+echo htmlentities ( implode ("\n", $maketxt ) );
298
+echo "</pre>"."</blockquote>";
299
+
300
+echo "Please let us know that this happened, and paste the above output into your email message.<br>";
301
+
302
+include_once $bottom_inc;
303
+
304
+// For emacs:
305
+//  Local variables:
306
+//  c-basic-offset: 4
307
+//  c-indent-level: 4
308
+//  tab-width: 4
309
+//  End:
310
+
311
+?>

+ 69
- 0
contrib/rom-o-matic/customize-flags.php View File

@@ -0,0 +1,69 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+// Get utility functions and set globals
23
+require_once "utils.php";
24
+
25
+// Prepare settable compile options for presentation to user
26
+$flags = default_flags ();
27
+
28
+$build = "<input type=\"submit\" name=\"A\" value=\"Get Image\">";
29
+$restart = "<input type=\"submit\" name=\"A\" value=\"Start Over\">";
30
+
31
+// Begin html output
32
+include_once $top_inc;
33
+
34
+?>
35
+
36
+<form action="build.php" method=POST>
37
+  <input type="hidden" name="version" value = "<?php echo $version ?>">
38
+  <input type="hidden" name="use_flags" value="1">
39
+  <h3>
40
+    Make changes below and press <?php echo $build ?> to create an image, <br>
41
+    Or press <?php echo $restart ?> to return to the main page.
42
+  </h3>
43
+  <hr>
44
+  <ul>
45
+  <?php require ( "directions.php" ); ?>
46
+  </ul>
47
+  <hr>
48
+  <?php echo_flags( $flags ); ?>
49
+  <hr>
50
+  <h3>Embedded Script:</h3>
51
+  <?php echo textarea ( "embedded_script", "", "10", "50" ); ?>
52
+  <br><br>
53
+  <hr>
54
+  <center><table width="35%"><tr>
55
+  <td align="left"> <?php echo $build; ?> </td>
56
+  <td align="right"> <?php echo $restart ?></td>
57
+  </tr></table></center>
58
+</form>
59
+
60
+<?php include_once $bottom_inc; ?>
61
+<?
62
+// For emacs:
63
+//
64
+// Local variables:
65
+//  c-basic-offset: 4
66
+//  c-indent-level: 4
67
+//  tab-width: 4
68
+// End:
69
+?>

+ 63
- 0
contrib/rom-o-matic/directions.php View File

@@ -0,0 +1,63 @@
1
+<?php
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+?>
23
+    <li>
24
+      Choose an output format: <?php echo keys_menubox ( "ofmt", $ofmts,
25
+      isset ( $_POST['ofmt'] ) ? $_POST['ofmt'] : "") ?>
26
+      <br><br>
27
+    </li>
28
+    <li>
29
+      Choose a NIC type: <?php echo keys_menubox ( "nic", $nics,
30
+      isset ( $_POST['nic'] ) ? $_POST['nic'] : "" ) ?>
31
+      <br><br>
32
+    </li>
33
+    <li>
34
+      <strong>( optional &mdash; for binary ROM image format only )</strong> <br><br>
35
+      If you choose <em>Binary ROM image</em> as your output format, you must<br>
36
+      enter <strong>4 hex digits</strong> below for
37
+      <em>PCI VENDOR CODE</em> and <em>PCI DEVICE CODE</em>  <br>
38
+      that match the NIC device for which you are making this image.<br><br>
39
+      Information on how to determine NIC PCI IDs may be found
40
+      <a href="http://www.ipxe.org/howto/romburning"
41
+      target="_blank">here</a>.
42
+      <br><br>
43
+      PCI VENDOR CODE:  <?php echo textbox ( "pci_vendor_code",
44
+      isset ( $_POST['pci_vendor_code'] ) ? $_POST['pci_vendor_code']
45
+              : "", 6 ); ?>
46
+      &nbsp;&nbsp;
47
+      PCI DEVICE CODE:  <?php echo textbox ( "pci_device_code",
48
+      isset ( $_POST['pci_device_code'] ) ? $_POST['pci_device_code']
49
+              : "", 6 ); ?>
50
+      <h4>Please note for ROM images:</h4>
51
+      <ul>
52
+        <li>
53
+          If you enter PCI IDs, we will attempt to determine the correct<br>
54
+          driver to support them, and will ignore any NIC type entered
55
+          above.<br><br>
56
+        </li>
57
+        <li>
58
+          iPXE does not support all possible PCI IDs for supported
59
+          NICs.
60
+          <br><br>
61
+        </li>
62
+      </ul>
63
+    </li>

+ 1
- 0
contrib/rom-o-matic/doc/AUTOBOOT_CMD.html View File

@@ -0,0 +1 @@
1
+Automatic booting

+ 1
- 0
contrib/rom-o-matic/doc/BANNER_TIMEOUT.html View File

@@ -0,0 +1 @@
1
+Tenths of a second for which the shell banner should appear

+ 3
- 0
contrib/rom-o-matic/doc/COMCONSOLE.html View File

@@ -0,0 +1,3 @@
1
+Serial Console I/O port address.  Common addresses are:<br>
2
+COM1 =>	0x3f8, COM2 => 0x2f8, COM3 => 0x3e8, COM4 => 0x2e8
3
+

+ 1
- 0
contrib/rom-o-matic/doc/COMDATA.html View File

@@ -0,0 +1 @@
1
+Serial Console Data bits

+ 1
- 0
contrib/rom-o-matic/doc/COMPARITY.html View File

@@ -0,0 +1 @@
1
+Serial Console Parity: 0=None, 1=Odd, 2=Even

+ 1
- 0
contrib/rom-o-matic/doc/COMPRESERVE.html View File

@@ -0,0 +1 @@
1
+Keep settings from a previous user of the serial port

+ 1
- 0
contrib/rom-o-matic/doc/COMSPEED.html View File

@@ -0,0 +1 @@
1
+Serial Console Baud rate

+ 1
- 0
contrib/rom-o-matic/doc/COMSTOP.html View File

@@ -0,0 +1 @@
1
+Serial Console Stop bits

+ 1
- 0
contrib/rom-o-matic/doc/CONFIG_CMD.html View File

@@ -0,0 +1 @@
1
+Option configuration console

+ 1
- 0
contrib/rom-o-matic/doc/CONSOLE_PC_BIOS.html View File

@@ -0,0 +1 @@
1
+Enable Default BIOS console

+ 1
- 0
contrib/rom-o-matic/doc/CONSOLE_SERIAL.html View File

@@ -0,0 +1 @@
1
+Enable Serial port console

+ 1
- 0
contrib/rom-o-matic/doc/CRYPTO_80211_WEP.html View File

@@ -0,0 +1 @@
1
+Wireless WEP encryption support

+ 1
- 0
contrib/rom-o-matic/doc/CRYPTO_80211_WPA.html View File

@@ -0,0 +1 @@
1
+Wireless WPA encryption support

+ 1
- 0
contrib/rom-o-matic/doc/CRYPTO_80211_WPA2.html View File

@@ -0,0 +1 @@
1
+Wireless WPA2 encryption support

+ 1
- 0
contrib/rom-o-matic/doc/DHCP_CMD.html View File

@@ -0,0 +1 @@
1
+DHCP management commands

+ 1
- 0
contrib/rom-o-matic/doc/DNS_RESOLVER.html View File

@@ -0,0 +1 @@
1
+DNS resolver

+ 1
- 0
contrib/rom-o-matic/doc/DOWNLOAD_PROTO_FTP.html View File

@@ -0,0 +1 @@
1
+File Transfer Protocol

+ 1
- 0
contrib/rom-o-matic/doc/DOWNLOAD_PROTO_HTTP.html View File

@@ -0,0 +1 @@
1
+Hypertext Transfer Protocol

+ 1
- 0
contrib/rom-o-matic/doc/DOWNLOAD_PROTO_TFTP.html View File

@@ -0,0 +1 @@
1
+Trivial File Transfer Protocol

+ 1
- 0
contrib/rom-o-matic/doc/IFMGMT_CMD.html View File

@@ -0,0 +1 @@
1
+Interface management commands

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_BZIMAGE.html View File

@@ -0,0 +1 @@
1
+Linux bzImage image support

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_CMD.html View File

@@ -0,0 +1 @@
1
+Image management commands

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_ELF.html View File

@@ -0,0 +1 @@
1
+ELF image support

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_MULTIBOOT.html View File

@@ -0,0 +1 @@
1
+MultiBoot image support

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_NBI.html View File

@@ -0,0 +1 @@
1
+NBI image support

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_PXE.html View File

@@ -0,0 +1 @@
1
+PXE image support

+ 1
- 0
contrib/rom-o-matic/doc/IMAGE_SCRIPT.html View File

@@ -0,0 +1 @@
1
+iPXE script image support

+ 1
- 0
contrib/rom-o-matic/doc/IWMGMT_CMD.html View File

@@ -0,0 +1 @@
1
+Wireless interface management commands

+ 1
- 0
contrib/rom-o-matic/doc/NMB_RESOLVER.html View File

@@ -0,0 +1 @@
1
+NMB resolver

+ 1
- 0
contrib/rom-o-matic/doc/NVO_CMD.html View File

@@ -0,0 +1 @@
1
+Non-volatile option storage commands

+ 1
- 0
contrib/rom-o-matic/doc/ROUTE_CMD.html View File

@@ -0,0 +1 @@
1
+Routing table management commands

+ 1
- 0
contrib/rom-o-matic/doc/SANBOOT_CMD.html View File

@@ -0,0 +1 @@
1
+SAN boot commands

+ 531
- 0
contrib/rom-o-matic/flag-table.php View File

@@ -0,0 +1,531 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+$ofmts = array
23
+	( "Floppy bootable image (.dsk)" => "dsk",
24
+	  "SYSLINUX-based bootable floppy image (.sdsk)" => "sdsk",
25
+	  "ISO bootable image (.iso)" => "iso",
26
+	  "ISO bootable image with legacy floppy emulation (.liso)" => "liso",
27
+	  "Linux kernel (SYSLINUX/GRUB/LILO) loadable image (.lkrn)" => "lkrn",
28
+	  "USB Keychain disk image (.usb)" => "usb",
29
+	  "ROM binary (flashable) image (.rom)" => "rom",
30
+	  "ROM binary (flashable) for problem PMM BIOSES  (.hrom)" => "hrom",
31
+	  "PXE bootstrap loader image [Unload PXE stack] (.pxe)" => "pxe",
32
+	  "PXE bootstrap loader keep [Keep PXE stack method 1] (.kpxe)" => "kpxe",
33
+	  "PXE bootstrap loader keep [Keep PXE stack method 2] (.kkpxe)" => "kkpxe",
34
+	);
35
+
36
+$flag_table = array (
37
+
38
+	// Begin General Options:
39
+
40
+	"HDR_MISC_OPTIONS"
41
+	=> array (
42
+	   "flag" => "HDR_MISC_OPTIONS",
43
+	   "hide_from_user" => "yes",  // Hide even the header
44
+	   "type" => "header",
45
+	   "label" => "Miscellaneous Options"
46
+		),
47
+
48
+	"PRODUCT_NAME"
49
+	=> array (
50
+	   "flag" => "PRODUCT_NAME",
51
+	   "hide_from_user" => "yes",
52
+	   "type" => "string",
53
+	   "value" => "",
54
+	   "cfgsec" => "general"
55
+	   ),
56
+
57
+	"PRODUCT_SHORT_NAME"
58
+	=> array (
59
+	   "flag" => "PRODUCT_SHORT_NAME",
60
+	   "hide_from_user" => "yes",
61
+	   "type" => "string",
62
+	   "value" => "iPXE",
63
+	   "cfgsec" => "general"
64
+	   ),
65
+
66
+	// End General Options:
67
+
68
+	// Begin Console Options:
69
+
70
+	"HDR_CONSOLE_OPTIONS"
71
+	=> array (
72
+	   "flag" => "HDR_CONSOLE_OPTIONS",
73
+	   "type" => "header",
74
+	   "label" => "Console Options"
75
+		),
76
+
77
+	"CONSOLE_PCBIOS"
78
+	=> array (
79
+	   "flag" => "CONSOLE_PCBIOS",
80
+	   "type" => "on/off",
81
+	   "value" => "on",
82
+	   "cfgsec" => "console"
83
+	   ),
84
+
85
+	"CONSOLE_SERIAL"
86
+	=> array (
87
+	   "flag" => "CONSOLE_SERIAL",
88
+	   "type" => "on/off",
89
+	   "value" => "off",
90
+	   "cfgsec" => "console"
91
+	   ),
92
+
93
+	"BANNER_TIMEOUT"
94
+	=> array (
95
+	   "flag" => "BANNER_TIMEOUT",
96
+	   "type" => "integer",
97
+	   "value" => "20",
98
+	   "cfgsec" => "general"
99
+	   ),
100
+
101
+        "KEYBOARD_MAP"
102
+        => array (
103
+           "flag" => "KEYBOARD_MAP",
104
+           "type" => "choice",
105
+	   "options" => array("al","az","bg","by","cf","cz","de","dk","es","et","fi","fr",
106
+	      "gr","hu","il","it","lt","mk","mt","nl","no","pl","pt","ro","ru","sg","sr",
107
+	      "th","ua","uk","us","wo"),
108
+           "value" => "us",
109
+           "cfgsec" => "console"
110
+           ),
111
+
112
+	"LOG_LEVEL"
113
+	=> array (
114
+	   "flag" => "LOG_LEVEL",
115
+	   "type" => "choice",
116
+	   "options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR",
117
+	      "LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"),
118
+	   "value" => "LOG_NONE",
119
+	   "cfgsec" => "console"
120
+	   ),
121
+
122
+	// End Console Options
123
+
124
+	// Begin Network Protocol Options:
125
+
126
+	"HDR_NETWORK_PROTOCOL_OPTIONS"
127
+	=> array (
128
+	   "flag" => "HDR_NETWORK_PROTOCOL_OPTIONS",
129
+	   "hide_from_user" => "yes",  // Hide even the header
130
+	   "type" => "header",
131
+	   "label" => "Network Protocol Options"
132
+		),
133
+
134
+	"NET_PROTO_IPV4"
135
+	=> array (
136
+	   "flag" => "NET_PROTO_IPV4",
137
+	   "type" => "on/off",
138
+	   "value" => "on",
139
+	   "hide_from_user" => "yes",
140
+	   "cfgsec" => "general"
141
+	   ),
142
+
143
+	// End Network Protocol Options
144
+
145
+	// Begin Serial Port configuration
146
+
147
+	"HDR_SERIAL_PORT_OPTIONS"
148
+	=> array (
149
+	   "flag" => "HDR_SERIAL_PORT_OPTIONS",
150
+	   "type" => "header",
151
+	   "label" => "Serial Port Options"
152
+		),
153
+
154
+	"COMCONSOLE"
155
+	=> array (
156
+	   "flag" => "COMCONSOLE",
157
+	   "type" => "integer-hex", // e.g. 0x378
158
+	   "value" => "0x3F8",
159
+	   "cfgsec" => "serial"
160
+		),
161
+
162
+	"COMPRESERVE"
163
+	=> array (
164
+	   "flag" => "COMPRESERVE",
165
+	   "type" => "on/off",
166
+	   "value" => "off",
167
+	   "cfgsec" => "serial"
168
+	   ),
169
+
170
+	"COMSPEED"
171
+	=> array (
172
+	   "flag" => "COMSPEED",
173
+	   "type" => "integer",
174
+	   "value" => "115200",
175
+	   "cfgsec" => "serial"
176
+	   ),
177
+
178
+	"COMDATA"
179
+	=> array (
180
+	   "flag" => "COMDATA",
181
+	   "type" => "integer",
182
+	   "value" => "8",
183
+	   "cfgsec" => "serial"
184
+	   ),
185
+
186
+	"COMPARITY"
187
+	=> array (
188
+	   "flag" => "COMPARITY",
189
+	   "type" => "integer",
190
+	   "value" => "0",
191
+	   "cfgsec" => "serial"
192
+	   ),
193
+
194
+	"COMSTOP"
195
+	=> array (
196
+	   "flag" => "COMSTOP",
197
+	   "type" => "integer",
198
+	   "value" => "1",
199
+	   "cfgsec" => "serial"
200
+	   ),
201
+
202
+	// End Serial Options
203
+
204
+	// Begin Download Protocols
205
+
206
+	"HDR_DOWNLOAD_PROTOCOLS"
207
+	=> array (
208
+	   "flag" => "HDR_DOWNLOAD_PROTOCOLS",
209
+	   "type" => "header",
210
+	   "label" => "Download Protocols"
211
+		),
212
+
213
+	"DOWNLOAD_PROTO_TFTP"
214
+	=> array (
215
+	   "flag" => "DOWNLOAD_PROTO_TFTP",
216
+	   "type" => "on/off",
217
+	   "value" => "on",
218
+	   "cfgsec" => "general"
219
+	   ),
220
+
221
+	"DOWNLOAD_PROTO_HTTP"
222
+	=> array (
223
+	   "flag" => "DOWNLOAD_PROTO_HTTP",
224
+	   "type" => "on/off",
225
+	   "value" => "on",
226
+	   "cfgsec" => "general"
227
+	   ),
228
+
229
+	"DOWNLOAD_PROTO_HTTPS"
230
+	=> array (
231
+	   "flag" => "DOWNLOAD_PROTO_HTTPS",
232
+	   "type" => "on/off",
233
+	   "value" => "off",
234
+	   "cfgsec" => "general"
235
+	   ),
236
+
237
+	"DOWNLOAD_PROTO_FTP"
238
+	=> array (
239
+	   "flag" => "DOWNLOAD_PROTO_FTP",
240
+	   "type" => "on/off",
241
+	   "value" => "off",
242
+	   "cfgsec" => "general"
243
+	   ),
244
+
245
+	// End Download Protocols
246
+
247
+	// Begin SAN boot protocols
248
+
249
+	"HDR_SANBOOT_PROTOCOLS"
250
+	=> array (
251
+	   "flag" => "HDR_SANBOOT_PROTOCOLS",
252
+	   "type" => "header",
253
+	   "label" => "SAN Boot Protocols"
254
+		),
255
+
256
+	"SANBOOT_PROTO_ISCSI"
257
+	=> array (
258
+	   "flag" => "SANBOOT_PROTO_ISCSI",
259
+	   "type" => "on/off",
260
+	   "value" => "on",
261
+	   "cfgsec" => "general"
262
+	   ),
263
+
264
+	"SANBOOT_PROTO_AOE"
265
+	=> array (
266
+	   "flag" => "SANBOOT_PROTO_AOE",
267
+	   "type" => "on/off",
268
+	   "value" => "on",
269
+	   "cfgsec" => "general"
270
+	   ),
271
+
272
+	// End SAN boot protocols
273
+
274
+	// Begin Name resolution modules
275
+
276
+	"HDR_NAME_RESOLUTION_MODULES"
277
+	=> array (
278
+	   "flag" => "HDR_NAME_RESOLUTION_MODULES",
279
+	   "type" => "header",
280
+	   "label" => "Name Resolution Modules"
281
+	   ),
282
+
283
+	"DNS_RESOLVER"
284
+	=> array (
285
+	   "flag" => "DNS_RESOLVER",
286
+	   "type" => "on/off",
287
+	   "value" => "on",
288
+	   "cfgsec" => "general"
289
+		),
290
+
291
+	"NMB_RESOLVER"
292
+	=> array (
293
+	   "flag" => "NMB_RESOLVER",
294
+	   "type" => "on/off",
295
+	   "value" => "off",
296
+	   "hide_from_user" => "yes",
297
+	   "cfgsec" => "general"
298
+		),
299
+
300
+	// End Name resolution modules
301
+
302
+	// Begin Image types
303
+
304
+	"HDR_IMAGE_TYPES"
305
+	=> array (
306
+	   "flag" => "HDR_IMAGE_TYPES",
307
+	   "type" => "header",
308
+	   "label" => "Image Types",
309
+	   ),
310
+
311
+	"IMAGE_ELF"
312
+	=> array (
313
+	   "flag" => "IMAGE_ELF",
314
+	   "type" => "on/off",
315
+	   "value" => "on",
316
+	   "cfgsec" => "general"
317
+	   ),
318
+
319
+	"IMAGE_NBI"
320
+	=> array (
321
+	   "flag" => "IMAGE_NBI",
322
+	   "type" => "on/off",
323
+	   "value" => "on",
324
+	   "cfgsec" => "general"
325
+		),
326
+
327
+	"IMAGE_MULTIBOOT"
328
+	=> array (
329
+	   "flag" => "IMAGE_MULTIBOOT",
330
+	   "type" => "on/off",
331
+	   "value" => "on",
332
+	   "cfgsec" => "general"
333
+	   ),
334
+
335
+	"IMAGE_PXE"
336
+	=> array (
337
+	   "flag" => "IMAGE_PXE",
338
+	   "type" => "on/off",
339
+	   "value" => "on",
340
+	   "cfgsec" => "general"
341
+	   ),
342
+
343
+	"IMAGE_SCRIPT"
344
+	=> array (
345
+	   "flag" => "IMAGE_SCRIPT",
346
+	   "type" => "on/off",
347
+	   "value" => "on",
348
+	   "cfgsec" => "general"
349
+	   ),
350
+
351
+	"IMAGE_BZIMAGE"
352
+	=> array (
353
+	   "flag" => "IMAGE_BZIMAGE",
354
+	   "type" => "on/off",
355
+	   "value" => "on",
356
+	   "cfgsec" => "general"
357
+	   ),
358
+
359
+	"IMAGE_COMBOOT"
360
+	=> array (
361
+	   "flag" => "IMAGE_COMBOOT",
362
+	   "type" => "on/off",
363
+	   "value" => "on",
364
+	   "cfgsec" => "general"
365
+	   ),
366
+
367
+	// End Image types
368
+
369
+	// Begin Command-line commands to include
370
+
371
+	"HDR_COMMAND_LINE_OPTIONS"
372
+	=> array (
373
+	   "flag" => "HDR_COMMAND_LINE_OPTIONS",
374
+	   "type" => "header",
375
+	   "label" => "Command Line Options",
376
+	   ),
377
+
378
+	"AUTOBOOT_CMD"
379
+	=> array (
380
+	   "flag" => "AUTOBOOT_CMD",
381
+	   "type" => "on/off",
382
+	   "value" => "on",
383
+	   "cfgsec" => "general"
384
+	   ),
385
+
386
+	"NVO_CMD"
387
+	=> array (
388
+	   "flag" => "NVO_CMD",
389
+	   "type" => "on/off",
390
+	   "value" => "on",
391
+	   "cfgsec" => "general"
392
+	   ),
393
+
394
+	"CONFIG_CMD"
395
+	=> array (
396
+	   "flag" => "CONFIG_CMD",
397
+	   "type" => "on/off",
398
+	   "value" => "on",
399
+	   "cfgsec" => "general"
400
+	   ),
401
+
402
+	"IFMGMT_CMD"
403
+	=> array (
404
+	   "flag" => "IFMGMT_CMD",
405
+	   "type" => "on/off",
406
+	   "value" => "on",
407
+	   "cfgsec" => "general"
408
+	   ),
409
+
410
+	"IWMGMT_CMD"
411
+	=> array (
412
+	   "flag" => "IWMGMT_CMD",
413
+	   "type" => "on/off",
414
+	   "value" => "on",
415
+	   "cfgsec" => "general"
416
+	   ),
417
+
418
+	"ROUTE_CMD"
419
+	=> array (
420
+	   "flag" => "ROUTE_CMD",
421
+	   "type" => "on/off",
422
+	   "value" => "on",
423
+	   "cfgsec" => "general"
424
+	   ),
425
+
426
+	"IMAGE_CMD"
427
+	=> array (
428
+	   "flag" => "IMAGE_CMD",
429
+	   "type" => "on/off",
430
+	   "value" => "on",
431
+	   "cfgsec" => "general"
432
+	   ),
433
+
434
+	"DHCP_CMD"
435
+	=> array (
436
+	   "flag" => "DHCP_CMD",
437
+	   "type" => "on/off",
438
+	   "value" => "on",
439
+	   "cfgsec" => "general"
440
+		),
441
+
442
+	"SANBOOT_CMD"
443
+	=> array (
444
+	   "flag" => "SANBOOT_CMD",
445
+	   "type" => "on/off",
446
+	   "value" => "on",
447
+	   "cfgsec" => "general"
448
+		),
449
+
450
+	"LOGIN_CMD"
451
+	=> array (
452
+	   "flag" => "LOGIN_CMD",
453
+	   "type" => "on/off",
454
+	   "value" => "on",
455
+	   "cfgsec" => "general"
456
+		),
457
+
458
+	"TIME_CMD"
459
+	=> array (
460
+	   "flag" => "TIME_CMD",
461
+	   "type" => "on/off",
462
+	   "value" => "off",
463
+	   "cfgsec" => "general"
464
+		),
465
+
466
+	"DIGEST_CMD"
467
+	=> array (
468
+	   "flag" => "DIGEST_CMD",
469
+	   "type" => "on/off",
470
+	   "value" => "off",
471
+	   "cfgsec" => "general"
472
+		),
473
+
474
+	// End Command-line commands to include
475
+
476
+	// Begin Wireless options
477
+
478
+	"HDR_WIRELESS_OPTIONS"
479
+	=> array (
480
+	   "flag" => "HDR_WIRELESS_OPTIONS",
481
+	   "type" => "header",
482
+	   "label" => "Wireless Interface Options",
483
+	   ),
484
+
485
+	"CRYPTO_80211_WEP"
486
+	=> array (
487
+	   "flag" => "CRYPTO_80211_WEP",
488
+	   "type" => "on/off",
489
+	   "value" => "on",
490
+	   "cfgsec" => "general"
491
+	   ),
492
+
493
+	"CRYPTO_80211_WPA"
494
+	=> array (
495
+	   "flag" => "CRYPTO_80211_WPA",
496
+	   "type" => "on/off",
497
+	   "value" => "on",
498
+	   "cfgsec" => "general"
499
+	   ),
500
+
501
+	"CRYPTO_80211_WPA2"
502
+	=> array (
503
+	   "flag" => "CRYPTO_80211_WPA2",
504
+	   "type" => "on/off",
505
+	   "value" => "on",
506
+	   "cfgsec" => "general"
507
+	   ),
508
+
509
+	// End Wireless options
510
+
511
+	// Obscure options required to compile
512
+	"NETDEV_DISCARD_RATE"
513
+	=> array (
514
+	   "flag" => "NETDEV_DISCARD_RATE",
515
+	   "type" => "integer",
516
+	   "value" => "0",
517
+	   "cfgsec" => "general",
518
+	   "hide_from_user" => true
519
+	   )
520
+
521
+	// End Obscure options
522
+);
523
+
524
+// For emacs:
525
+// Local variables:
526
+//	c-basic-offset: 4
527
+//	c-indent-level: 4
528
+//	tab-width: 4
529
+// End:
530
+
531
+?>

+ 51
- 0
contrib/rom-o-matic/globals.php View File

@@ -0,0 +1,51 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+// Directory containing iPXE source code tree
23
+$src_dir = "../../src";
24
+
25
+// Compute iPXE version based on source tree
26
+exec ( "make -C '$src_dir' version 2>&1", $make_output, $status );
27
+$version = ( $status == 0 && count ( $make_output  ) > 1 )
28
+           ? trim ( $make_output[count ( $make_output ) - 2] )
29
+           : "";
30
+
31
+// Email address of person responsible for this website
32
+$webmaster_email = "webmaster@example.com";
33
+
34
+// Files that header and footer text
35
+$top_inc = "top.php";
36
+$bottom_inc = "bottom.php";
37
+
38
+// Descriptive strings
39
+$header_title = "ROM-o-matic for iPXE $version";
40
+$html_tagline = "ROM-o-matic dynamically generates iPXE images";
41
+$html_title   = "ROM-o-matic for iPXE $version";
42
+$description  = "a dynamic iPXE image generator";
43
+
44
+// For emacs:
45
+// Local variables:
46
+//  c-basic-offset: 4
47
+//  c-indent-level: 4
48
+//  tab-width: 4
49
+// End:
50
+
51
+?>

+ 47
- 0
contrib/rom-o-matic/index.php View File

@@ -0,0 +1,47 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+// Get utility functions and set globals
23
+require_once "utils.php";
24
+
25
+// Begin html output
26
+include_once $top_inc;
27
+
28
+?>
29
+<form action="build.php" method=POST>
30
+  <input type="hidden" name="version" value = "<?php echo $version ?>">
31
+  <h3>To create an image:</h3>
32
+  <ol>
33
+    <?php require ( "directions.php" ); ?>
34
+    <li>
35
+      Generate and download an image:
36
+      <input type="submit" name="A" value="Get Image">
37
+      <br><br>
38
+    </li>
39
+    <li>
40
+      (optional) Customize image configuration options:
41
+      <input type="submit" name="A" value="Customize">
42
+      <br><br>
43
+    </li>
44
+  </ol>
45
+</form>
46
+
47
+<?php include_once $bottom_inc ?>

+ 41
- 0
contrib/rom-o-matic/top.php View File

@@ -0,0 +1,41 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
+
3
+<?php
4
+
5
+/**
6
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
7
+ * Copyright (C) 2009 Entity Cyber, Inc.
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU General Public License as
11
+ * published by the Free Software Foundation; either version 2 of the
12
+ * License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful, but
15
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
+ * General Public License for more details.
18
+ *
19
+ * You should have received a copy of the GNU General Public License
20
+ * along with this program; if not, write to the Free Software
21
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
+ */
23
+
24
+?>
25
+
26
+<html>
27
+<head>
28
+  <link rev="made" href="mailto:<?php echo "${webmaster_email}" ?>">
29
+  <meta name="keywords" content="rom, etherboot, ipxe, open source, rom-o-matic.net">
30
+  <title><?php echo $header_title ?></title>
31
+  <meta name="description" content="<?php echo $description ?>">
32
+</head>
33
+<h1>
34
+<?php echo "$html_title" ?>&nbsp;
35
+</h1>
36
+<hr>
37
+<h2>
38
+<?php echo "$html_tagline" ?>
39
+</h2>
40
+</form>
41
+<hr>

+ 684
- 0
contrib/rom-o-matic/utils.php View File

@@ -0,0 +1,684 @@
1
+<?php // -*- Mode: PHP; -*-
2
+
3
+/**
4
+ * Copyright (C) 2009 Marty Connor <mdc@etherboot.org>.
5
+ * Copyright (C) 2009 Entity Cyber, Inc.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+// Include table of user-configurable iPXE options
23
+require_once "flag-table.php";
24
+
25
+// Include user-shadowable globals
26
+require_once "globals.php";
27
+
28
+// Allow user to shadow globals
29
+if ( is_file ( 'local-config.php' ) ) {
30
+    include_once "local-config.php";
31
+}
32
+
33
+////
34
+// General utility functions
35
+////
36
+
37
+/**
38
+ * Remove undesirable characters from a given string
39
+ *
40
+ * Certain characters have the potential to be used for
41
+ * malicious purposes by web-based attackers.  This routine
42
+ * filters out such characters.
43
+ *
44
+ * @param string $s supplied string
45
+ *
46
+ * @return string returned string with unwanted characters
47
+ *                removed
48
+ */
49
+function cleanstring ( $s )
50
+{
51
+    $len = strlen ( $s );
52
+    if ( $len > 80 ) {
53
+        $s = substr ( $s, 0, 80 );
54
+    }
55
+
56
+    $s      = trim ( $s );
57
+    $pos    = 0;
58
+    $result = "";
59
+
60
+    while ( $pos < $len ) {
61
+        $ltr = ord ( ucfirst ( $s[$pos] ) );
62
+        if ( ( $ltr >= ord ( "A" ) ) && ( $ltr <= ord ( "Z" ) ) ||
63
+             ( $ltr >= ord ( "0" ) ) && ( $ltr <= ord ( "9" ) ) ||
64
+             ( $ltr == ord ( "." ) ) && ( strlen ( $result ) > 0 ) ||
65
+             ( $ltr == ord ( "_" ) ) ||
66
+             ( $ltr == ord ( "+" ) ) ||
67
+             ( $ltr == ord ( ":" ) ) ||
68
+             ( $ltr == ord ( "/" ) ) ||
69
+             ( $ltr == ord ( "-" ) ) ) {
70
+            $result .= $s[$pos];
71
+        }
72
+        $pos++;
73
+    }
74
+    return $result;
75
+}
76
+
77
+/**
78
+ * Return URL of the currently running script, minus the filename
79
+ *
80
+ * @return string the URL of the currently running script, minus the filename
81
+ */
82
+function curDirURL ()
83
+{
84
+        $dir = dirname ( $_SERVER['PHP_SELF'] );
85
+
86
+        if ( $dir == "." || $dir == "/" ) {
87
+                $dir = "";
88
+        }
89
+
90
+        $isHTTPS = ( isset ( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" );
91
+        $port = ( isset($_SERVER["SERVER_PORT"] ) &&
92
+                          ( ( !$isHTTPS && $_SERVER["SERVER_PORT"] != "80" ) ||
93
+                                ( $isHTTPS  && $_SERVER["SERVER_PORT"] != "443" ) ) );
94
+
95
+        $port = ( $port ) ? ':' . $_SERVER["SERVER_PORT"] : '';
96
+
97
+        $dest = ( $isHTTPS ? 'https://' : 'http://' ) .
98
+                $_SERVER["SERVER_NAME"] . $dir . "/";
99
+
100
+        return $dest;
101
+}
102
+
103
+/**
104
+ * Extract NIC families and associated ROM PCI IDs from the src/bin/NIC file.
105
+ *
106
+ * $src_dir must contain the path of the iPXE src directory for this build
107
+ *
108
+ * @return array[0] array $new_nics
109
+ * @return array[1] array $roms
110
+ */
111
+function parse_nic_file ()
112
+{
113
+    global $src_dir;
114
+
115
+    $fd = fopen ( "$src_dir/bin/NIC", "r" );
116
+    if ( ! $fd ) {
117
+        die ( "Missing src/bin/NIC file.  'make bin/NIC'" );
118
+    }
119
+
120
+    $nics = array ();
121
+    $roms = array ();
122
+    $nic = "";
123
+
124
+    while ( !feof ( $fd ) ) {
125
+
126
+        $line = trim ( fgets ( $fd, 200 ) );
127
+
128
+        $first_eight_chars = substr ( $line, 0, 8 );
129
+        settype ( $first_eight_chars, "string" );
130
+
131
+        if ( strpos ( $first_eight_chars, "family" ) === 0 ) {
132
+
133
+            // get pathname of NIC driver
134
+            #list ( $dummy, $nic ) = split( "[ \t]+", $line );
135
+            list ( $dummy, $nic ) = explode("\t", $line);
136
+            settype ( $nic, "string" );
137
+
138
+            // extract filename name of driver from pathname
139
+            $nic = substr ( $nic, strrpos ( $nic, "/" ) + 1,
140
+			   strlen ( $nic ) - strrpos ( $nic, "/" ) + 1 );
141
+
142
+            $nics[$nic] = $nic;
143
+
144
+            // For each ISA NIC, there can only be one ROM variant
145
+            $roms[$nic] = $nic;
146
+        }
147
+
148
+        // If the first 8 digits of the line are hex digits
149
+        // add this rom to the current nic family.
150
+
151
+        if (    ( strlen ( $first_eight_chars ) == 8 )
152
+             && ( ctype_xdigit ( $first_eight_chars ) )
153
+             && ( $nic != "" ) ) {
154
+
155
+            $roms[$first_eight_chars] = $nic;
156
+        }
157
+    }
158
+    fclose ( $fd );
159
+
160
+    // put most NICs in nice alpha order for menu
161
+    ksort ( $nics );
162
+
163
+    // add special cases to the top
164
+
165
+	$new_nics = array ( "all-drivers" => "ipxe",
166
+						"undionly" => "undionly",
167
+						"undi" => "undi",
168
+    );
169
+
170
+	foreach ( $nics as $key => $value ) {
171
+		// skip the undi driver
172
+		if ( $key != "undi" ) {
173
+			$new_nics[$key] = $value;
174
+		}
175
+	}
176
+
177
+	return array ( $new_nics, $roms );
178
+}
179
+
180
+////
181
+// HTML form utility functions
182
+////
183
+
184
+/**
185
+ * Return html code to create hidden form input fields
186
+ *
187
+ * @param string $flag  name of form variable to set
188
+ * @param string $value value to give form variable
189
+ *
190
+ * @return string html code for given hidden form input field
191
+ */
192
+function hidden ( $flag, $value )
193
+{
194
+    $value = htmlentities ( $value );
195
+    return "<input type=\"hidden\" value=\"$value\" name=\"$flag\"></input>";
196
+}
197
+
198
+/**
199
+ * Return html code to create checkbox form input fields
200
+ *
201
+ * @param string $flag  name of form variable to set
202
+ * @param string $value "on" means box should be checked
203
+ *
204
+ * @return string html code for given hidden form input field
205
+ */
206
+function checkbox ( $flag, $value )
207
+{
208
+    return "<input type=\"checkbox\" value=\"on\" name=\"$flag\"" .
209
+        ($value == "on" ? " checked>" : ">" );
210
+}
211
+
212
+/**
213
+ * Return html code to create text form input fields
214
+ *
215
+ * @param string $flag  name of form variable to set
216
+ * @param string $value initial contents of field
217
+ * @param string $size  size in characters of text box
218
+ *
219
+ * @return string html code for given text input field
220
+ */
221
+function textbox ( $flag, $value, $size )
222
+{
223
+    $value = htmlentities ( $value );
224
+    return "<input type=\"text\" size=\"$size\" value=\"$value\" name=\"$flag\">";
225
+}
226
+
227
+/**
228
+ * Return html code to create textarea form fields
229
+ *
230
+ * @param string $flag  name of form variable to set
231
+ * @param string $value initial contents of textarea
232
+ * @param string $rows  height of text area in rows
233
+ * @param string $cols  width of text area in columns
234
+ *
235
+ * @return string html code for given textarea input field
236
+ */
237
+function textarea ( $flag, $value, $rows, $cols )
238
+{
239
+    $value = htmlentities ( $value );
240
+    return "<textarea name=\"$flag\" rows=\"$rows\" cols=\"$cols\">"
241
+            . $value . "</textarea>";
242
+}
243
+
244
+/**
245
+ * Return html code to create select (menu) form fields
246
+ *
247
+ * Use array of strings as menu choices
248
+ *
249
+ * @param string $flag    name of form variable to set
250
+ * @param array  $options array of strings representing choices
251
+ * @param string $value   value of choice to select in menu
252
+ *
253
+ * @return string html code for given select (menu) input field
254
+ */
255
+function menubox ( $name, $options, $value )
256
+{
257
+    $s="<select name=\"$name\">";
258
+
259
+	foreach ( $options as $ignore => $option ) {
260
+        if ( !$value ) $value = $option;
261
+        $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
262
+            htmlentities ( $option ) . "</option>";
263
+    }
264
+    return $s . "</select>";
265
+}
266
+
267
+/**
268
+ * Return html code to create select (menu) form fields
269
+ *
270
+ * Use indices of array of strings as menu choices rather than
271
+ * the values pointed to by the indicies.
272
+ *
273
+ * @param string $flag    name of form variable to set
274
+ * @param array  $options array of strings representing choices
275
+ * @param string $value   value of choice to select in menu
276
+ *
277
+ * @return string html code for given select (menu) input field
278
+ */
279
+function keys_menubox ( $name, $options, $value )
280
+{
281
+    $s="<select name=\"$name\">";
282
+
283
+    foreach ( $options as $option => $ignore ) {
284
+        if ( !$value ) $value = $option;
285
+        $s .= "<option" . ( $option == $value ? " selected>" : ">" ) .
286
+            htmlentities ( $option ) . "</option>";
287
+    }
288
+    return $s . "</select>";
289
+}
290
+
291
+////
292
+// Flag (compile option) handling functions
293
+////
294
+
295
+/**
296
+ * Return default compile options (flags)
297
+ *
298
+ * Initial compile options are in a global called $flag_table.
299
+ * Create and return an array containing the ones we want.
300
+ *
301
+ * @return array default compile options (flags)
302
+ */
303
+function default_flags ()
304
+{
305
+    global $flag_table;
306
+
307
+    $flags = array ();
308
+
309
+    foreach ( $flag_table as $key => $props ) {
310
+
311
+        $flag  = $props["flag"];
312
+        $type  = $props["type"];
313
+
314
+        // Fields like headers have no "value" property
315
+        if ( isset ( $props["value"] ) ) {
316
+            $flags[$flag] = $props["value"];
317
+        }
318
+    }
319
+    return $flags;
320
+}
321
+
322
+/**
323
+ * Return combination of default and user compile options (flags)
324
+ *
325
+ * Initial compile options are in a global called $flag_table.
326
+ * Compile options may have been changed via form input. We return
327
+ * an array with either the default value of each option or a user
328
+ * supplied value from form input.
329
+ *
330
+ * @return array combined default and user supplied compile options (flags)
331
+ */
332
+function get_flags ()
333
+{
334
+    global $flag_table;
335
+
336
+    $flags = default_flags ();
337
+
338
+    if ( ! isset ( $_POST["use_flags"] ) )
339
+        return $flags;
340
+
341
+    foreach ( $flag_table as $key => $props ) {
342
+
343
+        $flag = $props["flag"];
344
+        $type = $props["type"];
345
+
346
+        if ( isset ( $_POST["$flag"] ) ) {
347
+            $flags[$flag] = $_POST["$flag"];
348
+            if ( $type == "integer-hex" ) {
349
+                if ( strtolower ( substr ( $flags[$flag], 0, 2 ) ) != "0x" ) {
350
+                    $flags[$flag] = "0x" . $flags[$flag];
351
+                }
352
+            }
353
+        } else if ( $type == "on/off" ) {
354
+			// Unchecked checkboxes don't pass any POST value
355
+			// so we must check for them specially.  At this
356
+			// point we know that there is no $_POST value set
357
+			// for this option.  If it is a checkbox, this means
358
+			// it is unchecked, so record that in $flags so we
359
+			// can later generate an #undef for this option.
360
+            $flags[$flag] = "off";
361
+        }
362
+    }
363
+    return $flags;
364
+}
365
+
366
+/**
367
+ * Output given value in appropriate format for iPXE config file
368
+ *
369
+ * iPXE config/*.h files use C pre-processor syntax.  Output the given
370
+ * compile option in a format appropriate to its type
371
+ *
372
+ * @param string $key   index into $flag_table for given compile option
373
+ * @param string $value value we wish to set compile option to
374
+ *
375
+ * @return string code to set compile option to given value
376
+ */
377
+function pprint_flag ( $key, $value )
378
+{
379
+    global $flag_table;
380
+
381
+    // Determine type of given compile option (flag)
382
+    $type = $flag_table[$key]["type"];
383
+    $s = "";
384
+
385
+    if ( $type == "on/off" && $value == "on" ) {
386
+        $s = "#define $key";
387
+    } else if ( $type == "on/off" && $value != "on" ) {
388
+        $s = "#undef $key";
389
+    } else if ( $type == "string" ) {
390
+        $s = ( "#define $key \"" . cleanstring ( $value ) . "\"" );
391
+    } else if ($type == "qstring" ) {
392
+        $s = ( "#define $key \\\"" . cleanstring ( $value ) . "\\\"" );
393
+    } else {
394
+        $s = "#define $key " . cleanstring ( $value );
395
+    }
396
+
397
+    return $s;
398
+}
399
+
400
+/**
401
+ * Output html code to display all compile options as a table
402
+ *
403
+ * @param array $flags array of compile options
404
+ *
405
+ * @return void
406
+ */
407
+function echo_flags ( $flags )
408
+{
409
+    global $flag_table;
410
+
411
+    echo "<table>\n";
412
+
413
+	foreach ( $flag_table as $key => $props ) {
414
+
415
+        // Hide parameters from users that should not be changed.
416
+        $hide_from_user = isset ( $props["hide_from_user"] ) ? $props["hide_from_user"] : "no";
417
+
418
+        $flag = $props["flag"];
419
+        $type = $props["type"];
420
+
421
+        $value = isset ( $flags[$flag] ) ? $flags[$flag] : '';
422
+
423
+        if ( $hide_from_user == "yes" ) {
424
+
425
+            // Hidden flags cannot not be set by the user.  We use hidden form
426
+            // fields to keep them at their default values.
427
+            if ( $type != "header" ) {
428
+                echo hidden ( $flag, $value );
429
+            }
430
+
431
+        } else {
432
+
433
+            // Flag (iPXE compile option) should be displayed to user
434
+
435
+            if ( $type == "header" ) {
436
+
437
+                $label = $props["label"];
438
+                echo "<td colspan=2><hr><h3>$label</h3><hr></td>";
439
+
440
+            } else if ($type == "on/off" ) {
441
+
442
+                echo "<td>", checkbox ( $flag, $value ), "</td><td><strong>$flag</strong></td>";
443
+
444
+            } else {   // don't display checkbox for non-on/off flags
445
+
446
+                echo "<td>&nbsp;</td><td><strong>$flag: </strong>";
447
+
448
+                if ($type == "choice" ) {
449
+                    $options = $props["options"];
450
+                    echo menubox($flag, $options, $value);
451
+
452
+                } else {
453
+
454
+                    echo textbox($flag, $value, ($type == "integer" ||
455
+                                                 $type == "integer-hex"
456
+                                                     ? 7 : 25));
457
+                }
458
+                echo "</td>";
459
+            }
460
+            echo "</tr>\n";
461
+
462
+            if ( $type != "header" ) {
463
+				echo "<tr><td>&nbsp;</td>";
464
+				echo "<td>\n";
465
+				if ( is_file ( "doc/$flag.html" ) ) {
466
+					include_once "doc/$flag.html";
467
+				}
468
+				echo "\n</td></tr>\n";
469
+            }
470
+        }
471
+    }
472
+    echo "</table>";
473
+}
474
+
475
+/**
476
+ * Return an array of configuration sections used in all compile options
477
+ *
478
+ * $flag_table, the global list of compile options contains a 'cfgsec'
479
+ * property for each flag we are interested in.  We return a list of
480
+ * all the unique cfgsec options we find in $flag_table.
481
+ *
482
+ * @return array an array of strings representing all unique cfgsec values
483
+ *               found in $flag_table
484
+ */
485
+function get_flag_cfgsecs ()
486
+{
487
+    global $flag_table;
488
+    $cfgsecs = array ();
489
+
490
+    foreach ( $flag_table as $key => $props ) {
491
+        if ( isset ( $props['cfgsec'] ) ) {
492
+            $cfgsec = $props["cfgsec"];
493
+            $cfgsecs[$cfgsec] = $cfgsec;
494
+        }
495
+    }
496
+    return $cfgsecs;
497
+}
498
+
499
+////
500
+// File and directory handling functions
501
+////
502
+
503
+/**
504
+ * Create a copy of a given source directory to a given destination
505
+ *
506
+ * Since we are going to modify the source directory, we create a copy
507
+ * of the directory with a unique name in the given destination directory.
508
+ * We supply a prefix for the tempnam call to prepend to the random filename
509
+ * it generates.
510
+ *
511
+ * @param string $src    source directory
512
+ * @param string $dst    destination directory
513
+ * @param string $prefix string to append to directory created
514
+ *
515
+ * @return string absolute path to destination directory
516
+ */
517
+function mktempcopy ( $src, $dst, $prefix )
518
+{
519
+    if ( $src[0] != "/" ) {
520
+        $src = dirname ( $_SERVER['SCRIPT_FILENAME'] ) . "/" . $src;
521
+    }
522
+
523
+    // Create a file in the given destination directory with a unique name
524
+    $dir = tempnam ( $dst, $prefix );
525
+
526
+    // Delete the file just created, since it would interfere with the copy we
527
+    // are about to do.  We only care that the dir name we copy to is unique.
528
+    unlink ( $dir );
529
+
530
+    exec ( "/bin/cp -a '$src' '$dir' 2>&1", $cpytxt, $status );
531
+
532
+    if ( $status != 0 ) {
533
+        die ( "src directory copy failed!" );
534
+    }
535
+    return $dir;
536
+}
537
+
538
+/**
539
+ * Write iPXE config files based on value of given flags
540
+ *
541
+ * iPXE compile options are stored in src/config/*.h .
542
+ * We write out a config file for each set of options.
543
+ *
544
+ * @param string $config_dir directory to write .h files to
545
+ * @param array  $flags array of compile options for this build
546
+ *
547
+ * @return void
548
+ */
549
+function write_ipxe_config_files ( $config_dir, $flags )
550
+{
551
+    global $flag_table;
552
+
553
+    $cfgsecs = get_flag_cfgsecs ();
554
+
555
+    foreach ( $cfgsecs as $cfgsec ) {
556
+
557
+        $fname = $config_dir . "/" . $cfgsec . ".h";
558
+
559
+        $fp = fopen ( $fname, "wb" );
560
+        if ( $fp <= 0 ) {
561
+            die ( "Unable to open $fname file for output!" );
562
+        }
563
+
564
+        $ifdef_secname = "CONFIG_" . strtoupper ( $cfgsec ) . "_H";
565
+
566
+        fwrite ( $fp, "#ifndef ${ifdef_secname}\n" );
567
+        fwrite ( $fp, "#define ${ifdef_secname}\n" );
568
+        fwrite ( $fp, "#include <config/defaults.h>\n" );
569
+
570
+        foreach ( $flags as $key => $value ) {
571
+            // When the flag matches this section name, write it out
572
+            if ( $flag_table[$key]["cfgsec"] == $cfgsec ) {
573
+                fwrite ( $fp, pprint_flag ( $key, $value ) . "\n" );
574
+            }
575
+        }
576
+        fwrite ( $fp, "#endif /* ${ifdef_secname} */\n" );
577
+        fclose ( $fp );
578
+    }
579
+}
580
+
581
+/**
582
+ * Output a string to a file
583
+ *
584
+ * Output a given string to a given pathname. The file will be created if
585
+ * necessary, and the string will replace the file's contents in all cases.
586
+ *
587
+ * @param string $fname pathname of file to output string to
588
+ * @param string $ftext text to output to file
589
+ *
590
+ * @return void
591
+ */
592
+function write_file_from_string ( $fname, $ftext )
593
+{
594
+        $fp = fopen ( $fname, "wb" );
595
+        if ( ! $fp ) {
596
+            die ( "Unable to open $fname file for output!" );
597
+        }
598
+        fwrite ( $fp, $ftext );
599
+        fclose ( $fp );
600
+}
601
+
602
+/**
603
+ * Delete a file or recursively delete a directory tree
604
+ *
605
+ * @param   string   $file_or_dir_name  name of file or directory to delete
606
+ * @return  bool     Returns TRUE on success, FALSE on failure
607
+ */
608
+function rm_file_or_dir ( $file_or_dir_name )
609
+{
610
+    if ( ! file_exists ( $file_or_dir_name ) ) {
611
+        return false;
612
+    }
613
+
614
+    if ( is_file ( $file_or_dir_name ) || is_link ( $file_or_dir_name ) ) {
615
+        return unlink ( $file_or_dir_name );
616
+    }
617
+
618
+    $dir = dir ( $file_or_dir_name );
619
+    while ( ( $dir_entry = $dir->read () ) !== false ) {
620
+
621
+        if ( $dir_entry == '.' || $dir_entry == '..') {
622
+            continue;
623
+        }
624
+        rm_file_or_dir ( $file_or_dir_name . '/' . $dir_entry );
625
+    }
626
+    $dir->close();
627
+
628
+    return rmdir ( $file_or_dir_name );
629
+}
630
+
631
+////
632
+// Debugging functions
633
+////
634
+
635
+/**
636
+ * Emit html code to display given array of compile options (flags)
637
+ *
638
+ * @param array  $flags array of compile options for this build
639
+ *
640
+ * @return void
641
+ */
642
+function show_flags ( $flags )
643
+{
644
+    echo ( "\$flags contains " . count ( $flags ) . " elements:" . "<br>" );
645
+
646
+	foreach ( $flags as $key => $flag ) {
647
+        echo ( "\$flags[" . $key . "]=" . "\"$flag\"" . "<br>" );
648
+    }
649
+}
650
+
651
+/**
652
+ * Emit HTML code to display default array of compile options (flags)
653
+ *
654
+ * $flag_table contains default compile options and properties.  This
655
+ * routine outputs HTML code to display all properties of $flag_table.
656
+ *
657
+ * @return void
658
+ */
659
+function dump_flag_table ()
660
+{
661
+    global $flag_table;
662
+
663
+    echo ( "\$flag_table contains " . count ( $flag_table ) . " elements:" . "<br>" );
664
+
665
+	foreach ( $flag_table as $key => $props ) {
666
+        print ( "flag_table[" . $key . "] = " . "<br>" );
667
+
668
+		foreach ( $props as $key2 => $props2 ) {
669
+            print ( "&nbsp;&nbsp;&nbsp;" . $key2 . " = " . $props2 . "<br>" );
670
+        }
671
+    }
672
+}
673
+
674
+// Parse src/bin/NIC file
675
+list ( $nics, $roms ) = parse_nic_file ();
676
+
677
+// For emacs:
678
+// Local variables:
679
+//  c-basic-offset: 4
680
+//  c-indent-level: 4
681
+//  tab-width: 4
682
+// End:
683
+
684
+?>

+ 6
- 0
contrib/vm/.gitignore View File

@@ -0,0 +1,6 @@
1
+bochsout.txt
2
+parport.out
3
+ne2k-tx.log
4
+ne2k-txdump.txt
5
+bochs
6
+qemu

+ 7
- 0
contrib/vm/Makefile View File

@@ -0,0 +1,7 @@
1
+all : serial-console.1
2
+
3
+%.1 : %
4
+	pod2man $< > $@
5
+
6
+clean :
7
+	rm -f serial-console.1

+ 15
- 0
contrib/vm/bochs-writable-ROM-patch View File

@@ -0,0 +1,15 @@
1
+--- memory/memory.cc	18 Oct 2008 18:10:14 -0000	1.71
2
++++ memory/memory.cc	21 Oct 2008 19:47:07 -0000
3
+@@ -172,7 +172,11 @@
4
+             break;
5
+
6
+           case 0x0:   // Writes to ROM, Inhibit
7
+-            BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
8
++            if ((a20addr & 0xfffe0000) == 0x000e0000) {
9
++	      BX_DEBUG(("Write to ROM ignored: address 0x" FMT_PHY_ADDRX ", data %02x", a20addr, *data_ptr));
10
++	    } else {
11
++	      BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ] = *data_ptr;
12
++            }
13
+             break;
14
+
15
+           default:

+ 1131
- 0
contrib/vm/bochsrc.txt
File diff suppressed because it is too large
View File


+ 49
- 0
contrib/vm/cow View File

@@ -0,0 +1,49 @@
1
+#!/bin/sh
2
+
3
+set -e
4
+
5
+imgloop=
6
+tmpfile=
7
+tmploop=
8
+dmname=
9
+cowlink=
10
+
11
+function cleanup () {
12
+    set +e
13
+    [ -n "$cowlink" ] && rm $cowlink
14
+    [ -n "$dmname" ] && dmsetup remove $dmname
15
+    [ -n "$tmploop" ] && losetup -d $tmploop
16
+    [ -n "$tmpfile" ] && rm $tmpfile
17
+    [ -n "$imgloop" ] && losetup -d $imgloop
18
+}
19
+
20
+trap cleanup EXIT
21
+
22
+imgfile=$1 ; shift
23
+command=$1 ; shift
24
+if [ -z "$imgfile" -o -z "$command" ] ; then
25
+    echo Syntax: $0 /path/to/image/file command [args..]
26
+    exit 1
27
+fi
28
+
29
+# Set up image loop device
30
+x=`losetup -f` ; losetup -r $x $imgfile ; imgloop=$x
31
+
32
+# Create temporary file and set up temporary loop device
33
+tmpfile=`mktemp $imgfile.XXXXXXXXXX`
34
+truncate -r $imgfile $tmpfile
35
+x=`losetup -f` ; losetup $x $tmpfile ; tmploop=$x
36
+
37
+# Create snapshot device
38
+imgsize=`blockdev --getsz $imgloop`
39
+x=`basename $imgfile` ; echo 0 $imgsize snapshot $imgloop $tmploop N 16 | \
40
+    dmsetup create $x ; dmname=$x
41
+chown --reference=$imgfile /dev/mapper/$dmname
42
+chmod --reference=$imgfile /dev/mapper/$dmname
43
+
44
+# Create symlink
45
+x=$imgfile.cow ; ln -s /dev/mapper/$dmname $x ; cowlink=$x
46
+
47
+# Wait until killed
48
+echo "Created $cowlink"
49
+$command "$@" $cowlink

+ 278
- 0
contrib/vm/serial-console View File

@@ -0,0 +1,278 @@
1
+#!/usr/bin/perl -w
2
+
3
+=head1 NAME
4
+
5
+serial-console
6
+
7
+=head1 SYNOPSIS
8
+
9
+serial-console [options]
10
+
11
+Options:
12
+
13
+    -h,--help         Display brief help message
14
+    -v,--verbose      Increase verbosity
15
+    -q,--quiet        Decrease verbosity
16
+    -l,--log FILE     Log output to file
17
+    -r,--rcfile	FILE  Modify specified bochsrc file
18
+
19
+=head1 DESCRIPTION
20
+
21
+C<serial-console> provides a virtual serial console for use with
22
+Bochs.  Running C<serial-console> creates a pseudo-tty.  The master
23
+side of this pty is made available to the user for interaction; the
24
+slave device is written to the Bochs configuration file
25
+(C<bochsrc.txt>) for use by a subsequent Bochs session.
26
+
27
+=head1 EXAMPLES
28
+
29
+=over 4
30
+
31
+=item C<serial-console>
32
+
33
+Create a virtual serial console for Bochs, modify C<bochsrc.txt>
34
+appropriately.
35
+
36
+=item C<serial-console -r ../.bochsrc -l serial.log>
37
+
38
+Create a virtual serial console for Bochs, modify C<../.bochsrc>
39
+appropriately, log output to C<serial.log>.
40
+
41
+=back
42
+
43
+=head1 INVOCATION
44
+
45
+Before starting Bochs, run C<serial-console> in a different session
46
+(e.g. a different xterm window).  When you subsequently start Bochs,
47
+anything that the emulated machine writes to its serial port will
48
+appear in the window running C<serial-console>, and anything typed in
49
+the C<serial-console> window will arrive on the emulated machine's
50
+serial port.
51
+
52
+You do B<not> need to rerun C<serial-console> afresh for each Bochs
53
+session.
54
+
55
+=head1 OPTIONS
56
+
57
+=over 4
58
+
59
+=item B<-l,--log FILE>
60
+
61
+Log all output (i.e. everything that is printed in the
62
+C<serial-console> window) to the specified file.
63
+
64
+=item B<-r,--rcfile FILE>
65
+
66
+Modify the specified bochsrc file.  The file will be updated to
67
+contain the path to the slave side of the psuedo tty that we create.
68
+The original file will be restored when C<serial-console> exits.  The
69
+default is to modify the file C<bochsrc.txt> in the current directory.
70
+
71
+To avoid modifying any bochsrc file, use C<--norcfile>.
72
+
73
+=back
74
+
75
+=cut
76
+
77
+use IO::Pty;
78
+use IO::Select;
79
+use File::Spec::Functions qw ( :ALL );
80
+use Getopt::Long;
81
+use Pod::Usage;
82
+use POSIX qw ( :termios_h );
83
+use strict;
84
+use warnings;
85
+
86
+my $o;
87
+my $restore_file = {};
88
+my $restore_termios;
89
+use constant BLOCKSIZE => 8192;
90
+
91
+##############################################################################
92
+#
93
+# Parse command line options into options hash ($o)
94
+#
95
+# $o = parse_opts();
96
+
97
+sub parse_opts {
98
+  # $o is the hash that will hold the options
99
+  my $o = {
100
+    verbosity => 1,
101
+    rcfile => 'bochsrc.txt',
102
+  };
103
+  # Special handlers for some options
104
+  my $opt_handlers = {
105
+    verbose => sub { $o->{verbosity}++; },
106
+    quiet => sub { $o->{verbosity}--; },
107
+    help => sub { pod2usage(1); },
108
+    norcfile => sub { delete $o->{rcfile}; },
109
+  };
110
+  # Merge handlers into main options hash (so that Getopt::Long can find them)
111
+  $o->{$_} = $opt_handlers->{$_} foreach keys %$opt_handlers;
112
+  # Option specifiers for Getopt::Long
113
+  my @optspec = ( 'help|h|?',
114
+                  'quiet|q+',
115
+                  'verbose|v+',
116
+		  'log|l=s',
117
+		  'rcfile|r=s',
118
+		  'norcfile',
119
+                  );
120
+  # Do option parsing
121
+  Getopt::Long::Configure ( 'bundling' );
122
+  pod2usage("Error parsing command-line options") unless GetOptions (
123
+  $o, @optspec );
124
+  # Clean up $o by removing the handlers
125
+  delete $o->{$_} foreach keys %$opt_handlers;
126
+  return $o;
127
+}
128
+
129
+##############################################################################
130
+#
131
+# Modify bochsrc file
132
+
133
+sub patch_bochsrc {
134
+  my $active = shift;
135
+  my $pty = shift;
136
+
137
+  # Rename active file to backup file
138
+  ( my $vol, my $dir, my $file ) = splitpath ( $active );
139
+  $file = '.'.$file.".serial-console";
140
+  my $backup = catpath ( $vol, $dir, $file );
141
+  rename $active, $backup
142
+      or die "Could not back up $active to $backup: $!\n";
143
+
144
+  # Derive line to be inserted
145
+  my $patch = "com1: enabled=1, mode=term, dev=$pty\n";
146
+
147
+  # Modify file
148
+  open my $old, "<$backup" or die "Could not open $backup: $!\n";
149
+  open my $new, ">$active" or die "Could not open $active: $!\n";
150
+  print $new <<"EOF";
151
+##################################################
152
+#
153
+# This file has been modified by serial-console.
154
+#
155
+# Do not modify this file; it will be erased when
156
+# serial-console (pid $$) exits and will be
157
+# replaced with the backup copy held in
158
+# $backup.
159
+#
160
+##################################################
161
+
162
+
163
+EOF
164
+  my $patched;
165
+  while ( my $line = <$old> ) {
166
+    if ( $line =~ /^\s*\#?\s*com1:\s*\S/ ) {
167
+      if ( ! $patched ) {
168
+	$line = $patch;
169
+	$patched = 1;
170
+      } else {
171
+	$line = '# '.$line unless $line =~ /^\s*\#/;
172
+      }
173
+    }
174
+    print $new $line;
175
+  }
176
+  print $new $patch unless $patched;
177
+  close $old;
178
+  close $new;
179
+
180
+  return $backup;
181
+}
182
+
183
+##############################################################################
184
+#
185
+# Attach/detach message printing and terminal settings
186
+
187
+sub bochs_attached {
188
+  print STDERR "Bochs attached.\n\n\n"
189
+      if $o->{verbosity} >= 1;
190
+}
191
+
192
+sub bochs_detached {
193
+  print STDERR "\n\nWaiting for bochs to attach...\n"
194
+      if $o->{verbosity} >= 1;
195
+}
196
+
197
+##############################################################################
198
+#
199
+# Main program
200
+
201
+$o = parse_opts();
202
+pod2usage(1) if @ARGV;
203
+
204
+# Catch signals
205
+my $sigdie = sub { die "Exiting via signal\n"; };
206
+$SIG{INT} = $sigdie;
207
+
208
+# Create Pty, close slave side
209
+my $pty = IO::Pty->new();
210
+$pty->close_slave();
211
+$pty->set_raw();
212
+print STDERR "Slave pty is ".$pty->ttyname."\n" if $o->{verbosity} >= 1;
213
+
214
+# Open logfile
215
+my $log;
216
+if ( $o->{log} ) {
217
+  open $log, ">$o->{log}" or die "Could not open $o->{log}: $!\n";
218
+}
219
+
220
+# Set up terminal
221
+my $termios;
222
+if ( -t STDIN ) {
223
+  $termios = POSIX::Termios->new;
224
+  $restore_termios = POSIX::Termios->new;
225
+  $termios->getattr ( fileno(STDIN) );
226
+  $restore_termios->getattr ( fileno(STDIN) );
227
+  $termios->setlflag ( $termios->getlflag & ~(ICANON) & ~(ECHO) );
228
+  $termios->setiflag ( $termios->getiflag & ~(ICRNL) );
229
+  $termios->setattr ( fileno(STDIN), TCSANOW );
230
+}
231
+
232
+# Modify bochsrc file
233
+$restore_file = { $o->{rcfile} =>
234
+		  patch_bochsrc ( $o->{rcfile}, $pty->ttyname ) }
235
+    if $o->{rcfile};
236
+
237
+# Start character shunt
238
+my $attached = 1;
239
+my $select = IO::Select->new ( \*STDIN, $pty );
240
+while ( 1 ) {
241
+  my %can_read = map { $_ => 1 }
242
+		     $select->can_read ( $attached ? undef : 1 );
243
+  if ( $can_read{\*STDIN} ) {
244
+    sysread ( STDIN, my $data, BLOCKSIZE )
245
+	or die "Cannot read from STDIN: $!\n";
246
+    $pty->syswrite ( $data );
247
+  }
248
+  if ( $can_read{$pty} ) {
249
+    if ( $pty->sysread ( my $data, BLOCKSIZE ) ) {
250
+      # Actual data available
251
+      bochs_attached() if $attached == 0;
252
+      $attached = 1;
253
+      syswrite ( STDOUT, $data );
254
+      $log->syswrite ( $data ) if $log;
255
+    } else {
256
+      # No data available but select() says we can read.  This almost
257
+      # certainly indicates that nothing is attached to the slave.
258
+      bochs_detached() if $attached == 1;
259
+      $attached = 0;
260
+      sleep ( 1 );
261
+    }
262
+  } else {
263
+    bochs_attached() if $attached == 0;
264
+    $attached = 1;
265
+  }
266
+}
267
+
268
+END {
269
+  # Restore bochsrc file if applicable
270
+  if ( ( my $orig_file, my $backup_file ) = %$restore_file ) {
271
+    unlink $orig_file;
272
+    rename $backup_file, $orig_file;
273
+  }
274
+  # Restore terminal settings if applicable
275
+  if ( $restore_termios ) {
276
+    $restore_termios->setattr ( fileno(STDIN), TCSANOW );
277
+  }
278
+}

+ 190
- 0
contrib/vm/serial-console.1 View File

@@ -0,0 +1,190 @@
1
+.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
2
+.\"
3
+.\" Standard preamble:
4
+.\" ========================================================================
5
+.de Sp \" Vertical space (when we can't use .PP)
6
+.if t .sp .5v
7
+.if n .sp
8
+..
9
+.de Vb \" Begin verbatim text
10
+.ft CW
11
+.nf
12
+.ne \\$1
13
+..
14
+.de Ve \" End verbatim text
15
+.ft R
16
+.fi
17
+..
18
+.\" Set up some character translations and predefined strings.  \*(-- will
19
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
20
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
21
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
22
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
23
+.\" nothing in troff, for use with C<>.
24
+.tr \(*W-
25
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
26
+.ie n \{\
27
+.    ds -- \(*W-
28
+.    ds PI pi
29
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
30
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
31
+.    ds L" ""
32
+.    ds R" ""
33
+.    ds C` ""
34
+.    ds C' ""
35
+'br\}
36
+.el\{\
37
+.    ds -- \|\(em\|
38
+.    ds PI \(*p
39
+.    ds L" ``
40
+.    ds R" ''
41
+'br\}
42
+.\"
43
+.\" Escape single quotes in literal strings from groff's Unicode transform.
44
+.ie \n(.g .ds Aq \(aq
45
+.el       .ds Aq '
46
+.\"
47
+.\" If the F register is turned on, we'll generate index entries on stderr for
48
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
49
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
50
+.\" output yourself in some meaningful fashion.
51
+.ie \nF \{\
52
+.    de IX
53
+.    tm Index:\\$1\t\\n%\t"\\$2"
54
+..
55
+.    nr % 0
56
+.    rr F
57
+.\}
58
+.el \{\
59
+.    de IX
60
+..
61
+.\}
62
+.\"
63
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
64
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
65
+.    \" fudge factors for nroff and troff
66
+.if n \{\
67
+.    ds #H 0
68
+.    ds #V .8m
69
+.    ds #F .3m
70
+.    ds #[ \f1
71
+.    ds #] \fP
72
+.\}
73
+.if t \{\
74
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
75
+.    ds #V .6m
76
+.    ds #F 0
77
+.    ds #[ \&
78
+.    ds #] \&
79
+.\}
80
+.    \" simple accents for nroff and troff
81
+.if n \{\
82
+.    ds ' \&
83
+.    ds ` \&
84
+.    ds ^ \&
85
+.    ds , \&
86
+.    ds ~ ~
87
+.    ds /
88
+.\}
89
+.if t \{\
90
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
91
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
92
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
93
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
94
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
95
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
96
+.\}
97
+.    \" troff and (daisy-wheel) nroff accents
98
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
99
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
100
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
101
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
102
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
103
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
104
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
105
+.ds ae a\h'-(\w'a'u*4/10)'e
106
+.ds Ae A\h'-(\w'A'u*4/10)'E
107
+.    \" corrections for vroff
108
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
109
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
110
+.    \" for low resolution devices (crt and lpr)
111
+.if \n(.H>23 .if \n(.V>19 \
112
+\{\
113
+.    ds : e
114
+.    ds 8 ss
115
+.    ds o a
116
+.    ds d- d\h'-1'\(ga
117
+.    ds D- D\h'-1'\(hy
118
+.    ds th \o'bp'
119
+.    ds Th \o'LP'
120
+.    ds ae ae
121
+.    ds Ae AE
122
+.\}
123
+.rm #[ #] #H #V #F C
124
+.\" ========================================================================
125
+.\"
126
+.IX Title "SERIAL-CONSOLE 1"
127
+.TH SERIAL-CONSOLE 1 "2010-09-22" "perl v5.10.1" "User Contributed Perl Documentation"
128
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
129
+.\" way too many mistakes in technical documents.
130
+.if n .ad l
131
+.nh
132
+.SH "NAME"
133
+serial\-console
134
+.SH "SYNOPSIS"
135
+.IX Header "SYNOPSIS"
136
+serial-console [options]
137
+.PP
138
+Options:
139
+.PP
140
+.Vb 5
141
+\&    \-h,\-\-help         Display brief help message
142
+\&    \-v,\-\-verbose      Increase verbosity
143
+\&    \-q,\-\-quiet        Decrease verbosity
144
+\&    \-l,\-\-log FILE     Log output to file
145
+\&    \-r,\-\-rcfile FILE  Modify specified bochsrc file
146
+.Ve
147
+.SH "DESCRIPTION"
148
+.IX Header "DESCRIPTION"
149
+\&\f(CW\*(C`serial\-console\*(C'\fR provides a virtual serial console for use with
150
+Bochs.  Running \f(CW\*(C`serial\-console\*(C'\fR creates a pseudo-tty.  The master
151
+side of this pty is made available to the user for interaction; the
152
+slave device is written to the Bochs configuration file
153
+(\f(CW\*(C`bochsrc.txt\*(C'\fR) for use by a subsequent Bochs session.
154
+.SH "EXAMPLES"
155
+.IX Header "EXAMPLES"
156
+.ie n .IP """serial\-console""" 4
157
+.el .IP "\f(CWserial\-console\fR" 4
158
+.IX Item "serial-console"
159
+Create a virtual serial console for Bochs, modify \f(CW\*(C`bochsrc.txt\*(C'\fR
160
+appropriately.
161
+.ie n .IP """serial\-console \-r ../.bochsrc \-l serial.log""" 4
162
+.el .IP "\f(CWserial\-console \-r ../.bochsrc \-l serial.log\fR" 4
163
+.IX Item "serial-console -r ../.bochsrc -l serial.log"
164
+Create a virtual serial console for Bochs, modify \f(CW\*(C`../.bochsrc\*(C'\fR
165
+appropriately, log output to \f(CW\*(C`serial.log\*(C'\fR.
166
+.SH "INVOCATION"
167
+.IX Header "INVOCATION"
168
+Before starting Bochs, run \f(CW\*(C`serial\-console\*(C'\fR in a different session
169
+(e.g. a different xterm window).  When you subsequently start Bochs,
170
+anything that the emulated machine writes to its serial port will
171
+appear in the window running \f(CW\*(C`serial\-console\*(C'\fR, and anything typed in
172
+the \f(CW\*(C`serial\-console\*(C'\fR window will arrive on the emulated machine's
173
+serial port.
174
+.PP
175
+You do \fBnot\fR need to rerun \f(CW\*(C`serial\-console\*(C'\fR afresh for each Bochs
176
+session.
177
+.SH "OPTIONS"
178
+.IX Header "OPTIONS"
179
+.IP "\fB\-l,\-\-log \s-1FILE\s0\fR" 4
180
+.IX Item "-l,--log FILE"
181
+Log all output (i.e. everything that is printed in the
182
+\&\f(CW\*(C`serial\-console\*(C'\fR window) to the specified file.
183
+.IP "\fB\-r,\-\-rcfile \s-1FILE\s0\fR" 4
184
+.IX Item "-r,--rcfile FILE"
185
+Modify the specified bochsrc file.  The file will be updated to
186
+contain the path to the slave side of the psuedo tty that we create.
187
+The original file will be restored when \f(CW\*(C`serial\-console\*(C'\fR exits.  The
188
+default is to modify the file \f(CW\*(C`bochsrc.txt\*(C'\fR in the current directory.
189
+.Sp
190
+To avoid modifying any bochsrc file, use \f(CW\*(C`\-\-norcfile\*(C'\fR.

+ 4
- 0
src/.gitignore View File

@@ -0,0 +1,4 @@
1
+.toolcheck
2
+.echocheck
3
+TAGS*
4
+bin*

+ 211
- 0
src/Makefile View File

@@ -0,0 +1,211 @@
1
+###############################################################################
2
+#
3
+# Initialise various variables
4
+#
5
+
6
+CLEANUP		:=
7
+CFLAGS		:=
8
+ASFLAGS		:=
9
+LDFLAGS		:=
10
+HOST_CFLAGS	:=
11
+MAKEDEPS	:= Makefile
12
+
13
+###############################################################################
14
+#
15
+# Locations of tools
16
+#
17
+HOST_CC		:= gcc
18
+RM		:= rm -f
19
+TOUCH		:= touch
20
+MKDIR		:= mkdir
21
+CP		:= cp
22
+ECHO		:= echo
23
+PRINTF		:= printf
24
+PERL		:= perl
25
+TRUE		:= true
26
+CC		:= $(CROSS_COMPILE)gcc
27
+CPP		:= $(CC) -E
28
+AS		:= $(CROSS_COMPILE)as
29
+LD		:= $(CROSS_COMPILE)ld
30
+SIZE		:= $(CROSS_COMPILE)size
31
+AR		:= $(CROSS_COMPILE)ar
32
+RANLIB		:= $(CROSS_COMPILE)ranlib
33
+OBJCOPY		:= $(CROSS_COMPILE)objcopy
34
+NM		:= $(CROSS_COMPILE)nm
35
+OBJDUMP		:= $(CROSS_COMPILE)objdump
36
+OPENSSL		:= openssl
37
+CSPLIT		:= csplit
38
+PARSEROM	:= ./util/parserom.pl
39
+FIXROM		:= ./util/fixrom.pl
40
+SYMCHECK	:= ./util/symcheck.pl
41
+SORTOBJDUMP	:= ./util/sortobjdump.pl
42
+PADIMG		:= ./util/padimg.pl
43
+LICENCE		:= ./util/licence.pl
44
+NRV2B		:= ./util/nrv2b
45
+ZBIN		:= ./util/zbin
46
+ELF2EFI32	:= ./util/elf2efi32
47
+ELF2EFI64	:= ./util/elf2efi64
48
+EFIROM		:= ./util/efirom
49
+EFIFATBIN	:= ./util/efifatbin
50
+ICCFIX		:= ./util/iccfix
51
+EINFO		:= ./util/einfo
52
+GENKEYMAP	:= ./util/genkeymap.pl
53
+DOXYGEN		:= doxygen
54
+LCAB		:= lcab
55
+BINUTILS_DIR	:= /usr
56
+BFD_DIR		:= $(BINUTILS_DIR)
57
+ZLIB_DIR	:= /usr
58
+
59
+###############################################################################
60
+#
61
+# SRCDIRS lists all directories containing source files.
62
+#
63
+SRCDIRS		:=
64
+SRCDIRS		+= libgcc
65
+SRCDIRS		+= core
66
+SRCDIRS		+= net net/oncrpc net/tcp net/udp net/infiniband net/80211
67
+SRCDIRS		+= image
68
+SRCDIRS		+= drivers/bus
69
+SRCDIRS		+= drivers/net
70
+SRCDIRS		+= drivers/net/e1000
71
+SRCDIRS		+= drivers/net/e1000e
72
+SRCDIRS		+= drivers/net/igb
73
+SRCDIRS		+= drivers/net/igbvf
74
+SRCDIRS		+= drivers/net/phantom
75
+SRCDIRS		+= drivers/net/rtl818x
76
+SRCDIRS		+= drivers/net/ath
77
+SRCDIRS		+= drivers/net/ath/ath5k
78
+SRCDIRS		+= drivers/net/ath/ath9k
79
+SRCDIRS		+= drivers/net/vxge
80
+SRCDIRS		+= drivers/net/efi
81
+SRCDIRS		+= drivers/net/tg3
82
+SRCDIRS		+= drivers/block
83
+SRCDIRS		+= drivers/nvs
84
+SRCDIRS		+= drivers/bitbash
85
+SRCDIRS		+= drivers/infiniband
86
+SRCDIRS		+= drivers/usb
87
+SRCDIRS		+= interface/pxe interface/efi interface/smbios
88
+SRCDIRS		+= interface/bofm
89
+SRCDIRS		+= interface/xen
90
+SRCDIRS		+= interface/hyperv
91
+SRCDIRS		+= tests
92
+SRCDIRS		+= crypto crypto/mishmash
93
+SRCDIRS		+= hci hci/commands hci/tui
94
+SRCDIRS		+= hci/mucurses hci/mucurses/widgets
95
+SRCDIRS		+= hci/keymap
96
+SRCDIRS		+= usr
97
+SRCDIRS		+= config
98
+
99
+# NON_AUTO_SRCS lists files that are excluded from the normal
100
+# automatic build system.
101
+#
102
+NON_AUTO_SRCS	:=
103
+NON_AUTO_SRCS	+= core/version.c
104
+NON_AUTO_SRCS	+= drivers/net/prism2.c
105
+
106
+# INCDIRS lists the include path
107
+#
108
+INCDIRS		:=
109
+INCDIRS		+= include .
110
+
111
+###############################################################################
112
+#
113
+# Default build target: build the most common targets and print out a
114
+# helpfully suggestive message
115
+#
116
+ALL		:= bin/blib.a bin/ipxe.dsk bin/ipxe.lkrn bin/ipxe.iso \
117
+		   bin/ipxe.usb bin/ipxe.pxe bin/undionly.kpxe bin/rtl8139.rom \
118
+		   bin/8086100e.mrom bin/80861209.rom bin/10500940.rom \
119
+		   bin/10222000.rom bin/10ec8139.rom bin/1af41000.rom \
120
+		   bin/8086100f.mrom bin/808610d3.mrom bin/15ad07b0.rom
121
+
122
+all : $(ALL)
123
+	@$(ECHO) '==========================================================='
124
+	@$(ECHO)
125
+	@$(ECHO) 'To create a bootable floppy, type'
126
+	@$(ECHO) '    cat bin/ipxe.dsk > /dev/fd0'
127
+	@$(ECHO) 'where /dev/fd0 is your floppy drive.  This will erase any'
128
+	@$(ECHO) 'data already on the disk.'
129
+	@$(ECHO)
130
+	@$(ECHO) 'To create a bootable USB key, type'
131
+	@$(ECHO) '    cat bin/ipxe.usb > /dev/sdX'
132
+	@$(ECHO) 'where /dev/sdX is your USB key, and is *not* a real hard'
133
+	@$(ECHO) 'disk on your system.  This will erase any data already on'
134
+	@$(ECHO) 'the USB key.'
135
+	@$(ECHO)
136
+	@$(ECHO) 'To create a bootable CD-ROM, burn the ISO image '
137
+	@$(ECHO) 'bin/ipxe.iso to a blank CD-ROM.'
138
+	@$(ECHO)
139
+	@$(ECHO) 'These images contain drivers for all supported cards.  You'
140
+	@$(ECHO) 'can build more customised images, and ROM images, using'
141
+	@$(ECHO) '    make bin/<rom-name>.<output-format>'
142
+	@$(ECHO)
143
+	@$(ECHO) '==========================================================='
144
+
145
+###############################################################################
146
+#
147
+# Comprehensive build target: build a selection of cross-platform
148
+# targets to expose potential build errors that show up only on
149
+# certain platforms
150
+#
151
+everything :
152
+	$(Q)$(MAKE) --no-print-directory $(ALL) \
153
+		bin/3c509.rom bin/intel.rom bin/intel.mrom \
154
+		bin-i386-efi/ipxe.efi bin-i386-efi/ipxe.efidrv \
155
+		bin-i386-efi/ipxe.efirom \
156
+		bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \
157
+		bin-x86_64-efi/ipxe.efirom \
158
+		bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux \
159
+		bin-i386-linux/tests.linux bin-x86_64-linux/tests.linux
160
+
161
+###############################################################################
162
+#
163
+# VMware build target: all ROMs used with VMware
164
+#
165
+vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
166
+	@$(ECHO) '==========================================================='
167
+	@$(ECHO) 
168
+	@$(ECHO) 'Available ROMs:'
169
+	@$(ECHO) '    bin/8086100f.mrom -- intel/e1000'
170
+	@$(ECHO) '    bin/808610d3.mrom -- intel/e1000e'
171
+	@$(ECHO) '    bin/10222000.rom  -- vlance/pcnet32'
172
+	@$(ECHO) '    bin/15ad07b0.rom  -- vmxnet3'
173
+	@$(ECHO) 
174
+	@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
175
+	@$(ECHO)
176
+	@$(ECHO) '==========================================================='
177
+
178
+###############################################################################
179
+#
180
+# Build targets that do nothing but might be tried by users
181
+#
182
+configure :
183
+	@$(ECHO) "No configuration needed."
184
+
185
+install :
186
+	@$(ECHO) "No installation required."
187
+
188
+###############################################################################
189
+#
190
+# Version number calculations
191
+#
192
+VERSION_MAJOR	= 1
193
+VERSION_MINOR	= 0
194
+VERSION_PATCH	= 0
195
+EXTRAVERSION	= +
196
+MM_VERSION	= $(VERSION_MAJOR).$(VERSION_MINOR)
197
+VERSION		= $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
198
+ifneq ($(wildcard ../.git),)
199
+GITVERSION := $(shell git describe --always --abbrev=1 --match "" 2>/dev/null)
200
+VERSION		+= ($(GITVERSION))
201
+endif
202
+version :
203
+	@$(ECHO) "$(VERSION)"
204
+
205
+###############################################################################
206
+#
207
+# Drag in the bulk of the build system
208
+#
209
+
210
+MAKEDEPS	+= Makefile.housekeeping
211
+include Makefile.housekeeping

+ 1485
- 0
src/Makefile.housekeeping
File diff suppressed because it is too large
View File


+ 128
- 0
src/arch/i386/Makefile View File

@@ -0,0 +1,128 @@
1
+# Force i386-only instructions
2
+#
3
+CFLAGS		+= -march=i386
4
+
5
+# Code size reduction.
6
+#
7
+CFLAGS		+= -fomit-frame-pointer
8
+
9
+# Code size reduction.
10
+#
11
+ifeq ($(CCTYPE),gcc)
12
+CFLAGS		+= -fstrength-reduce
13
+endif
14
+
15
+# Code size reduction.  gcc3 needs a different syntax to gcc2 if you
16
+# want to avoid spurious warnings.
17
+#
18
+ifeq ($(CCTYPE),gcc)
19
+GCC_VERSION	:= $(subst ., ,$(shell $(CC) -dumpversion))
20
+GCC_MAJOR	:= $(firstword $(GCC_VERSION))
21
+ifeq ($(GCC_MAJOR),2)
22
+CFLAGS		+= -malign-jumps=1 -malign-loops=1 -malign-functions=1
23
+else
24
+CFLAGS		+= -falign-jumps=1 -falign-loops=1 -falign-functions=1
25
+endif # gcc2
26
+endif # gcc
27
+
28
+# Code size reduction.  This is almost always a win.  The kernel uses
29
+# it, too.
30
+#
31
+ifeq ($(CCTYPE),gcc)
32
+CFLAGS		+= -mpreferred-stack-boundary=2
33
+endif
34
+
35
+# Code size reduction.  Use regparm for all functions - C functions
36
+# called from assembly (or vice versa) need __asmcall now
37
+#
38
+CFLAGS		+= -mregparm=3
39
+
40
+# Code size reduction.  Use -mrtd (same __asmcall requirements as above)
41
+ifeq ($(CCTYPE),gcc)
42
+CFLAGS		+= -mrtd
43
+endif
44
+
45
+# Code size reduction.  This is the logical complement to -mregparm=3.
46
+# It doesn't currently buy us anything, but if anything ever tries to
47
+# return small structures, let's be prepared
48
+#
49
+CFLAGS		+= -freg-struct-return
50
+
51
+# Force 32-bit code even on an x86-64 machine
52
+#
53
+CFLAGS		+= -m32
54
+ASFLAGS		+= --32
55
+ifeq ($(HOST_OS),FreeBSD)
56
+LDFLAGS		+= -m elf_i386_fbsd
57
+else ifeq ($(HOST_OS),OpenBSD)
58
+LDFLAGS		+= -m elf_i386_obsd
59
+else
60
+LDFLAGS		+= -m elf_i386
61
+endif
62
+
63
+# EFI requires -fshort-wchar, and nothing else currently uses wchar_t
64
+#
65
+CFLAGS		+= -fshort-wchar
66
+
67
+# We need to undefine the default macro "i386" when compiling .S
68
+# files, otherwise ".arch i386" translates to ".arch 1"...
69
+#
70
+CFLAGS			+= -Ui386
71
+
72
+# Some widespread patched versions of gcc include -fPIE -Wl,-pie by
73
+# default.  Note that gcc will exit *successfully* if it fails to
74
+# recognise an option that starts with "no", so we have to test for
75
+# output on stderr instead of checking the exit status.
76
+#
77
+ifeq ($(CCTYPE),gcc)
78
+PIE_TEST = [ -z "`$(CC) -fno-PIE -nopie -x c -c /dev/null -o /dev/null 2>&1`" ]
79
+PIE_FLAGS := $(shell $(PIE_TEST) && $(ECHO) '-fno-PIE -nopie')
80
+WORKAROUND_CFLAGS += $(PIE_FLAGS)
81
+endif
82
+
83
+# Define version string for lkrnprefix.S
84
+#
85
+CFLAGS_lkrnprefix	+= -DVERSION="\"$(VERSION)\""
86
+
87
+# Locations of isolinux files
88
+#
89
+SYSLINUX_DIR_LIST	:= \
90
+	/usr/lib/syslinux \
91
+	/usr/lib/syslinux/bios \
92
+	/usr/lib/syslinux/modules/bios \
93
+	/usr/share/syslinux \
94
+	/usr/share/syslinux/bios \
95
+	/usr/share/syslinux/modules/bios \
96
+	/usr/local/share/syslinux \
97
+	/usr/local/share/syslinux/bios \
98
+	/usr/local/share/syslinux/modules/bios \
99
+	/usr/lib/ISOLINUX
100
+ISOLINUX_BIN_LIST	:= \
101
+	$(ISOLINUX_BIN) \
102
+	$(patsubst %,%/isolinux.bin,$(SYSLINUX_DIR_LIST))
103
+LDLINUX_C32_LIST	:= \
104
+	$(LDLINUX_C32) \
105
+	$(patsubst %,%/ldlinux.c32,$(SYSLINUX_DIR_LIST))
106
+ISOLINUX_BIN	= $(firstword $(wildcard $(ISOLINUX_BIN_LIST)))
107
+LDLINUX_C32	= $(firstword $(wildcard $(LDLINUX_C32_LIST)))
108
+
109
+# i386-specific directories containing source files
110
+#
111
+SRCDIRS		+= arch/i386/core arch/i386/transitions arch/i386/prefix
112
+SRCDIRS		+= arch/i386/firmware/pcbios
113
+SRCDIRS		+= arch/i386/image
114
+SRCDIRS		+= arch/i386/interface/pcbios
115
+SRCDIRS		+= arch/i386/interface/pxe
116
+SRCDIRS		+= arch/i386/interface/pxeparent
117
+SRCDIRS 	+= arch/i386/interface/syslinux
118
+SRCDIRS		+= arch/i386/hci/commands
119
+
120
+# Include common x86 Makefile
121
+#
122
+MAKEDEPS	+= arch/x86/Makefile
123
+include arch/x86/Makefile
124
+
125
+# Include platform-specific Makefile
126
+#
127
+MAKEDEPS	+= arch/i386/Makefile.$(PLATFORM)
128
+include arch/i386/Makefile.$(PLATFORM)

+ 18
- 0
src/arch/i386/Makefile.efi View File

@@ -0,0 +1,18 @@
1
+# -*- makefile -*- : Force emacs to use Makefile mode
2
+
3
+# Specify EFI image builder
4
+#
5
+ELF2EFI		= $(ELF2EFI32)
6
+
7
+# Use EFI ABI
8
+#
9
+CFLAGS		+= -malign-double
10
+
11
+# Specify EFI boot file
12
+#
13
+EFI_BOOT_FILE	= bootia32.efi
14
+
15
+# Include generic EFI Makefile
16
+#
17
+MAKEDEPS	+= arch/x86/Makefile.efi
18
+include arch/x86/Makefile.efi

+ 6
- 0
src/arch/i386/Makefile.linux View File

@@ -0,0 +1,6 @@
1
+LDSCRIPT = arch/i386/scripts/linux.lds
2
+
3
+SRCDIRS += arch/i386/core/linux
4
+
5
+MAKEDEPS += arch/x86/Makefile.linux
6
+include arch/x86/Makefile.linux

+ 101
- 0
src/arch/i386/Makefile.pcbios View File

@@ -0,0 +1,101 @@
1
+# -*- makefile -*- : Force emacs to use Makefile mode
2
+
3
+# The i386 linker script
4
+#
5
+LDSCRIPT	= arch/i386/scripts/i386.lds
6
+
7
+# Stop ld from complaining about our customised linker script
8
+#
9
+LDFLAGS		+= -N --no-check-sections
10
+
11
+# pcbios specific drivers
12
+SRCDIRS		+= arch/i386/drivers
13
+SRCDIRS		+= arch/i386/drivers/net
14
+
15
+# Media types.
16
+#
17
+MEDIA		+= rom
18
+MEDIA		+= mrom
19
+MEDIA		+= pcirom
20
+MEDIA		+= isarom
21
+MEDIA		+= pxe
22
+MEDIA		+= kpxe
23
+MEDIA		+= kkpxe
24
+MEDIA		+= kkkpxe
25
+MEDIA		+= lkrn
26
+MEDIA		+= dsk
27
+MEDIA		+= nbi
28
+MEDIA		+= hd
29
+MEDIA		+= raw
30
+MEDIA		+= exe
31
+
32
+# Padding rules
33
+#
34
+PAD_rom		= $(PERL) $(PADIMG) --blksize=512 --byte=0xff
35
+PAD_mrom	= $(PAD_rom)
36
+PAD_pcirom	= $(PAD_rom)
37
+PAD_isarom	= $(PAD_rom)
38
+PAD_dsk		= $(PERL) $(PADIMG) --blksize=512
39
+PAD_hd		= $(PERL) $(PADIMG) --blksize=32768
40
+PAD_exe		= $(PERL) $(PADIMG) --blksize=512
41
+
42
+# Finalisation rules
43
+#
44
+FINALISE_rom	= $(PERL) $(FIXROM)
45
+FINALISE_mrom	= $(FINALISE_rom)
46
+FINALISE_pcirom	= $(FINALISE_rom)
47
+FINALISE_isarom	= $(FINALISE_rom)
48
+
49
+# Use $(ROMS) rather than $(DRIVERS) for "allroms", "allmroms", etc.
50
+#
51
+LIST_NAME_rom := ROMS
52
+LIST_NAME_mrom := ROMS
53
+LIST_NAME_pcirom := ROMS
54
+LIST_NAME_isarom := ROMS
55
+
56
+# rule to make a non-emulation ISO boot image
57
+NON_AUTO_MEDIA	+= iso
58
+%iso:	%lkrn util/geniso
59
+	$(QM)$(ECHO) "  [GENISO] $@"
60
+	$(Q)ISOLINUX_BIN=$(ISOLINUX_BIN) LDLINUX_C32=$(LDLINUX_C32) \
61
+	    VERSION="$(VERSION)" bash util/geniso -o $@ $<
62
+
63
+# rule to make a floppy emulation ISO boot image
64
+NON_AUTO_MEDIA	+= liso
65
+%liso:	%lkrn util/geniso
66
+	$(QM)$(ECHO) "  [GENISO] $@"
67
+	$(Q)VERSION="$(VERSION)" bash util/geniso -l -o $@ $<
68
+
69
+# rule to make a syslinux floppy image (mountable, bootable)
70
+NON_AUTO_MEDIA	+= sdsk
71
+%sdsk:	%lkrn util/gensdsk
72
+	$(QM)$(ECHO) "  [GENSDSK] $@"
73
+	$(Q)bash util/gensdsk $@ $<
74
+
75
+# rule to write disk images to /dev/fd0
76
+NON_AUTO_MEDIA	+= fd0
77
+%fd0 : %dsk
78
+	$(QM)$(ECHO) "  [DD] $@"
79
+	$(Q)dd if=$< bs=512 conv=sync of=/dev/fd0
80
+	$(Q)sync
81
+
82
+# Special target for building Master Boot Record binary
83
+$(BIN)/mbr.bin : $(BIN)/mbr.o
84
+	$(QM)$(ECHO) "  [OBJCOPY] $@"
85
+	$(Q)$(OBJCOPY) -O binary $< $@
86
+
87
+# rule to make a USB disk image
88
+$(BIN)/usbdisk.bin : $(BIN)/usbdisk.o
89
+	$(QM)$(ECHO) "  [OBJCOPY] $@"
90
+	$(Q)$(OBJCOPY) -O binary $< $@
91
+
92
+NON_AUTO_MEDIA	+= usb
93
+%usb: $(BIN)/usbdisk.bin %hd
94
+	$(QM)$(ECHO) "  [FINISH] $@"
95
+	$(Q)cat $^ > $@
96
+
97
+# Padded floppy image (e.g. for iLO)
98
+NON_AUTO_MEDIA += pdsk
99
+%pdsk : %dsk
100
+	$(Q)cp $< $@
101
+	$(Q)$(PADIMG) --blksize=1474560 $@

+ 197
- 0
src/arch/i386/README.i386 View File

@@ -0,0 +1,197 @@
1
+Etherboot/NILO i386 initialisation path and external call interface
2
+===================================================================
3
+
4
+1. Background
5
+
6
+GCC compiles 32-bit code.  It is capable of producing
7
+position-independent code, but the resulting binary is about 25%
8
+bigger than the corresponding fixed-position code.  Since one main use
9
+of Etherboot is as firmware to be burned into an EPROM, code size must
10
+be kept as small as possible.
11
+
12
+This means that we want to compile fixed-position code with GCC, and
13
+link it to have a predetermined start address.  The problem then is
14
+that we must know the address that the code will be loaded to when it
15
+runs.  There are several ways to solve this:
16
+
17
+1. Pick an address, link the code with this start address, then make
18
+   sure that the code gets loaded at that location.  This is
19
+   problematic, because we may pick an address that we later end up
20
+   wanting to use to load the operating system that we're booting.
21
+
22
+2. Pick an address, link the code with this start address, then set up
23
+   virtual addressing so that the virtual addresses match the
24
+   link-time addresses regardless of the real physical address that
25
+   the code is loaded to.  This enables us to relocate Etherboot to
26
+   the top of high memory, where it will be out of the way of any
27
+   loading operating system.
28
+
29
+3. Link the code with a text start address of zero and a data start
30
+   address also of zero.  Use 16-bit real mode and the
31
+   quasi-position-independence it gives you via segment addressing.
32
+   Doing this requires that we generate 16-bit code, rather than
33
+   32-bit code, and restricts us to a maximum of 64kB in each segment.
34
+
35
+There are other possible approaches (e.g. including a relocation table
36
+and code that performs standard dynamic relocation), but the three
37
+options listed above are probably the best available.
38
+
39
+Etherboot can be invoked in a variety of ways (ROM, floppy, as a PXE
40
+NBP, etc).  Several of these ways involve control being passed to
41
+Etherboot with the CPU in 16-bit real mode.  Some will involve the CPU
42
+being in 32-bit protected mode, and there's an outside chance that
43
+some may involve the CPU being in 16-bit protected mode.  We will
44
+almost certainly have to effect a CPU mode change in order to reach
45
+the mode we want to be in to execute the C code.
46
+
47
+Additionally, Etherboot may wish to call external routines, such as
48
+BIOS interrupts, which must be called in 16-bit real mode.  When
49
+providing a PXE API, Etherboot must provide a mechanism for external
50
+code to call it from 16-bit real mode.
51
+
52
+Not all i386 builds of Etherboot will want to make real-mode calls.
53
+For example, when built for LinuxBIOS rather than the standard PCBIOS,
54
+no real-mode calls are necessary.
55
+
56
+For the ultimate in PXE compatibility, we may want to build Etherboot
57
+to run permanently in real mode.
58
+
59
+There is a wide variety of potential combinations of mode switches
60
+that we may wish to implement.  There are additional complications,
61
+such as the inability to access a high-memory stack when running in
62
+real mode.
63
+
64
+2. Transition libraries
65
+
66
+To handle all these various combinations of mode switches, we have
67
+several "transition" libraries in Etherboot.  We also have the concept
68
+of an "internal" and an "external" environment.  The internal
69
+environment is the environment within which we can execute C code.
70
+The external environment is the environment of whatever external code
71
+we're trying to interface to, such as the system BIOS or a PXE NBP.
72
+
73
+As well as having a separate addressing scheme, the internal
74
+environment also has a separate stack.
75
+
76
+The transition libraries are:
77
+
78
+a) librm
79
+
80
+librm handles transitions between an external 16-bit real-mode
81
+environment and an internal 32-bit protected-mode environment with
82
+virtual addresses.
83
+
84
+b) libkir
85
+
86
+libkir handles transitions between an external 16-bit real-mode (or
87
+16:16 or 16:32 protected-mode) environment and an internal 16-bit
88
+real-mode (or 16:16 protected-mode) environment.
89
+
90
+c) libpm
91
+
92
+libpm handles transitions between an external 32-bit protected-mode
93
+environment with flat physical addresses and an internal 32-bit
94
+protected-mode environment with virtual addresses.
95
+
96
+The transition libraries handle the transitions required when
97
+Etherboot is started up for the first time, the transitions required
98
+to execute any external code, and the transitions required when
99
+Etherboot exits (if it exits).  When Etherboot provides a PXE API,
100
+they also handle the transitions required when a PXE client makes a
101
+PXE API call to Etherboot.
102
+
103
+Etherboot may use multiple transition libraries.  For example, an
104
+Etherboot ELF image does not require librm for its initial transitions
105
+from prefix to runtime, but may require librm for calling external
106
+real-mode functions.
107
+
108
+3. Setup and initialisation
109
+
110
+Etherboot is conceptually divided into the prefix, the decompressor,
111
+and the runtime image.  (For non-compressed images, the decompressor
112
+is a no-op.)  The complete image comprises all three parts and is
113
+distinct from the runtime image, which exclude the prefix and the
114
+decompressor.
115
+
116
+The prefix does several tasks:
117
+
118
+  Load the complete image into memory.  (For example, the floppy
119
+  prefix issues BIOS calls to load the remainder of the complete image
120
+  from the floppy disk into RAM, and the ISA ROM prefix copies the ROM
121
+  contents into RAM for faster access.)
122
+
123
+  Call the decompressor, if the runtime image is compressed.  This
124
+  decompresses the runtime image.
125
+
126
+  Call the runtime image's setup() routine.  This is a routine
127
+  implemented in assembly code which sets up the internal environment
128
+  so that C code can execute.
129
+
130
+  Call the runtime image's arch_initialise() routine.  This is a
131
+  routine implemented in C which does some basic startup tasks, such
132
+  as initialising the console device, obtaining a memory map and
133
+  relocating the runtime image to high memory.
134
+
135
+  Call the runtime image's arch_main() routine.  This records the exit
136
+  mechanism requested by the prefix and calls main().  (The prefix
137
+  needs to register an exit mechanism because by the time main()
138
+  returns, the memory occupied by the prefix has most likely been
139
+  overwritten.)
140
+
141
+When acting as a PXE ROM, the ROM prefix contains an UNDI loader
142
+routine in addition to its usual code.  The UNDI loader performs a
143
+similar sequence of steps:
144
+
145
+  Load the complete image into memory.
146
+
147
+  Call the decompressor.
148
+
149
+  Call the runtime image's setup() routine.
150
+
151
+  Call the runtime image's arch_initialise() routine.
152
+
153
+  Call the runtime image's install_pxe_stack() routine.
154
+
155
+  Return to caller.
156
+
157
+The runtime image's setup() routine will perform the following steps:
158
+
159
+  Switch to the internal environment using an appropriate transition
160
+  library.  This will record the parameters of the external
161
+  environment.
162
+
163
+  Set up the internal environment: load a stack, and set up a GDT for
164
+  virtual addressing if virtual addressing is to be used.
165
+
166
+  Switch back to the external environment using the transition
167
+  library.  This will record the parameters of the internal
168
+  environment.
169
+
170
+Once the setup() routine has returned, the internal environment has been
171
+set up ready for C code to run.  The prefix can call C routines using
172
+a function from the transition library.
173
+
174
+The runtime image's arch_initialise() routine will perform the
175
+following steps:
176
+
177
+  Zero the bss
178
+
179
+  Initialise the console device(s) and print a welcome message.
180
+
181
+  Obtain a memory map via the INT 15,E820 BIOS call or suitable
182
+  fallback mechanism. [not done if libkir is being used]
183
+
184
+  Relocate the runtime image to the top of high memory. [not done if
185
+  libkir is being used]
186
+
187
+  Install librm to base memory. [done only if librm is being used]
188
+
189
+  Call initialise().
190
+
191
+  Return to the prefix, setting registers to indicate to the prefix
192
+  the new location of the transition library, if applicable.  Which
193
+  registers these are is specific to the transition library being
194
+  used.
195
+
196
+Once the arch_initialise() routine has returned, the prefix will
197
+probably call arch_main().

+ 37
- 0
src/arch/i386/core/basemem_packet.c View File

@@ -0,0 +1,37 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * Packet buffer in base memory.  Used by various components which
30
+ * need to pass packets to and from external real-mode code.
31
+ *
32
+ */
33
+
34
+#include <basemem_packet.h>
35
+
36
+#undef basemem_packet
37
+char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );

+ 175
- 0
src/arch/i386/core/cachedhcp.c View File

@@ -0,0 +1,175 @@
1
+/*
2
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <stdlib.h>
28
+#include <ipxe/dhcppkt.h>
29
+#include <ipxe/init.h>
30
+#include <ipxe/netdevice.h>
31
+#include <realmode.h>
32
+#include <pxe_api.h>
33
+
34
+/** @file
35
+ *
36
+ * Cached DHCP packet
37
+ *
38
+ */
39
+
40
+/** Cached DHCPACK physical address
41
+ *
42
+ * This can be set by the prefix.
43
+ */
44
+uint32_t __bss16 ( cached_dhcpack_phys );
45
+#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
46
+
47
+/** Colour for debug messages */
48
+#define colour &cached_dhcpack_phys
49
+
50
+/** Cached DHCPACK */
51
+static struct dhcp_packet *cached_dhcpack;
52
+
53
+/**
54
+ * Cached DHCPACK startup function
55
+ *
56
+ */
57
+static void cachedhcp_init ( void ) {
58
+	struct dhcp_packet *dhcppkt;
59
+	struct dhcp_packet *tmp;
60
+	struct dhcphdr *dhcphdr;
61
+	size_t len;
62
+
63
+	/* Do nothing if no cached DHCPACK is present */
64
+	if ( ! cached_dhcpack_phys ) {
65
+		DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
66
+		return;
67
+	}
68
+
69
+	/* No reliable way to determine length before parsing packet;
70
+	 * start by assuming maximum length permitted by PXE.
71
+	 */
72
+	len = sizeof ( BOOTPLAYER_t );
73
+
74
+	/* Allocate and populate DHCP packet */
75
+	dhcppkt = zalloc ( sizeof ( *dhcppkt ) + len );
76
+	if ( ! dhcppkt ) {
77
+		DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
78
+		return;
79
+	}
80
+	dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
81
+	copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
82
+			 len );
83
+	dhcppkt_init ( dhcppkt, dhcphdr, len );
84
+
85
+	/* Resize packet to required length.  If reallocation fails,
86
+	 * just continue to use the original packet.
87
+	 */
88
+	len = dhcppkt_len ( dhcppkt );
89
+	tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
90
+	if ( tmp )
91
+		dhcppkt = tmp;
92
+
93
+	/* Reinitialise packet at new address */
94
+	dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
95
+	dhcppkt_init ( dhcppkt, dhcphdr, len );
96
+
97
+	/* Store as cached DHCPACK, and mark original copy as consumed */
98
+	DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
99
+	       cached_dhcpack_phys, len );
100
+	cached_dhcpack = dhcppkt;
101
+	cached_dhcpack_phys = 0;
102
+}
103
+
104
+/**
105
+ * Cached DHCPACK startup function
106
+ *
107
+ */
108
+static void cachedhcp_startup ( void ) {
109
+
110
+	/* If cached DHCP packet was not claimed by any network device
111
+	 * during startup, then free it.
112
+	 */
113
+	if ( cached_dhcpack ) {
114
+		DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
115
+		dhcppkt_put ( cached_dhcpack );
116
+		cached_dhcpack = NULL;
117
+	}
118
+}
119
+
120
+/** Cached DHCPACK initialisation function */
121
+struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
122
+	.initialise = cachedhcp_init,
123
+};
124
+
125
+/** Cached DHCPACK startup function */
126
+struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
127
+	.startup = cachedhcp_startup,
128
+};
129
+
130
+/**
131
+ * Apply cached DHCPACK to network device, if applicable
132
+ *
133
+ * @v netdev		Network device
134
+ * @ret rc		Return status code
135
+ */
136
+static int cachedhcp_probe ( struct net_device *netdev ) {
137
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
138
+	int rc;
139
+
140
+	/* Do nothing unless we have a cached DHCPACK */
141
+	if ( ! cached_dhcpack )
142
+		return 0;
143
+
144
+	/* Do nothing unless cached DHCPACK's MAC address matches this
145
+	 * network device.
146
+	 */
147
+	if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
148
+		      ll_protocol->ll_addr_len ) != 0 ) {
149
+		DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
150
+		       netdev->name );
151
+		return 0;
152
+	}
153
+	DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
154
+
155
+	/* Register as DHCP settings for this network device */
156
+	if ( ( rc = register_settings ( &cached_dhcpack->settings,
157
+					netdev_settings ( netdev ),
158
+					DHCP_SETTINGS_NAME ) ) != 0 ) {
159
+		DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
160
+		       strerror ( rc ) );
161
+		return rc;
162
+	}
163
+
164
+	/* Claim cached DHCPACK */
165
+	dhcppkt_put ( cached_dhcpack );
166
+	cached_dhcpack = NULL;
167
+
168
+	return 0;
169
+}
170
+
171
+/** Cached DHCP packet network device driver */
172
+struct net_driver cachedhcp_driver __net_driver = {
173
+	.name = "cachedhcp",
174
+	.probe = cachedhcp_probe,
175
+};

+ 23
- 0
src/arch/i386/core/dumpregs.c View File

@@ -0,0 +1,23 @@
1
+#include <stdio.h>
2
+#include <realmode.h>
3
+
4
+void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
5
+
6
+	__asm__ __volatile__ (
7
+		TEXT16_CODE ( ".globl dump_regs\n\t"
8
+			      "\ndump_regs:\n\t"
9
+			      "pushl $_dump_regs\n\t"
10
+			      "pushw %%cs\n\t"
11
+			      "call prot_call\n\t"
12
+			      "addr32 leal 4(%%esp), %%esp\n\t"
13
+			      "ret\n\t" ) : : );
14
+
15
+	printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
16
+		 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
17
+		 "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
18
+		 ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx,
19
+		 ix86->regs.edx, ix86->regs.esi, ix86->regs.edi,
20
+		 ix86->regs.ebp, ix86->regs.esp,
21
+		 ix86->segs.cs, ix86->segs.ss, ix86->segs.ds,
22
+		 ix86->segs.es, ix86->segs.fs, ix86->segs.gs );
23
+}

+ 140
- 0
src/arch/i386/core/gdbidt.S View File

@@ -0,0 +1,140 @@
1
+/*
2
+ * Interrupt handlers for GDB stub
3
+ */
4
+
5
+#define SIZEOF_I386_REGS	32
6
+#define SIZEOF_I386_FLAGS	4
7
+
8
+/****************************************************************************
9
+ * Interrupt handlers
10
+ ****************************************************************************
11
+ */
12
+	.section ".text", "ax", @progbits
13
+	.code32
14
+
15
+/* POSIX signal numbers for reporting traps to GDB */
16
+#define SIGILL 4
17
+#define SIGTRAP 5
18
+#define SIGBUS 7
19
+#define SIGFPE 8
20
+#define SIGSEGV 11
21
+#define SIGSTKFLT 16
22
+
23
+	.globl	gdbmach_nocode_sigfpe
24
+gdbmach_nocode_sigfpe:
25
+	pushl	$SIGFPE
26
+	jmp	gdbmach_interrupt
27
+
28
+	.globl	gdbmach_nocode_sigtrap
29
+gdbmach_nocode_sigtrap:
30
+	pushl	$SIGTRAP
31
+	jmp	gdbmach_interrupt
32
+
33
+	.globl	gdbmach_nocode_sigstkflt
34
+gdbmach_nocode_sigstkflt:
35
+	pushl	$SIGSTKFLT
36
+	jmp	gdbmach_interrupt
37
+
38
+	.globl	gdbmach_nocode_sigill
39
+gdbmach_nocode_sigill:
40
+	pushl	$SIGILL
41
+	jmp	gdbmach_interrupt
42
+
43
+	.globl	gdbmach_withcode_sigbus
44
+gdbmach_withcode_sigbus:
45
+	movl	$SIGBUS, (%esp)
46
+	jmp	gdbmach_interrupt
47
+
48
+	.globl	gdbmach_withcode_sigsegv
49
+gdbmach_withcode_sigsegv:
50
+	movl	$SIGSEGV, (%esp)
51
+	jmp	gdbmach_interrupt
52
+
53
+/* When invoked, the stack contains: eflags, cs, eip, signo. */
54
+#define IH_OFFSET_GDB_REGS ( 0 )
55
+#define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )
56
+#define IH_OFFSET_GDB_EFLAGS ( IH_OFFSET_GDB_EIP + 4 )
57
+#define IH_OFFSET_GDB_SEG_REGS ( IH_OFFSET_GDB_EFLAGS + SIZEOF_I386_FLAGS )
58
+#define IH_OFFSET_GDB_END ( IH_OFFSET_GDB_SEG_REGS + 6 * 4 )
59
+#define IH_OFFSET_SIGNO ( IH_OFFSET_GDB_END )
60
+#define IH_OFFSET_OLD_EIP ( IH_OFFSET_SIGNO + 4 )
61
+#define IH_OFFSET_OLD_CS ( IH_OFFSET_OLD_EIP + 4 )
62
+#define IH_OFFSET_OLD_EFLAGS ( IH_OFFSET_OLD_CS + 4 )
63
+#define IH_OFFSET_END ( IH_OFFSET_OLD_EFLAGS + 4 )
64
+
65
+/* We also access the stack whilst still storing or restoring
66
+ * the register snapshot.  Since ESP is in flux, we need
67
+ * special offsets.
68
+ */
69
+#define IH_OFFSET_FLUX_OLD_CS ( IH_OFFSET_OLD_CS - 44 )
70
+#define IH_OFFSET_FLUX_OLD_EFLAGS ( IH_OFFSET_OLD_EFLAGS - 40 )
71
+#define IH_OFFSET_FLUX_OLD_EIP ( IH_OFFSET_OLD_EIP - 36 )
72
+#define IH_OFFSET_FLUX_END ( IH_OFFSET_END - 20 )
73
+gdbmach_interrupt:
74
+	/* Store CPU state in GDB register snapshot */
75
+	pushw	$0
76
+	pushw	%gs
77
+	pushw	$0
78
+	pushw	%fs
79
+	pushw	$0
80
+	pushw	%es
81
+	pushw	$0
82
+	pushw	%ds
83
+	pushw	$0
84
+	pushw	%ss
85
+	pushw	$0
86
+	pushw	IH_OFFSET_FLUX_OLD_CS + 2(%esp)
87
+	pushl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
88
+	pushl	IH_OFFSET_FLUX_OLD_EIP(%esp)
89
+	pushl	%edi
90
+	pushl	%esi
91
+	pushl	%ebp
92
+	leal	IH_OFFSET_FLUX_END(%esp), %edi
93
+	pushl	%edi /* old ESP */
94
+	pushl	%ebx
95
+	pushl	%edx
96
+	pushl	%ecx
97
+	pushl	%eax
98
+
99
+	/* Switch to virtual addressing */
100
+	call	_intr_to_virt
101
+
102
+	/* Call GDB stub exception handler */
103
+	pushl	%esp
104
+	pushl	(IH_OFFSET_SIGNO + 4)(%esp)
105
+	call	gdbmach_handler
106
+	addl	$8, %esp
107
+
108
+	/* Copy register snapshot to new stack and switch to new stack */
109
+	movl	%esp, %esi
110
+	movl	(IH_OFFSET_GDB_SEG_REGS + 4)(%esp), %eax
111
+	movl	%eax, %es
112
+	movl	(IH_OFFSET_GDB_REGS + 16)(%esp), %edi
113
+	subl	$IH_OFFSET_END, %edi
114
+	movl	$(IH_OFFSET_END / 4), %ecx
115
+	pushl	%edi
116
+	ss rep movsl
117
+	popl	%edi
118
+	movl	%eax, %ss
119
+	movl	%edi, %esp
120
+
121
+	/* Restore CPU state from GDB register snapshot */
122
+	popl	%eax
123
+	popl	%ecx
124
+	popl	%edx
125
+	popl	%ebx
126
+	popl	%ebp /* Skip %esp: already loaded */
127
+	popl	%ebp
128
+	popl	%esi
129
+	popl	%edi
130
+	popl	IH_OFFSET_FLUX_OLD_EIP(%esp)
131
+	popl	IH_OFFSET_FLUX_OLD_EFLAGS(%esp)
132
+	popl	IH_OFFSET_FLUX_OLD_CS(%esp)
133
+	popl	%ds /* Skip %ss: already loaded */
134
+	popl	%ds
135
+	popl	%es
136
+	popl	%fs
137
+	popl	%gs
138
+
139
+	addl	$4, %esp /* drop signo */
140
+	iret

+ 184
- 0
src/arch/i386/core/gdbmach.c View File

@@ -0,0 +1,184 @@
1
+/*
2
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stddef.h>
27
+#include <stdio.h>
28
+#include <assert.h>
29
+#include <ipxe/uaccess.h>
30
+#include <ipxe/gdbstub.h>
31
+#include <librm.h>
32
+#include <gdbmach.h>
33
+
34
+/** @file
35
+ *
36
+ * GDB architecture-specific bits for i386
37
+ *
38
+ */
39
+
40
+enum {
41
+	DR7_CLEAR = 0x00000400,    /* disable hardware breakpoints */
42
+	DR6_CLEAR = 0xffff0ff0,    /* clear breakpoint status */
43
+};
44
+
45
+/** Hardware breakpoint, fields stored in x86 bit pattern form */
46
+struct hwbp {
47
+	int type;           /* type (1=write watchpoint, 3=access watchpoint) */
48
+	unsigned long addr; /* linear address */
49
+	size_t len;         /* length (0=1-byte, 1=2-byte, 3=4-byte) */
50
+	int enabled;
51
+};
52
+
53
+static struct hwbp hwbps [ 4 ];
54
+static gdbreg_t dr7 = DR7_CLEAR;
55
+
56
+static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) {
57
+	struct hwbp *available = NULL;
58
+	unsigned int i;
59
+	for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) {
60
+		if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) {
61
+			return &hwbps [ i ];
62
+		}
63
+		if ( !hwbps [ i ].enabled ) {
64
+			available = &hwbps [ i ];
65
+		}
66
+	}
67
+	return available;
68
+}
69
+
70
+static void gdbmach_commit_hwbp ( struct hwbp *bp ) {
71
+	unsigned int regnum = bp - hwbps;
72
+
73
+	/* Set breakpoint address */
74
+	assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) );
75
+	switch ( regnum ) {
76
+		case 0:
77
+			__asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
78
+			break;
79
+		case 1:
80
+			__asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
81
+			break;
82
+		case 2:
83
+			__asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
84
+			break;
85
+		case 3:
86
+			__asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
87
+			break;
88
+	}
89
+
90
+	/* Set type */
91
+	dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
92
+	dr7 |= bp->type << ( 16 + 4 * regnum );
93
+
94
+	/* Set length */
95
+	dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) );
96
+	dr7 |= bp->len << ( 18 + 4 * regnum );
97
+
98
+	/* Set/clear local enable bit */
99
+	dr7 &= ~( 0x3 << 2 * regnum );
100
+ 	dr7 |= bp->enabled << 2 * regnum;
101
+}
102
+
103
+int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) {
104
+	struct hwbp *bp;
105
+	
106
+	/* Check and convert breakpoint type to x86 type */
107
+	switch ( type ) {
108
+		case GDBMACH_WATCH:
109
+			type = 0x1;
110
+			break;
111
+		case GDBMACH_AWATCH:
112
+			type = 0x3;
113
+			break;
114
+		default:
115
+			return 0; /* unsupported breakpoint type */
116
+	}
117
+
118
+	/* Only lengths 1, 2, and 4 are supported */
119
+	if ( len != 2 && len != 4 ) {
120
+		len = 1;
121
+	}
122
+	len--; /* convert to x86 breakpoint length bit pattern */
123
+
124
+	/* Calculate linear address by adding segment base */
125
+	addr += virt_offset;
126
+
127
+	/* Set up the breakpoint */
128
+	bp = gdbmach_find_hwbp ( type, addr, len );
129
+	if ( !bp ) {
130
+		return 0; /* ran out of hardware breakpoints */
131
+	}
132
+	bp->type = type;
133
+	bp->addr = addr;
134
+	bp->len = len;
135
+	bp->enabled = enable;
136
+	gdbmach_commit_hwbp ( bp );
137
+	return 1;
138
+}
139
+
140
+static void gdbmach_disable_hwbps ( void ) {
141
+	/* Store and clear hardware breakpoints */
142
+	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) );
143
+}
144
+
145
+static void gdbmach_enable_hwbps ( void ) {
146
+	/* Clear breakpoint status register */
147
+	__asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) );
148
+
149
+	/* Restore hardware breakpoints */
150
+	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
151
+}
152
+
153
+__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
154
+	gdbmach_disable_hwbps();
155
+	gdbstub_handler ( signo, regs );
156
+	gdbmach_enable_hwbps();
157
+}
158
+
159
+static void * gdbmach_interrupt_vectors[] = {
160
+	gdbmach_nocode_sigfpe,		/* Divide by zero */
161
+	gdbmach_nocode_sigtrap,		/* Debug trap */
162
+	NULL,				/* Non-maskable interrupt */
163
+	gdbmach_nocode_sigtrap,		/* Breakpoint */
164
+	gdbmach_nocode_sigstkflt,	/* Overflow */
165
+	gdbmach_nocode_sigstkflt,	/* Bound range exceeded */
166
+	gdbmach_nocode_sigill,		/* Invalid opcode */
167
+	NULL,				/* Device not available */
168
+	gdbmach_withcode_sigbus,	/* Double fault */
169
+	NULL,				/* Coprocessor segment overrun */
170
+	gdbmach_withcode_sigsegv,	/* Invalid TSS */
171
+	gdbmach_withcode_sigsegv,	/* Segment not present */
172
+	gdbmach_withcode_sigsegv,	/* Stack segment fault */
173
+	gdbmach_withcode_sigsegv,	/* General protection fault */
174
+	gdbmach_withcode_sigsegv,	/* Page fault */
175
+};
176
+
177
+void gdbmach_init ( void ) {
178
+	unsigned int i;
179
+
180
+	for ( i = 0 ; i < ( sizeof ( gdbmach_interrupt_vectors ) /
181
+			    sizeof ( gdbmach_interrupt_vectors[0] ) ) ; i++ ) {
182
+		set_interrupt_vector ( i, gdbmach_interrupt_vectors[i] );
183
+	}
184
+}

+ 45
- 0
src/arch/i386/core/linux/linux_syscall.S View File

@@ -0,0 +1,45 @@
1
+
2
+	.section ".data"
3
+	.globl linux_errno
4
+
5
+linux_errno:	.int 0
6
+
7
+	.section ".text"
8
+	.code32
9
+	.globl linux_syscall
10
+	.type  linux_syscall, @function
11
+
12
+linux_syscall:
13
+	/* Save registers */
14
+	pushl	%ebx
15
+	pushl	%esi
16
+	pushl	%edi
17
+	pushl	%ebp
18
+
19
+	movl	20(%esp), %eax  // C arg1 -> syscall number
20
+	movl	24(%esp), %ebx  // C arg2 -> syscall arg1
21
+	movl	28(%esp), %ecx  // C arg3 -> syscall arg2
22
+	movl	32(%esp), %edx  // C arg4 -> syscall arg3
23
+	movl	36(%esp), %esi  // C arg5 -> syscall arg4
24
+	movl	40(%esp), %edi  // C arg6 -> syscall arg5
25
+	movl	44(%esp), %ebp  // C arg7 -> syscall arg6
26
+
27
+	int	$0x80
28
+
29
+	/* Restore registers */
30
+	popl	%ebp
31
+	popl	%edi
32
+	popl	%esi
33
+	popl	%ebx
34
+
35
+	cmpl	$-4095, %eax
36
+	jae	1f
37
+	ret
38
+
39
+1:
40
+	negl	%eax
41
+	movl	%eax, linux_errno
42
+	movl	$-1, %eax
43
+	ret
44
+
45
+	.size linux_syscall, . - linux_syscall

+ 28
- 0
src/arch/i386/core/linux/linuxprefix.S View File

@@ -0,0 +1,28 @@
1
+#include <linux/unistd.h>
2
+
3
+	.section ".text"
4
+	.code32
5
+	.globl _linux_start
6
+	.type _linux_start, @function
7
+
8
+_linux_start:
9
+	xorl	%ebp, %ebp
10
+
11
+	popl	%esi       // save argc
12
+	movl	%esp, %edi // save argv
13
+
14
+	andl	$~15, %esp // 16-byte align the stack
15
+
16
+	pushl	%edi // argv -> C arg2
17
+	pushl	%esi // argc -> C arg1
18
+
19
+	call	save_args
20
+
21
+	/* Our main doesn't use any arguments */
22
+	call	main
23
+
24
+	movl	%eax, %ebx // rc -> syscall arg1
25
+	movl	$__NR_exit, %eax
26
+	int	$0x80
27
+
28
+	.size _linux_start, . - _linux_start

+ 51
- 0
src/arch/i386/core/nulltrap.c View File

@@ -0,0 +1,51 @@
1
+#include <stdint.h>
2
+#include <stdio.h>
3
+
4
+__attribute__ (( noreturn, section ( ".text.null_trap" ) ))
5
+void null_function_trap ( void ) {
6
+	void *stack;
7
+
8
+	/* 128 bytes of NOPs; the idea of this is that if something
9
+	 * dereferences a NULL pointer and overwrites us, we at least
10
+	 * have some chance of still getting to execute the printf()
11
+	 * statement.
12
+	 */
13
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
14
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
15
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
16
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
17
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
18
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
19
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
20
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
21
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
22
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
23
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
24
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
25
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
26
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
27
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
28
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
29
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
30
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
31
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
32
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
33
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
34
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
35
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
36
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
37
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
38
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
39
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
40
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
41
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
42
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
43
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
44
+	__asm__ __volatile__ ( "nop ; nop ; nop ; nop" );
45
+
46
+	__asm__ __volatile__ ( "movl %%esp, %0" : "=r" ( stack ) );
47
+	printf ( "NULL method called from %p (stack %p)\n", 
48
+		 __builtin_return_address ( 0 ), stack );
49
+	DBG_HD ( stack, 256 );
50
+	while ( 1 ) {}
51
+}

+ 42
- 0
src/arch/i386/core/patch_cf.S View File

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright (C) 2009 H. Peter Anvin <hpa@zytor.com>
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License
6
+ * as published by the Free Software Foundation; either version 2
7
+ * of the License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17
+ *
18
+ * You can also choose to distribute this program under the terms of
19
+ * the Unmodified Binary Distribution Licence (as given in the file
20
+ * COPYING.UBDL), provided that you have satisfied its requirements.
21
+ */
22
+
23
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
24
+
25
+	.text
26
+	.arch i386
27
+	.code16
28
+
29
+/****************************************************************************
30
+ * Set/clear CF on the stack as appropriate, assumes stack is as it should
31
+ * be immediately before IRET
32
+ ****************************************************************************
33
+ */
34
+	.section ".text16", "ax", @progbits
35
+	.globl patch_cf
36
+patch_cf:
37
+	pushw	%bp
38
+	movw	%sp, %bp
39
+	setc	8(%bp)	/* Set/reset CF; clears PF, AF, ZF, SF */
40
+	popw	%bp
41
+	ret
42
+	.size patch_cf, . - patch_cf

+ 48
- 0
src/arch/i386/core/pci_autoboot.c View File

@@ -0,0 +1,48 @@
1
+/*
2
+ * Copyright (C) 2014 Red Hat Inc.
3
+ *	Alex Williamson <alex.williamson@redhat.com>
4
+ *
5
+ * This program is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU General Public License as
7
+ * published by the Free Software Foundation; either version 2 of the
8
+ * License, or any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful, but
11
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
+ * 02110-1301, USA.
19
+ *
20
+ * You can also choose to distribute this program under the terms of
21
+ * the Unmodified Binary Distribution Licence (as given in the file
22
+ * COPYING.UBDL), provided that you have satisfied its requirements.
23
+ */
24
+
25
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
26
+
27
+#include <stdint.h>
28
+#include <ipxe/device.h>
29
+#include <ipxe/init.h>
30
+#include <realmode.h>
31
+#include <usr/autoboot.h>
32
+
33
+uint16_t __bss16 ( autoboot_busdevfn );
34
+#define autoboot_busdevfn __use_data16 ( autoboot_busdevfn )
35
+
36
+/**
37
+ * Initialise PCI autoboot device
38
+ */
39
+static void pci_autoboot_init ( void ) {
40
+
41
+	if ( autoboot_busdevfn )
42
+		set_autoboot_busloc ( BUS_TYPE_PCI, autoboot_busdevfn );
43
+}
44
+
45
+/** PCI autoboot device initialisation function */
46
+struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = {
47
+	.initialise = pci_autoboot_init,
48
+};

+ 94
- 0
src/arch/i386/core/rdtsc_timer.c View File

@@ -0,0 +1,94 @@
1
+/*
2
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/** @file
27
+ *
28
+ * RDTSC timer
29
+ *
30
+ */
31
+
32
+#include <assert.h>
33
+#include <ipxe/timer.h>
34
+#include <ipxe/pit8254.h>
35
+
36
+/**
37
+ * Number of TSC ticks per microsecond
38
+ *
39
+ * This is calibrated on the first use of the timer.
40
+ */
41
+static unsigned long rdtsc_ticks_per_usec;
42
+
43
+/**
44
+ * Delay for a fixed number of microseconds
45
+ *
46
+ * @v usecs		Number of microseconds for which to delay
47
+ */
48
+static void rdtsc_udelay ( unsigned long usecs ) {
49
+	unsigned long start;
50
+	unsigned long elapsed;
51
+
52
+	/* Sanity guard, since we may divide by this */
53
+	if ( ! usecs )
54
+		usecs = 1;
55
+
56
+	start = currticks();
57
+	if ( rdtsc_ticks_per_usec ) {
58
+		/* Already calibrated; busy-wait until done */
59
+		do {
60
+			elapsed = ( currticks() - start );
61
+		} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
62
+	} else {
63
+		/* Not yet calibrated; use 8254 PIT and calibrate
64
+		 * based on result.
65
+		 */
66
+		pit8254_udelay ( usecs );
67
+		elapsed = ( currticks() - start );
68
+		rdtsc_ticks_per_usec = ( elapsed / usecs );
69
+		DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
70
+		      "(%ld MHz)\n", elapsed, usecs,
71
+		      ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
72
+	}
73
+}
74
+
75
+/**
76
+ * Get number of ticks per second
77
+ *
78
+ * @ret ticks_per_sec	Number of ticks per second
79
+ */
80
+static unsigned long rdtsc_ticks_per_sec ( void ) {
81
+
82
+	/* Calibrate timer, if not already done */
83
+	if ( ! rdtsc_ticks_per_usec )
84
+		udelay ( 1 );
85
+
86
+	/* Sanity check */
87
+	assert ( rdtsc_ticks_per_usec != 0 );
88
+
89
+	return ( rdtsc_ticks_per_usec * 1000 * 1000 );
90
+}
91
+
92
+PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
93
+PROVIDE_TIMER_INLINE ( rdtsc, currticks );
94
+PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );

+ 138
- 0
src/arch/i386/core/relocate.c View File

@@ -0,0 +1,138 @@
1
+#include <ipxe/io.h>
2
+#include <registers.h>
3
+
4
+/*
5
+ * Originally by Eric Biederman
6
+ *
7
+ * Heavily modified by Michael Brown 
8
+ *
9
+ */
10
+
11
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
12
+
13
+/*
14
+ * The linker passes in the symbol _max_align, which is the alignment
15
+ * that we must preserve, in bytes.
16
+ *
17
+ */
18
+extern char _max_align[];
19
+#define max_align ( ( unsigned int ) _max_align )
20
+
21
+/* Linker symbols */
22
+extern char _textdata[];
23
+extern char _etextdata[];
24
+
25
+/* within 1MB of 4GB is too close. 
26
+ * MAX_ADDR is the maximum address we can easily do DMA to.
27
+ *
28
+ * Not sure where this constraint comes from, but kept it from Eric's
29
+ * old code - mcb30
30
+ */
31
+#define MAX_ADDR (0xfff00000UL)
32
+
33
+/**
34
+ * Relocate iPXE
35
+ *
36
+ * @v ebp		Maximum address to use for relocation
37
+ * @ret esi		Current physical address
38
+ * @ret edi		New physical address
39
+ * @ret ecx		Length to copy
40
+ *
41
+ * This finds a suitable location for iPXE near the top of 32-bit
42
+ * address space, and returns the physical address of the new location
43
+ * to the prefix in %edi.
44
+ */
45
+__asmcall void relocate ( struct i386_all_regs *ix86 ) {
46
+	struct memory_map memmap;
47
+	unsigned long start, end, size, padded_size, max;
48
+	unsigned long new_start, new_end;
49
+	unsigned i;
50
+
51
+	/* Get memory map and current location */
52
+	get_memmap ( &memmap );
53
+	start = virt_to_phys ( _textdata );
54
+	end = virt_to_phys ( _etextdata );
55
+	size = ( end - start );
56
+	padded_size = ( size + max_align - 1 );
57
+
58
+	DBG ( "Relocate: currently at [%lx,%lx)\n"
59
+	      "...need %lx bytes for %d-byte alignment\n",
60
+	      start, end, padded_size, max_align );
61
+
62
+	/* Determine maximum usable address */
63
+	max = MAX_ADDR;
64
+	if ( ix86->regs.ebp < max ) {
65
+		max = ix86->regs.ebp;
66
+		DBG ( "Limiting relocation to [0,%lx)\n", max );
67
+	}
68
+
69
+	/* Walk through the memory map and find the highest address
70
+	 * below 4GB that iPXE will fit into.
71
+	 */
72
+	new_end = end;
73
+	for ( i = 0 ; i < memmap.count ; i++ ) {
74
+		struct memory_region *region = &memmap.regions[i];
75
+		unsigned long r_start, r_end;
76
+
77
+		DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
78
+		
79
+		/* Truncate block to maximum address.  This will be
80
+		 * less than 4GB, which means that we can get away
81
+		 * with using just 32-bit arithmetic after this stage.
82
+		 */
83
+		if ( region->start > max ) {
84
+			DBG ( "...starts after max=%lx\n", max );
85
+			continue;
86
+		}
87
+		r_start = region->start;
88
+		if ( region->end > max ) {
89
+			DBG ( "...end truncated to max=%lx\n", max );
90
+			r_end = max;
91
+		} else {
92
+			r_end = region->end;
93
+		}
94
+		DBG ( "...usable portion is [%lx,%lx)\n", r_start, r_end );
95
+
96
+		/* If we have rounded down r_end below r_ start, skip
97
+		 * this block.
98
+		 */
99
+		if ( r_end < r_start ) {
100
+			DBG ( "...truncated to negative size\n" );
101
+			continue;
102
+		}
103
+
104
+		/* Check that there is enough space to fit in iPXE */
105
+		if ( ( r_end - r_start ) < size ) {
106
+			DBG ( "...too small (need %lx bytes)\n", size );
107
+			continue;
108
+		}
109
+
110
+		/* If the start address of the iPXE we would
111
+		 * place in this block is higher than the end address
112
+		 * of the current highest block, use this block.
113
+		 *
114
+		 * Note that this avoids overlaps with the current
115
+		 * iPXE, as well as choosing the highest of all viable
116
+		 * blocks.
117
+		 */
118
+		if ( ( r_end - size ) > new_end ) {
119
+			new_end = r_end;
120
+			DBG ( "...new best block found.\n" );
121
+		}
122
+	}
123
+
124
+	/* Calculate new location of iPXE, and align it to the
125
+	 * required alignemnt.
126
+	 */
127
+	new_start = new_end - padded_size;
128
+	new_start += ( start - new_start ) & ( max_align - 1 );
129
+	new_end = new_start + size;
130
+
131
+	DBG ( "Relocating from [%lx,%lx) to [%lx,%lx)\n",
132
+	      start, end, new_start, new_end );
133
+	
134
+	/* Let prefix know what to copy */
135
+	ix86->regs.esi = start;
136
+	ix86->regs.edi = new_start;
137
+	ix86->regs.ecx = size;
138
+}

+ 269
- 0
src/arch/i386/core/runtime.c View File

@@ -0,0 +1,269 @@
1
+/*
2
+ * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/** @file
27
+ *
28
+ * Command line and initrd passed to iPXE at runtime
29
+ *
30
+ */
31
+
32
+#include <stddef.h>
33
+#include <stdint.h>
34
+#include <stdlib.h>
35
+#include <ctype.h>
36
+#include <errno.h>
37
+#include <assert.h>
38
+#include <ipxe/init.h>
39
+#include <ipxe/image.h>
40
+#include <ipxe/script.h>
41
+#include <ipxe/umalloc.h>
42
+#include <realmode.h>
43
+
44
+/** Command line physical address
45
+ *
46
+ * This can be set by the prefix.
47
+ */
48
+uint32_t __bss16 ( cmdline_phys );
49
+#define cmdline_phys __use_data16 ( cmdline_phys )
50
+
51
+/** initrd physical address
52
+ *
53
+ * This can be set by the prefix.
54
+ */
55
+uint32_t __bss16 ( initrd_phys );
56
+#define initrd_phys __use_data16 ( initrd_phys )
57
+
58
+/** initrd length
59
+ *
60
+ * This can be set by the prefix.
61
+ */
62
+uint32_t __bss16 ( initrd_len );
63
+#define initrd_len __use_data16 ( initrd_len )
64
+
65
+/** Internal copy of the command line */
66
+static char *cmdline_copy;
67
+
68
+/** Free command line image */
69
+static void cmdline_image_free ( struct refcnt *refcnt ) {
70
+	struct image *image = container_of ( refcnt, struct image, refcnt );
71
+
72
+	DBGC ( image, "RUNTIME freeing command line\n" );
73
+	free ( cmdline_copy );
74
+}
75
+
76
+/** Embedded script representing the command line */
77
+static struct image cmdline_image = {
78
+	.refcnt = REF_INIT ( cmdline_image_free ),
79
+	.name = "<CMDLINE>",
80
+	.type = &script_image_type,
81
+};
82
+
83
+/** Colour for debug messages */
84
+#define colour &cmdline_image
85
+
86
+/**
87
+ * Strip unwanted cruft from command line
88
+ *
89
+ * @v cmdline		Command line
90
+ * @v cruft		Initial substring of cruft to strip
91
+ */
92
+static void cmdline_strip ( char *cmdline, const char *cruft ) {
93
+	char *strip;
94
+	char *strip_end;
95
+
96
+	/* Find unwanted cruft, if present */
97
+	if ( ! ( strip = strstr ( cmdline, cruft ) ) )
98
+		return;
99
+
100
+	/* Strip unwanted cruft */
101
+	strip_end = strchr ( strip, ' ' );
102
+	if ( strip_end ) {
103
+		*strip_end = '\0';
104
+		DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
105
+		strcpy ( strip, ( strip_end + 1 ) );
106
+	} else {
107
+		DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
108
+		*strip = '\0';
109
+	}
110
+}
111
+
112
+/**
113
+ * Initialise command line
114
+ *
115
+ * @ret rc		Return status code
116
+ */
117
+static int cmdline_init ( void ) {
118
+	userptr_t cmdline_user;
119
+	char *cmdline;
120
+	size_t len;
121
+	int rc;
122
+
123
+	/* Do nothing if no command line was specified */
124
+	if ( ! cmdline_phys ) {
125
+		DBGC ( colour, "RUNTIME found no command line\n" );
126
+		return 0;
127
+	}
128
+	cmdline_user = phys_to_user ( cmdline_phys );
129
+	len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
130
+
131
+	/* Allocate and copy command line */
132
+	cmdline_copy = malloc ( len );
133
+	if ( ! cmdline_copy ) {
134
+		DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
135
+		       "command line\n", len );
136
+		rc = -ENOMEM;
137
+		goto err_alloc_cmdline_copy;
138
+	}
139
+	cmdline = cmdline_copy;
140
+	copy_from_user ( cmdline, cmdline_user, 0, len );
141
+	DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
142
+	       cmdline, cmdline_phys );
143
+
144
+	/* Mark command line as consumed */
145
+	cmdline_phys = 0;
146
+
147
+	/* Strip unwanted cruft from the command line */
148
+	cmdline_strip ( cmdline, "BOOT_IMAGE=" );
149
+	cmdline_strip ( cmdline, "initrd=" );
150
+	while ( isspace ( *cmdline ) )
151
+		cmdline++;
152
+	DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
153
+
154
+	/* Prepare and register image */
155
+	cmdline_image.data = virt_to_user ( cmdline );
156
+	cmdline_image.len = strlen ( cmdline );
157
+	if ( cmdline_image.len ) {
158
+		if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
159
+			DBGC ( colour, "RUNTIME could not register command "
160
+			       "line: %s\n", strerror ( rc ) );
161
+			goto err_register_image;
162
+		}
163
+	}
164
+
165
+	/* Drop our reference to the image */
166
+	image_put ( &cmdline_image );
167
+
168
+	return 0;
169
+
170
+ err_register_image:
171
+	image_put ( &cmdline_image );
172
+ err_alloc_cmdline_copy:
173
+	return rc;
174
+}
175
+
176
+/**
177
+ * Initialise initrd
178
+ *
179
+ * @ret rc		Return status code
180
+ */
181
+static int initrd_init ( void ) {
182
+	struct image *image;
183
+	int rc;
184
+
185
+	/* Do nothing if no initrd was specified */
186
+	if ( ! initrd_phys ) {
187
+		DBGC ( colour, "RUNTIME found no initrd\n" );
188
+		return 0;
189
+	}
190
+	if ( ! initrd_len ) {
191
+		DBGC ( colour, "RUNTIME found empty initrd\n" );
192
+		return 0;
193
+	}
194
+	DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
195
+	       initrd_phys, ( initrd_phys + initrd_len ) );
196
+
197
+	/* Allocate image */
198
+	image = alloc_image ( NULL );
199
+	if ( ! image ) {
200
+		DBGC ( colour, "RUNTIME could not allocate image for "
201
+		       "initrd\n" );
202
+		rc = -ENOMEM;
203
+		goto err_alloc_image;
204
+	}
205
+	if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
206
+		DBGC ( colour, "RUNTIME could not set image name: %s\n",
207
+		       strerror ( rc ) );
208
+		goto err_set_name;
209
+	}
210
+
211
+	/* Allocate and copy initrd content */
212
+	image->data = umalloc ( initrd_len );
213
+	if ( ! image->data ) {
214
+		DBGC ( colour, "RUNTIME could not allocate %d bytes for "
215
+		       "initrd\n", initrd_len );
216
+		rc = -ENOMEM;
217
+		goto err_umalloc;
218
+	}
219
+	image->len = initrd_len;
220
+	memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
221
+		      initrd_len );
222
+
223
+	/* Mark initrd as consumed */
224
+	initrd_phys = 0;
225
+
226
+	/* Register image */
227
+	if ( ( rc = register_image ( image ) ) != 0 ) {
228
+		DBGC ( colour, "RUNTIME could not register initrd: %s\n",
229
+		       strerror ( rc ) );
230
+		goto err_register_image;
231
+	}
232
+
233
+	/* Drop our reference to the image */
234
+	image_put ( image );
235
+
236
+	return 0;
237
+
238
+ err_register_image:
239
+ err_umalloc:
240
+ err_set_name:
241
+	image_put ( image );
242
+ err_alloc_image:
243
+	return rc;
244
+}
245
+
246
+/**
247
+ * Initialise command line and initrd
248
+ *
249
+ */
250
+static void runtime_init ( void ) {
251
+	int rc;
252
+
253
+	/* Initialise command line */
254
+	if ( ( rc = cmdline_init() ) != 0 ) {
255
+		/* No way to report failure */
256
+		return;
257
+	}
258
+
259
+	/* Initialise initrd */
260
+	if ( ( rc = initrd_init() ) != 0 ) {
261
+		/* No way to report failure */
262
+		return;
263
+	}
264
+}
265
+
266
+/** Command line and initrd initialisation function */
267
+struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
268
+	.startup = runtime_init,
269
+};

+ 64
- 0
src/arch/i386/core/setjmp.S View File

@@ -0,0 +1,64 @@
1
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
2
+
3
+	.text
4
+	.arch i386
5
+	.code32
6
+
7
+	/* Must match jmp_buf structure layout */
8
+	.struct	0
9
+env_retaddr:	.long	0
10
+env_stack:	.long	0
11
+env_ebx:	.long	0
12
+env_esi:	.long	0
13
+env_edi:	.long	0
14
+env_ebp:	.long	0
15
+	.previous
16
+
17
+/*
18
+ * Save stack context for non-local goto
19
+ */
20
+	.globl	setjmp
21
+setjmp:
22
+	/* Get jmp_buf pointer in %edx */
23
+	movl	4(%esp),%edx
24
+	/* Save return address */
25
+	movl	0(%esp),%eax
26
+	movl	%eax, env_retaddr(%edx)
27
+	/* Save stack pointer */
28
+	movl	%esp, env_stack(%edx)
29
+	/* Save other registers */
30
+	movl	%ebx, env_ebx(%edx)
31
+	movl	%esi, env_esi(%edx)
32
+	movl	%edi, env_edi(%edx)
33
+	movl	%ebp, env_ebp(%edx)
34
+	/* Return 0 when returning as setjmp() */
35
+	xorl	%eax, %eax
36
+	ret
37
+	.size	setjmp, . - setjmp
38
+
39
+/*
40
+ * Non-local jump to a saved stack context
41
+ */
42
+	.globl	longjmp
43
+longjmp:
44
+	/* Get jmp_buf pointer in %edx */
45
+	movl	4(%esp),%edx
46
+	/* Get result in %eax */
47
+	movl	8(%esp),%eax
48
+	/* Force result to non-zero */
49
+	testl	%eax, %eax
50
+	jnz	1f
51
+	incl	%eax
52
+1:	/* Restore stack pointer */
53
+	movl	env_stack(%edx), %esp
54
+	/* Restore other registers */
55
+	movl	env_ebx(%edx), %ebx
56
+	movl	env_esi(%edx), %esi
57
+	movl	env_edi(%edx), %edi
58
+	movl	env_ebp(%edx), %ebp
59
+	/* Replace return address on the new stack */
60
+	popl	%ecx	/* discard */
61
+	pushl	env_retaddr(%edx)
62
+	/* Return to setjmp() caller */
63
+	ret
64
+	.size	longjmp, . - longjmp

+ 15
- 0
src/arch/i386/core/stack.S View File

@@ -0,0 +1,15 @@
1
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
2
+
3
+	.arch i386
4
+
5
+/****************************************************************************
6
+ * Internal stack
7
+ ****************************************************************************
8
+ */
9
+	.section ".stack", "aw", @nobits
10
+	.align 8
11
+	.globl _stack
12
+_stack:
13
+	.space 4096
14
+	.globl _estack
15
+_estack:

+ 15
- 0
src/arch/i386/core/stack16.S View File

@@ -0,0 +1,15 @@
1
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
2
+
3
+	.arch i386
4
+
5
+/****************************************************************************
6
+ * Internal stack
7
+ ****************************************************************************
8
+ */
9
+	.section ".stack16", "aw", @nobits
10
+	.align 8
11
+	.globl _stack16
12
+_stack16:
13
+	.space 4096
14
+	.globl _estack16
15
+_estack16:

+ 113
- 0
src/arch/i386/core/video_subr.c View File

@@ -0,0 +1,113 @@
1
+/*
2
+ *
3
+ * modified from linuxbios code
4
+ * by Cai Qiang <rimy2000@hotmail.com>
5
+ *
6
+ */
7
+
8
+#include "stddef.h"
9
+#include "string.h"
10
+#include <ipxe/io.h>
11
+#include <ipxe/console.h>
12
+#include <ipxe/init.h>
13
+#include "vga.h"
14
+#include <config/console.h>
15
+
16
+/* Set default console usage if applicable */
17
+#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
18
+	CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
19
+#undef CONSOLE_DIRECT_VGA
20
+#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
21
+#endif
22
+
23
+struct console_driver vga_console __console_driver;
24
+
25
+static char *vidmem;		/* The video buffer */
26
+static int video_line, video_col;
27
+
28
+#define VIDBUFFER 0xB8000	
29
+
30
+static void memsetw(void *s, int c, unsigned int n)
31
+{
32
+	unsigned int i;
33
+	u16 *ss = (u16 *) s;
34
+
35
+	for (i = 0; i < n; i++) {
36
+		ss[i] = ( u16 ) c;
37
+	}
38
+}
39
+
40
+static void video_init(void)
41
+{
42
+	static int inited=0;
43
+
44
+	vidmem = (char *)phys_to_virt(VIDBUFFER);
45
+
46
+	if (!inited) {
47
+		video_line = 0;
48
+		video_col = 0;
49
+	
50
+	 	memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
51
+
52
+		inited=1;
53
+	}
54
+}
55
+
56
+static void video_scroll(void)
57
+{
58
+	int i;
59
+
60
+	memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
61
+	for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
62
+		vidmem[i] = ' ';
63
+}
64
+
65
+static void vga_putc(int byte)
66
+{
67
+	if (byte == '\n') {
68
+		video_line++;
69
+		video_col = 0;
70
+
71
+	} else if (byte == '\r') {
72
+		video_col = 0;
73
+
74
+	} else if (byte == '\b') {
75
+		video_col--;
76
+
77
+	} else if (byte == '\t') {
78
+		video_col += 4;
79
+
80
+	} else if (byte == '\a') {
81
+		//beep
82
+		//beep(500);
83
+
84
+	} else {
85
+		vidmem[((video_col + (video_line *COLS)) * 2)] = byte;
86
+		vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
87
+		video_col++;
88
+	}
89
+	if (video_col < 0) {
90
+		video_col = 0;
91
+	}
92
+	if (video_col >= COLS) {
93
+		video_line++;
94
+		video_col = 0;
95
+	}
96
+	if (video_line >= LINES) {
97
+		video_scroll();
98
+		video_line--;
99
+	}
100
+	// move the cursor
101
+	write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI);
102
+	write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
103
+}
104
+
105
+struct console_driver vga_console __console_driver = {
106
+	.putchar = vga_putc,
107
+	.disabled = CONSOLE_DISABLED,
108
+	.usage = CONSOLE_DIRECT_VGA,
109
+};
110
+
111
+struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
112
+	.initialise = video_init,
113
+};

+ 145
- 0
src/arch/i386/core/virtaddr.S View File

@@ -0,0 +1,145 @@
1
+/*
2
+ * Functions to support the virtual addressing method of relocation
3
+ * that Etherboot uses.
4
+ *
5
+ */
6
+
7
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
8
+
9
+#include "librm.h"
10
+		
11
+	.arch i386
12
+	.text
13
+	.code32
14
+	
15
+/****************************************************************************
16
+ * _virt_to_phys (virtual addressing)
17
+ *
18
+ * Switch from virtual to flat physical addresses.  %esp is adjusted
19
+ * to a physical value.  Segment registers are set to flat physical
20
+ * selectors.  All other registers are preserved.  Flags are
21
+ * preserved.
22
+ *
23
+ * Parameters: none
24
+ * Returns: none
25
+ ****************************************************************************
26
+ */
27
+	.globl _virt_to_phys
28
+_virt_to_phys:
29
+	/* Preserve registers and flags */
30
+	pushfl
31
+	pushl	%eax
32
+	pushl	%ebp
33
+
34
+	/* Change return address to a physical address */
35
+	movl	virt_offset, %ebp
36
+	addl	%ebp, 12(%esp)
37
+
38
+	/* Switch to physical code segment */
39
+	cli
40
+	pushl	$PHYSICAL_CS
41
+	leal	1f(%ebp), %eax
42
+	pushl	%eax
43
+	lret
44
+1:
45
+	/* Reload other segment registers and adjust %esp */
46
+	movl	$PHYSICAL_DS, %eax
47
+	movl	%eax, %ds
48
+	movl	%eax, %es
49
+	movl	%eax, %fs
50
+	movl	%eax, %gs
51
+	movl	%eax, %ss
52
+	addl	%ebp, %esp
53
+
54
+	/* Restore registers and flags, and return */
55
+	popl	%ebp
56
+	popl	%eax
57
+	popfl
58
+	ret
59
+
60
+/****************************************************************************
61
+ * _phys_to_virt (flat physical addressing)
62
+ *
63
+ * Switch from flat physical to virtual addresses.  %esp is adjusted
64
+ * to a virtual value.  Segment registers are set to virtual
65
+ * selectors.  All other registers are preserved.  Flags are
66
+ * preserved.
67
+ *
68
+ * Parameters: none
69
+ * Returns: none
70
+ ****************************************************************************
71
+ */
72
+	.globl _phys_to_virt
73
+_phys_to_virt:
74
+	/* Preserve registers and flags */
75
+	pushfl
76
+	pushl	%eax
77
+	pushl	%ebp
78
+
79
+	/* Switch to virtual code segment */
80
+	cli
81
+	ljmp	$VIRTUAL_CS, $1f
82
+1:
83
+	/* Reload data segment registers */
84
+	movl	$VIRTUAL_DS, %eax
85
+	movl	%eax, %ds
86
+	movl	%eax, %es
87
+	movl	%eax, %fs
88
+	movl	%eax, %gs
89
+
90
+	/* Reload stack segment and adjust %esp */
91
+	movl	virt_offset, %ebp
92
+	movl	%eax, %ss
93
+	subl	%ebp, %esp
94
+
95
+	/* Change the return address to a virtual address */
96
+	subl	%ebp, 12(%esp)
97
+
98
+	/* Restore registers and flags, and return */
99
+	popl	%ebp
100
+	popl	%eax
101
+	popfl
102
+	ret
103
+
104
+/****************************************************************************
105
+ * _intr_to_virt (virtual code segment, virtual or physical stack segment)
106
+ *
107
+ * Switch from virtual code segment with either a virtual or physical
108
+ * stack segment to using virtual addressing.  %esp is adjusted if
109
+ * necessary to a virtual value.  Segment registers are set to virtual
110
+ * selectors.  All other registers are preserved.  Flags are
111
+ * preserved.
112
+ *
113
+ * Parameters: none
114
+ * Returns: none
115
+ ****************************************************************************
116
+ */
117
+	.globl _intr_to_virt
118
+_intr_to_virt:
119
+	/* Preserve registers and flags */
120
+	pushfl
121
+	pushl	%eax
122
+	pushl	%ebp
123
+
124
+	/* Check whether stack segment is physical or virtual */
125
+	movl	%ss, %eax
126
+	cmpw	$VIRTUAL_DS, %ax
127
+	movl	$VIRTUAL_DS, %eax
128
+
129
+	/* Reload data segment registers */
130
+	movl	%eax, %ds
131
+	movl	%eax, %es
132
+	movl	%eax, %fs
133
+	movl	%eax, %gs
134
+
135
+	/* Reload stack segment and adjust %esp if necessary */
136
+	je	1f
137
+	movl	virt_offset, %ebp
138
+	movl	%eax, %ss
139
+	subl	%ebp, %esp
140
+1:
141
+	/* Restore registers and flags, and return */
142
+	popl	%ebp
143
+	popl	%eax
144
+	popfl
145
+	ret

+ 146
- 0
src/arch/i386/drivers/net/undi.c View File

@@ -0,0 +1,146 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <stdio.h>
25
+#include <string.h>
26
+#include <ipxe/pci.h>
27
+#include <undi.h>
28
+#include <undirom.h>
29
+#include <undiload.h>
30
+#include <undinet.h>
31
+#include <undipreload.h>
32
+
33
+/** @file
34
+ *
35
+ * UNDI PCI driver
36
+ *
37
+ */
38
+
39
+/**
40
+ * Find UNDI ROM for PCI device
41
+ *
42
+ * @v pci		PCI device
43
+ * @ret undirom		UNDI ROM, or NULL
44
+ *
45
+ * Try to find a driver for this device.  Try an exact match on the
46
+ * ROM address first, then fall back to a vendor/device ID match only
47
+ */
48
+static struct undi_rom * undipci_find_rom ( struct pci_device *pci ) {
49
+	struct undi_rom *undirom;
50
+	unsigned long rombase;
51
+	
52
+	rombase = pci_bar_start ( pci, PCI_ROM_ADDRESS );
53
+	undirom = undirom_find_pci ( pci->vendor, pci->device, rombase );
54
+	if ( ! undirom )
55
+		undirom = undirom_find_pci ( pci->vendor, pci->device, 0 );
56
+	return undirom;
57
+}
58
+
59
+/**
60
+ * Probe PCI device
61
+ *
62
+ * @v pci		PCI device
63
+ * @v id		PCI ID
64
+ * @ret rc		Return status code
65
+ */
66
+static int undipci_probe ( struct pci_device *pci ) {
67
+	struct undi_device *undi;
68
+	struct undi_rom *undirom;
69
+	int rc;
70
+
71
+	/* Allocate UNDI device structure */
72
+	undi = zalloc ( sizeof ( *undi ) );
73
+	if ( ! undi )
74
+		return -ENOMEM;
75
+	pci_set_drvdata ( pci, undi );
76
+
77
+	/* Find/create our pixie */
78
+	if ( preloaded_undi.pci_busdevfn == pci->busdevfn ) {
79
+		/* Claim preloaded UNDI device */
80
+		DBGC ( undi, "UNDI %p using preloaded UNDI device\n", undi );
81
+		memcpy ( undi, &preloaded_undi, sizeof ( *undi ) );
82
+		memset ( &preloaded_undi, 0, sizeof ( preloaded_undi ) );
83
+	} else {
84
+		/* Find UNDI ROM for PCI device */
85
+		if ( ! ( undirom = undipci_find_rom ( pci ) ) ) {
86
+			rc = -ENODEV;
87
+			goto err_find_rom;
88
+		}
89
+
90
+		/* Call UNDI ROM loader to create pixie */
91
+		if ( ( rc = undi_load_pci ( undi, undirom,
92
+					    pci->busdevfn ) ) != 0 ) {
93
+			goto err_load_pci;
94
+		}
95
+	}
96
+
97
+	/* Add to device hierarchy */
98
+	snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
99
+		   "UNDI-%s", pci->dev.name );
100
+	memcpy ( &undi->dev.desc, &pci->dev.desc, sizeof ( undi->dev.desc ) );
101
+	undi->dev.parent = &pci->dev;
102
+	INIT_LIST_HEAD ( &undi->dev.children );
103
+	list_add ( &undi->dev.siblings, &pci->dev.children );
104
+
105
+	/* Create network device */
106
+	if ( ( rc = undinet_probe ( undi ) ) != 0 )
107
+		goto err_undinet_probe;
108
+	
109
+	return 0;
110
+
111
+ err_undinet_probe:
112
+	undi_unload ( undi );
113
+	list_del ( &undi->dev.siblings );
114
+ err_find_rom:
115
+ err_load_pci:
116
+	free ( undi );
117
+	pci_set_drvdata ( pci, NULL );
118
+	return rc;
119
+}
120
+
121
+/**
122
+ * Remove PCI device
123
+ *
124
+ * @v pci	PCI device
125
+ */
126
+static void undipci_remove ( struct pci_device *pci ) {
127
+	struct undi_device *undi = pci_get_drvdata ( pci );
128
+
129
+	undinet_remove ( undi );
130
+	undi_unload ( undi );
131
+	list_del ( &undi->dev.siblings );
132
+	free ( undi );
133
+	pci_set_drvdata ( pci, NULL );
134
+}
135
+
136
+static struct pci_device_id undipci_nics[] = {
137
+	PCI_ROM ( 0xffff, 0xffff, "undipci", "UNDI (PCI)", 0 ),
138
+};
139
+
140
+struct pci_driver undipci_driver __pci_driver_fallback = {
141
+	.ids = undipci_nics,
142
+	.id_count = ( sizeof ( undipci_nics ) / sizeof ( undipci_nics[0] ) ),
143
+	.class = PCI_CLASS_ID ( PCI_CLASS_NETWORK, PCI_ANY_ID, PCI_ANY_ID ),
144
+	.probe = undipci_probe,
145
+	.remove = undipci_remove,
146
+};

+ 87
- 0
src/arch/i386/drivers/net/undiisr.S View File

@@ -0,0 +1,87 @@
1
+FILE_LICENCE ( GPL2_OR_LATER )
2
+
3
+#define PXENV_UNDI_ISR 0x0014
4
+#define PXENV_UNDI_ISR_IN_START 1
5
+#define PXENV_UNDI_ISR_OUT_OURS 0
6
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1
7
+
8
+#define IRQ_PIC_CUTOFF 8
9
+#define ICR_EOI_NON_SPECIFIC 0x20
10
+#define PIC1_ICR 0x20
11
+#define PIC2_ICR 0xa0
12
+	
13
+	.text
14
+	.arch i386
15
+	.code16
16
+
17
+	.section ".text16", "ax", @progbits
18
+	.globl undiisr
19
+undiisr:
20
+	
21
+	/* Preserve registers */
22
+	pushw	%ds
23
+	pushw	%es
24
+	pushw	%fs
25
+	pushw	%gs
26
+	pushfl
27
+	pushal
28
+
29
+	/* Set up our segment registers */
30
+	movw	%cs:rm_ds, %ax
31
+	movw	%ax, %ds
32
+
33
+	/* Check that we have an UNDI entry point */
34
+	cmpw	$0, pxeparent_entry_point
35
+	je	chain
36
+	
37
+	/* Issue UNDI API call */
38
+	movw	%ax, %es
39
+	movw	$undinet_params, %di
40
+	movw	$PXENV_UNDI_ISR, %bx
41
+	movw	$PXENV_UNDI_ISR_IN_START, funcflag
42
+	pushw	%es
43
+	pushw	%di
44
+	pushw	%bx
45
+	lcall	*pxeparent_entry_point
46
+	cli	/* Just in case */
47
+	addw	$6, %sp
48
+	cmpw	$PXENV_UNDI_ISR_OUT_OURS, funcflag
49
+	jne	eoi
50
+	
51
+trig:	/* Record interrupt occurence */
52
+	incb	undiisr_trigger_count
53
+
54
+eoi:	/* Send EOI */
55
+	movb	$ICR_EOI_NON_SPECIFIC, %al
56
+	cmpb	$IRQ_PIC_CUTOFF, undiisr_irq
57
+	jb	1f
58
+	outb	%al, $PIC2_ICR
59
+1:	outb	%al, $PIC1_ICR
60
+	jmp	exit
61
+	
62
+chain:	/* Chain to next handler */
63
+	pushfw
64
+	lcall	*undiisr_next_handler
65
+	
66
+exit:	/* Restore registers and return */
67
+	cli
68
+	popal
69
+	movzwl	%sp, %esp
70
+	addr32	movl -20(%esp), %esp	/* %esp isn't restored by popal */
71
+	popfl
72
+	popw	%gs
73
+	popw	%fs
74
+	popw	%es
75
+	popw	%ds
76
+	iret
77
+
78
+	.section ".data16", "aw", @progbits
79
+undinet_params:
80
+status:			.word	0
81
+funcflag:		.word	0
82
+bufferlength:		.word	0
83
+framelength:		.word	0
84
+frameheaderlength:	.word	0
85
+frame:			.word	0, 0
86
+prottype:		.byte	0
87
+pkttype:		.byte	0

+ 184
- 0
src/arch/i386/drivers/net/undiload.c View File

@@ -0,0 +1,184 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <stdlib.h>
28
+#include <string.h>
29
+#include <pxe.h>
30
+#include <realmode.h>
31
+#include <bios.h>
32
+#include <pnpbios.h>
33
+#include <basemem.h>
34
+#include <ipxe/pci.h>
35
+#include <undi.h>
36
+#include <undirom.h>
37
+#include <undiload.h>
38
+
39
+/** @file
40
+ *
41
+ * UNDI load/unload
42
+ *
43
+ */
44
+
45
+/* Disambiguate the various error causes */
46
+#define EINFO_EUNDILOAD							\
47
+	__einfo_uniqify ( EINFO_EPLATFORM, 0x01,			\
48
+			  "UNDI loader error" )
49
+#define EUNDILOAD( status ) EPLATFORM ( EINFO_EUNDILOAD, status )
50
+
51
+/** Parameter block for calling UNDI loader */
52
+static struct s_UNDI_LOADER __bss16 ( undi_loader );
53
+#define undi_loader __use_data16 ( undi_loader )
54
+
55
+/** UNDI loader entry point */
56
+static SEGOFF16_t __bss16 ( undi_loader_entry );
57
+#define undi_loader_entry __use_data16 ( undi_loader_entry )
58
+
59
+/**
60
+ * Call UNDI loader to create a pixie
61
+ *
62
+ * @v undi		UNDI device
63
+ * @v undirom		UNDI ROM
64
+ * @ret rc		Return status code
65
+ */
66
+int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
67
+	struct s_PXE ppxe;
68
+	unsigned int fbms_seg;
69
+	uint16_t exit;
70
+	int rc;
71
+
72
+	/* Only one UNDI instance may be loaded at any given time */
73
+	if ( undi_loader_entry.segment ) {
74
+		DBG ( "UNDI %p cannot load multiple instances\n", undi );
75
+		return -EBUSY;
76
+	}
77
+
78
+	/* Set up START_UNDI parameters */
79
+	memset ( &undi_loader, 0, sizeof ( undi_loader ) );
80
+	undi_loader.AX = undi->pci_busdevfn;
81
+	undi_loader.BX = undi->isapnp_csn;
82
+	undi_loader.DX = undi->isapnp_read_port;
83
+	undi_loader.ES = BIOS_SEG;
84
+	undi_loader.DI = find_pnp_bios();
85
+
86
+	/* Allocate base memory for PXE stack */
87
+	undi->restore_fbms = get_fbms();
88
+	fbms_seg = ( undi->restore_fbms << 6 );
89
+	fbms_seg -= ( ( undirom->code_size + 0x0f ) >> 4 );
90
+	undi_loader.UNDI_CS = fbms_seg;
91
+	fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 );
92
+	undi_loader.UNDI_DS = fbms_seg;
93
+
94
+	/* Debug info */
95
+	DBGC ( undi, "UNDI %p loading UNDI ROM %p to CS %04x DS %04x for ",
96
+	       undi, undirom, undi_loader.UNDI_CS, undi_loader.UNDI_DS );
97
+	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
98
+		unsigned int bus = ( undi->pci_busdevfn >> 8 );
99
+		unsigned int devfn = ( undi->pci_busdevfn & 0xff );
100
+		DBGC ( undi, "PCI %02x:%02x.%x\n",
101
+		       bus, PCI_SLOT ( devfn ), PCI_FUNC ( devfn ) );
102
+	}
103
+	if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
104
+		DBGC ( undi, "ISAPnP(%04x) CSN %04x\n",
105
+		       undi->isapnp_read_port, undi->isapnp_csn );
106
+	}
107
+
108
+	/* Call loader */
109
+	undi_loader_entry = undirom->loader_entry;
110
+	__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
111
+					   "pushw %%ds\n\t"
112
+					   "pushw %%ax\n\t"
113
+					   "lcall *undi_loader_entry\n\t"
114
+					   "popl %%ebp\n\t" /* discard */
115
+					   "popl %%ebp\n\t" /* gcc bug */ )
116
+			       : "=a" ( exit )
117
+			       : "a" ( __from_data16 ( &undi_loader ) )
118
+			       : "ebx", "ecx", "edx", "esi", "edi" );
119
+
120
+	if ( exit != PXENV_EXIT_SUCCESS ) {
121
+		/* Clear entry point */
122
+		memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
123
+
124
+		rc = -EUNDILOAD ( undi_loader.Status );
125
+		DBGC ( undi, "UNDI %p loader failed: %s\n",
126
+		       undi, strerror ( rc ) );
127
+		return rc;
128
+	}
129
+
130
+	/* Populate PXE device structure */
131
+	undi->pxenv = undi_loader.PXENVptr;
132
+	undi->ppxe = undi_loader.PXEptr;
133
+	copy_from_real ( &ppxe, undi->ppxe.segment, undi->ppxe.offset,
134
+			 sizeof ( ppxe ) );
135
+	undi->entry = ppxe.EntryPointSP;
136
+	DBGC ( undi, "UNDI %p loaded PXENV+ %04x:%04x !PXE %04x:%04x "
137
+	       "entry %04x:%04x\n", undi, undi->pxenv.segment,
138
+	       undi->pxenv.offset, undi->ppxe.segment, undi->ppxe.offset,
139
+	       undi->entry.segment, undi->entry.offset );
140
+
141
+	/* Update free base memory counter */
142
+	undi->fbms = ( fbms_seg >> 6 );
143
+	set_fbms ( undi->fbms );
144
+	DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n",
145
+	       undi, undi->fbms, undi->restore_fbms );
146
+
147
+	return 0;
148
+}
149
+
150
+/**
151
+ * Unload a pixie
152
+ *
153
+ * @v undi		UNDI device
154
+ * @ret rc		Return status code
155
+ *
156
+ * Erases the PXENV+ and !PXE signatures, and frees the used base
157
+ * memory (if possible).
158
+ */
159
+int undi_unload ( struct undi_device *undi ) {
160
+	static uint32_t dead = 0xdeaddead;
161
+
162
+	DBGC ( undi, "UNDI %p unloading\n", undi );
163
+
164
+	/* Clear entry point */
165
+	memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
166
+
167
+	/* Erase signatures */
168
+	if ( undi->pxenv.segment )
169
+		put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );
170
+	if ( undi->ppxe.segment )
171
+		put_real ( dead, undi->ppxe.segment, undi->ppxe.offset );
172
+
173
+	/* Free base memory, if possible */
174
+	if ( undi->fbms == get_fbms() ) {
175
+		DBGC ( undi, "UNDI %p freeing [%d,%d) kB of base memory\n",
176
+		       undi, undi->fbms, undi->restore_fbms );
177
+		set_fbms ( undi->restore_fbms );
178
+		return 0;
179
+	} else {
180
+		DBGC ( undi, "UNDI %p leaking [%d,%d) kB of base memory\n",
181
+		       undi, undi->fbms, undi->restore_fbms );
182
+		return -EBUSY;
183
+	}
184
+}

+ 822
- 0
src/arch/i386/drivers/net/undinet.c View File

@@ -0,0 +1,822 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <string.h>
23
+#include <unistd.h>
24
+#include <byteswap.h>
25
+#include <pxe.h>
26
+#include <realmode.h>
27
+#include <pic8259.h>
28
+#include <biosint.h>
29
+#include <pnpbios.h>
30
+#include <basemem_packet.h>
31
+#include <ipxe/io.h>
32
+#include <ipxe/iobuf.h>
33
+#include <ipxe/netdevice.h>
34
+#include <ipxe/if_ether.h>
35
+#include <ipxe/ethernet.h>
36
+#include <ipxe/profile.h>
37
+#include <undi.h>
38
+#include <undinet.h>
39
+#include <pxeparent.h>
40
+
41
+/** @file
42
+ *
43
+ * UNDI network device driver
44
+ *
45
+ */
46
+
47
+/** An UNDI NIC */
48
+struct undi_nic {
49
+	/** Device supports IRQs */
50
+	int irq_supported;
51
+	/** Assigned IRQ number */
52
+	unsigned int irq;
53
+	/** Currently processing ISR */
54
+	int isr_processing;
55
+	/** Bug workarounds */
56
+	int hacks;
57
+};
58
+
59
+/**
60
+ * @defgroup undi_hacks UNDI workarounds
61
+ * @{
62
+ */
63
+
64
+/** Work around Etherboot 5.4 bugs */
65
+#define UNDI_HACK_EB54		0x0001
66
+
67
+/** @} */
68
+
69
+/** Maximum number of times to retry PXENV_UNDI_INITIALIZE */
70
+#define UNDI_INITIALIZE_RETRY_MAX 10
71
+
72
+/** Delay between retries of PXENV_UNDI_INITIALIZE */
73
+#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
74
+
75
+/** Maximum number of received packets per poll */
76
+#define UNDI_RX_QUOTA 4
77
+
78
+/** Alignment of received frame payload */
79
+#define UNDI_RX_ALIGN 16
80
+
81
+static void undinet_close ( struct net_device *netdev );
82
+
83
+/** Address of UNDI entry point */
84
+static SEGOFF16_t undinet_entry;
85
+
86
+/** Transmit profiler */
87
+static struct profiler undinet_tx_profiler __profiler =
88
+	{ .name = "undinet.tx" };
89
+
90
+/** Transmit call profiler */
91
+static struct profiler undinet_tx_call_profiler __profiler =
92
+	{ .name = "undinet.tx_call" };
93
+
94
+/** IRQ profiler */
95
+static struct profiler undinet_irq_profiler __profiler =
96
+	{ .name = "undinet.irq" };
97
+
98
+/** ISR call profiler */
99
+static struct profiler undinet_isr_call_profiler __profiler =
100
+	{ .name = "undinet.isr_call" };
101
+
102
+/** Receive profiler */
103
+static struct profiler undinet_rx_profiler __profiler =
104
+	{ .name = "undinet.rx" };
105
+
106
+/*****************************************************************************
107
+ *
108
+ * UNDI interrupt service routine
109
+ *
110
+ *****************************************************************************
111
+ */
112
+
113
+/**
114
+ * UNDI interrupt service routine
115
+ *
116
+ * The UNDI ISR increments a counter (@c trigger_count) and exits.
117
+ */
118
+extern void undiisr ( void );
119
+
120
+/** IRQ number */
121
+uint8_t __data16 ( undiisr_irq );
122
+#define undiisr_irq __use_data16 ( undiisr_irq )
123
+
124
+/** IRQ chain vector */
125
+struct segoff __data16 ( undiisr_next_handler );
126
+#define undiisr_next_handler __use_data16 ( undiisr_next_handler )
127
+
128
+/** IRQ trigger count */
129
+volatile uint8_t __data16 ( undiisr_trigger_count ) = 0;
130
+#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count )
131
+
132
+/** Last observed trigger count */
133
+static unsigned int last_trigger_count = 0;
134
+
135
+/**
136
+ * Hook UNDI interrupt service routine
137
+ *
138
+ * @v irq		IRQ number
139
+ */
140
+static void undinet_hook_isr ( unsigned int irq ) {
141
+
142
+	assert ( irq <= IRQ_MAX );
143
+	assert ( undiisr_irq == 0 );
144
+
145
+	undiisr_irq = irq;
146
+	hook_bios_interrupt ( IRQ_INT ( irq ),
147
+			      ( ( unsigned int ) undiisr ),
148
+			      &undiisr_next_handler );
149
+}
150
+
151
+/**
152
+ * Unhook UNDI interrupt service routine
153
+ *
154
+ * @v irq		IRQ number
155
+ */
156
+static void undinet_unhook_isr ( unsigned int irq ) {
157
+
158
+	assert ( irq <= IRQ_MAX );
159
+
160
+	unhook_bios_interrupt ( IRQ_INT ( irq ),
161
+				( ( unsigned int ) undiisr ),
162
+				&undiisr_next_handler );
163
+	undiisr_irq = 0;
164
+}
165
+
166
+/**
167
+ * Test to see if UNDI ISR has been triggered
168
+ *
169
+ * @ret triggered	ISR has been triggered since last check
170
+ */
171
+static int undinet_isr_triggered ( void ) {
172
+	unsigned int this_trigger_count;
173
+
174
+	/* Read trigger_count.  Do this only once; it is volatile */
175
+	this_trigger_count = undiisr_trigger_count;
176
+
177
+	if ( this_trigger_count == last_trigger_count ) {
178
+		/* Not triggered */
179
+		return 0;
180
+	} else {
181
+		/* Triggered */
182
+		last_trigger_count = this_trigger_count;
183
+		return 1;
184
+	}
185
+}
186
+
187
+/*****************************************************************************
188
+ *
189
+ * UNDI network device interface
190
+ *
191
+ *****************************************************************************
192
+ */
193
+
194
+/** UNDI transmit buffer descriptor */
195
+static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
196
+#define undinet_tbd __use_data16 ( undinet_tbd )
197
+
198
+/** UNDI transmit destination address */
199
+static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] );
200
+#define undinet_destaddr __use_data16 ( undinet_destaddr )
201
+
202
+/**
203
+ * Transmit packet
204
+ *
205
+ * @v netdev		Network device
206
+ * @v iobuf		I/O buffer
207
+ * @ret rc		Return status code
208
+ */
209
+static int undinet_transmit ( struct net_device *netdev,
210
+			      struct io_buffer *iobuf ) {
211
+	struct undi_nic *undinic = netdev->priv;
212
+	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
213
+	const void *ll_dest;
214
+	const void *ll_source;
215
+	uint16_t net_proto;
216
+	unsigned int flags;
217
+	uint8_t protocol;
218
+	size_t len;
219
+	int rc;
220
+
221
+	/* Start profiling */
222
+	profile_start ( &undinet_tx_profiler );
223
+
224
+	/* Technically, we ought to make sure that the previous
225
+	 * transmission has completed before we re-use the buffer.
226
+	 * However, many PXE stacks (including at least some Intel PXE
227
+	 * stacks and Etherboot 5.4) fail to generate TX completions.
228
+	 * In practice this won't be a problem, since our TX datapath
229
+	 * has a very low packet volume and we can get away with
230
+	 * assuming that a TX will be complete by the time we want to
231
+	 * transmit the next packet.
232
+	 */
233
+
234
+	/* Some PXE stacks are unable to cope with P_UNKNOWN, and will
235
+	 * always try to prepend a link-layer header.  Work around
236
+	 * these stacks by stripping the existing link-layer header
237
+	 * and allowing the PXE stack to (re)construct the link-layer
238
+	 * header itself.
239
+	 */
240
+	if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source,
241
+			       &net_proto, &flags ) ) != 0 ) {
242
+		DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: "
243
+		       "%s\n", undinic, strerror ( rc ) );
244
+		return rc;
245
+	}
246
+	memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) );
247
+	switch ( net_proto ) {
248
+	case htons ( ETH_P_IP ) :
249
+		protocol = P_IP;
250
+		break;
251
+	case htons ( ETH_P_ARP ) :
252
+		protocol = P_ARP;
253
+		break;
254
+	case htons ( ETH_P_RARP ) :
255
+		protocol = P_RARP;
256
+		break;
257
+	default:
258
+		/* Unknown protocol; restore the original link-layer header */
259
+		iob_push ( iobuf, sizeof ( struct ethhdr ) );
260
+		protocol = P_UNKNOWN;
261
+		break;
262
+	}
263
+
264
+	/* Copy packet to UNDI I/O buffer */
265
+	len = iob_len ( iobuf );
266
+	if ( len > sizeof ( basemem_packet ) )
267
+		len = sizeof ( basemem_packet );
268
+	memcpy ( &basemem_packet, iobuf->data, len );
269
+
270
+	/* Create PXENV_UNDI_TRANSMIT data structure */
271
+	memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
272
+	undi_transmit.Protocol = protocol;
273
+	undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ?
274
+				   XMT_BROADCAST : XMT_DESTADDR );
275
+	undi_transmit.DestAddr.segment = rm_ds;
276
+	undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr );
277
+	undi_transmit.TBD.segment = rm_ds;
278
+	undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd );
279
+
280
+	/* Create PXENV_UNDI_TBD data structure */
281
+	undinet_tbd.ImmedLength = len;
282
+	undinet_tbd.Xmit.segment = rm_ds;
283
+	undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
284
+
285
+	/* Issue PXE API call */
286
+	profile_start ( &undinet_tx_call_profiler );
287
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT,
288
+				     &undi_transmit,
289
+				     sizeof ( undi_transmit ) ) ) != 0 )
290
+		goto done;
291
+	profile_stop ( &undinet_tx_call_profiler );
292
+
293
+	/* Free I/O buffer */
294
+	netdev_tx_complete ( netdev, iobuf );
295
+	profile_stop ( &undinet_tx_profiler );
296
+ done:
297
+	return rc;
298
+}
299
+
300
+/** 
301
+ * Poll for received packets
302
+ *
303
+ * @v netdev		Network device
304
+ *
305
+ * Fun, fun, fun.  UNDI drivers don't use polling; they use
306
+ * interrupts.  We therefore cheat and pretend that an interrupt has
307
+ * occurred every time undinet_poll() is called.  This isn't too much
308
+ * of a hack; PCI devices share IRQs and so the first thing that a
309
+ * proper ISR should do is call PXENV_UNDI_ISR to determine whether or
310
+ * not the UNDI NIC generated the interrupt; there is no harm done by
311
+ * spurious calls to PXENV_UNDI_ISR.  Similarly, we wouldn't be
312
+ * handling them any more rapidly than the usual rate of
313
+ * undinet_poll() being called even if we did implement a full ISR.
314
+ * So it should work.  Ha!
315
+ *
316
+ * Addendum (21/10/03).  Some cards don't play nicely with this trick,
317
+ * so instead of doing it the easy way we have to go to all the hassle
318
+ * of installing a genuine interrupt service routine and dealing with
319
+ * the wonderful 8259 Programmable Interrupt Controller.  Joy.
320
+ *
321
+ * Addendum (10/07/07).  When doing things such as iSCSI boot, in
322
+ * which we have to co-operate with a running OS, we can't get away
323
+ * with the "ISR-just-increments-a-counter-and-returns" trick at all,
324
+ * because it involves tying up the PIC for far too long, and other
325
+ * interrupt-dependent components (e.g. local disks) start breaking.
326
+ * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
327
+ * from within interrupt context in order to deassert the device
328
+ * interrupt, and sends EOI if applicable.
329
+ */
330
+static void undinet_poll ( struct net_device *netdev ) {
331
+	struct undi_nic *undinic = netdev->priv;
332
+	struct s_PXENV_UNDI_ISR undi_isr;
333
+	struct io_buffer *iobuf = NULL;
334
+	unsigned int quota = UNDI_RX_QUOTA;
335
+	size_t len;
336
+	size_t reserve_len;
337
+	size_t frag_len;
338
+	size_t max_frag_len;
339
+	int rc;
340
+
341
+	if ( ! undinic->isr_processing ) {
342
+		/* Allow interrupt to occur.  Do this even if
343
+		 * interrupts are not known to be supported, since
344
+		 * some cards erroneously report that they do not
345
+		 * support interrupts.
346
+		 */
347
+		if ( ! undinet_isr_triggered() ) {
348
+			/* Allow interrupt to occur */
349
+			profile_start ( &undinet_irq_profiler );
350
+			__asm__ __volatile__ ( "sti\n\t"
351
+					       "nop\n\t"
352
+					       "nop\n\t"
353
+					       "cli\n\t" );
354
+			profile_stop ( &undinet_irq_profiler );
355
+
356
+			/* If interrupts are known to be supported,
357
+			 * then do nothing on this poll; wait for the
358
+			 * interrupt to be triggered.
359
+			 */
360
+			if ( undinic->irq_supported )
361
+				return;
362
+		}
363
+
364
+		/* Start ISR processing */
365
+		undinic->isr_processing = 1;
366
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
367
+	} else {
368
+		/* Continue ISR processing */
369
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
370
+	}
371
+
372
+	/* Run through the ISR loop */
373
+	while ( quota ) {
374
+		profile_start ( &undinet_isr_call_profiler );
375
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
376
+					     &undi_isr,
377
+					     sizeof ( undi_isr ) ) ) != 0 ) {
378
+			netdev_rx_err ( netdev, NULL, rc );
379
+			break;
380
+		}
381
+		profile_stop ( &undinet_isr_call_profiler );
382
+		switch ( undi_isr.FuncFlag ) {
383
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
384
+			/* We don't care about transmit completions */
385
+			break;
386
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
387
+			/* Packet fragment received */
388
+			profile_start ( &undinet_rx_profiler );
389
+			len = undi_isr.FrameLength;
390
+			frag_len = undi_isr.BufferLength;
391
+			reserve_len = ( -undi_isr.FrameHeaderLength &
392
+					( UNDI_RX_ALIGN - 1 ) );
393
+			if ( ( len == 0 ) || ( len < frag_len ) ) {
394
+				/* Don't laugh.  VMWare does it. */
395
+				DBGC ( undinic, "UNDINIC %p reported insane "
396
+				       "fragment (%zd of %zd bytes)\n",
397
+				       undinic, frag_len, len );
398
+				netdev_rx_err ( netdev, NULL, -EINVAL );
399
+				break;
400
+			}
401
+			if ( ! iobuf ) {
402
+				iobuf = alloc_iob ( reserve_len + len );
403
+				if ( ! iobuf ) {
404
+					DBGC ( undinic, "UNDINIC %p could not "
405
+					       "allocate %zd bytes for RX "
406
+					       "buffer\n", undinic, len );
407
+					/* Fragment will be dropped */
408
+					netdev_rx_err ( netdev, NULL, -ENOMEM );
409
+					goto done;
410
+				}
411
+				iob_reserve ( iobuf, reserve_len );
412
+			}
413
+			max_frag_len = iob_tailroom ( iobuf );
414
+			if ( frag_len > max_frag_len ) {
415
+				DBGC ( undinic, "UNDINIC %p fragment too big "
416
+				       "(%zd+%zd does not fit into %zd)\n",
417
+				       undinic, iob_len ( iobuf ), frag_len,
418
+				       ( iob_len ( iobuf ) + max_frag_len ) );
419
+				frag_len = max_frag_len;
420
+			}
421
+			copy_from_real ( iob_put ( iobuf, frag_len ),
422
+					 undi_isr.Frame.segment,
423
+					 undi_isr.Frame.offset, frag_len );
424
+			if ( iob_len ( iobuf ) == len ) {
425
+				/* Whole packet received; deliver it */
426
+				netdev_rx ( netdev, iob_disown ( iobuf ) );
427
+				quota--;
428
+				/* Etherboot 5.4 fails to return all packets
429
+				 * under mild load; pretend it retriggered.
430
+				 */
431
+				if ( undinic->hacks & UNDI_HACK_EB54 )
432
+					--last_trigger_count;
433
+			}
434
+			profile_stop ( &undinet_rx_profiler );
435
+			break;
436
+		case PXENV_UNDI_ISR_OUT_DONE:
437
+			/* Processing complete */
438
+			undinic->isr_processing = 0;
439
+			goto done;
440
+		default:
441
+			/* Should never happen.  VMWare does it routinely. */
442
+			DBGC ( undinic, "UNDINIC %p ISR returned invalid "
443
+			       "FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
444
+			undinic->isr_processing = 0;
445
+			goto done;
446
+		}
447
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
448
+	}
449
+
450
+ done:
451
+	if ( iobuf ) {
452
+		DBGC ( undinic, "UNDINIC %p returned incomplete packet "
453
+		       "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
454
+		       ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
455
+		netdev_rx_err ( netdev, iobuf, -EINVAL );
456
+	}
457
+}
458
+
459
+/**
460
+ * Open NIC
461
+ *
462
+ * @v netdev		Net device
463
+ * @ret rc		Return status code
464
+ */
465
+static int undinet_open ( struct net_device *netdev ) {
466
+	struct undi_nic *undinic = netdev->priv;
467
+	struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
468
+	struct s_PXENV_UNDI_OPEN undi_open;
469
+	int rc;
470
+
471
+	/* Hook interrupt service routine and enable interrupt if applicable */
472
+	if ( undinic->irq ) {
473
+		undinet_hook_isr ( undinic->irq );
474
+		enable_irq ( undinic->irq );
475
+		send_eoi ( undinic->irq );
476
+	}
477
+
478
+	/* Set station address.  Required for some PXE stacks; will
479
+	 * spuriously fail on others.  Ignore failures.  We only ever
480
+	 * use it to set the MAC address to the card's permanent value
481
+	 * anyway.
482
+	 */
483
+	memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
484
+		 sizeof ( undi_set_address.StationAddress ) );
485
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS,
486
+			 &undi_set_address, sizeof ( undi_set_address ) );
487
+
488
+	/* Open NIC.  We ask for promiscuous operation, since it's the
489
+	 * only way to ask for all multicast addresses.  On any
490
+	 * switched network, it shouldn't really make a difference to
491
+	 * performance.
492
+	 */
493
+	memset ( &undi_open, 0, sizeof ( undi_open ) );
494
+	undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
495
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN,
496
+				     &undi_open, sizeof ( undi_open ) ) ) != 0 )
497
+		goto err;
498
+
499
+	DBGC ( undinic, "UNDINIC %p opened\n", undinic );
500
+	return 0;
501
+
502
+ err:
503
+	undinet_close ( netdev );
504
+	return rc;
505
+}
506
+
507
+/**
508
+ * Close NIC
509
+ *
510
+ * @v netdev		Net device
511
+ */
512
+static void undinet_close ( struct net_device *netdev ) {
513
+	struct undi_nic *undinic = netdev->priv;
514
+	struct s_PXENV_UNDI_ISR undi_isr;
515
+	struct s_PXENV_UNDI_CLOSE undi_close;
516
+	int rc;
517
+
518
+	/* Ensure ISR has exited cleanly */
519
+	while ( undinic->isr_processing ) {
520
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
521
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
522
+					     &undi_isr,
523
+					     sizeof ( undi_isr ) ) ) != 0 )
524
+			break;
525
+		switch ( undi_isr.FuncFlag ) {
526
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
527
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
528
+			/* Continue draining */
529
+			break;
530
+		default:
531
+			/* Stop processing */
532
+			undinic->isr_processing = 0;
533
+			break;
534
+		}
535
+	}
536
+
537
+	/* Close NIC */
538
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
539
+			 &undi_close, sizeof ( undi_close ) );
540
+
541
+	/* Disable interrupt and unhook ISR if applicable */
542
+	if ( undinic->irq ) {
543
+		disable_irq ( undinic->irq );
544
+		undinet_unhook_isr ( undinic->irq );
545
+	}
546
+
547
+	DBGC ( undinic, "UNDINIC %p closed\n", undinic );
548
+}
549
+
550
+/**
551
+ * Enable/disable interrupts
552
+ *
553
+ * @v netdev		Net device
554
+ * @v enable		Interrupts should be enabled
555
+ */
556
+static void undinet_irq ( struct net_device *netdev, int enable ) {
557
+	struct undi_nic *undinic = netdev->priv;
558
+
559
+	/* Cannot support interrupts yet */
560
+	DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n",
561
+	       undinic, ( enable ? "enable" : "disable" ) );
562
+}
563
+
564
+/** UNDI network device operations */
565
+static struct net_device_operations undinet_operations = {
566
+	.open		= undinet_open,
567
+	.close		= undinet_close,
568
+	.transmit	= undinet_transmit,
569
+	.poll		= undinet_poll,
570
+	.irq   		= undinet_irq,
571
+};
572
+
573
+/** A device with broken support for generating interrupts */
574
+struct undinet_irq_broken {
575
+	/** PCI vendor ID */
576
+	uint16_t pci_vendor;
577
+	/** PCI device ID */
578
+	uint16_t pci_device;
579
+};
580
+
581
+/**
582
+ * List of devices with broken support for generating interrupts
583
+ *
584
+ * Some PXE stacks are known to claim that IRQs are supported, but
585
+ * then never generate interrupts.  No satisfactory solution has been
586
+ * found to this problem; the workaround is to add the PCI vendor and
587
+ * device IDs to this list.  This is something of a hack, since it
588
+ * will generate false positives for identical devices with a working
589
+ * PXE stack (e.g. those that have been reflashed with iPXE), but it's
590
+ * an improvement on the current situation.
591
+ */
592
+static const struct undinet_irq_broken undinet_irq_broken_list[] = {
593
+	/* HP XX70x laptops */
594
+	{ .pci_vendor = 0x8086, .pci_device = 0x1502 },
595
+	{ .pci_vendor = 0x8086, .pci_device = 0x1503 },
596
+};
597
+
598
+/**
599
+ * Check for devices with broken support for generating interrupts
600
+ *
601
+ * @v undi		UNDI device
602
+ * @ret irq_is_broken	Interrupt support is broken; no interrupts are generated
603
+ */
604
+static int undinet_irq_is_broken ( struct undi_device *undi ) {
605
+	const struct undinet_irq_broken *broken;
606
+	unsigned int i;
607
+
608
+	for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
609
+			    sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
610
+		broken = &undinet_irq_broken_list[i];
611
+		if ( ( undi->dev.desc.bus_type == BUS_TYPE_PCI ) &&
612
+		     ( undi->dev.desc.vendor == broken->pci_vendor ) &&
613
+		     ( undi->dev.desc.device == broken->pci_device ) ) {
614
+			return 1;
615
+		}
616
+	}
617
+	return 0;
618
+}
619
+
620
+/**
621
+ * Probe UNDI device
622
+ *
623
+ * @v undi		UNDI device
624
+ * @ret rc		Return status code
625
+ */
626
+int undinet_probe ( struct undi_device *undi ) {
627
+	struct net_device *netdev;
628
+	struct undi_nic *undinic;
629
+	struct s_PXENV_START_UNDI start_undi;
630
+	struct s_PXENV_UNDI_STARTUP undi_startup;
631
+	struct s_PXENV_UNDI_INITIALIZE undi_init;
632
+	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
633
+	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
634
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
635
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
636
+	struct s_PXENV_STOP_UNDI stop_undi;
637
+	unsigned int retry;
638
+	int rc;
639
+
640
+	/* Allocate net device */
641
+	netdev = alloc_etherdev ( sizeof ( *undinic ) );
642
+	if ( ! netdev )
643
+		return -ENOMEM;
644
+	netdev_init ( netdev, &undinet_operations );
645
+	undinic = netdev->priv;
646
+	undi_set_drvdata ( undi, netdev );
647
+	netdev->dev = &undi->dev;
648
+	memset ( undinic, 0, sizeof ( *undinic ) );
649
+	undinet_entry = undi->entry;
650
+	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
651
+
652
+	/* Hook in UNDI stack */
653
+	if ( ! ( undi->flags & UNDI_FL_STARTED ) ) {
654
+		memset ( &start_undi, 0, sizeof ( start_undi ) );
655
+		start_undi.AX = undi->pci_busdevfn;
656
+		start_undi.BX = undi->isapnp_csn;
657
+		start_undi.DX = undi->isapnp_read_port;
658
+		start_undi.ES = BIOS_SEG;
659
+		start_undi.DI = find_pnp_bios();
660
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI,
661
+					     &start_undi,
662
+					     sizeof ( start_undi ) ) ) != 0 )
663
+			goto err_start_undi;
664
+	}
665
+	undi->flags |= UNDI_FL_STARTED;
666
+
667
+	/* Bring up UNDI stack */
668
+	if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
669
+		memset ( &undi_startup, 0, sizeof ( undi_startup ) );
670
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP,
671
+					     &undi_startup,
672
+					     sizeof ( undi_startup ) ) ) != 0 )
673
+			goto err_undi_startup;
674
+		/* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
675
+		 * due to a transient condition (e.g. media test
676
+		 * failing because the link has only just come out of
677
+		 * reset).  We may therefore need to retry this call
678
+		 * several times.
679
+		 */
680
+		for ( retry = 0 ; ; ) {
681
+			memset ( &undi_init, 0, sizeof ( undi_init ) );
682
+			if ( ( rc = pxeparent_call ( undinet_entry,
683
+						     PXENV_UNDI_INITIALIZE,
684
+						     &undi_init,
685
+						     sizeof ( undi_init ))) ==0)
686
+				break;
687
+			if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
688
+				goto err_undi_initialize;
689
+			DBGC ( undinic, "UNDINIC %p retrying "
690
+			       "PXENV_UNDI_INITIALIZE (retry %d)\n",
691
+			       undinic, retry );
692
+			/* Delay to allow link to settle if necessary */
693
+			mdelay ( UNDI_INITIALIZE_RETRY_DELAY_MS );
694
+		}
695
+	}
696
+	undi->flags |= UNDI_FL_INITIALIZED;
697
+
698
+	/* Get device information */
699
+	memset ( &undi_info, 0, sizeof ( undi_info ) );
700
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION,
701
+				     &undi_info, sizeof ( undi_info ) ) ) != 0 )
702
+		goto err_undi_get_information;
703
+	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
704
+	memcpy ( netdev->ll_addr, undi_info.CurrentNodeAddress, ETH_ALEN );
705
+	undinic->irq = undi_info.IntNumber;
706
+	if ( undinic->irq > IRQ_MAX ) {
707
+		DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
708
+		       undinic, undinic->irq );
709
+		rc = -EINVAL;
710
+		goto err_bad_irq;
711
+	}
712
+	DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
713
+	       undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
714
+
715
+	/* Get interface information */
716
+	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
717
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO,
718
+				     &undi_iface,
719
+				     sizeof ( undi_iface ) ) ) != 0 )
720
+		goto err_undi_get_iface_info;
721
+	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
722
+	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
723
+	       undi_iface.ServiceFlags );
724
+	if ( ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) &&
725
+	     ( undinic->irq != 0 ) ) {
726
+		undinic->irq_supported = 1;
727
+	}
728
+	DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
729
+	       ( undinic->irq_supported ? "interrupt" : "polling" ) );
730
+	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
731
+		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
732
+		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
733
+		       undinic );
734
+		undinic->hacks |= UNDI_HACK_EB54;
735
+	}
736
+	if ( undinet_irq_is_broken ( undi ) ) {
737
+		DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
738
+		       "broken interrupts\n", undinic );
739
+		undinic->irq_supported = 0;
740
+	}
741
+
742
+	/* Register network device */
743
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
744
+		goto err_register;
745
+
746
+	/* Mark as link up; we don't handle link state */
747
+	netdev_link_up ( netdev );
748
+
749
+	DBGC ( undinic, "UNDINIC %p added\n", undinic );
750
+	return 0;
751
+
752
+ err_register:
753
+ err_undi_get_iface_info:
754
+ err_bad_irq:
755
+ err_undi_get_information:
756
+ err_undi_initialize:
757
+	/* Shut down UNDI stack */
758
+	memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
759
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
760
+			 sizeof ( undi_shutdown ) );
761
+	memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
762
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup,
763
+			 sizeof ( undi_cleanup ) );
764
+	undi->flags &= ~UNDI_FL_INITIALIZED;
765
+ err_undi_startup:
766
+	/* Unhook UNDI stack */
767
+	memset ( &stop_undi, 0, sizeof ( stop_undi ) );
768
+	pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
769
+			 sizeof ( stop_undi ) );
770
+	undi->flags &= ~UNDI_FL_STARTED;
771
+ err_start_undi:
772
+	netdev_nullify ( netdev );
773
+	netdev_put ( netdev );
774
+	undi_set_drvdata ( undi, NULL );
775
+	return rc;
776
+}
777
+
778
+/**
779
+ * Remove UNDI device
780
+ *
781
+ * @v undi		UNDI device
782
+ */
783
+void undinet_remove ( struct undi_device *undi ) {
784
+	struct net_device *netdev = undi_get_drvdata ( undi );
785
+	struct undi_nic *undinic = netdev->priv;
786
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
787
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
788
+	struct s_PXENV_STOP_UNDI stop_undi;
789
+
790
+	/* Unregister net device */
791
+	unregister_netdev ( netdev );
792
+
793
+	/* If we are preparing for an OS boot, or if we cannot exit
794
+	 * via the PXE stack, then shut down the PXE stack.
795
+	 */
796
+	if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) {
797
+
798
+		/* Shut down UNDI stack */
799
+		memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
800
+		pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN,
801
+				 &undi_shutdown, sizeof ( undi_shutdown ) );
802
+		memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
803
+		pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP,
804
+				 &undi_cleanup, sizeof ( undi_cleanup ) );
805
+		undi->flags &= ~UNDI_FL_INITIALIZED;
806
+
807
+		/* Unhook UNDI stack */
808
+		memset ( &stop_undi, 0, sizeof ( stop_undi ) );
809
+		pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
810
+				 sizeof ( stop_undi ) );
811
+		undi->flags &= ~UNDI_FL_STARTED;
812
+	}
813
+
814
+	/* Clear entry point */
815
+	memset ( &undinet_entry, 0, sizeof ( undinet_entry ) );
816
+
817
+	/* Free network device */
818
+	netdev_nullify ( netdev );
819
+	netdev_put ( netdev );
820
+
821
+	DBGC ( undinic, "UNDINIC %p removed\n", undinic );
822
+}

+ 142
- 0
src/arch/i386/drivers/net/undionly.c View File

@@ -0,0 +1,142 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <stdlib.h>
28
+#include <stdio.h>
29
+#include <string.h>
30
+#include <ipxe/device.h>
31
+#include <ipxe/init.h>
32
+#include <ipxe/pci.h>
33
+#include <undi.h>
34
+#include <undinet.h>
35
+#include <undipreload.h>
36
+
37
+/** @file
38
+ *
39
+ * "Pure" UNDI driver
40
+ *
41
+ * This is the UNDI driver without explicit support for PCI or any
42
+ * other bus type.  It is capable only of using the preloaded UNDI
43
+ * device.  It must not be combined in an image with any other
44
+ * drivers.
45
+ *
46
+ * If you want a PXE-loadable image that contains only the UNDI
47
+ * driver, build "bin/undionly.kpxe".
48
+ *
49
+ * If you want any other image format, or any other drivers in
50
+ * addition to the UNDI driver, build e.g. "bin/undi.dsk".
51
+ */
52
+
53
+/**
54
+ * Probe UNDI root bus
55
+ *
56
+ * @v rootdev		UNDI bus root device
57
+ *
58
+ * Scans the UNDI bus for devices and registers all devices it can
59
+ * find.
60
+ */
61
+static int undibus_probe ( struct root_device *rootdev ) {
62
+	struct undi_device *undi = &preloaded_undi;
63
+	int rc;
64
+
65
+	/* Check for a valie preloaded UNDI device */
66
+	if ( ! undi->entry.segment ) {
67
+		DBG ( "No preloaded UNDI device found!\n" );
68
+		return -ENODEV;
69
+	}
70
+
71
+	/* Add to device hierarchy */
72
+	undi->dev.driver_name = "undionly";
73
+	if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
74
+		undi->dev.desc.bus_type = BUS_TYPE_PCI;
75
+		undi->dev.desc.location = undi->pci_busdevfn;
76
+		undi->dev.desc.vendor = undi->pci_vendor;
77
+		undi->dev.desc.device = undi->pci_device;
78
+		snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
79
+			   "UNDI-PCI%02x:%02x.%x",
80
+			   PCI_BUS ( undi->pci_busdevfn ),
81
+			   PCI_SLOT ( undi->pci_busdevfn ),
82
+			   PCI_FUNC ( undi->pci_busdevfn ) );
83
+	} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
84
+		undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
85
+		snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
86
+			   "UNDI-ISAPNP" );
87
+	}
88
+	undi->dev.parent = &rootdev->dev;
89
+	list_add ( &undi->dev.siblings, &rootdev->dev.children);
90
+	INIT_LIST_HEAD ( &undi->dev.children );
91
+
92
+	/* Create network device */
93
+	if ( ( rc = undinet_probe ( undi ) ) != 0 )
94
+		goto err;
95
+
96
+	return 0;
97
+
98
+ err:
99
+	list_del ( &undi->dev.siblings );
100
+	return rc;
101
+}
102
+
103
+/**
104
+ * Remove UNDI root bus
105
+ *
106
+ * @v rootdev		UNDI bus root device
107
+ */
108
+static void undibus_remove ( struct root_device *rootdev __unused ) {
109
+	struct undi_device *undi = &preloaded_undi;
110
+
111
+	undinet_remove ( undi );
112
+	list_del ( &undi->dev.siblings );
113
+}
114
+
115
+/** UNDI bus root device driver */
116
+static struct root_driver undi_root_driver = {
117
+	.probe = undibus_probe,
118
+	.remove = undibus_remove,
119
+};
120
+
121
+/** UNDI bus root device */
122
+struct root_device undi_root_device __root_device = {
123
+	.dev = { .name = "UNDI" },
124
+	.driver = &undi_root_driver,
125
+};
126
+
127
+/**
128
+ * Prepare for exit
129
+ *
130
+ * @v booting		System is shutting down for OS boot
131
+ */
132
+static void undionly_shutdown ( int booting ) {
133
+	/* If we are shutting down to boot an OS, clear the "keep PXE
134
+	 * stack" flag.
135
+	 */
136
+	if ( booting )
137
+		preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
138
+}
139
+
140
+struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
141
+	.shutdown = undionly_shutdown,
142
+};

+ 42
- 0
src/arch/i386/drivers/net/undipreload.c View File

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <realmode.h>
27
+#include <undipreload.h>
28
+
29
+/** @file
30
+ *
31
+ * Preloaded UNDI stack
32
+ *
33
+ */
34
+
35
+/**
36
+ * Preloaded UNDI device
37
+ *
38
+ * This is the UNDI device that was present when Etherboot started
39
+ * execution (i.e. when loading a .kpxe image).  The first driver to
40
+ * claim this device must zero out this data structure.
41
+ */
42
+struct undi_device __data16 ( preloaded_undi );

+ 235
- 0
src/arch/i386/drivers/net/undirom.c View File

@@ -0,0 +1,235 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+#include <pxe.h>
26
+#include <realmode.h>
27
+#include <undirom.h>
28
+
29
+/** @file
30
+ *
31
+ * UNDI expansion ROMs
32
+ *
33
+ */
34
+
35
+/** List of all UNDI ROMs */
36
+static LIST_HEAD ( undiroms );
37
+
38
+/**
39
+ * Parse PXE ROM ID structure
40
+ *
41
+ * @v undirom		UNDI ROM
42
+ * @v pxeromid		Offset within ROM to PXE ROM ID structure
43
+ * @ret rc		Return status code
44
+ */
45
+static int undirom_parse_pxeromid ( struct undi_rom *undirom,
46
+				   unsigned int pxeromid ) {
47
+	struct undi_rom_id undi_rom_id;
48
+	unsigned int undiloader;
49
+
50
+	DBGC ( undirom, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom,
51
+	       undirom->rom_segment, pxeromid );
52
+
53
+	/* Read PXE ROM ID structure and verify */
54
+	copy_from_real ( &undi_rom_id, undirom->rom_segment, pxeromid,
55
+			 sizeof ( undi_rom_id ) );
56
+	if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
57
+		DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
58
+		       "%08x\n", undirom, undi_rom_id.Signature );
59
+		return -EINVAL;
60
+	}
61
+
62
+	/* Check for UNDI loader */
63
+	undiloader = undi_rom_id.UNDILoader;
64
+	if ( ! undiloader ) {
65
+		DBGC ( undirom, "UNDIROM %p has no UNDI loader\n", undirom );
66
+		return -EINVAL;
67
+	}
68
+
69
+	/* Fill in UNDI ROM loader fields */
70
+	undirom->loader_entry.segment = undirom->rom_segment;
71
+	undirom->loader_entry.offset = undiloader;
72
+	undirom->code_size = undi_rom_id.CodeSize;
73
+	undirom->data_size = undi_rom_id.DataSize;
74
+
75
+	DBGC ( undirom, "UNDIROM %p has UNDI loader at %04x:%04x "
76
+	       "(code %04zx data %04zx)\n", undirom,
77
+	       undirom->loader_entry.segment, undirom->loader_entry.offset,
78
+	       undirom->code_size, undirom->data_size );
79
+	return 0;
80
+}
81
+
82
+/**
83
+ * Parse PCI expansion header
84
+ *
85
+ * @v undirom		UNDI ROM
86
+ * @v pcirheader	Offset within ROM to PCI expansion header
87
+ */
88
+static int undirom_parse_pcirheader ( struct undi_rom *undirom,
89
+				     unsigned int pcirheader ) {
90
+	struct pcir_header pcir_header;
91
+
92
+	DBGC ( undirom, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
93
+	       undirom, undirom->rom_segment, pcirheader );
94
+
95
+	/* Read PCI expansion header and verify */
96
+	copy_from_real ( &pcir_header, undirom->rom_segment, pcirheader,
97
+			 sizeof ( pcir_header ) );
98
+	if ( pcir_header.signature != PCIR_SIGNATURE ) {
99
+		DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
100
+		       "signature %08x\n", undirom, pcir_header.signature );
101
+		return -EINVAL;
102
+	}
103
+
104
+	/* Fill in UNDI ROM PCI device fields */
105
+	undirom->bus_type = PCI_NIC;
106
+	undirom->bus_id.pci.vendor_id = pcir_header.vendor_id;
107
+	undirom->bus_id.pci.device_id = pcir_header.device_id;
108
+
109
+	DBGC ( undirom, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom,
110
+	       undirom->bus_id.pci.vendor_id, undirom->bus_id.pci.device_id );
111
+	return 0;
112
+	
113
+}
114
+
115
+/**
116
+ * Probe UNDI ROM
117
+ *
118
+ * @v rom_segment	ROM segment address
119
+ * @ret rc		Return status code
120
+ */
121
+static int undirom_probe ( unsigned int rom_segment ) {
122
+	struct undi_rom *undirom = NULL;
123
+	struct undi_rom_header romheader;
124
+	size_t rom_len;
125
+	unsigned int pxeromid;
126
+	unsigned int pcirheader;
127
+	int rc;
128
+
129
+	/* Read expansion ROM header and verify */
130
+	copy_from_real ( &romheader, rom_segment, 0, sizeof ( romheader ) );
131
+	if ( romheader.Signature != ROM_SIGNATURE ) {
132
+		rc = -EINVAL;
133
+		goto err;
134
+	}
135
+	rom_len = ( romheader.ROMLength * 512 );
136
+
137
+	/* Allocate memory for UNDI ROM */
138
+	undirom = zalloc ( sizeof ( *undirom ) );
139
+	if ( ! undirom ) {
140
+		DBG ( "Could not allocate UNDI ROM structure\n" );
141
+		rc = -ENOMEM;
142
+		goto err;
143
+	}
144
+	DBGC ( undirom, "UNDIROM %p trying expansion ROM at %04x:0000 "
145
+	       "(%zdkB)\n", undirom, rom_segment, ( rom_len / 1024 ) );
146
+	undirom->rom_segment = rom_segment;
147
+
148
+	/* Check for and parse PXE ROM ID */
149
+	pxeromid = romheader.PXEROMID;
150
+	if ( ! pxeromid ) {
151
+		DBGC ( undirom, "UNDIROM %p has no PXE ROM ID\n", undirom );
152
+		rc = -EINVAL;
153
+		goto err;
154
+	}
155
+	if ( pxeromid > rom_len ) {
156
+		DBGC ( undirom, "UNDIROM %p PXE ROM ID outside ROM\n",
157
+		       undirom );
158
+		rc = -EINVAL;
159
+		goto err;
160
+	}
161
+	if ( ( rc = undirom_parse_pxeromid ( undirom, pxeromid ) ) != 0 )
162
+		goto err;
163
+
164
+	/* Parse PCIR header, if present */
165
+	pcirheader = romheader.PCIRHeader;
166
+	if ( pcirheader )
167
+		undirom_parse_pcirheader ( undirom, pcirheader );
168
+
169
+	/* Add to UNDI ROM list and return */
170
+	DBGC ( undirom, "UNDIROM %p registered\n", undirom );
171
+	list_add ( &undirom->list, &undiroms );
172
+	return 0;
173
+
174
+ err:
175
+	free ( undirom );
176
+	return rc;
177
+}
178
+
179
+/**
180
+ * Create UNDI ROMs for all possible expansion ROMs
181
+ *
182
+ * @ret 
183
+ */
184
+static void undirom_probe_all_roms ( void ) {
185
+	static int probed = 0;
186
+	unsigned int rom_segment;
187
+
188
+	/* Perform probe only once */
189
+	if ( probed )
190
+		return;
191
+
192
+	DBG ( "Scanning for PXE expansion ROMs\n" );
193
+
194
+	/* Scan through expansion ROM region at 512 byte intervals */
195
+	for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
196
+	      rom_segment += 0x20 ) {
197
+		undirom_probe ( rom_segment );
198
+	}
199
+
200
+	probed = 1;
201
+}
202
+
203
+/**
204
+ * Find UNDI ROM for PCI device
205
+ *
206
+ * @v vendor_id		PCI vendor ID
207
+ * @v device_id		PCI device ID
208
+ * @v rombase		ROM base address, or 0 for any
209
+ * @ret undirom		UNDI ROM, or NULL
210
+ */
211
+struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
212
+				     unsigned int device_id,
213
+				     unsigned int rombase ) {
214
+	struct undi_rom *undirom;
215
+
216
+	undirom_probe_all_roms();
217
+
218
+	list_for_each_entry ( undirom, &undiroms, list ) {
219
+		if ( undirom->bus_type != PCI_NIC )
220
+			continue;
221
+		if ( undirom->bus_id.pci.vendor_id != vendor_id )
222
+			continue;
223
+		if ( undirom->bus_id.pci.device_id != device_id )
224
+			continue;
225
+		if ( rombase && ( ( undirom->rom_segment << 4 ) != rombase ) )
226
+			continue;
227
+		DBGC ( undirom, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
228
+		       undirom, vendor_id, device_id, rombase );
229
+		return undirom;
230
+	}
231
+
232
+	DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
233
+	      vendor_id, device_id, rombase );
234
+	return NULL;
235
+}

+ 51
- 0
src/arch/i386/firmware/pcbios/basemem.c View File

@@ -0,0 +1,51 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <realmode.h>
28
+#include <bios.h>
29
+#include <basemem.h>
30
+#include <ipxe/hidemem.h>
31
+
32
+/** @file
33
+ *
34
+ * Base memory allocation
35
+ *
36
+ */
37
+
38
+/**
39
+ * Set the BIOS free base memory counter
40
+ *
41
+ * @v new_fbms		New free base memory counter (in kB)
42
+ */
43
+void set_fbms ( unsigned int new_fbms ) {
44
+	uint16_t fbms = new_fbms;
45
+
46
+	/* Update the BIOS memory counter */
47
+	put_real ( fbms, BDA_SEG, BDA_FBMS );
48
+
49
+	/* Update our hidden memory region map */
50
+	hide_basemem();
51
+}

+ 566
- 0
src/arch/i386/firmware/pcbios/bios_console.c View File

@@ -0,0 +1,566 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <assert.h>
27
+#include <realmode.h>
28
+#include <bios.h>
29
+#include <biosint.h>
30
+#include <ipxe/console.h>
31
+#include <ipxe/ansiesc.h>
32
+#include <ipxe/keys.h>
33
+#include <ipxe/keymap.h>
34
+#include <ipxe/init.h>
35
+#include <config/console.h>
36
+
37
+#define ATTR_BOLD		0x08
38
+
39
+#define ATTR_FCOL_MASK		0x07
40
+#define ATTR_FCOL_BLACK		0x00
41
+#define ATTR_FCOL_BLUE		0x01
42
+#define ATTR_FCOL_GREEN		0x02
43
+#define ATTR_FCOL_CYAN		0x03
44
+#define ATTR_FCOL_RED		0x04
45
+#define ATTR_FCOL_MAGENTA	0x05
46
+#define ATTR_FCOL_YELLOW	0x06
47
+#define ATTR_FCOL_WHITE		0x07
48
+
49
+#define ATTR_BLINK		0x80
50
+
51
+#define ATTR_BCOL_MASK		0x70
52
+#define ATTR_BCOL_BLACK		0x00
53
+#define ATTR_BCOL_BLUE		0x10
54
+#define ATTR_BCOL_GREEN		0x20
55
+#define ATTR_BCOL_CYAN		0x30
56
+#define ATTR_BCOL_RED		0x40
57
+#define ATTR_BCOL_MAGENTA	0x50
58
+#define ATTR_BCOL_YELLOW	0x60
59
+#define ATTR_BCOL_WHITE		0x70
60
+
61
+#define ATTR_DEFAULT		ATTR_FCOL_WHITE
62
+
63
+/* Set default console usage if applicable */
64
+#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
65
+#undef CONSOLE_PCBIOS
66
+#define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
67
+#endif
68
+
69
+/** Current character attribute */
70
+static unsigned int bios_attr = ATTR_DEFAULT;
71
+
72
+/** Keypress injection lock */
73
+static uint8_t __text16 ( bios_inject_lock );
74
+#define bios_inject_lock __use_text16 ( bios_inject_lock )
75
+
76
+/** Vector for chaining to other INT 16 handlers */
77
+static struct segoff __text16 ( int16_vector );
78
+#define int16_vector __use_text16 ( int16_vector )
79
+
80
+/** Assembly wrapper */
81
+extern void int16_wrapper ( void );
82
+
83
+/**
84
+ * Handle ANSI CUP (cursor position)
85
+ *
86
+ * @v ctx		ANSI escape sequence context
87
+ * @v count		Parameter count
88
+ * @v params[0]		Row (1 is top)
89
+ * @v params[1]		Column (1 is left)
90
+ */
91
+static void bios_handle_cup ( struct ansiesc_context *ctx __unused,
92
+			      unsigned int count __unused, int params[] ) {
93
+	int cx = ( params[1] - 1 );
94
+	int cy = ( params[0] - 1 );
95
+
96
+	if ( cx < 0 )
97
+		cx = 0;
98
+	if ( cy < 0 )
99
+		cy = 0;
100
+
101
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
102
+					   "int $0x10\n\t"
103
+					   "cli\n\t" )
104
+			       : : "a" ( 0x0200 ), "b" ( 1 ),
105
+			           "d" ( ( cy << 8 ) | cx ) );
106
+}
107
+
108
+/**
109
+ * Handle ANSI ED (erase in page)
110
+ *
111
+ * @v ctx		ANSI escape sequence context
112
+ * @v count		Parameter count
113
+ * @v params[0]		Region to erase
114
+ */
115
+static void bios_handle_ed ( struct ansiesc_context *ctx __unused,
116
+			     unsigned int count __unused,
117
+			     int params[] __unused ) {
118
+	/* We assume that we always clear the whole screen */
119
+	assert ( params[0] == ANSIESC_ED_ALL );
120
+
121
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
122
+					   "int $0x10\n\t"
123
+					   "cli\n\t" )
124
+			       : : "a" ( 0x0600 ), "b" ( bios_attr << 8 ),
125
+				   "c" ( 0 ),
126
+				   "d" ( ( ( console_height - 1 ) << 8 ) |
127
+					 ( console_width - 1 ) ) );
128
+}
129
+
130
+/**
131
+ * Handle ANSI SGR (set graphics rendition)
132
+ *
133
+ * @v ctx		ANSI escape sequence context
134
+ * @v count		Parameter count
135
+ * @v params		List of graphic rendition aspects
136
+ */
137
+static void bios_handle_sgr ( struct ansiesc_context *ctx __unused,
138
+			      unsigned int count, int params[] ) {
139
+	static const uint8_t bios_attr_fcols[10] = {
140
+		ATTR_FCOL_BLACK, ATTR_FCOL_RED, ATTR_FCOL_GREEN,
141
+		ATTR_FCOL_YELLOW, ATTR_FCOL_BLUE, ATTR_FCOL_MAGENTA,
142
+		ATTR_FCOL_CYAN, ATTR_FCOL_WHITE,
143
+		ATTR_FCOL_WHITE, ATTR_FCOL_WHITE /* defaults */
144
+	};
145
+	static const uint8_t bios_attr_bcols[10] = {
146
+		ATTR_BCOL_BLACK, ATTR_BCOL_RED, ATTR_BCOL_GREEN,
147
+		ATTR_BCOL_YELLOW, ATTR_BCOL_BLUE, ATTR_BCOL_MAGENTA,
148
+		ATTR_BCOL_CYAN, ATTR_BCOL_WHITE,
149
+		ATTR_BCOL_BLACK, ATTR_BCOL_BLACK /* defaults */
150
+	};
151
+	unsigned int i;
152
+	int aspect;
153
+
154
+	for ( i = 0 ; i < count ; i++ ) {
155
+		aspect = params[i];
156
+		if ( aspect == 0 ) {
157
+			bios_attr = ATTR_DEFAULT;
158
+		} else if ( aspect == 1 ) {
159
+			bios_attr |= ATTR_BOLD;
160
+		} else if ( aspect == 5 ) {
161
+			bios_attr |= ATTR_BLINK;
162
+		} else if ( aspect == 22 ) {
163
+			bios_attr &= ~ATTR_BOLD;
164
+		} else if ( aspect == 25 ) {
165
+			bios_attr &= ~ATTR_BLINK;
166
+		} else if ( ( aspect >= 30 ) && ( aspect <= 39 ) ) {
167
+			bios_attr &= ~ATTR_FCOL_MASK;
168
+			bios_attr |= bios_attr_fcols[ aspect - 30 ];
169
+		} else if ( ( aspect >= 40 ) && ( aspect <= 49 ) ) {
170
+			bios_attr &= ~ATTR_BCOL_MASK;
171
+			bios_attr |= bios_attr_bcols[ aspect - 40 ];
172
+		}
173
+	}
174
+}
175
+
176
+/**
177
+ * Handle ANSI DECTCEM set (show cursor)
178
+ *
179
+ * @v ctx		ANSI escape sequence context
180
+ * @v count		Parameter count
181
+ * @v params		List of graphic rendition aspects
182
+ */
183
+static void bios_handle_dectcem_set ( struct ansiesc_context *ctx __unused,
184
+				      unsigned int count __unused,
185
+				      int params[] __unused ) {
186
+	uint8_t height;
187
+
188
+	/* Get character height */
189
+	get_real ( height, BDA_SEG, BDA_CHAR_HEIGHT );
190
+
191
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
192
+					   "int $0x10\n\t"
193
+					   "cli\n\t" )
194
+			       : : "a" ( 0x0100 ),
195
+				   "c" ( ( ( height - 2 ) << 8 ) |
196
+					 ( height - 1 ) ) );
197
+}
198
+
199
+/**
200
+ * Handle ANSI DECTCEM reset (hide cursor)
201
+ *
202
+ * @v ctx		ANSI escape sequence context
203
+ * @v count		Parameter count
204
+ * @v params		List of graphic rendition aspects
205
+ */
206
+static void bios_handle_dectcem_reset ( struct ansiesc_context *ctx __unused,
207
+					unsigned int count __unused,
208
+					int params[] __unused ) {
209
+
210
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
211
+					   "int $0x10\n\t"
212
+					   "cli\n\t" )
213
+			       : : "a" ( 0x0100 ), "c" ( 0x2000 ) );
214
+}
215
+
216
+/** BIOS console ANSI escape sequence handlers */
217
+static struct ansiesc_handler bios_ansiesc_handlers[] = {
218
+	{ ANSIESC_CUP, bios_handle_cup },
219
+	{ ANSIESC_ED, bios_handle_ed },
220
+	{ ANSIESC_SGR, bios_handle_sgr },
221
+	{ ANSIESC_DECTCEM_SET, bios_handle_dectcem_set },
222
+	{ ANSIESC_DECTCEM_RESET, bios_handle_dectcem_reset },
223
+	{ 0, NULL }
224
+};
225
+
226
+/** BIOS console ANSI escape sequence context */
227
+static struct ansiesc_context bios_ansiesc_ctx = {
228
+	.handlers = bios_ansiesc_handlers,
229
+};
230
+
231
+/**
232
+ * Print a character to BIOS console
233
+ *
234
+ * @v character		Character to be printed
235
+ */
236
+static void bios_putchar ( int character ) {
237
+	int discard_a, discard_b, discard_c;
238
+
239
+	/* Intercept ANSI escape sequences */
240
+	character = ansiesc_process ( &bios_ansiesc_ctx, character );
241
+	if ( character < 0 )
242
+		return;
243
+
244
+	/* Print character with attribute */
245
+	__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
246
+					   "sti\n\t"
247
+					   /* Skip non-printable characters */
248
+					   "cmpb $0x20, %%al\n\t"
249
+					   "jb 1f\n\t"
250
+					   /* Read attribute */
251
+					   "movb %%al, %%cl\n\t"
252
+					   "movb $0x08, %%ah\n\t"
253
+					   "int $0x10\n\t"
254
+					   "xchgb %%al, %%cl\n\t"
255
+					   /* Skip if attribute matches */
256
+					   "cmpb %%ah, %%bl\n\t"
257
+					   "je 1f\n\t"
258
+					   /* Set attribute */
259
+					   "movw $0x0001, %%cx\n\t"
260
+					   "movb $0x09, %%ah\n\t"
261
+					   "int $0x10\n\t"
262
+					   "\n1:\n\t"
263
+					   /* Print character */
264
+					   "xorw %%bx, %%bx\n\t"
265
+					   "movb $0x0e, %%ah\n\t"
266
+					   "int $0x10\n\t"
267
+					   "cli\n\t"
268
+					   "popl %%ebp\n\t" /* gcc bug */ )
269
+			       : "=a" ( discard_a ), "=b" ( discard_b ),
270
+			         "=c" ( discard_c )
271
+			       : "a" ( character ), "b" ( bios_attr ) );
272
+}
273
+
274
+/**
275
+ * Pointer to current ANSI output sequence
276
+ *
277
+ * While we are in the middle of returning an ANSI sequence for a
278
+ * special key, this will point to the next character to return.  When
279
+ * not in the middle of such a sequence, this will point to a NUL
280
+ * (note: not "will be NULL").
281
+ */
282
+static const char *bios_ansi_input = "";
283
+
284
+/** A BIOS key */
285
+struct bios_key {
286
+	/** Scancode */
287
+	uint8_t scancode;
288
+	/** Key code */
289
+	uint16_t key;
290
+} __attribute__ (( packed ));
291
+
292
+/** Mapping from BIOS scan codes to iPXE key codes */
293
+static const struct bios_key bios_keys[] = {
294
+	{ 0x53, KEY_DC },
295
+	{ 0x48, KEY_UP },
296
+	{ 0x50, KEY_DOWN },
297
+	{ 0x4b, KEY_LEFT },
298
+	{ 0x4d, KEY_RIGHT },
299
+	{ 0x47, KEY_HOME },
300
+	{ 0x4f, KEY_END },
301
+	{ 0x49, KEY_PPAGE },
302
+	{ 0x51, KEY_NPAGE },
303
+	{ 0x3f, KEY_F5 },
304
+	{ 0x40, KEY_F6 },
305
+	{ 0x41, KEY_F7 },
306
+	{ 0x42, KEY_F8 },
307
+	{ 0x43, KEY_F9 },
308
+	{ 0x44, KEY_F10 },
309
+	{ 0x85, KEY_F11 },
310
+	{ 0x86, KEY_F12 },
311
+};
312
+
313
+/**
314
+ * Get ANSI escape sequence corresponding to BIOS scancode
315
+ *
316
+ * @v scancode		BIOS scancode
317
+ * @ret ansi_seq	ANSI escape sequence, if any, otherwise NULL
318
+ */
319
+static const char * bios_ansi_seq ( unsigned int scancode ) {
320
+	static char buf[ 5 /* "[" + two digits + terminator + NUL */ ];
321
+	unsigned int key;
322
+	unsigned int terminator;
323
+	unsigned int n;
324
+	unsigned int i;
325
+	char *tmp = buf;
326
+
327
+	/* Construct ANSI escape sequence for scancode, if known */
328
+	for ( i = 0 ; i < ( sizeof ( bios_keys ) /
329
+			    sizeof ( bios_keys[0] ) ) ; i++ ) {
330
+
331
+		/* Look for matching scancode */
332
+		if ( bios_keys[i].scancode != scancode )
333
+			continue;
334
+
335
+		/* Construct escape sequence */
336
+		key = bios_keys[i].key;
337
+		n = KEY_ANSI_N ( key );
338
+		terminator = KEY_ANSI_TERMINATOR ( key );
339
+		*(tmp++) = '[';
340
+		if ( n )
341
+			tmp += sprintf ( tmp, "%d", n );
342
+		*(tmp++) = terminator;
343
+		*(tmp++) = '\0';
344
+		assert ( tmp <= &buf[ sizeof ( buf ) ] );
345
+		return buf;
346
+	}
347
+
348
+	DBG ( "Unrecognised BIOS scancode %02x\n", scancode );
349
+	return NULL;
350
+}
351
+
352
+/**
353
+ * Map a key
354
+ *
355
+ * @v character		Character read from console
356
+ * @ret character	Mapped character
357
+ */
358
+static int bios_keymap ( unsigned int character ) {
359
+	struct key_mapping *mapping;
360
+
361
+	for_each_table_entry ( mapping, KEYMAP ) {
362
+		if ( mapping->from == character )
363
+			return mapping->to;
364
+	}
365
+	return character;
366
+}
367
+
368
+/**
369
+ * Get character from BIOS console
370
+ *
371
+ * @ret character	Character read from console
372
+ */
373
+static int bios_getchar ( void ) {
374
+	uint16_t keypress;
375
+	unsigned int character;
376
+	const char *ansi_seq;
377
+
378
+	/* If we are mid-sequence, pass out the next byte */
379
+	if ( ( character = *bios_ansi_input ) ) {
380
+		bios_ansi_input++;
381
+		return character;
382
+	}
383
+
384
+	/* Do nothing if injection is in progress */
385
+	if ( bios_inject_lock )
386
+		return 0;
387
+
388
+	/* Read character from real BIOS console */
389
+	bios_inject_lock++;
390
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
391
+					   "int $0x16\n\t"
392
+					   "cli\n\t" )
393
+			       : "=a" ( keypress )
394
+			       : "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
395
+	bios_inject_lock--;
396
+	character = ( keypress & 0xff );
397
+
398
+	/* If it's a normal character, just map and return it */
399
+	if ( character && ( character < 0x80 ) )
400
+		return bios_keymap ( character );
401
+
402
+	/* Otherwise, check for a special key that we know about */
403
+	if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {
404
+		/* Start of escape sequence: return ESC (0x1b) */
405
+		bios_ansi_input = ansi_seq;
406
+		return 0x1b;
407
+	}
408
+
409
+	return 0;
410
+}
411
+
412
+/**
413
+ * Check for character ready to read from BIOS console
414
+ *
415
+ * @ret True		Character available to read
416
+ * @ret False		No character available to read
417
+ */
418
+static int bios_iskey ( void ) {
419
+	unsigned int discard_a;
420
+	unsigned int flags;
421
+
422
+	/* If we are mid-sequence, we are always ready */
423
+	if ( *bios_ansi_input )
424
+		return 1;
425
+
426
+	/* Do nothing if injection is in progress */
427
+	if ( bios_inject_lock )
428
+		return 0;
429
+
430
+	/* Otherwise check the real BIOS console */
431
+	bios_inject_lock++;
432
+	__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
433
+					   "int $0x16\n\t"
434
+					   "pushfw\n\t"
435
+					   "popw %w0\n\t"
436
+					   "cli\n\t" )
437
+			       : "=r" ( flags ), "=a" ( discard_a )
438
+			       : "a" ( 0x1100 ), "m" ( bios_inject_lock ) );
439
+	bios_inject_lock--;
440
+	return ( ! ( flags & ZF ) );
441
+}
442
+
443
+/** BIOS console */
444
+struct console_driver bios_console __console_driver = {
445
+	.putchar = bios_putchar,
446
+	.getchar = bios_getchar,
447
+	.iskey = bios_iskey,
448
+	.usage = CONSOLE_PCBIOS,
449
+};
450
+
451
+/**
452
+ * Inject keypresses
453
+ *
454
+ * @v ix86		Registers as passed to INT 16
455
+ */
456
+static __asmcall void bios_inject ( struct i386_all_regs *ix86 ) {
457
+	unsigned int discard_a;
458
+	unsigned int scancode;
459
+	unsigned int i;
460
+	uint16_t keypress;
461
+	int key;
462
+
463
+	/* If this is a blocking call, then loop until the
464
+	 * non-blocking variant of the call indicates that a keypress
465
+	 * is available.  Do this without acquiring the injection
466
+	 * lock, so that injection may take place.
467
+	 */
468
+	if ( ( ix86->regs.ah & ~0x10 ) == 0x00 ) {
469
+		__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
470
+						   "\n1:\n\t"
471
+						   "pushw %%ax\n\t"
472
+						   "int $0x16\n\t"
473
+						   "popw %%ax\n\t"
474
+						   "jc 2f\n\t"
475
+						   "jz 1b\n\t"
476
+						   "\n2:\n\t"
477
+						   "cli\n\t" )
478
+				       : "=a" ( discard_a )
479
+				       : "a" ( ix86->regs.eax | 0x0100 ),
480
+					 "m" ( bios_inject_lock ) );
481
+	}
482
+
483
+	/* Acquire injection lock */
484
+	bios_inject_lock++;
485
+
486
+	/* Check for keypresses */
487
+	if ( iskey() ) {
488
+
489
+		/* Get key */
490
+		key = getkey ( 0 );
491
+
492
+		/* Reverse internal CR->LF mapping */
493
+		if ( key == '\n' )
494
+			key = '\r';
495
+
496
+		/* Convert to keypress */
497
+		keypress = ( ( key << 8 ) | key );
498
+
499
+		/* Handle special keys */
500
+		if ( key >= KEY_MIN ) {
501
+			for ( i = 0 ; i < ( sizeof ( bios_keys ) /
502
+					    sizeof ( bios_keys[0] ) ) ; i++ ) {
503
+				if ( bios_keys[i].key == key ) {
504
+					scancode = bios_keys[i].scancode;
505
+					keypress = ( scancode << 8 );
506
+					break;
507
+				}
508
+			}
509
+		}
510
+
511
+		/* Inject keypress */
512
+		DBGC ( &bios_console, "BIOS injecting keypress %04x\n",
513
+		       keypress );
514
+		__asm__ __volatile__ ( REAL_CODE ( "int $0x16\n\t" )
515
+				       : "=a" ( discard_a )
516
+				       : "a" ( 0x0500 ), "c" ( keypress ),
517
+					 "m" ( bios_inject_lock ) );
518
+	}
519
+
520
+	/* Release injection lock */
521
+	bios_inject_lock--;
522
+}
523
+
524
+/**
525
+ * Start up keypress injection
526
+ *
527
+ */
528
+static void bios_inject_startup ( void ) {
529
+
530
+	/* Assembly wrapper to call bios_inject() */
531
+	__asm__ __volatile__ (
532
+		TEXT16_CODE ( "\nint16_wrapper:\n\t"
533
+			      "pushfw\n\t"
534
+			      "cmpb $0, %%cs:bios_inject_lock\n\t"
535
+			      "jnz 1f\n\t"
536
+			      "pushl %0\n\t"
537
+			      "pushw %%cs\n\t"
538
+			      "call prot_call\n\t"
539
+			      "addw $4, %%sp\n\t"
540
+			      "\n1:\n\t"
541
+			      "popfw\n\t"
542
+			      "ljmp *%%cs:int16_vector\n\t" )
543
+		: : "i" ( bios_inject ) );
544
+
545
+	/* Hook INT 16 */
546
+	hook_bios_interrupt ( 0x16, ( ( unsigned int ) int16_wrapper ),
547
+			      &int16_vector );
548
+}
549
+
550
+/**
551
+ * Shut down keypress injection
552
+ *
553
+ * @v booting		System is shutting down for OS boot
554
+ */
555
+static void bios_inject_shutdown ( int booting __unused ) {
556
+
557
+	/* Unhook INT 16 */
558
+	unhook_bios_interrupt ( 0x16, ( ( unsigned int ) int16_wrapper ),
559
+				&int16_vector );
560
+}
561
+
562
+/** Keypress injection startup function */
563
+struct startup_fn bios_inject_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
564
+	.startup = bios_inject_startup,
565
+	.shutdown = bios_inject_shutdown,
566
+};

+ 589
- 0
src/arch/i386/firmware/pcbios/e820mangler.S View File

@@ -0,0 +1,589 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
25
+
26
+	.text
27
+	.arch i386
28
+	.code16
29
+
30
+#define SMAP 0x534d4150
31
+
32
+/* Most documentation refers to the E820 buffer as being 20 bytes, and
33
+ * the API makes it perfectly legitimate to pass only a 20-byte buffer
34
+ * and expect to get valid data.  However, some morons at ACPI decided
35
+ * to extend the data structure by adding an extra "extended
36
+ * attributes" field and by including critical information within this
37
+ * field, such as whether or not the region is enabled.  A caller who
38
+ * passes in only a 20-byte buffer therefore risks getting very, very
39
+ * misleading information.
40
+ *
41
+ * I have personally witnessed an HP BIOS that returns a value of
42
+ * 0x0009 in the extended attributes field.  If we don't pass this
43
+ * value through to the caller, 32-bit WinPE will die, usually with a
44
+ * PAGE_FAULT_IN_NONPAGED_AREA blue screen of death.
45
+ *
46
+ * Allow a ridiculously large maximum value (64 bytes) for the E820
47
+ * buffer as a guard against insufficiently creative idiots in the
48
+ * future.
49
+ */
50
+#define E820MAXSIZE	64
51
+
52
+/****************************************************************************
53
+ *
54
+ * Allowed memory windows
55
+ *
56
+ * There are two ways to view this list.  The first is as a list of
57
+ * (non-overlapping) allowed memory regions, sorted by increasing
58
+ * address.  The second is as a list of (non-overlapping) hidden
59
+ * memory regions, again sorted by increasing address.  The second
60
+ * view is offset by half an entry from the first: think about this
61
+ * for a moment and it should make sense.
62
+ *
63
+ * xxx_memory_window is used to indicate an "allowed region"
64
+ * structure, hidden_xxx_memory is used to indicate a "hidden region"
65
+ * structure.  Each structure is 16 bytes in length.
66
+ *
67
+ ****************************************************************************
68
+ */
69
+	.section ".data16", "aw", @progbits
70
+	.align 16
71
+	.globl hidemem_base
72
+	.globl hidemem_umalloc
73
+	.globl hidemem_textdata
74
+memory_windows:
75
+base_memory_window:	.long 0x00000000, 0x00000000 /* Start of memory */
76
+
77
+hidemem_base:		.long 0x000a0000, 0x00000000 /* Changes at runtime */
78
+ext_memory_window:	.long 0x000a0000, 0x00000000 /* 640kB mark */
79
+
80
+hidemem_umalloc:	.long 0xffffffff, 0xffffffff /* Changes at runtime */
81
+			.long 0xffffffff, 0xffffffff /* Changes at runtime */
82
+
83
+hidemem_textdata:	.long 0xffffffff, 0xffffffff /* Changes at runtime */
84
+			.long 0xffffffff, 0xffffffff /* Changes at runtime */
85
+
86
+			.long 0xffffffff, 0xffffffff /* End of memory */
87
+memory_windows_end:
88
+
89
+/****************************************************************************
90
+ * Truncate region to memory window
91
+ *
92
+ * Parameters:
93
+ *  %edx:%eax	Start of region
94
+ *  %ecx:%ebx	Length of region
95
+ *  %si		Memory window
96
+ * Returns:
97
+ *  %edx:%eax	Start of windowed region
98
+ *  %ecx:%ebx	Length of windowed region
99
+ ****************************************************************************
100
+ */
101
+	.section ".text16", "ax", @progbits
102
+window_region:
103
+	/* Convert (start,len) to (start, end) */
104
+	addl	%eax, %ebx
105
+	adcl	%edx, %ecx
106
+	/* Truncate to window start */
107
+	cmpl	4(%si), %edx
108
+	jne	1f
109
+	cmpl	0(%si), %eax
110
+1:	jae	2f
111
+	movl	4(%si), %edx
112
+	movl	0(%si), %eax
113
+2:	/* Truncate to window end */
114
+	cmpl	12(%si), %ecx
115
+	jne	1f
116
+	cmpl	8(%si), %ebx
117
+1:	jbe	2f
118
+	movl	12(%si), %ecx
119
+	movl	8(%si), %ebx
120
+2:	/* Convert (start, end) back to (start, len) */
121
+	subl	%eax, %ebx
122
+	sbbl	%edx, %ecx
123
+	/* If length is <0, set length to 0 */
124
+	jae	1f
125
+	xorl	%ebx, %ebx
126
+	xorl	%ecx, %ecx
127
+	ret
128
+	.size	window_region, . - window_region
129
+
130
+/****************************************************************************
131
+ * Patch "memory above 1MB" figure
132
+ *
133
+ * Parameters:
134
+ *  %ax		Memory above 1MB, in 1kB blocks
135
+ * Returns:
136
+ *  %ax		Modified memory above 1M in 1kB blocks
137
+ ****************************************************************************
138
+ */
139
+	.section ".text16", "ax", @progbits
140
+patch_1m:
141
+	pushal
142
+	/* Convert to (start,len) format and call truncate */
143
+	xorl	%ecx, %ecx
144
+	movzwl	%ax, %ebx
145
+	shll	$10, %ebx
146
+	xorl	%edx, %edx
147
+	movl	$0x100000, %eax
148
+	movw	$ext_memory_window, %si
149
+	call	window_region
150
+	/* Convert back to "memory above 1MB" format and return via %ax */
151
+	pushfw
152
+	shrl	$10, %ebx
153
+	popfw
154
+	movw	%sp, %bp
155
+	movw	%bx, 28(%bp)
156
+	popal
157
+	ret
158
+	.size patch_1m, . - patch_1m
159
+
160
+/****************************************************************************
161
+ * Patch "memory above 16MB" figure
162
+ *
163
+ * Parameters:
164
+ *  %bx		Memory above 16MB, in 64kB blocks
165
+ * Returns:
166
+ *  %bx		Modified memory above 16M in 64kB blocks
167
+ ****************************************************************************
168
+ */
169
+	.section ".text16", "ax", @progbits
170
+patch_16m:
171
+	pushal
172
+	/* Convert to (start,len) format and call truncate */
173
+	xorl	%ecx, %ecx
174
+	shll	$16, %ebx
175
+	xorl	%edx, %edx
176
+	movl	$0x1000000, %eax
177
+	movw	$ext_memory_window, %si
178
+	call	window_region
179
+	/* Convert back to "memory above 16MB" format and return via %bx */
180
+	pushfw
181
+	shrl	$16, %ebx
182
+	popfw
183
+	movw	%sp, %bp
184
+	movw	%bx, 16(%bp)
185
+	popal
186
+	ret
187
+	.size patch_16m, . - patch_16m
188
+
189
+/****************************************************************************
190
+ * Patch "memory between 1MB and 16MB" and "memory above 16MB" figures
191
+ *
192
+ * Parameters:
193
+ *  %ax		Memory between 1MB and 16MB, in 1kB blocks
194
+ *  %bx		Memory above 16MB, in 64kB blocks
195
+ * Returns:
196
+ *  %ax		Modified memory between 1MB and 16MB, in 1kB blocks
197
+ *  %bx		Modified memory above 16MB, in 64kB blocks
198
+ ****************************************************************************
199
+ */
200
+	.section ".text16", "ax", @progbits
201
+patch_1m_16m:
202
+	call	patch_1m
203
+	call	patch_16m
204
+	/* If 1M region is no longer full-length, kill off the 16M region */
205
+	cmpw	$( 15 * 1024 ), %ax
206
+	je	1f
207
+	xorw	%bx, %bx
208
+1:	ret
209
+	.size patch_1m_16m, . - patch_1m_16m
210
+
211
+/****************************************************************************
212
+ * Get underlying e820 memory region to underlying_e820 buffer
213
+ *
214
+ * Parameters:
215
+ *   As for INT 15,e820
216
+ * Returns:
217
+ *   As for INT 15,e820
218
+ *
219
+ * Wraps the underlying INT 15,e820 call so that the continuation
220
+ * value (%ebx) is a 16-bit simple sequence counter (with the high 16
221
+ * bits ignored), and termination is always via CF=1 rather than
222
+ * %ebx=0.
223
+ *
224
+ ****************************************************************************
225
+ */
226
+	.section ".text16", "ax", @progbits
227
+get_underlying_e820:
228
+
229
+	/* If the requested region is in the cache, return it */
230
+	cmpw	%bx, underlying_e820_index
231
+	jne	2f
232
+	pushw	%di
233
+	pushw	%si
234
+	movw	$underlying_e820_cache, %si
235
+	cmpl	underlying_e820_cache_size, %ecx
236
+	jbe	1f
237
+	movl	underlying_e820_cache_size, %ecx
238
+1:	pushl	%ecx
239
+	rep movsb
240
+	popl	%ecx
241
+	popw	%si
242
+	popw	%di
243
+	incw	%bx
244
+	movl	%edx, %eax
245
+	clc
246
+	ret
247
+2:	
248
+	/* If the requested region is earlier than the cached region,
249
+	 * invalidate the cache.
250
+	 */
251
+	cmpw	%bx, underlying_e820_index
252
+	jbe	1f
253
+	movw	$0xffff, underlying_e820_index
254
+1:
255
+	/* If the cache is invalid, reset the underlying %ebx */
256
+	cmpw	$0xffff, underlying_e820_index
257
+	jne	1f
258
+	andl	$0, underlying_e820_ebx
259
+1:	
260
+	/* If the cache is valid but the continuation value is zero,
261
+	 * this means that the previous underlying call returned with
262
+	 * %ebx=0.  Return with CF=1 in this case.
263
+	 */
264
+	cmpw	$0xffff, underlying_e820_index
265
+	je	1f
266
+	cmpl	$0, underlying_e820_ebx
267
+	jne	1f
268
+	stc
269
+	ret
270
+1:	
271
+	/* Get the next region into the cache */
272
+	pushl	%eax
273
+	pushl	%ebx
274
+	pushl	%ecx
275
+	pushl	%edx
276
+	pushl	%esi	/* Some implementations corrupt %esi, so we	*/
277
+	pushl	%edi	/* preserve %esi, %edi and %ebp to be paranoid	*/
278
+	pushl	%ebp
279
+	pushw	%es
280
+	pushw	%ds
281
+	popw	%es
282
+	movw	$underlying_e820_cache, %di
283
+	cmpl	$E820MAXSIZE, %ecx
284
+	jbe	1f
285
+	movl	$E820MAXSIZE, %ecx
286
+1:	movl	underlying_e820_ebx, %ebx
287
+	stc
288
+	pushfw
289
+	lcall	*%cs:int15_vector
290
+	popw	%es
291
+	popl	%ebp
292
+	popl	%edi
293
+	popl	%esi
294
+	/* Check for error return from underlying e820 call */
295
+	jc	2f /* CF set: error */
296
+	cmpl	$SMAP, %eax
297
+	je	3f /* 'SMAP' missing: error */
298
+2:	/* An error occurred: return values returned by underlying e820 call */
299
+	stc	/* Force CF set if SMAP was missing */
300
+	addr32 leal 16(%esp), %esp /* avoid changing other flags */
301
+	ret
302
+3:	/* No error occurred */
303
+	movl	%ebx, underlying_e820_ebx
304
+	movl	%ecx, underlying_e820_cache_size
305
+	popl	%edx
306
+	popl	%ecx
307
+	popl	%ebx
308
+	popl	%eax
309
+	/* Mark cache as containing this result */
310
+	incw	underlying_e820_index
311
+
312
+	/* Loop until found */
313
+	jmp	get_underlying_e820
314
+	.size	get_underlying_e820, . - get_underlying_e820
315
+
316
+	.section ".data16", "aw", @progbits
317
+underlying_e820_index:
318
+	.word	0xffff /* Initialise to an invalid value */
319
+	.size underlying_e820_index, . - underlying_e820_index
320
+
321
+	.section ".bss16", "aw", @nobits
322
+underlying_e820_ebx:
323
+	.long	0
324
+	.size underlying_e820_ebx, . - underlying_e820_ebx
325
+
326
+	.section ".bss16", "aw", @nobits
327
+underlying_e820_cache:
328
+	.space	E820MAXSIZE
329
+	.size underlying_e820_cache, . - underlying_e820_cache
330
+
331
+	.section ".bss16", "aw", @nobits
332
+underlying_e820_cache_size:
333
+	.long	0
334
+	.size	underlying_e820_cache_size, . - underlying_e820_cache_size
335
+
336
+/****************************************************************************
337
+ * Get windowed e820 region, without empty region stripping
338
+ *
339
+ * Parameters:
340
+ *   As for INT 15,e820
341
+ * Returns:
342
+ *   As for INT 15,e820
343
+ *
344
+ * Wraps the underlying INT 15,e820 call so that each underlying
345
+ * region is returned N times, windowed to fit within N visible-memory
346
+ * windows.  Termination is always via CF=1.
347
+ *
348
+ ****************************************************************************
349
+ */
350
+	.section ".text16", "ax", @progbits
351
+get_windowed_e820:
352
+
353
+	/* Preserve registers */
354
+	pushl	%esi
355
+	pushw	%bp
356
+
357
+	/* Split %ebx into %si:%bx, store original %bx in %bp */
358
+	pushl	%ebx
359
+	popw	%bp
360
+	popw	%si
361
+
362
+	/* %si == 0 => start of memory_windows list */
363
+	testw	%si, %si
364
+	jne	1f
365
+	movw	$memory_windows, %si
366
+1:	
367
+	/* Get (cached) underlying e820 region to buffer */
368
+	call	get_underlying_e820
369
+	jc	99f /* Abort on error */
370
+
371
+	/* Preserve registers */
372
+	pushal
373
+	/* start => %edx:%eax, len => %ecx:%ebx */
374
+	movl	%es:0(%di), %eax
375
+	movl	%es:4(%di), %edx
376
+	movl	%es:8(%di), %ebx
377
+	movl	%es:12(%di), %ecx
378
+	/* Truncate region to current window */
379
+	call	window_region
380
+1:	/* Store modified values in e820 map entry */
381
+	movl	%eax, %es:0(%di)
382
+	movl	%edx, %es:4(%di)
383
+	movl	%ebx, %es:8(%di)
384
+	movl	%ecx, %es:12(%di)
385
+	/* Restore registers */
386
+	popal
387
+
388
+	/* Derive continuation value for next call */
389
+	addw	$16, %si
390
+	cmpw	$memory_windows_end, %si
391
+	jne	1f
392
+	/* End of memory windows: reset %si and allow %bx to continue */
393
+	xorw	%si, %si
394
+	jmp	2f
395
+1:	/* More memory windows to go: restore original %bx */
396
+	movw	%bp, %bx
397
+2:	/* Construct %ebx from %si:%bx */
398
+	pushw	%si
399
+	pushw	%bx
400
+	popl	%ebx
401
+
402
+98:	/* Clear CF */
403
+	clc
404
+99:	/* Restore registers and return */
405
+	popw	%bp
406
+	popl	%esi
407
+	ret
408
+	.size get_windowed_e820, . - get_windowed_e820
409
+
410
+/****************************************************************************
411
+ * Get windowed e820 region, with empty region stripping
412
+ *
413
+ * Parameters:
414
+ *   As for INT 15,e820
415
+ * Returns:
416
+ *   As for INT 15,e820
417
+ *
418
+ * Wraps the underlying INT 15,e820 call so that each underlying
419
+ * region is returned up to N times, windowed to fit within N
420
+ * visible-memory windows.  Empty windows are never returned.
421
+ * Termination is always via CF=1.
422
+ *
423
+ ****************************************************************************
424
+ */
425
+	.section ".text16", "ax", @progbits
426
+get_nonempty_e820:
427
+
428
+	/* Record entry parameters */
429
+	pushl	%eax
430
+	pushl	%ecx
431
+	pushl	%edx
432
+
433
+	/* Get next windowed region */
434
+	call	get_windowed_e820
435
+	jc	99f /* abort on error */
436
+
437
+	/* If region is non-empty, finish here */
438
+	cmpl	$0, %es:8(%di)
439
+	jne	98f
440
+	cmpl	$0, %es:12(%di)
441
+	jne	98f
442
+
443
+	/* Region was empty: restore entry parameters and go to next region */
444
+	popl	%edx
445
+	popl	%ecx
446
+	popl	%eax
447
+	jmp	get_nonempty_e820
448
+
449
+98:	/* Clear CF */
450
+	clc
451
+99:	/* Return values from underlying call */
452
+	addr32 leal 12(%esp), %esp /* avoid changing flags */
453
+	ret
454
+	.size get_nonempty_e820, . - get_nonempty_e820
455
+
456
+/****************************************************************************
457
+ * Get mangled e820 region, with empty region stripping
458
+ *
459
+ * Parameters:
460
+ *   As for INT 15,e820
461
+ * Returns:
462
+ *   As for INT 15,e820
463
+ *
464
+ * Wraps the underlying INT 15,e820 call so that underlying regions
465
+ * are windowed to the allowed memory regions.  Empty regions are
466
+ * stripped from the map.  Termination is always via %ebx=0.
467
+ *
468
+ ****************************************************************************
469
+ */
470
+	.section ".text16", "ax", @progbits
471
+get_mangled_e820:
472
+
473
+	/* Get a nonempty region */
474
+	call	get_nonempty_e820
475
+	jc	99f /* Abort on error */
476
+
477
+	/* Peek ahead to see if there are any further nonempty regions */
478
+	pushal
479
+	pushw	%es
480
+	movw	%sp, %bp
481
+	subw	%cx, %sp
482
+	movl	$0xe820, %eax
483
+	movl	$SMAP, %edx
484
+	pushw	%ss
485
+	popw	%es
486
+	movw	%sp, %di
487
+	call	get_nonempty_e820
488
+	movw	%bp, %sp
489
+	popw	%es
490
+	popal
491
+	jnc	99f /* There are further nonempty regions */
492
+
493
+	/* No futher nonempty regions: zero %ebx and clear CF */
494
+	xorl	%ebx, %ebx
495
+	
496
+99:	/* Return */
497
+	ret
498
+	.size get_mangled_e820, . - get_mangled_e820
499
+
500
+/****************************************************************************
501
+ * INT 15,e820 handler
502
+ ****************************************************************************
503
+ */
504
+	.section ".text16", "ax", @progbits
505
+int15_e820:
506
+	pushw	%ds
507
+	pushw	%cs:rm_ds
508
+	popw	%ds
509
+	call	get_mangled_e820
510
+	popw	%ds
511
+	call	patch_cf
512
+	iret
513
+	.size int15_e820, . - int15_e820
514
+	
515
+/****************************************************************************
516
+ * INT 15,e801 handler
517
+ ****************************************************************************
518
+ */
519
+	.section ".text16", "ax", @progbits
520
+int15_e801:
521
+	/* Call previous handler */
522
+	pushfw
523
+	lcall	*%cs:int15_vector
524
+	call	patch_cf
525
+	/* Edit result */
526
+	pushw	%ds
527
+	pushw	%cs:rm_ds
528
+	popw	%ds
529
+	call	patch_1m_16m
530
+	xchgw	%ax, %cx
531
+	xchgw	%bx, %dx
532
+	call	patch_1m_16m
533
+	xchgw	%ax, %cx
534
+	xchgw	%bx, %dx
535
+	popw	%ds
536
+	iret
537
+	.size int15_e801, . - int15_e801
538
+	
539
+/****************************************************************************
540
+ * INT 15,88 handler
541
+ ****************************************************************************
542
+ */
543
+	.section ".text16", "ax", @progbits
544
+int15_88:
545
+	/* Call previous handler */
546
+	pushfw
547
+	lcall	*%cs:int15_vector
548
+	call	patch_cf
549
+	/* Edit result */
550
+	pushw	%ds
551
+	pushw	%cs:rm_ds
552
+	popw	%ds
553
+	call	patch_1m
554
+	popw	%ds
555
+	iret
556
+	.size int15_88, . - int15_88
557
+		
558
+/****************************************************************************
559
+ * INT 15 handler
560
+ ****************************************************************************
561
+ */
562
+	.section ".text16", "ax", @progbits
563
+	.globl int15
564
+int15:
565
+	/* See if we want to intercept this call */
566
+	pushfw
567
+	cmpw	$0xe820, %ax
568
+	jne	1f
569
+	cmpl	$SMAP, %edx
570
+	jne	1f
571
+	popfw
572
+	jmp	int15_e820
573
+1:	cmpw	$0xe801, %ax
574
+	jne	2f
575
+	popfw
576
+	jmp	int15_e801
577
+2:	cmpb	$0x88, %ah
578
+	jne	3f
579
+	popfw
580
+	jmp	int15_88
581
+3:	popfw
582
+	ljmp	*%cs:int15_vector
583
+	.size int15, . - int15
584
+	
585
+	.section ".text16.data", "aw", @progbits
586
+	.globl int15_vector
587
+int15_vector:
588
+	.long 0
589
+	.size int15_vector, . - int15_vector

+ 98
- 0
src/arch/i386/firmware/pcbios/fakee820.c View File

@@ -0,0 +1,98 @@
1
+/* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
2
+ *
3
+ * This program is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU General Public License as
5
+ * published by the Free Software Foundation; either version 2 of the
6
+ * License, or any later version.
7
+ *
8
+ * This program is distributed in the hope that it will be useful, but
9
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU General Public License
14
+ * along with this program; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16
+ * 02110-1301, USA.
17
+ *
18
+ * You can also choose to distribute this program under the terms of
19
+ * the Unmodified Binary Distribution Licence (as given in the file
20
+ * COPYING.UBDL), provided that you have satisfied its requirements.
21
+ */
22
+
23
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
24
+
25
+#include <realmode.h>
26
+#include <biosint.h>
27
+
28
+/** Assembly routine in inline asm */
29
+extern void int15_fakee820();
30
+
31
+/** Original INT 15 handler */
32
+static struct segoff __text16 ( real_int15_vector );
33
+#define real_int15_vector __use_text16 ( real_int15_vector )
34
+
35
+/** An INT 15,e820 memory map entry */
36
+struct e820_entry {
37
+	/** Start of region */
38
+	uint64_t start;
39
+	/** Length of region */
40
+	uint64_t len;
41
+	/** Type of region */
42
+	uint32_t type;
43
+} __attribute__ (( packed ));
44
+
45
+#define E820_TYPE_RAM		1 /**< Normal memory */
46
+#define E820_TYPE_RSVD		2 /**< Reserved and unavailable */
47
+#define E820_TYPE_ACPI		3 /**< ACPI reclaim memory */
48
+#define E820_TYPE_NVS		4 /**< ACPI NVS memory */
49
+
50
+/** Fake e820 map */
51
+static struct e820_entry __text16_array ( e820map, [] ) __used = {
52
+	{ 0x00000000ULL, ( 0x000a0000ULL - 0x00000000ULL ), E820_TYPE_RAM },
53
+	{ 0x00100000ULL, ( 0xcfb50000ULL - 0x00100000ULL ), E820_TYPE_RAM },
54
+	{ 0xcfb50000ULL, ( 0xcfb64000ULL - 0xcfb50000ULL ), E820_TYPE_RSVD },
55
+	{ 0xcfb64000ULL, ( 0xcfb66000ULL - 0xcfb64000ULL ), E820_TYPE_RSVD },
56
+	{ 0xcfb66000ULL, ( 0xcfb85c00ULL - 0xcfb66000ULL ), E820_TYPE_ACPI },
57
+	{ 0xcfb85c00ULL, ( 0xd0000000ULL - 0xcfb85c00ULL ), E820_TYPE_RSVD },
58
+	{ 0xe0000000ULL, ( 0xf0000000ULL - 0xe0000000ULL ), E820_TYPE_RSVD },
59
+	{ 0xfe000000ULL, (0x100000000ULL - 0xfe000000ULL ), E820_TYPE_RSVD },
60
+	{0x100000000ULL, (0x230000000ULL -0x100000000ULL ), E820_TYPE_RAM },
61
+};
62
+#define e820map __use_text16 ( e820map )
63
+
64
+void fake_e820 ( void ) {
65
+	__asm__ __volatile__ (
66
+		TEXT16_CODE ( "\nint15_fakee820:\n\t"
67
+			      "pushfw\n\t"
68
+			      "cmpl $0xe820, %%eax\n\t"
69
+			      "jne 99f\n\t"
70
+			      "cmpl $0x534d4150, %%edx\n\t"
71
+			      "jne 99f\n\t"
72
+			      "pushaw\n\t"
73
+			      "movw %%sp, %%bp\n\t"
74
+			      "andb $~0x01, 22(%%bp)\n\t" /* Clear return CF */
75
+			      "leaw e820map(%%bx), %%si\n\t"
76
+			      "cs rep movsb\n\t"
77
+			      "popaw\n\t"
78
+			      "movl %%edx, %%eax\n\t"
79
+			      "addl $20, %%ebx\n\t"
80
+			      "cmpl %0, %%ebx\n\t"
81
+			      "jne 1f\n\t"
82
+			      "xorl %%ebx,%%ebx\n\t"
83
+			      "\n1:\n\t"
84
+			      "popfw\n\t"
85
+			      "iret\n\t"
86
+			      "\n99:\n\t"
87
+			      "popfw\n\t"
88
+			      "ljmp *%%cs:real_int15_vector\n\t" )
89
+		: : "i" ( sizeof ( e820map ) ) );
90
+
91
+	hook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
92
+			      &real_int15_vector );
93
+}
94
+
95
+void unfake_e820 ( void ) {
96
+	unhook_bios_interrupt ( 0x15, ( unsigned int ) int15_fakee820,
97
+				&real_int15_vector );
98
+}

+ 235
- 0
src/arch/i386/firmware/pcbios/hidemem.c View File

@@ -0,0 +1,235 @@
1
+/* Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
2
+ *
3
+ * This program is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU General Public License as
5
+ * published by the Free Software Foundation; either version 2 of the
6
+ * License, or any later version.
7
+ *
8
+ * This program is distributed in the hope that it will be useful, but
9
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU General Public License
14
+ * along with this program; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16
+ * 02110-1301, USA.
17
+ *
18
+ * You can also choose to distribute this program under the terms of
19
+ * the Unmodified Binary Distribution Licence (as given in the file
20
+ * COPYING.UBDL), provided that you have satisfied its requirements.
21
+ */
22
+
23
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
24
+
25
+#include <assert.h>
26
+#include <realmode.h>
27
+#include <biosint.h>
28
+#include <basemem.h>
29
+#include <fakee820.h>
30
+#include <ipxe/init.h>
31
+#include <ipxe/io.h>
32
+#include <ipxe/hidemem.h>
33
+
34
+/** Set to true if you want to test a fake E820 map */
35
+#define FAKE_E820 0
36
+
37
+/** Alignment for hidden memory regions */
38
+#define ALIGN_HIDDEN 4096   /* 4kB page alignment should be enough */
39
+
40
+/**
41
+ * A hidden region of iPXE
42
+ *
43
+ * This represents a region that will be edited out of the system's
44
+ * memory map.
45
+ *
46
+ * This structure is accessed by assembly code, so must not be
47
+ * changed.
48
+ */
49
+struct hidden_region {
50
+	/** Physical start address */
51
+	uint64_t start;
52
+	/** Physical end address */
53
+	uint64_t end;
54
+};
55
+
56
+/** Hidden base memory */
57
+extern struct hidden_region __data16 ( hidemem_base );
58
+#define hidemem_base __use_data16 ( hidemem_base )
59
+
60
+/** Hidden umalloc memory */
61
+extern struct hidden_region __data16 ( hidemem_umalloc );
62
+#define hidemem_umalloc __use_data16 ( hidemem_umalloc )
63
+
64
+/** Hidden text memory */
65
+extern struct hidden_region __data16 ( hidemem_textdata );
66
+#define hidemem_textdata __use_data16 ( hidemem_textdata )
67
+
68
+/** Assembly routine in e820mangler.S */
69
+extern void int15();
70
+
71
+/** Vector for storing original INT 15 handler */
72
+extern struct segoff __text16 ( int15_vector );
73
+#define int15_vector __use_text16 ( int15_vector )
74
+
75
+/* The linker defines these symbols for us */
76
+extern char _textdata[];
77
+extern char _etextdata[];
78
+extern char _text16_memsz[];
79
+#define _text16_memsz ( ( unsigned int ) _text16_memsz )
80
+extern char _data16_memsz[];
81
+#define _data16_memsz ( ( unsigned int ) _data16_memsz )
82
+
83
+/**
84
+ * Hide region of memory from system memory map
85
+ *
86
+ * @v region		Hidden memory region
87
+ * @v start		Start of region
88
+ * @v end		End of region
89
+ */
90
+static void hide_region ( struct hidden_region *region,
91
+			  physaddr_t start, physaddr_t end ) {
92
+
93
+	/* Some operating systems get a nasty shock if a region of the
94
+	 * E820 map seems to start on a non-page boundary.  Make life
95
+	 * safer by rounding out our edited region.
96
+	 */
97
+	region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
98
+	region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
99
+
100
+	DBG ( "Hiding region [%llx,%llx)\n", region->start, region->end );
101
+}
102
+
103
+/**
104
+ * Hide used base memory
105
+ *
106
+ */
107
+void hide_basemem ( void ) {
108
+	/* Hide from the top of free base memory to 640kB.  Don't use
109
+	 * hide_region(), because we don't want this rounded to the
110
+	 * nearest page boundary.
111
+	 */
112
+	hidemem_base.start = ( get_fbms() * 1024 );
113
+}
114
+
115
+/**
116
+ * Hide umalloc() region
117
+ *
118
+ */
119
+void hide_umalloc ( physaddr_t start, physaddr_t end ) {
120
+	assert ( end <= virt_to_phys ( _textdata ) );
121
+	hide_region ( &hidemem_umalloc, start, end );
122
+}
123
+
124
+/**
125
+ * Hide .text and .data
126
+ *
127
+ */
128
+void hide_textdata ( void ) {
129
+	hide_region ( &hidemem_textdata, virt_to_phys ( _textdata ),
130
+		      virt_to_phys ( _etextdata ) );
131
+}
132
+
133
+/**
134
+ * Hide Etherboot
135
+ *
136
+ * Installs an INT 15 handler to edit Etherboot out of the memory map
137
+ * returned by the BIOS.
138
+ */
139
+static void hide_etherboot ( void ) {
140
+	struct memory_map memmap;
141
+	unsigned int rm_ds_top;
142
+	unsigned int rm_cs_top;
143
+	unsigned int fbms;
144
+
145
+	/* Dump memory map before mangling */
146
+	DBG ( "Hiding iPXE from system memory map\n" );
147
+	get_memmap ( &memmap );
148
+
149
+	/* Hook in fake E820 map, if we're testing one */
150
+	if ( FAKE_E820 ) {
151
+		DBG ( "Hooking in fake E820 map\n" );
152
+		fake_e820();
153
+		get_memmap ( &memmap );
154
+	}
155
+
156
+	/* Initialise the hidden regions */
157
+	hide_basemem();
158
+	hide_umalloc ( virt_to_phys ( _textdata ), virt_to_phys ( _textdata ) );
159
+	hide_textdata();
160
+
161
+	/* Some really moronic BIOSes bring up the PXE stack via the
162
+	 * UNDI loader entry point and then don't bother to unload it
163
+	 * before overwriting the code and data segments.  If this
164
+	 * happens, we really don't want to leave INT 15 hooked,
165
+	 * because that will cause any loaded OS to die horribly as
166
+	 * soon as it attempts to fetch the system memory map.
167
+	 *
168
+	 * We use a heuristic to guess whether or not we are being
169
+	 * loaded sensibly.
170
+	 */
171
+	rm_cs_top = ( ( ( rm_cs << 4 ) + _text16_memsz + 1024 - 1 ) >> 10 );
172
+	rm_ds_top = ( ( ( rm_ds << 4 ) + _data16_memsz + 1024 - 1 ) >> 10 );
173
+	fbms = get_fbms();
174
+	if ( ( rm_cs_top < fbms ) && ( rm_ds_top < fbms ) ) {
175
+		DBG ( "Detected potentially unsafe UNDI load at CS=%04x "
176
+		      "DS=%04x FBMS=%dkB\n", rm_cs, rm_ds, fbms );
177
+		DBG ( "Disabling INT 15 memory hiding\n" );
178
+		return;
179
+	}
180
+
181
+	/* Hook INT 15 */
182
+	hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
183
+			      &int15_vector );
184
+
185
+	/* Dump memory map after mangling */
186
+	DBG ( "Hidden iPXE from system memory map\n" );
187
+	get_memmap ( &memmap );
188
+}
189
+
190
+/**
191
+ * Unhide Etherboot
192
+ *
193
+ * Uninstalls the INT 15 handler installed by hide_etherboot(), if
194
+ * possible.
195
+ */
196
+static void unhide_etherboot ( int flags __unused ) {
197
+	struct memory_map memmap;
198
+	int rc;
199
+
200
+	/* If we have more than one hooked interrupt at this point, it
201
+	 * means that some other vector is still hooked, in which case
202
+	 * we can't safely unhook INT 15 because we need to keep our
203
+	 * memory protected.  (We expect there to be at least one
204
+	 * hooked interrupt, because INT 15 itself is still hooked).
205
+	 */
206
+	if ( hooked_bios_interrupts > 1 ) {
207
+		DBG ( "Cannot unhide: %d interrupt vectors still hooked\n",
208
+		      hooked_bios_interrupts );
209
+		return;
210
+	}
211
+
212
+	/* Try to unhook INT 15 */
213
+	if ( ( rc = unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
214
+					    &int15_vector ) ) != 0 ) {
215
+		DBG ( "Cannot unhook INT15: %s\n", strerror ( rc ) );
216
+		/* Leave it hooked; there's nothing else we can do,
217
+		 * and it should be intrinsically safe (though
218
+		 * wasteful of RAM).
219
+		 */
220
+	}
221
+
222
+	/* Unhook fake E820 map, if used */
223
+	if ( FAKE_E820 )
224
+		unfake_e820();
225
+
226
+	/* Dump memory map after unhiding */
227
+	DBG ( "Unhidden iPXE from system memory map\n" );
228
+	get_memmap ( &memmap );
229
+}
230
+
231
+/** Hide Etherboot startup function */
232
+struct startup_fn hide_etherboot_startup_fn __startup_fn ( STARTUP_EARLY ) = {
233
+	.startup = hide_etherboot,
234
+	.shutdown = unhide_etherboot,
235
+};

+ 343
- 0
src/arch/i386/firmware/pcbios/memmap.c View File

@@ -0,0 +1,343 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <errno.h>
28
+#include <realmode.h>
29
+#include <bios.h>
30
+#include <memsizes.h>
31
+#include <ipxe/io.h>
32
+
33
+/**
34
+ * @file
35
+ *
36
+ * Memory mapping
37
+ *
38
+ */
39
+
40
+/** Magic value for INT 15,e820 calls */
41
+#define SMAP ( 0x534d4150 )
42
+
43
+/** An INT 15,e820 memory map entry */
44
+struct e820_entry {
45
+	/** Start of region */
46
+	uint64_t start;
47
+	/** Length of region */
48
+	uint64_t len;
49
+	/** Type of region */
50
+	uint32_t type;
51
+	/** Extended attributes (optional) */
52
+	uint32_t attrs;
53
+} __attribute__ (( packed ));
54
+
55
+#define E820_TYPE_RAM		1 /**< Normal memory */
56
+#define E820_TYPE_RESERVED	2 /**< Reserved and unavailable */
57
+#define E820_TYPE_ACPI		3 /**< ACPI reclaim memory */
58
+#define E820_TYPE_NVS		4 /**< ACPI NVS memory */
59
+
60
+#define E820_ATTR_ENABLED	0x00000001UL
61
+#define E820_ATTR_NONVOLATILE	0x00000002UL
62
+#define E820_ATTR_UNKNOWN	0xfffffffcUL
63
+
64
+#define E820_MIN_SIZE		20
65
+
66
+/** Buffer for INT 15,e820 calls */
67
+static struct e820_entry __bss16 ( e820buf );
68
+#define e820buf __use_data16 ( e820buf )
69
+
70
+/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */
71
+uint8_t __bss16 ( memmap_post );
72
+#define memmap_post __use_data16 ( memmap_post )
73
+
74
+/**
75
+ * Get size of extended memory via INT 15,e801
76
+ *
77
+ * @ret extmem		Extended memory size, in kB, or 0
78
+ */
79
+static unsigned int extmemsize_e801 ( void ) {
80
+	uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
81
+	uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
82
+	unsigned int flags;
83
+	unsigned int extmem;
84
+
85
+	/* Inhibit INT 15,e801 during POST */
86
+	if ( memmap_post ) {
87
+		DBG ( "INT 15,e801 not available during POST\n" );
88
+		return 0;
89
+	}
90
+
91
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
92
+					   "int $0x15\n\t"
93
+					   "pushfw\n\t"
94
+					   "popw %w0\n\t" )
95
+			       : "=r" ( flags ),
96
+				 "=a" ( extmem_1m_to_16m_k ),
97
+				 "=b" ( extmem_16m_plus_64k ),
98
+				 "=c" ( confmem_1m_to_16m_k ),
99
+				 "=d" ( confmem_16m_plus_64k )
100
+			       : "a" ( 0xe801 ) );
101
+
102
+	if ( flags & CF ) {
103
+		DBG ( "INT 15,e801 failed with CF set\n" );
104
+		return 0;
105
+	}
106
+
107
+	if ( ! ( extmem_1m_to_16m_k | extmem_16m_plus_64k ) ) {
108
+		DBG ( "INT 15,e801 extmem=0, using confmem\n" );
109
+		extmem_1m_to_16m_k = confmem_1m_to_16m_k;
110
+		extmem_16m_plus_64k = confmem_16m_plus_64k;
111
+	}
112
+
113
+	extmem = ( extmem_1m_to_16m_k + ( extmem_16m_plus_64k * 64 ) );
114
+	DBG ( "INT 15,e801 extended memory size %d+64*%d=%d kB "
115
+	      "[100000,%llx)\n", extmem_1m_to_16m_k, extmem_16m_plus_64k,
116
+	      extmem, ( 0x100000 + ( ( ( uint64_t ) extmem ) * 1024 ) ) );
117
+
118
+	/* Sanity check.  Some BIOSes report the entire 4GB address
119
+	 * space as available, which cannot be correct (since that
120
+	 * would leave no address space available for 32-bit PCI
121
+	 * BARs).
122
+	 */
123
+	if ( extmem == ( 0x400000 - 0x400 ) ) {
124
+		DBG ( "INT 15,e801 reported whole 4GB; assuming insane\n" );
125
+		return 0;
126
+	}
127
+
128
+	return extmem;
129
+}
130
+
131
+/**
132
+ * Get size of extended memory via INT 15,88
133
+ *
134
+ * @ret extmem		Extended memory size, in kB
135
+ */
136
+static unsigned int extmemsize_88 ( void ) {
137
+	uint16_t extmem;
138
+
139
+	/* Ignore CF; it is not reliable for this call */
140
+	__asm__ __volatile__ ( REAL_CODE ( "int $0x15" )
141
+			       : "=a" ( extmem ) : "a" ( 0x8800 ) );
142
+
143
+	DBG ( "INT 15,88 extended memory size %d kB [100000, %x)\n",
144
+	      extmem, ( 0x100000 + ( extmem * 1024 ) ) );
145
+	return extmem;
146
+}
147
+
148
+/**
149
+ * Get size of extended memory
150
+ *
151
+ * @ret extmem		Extended memory size, in kB
152
+ *
153
+ * Note that this is only an approximation; for an accurate picture,
154
+ * use the E820 memory map obtained via get_memmap();
155
+ */
156
+unsigned int extmemsize ( void ) {
157
+	unsigned int extmem_e801;
158
+	unsigned int extmem_88;
159
+
160
+	/* Try INT 15,e801 first, then fall back to INT 15,88 */
161
+	extmem_88 = extmemsize_88();
162
+	extmem_e801 = extmemsize_e801();
163
+	return ( extmem_e801 ? extmem_e801 : extmem_88 );
164
+}
165
+
166
+/**
167
+ * Get e820 memory map
168
+ *
169
+ * @v memmap		Memory map to fill in
170
+ * @ret rc		Return status code
171
+ */
172
+static int meme820 ( struct memory_map *memmap ) {
173
+	struct memory_region *region = memmap->regions;
174
+	struct memory_region *prev_region = NULL;
175
+	uint32_t next = 0;
176
+	uint32_t smap;
177
+	size_t size;
178
+	unsigned int flags;
179
+	unsigned int discard_D;
180
+
181
+	/* Inhibit INT 15,e820 during POST */
182
+	if ( memmap_post ) {
183
+		DBG ( "INT 15,e820 not available during POST\n" );
184
+		return -ENOTTY;
185
+	}
186
+
187
+	/* Clear the E820 buffer.  Do this once before starting,
188
+	 * rather than on each call; some BIOSes rely on the contents
189
+	 * being preserved between calls.
190
+	 */
191
+	memset ( &e820buf, 0, sizeof ( e820buf ) );
192
+
193
+	do {
194
+		/* Some BIOSes corrupt %esi for fun. Guard against
195
+		 * this by telling gcc that all non-output registers
196
+		 * may be corrupted.
197
+		 */
198
+		__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t"
199
+						   "stc\n\t"
200
+						   "int $0x15\n\t"
201
+						   "pushfw\n\t"
202
+						   "popw %%dx\n\t"
203
+						   "popl %%ebp\n\t" )
204
+				       : "=a" ( smap ), "=b" ( next ),
205
+					 "=c" ( size ), "=d" ( flags ),
206
+					 "=D" ( discard_D )
207
+				       : "a" ( 0xe820 ), "b" ( next ),
208
+					 "D" ( __from_data16 ( &e820buf ) ),
209
+					 "c" ( sizeof ( e820buf ) ),
210
+					 "d" ( SMAP )
211
+				       : "esi", "memory" );
212
+
213
+		if ( smap != SMAP ) {
214
+			DBG ( "INT 15,e820 failed SMAP signature check\n" );
215
+			return -ENOTSUP;
216
+		}
217
+
218
+		if ( size < E820_MIN_SIZE ) {
219
+			DBG ( "INT 15,e820 returned only %zd bytes\n", size );
220
+			return -EINVAL;
221
+		}
222
+
223
+		if ( flags & CF ) {
224
+			DBG ( "INT 15,e820 terminated on CF set\n" );
225
+			break;
226
+		}
227
+
228
+		/* If first region is not RAM, assume map is invalid */
229
+		if ( ( memmap->count == 0 ) &&
230
+		     ( e820buf.type != E820_TYPE_RAM ) ) {
231
+		       DBG ( "INT 15,e820 failed, first entry not RAM\n" );
232
+		       return -EINVAL;
233
+		}
234
+
235
+		DBG ( "INT 15,e820 region [%llx,%llx) type %d",
236
+		      e820buf.start, ( e820buf.start + e820buf.len ),
237
+		      ( int ) e820buf.type );
238
+		if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
239
+			DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
240
+					? "enabled" : "disabled" ) );
241
+			if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
242
+				DBG ( ", non-volatile" );
243
+			if ( e820buf.attrs & E820_ATTR_UNKNOWN )
244
+				DBG ( ", other [%08x]", e820buf.attrs );
245
+			DBG ( ")" );
246
+		}
247
+		DBG ( "\n" );
248
+
249
+		/* Discard non-RAM regions */
250
+		if ( e820buf.type != E820_TYPE_RAM )
251
+			continue;
252
+
253
+		/* Check extended attributes, if present */
254
+		if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
255
+			if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
256
+				continue;
257
+			if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
258
+				continue;
259
+		}
260
+
261
+		region->start = e820buf.start;
262
+		region->end = e820buf.start + e820buf.len;
263
+
264
+		/* Check for adjacent regions and merge them */
265
+		if ( prev_region && ( region->start == prev_region->end ) ) {
266
+			prev_region->end = region->end;
267
+		} else {
268
+			prev_region = region;
269
+			region++;
270
+			memmap->count++;
271
+		}
272
+
273
+		if ( memmap->count >= ( sizeof ( memmap->regions ) /
274
+					sizeof ( memmap->regions[0] ) ) ) {
275
+			DBG ( "INT 15,e820 too many regions returned\n" );
276
+			/* Not a fatal error; what we've got so far at
277
+			 * least represents valid regions of memory,
278
+			 * even if we couldn't get them all.
279
+			 */
280
+			break;
281
+		}
282
+	} while ( next != 0 );
283
+
284
+	/* Sanity checks.  Some BIOSes report complete garbage via INT
285
+	 * 15,e820 (especially at POST time), despite passing the
286
+	 * signature checks.  We currently check for a base memory
287
+	 * region (starting at 0) and at least one high memory region
288
+	 * (starting at 0x100000).
289
+	 */
290
+	if ( memmap->count < 2 ) {
291
+		DBG ( "INT 15,e820 returned only %d regions; assuming "
292
+		      "insane\n", memmap->count );
293
+		return -EINVAL;
294
+	}
295
+	if ( memmap->regions[0].start != 0 ) {
296
+		DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
297
+		      "assuming insane\n", memmap->regions[0].start );
298
+		return -EINVAL;
299
+	}
300
+	if ( memmap->regions[1].start != 0x100000 ) {
301
+		DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
302
+		      "assuming insane\n", memmap->regions[0].start );
303
+		return -EINVAL;
304
+	}
305
+
306
+	return 0;
307
+}
308
+
309
+/**
310
+ * Get memory map
311
+ *
312
+ * @v memmap		Memory map to fill in
313
+ */
314
+void x86_get_memmap ( struct memory_map *memmap ) {
315
+	unsigned int basemem, extmem;
316
+	int rc;
317
+
318
+	DBG ( "Fetching system memory map\n" );
319
+
320
+	/* Clear memory map */
321
+	memset ( memmap, 0, sizeof ( *memmap ) );
322
+
323
+	/* Get base and extended memory sizes */
324
+	basemem = basememsize();
325
+	DBG ( "FBMS base memory size %d kB [0,%x)\n",
326
+	      basemem, ( basemem * 1024 ) );
327
+	extmem = extmemsize();
328
+	
329
+	/* Try INT 15,e820 first */
330
+	if ( ( rc = meme820 ( memmap ) ) == 0 ) {
331
+		DBG ( "Obtained system memory map via INT 15,e820\n" );
332
+		return;
333
+	}
334
+
335
+	/* Fall back to constructing a map from basemem and extmem sizes */
336
+	DBG ( "INT 15,e820 failed; constructing map\n" );
337
+	memmap->regions[0].end = ( basemem * 1024 );
338
+	memmap->regions[1].start = 0x100000;
339
+	memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
340
+	memmap->count = 2;
341
+}
342
+
343
+PROVIDE_IOAPI ( x86, get_memmap, x86_get_memmap );

+ 114
- 0
src/arch/i386/firmware/pcbios/pnpbios.c View File

@@ -0,0 +1,114 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <string.h>
28
+#include <errno.h>
29
+#include <realmode.h>
30
+#include <pnpbios.h>
31
+
32
+/** @file
33
+ *
34
+ * PnP BIOS
35
+ *
36
+ */
37
+
38
+/** PnP BIOS structure */
39
+struct pnp_bios {
40
+	/** Signature
41
+	 *
42
+	 * Must be equal to @c PNP_BIOS_SIGNATURE
43
+	 */
44
+	uint32_t signature;
45
+	/** Version as BCD (e.g. 1.0 is 0x10) */
46
+	uint8_t version;
47
+	/** Length of this structure */
48
+	uint8_t length;
49
+	/** System capabilities */
50
+	uint16_t control;
51
+	/** Checksum */
52
+	uint8_t checksum;
53
+} __attribute__ (( packed ));
54
+
55
+/** Signature for a PnP BIOS structure */
56
+#define PNP_BIOS_SIGNATURE \
57
+	( ( '$' << 0 ) + ( 'P' << 8 ) + ( 'n' << 16 ) + ( 'P' << 24 ) )
58
+
59
+/**
60
+ * Test address for PnP BIOS structure
61
+ *
62
+ * @v offset		Offset within BIOS segment to test
63
+ * @ret rc		Return status code
64
+ */
65
+static int is_pnp_bios ( unsigned int offset ) {
66
+	union {
67
+		struct pnp_bios pnp_bios;
68
+		uint8_t bytes[256]; /* 256 is maximum length possible */
69
+	} u;
70
+	size_t len;
71
+	unsigned int i;
72
+	uint8_t sum = 0;
73
+
74
+	/* Read start of header and verify signature */
75
+	copy_from_real ( &u.pnp_bios, BIOS_SEG, offset, sizeof ( u.pnp_bios ));
76
+	if ( u.pnp_bios.signature != PNP_BIOS_SIGNATURE )
77
+		return -EINVAL;
78
+
79
+	/* Read whole header and verify checksum */
80
+	len = u.pnp_bios.length;
81
+	copy_from_real ( &u.bytes, BIOS_SEG, offset, len );
82
+	for ( i = 0 ; i < len ; i++ ) {
83
+		sum += u.bytes[i];
84
+	}
85
+	if ( sum != 0 )
86
+		return -EINVAL;
87
+
88
+	DBG ( "Found PnP BIOS at %04x:%04x\n", BIOS_SEG, offset );
89
+
90
+	return 0;
91
+}
92
+
93
+/**
94
+ * Locate Plug-and-Play BIOS
95
+ *
96
+ * @ret pnp_offset	Offset of PnP BIOS structure within BIOS segment
97
+ *
98
+ * The PnP BIOS structure will be at BIOS_SEG:pnp_offset.  If no PnP
99
+ * BIOS is found, -1 is returned.
100
+ */
101
+int find_pnp_bios ( void ) {
102
+	static int pnp_offset = 0;
103
+
104
+	if ( pnp_offset )
105
+		return pnp_offset;
106
+
107
+	for ( pnp_offset = 0 ; pnp_offset < 0x10000 ; pnp_offset += 0x10 ) {
108
+		if ( is_pnp_bios ( pnp_offset ) == 0 )
109
+			return pnp_offset;
110
+	}
111
+
112
+	pnp_offset = -1;
113
+	return pnp_offset;
114
+}

+ 117
- 0
src/arch/i386/hci/commands/pxe_cmd.c View File

@@ -0,0 +1,117 @@
1
+/*
2
+ * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+#include <ipxe/netdevice.h>
25
+#include <ipxe/command.h>
26
+#include <ipxe/parseopt.h>
27
+#include <hci/ifmgmt_cmd.h>
28
+#include <pxe_call.h>
29
+
30
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
31
+
32
+/** @file
33
+ *
34
+ * PXE commands
35
+ *
36
+ */
37
+
38
+/** "startpxe" options */
39
+struct startpxe_options {};
40
+
41
+/** "startpxe" option list */
42
+static struct option_descriptor startpxe_opts[] = {};
43
+
44
+/**
45
+ * "startpxe" payload
46
+ *
47
+ * @v netdev		Network device
48
+ * @v opts		Command options
49
+ * @ret rc		Return status code
50
+ */
51
+static int startpxe_payload ( struct net_device *netdev,
52
+			      struct startpxe_options *opts __unused ) {
53
+
54
+	if ( netdev_is_open ( netdev ) )
55
+		pxe_activate ( netdev );
56
+
57
+	return 0;
58
+}
59
+
60
+/** "startpxe" command descriptor */
61
+static struct ifcommon_command_descriptor startpxe_cmd =
62
+	IFCOMMON_COMMAND_DESC ( struct startpxe_options, startpxe_opts,
63
+				0, MAX_ARGUMENTS, "[<interface>]",
64
+				startpxe_payload, 0 );
65
+
66
+/**
67
+ * The "startpxe" command
68
+ *
69
+ * @v argc		Argument count
70
+ * @v argv		Argument list
71
+ * @ret rc		Return status code
72
+ */
73
+static int startpxe_exec ( int argc, char **argv ) {
74
+	return ifcommon_exec ( argc, argv, &startpxe_cmd );
75
+}
76
+
77
+/** "stoppxe" options */
78
+struct stoppxe_options {};
79
+
80
+/** "stoppxe" option list */
81
+static struct option_descriptor stoppxe_opts[] = {};
82
+
83
+/** "stoppxe" command descriptor */
84
+static struct command_descriptor stoppxe_cmd =
85
+	COMMAND_DESC ( struct stoppxe_options, stoppxe_opts, 0, 0, NULL );
86
+
87
+/**
88
+ * The "stoppxe" command
89
+ *
90
+ * @v argc		Argument count
91
+ * @v argv		Argument list
92
+ * @ret rc		Return status code
93
+ */
94
+static int stoppxe_exec ( int argc __unused, char **argv __unused ) {
95
+	struct stoppxe_options opts;
96
+	int rc;
97
+
98
+	/* Parse options */
99
+	if ( ( rc = parse_options ( argc, argv, &stoppxe_cmd, &opts ) ) != 0 )
100
+		return rc;
101
+
102
+	pxe_deactivate();
103
+
104
+	return 0;
105
+}
106
+
107
+/** PXE commands */
108
+struct command pxe_commands[] __command = {
109
+	{
110
+		.name = "startpxe",
111
+		.exec = startpxe_exec,
112
+	},
113
+	{
114
+		.name = "stoppxe",
115
+		.exec = stoppxe_exec,
116
+	},
117
+};

+ 141
- 0
src/arch/i386/image/bootsector.c View File

@@ -0,0 +1,141 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * x86 bootsector image format
30
+ *
31
+ */
32
+
33
+#include <errno.h>
34
+#include <realmode.h>
35
+#include <biosint.h>
36
+#include <bootsector.h>
37
+#include <ipxe/console.h>
38
+
39
+/** Vector for storing original INT 18 handler
40
+ *
41
+ * We do not chain to this vector, so there is no need to place it in
42
+ * .text16.
43
+ */
44
+static struct segoff int18_vector;
45
+
46
+/** Vector for storing original INT 19 handler
47
+ *
48
+ * We do not chain to this vector, so there is no need to place it in
49
+ * .text16.
50
+ */
51
+static struct segoff int19_vector;
52
+
53
+/** Restart point for INT 18 or 19 */
54
+extern void bootsector_exec_fail ( void );
55
+
56
+/**
57
+ * Jump to preloaded bootsector
58
+ *
59
+ * @v segment		Real-mode segment
60
+ * @v offset		Real-mode offset
61
+ * @v drive		Drive number to pass to boot sector
62
+ * @ret rc		Return status code
63
+ */
64
+int call_bootsector ( unsigned int segment, unsigned int offset,
65
+		      unsigned int drive ) {
66
+	int discard_b, discard_D, discard_d;
67
+
68
+	/* Reset console, since boot sector will probably use it */
69
+	console_reset();
70
+
71
+	DBG ( "Booting from boot sector at %04x:%04x\n", segment, offset );
72
+
73
+	/* Hook INTs 18 and 19 to capture failure paths */
74
+	hook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
75
+			      &int18_vector );
76
+	hook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
77
+			      &int19_vector );
78
+
79
+	/* Boot the loaded sector
80
+	 *
81
+	 * We assume that the boot sector may completely destroy our
82
+	 * real-mode stack, so we preserve everything we need in
83
+	 * static storage.
84
+	 */
85
+	__asm__ __volatile__ ( REAL_CODE ( /* Save return address off-stack */
86
+					   "popw %%cs:saved_retaddr\n\t"
87
+					   /* Save stack pointer */
88
+					   "movw %%ss, %%ax\n\t"
89
+					   "movw %%ax, %%cs:saved_ss\n\t"
90
+					   "movw %%sp, %%cs:saved_sp\n\t"
91
+					   /* Save frame pointer (gcc bug) */
92
+					   "movl %%ebp, %%cs:saved_ebp\n\t"
93
+					   /* Prepare jump to boot sector */
94
+					   "pushw %%bx\n\t"
95
+					   "pushw %%di\n\t"
96
+					   /* Clear all registers */
97
+					   "xorl %%eax, %%eax\n\t"
98
+					   "xorl %%ebx, %%ebx\n\t"
99
+					   "xorl %%ecx, %%ecx\n\t"
100
+					   /* %edx contains drive number */
101
+					   "xorl %%esi, %%esi\n\t"
102
+					   "xorl %%edi, %%edi\n\t"
103
+					   "xorl %%ebp, %%ebp\n\t"
104
+					   "movw %%ax, %%ds\n\t"
105
+					   "movw %%ax, %%es\n\t"
106
+					   "movw %%ax, %%fs\n\t"
107
+					   "movw %%ax, %%gs\n\t"
108
+					   /* Jump to boot sector */
109
+					   "sti\n\t"
110
+					   "lret\n\t"
111
+					   /* Preserved variables */
112
+					   "\nsaved_ebp: .long 0\n\t"
113
+					   "\nsaved_ss: .word 0\n\t"
114
+					   "\nsaved_sp: .word 0\n\t"
115
+					   "\nsaved_retaddr: .word 0\n\t"
116
+					   /* Boot failure return point */
117
+					   "\nbootsector_exec_fail:\n\t"
118
+					   /* Restore frame pointer (gcc bug) */
119
+					   "movl %%cs:saved_ebp, %%ebp\n\t"
120
+					   /* Restore stack pointer */
121
+					   "movw %%cs:saved_ss, %%ax\n\t"
122
+					   "movw %%ax, %%ss\n\t"
123
+					   "movw %%cs:saved_sp, %%sp\n\t"
124
+					   /* Return via saved address */
125
+					   "jmp *%%cs:saved_retaddr\n\t" )
126
+			       : "=b" ( discard_b ), "=D" ( discard_D ),
127
+			         "=d" ( discard_d )
128
+			       : "b" ( segment ), "D" ( offset ),
129
+			         "d" ( drive )
130
+			       : "eax", "ecx", "esi" );
131
+
132
+	DBG ( "Booted disk returned via INT 18 or 19\n" );
133
+
134
+	/* Unhook INTs 18 and 19 */
135
+	unhook_bios_interrupt ( 0x18, ( unsigned int ) bootsector_exec_fail,
136
+				&int18_vector );
137
+	unhook_bios_interrupt ( 0x19, ( unsigned int ) bootsector_exec_fail,
138
+				&int19_vector );
139
+	
140
+	return -ECANCELED;
141
+}

+ 669
- 0
src/arch/i386/image/bzimage.c View File

@@ -0,0 +1,669 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * Linux bzImage image format
30
+ *
31
+ */
32
+
33
+#include <stdint.h>
34
+#include <stdlib.h>
35
+#include <string.h>
36
+#include <errno.h>
37
+#include <assert.h>
38
+#include <realmode.h>
39
+#include <bzimage.h>
40
+#include <initrd.h>
41
+#include <ipxe/uaccess.h>
42
+#include <ipxe/image.h>
43
+#include <ipxe/segment.h>
44
+#include <ipxe/init.h>
45
+#include <ipxe/cpio.h>
46
+#include <ipxe/features.h>
47
+
48
+FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
49
+
50
+/**
51
+ * bzImage context
52
+ */
53
+struct bzimage_context {
54
+	/** Boot protocol version */
55
+	unsigned int version;
56
+	/** Real-mode kernel portion load segment address */
57
+	unsigned int rm_kernel_seg;
58
+	/** Real-mode kernel portion load address */
59
+	userptr_t rm_kernel;
60
+	/** Real-mode kernel portion file size */
61
+	size_t rm_filesz;
62
+	/** Real-mode heap top (offset from rm_kernel) */
63
+	size_t rm_heap;
64
+	/** Command line (offset from rm_kernel) */
65
+	size_t rm_cmdline;
66
+	/** Command line maximum length */
67
+	size_t cmdline_size;
68
+	/** Real-mode kernel portion total memory size */
69
+	size_t rm_memsz;
70
+	/** Non-real-mode kernel portion load address */
71
+	userptr_t pm_kernel;
72
+	/** Non-real-mode kernel portion file and memory size */
73
+	size_t pm_sz;
74
+	/** Video mode */
75
+	unsigned int vid_mode;
76
+	/** Memory limit */
77
+	uint64_t mem_limit;
78
+	/** Initrd address */
79
+	physaddr_t ramdisk_image;
80
+	/** Initrd size */
81
+	physaddr_t ramdisk_size;
82
+
83
+	/** Command line magic block */
84
+	struct bzimage_cmdline cmdline_magic;
85
+	/** bzImage header */
86
+	struct bzimage_header bzhdr;
87
+};
88
+
89
+/**
90
+ * Parse bzImage header
91
+ *
92
+ * @v image		bzImage file
93
+ * @v bzimg		bzImage context
94
+ * @v src		bzImage to parse
95
+ * @ret rc		Return status code
96
+ */
97
+static int bzimage_parse_header ( struct image *image,
98
+				  struct bzimage_context *bzimg,
99
+				  userptr_t src ) {
100
+	unsigned int syssize;
101
+	int is_bzimage;
102
+
103
+	/* Sanity check */
104
+	if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) {
105
+		DBGC ( image, "bzImage %p too short for kernel header\n",
106
+		       image );
107
+		return -ENOEXEC;
108
+	}
109
+
110
+	/* Read in header structures */
111
+	memset ( bzimg, 0, sizeof ( *bzimg ) );
112
+	copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET,
113
+			 sizeof ( bzimg->cmdline_magic ) );
114
+	copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET,
115
+			 sizeof ( bzimg->bzhdr ) );
116
+
117
+	/* Calculate size of real-mode portion */
118
+	bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ?
119
+				 bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 );
120
+	if ( bzimg->rm_filesz > image->len ) {
121
+		DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
122
+		       image, bzimg->rm_filesz );
123
+		return -ENOEXEC;
124
+	}
125
+	bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE;
126
+
127
+	/* Calculate size of protected-mode portion */
128
+	bzimg->pm_sz = ( image->len - bzimg->rm_filesz );
129
+	syssize = ( ( bzimg->pm_sz + 15 ) / 16 );
130
+
131
+	/* Check for signatures and determine version */
132
+	if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) {
133
+		DBGC ( image, "bzImage %p missing 55AA signature\n", image );
134
+		return -ENOEXEC;
135
+	}
136
+	if ( bzimg->bzhdr.header == BZI_SIGNATURE ) {
137
+		/* 2.00+ */
138
+		bzimg->version = bzimg->bzhdr.version;
139
+	} else {
140
+		/* Pre-2.00.  Check that the syssize field is correct,
141
+		 * as a guard against accepting arbitrary binary data,
142
+		 * since the 55AA check is pretty lax.  Note that the
143
+		 * syssize field is unreliable for protocols between
144
+		 * 2.00 and 2.03 inclusive, so we should not always
145
+		 * check this field.
146
+		 */
147
+		bzimg->version = 0x0100;
148
+		if ( bzimg->bzhdr.syssize != syssize ) {
149
+			DBGC ( image, "bzImage %p bad syssize %x (expected "
150
+			       "%x)\n", image, bzimg->bzhdr.syssize, syssize );
151
+			return -ENOEXEC;
152
+		}
153
+	}
154
+
155
+	/* Determine image type */
156
+	is_bzimage = ( ( bzimg->version >= 0x0200 ) ?
157
+		       ( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 );
158
+
159
+	/* Calculate load address of real-mode portion */
160
+	bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 );
161
+	bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 );
162
+
163
+	/* Allow space for the stack and heap */
164
+	bzimg->rm_memsz += BZI_STACK_SIZE;
165
+	bzimg->rm_heap = bzimg->rm_memsz;
166
+
167
+	/* Allow space for the command line */
168
+	bzimg->rm_cmdline = bzimg->rm_memsz;
169
+	bzimg->rm_memsz += BZI_CMDLINE_SIZE;
170
+
171
+	/* Calculate load address of protected-mode portion */
172
+	bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR
173
+					: BZI_LOAD_LOW_ADDR );
174
+
175
+	/* Extract video mode */
176
+	bzimg->vid_mode = bzimg->bzhdr.vid_mode;
177
+
178
+	/* Extract memory limit */
179
+	bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ?
180
+			     bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX );
181
+
182
+	/* Extract command line size */
183
+	bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ?
184
+				bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE );
185
+
186
+	DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx "
187
+	       "cmdlen %zd\n", image, bzimg->version,
188
+	       user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz,
189
+	       user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz,
190
+	       bzimg->cmdline_size );
191
+
192
+	return 0;
193
+}
194
+
195
+/**
196
+ * Update bzImage header in loaded kernel
197
+ *
198
+ * @v image		bzImage file
199
+ * @v bzimg		bzImage context
200
+ * @v dst		bzImage to update
201
+ */
202
+static void bzimage_update_header ( struct image *image,
203
+				    struct bzimage_context *bzimg,
204
+				    userptr_t dst ) {
205
+
206
+	/* Set loader type */
207
+	if ( bzimg->version >= 0x0200 )
208
+		bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_IPXE;
209
+
210
+	/* Set heap end pointer */
211
+	if ( bzimg->version >= 0x0201 ) {
212
+		bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 );
213
+		bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP;
214
+	}
215
+
216
+	/* Set command line */
217
+	if ( bzimg->version >= 0x0202 ) {
218
+		bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel,
219
+							   bzimg->rm_cmdline );
220
+	} else {
221
+		bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
222
+		bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
223
+		if ( bzimg->version >= 0x0200 )
224
+			bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
225
+	}
226
+
227
+	/* Set video mode */
228
+	bzimg->bzhdr.vid_mode = bzimg->vid_mode;
229
+
230
+	/* Set initrd address */
231
+	if ( bzimg->version >= 0x0200 ) {
232
+		bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image;
233
+		bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size;
234
+	}
235
+
236
+	/* Write out header structures */
237
+	copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic,
238
+		       sizeof ( bzimg->cmdline_magic ) );
239
+	copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr,
240
+		       sizeof ( bzimg->bzhdr ) );
241
+
242
+	DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode );
243
+}
244
+
245
+/**
246
+ * Parse kernel command line for bootloader parameters
247
+ *
248
+ * @v image		bzImage file
249
+ * @v bzimg		bzImage context
250
+ * @v cmdline		Kernel command line
251
+ * @ret rc		Return status code
252
+ */
253
+static int bzimage_parse_cmdline ( struct image *image,
254
+				   struct bzimage_context *bzimg,
255
+				   const char *cmdline ) {
256
+	char *vga;
257
+	char *mem;
258
+
259
+	/* Look for "vga=" */
260
+	if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
261
+		vga += 4;
262
+		if ( strcmp ( vga, "normal" ) == 0 ) {
263
+			bzimg->vid_mode = BZI_VID_MODE_NORMAL;
264
+		} else if ( strcmp ( vga, "ext" ) == 0 ) {
265
+			bzimg->vid_mode = BZI_VID_MODE_EXT;
266
+		} else if ( strcmp ( vga, "ask" ) == 0 ) {
267
+			bzimg->vid_mode = BZI_VID_MODE_ASK;
268
+		} else {
269
+			bzimg->vid_mode = strtoul ( vga, &vga, 0 );
270
+			if ( *vga && ( *vga != ' ' ) ) {
271
+				DBGC ( image, "bzImage %p strange \"vga=\""
272
+				       "terminator '%c'\n", image, *vga );
273
+			}
274
+		}
275
+	}
276
+
277
+	/* Look for "mem=" */
278
+	if ( ( mem = strstr ( cmdline, "mem=" ) ) ) {
279
+		mem += 4;
280
+		bzimg->mem_limit = strtoul ( mem, &mem, 0 );
281
+		switch ( *mem ) {
282
+		case 'G':
283
+		case 'g':
284
+			bzimg->mem_limit <<= 10;
285
+		case 'M':
286
+		case 'm':
287
+			bzimg->mem_limit <<= 10;
288
+		case 'K':
289
+		case 'k':
290
+			bzimg->mem_limit <<= 10;
291
+			break;
292
+		case '\0':
293
+		case ' ':
294
+			break;
295
+		default:
296
+			DBGC ( image, "bzImage %p strange \"mem=\" "
297
+			       "terminator '%c'\n", image, *mem );
298
+			break;
299
+		}
300
+		bzimg->mem_limit -= 1;
301
+	}
302
+
303
+	return 0;
304
+}
305
+
306
+/**
307
+ * Set command line
308
+ *
309
+ * @v image		bzImage image
310
+ * @v bzimg		bzImage context
311
+ * @v cmdline		Kernel command line
312
+ */
313
+static void bzimage_set_cmdline ( struct image *image,
314
+				  struct bzimage_context *bzimg,
315
+				  const char *cmdline ) {
316
+	size_t cmdline_len;
317
+
318
+	/* Copy command line down to real-mode portion */
319
+	cmdline_len = ( strlen ( cmdline ) + 1 );
320
+	if ( cmdline_len > bzimg->cmdline_size )
321
+		cmdline_len = bzimg->cmdline_size;
322
+	copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
323
+		       cmdline, cmdline_len );
324
+	DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
325
+}
326
+
327
+/**
328
+ * Parse standalone image command line for cpio parameters
329
+ *
330
+ * @v image		bzImage file
331
+ * @v cpio		CPIO header
332
+ * @v cmdline		Command line
333
+ */
334
+static void bzimage_parse_cpio_cmdline ( struct image *image,
335
+					 struct cpio_header *cpio,
336
+					 const char *cmdline ) {
337
+	char *arg;
338
+	char *end;
339
+	unsigned int mode;
340
+
341
+	/* Look for "mode=" */
342
+	if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
343
+		arg += 5;
344
+		mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
345
+		if ( *end && ( *end != ' ' ) ) {
346
+			DBGC ( image, "bzImage %p strange \"mode=\""
347
+			       "terminator '%c'\n", image, *end );
348
+		}
349
+		cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
350
+	}
351
+}
352
+
353
+/**
354
+ * Align initrd length
355
+ *
356
+ * @v len		Length
357
+ * @ret len		Length rounded up to INITRD_ALIGN
358
+ */
359
+static inline size_t bzimage_align ( size_t len ) {
360
+
361
+	return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) );
362
+}
363
+
364
+/**
365
+ * Load initrd
366
+ *
367
+ * @v image		bzImage image
368
+ * @v initrd		initrd image
369
+ * @v address		Address at which to load, or UNULL
370
+ * @ret len		Length of loaded image, excluding zero-padding
371
+ */
372
+static size_t bzimage_load_initrd ( struct image *image,
373
+				    struct image *initrd,
374
+				    userptr_t address ) {
375
+	char *filename = initrd->cmdline;
376
+	char *cmdline;
377
+	struct cpio_header cpio;
378
+	size_t offset;
379
+	size_t name_len;
380
+	size_t pad_len;
381
+
382
+	/* Do not include kernel image itself as an initrd */
383
+	if ( initrd == image )
384
+		return 0;
385
+
386
+	/* Create cpio header for non-prebuilt images */
387
+	if ( filename && filename[0] ) {
388
+		cmdline = strchr ( filename, ' ' );
389
+		name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
390
+			       : strlen ( filename ) ) + 1 /* NUL */ );
391
+		memset ( &cpio, '0', sizeof ( cpio ) );
392
+		memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
393
+		cpio_set_field ( cpio.c_mode, 0100644 );
394
+		cpio_set_field ( cpio.c_nlink, 1 );
395
+		cpio_set_field ( cpio.c_filesize, initrd->len );
396
+		cpio_set_field ( cpio.c_namesize, name_len );
397
+		if ( cmdline ) {
398
+			bzimage_parse_cpio_cmdline ( image, &cpio,
399
+						     ( cmdline + 1 /* ' ' */ ));
400
+		}
401
+		offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
402
+	} else {
403
+		offset = 0;
404
+		name_len = 0;
405
+	}
406
+
407
+	/* Copy in initrd image body (and cpio header if applicable) */
408
+	if ( address ) {
409
+		memmove_user ( address, offset, initrd->data, 0, initrd->len );
410
+		if ( offset ) {
411
+			memset_user ( address, 0, 0, offset );
412
+			copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
413
+			copy_to_user ( address, sizeof ( cpio ), filename,
414
+				       ( name_len - 1 /* NUL (or space) */ ) );
415
+		}
416
+		DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
417
+		       "%s%s\n", image, initrd, user_to_phys ( address, 0 ),
418
+		       user_to_phys ( address, offset ),
419
+		       user_to_phys ( address, ( offset + initrd->len ) ),
420
+		       ( filename ? " " : "" ), ( filename ? filename : "" ) );
421
+		DBGC2_MD5A ( image, user_to_phys ( address, offset ),
422
+			     user_to_virt ( address, offset ), initrd->len );
423
+	}
424
+	offset += initrd->len;
425
+
426
+	/* Zero-pad to next INITRD_ALIGN boundary */
427
+	pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
428
+	if ( address )
429
+		memset_user ( address, offset, 0, pad_len );
430
+
431
+	return offset;
432
+}
433
+
434
+/**
435
+ * Check that initrds can be loaded
436
+ *
437
+ * @v image		bzImage image
438
+ * @v bzimg		bzImage context
439
+ * @ret rc		Return status code
440
+ */
441
+static int bzimage_check_initrds ( struct image *image,
442
+				   struct bzimage_context *bzimg ) {
443
+	struct image *initrd;
444
+	userptr_t bottom;
445
+	size_t len = 0;
446
+	int rc;
447
+
448
+	/* Calculate total loaded length of initrds */
449
+	for_each_image ( initrd ) {
450
+
451
+		/* Skip kernel */
452
+		if ( initrd == image )
453
+			continue;
454
+
455
+		/* Calculate length */
456
+		len += bzimage_load_initrd ( image, initrd, UNULL );
457
+		len = bzimage_align ( len );
458
+
459
+		DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
460
+		       image, initrd, user_to_phys ( initrd->data, 0 ),
461
+		       user_to_phys ( initrd->data, initrd->len ),
462
+		       ( initrd->cmdline ? " " : "" ),
463
+		       ( initrd->cmdline ? initrd->cmdline : "" ) );
464
+		DBGC2_MD5A ( image, user_to_phys ( initrd->data, 0 ),
465
+			     user_to_virt ( initrd->data, 0 ), initrd->len );
466
+	}
467
+
468
+	/* Calculate lowest usable address */
469
+	bottom = userptr_add ( bzimg->pm_kernel, bzimg->pm_sz );
470
+
471
+	/* Check that total length fits within space available for
472
+	 * reshuffling.  This is a conservative check, since CPIO
473
+	 * headers are not present during reshuffling, but this
474
+	 * doesn't hurt and keeps the code simple.
475
+	 */
476
+	if ( ( rc = initrd_reshuffle_check ( len, bottom ) ) != 0 ) {
477
+		DBGC ( image, "bzImage %p failed reshuffle check: %s\n",
478
+		       image, strerror ( rc ) );
479
+		return rc;
480
+	}
481
+
482
+	/* Check that total length fits within kernel's memory limit */
483
+	if ( user_to_phys ( bottom, len ) > bzimg->mem_limit ) {
484
+		DBGC ( image, "bzImage %p not enough space for initrds\n",
485
+		       image );
486
+		return -ENOBUFS;
487
+	}
488
+
489
+	return 0;
490
+}
491
+
492
+/**
493
+ * Load initrds, if any
494
+ *
495
+ * @v image		bzImage image
496
+ * @v bzimg		bzImage context
497
+ */
498
+static void bzimage_load_initrds ( struct image *image,
499
+				   struct bzimage_context *bzimg ) {
500
+	struct image *initrd;
501
+	struct image *highest = NULL;
502
+	struct image *other;
503
+	userptr_t top;
504
+	userptr_t dest;
505
+	size_t offset;
506
+	size_t len;
507
+
508
+	/* Reshuffle initrds into desired order */
509
+	initrd_reshuffle ( userptr_add ( bzimg->pm_kernel, bzimg->pm_sz ) );
510
+
511
+	/* Find highest initrd */
512
+	for_each_image ( initrd ) {
513
+		if ( ( highest == NULL ) ||
514
+		     ( userptr_sub ( initrd->data, highest->data ) > 0 ) ) {
515
+			highest = initrd;
516
+		}
517
+	}
518
+
519
+	/* Do nothing if there are no initrds */
520
+	if ( ! highest )
521
+		return;
522
+
523
+	/* Find highest usable address */
524
+	top = userptr_add ( highest->data, bzimage_align ( highest->len ) );
525
+	if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
526
+		top = phys_to_user ( bzimg->mem_limit );
527
+	DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
528
+	       image, user_to_phys ( top, 0 ) );
529
+
530
+	/* Load initrds in order */
531
+	for_each_image ( initrd ) {
532
+
533
+		/* Calculate cumulative length of following
534
+		 * initrds (including padding).
535
+		 */
536
+		offset = 0;
537
+		for_each_image ( other ) {
538
+			if ( other == initrd )
539
+				offset = 0;
540
+			offset += bzimage_load_initrd ( image, other, UNULL );
541
+			offset = bzimage_align ( offset );
542
+		}
543
+
544
+		/* Load initrd at this address */
545
+		dest = userptr_add ( top, -offset );
546
+		len = bzimage_load_initrd ( image, initrd, dest );
547
+
548
+		/* Record initrd location */
549
+		if ( ! bzimg->ramdisk_image )
550
+			bzimg->ramdisk_image = user_to_phys ( dest, 0 );
551
+		bzimg->ramdisk_size = ( user_to_phys ( dest, len ) -
552
+					bzimg->ramdisk_image );
553
+	}
554
+	DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n",
555
+	       image, bzimg->ramdisk_image,
556
+	       ( bzimg->ramdisk_image + bzimg->ramdisk_size ) );
557
+}
558
+
559
+/**
560
+ * Execute bzImage image
561
+ *
562
+ * @v image		bzImage image
563
+ * @ret rc		Return status code
564
+ */
565
+static int bzimage_exec ( struct image *image ) {
566
+	struct bzimage_context bzimg;
567
+	const char *cmdline = ( image->cmdline ? image->cmdline : "" );
568
+	int rc;
569
+
570
+	/* Read and parse header from image */
571
+	if ( ( rc = bzimage_parse_header ( image, &bzimg,
572
+					   image->data ) ) != 0 )
573
+		return rc;
574
+
575
+	/* Prepare segments */
576
+	if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
577
+				   bzimg.rm_memsz ) ) != 0 ) {
578
+		DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
579
+		       image, strerror ( rc ) );
580
+		return rc;
581
+	}
582
+	if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
583
+				   bzimg.pm_sz ) ) != 0 ) {
584
+		DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
585
+		       image, strerror ( rc ) );
586
+		return rc;
587
+	}
588
+
589
+	/* Parse command line for bootloader parameters */
590
+	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
591
+		return rc;
592
+
593
+	/* Check that initrds can be loaded */
594
+	if ( ( rc = bzimage_check_initrds ( image, &bzimg ) ) != 0 )
595
+		return rc;
596
+
597
+	/* Remove kernel from image list (without invalidating image pointer) */
598
+	unregister_image ( image_get ( image ) );
599
+
600
+	/* Load segments */
601
+	memcpy_user ( bzimg.rm_kernel, 0, image->data,
602
+		      0, bzimg.rm_filesz );
603
+	memcpy_user ( bzimg.pm_kernel, 0, image->data,
604
+		      bzimg.rm_filesz, bzimg.pm_sz );
605
+
606
+	/* Store command line */
607
+	bzimage_set_cmdline ( image, &bzimg, cmdline );
608
+
609
+	/* Prepare for exiting.  Must do this before loading initrds,
610
+	 * since loading the initrds will corrupt the external heap.
611
+	 */
612
+	shutdown_boot();
613
+
614
+	/* Load any initrds */
615
+	bzimage_load_initrds ( image, &bzimg );
616
+
617
+	/* Update kernel header */
618
+	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
619
+
620
+	DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
621
+	       "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
622
+	       bzimg.rm_kernel_seg, bzimg.rm_heap );
623
+
624
+	/* Jump to the kernel */
625
+	__asm__ __volatile__ ( REAL_CODE ( "movw %w0, %%ds\n\t"
626
+					   "movw %w0, %%es\n\t"
627
+					   "movw %w0, %%fs\n\t"
628
+					   "movw %w0, %%gs\n\t"
629
+					   "movw %w0, %%ss\n\t"
630
+					   "movw %w1, %%sp\n\t"
631
+					   "pushw %w2\n\t"
632
+					   "pushw $0\n\t"
633
+					   "lret\n\t" )
634
+			       : : "r" ( bzimg.rm_kernel_seg ),
635
+			           "r" ( bzimg.rm_heap ),
636
+			           "r" ( bzimg.rm_kernel_seg + 0x20 ) );
637
+
638
+	/* There is no way for the image to return, since we provide
639
+	 * no return address.
640
+	 */
641
+	assert ( 0 );
642
+
643
+	return -ECANCELED; /* -EIMPOSSIBLE */
644
+}
645
+
646
+/**
647
+ * Probe bzImage image
648
+ *
649
+ * @v image		bzImage file
650
+ * @ret rc		Return status code
651
+ */
652
+int bzimage_probe ( struct image *image ) {
653
+	struct bzimage_context bzimg;
654
+	int rc;
655
+
656
+	/* Read and parse header from image */
657
+	if ( ( rc = bzimage_parse_header ( image, &bzimg,
658
+					   image->data ) ) != 0 )
659
+		return rc;
660
+
661
+	return 0;
662
+}
663
+
664
+/** Linux bzImage image type */
665
+struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
666
+	.name = "bzImage",
667
+	.probe = bzimage_probe,
668
+	.exec = bzimage_exec,
669
+};

+ 0
- 0
src/arch/i386/image/com32.c View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save