1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
|
\ Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>
\ Copyright (c) 2011-2015 Devin Teske <dteske@FreeBSD.org>
\ All rights reserved.
\
\ Redistribution and use in source and binary forms, with or without
\ modification, are permitted provided that the following conditions
\ are met:
\ 1. Redistributions of source code must retain the above copyright
\ notice, this list of conditions and the following disclaimer.
\ 2. Redistributions in binary form must reproduce the above copyright
\ notice, this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\
\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
\ SUCH DAMAGE.
\
\ $FreeBSD$
only forth definitions
s" arch-i386" environment? [if] [if]
s" loader_version" environment? [if]
11 < [if]
.( Loader version 1.1+ required) cr
abort
[then]
[else]
.( Could not get loader version!) cr
abort
[then]
[then] [then]
include /boot/forth/support.4th
include /boot/forth/color.4th
include /boot/forth/delay.4th
include /boot/forth/check-password.4th
efi? [if]
include /boot/forth/efi.4th
[then]
only forth definitions
: bootmsg ( -- )
loader_color? dup ( -- bool bool )
if 7 fg 4 bg then
." Booting..."
if me then
cr
;
: try-menu-unset
\ menu-unset may not be present
s" beastie_disable" getenv
dup -1 <> if
s" YES" compare-insensitive 0= if
exit
then
else
drop
then
s" menu-unset"
sfind if
execute
else
drop
then
s" menusets-unset"
sfind if
execute
else
drop
then
;
only forth also support-functions also builtins definitions
\ the boot-args was parsed to individual options while loaded
\ now compose boot-args, so the boot can set kernel arguments
\ note the command line switched for boot command will cause
\ environment variable boot-args to be ignored
\ There are 2 larger strings, acpi-user-options and existing boot-args
\ other switches are 1 byte each, so allocate boot-args+acpi + extra bytes
\ for rest. Be sure to review this, if more options are to be added into
\ environment.
: set-boot-args { | addr len baddr blen aaddr alen -- }
s" boot-args" getenv dup -1 <> if
to blen to baddr
else
drop
then
s" acpi-user-options" getenv dup -1 <> if
to alen to aaddr
else
drop
then
\ allocate temporary space. max is:
\ 8 kernel switches
\ 26 for acpi, so use 40 for safety
blen alen 40 + + allocate abort" out of memory"
to addr
\ boot-addr may have file name before options, copy it to addr
baddr 0<> if
baddr c@ [char] - <> if
baddr blen [char] - strchr ( addr len )
dup 0= if \ no options, copy all
2drop
baddr addr blen move
blen to len
0 to blen
0 to baddr
else ( addr len )
dup blen
swap -
to len ( addr len )
to blen ( addr )
baddr addr len move ( addr )
to baddr \ baddr points now to first option
then
then
then
\ now add kernel switches
len 0<> if
bl addr len + c! len 1+ to len
then
[char] - addr len + c! len 1+ to len
s" boot_single" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] s addr len + c! len 1+ to len
then
else
drop
then
s" boot_verbose" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] v addr len + c! len 1+ to len
then
else
drop
then
s" boot_kmdb" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] k addr len + c! len 1+ to len
then
else
drop
then
s" boot_drop_into_kmdb" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] d addr len + c! len 1+ to len
then
else
drop
then
s" boot_reconfigure" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] r addr len + c! len 1+ to len
then
else
drop
then
s" boot_ask" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] a addr len + c! len 1+ to len
then
else
drop
then
s" boot_noncluster" getenv dup -1 <> if
s" YES" compare-insensitive 0= if
[char] x addr len + c! len 1+ to len
then
else
drop
then
\ now add remining boot args if blen != 0.
\ baddr[0] is '-', if baddr[1] != 'B' append to addr,
\ otherwise add space then copy
blen 0<> if
baddr 1+ c@ [char] B = if
addr len + 1- c@ [char] - = if \ if addr[len -1] == '-'
baddr 1+ to baddr
blen 1- to blen
else
bl addr len + c! len 1+ to len
then
else
baddr 1+ to baddr
blen 1- to blen
then
baddr addr len + blen move
len blen + to len
0 to baddr
0 to blen
then
\ last part - add acpi.
alen 0<> if
addr len + 1- c@ [char] - <> if
bl addr len + c! len 1+ to len
[char] - addr len + c! len 1+ to len
then
s" B acpi-user-options=" dup -rot ( len addr len )
addr len + swap move ( len )
len + to len
aaddr addr len + alen move
len alen + to len
then
\ check for left over '-'
addr len 1- + c@ [char] - = if
len 1- to len
\ but now we may also have left over ' '
len if ( len <> 0 )
addr len 1- + c@ bl = if
len 1- to len
then
then
then
\ if len != 0, set boot-args
len 0<> if
addr len s" boot-args" setenv
then
addr free drop
;
: boot
0= if ( interpreted ) get_arguments then
set-boot-args
\ Unload only if a path was passed. Paths start with /
dup if
>r over r> swap
c@ [char] / = if
0 1 unload drop
else
s" kernelname" getenv? if ( a kernel has been loaded )
try-menu-unset
bootmsg 1 boot exit
then
load_kernel_and_modules
?dup if exit then
try-menu-unset
bootmsg 0 1 boot exit
then
else
s" kernelname" getenv? if ( a kernel has been loaded )
try-menu-unset
bootmsg 1 boot exit
then
load_kernel_and_modules
?dup if exit then
try-menu-unset
bootmsg 0 1 boot exit
then
load_kernel_and_modules
?dup 0= if bootmsg 0 1 boot then
;
\ ***** boot-conf
\
\ Prepares to boot as specified by loaded configuration files.
: boot-conf
0= if ( interpreted ) get_arguments then
0 1 unload drop
load_kernel_and_modules
?dup 0= if 0 1 autoboot then
;
also forth definitions previous
builtin: boot
builtin: boot-conf
only forth definitions also support-functions
\
\ in case the boot-args is set, parse it and extract following options:
\ -a to boot_ask=YES
\ -s to boot_single=YES
\ -v to boot_verbose=YES
\ -k to boot_kmdb=YES
\ -d to boot_drop_into_kmdb=YES
\ -r to boot_reconfigure=YES
\ -x to boot_noncluster=YES
\ -B acpi-user-options=X to acpi-user-options=X
\
\ This is needed so that the menu can manage these options. Unfortunately, this
\ also means that boot-args will override previously set options, but we have no
\ way to control the processing order here. boot-args will be rebuilt at boot.
\
\ NOTE: The best way to address the order is to *not* set any above options
\ in boot-args.
: parse-boot-args { | baddr blen -- }
s" boot-args" getenv dup -1 = if drop exit then
to blen
to baddr
baddr blen
\ loop over all instances of switch blocks, starting with '-'
begin
[char] - strchr
2dup to blen to baddr
dup 0<>
while ( addr len ) \ points to -
\ block for switch B. keep it on top of the stack for case
\ the property list will get empty.
over 1+ c@ [char] B = if
2dup \ save "-B ...." in case options is empty
2 - swap 2 + ( addr len len-2 addr+2 ) \ skip -B
begin \ skip spaces
dup c@ bl =
while
1+ swap 1- swap
repeat
( addr len len' addr' )
\ its 3 cases now: end of string, -switch, or option list
over 0= if \ end of string, remove trailing -B
2drop ( addr len )
swap 0 swap c! \ store 0 at -B
blen swap ( blen len )
- ( rem )
baddr swap ( addr rem )
dup 0= if
s" boot-args" unsetenv
2drop
exit
then
\ trailing space(s)
begin
over ( addr rem addr )
over + 1- ( addr rem addr+rem-1 )
c@ bl =
while
1- swap ( rem-1 addr )
over ( rem-1 addr rem-1 )
over + ( rem-1 addr addr+rem-1 )
0 swap c!
swap
repeat
s" boot-args" setenv
recurse \ restart
exit
then
( addr len len' addr' )
dup c@ [char] - = if \ it is switch. set to boot-args
swap s" boot-args" setenv
2drop
recurse \ restart
exit
then
( addr len len' addr' )
\ its options string "option1,option2,... -..."
\ cut acpi-user-options=xxx and restart the parser
\ or skip to next option block
begin
dup c@ dup 0<> swap bl <> and \ stop if space or 0
while
dup 18 s" acpi-user-options=" compare 0= if \ matched
( addr len len' addr' )
\ addr' points to acpi options, find its end [',' or ' ' or 0 ]
\ set it as acpi-user-options and move remaining to addr'
2dup ( addr len len' addr' len' addr' )
\ skip to next option in list
\ loop to first , or bl or 0
begin
dup c@ [char] , <> >r
dup c@ bl <> >r
dup c@ 0<> r> r> and and
while
1+ swap 1- swap
repeat
( addr len len' addr' len" addr" )
>r >r ( addr len len' addr' R: addr" len" )
over r@ - ( addr len len' addr' proplen R: addr" len" )
dup 5 + ( addr len len' addr' proplen proplen+5 )
allocate abort" out of memory"
0 s" set " strcat ( addr len len' addr' proplen caddr clen )
>r >r 2dup r> r> 2swap strcat ( addr len len' addr' proplen caddr clen )
2dup + 0 swap c! \ terminate with 0
2dup evaluate drop free drop
( addr len len' addr' proplen R: addr" len" )
\ acpi-user-options is set, now move remaining string to its place.
\ addr: -B, addr': acpi... addr": reminder
swap ( addr len len' proplen addr' )
r> r> ( addr len len' proplen addr' len" addr" )
dup c@ [char] , = if
\ skip , and move addr" to addr'
1+ swap 1- ( addr len len' proplen addr' addr" len" )
rot swap 1+ move ( addr len len' proplen )
else \ its bl or 0 ( addr len len' proplen addr' len" addr" )
\ for both bl and 0 we need to copy to addr'-1 to remove
\ comma, then reset boot-args, and recurse will clear -B
\ if there are no properties left.
dup c@ 0= if
2drop ( addr len len' proplen addr' )
1- 0 swap c! ( addr len len' proplen )
else
>r >r ( addr len len' proplen addr' R: addr" len" )
1- swap 1+ swap
r> r> ( addr len len' proplen addr' len" addr" )
rot rot move ( addr len len' proplen )
then
then
2swap 2drop ( len' proplen )
nip ( proplen )
baddr blen rot -
s" boot-args" setenv
recurse
exit
else
( addr len len' addr' )
\ not acpi option, skip to next option in list
\ loop to first , or bl or 0
begin
dup c@ [char] , <> >r
dup c@ bl <> >r
dup c@ 0<> r> r> and and
while
1+ swap 1- swap
repeat
\ if its ',', skip over
dup c@ [char] , = if
1+ swap 1- swap
then
then
repeat
( addr len len' addr' )
\ this block is done, remove addr and len from stack
2swap 2drop swap
then
over c@ [char] - = if ( addr len )
2dup 1- swap 1+ ( addr len len' addr' )
begin \ loop till ' ' or 0
dup c@ dup 0<> swap bl <> and
while
dup c@ [char] s = if
s" set boot_single=YES" evaluate TRUE
else dup c@ [char] v = if
s" set boot_verbose=YES" evaluate TRUE
else dup c@ [char] k = if
s" set boot_kmdb=YES" evaluate TRUE
else dup c@ [char] d = if
s" set boot_drop_into_kmdb=YES" evaluate TRUE
else dup c@ [char] r = if
s" set boot_reconfigure=YES" evaluate TRUE
else dup c@ [char] a = if
s" set boot_ask=YES" evaluate TRUE
else dup c@ [char] x = if
s" set boot_noncluster=YES" evaluate TRUE
then then then then then then then
dup TRUE = if
drop
dup >r ( addr len len' addr' R: addr' )
1+ swap 1- ( addr len addr'+1 len'-1 R: addr' )
r> swap move ( addr len )
2drop baddr blen 1-
\ check if we have space after '-', if so, drop '- '
swap dup 1+ c@ bl = if
2 + swap 2 -
else
swap
then
dup dup 0= swap 1 = or if \ empty or only '-' is left.
2drop
s" boot-args" unsetenv
exit
else
s" boot-args" setenv
then
recurse
exit
then
1+ swap 1- swap
repeat
2swap 2drop
dup c@ 0= if \ end of string
2drop
exit
else
swap
then
then
repeat
2drop
;
\ ***** start
\
\ Initializes support.4th global variables, sets loader_conf_files,
\ processes conf files, and, if any one such file was successfully
\ read to the end, loads kernel and modules.
: start ( -- ) ( throws: abort & user-defined )
s" /boot/defaults/loader.conf" initialize
include_bootenv
include_conf_files
include_transient
\ If the user defined a post-initialize hook, call it now
s" post-initialize" sfind if execute else drop then
parse-boot-args
\ Will *NOT* try to load kernel and modules if no configuration file
\ was successfully loaded!
any_conf_read? if
s" loader_delay" getenv -1 = if
load_xen_throw
load_kernel
load_modules
else
drop
." Loading Kernel and Modules (Ctrl-C to Abort)" cr
s" also support-functions" evaluate
s" set delay_command='load_xen_throw load_kernel load_modules'" evaluate
s" set delay_showdots" evaluate
delay_execute
then
then
;
\ ***** initialize
\
\ Overrides support.4th initialization word with one that does
\ everything start one does, short of loading the kernel and
\ modules. Returns a flag.
: initialize ( -- flag )
s" /boot/defaults/loader.conf" initialize
include_bootenv
include_conf_files
include_transient
\ If the user defined a post-initialize hook, call it now
s" post-initialize" sfind if execute else drop then
parse-boot-args
any_conf_read?
;
\ ***** read-conf
\
\ Read a configuration file, whose name was specified on the command
\ line, if interpreted, or given on the stack, if compiled in.
: (read-conf) ( addr len -- )
conf_files string=
include_conf_files \ Will recurse on new loader_conf_files definitions
;
: read-conf ( <filename> | addr len -- ) ( throws: abort & user-defined )
state @ if
\ Compiling
postpone (read-conf)
else
\ Interpreting
bl parse (read-conf)
then
; immediate
\ show, enable, disable, toggle module loading. They all take module from
\ the next word
: set-module-flag ( module_addr val -- ) \ set and print flag
over module.flag !
dup module.name strtype
module.flag @ if ." will be loaded" else ." will not be loaded" then cr
;
: enable-module find-module ?dup if true set-module-flag then ;
: disable-module find-module ?dup if false set-module-flag then ;
: toggle-module find-module ?dup if dup module.flag @ 0= set-module-flag then ;
\ ***** show-module
\
\ Show loading information about a module.
: show-module ( <module> -- ) find-module ?dup if show-one-module then ;
: set-module-path ( addr len <module> -- )
find-module ?dup if
module.loadname string=
then
;
\ Words to be used inside configuration files
: retry false ; \ For use in load error commands
: ignore true ; \ For use in load error commands
\ Return to strict forth vocabulary
: #type
over - >r
type
r> spaces
;
: .? 2 spaces 2swap 15 #type 2 spaces type cr ;
: ?
['] ? execute
s" boot-conf" s" load kernel and modules, then autoboot" .?
s" read-conf" s" read a configuration file" .?
s" enable-module" s" enable loading of a module" .?
s" disable-module" s" disable loading of a module" .?
s" toggle-module" s" toggle loading of a module" .?
s" show-module" s" show module load data" .?
s" try-include" s" try to load/interpret files" .?
s" beadm" s" list or activate Boot Environments" .?
;
: try-include ( -- ) \ see loader.4th(8)
['] include ( -- xt ) \ get the execution token of `include'
catch ( xt -- exception# | 0 ) if \ failed
LF parse ( c -- s-addr/u ) 2drop \ advance >in to EOL (drop data)
\ ... prevents words unused by `include' from being interpreted
then
; immediate \ interpret immediately for access to `source' (aka tib)
include /boot/forth/beadm.4th
only forth definitions
|