1\ Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org> 2\ All rights reserved. 3\ 4\ Redistribution and use in source and binary forms, with or without 5\ modification, are permitted provided that the following conditions 6\ are met: 7\ 1. Redistributions of source code must retain the above copyright 8\ notice, this list of conditions and the following disclaimer. 9\ 2. Redistributions in binary form must reproduce the above copyright 10\ notice, this list of conditions and the following disclaimer in the 11\ documentation and/or other materials provided with the distribution. 12\ 13\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23\ SUCH DAMAGE. 24\ 25\ $FreeBSD$ 26 27\ Loader.rc support functions: 28\ 29\ initialize ( addr len -- ) as above, plus load_conf_files 30\ load_conf ( addr len -- ) load conf file given 31\ include_conf_files ( -- ) load all conf files in load_conf_files 32\ print_syntax_error ( -- ) print line and marker of where a syntax 33\ error was detected 34\ print_line ( -- ) print last line processed 35\ load_kernel ( -- ) load kernel 36\ load_modules ( -- ) load modules flagged 37\ 38\ Exported structures: 39\ 40\ string counted string structure 41\ cell .addr string address 42\ cell .len string length 43\ module module loading information structure 44\ cell module.flag should we load it? 45\ string module.name module's name 46\ string module.loadname name to be used in loading the module 47\ string module.type module's type 48\ string module.args flags to be passed during load 49\ string module.beforeload command to be executed before load 50\ string module.afterload command to be executed after load 51\ string module.loaderror command to be executed if load fails 52\ cell module.next list chain 53\ 54\ Exported global variables; 55\ 56\ string conf_files configuration files to be loaded 57\ cell modules_options pointer to first module information 58\ value verbose? indicates if user wants a verbose loading 59\ value any_conf_read? indicates if a conf file was successfully read 60\ 61\ Other exported words: 62\ note, strlen is internal 63\ strdup ( addr len -- addr' len) similar to strdup(3) 64\ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3) 65\ s' ( | string' -- addr len | ) similar to s" 66\ rudimentary structure support 67 68\ Exception values 69 701 constant ESYNTAX 712 constant ENOMEM 723 constant EFREE 734 constant ESETERROR \ error setting environment variable 745 constant EREAD \ error reading 756 constant EOPEN 767 constant EEXEC \ XXX never catched 778 constant EBEFORELOAD 789 constant EAFTERLOAD 79 80\ I/O constants 81 820 constant SEEK_SET 831 constant SEEK_CUR 842 constant SEEK_END 85 860 constant O_RDONLY 871 constant O_WRONLY 882 constant O_RDWR 89 90\ Crude structure support 91 92: structure: 93 create here 0 , ['] drop , 0 94 does> create here swap dup @ allot cell+ @ execute 95; 96: member: create dup , over , + does> cell+ @ + ; 97: ;structure swap ! ; 98: constructor! >body cell+ ! ; 99: constructor: over :noname ; 100: ;constructor postpone ; swap cell+ ! ; immediate 101: sizeof ' >body @ state @ if postpone literal then ; immediate 102: offsetof ' >body cell+ @ state @ if postpone literal then ; immediate 103: ptr 1 cells member: ; 104: int 1 cells member: ; 105 106\ String structure 107 108structure: string 109 ptr .addr 110 int .len 111 constructor: 112 0 over .addr ! 113 0 swap .len ! 114 ;constructor 115;structure 116 117 118\ Module options linked list 119 120structure: module 121 int module.flag 122 sizeof string member: module.name 123 sizeof string member: module.loadname 124 sizeof string member: module.type 125 sizeof string member: module.args 126 sizeof string member: module.beforeload 127 sizeof string member: module.afterload 128 sizeof string member: module.loaderror 129 ptr module.next 130;structure 131 132\ Internal loader structures (preloaded_file, kernel_module, file_metadata) 133\ must be in sync with the C struct in stand/common/bootstrap.h 134structure: preloaded_file 135 ptr pf.name 136 ptr pf.type 137 ptr pf.args 138 ptr pf.metadata \ file_metadata 139 int pf.loader 140 int pf.addr 141 int pf.size 142 ptr pf.modules \ kernel_module 143 ptr pf.next \ preloaded_file 144;structure 145 146structure: kernel_module 147 ptr km.name 148 \ ptr km.args 149 ptr km.fp \ preloaded_file 150 ptr km.next \ kernel_module 151;structure 152 153structure: file_metadata 154 int md.size 155 2 member: md.type \ this is not ANS Forth compatible (XXX) 156 ptr md.next \ file_metadata 157 0 member: md.data \ variable size 158;structure 159 160\ end of structures 161 162\ Global variables 163 164string conf_files 165string nextboot_conf_file 166create module_options sizeof module.next allot 0 module_options ! 167create last_module_option sizeof module.next allot 0 last_module_option ! 1680 value verbose? 1690 value nextboot? 170 171\ Support string functions 172: strdup { addr len -- addr' len' } 173 len allocate if ENOMEM throw then 174 addr over len move len 175; 176 177: strcat { addr len addr' len' -- addr len+len' } 178 addr' addr len + len' move 179 addr len len' + 180; 181 182: strchr { addr len c -- addr' len' } 183 begin 184 len 185 while 186 addr c@ c = if addr len exit then 187 addr 1 + to addr 188 len 1 - to len 189 repeat 190 0 0 191; 192 193: s' \ same as s", allows " in the string 194 [char] ' parse 195 state @ if postpone sliteral then 196; immediate 197 198: 2>r postpone >r postpone >r ; immediate 199: 2r> postpone r> postpone r> ; immediate 200: 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate 201 202: getenv? getenv -1 = if false else drop true then ; 203 204\ determine if a word appears in a string, case-insensitive 205: contains? ( addr1 len1 addr2 len2 -- 0 | -1 ) 206 2 pick 0= if 2drop 2drop true exit then 207 dup 0= if 2drop 2drop false exit then 208 begin 209 begin 210 swap dup c@ dup 32 = over 9 = or over 10 = or 211 over 13 = or over 44 = or swap drop 212 while 1+ swap 1- repeat 213 swap 2 pick 1- over < 214 while 215 2over 2over drop over compare-insensitive 0= if 216 2 pick over = if 2drop 2drop true exit then 217 2 pick tuck - -rot + swap over c@ dup 32 = 218 over 9 = or over 10 = or over 13 = or over 44 = or 219 swap drop if 2drop 2drop true exit then 220 then begin 221 swap dup c@ dup 32 = over 9 = or over 10 = or 222 over 13 = or over 44 = or swap drop 223 if false else true then 2 pick 0> and 224 while 1+ swap 1- repeat 225 swap 226 repeat 227 2drop 2drop false 228; 229 230: boot_serial? ( -- 0 | -1 ) 231 s" console" getenv dup -1 <> if 232 s" comconsole" 2swap contains? 233 else drop false then 234 s" boot_serial" getenv dup -1 <> if 235 swap drop 0> 236 else drop false then 237 or \ console contains comconsole ( or ) boot_serial 238 s" boot_multicons" getenv dup -1 <> if 239 swap drop 0> 240 else drop false then 241 or \ previous boolean ( or ) boot_multicons 242; 243 244\ Private definitions 245 246vocabulary support-functions 247only forth also support-functions definitions 248 249\ Some control characters constants 250 2517 constant bell 2528 constant backspace 2539 constant tab 25410 constant lf 25513 constant <cr> 256 257\ Read buffer size 258 25980 constant read_buffer_size 260 261\ Standard suffixes 262 263: load_module_suffix s" _load" ; 264: module_loadname_suffix s" _name" ; 265: module_type_suffix s" _type" ; 266: module_args_suffix s" _flags" ; 267: module_beforeload_suffix s" _before" ; 268: module_afterload_suffix s" _after" ; 269: module_loaderror_suffix s" _error" ; 270 271\ Support operators 272 273: >= < 0= ; 274: <= > 0= ; 275 276\ Assorted support functions 277 278: free-memory free if EFREE throw then ; 279 280: strget { var -- addr len } var .addr @ var .len @ ; 281 282\ assign addr len to variable. 283: strset { addr len var -- } addr var .addr ! len var .len ! ; 284 285\ free memory and reset fields 286: strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ; 287 288\ free old content, make a copy of the string and assign to variable 289: string= { addr len var -- } var strfree addr len strdup var strset ; 290 291: strtype ( str -- ) strget type ; 292 293\ assign a reference to what is on the stack 294: strref { addr len var -- addr len } 295 addr var .addr ! len var .len ! addr len 296; 297 298\ unquote a string 299: unquote ( addr len -- addr len ) 300 over c@ [char] " = if 2 chars - swap char+ swap then 301; 302 303\ Assignment data temporary storage 304 305string name_buffer 306string value_buffer 307 308\ Line by line file reading functions 309\ 310\ exported: 311\ line_buffer 312\ end_of_file? 313\ fd 314\ read_line 315\ reset_line_reading 316 317vocabulary line-reading 318also line-reading definitions 319 320\ File data temporary storage 321 322string read_buffer 3230 value read_buffer_ptr 324 325\ File's line reading function 326 327get-current ( -- wid ) previous definitions 328 329string line_buffer 3300 value end_of_file? 331variable fd 332 333>search ( wid -- ) definitions 334 335: skip_newlines 336 begin 337 read_buffer .len @ read_buffer_ptr > 338 while 339 read_buffer .addr @ read_buffer_ptr + c@ lf = if 340 read_buffer_ptr char+ to read_buffer_ptr 341 else 342 exit 343 then 344 repeat 345; 346 347: scan_buffer ( -- addr len ) 348 read_buffer_ptr >r 349 begin 350 read_buffer .len @ r@ > 351 while 352 read_buffer .addr @ r@ + c@ lf = if 353 read_buffer .addr @ read_buffer_ptr + ( -- addr ) 354 r@ read_buffer_ptr - ( -- len ) 355 r> to read_buffer_ptr 356 exit 357 then 358 r> char+ >r 359 repeat 360 read_buffer .addr @ read_buffer_ptr + ( -- addr ) 361 r@ read_buffer_ptr - ( -- len ) 362 r> to read_buffer_ptr 363; 364 365: line_buffer_resize ( len -- len ) 366 dup 0= if exit then 367 >r 368 line_buffer .len @ if 369 line_buffer .addr @ 370 line_buffer .len @ r@ + 371 resize if ENOMEM throw then 372 else 373 r@ allocate if ENOMEM throw then 374 then 375 line_buffer .addr ! 376 r> 377; 378 379: append_to_line_buffer ( addr len -- ) 380 dup 0= if 2drop exit then 381 line_buffer strget 382 2swap strcat 383 line_buffer .len ! 384 drop 385; 386 387: read_from_buffer 388 scan_buffer ( -- addr len ) 389 line_buffer_resize ( len -- len ) 390 append_to_line_buffer ( addr len -- ) 391; 392 393: refill_required? 394 read_buffer .len @ read_buffer_ptr = 395 end_of_file? 0= and 396; 397 398: refill_buffer 399 0 to read_buffer_ptr 400 read_buffer .addr @ 0= if 401 read_buffer_size allocate if ENOMEM throw then 402 read_buffer .addr ! 403 then 404 fd @ read_buffer .addr @ read_buffer_size fread 405 dup -1 = if EREAD throw then 406 dup 0= if true to end_of_file? then 407 read_buffer .len ! 408; 409 410get-current ( -- wid ) previous definitions >search ( wid -- ) 411 412: reset_line_reading 413 0 to read_buffer_ptr 414; 415 416: read_line 417 line_buffer strfree 418 skip_newlines 419 begin 420 read_from_buffer 421 refill_required? 422 while 423 refill_buffer 424 repeat 425; 426 427only forth also support-functions definitions 428 429\ Conf file line parser: 430\ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] | 431\ <spaces>[<comment>] 432\ <name> ::= <letter>{<letter>|<digit>|'_'} 433\ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name> 434\ <character_set> ::= ASCII 32 to 126, except '\' and '"' 435\ <comment> ::= '#'{<anything>} 436\ 437\ exported: 438\ line_pointer 439\ process_conf 440 4410 value line_pointer 442 443vocabulary file-processing 444also file-processing definitions 445 446\ parser functions 447\ 448\ exported: 449\ get_assignment 450 451vocabulary parser 452also parser definitions 453 4540 value parsing_function 4550 value end_of_line 456 457: end_of_line? line_pointer end_of_line = ; 458 459\ classifiers for various character classes in the input line 460 461: letter? 462 line_pointer c@ >r 463 r@ [char] A >= 464 r@ [char] Z <= and 465 r@ [char] a >= 466 r> [char] z <= and 467 or 468; 469 470: digit? 471 line_pointer c@ >r 472 r@ [char] - = 473 r@ [char] 0 >= 474 r> [char] 9 <= and 475 or 476; 477 478: quote? line_pointer c@ [char] " = ; 479 480: assignment_sign? line_pointer c@ [char] = = ; 481 482: comment? line_pointer c@ [char] # = ; 483 484: space? line_pointer c@ bl = line_pointer c@ tab = or ; 485 486: backslash? line_pointer c@ [char] \ = ; 487 488: underscore? line_pointer c@ [char] _ = ; 489 490: dot? line_pointer c@ [char] . = ; 491 492\ manipulation of input line 493: skip_character line_pointer char+ to line_pointer ; 494 495: skip_to_end_of_line end_of_line to line_pointer ; 496 497: eat_space 498 begin 499 end_of_line? if 0 else space? then 500 while 501 skip_character 502 repeat 503; 504 505: parse_name ( -- addr len ) 506 line_pointer 507 begin 508 end_of_line? if 0 else letter? digit? underscore? dot? or or or then 509 while 510 skip_character 511 repeat 512 line_pointer over - 513 strdup 514; 515 516: remove_backslashes { addr len | addr' len' -- addr' len' } 517 len allocate if ENOMEM throw then 518 to addr' 519 addr >r 520 begin 521 addr c@ [char] \ <> if 522 addr c@ addr' len' + c! 523 len' char+ to len' 524 then 525 addr char+ to addr 526 r@ len + addr = 527 until 528 r> drop 529 addr' len' 530; 531 532: parse_quote ( -- addr len ) 533 line_pointer 534 skip_character 535 end_of_line? if ESYNTAX throw then 536 begin 537 quote? 0= 538 while 539 backslash? if 540 skip_character 541 end_of_line? if ESYNTAX throw then 542 then 543 skip_character 544 end_of_line? if ESYNTAX throw then 545 repeat 546 skip_character 547 line_pointer over - 548 remove_backslashes 549; 550 551: read_name 552 parse_name ( -- addr len ) 553 name_buffer strset 554; 555 556: read_value 557 quote? if 558 parse_quote ( -- addr len ) 559 else 560 parse_name ( -- addr len ) 561 then 562 value_buffer strset 563; 564 565: comment 566 skip_to_end_of_line 567; 568 569: white_space_4 570 eat_space 571 comment? if ['] comment to parsing_function exit then 572 end_of_line? 0= if ESYNTAX throw then 573; 574 575: variable_value 576 read_value 577 ['] white_space_4 to parsing_function 578; 579 580: white_space_3 581 eat_space 582 letter? digit? quote? or or if 583 ['] variable_value to parsing_function exit 584 then 585 ESYNTAX throw 586; 587 588: assignment_sign 589 skip_character 590 ['] white_space_3 to parsing_function 591; 592 593: white_space_2 594 eat_space 595 assignment_sign? if ['] assignment_sign to parsing_function exit then 596 ESYNTAX throw 597; 598 599: variable_name 600 read_name 601 ['] white_space_2 to parsing_function 602; 603 604: white_space_1 605 eat_space 606 letter? if ['] variable_name to parsing_function exit then 607 comment? if ['] comment to parsing_function exit then 608 end_of_line? 0= if ESYNTAX throw then 609; 610 611get-current ( -- wid ) previous definitions >search ( wid -- ) 612 613: get_assignment 614 line_buffer strget + to end_of_line 615 line_buffer .addr @ to line_pointer 616 ['] white_space_1 to parsing_function 617 begin 618 end_of_line? 0= 619 while 620 parsing_function execute 621 repeat 622 parsing_function ['] comment = 623 parsing_function ['] white_space_1 = 624 parsing_function ['] white_space_4 = 625 or or 0= if ESYNTAX throw then 626; 627 628only forth also support-functions also file-processing definitions 629 630\ Process line 631 632: assignment_type? ( addr len -- flag ) 633 name_buffer strget 634 compare 0= 635; 636 637: suffix_type? ( addr len -- flag ) 638 name_buffer .len @ over <= if 2drop false exit then 639 name_buffer .len @ over - name_buffer .addr @ + 640 over compare 0= 641; 642 643: loader_conf_files? s" loader_conf_files" assignment_type? ; 644 645: nextboot_flag? s" nextboot_enable" assignment_type? ; 646 647: nextboot_conf? s" nextboot_conf" assignment_type? ; 648 649: verbose_flag? s" verbose_loading" assignment_type? ; 650 651: execute? s" exec" assignment_type? ; 652 653: module_load? load_module_suffix suffix_type? ; 654 655: module_loadname? module_loadname_suffix suffix_type? ; 656 657: module_type? module_type_suffix suffix_type? ; 658 659: module_args? module_args_suffix suffix_type? ; 660 661: module_beforeload? module_beforeload_suffix suffix_type? ; 662 663: module_afterload? module_afterload_suffix suffix_type? ; 664 665: module_loaderror? module_loaderror_suffix suffix_type? ; 666 667\ build a 'set' statement and execute it 668: set_environment_variable 669 name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string 670 allocate if ENOMEM throw then 671 dup 0 \ start with an empty string and append the pieces 672 s" set " strcat 673 name_buffer strget strcat 674 s" =" strcat 675 value_buffer strget strcat 676 ['] evaluate catch if 677 2drop free drop 678 ESETERROR throw 679 else 680 free-memory 681 then 682; 683 684: set_conf_files 685 set_environment_variable 686 s" loader_conf_files" getenv conf_files string= 687; 688 689: set_nextboot_conf 690 value_buffer strget unquote nextboot_conf_file string= 691; 692 693: append_to_module_options_list ( addr -- ) 694 module_options @ 0= if 695 dup module_options ! 696 last_module_option ! 697 else 698 dup last_module_option @ module.next ! 699 last_module_option ! 700 then 701; 702 703: set_module_name { addr -- } \ check leaks 704 name_buffer strget addr module.name string= 705; 706 707: yes_value? 708 value_buffer strget \ XXX could use unquote 709 2dup s' "YES"' compare >r 710 2dup s' "yes"' compare >r 711 2dup s" YES" compare >r 712 s" yes" compare r> r> r> and and and 0= 713; 714 715: find_module_option ( -- addr | 0 ) \ return ptr to entry matching name_buffer 716 module_options @ 717 begin 718 dup 719 while 720 dup module.name strget 721 name_buffer strget 722 compare 0= if exit then 723 module.next @ 724 repeat 725; 726 727: new_module_option ( -- addr ) 728 sizeof module allocate if ENOMEM throw then 729 dup sizeof module erase 730 dup append_to_module_options_list 731 dup set_module_name 732; 733 734: get_module_option ( -- addr ) 735 find_module_option 736 ?dup 0= if new_module_option then 737; 738 739: set_module_flag 740 name_buffer .len @ load_module_suffix nip - name_buffer .len ! 741 yes_value? get_module_option module.flag ! 742; 743 744: set_module_args 745 name_buffer .len @ module_args_suffix nip - name_buffer .len ! 746 value_buffer strget unquote 747 get_module_option module.args string= 748; 749 750: set_module_loadname 751 name_buffer .len @ module_loadname_suffix nip - name_buffer .len ! 752 value_buffer strget unquote 753 get_module_option module.loadname string= 754; 755 756: set_module_type 757 name_buffer .len @ module_type_suffix nip - name_buffer .len ! 758 value_buffer strget unquote 759 get_module_option module.type string= 760; 761 762: set_module_beforeload 763 name_buffer .len @ module_beforeload_suffix nip - name_buffer .len ! 764 value_buffer strget unquote 765 get_module_option module.beforeload string= 766; 767 768: set_module_afterload 769 name_buffer .len @ module_afterload_suffix nip - name_buffer .len ! 770 value_buffer strget unquote 771 get_module_option module.afterload string= 772; 773 774: set_module_loaderror 775 name_buffer .len @ module_loaderror_suffix nip - name_buffer .len ! 776 value_buffer strget unquote 777 get_module_option module.loaderror string= 778; 779 780: set_nextboot_flag 781 yes_value? to nextboot? 782; 783 784: set_verbose 785 yes_value? to verbose? 786; 787 788: execute_command 789 value_buffer strget unquote 790 ['] evaluate catch if EEXEC throw then 791; 792 793: process_assignment 794 name_buffer .len @ 0= if exit then 795 loader_conf_files? if set_conf_files exit then 796 nextboot_flag? if set_nextboot_flag exit then 797 nextboot_conf? if set_nextboot_conf exit then 798 verbose_flag? if set_verbose exit then 799 execute? if execute_command exit then 800 module_load? if set_module_flag exit then 801 module_loadname? if set_module_loadname exit then 802 module_type? if set_module_type exit then 803 module_args? if set_module_args exit then 804 module_beforeload? if set_module_beforeload exit then 805 module_afterload? if set_module_afterload exit then 806 module_loaderror? if set_module_loaderror exit then 807 set_environment_variable 808; 809 810\ free_buffer ( -- ) 811\ 812\ Free some pointers if needed. The code then tests for errors 813\ in freeing, and throws an exception if needed. If a pointer is 814\ not allocated, it's value (0) is used as flag. 815 816: free_buffers 817 name_buffer strfree 818 value_buffer strfree 819; 820 821\ Higher level file processing 822 823get-current ( -- wid ) previous definitions >search ( wid -- ) 824 825: process_conf 826 begin 827 end_of_file? 0= 828 while 829 free_buffers 830 read_line 831 get_assignment 832 ['] process_assignment catch 833 ['] free_buffers catch 834 swap throw throw 835 repeat 836; 837 838: peek_file ( addr len -- ) 839 0 to end_of_file? 840 reset_line_reading 841 O_RDONLY fopen fd ! 842 fd @ -1 = if EOPEN throw then 843 free_buffers 844 read_line 845 get_assignment 846 ['] process_assignment catch 847 ['] free_buffers catch 848 fd @ fclose 849 swap throw throw 850; 851 852only forth also support-functions definitions 853 854\ Interface to loading conf files 855 856: load_conf ( addr len -- ) 857 0 to end_of_file? 858 reset_line_reading 859 O_RDONLY fopen fd ! 860 fd @ -1 = if EOPEN throw then 861 ['] process_conf catch 862 fd @ fclose 863 throw 864; 865 866: print_line line_buffer strtype cr ; 867 868: print_syntax_error 869 line_buffer strtype cr 870 line_buffer .addr @ 871 begin 872 line_pointer over <> 873 while 874 bl emit char+ 875 repeat 876 drop 877 ." ^" cr 878; 879 880 881\ Debugging support functions 882 883only forth definitions also support-functions 884 885: test-file 886 ['] load_conf catch dup . 887 ESYNTAX = if cr print_syntax_error then 888; 889 890\ find a module name, leave addr on the stack (0 if not found) 891: find-module ( <module> -- ptr | 0 ) 892 bl parse ( addr len ) 893 module_options @ >r ( store current pointer ) 894 begin 895 r@ 896 while 897 2dup ( addr len addr len ) 898 r@ module.name strget 899 compare 0= if drop drop r> exit then ( found it ) 900 r> module.next @ >r 901 repeat 902 type ." was not found" cr r> 903; 904 905: show-nonempty ( addr len mod -- ) 906 strget dup verbose? or if 907 2swap type type cr 908 else 909 drop drop drop drop 910 then ; 911 912: show-one-module { addr -- addr } 913 ." Name: " addr module.name strtype cr 914 s" Path: " addr module.loadname show-nonempty 915 s" Type: " addr module.type show-nonempty 916 s" Flags: " addr module.args show-nonempty 917 s" Before load: " addr module.beforeload show-nonempty 918 s" After load: " addr module.afterload show-nonempty 919 s" Error: " addr module.loaderror show-nonempty 920 ." Status: " addr module.flag @ if ." Load" else ." Don't load" then cr 921 cr 922 addr 923; 924 925: show-module-options 926 module_options @ 927 begin 928 ?dup 929 while 930 show-one-module 931 module.next @ 932 repeat 933; 934 935: free-one-module { addr -- addr } 936 addr module.name strfree 937 addr module.loadname strfree 938 addr module.type strfree 939 addr module.args strfree 940 addr module.beforeload strfree 941 addr module.afterload strfree 942 addr module.loaderror strfree 943 addr 944; 945 946: free-module-options 947 module_options @ 948 begin 949 ?dup 950 while 951 free-one-module 952 dup module.next @ 953 swap free-memory 954 repeat 955 0 module_options ! 956 0 last_module_option ! 957; 958 959only forth also support-functions definitions 960 961\ Variables used for processing multiple conf files 962 963string current_file_name_ref \ used to print the file name 964 965\ Indicates if any conf file was successfully read 966 9670 value any_conf_read? 968 969\ loader_conf_files processing support functions 970 971: get_conf_files ( -- addr len ) \ put addr/len on stack, reset var 972 conf_files strget 0 0 conf_files strset 973; 974 975: skip_leading_spaces { addr len pos -- addr len pos' } 976 begin 977 pos len = if 0 else addr pos + c@ bl = then 978 while 979 pos char+ to pos 980 repeat 981 addr len pos 982; 983 984\ return the file name at pos, or free the string if nothing left 985: get_file_name { addr len pos -- addr len pos' addr' len' || 0 } 986 pos len = if 987 addr free abort" Fatal error freeing memory" 988 0 exit 989 then 990 pos >r 991 begin 992 \ stay in the loop until have chars and they are not blank 993 pos len = if 0 else addr pos + c@ bl <> then 994 while 995 pos char+ to pos 996 repeat 997 addr len pos addr r@ + pos r> - 998; 999 1000: get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 ) 1001 skip_leading_spaces 1002 get_file_name 1003; 1004 1005: print_current_file 1006 current_file_name_ref strtype 1007; 1008 1009: process_conf_errors 1010 dup 0= if true to any_conf_read? drop exit then 1011 >r 2drop r> 1012 dup ESYNTAX = if 1013 ." Warning: syntax error on file " print_current_file cr 1014 print_syntax_error drop exit 1015 then 1016 dup ESETERROR = if 1017 ." Warning: bad definition on file " print_current_file cr 1018 print_line drop exit 1019 then 1020 dup EREAD = if 1021 ." Warning: error reading file " print_current_file cr drop exit 1022 then 1023 dup EOPEN = if 1024 verbose? if ." Warning: unable to open file " print_current_file cr then 1025 drop exit 1026 then 1027 dup EFREE = abort" Fatal error freeing memory" 1028 dup ENOMEM = abort" Out of memory" 1029 throw \ Unknown error -- pass ahead 1030; 1031 1032\ Process loader_conf_files recursively 1033\ Interface to loader_conf_files processing 1034 1035: include_conf_files 1036 get_conf_files 0 ( addr len offset ) 1037 begin 1038 get_next_file ?dup ( addr len 1 | 0 ) 1039 while 1040 current_file_name_ref strref 1041 ['] load_conf catch 1042 process_conf_errors 1043 conf_files .addr @ if recurse then 1044 repeat 1045; 1046 1047: get_nextboot_conf_file ( -- addr len ) 1048 nextboot_conf_file strget 1049; 1050 1051: rewrite_nextboot_file ( -- ) 1052 get_nextboot_conf_file 1053 O_WRONLY fopen fd ! 1054 fd @ -1 = if EOPEN throw then 1055 fd @ s' nextboot_enable="NO" ' fwrite ( fd buf len -- nwritten ) drop 1056 fd @ fclose 1057; 1058 1059: include_nextboot_file ( -- ) 1060 s" nextboot_enable" getenv dup -1 <> if 1061 2dup s' "YES"' compare >r 1062 2dup s' "yes"' compare >r 1063 2dup s" YES" compare >r 1064 2dup s" yes" compare r> r> r> and and and 0= to nextboot? 1065 else 1066 drop 1067 get_nextboot_conf_file 1068 ['] peek_file catch if 2drop then 1069 then 1070 nextboot? if 1071 get_nextboot_conf_file 1072 current_file_name_ref strref 1073 ['] load_conf catch 1074 process_conf_errors 1075 ['] rewrite_nextboot_file catch if 2drop then 1076 then 1077 s' "NO"' s" nextboot_enable" setenv 1078; 1079 1080\ Module loading functions 1081 1082: load_parameters { addr -- addr addrN lenN ... addr1 len1 N } 1083 addr 1084 addr module.args strget 1085 addr module.loadname .len @ if 1086 addr module.loadname strget 1087 else 1088 addr module.name strget 1089 then 1090 addr module.type .len @ if 1091 addr module.type strget 1092 s" -t " 1093 4 ( -t type name flags ) 1094 else 1095 2 ( name flags ) 1096 then 1097; 1098 1099: before_load ( addr -- addr ) 1100 dup module.beforeload .len @ if 1101 dup module.beforeload strget 1102 ['] evaluate catch if EBEFORELOAD throw then 1103 then 1104; 1105 1106: after_load ( addr -- addr ) 1107 dup module.afterload .len @ if 1108 dup module.afterload strget 1109 ['] evaluate catch if EAFTERLOAD throw then 1110 then 1111; 1112 1113: load_error ( addr -- addr ) 1114 dup module.loaderror .len @ if 1115 dup module.loaderror strget 1116 evaluate \ This we do not intercept so it can throw errors 1117 then 1118; 1119 1120: pre_load_message ( addr -- addr ) 1121 verbose? if 1122 dup module.name strtype 1123 ." ..." 1124 then 1125; 1126 1127: load_error_message verbose? if ." failed!" cr then ; 1128 1129: load_successful_message verbose? if ." ok" cr then ; 1130 1131: load_module 1132 load_parameters load 1133; 1134 1135: process_module ( addr -- addr ) 1136 pre_load_message 1137 before_load 1138 begin 1139 ['] load_module catch if 1140 dup module.loaderror .len @ if 1141 load_error \ Command should return a flag! 1142 else 1143 load_error_message true \ Do not retry 1144 then 1145 else 1146 after_load 1147 load_successful_message true \ Successful, do not retry 1148 then 1149 until 1150; 1151 1152: process_module_errors ( addr ior -- ) 1153 dup EBEFORELOAD = if 1154 drop 1155 ." Module " 1156 dup module.name strtype 1157 dup module.loadname .len @ if 1158 ." (" dup module.loadname strtype ." )" 1159 then 1160 cr 1161 ." Error executing " 1162 dup module.beforeload strtype cr \ XXX there was a typo here 1163 abort 1164 then 1165 1166 dup EAFTERLOAD = if 1167 drop 1168 ." Module " 1169 dup module.name .addr @ over module.name .len @ type 1170 dup module.loadname .len @ if 1171 ." (" dup module.loadname strtype ." )" 1172 then 1173 cr 1174 ." Error executing " 1175 dup module.afterload strtype cr 1176 abort 1177 then 1178 1179 throw \ Don't know what it is all about -- pass ahead 1180; 1181 1182\ Module loading interface 1183 1184\ scan the list of modules, load enabled ones. 1185: load_modules ( -- ) ( throws: abort & user-defined ) 1186 module_options @ ( list_head ) 1187 begin 1188 ?dup 1189 while 1190 dup module.flag @ if 1191 ['] process_module catch 1192 process_module_errors 1193 then 1194 module.next @ 1195 repeat 1196; 1197 1198\ h00h00 magic used to try loading either a kernel with a given name, 1199\ or a kernel with the default name in a directory of a given name 1200\ (the pain!) 1201 1202: bootpath s" /boot/" ; 1203: modulepath s" module_path" ; 1204 1205\ Functions used to save and restore module_path's value. 1206: saveenv ( addr len | -1 -- addr' len | 0 -1 ) 1207 dup -1 = if 0 swap exit then 1208 strdup 1209; 1210: freeenv ( addr len | 0 -1 ) 1211 -1 = if drop else free abort" Freeing error" then 1212; 1213: restoreenv ( addr len | 0 -1 -- ) 1214 dup -1 = if ( it wasn't set ) 1215 2drop 1216 modulepath unsetenv 1217 else 1218 over >r 1219 modulepath setenv 1220 r> free abort" Freeing error" 1221 then 1222; 1223 1224: clip_args \ Drop second string if only one argument is passed 1225 1 = if 1226 2swap 2drop 1227 1 1228 else 1229 2 1230 then 1231; 1232 1233also builtins 1234 1235\ Parse filename from a semicolon-separated list 1236 1237\ replacement, not working yet 1238: newparse-; { addr len | a1 -- a' len-x addr x } 1239 addr len [char] ; strchr dup if ( a1 len1 ) 1240 swap to a1 ( store address ) 1241 1 - a1 @ 1 + swap ( remove match ) 1242 addr a1 addr - 1243 else 1244 0 0 addr len 1245 then 1246; 1247 1248: parse-; ( addr len -- addr' len-x addr x ) 1249 over 0 2swap ( addr 0 addr len ) 1250 begin 1251 dup 0 <> ( addr 0 addr len ) 1252 while 1253 over c@ [char] ; <> ( addr 0 addr len flag ) 1254 while 1255 1- swap 1+ swap 1256 2swap 1+ 2swap 1257 repeat then 1258 dup 0 <> if 1259 1- swap 1+ swap 1260 then 1261 2swap 1262; 1263 1264\ Try loading one of multiple kernels specified 1265 1266: try_multiple_kernels ( addr len addr' len' args -- flag ) 1267 >r 1268 begin 1269 parse-; 2>r 1270 2over 2r> 1271 r@ clip_args 1272 s" DEBUG" getenv? if 1273 s" echo Module_path: ${module_path}" evaluate 1274 ." Kernel : " >r 2dup type r> cr 1275 dup 2 = if ." Flags : " >r 2over type r> cr then 1276 then 1277 1 load 1278 while 1279 dup 0= 1280 until 1281 1 >r \ Failure 1282 else 1283 0 >r \ Success 1284 then 1285 2drop 2drop 1286 r> 1287 r> drop 1288; 1289 1290\ Try to load a kernel; the kernel name is taken from one of 1291\ the following lists, as ordered: 1292\ 1293\ 1. The "bootfile" environment variable 1294\ 2. The "kernel" environment variable 1295\ 1296\ Flags are passed, if available. If not, dummy values must be given. 1297\ 1298\ The kernel gets loaded from the current module_path. 1299 1300: load_a_kernel ( flags len 1 | x x 0 -- flag ) 1301 local args 1302 2local flags 1303 0 0 2local kernel 1304 end-locals 1305 1306 \ Check if a default kernel name exists at all, exits if not 1307 s" bootfile" getenv dup -1 <> if 1308 to kernel 1309 flags kernel args 1+ try_multiple_kernels 1310 dup 0= if exit then 1311 then 1312 drop 1313 1314 s" kernel" getenv dup -1 <> if 1315 to kernel 1316 else 1317 drop 1318 1 exit \ Failure 1319 then 1320 1321 \ Try all default kernel names 1322 flags kernel args 1+ try_multiple_kernels 1323; 1324 1325\ Try to load a kernel; the kernel name is taken from one of 1326\ the following lists, as ordered: 1327\ 1328\ 1. The "bootfile" environment variable 1329\ 2. The "kernel" environment variable 1330\ 1331\ Flags are passed, if provided. 1332\ 1333\ The kernel will be loaded from a directory computed from the 1334\ path given. Two directories will be tried in the following order: 1335\ 1336\ 1. /boot/path 1337\ 2. path 1338\ 1339\ The module_path variable is overridden if load is successful, by 1340\ prepending the successful path. 1341 1342: load_from_directory ( path len 1 | flags len' path len 2 -- flag ) 1343 local args 1344 2local path 1345 args 1 = if 0 0 then 1346 2local flags 1347 0 0 2local oldmodulepath \ like a string 1348 0 0 2local newmodulepath \ like a string 1349 end-locals 1350 1351 \ Set the environment variable module_path, and try loading 1352 \ the kernel again. 1353 modulepath getenv saveenv to oldmodulepath 1354 1355 \ Try prepending /boot/ first 1356 bootpath nip path nip + \ total length 1357 oldmodulepath nip dup -1 = if 1358 drop 1359 else 1360 1+ + \ add oldpath -- XXX why the 1+ ? 1361 then 1362 allocate if ( out of memory ) 1 exit then \ XXX throw ? 1363 1364 0 1365 bootpath strcat 1366 path strcat 1367 2dup to newmodulepath 1368 modulepath setenv 1369 1370 \ Try all default kernel names 1371 flags args 1- load_a_kernel 1372 0= if ( success ) 1373 oldmodulepath nip -1 <> if 1374 newmodulepath s" ;" strcat 1375 oldmodulepath strcat 1376 modulepath setenv 1377 newmodulepath drop free-memory 1378 oldmodulepath drop free-memory 1379 then 1380 0 exit 1381 then 1382 1383 \ Well, try without the prepended /boot/ 1384 path newmodulepath drop swap move 1385 newmodulepath drop path nip 1386 2dup to newmodulepath 1387 modulepath setenv 1388 1389 \ Try all default kernel names 1390 flags args 1- load_a_kernel 1391 if ( failed once more ) 1392 oldmodulepath restoreenv 1393 newmodulepath drop free-memory 1394 1 1395 else 1396 oldmodulepath nip -1 <> if 1397 newmodulepath s" ;" strcat 1398 oldmodulepath strcat 1399 modulepath setenv 1400 newmodulepath drop free-memory 1401 oldmodulepath drop free-memory 1402 then 1403 0 1404 then 1405; 1406 1407\ Try to load a kernel; the kernel name is taken from one of 1408\ the following lists, as ordered: 1409\ 1410\ 1. The "bootfile" environment variable 1411\ 2. The "kernel" environment variable 1412\ 3. The "path" argument 1413\ 1414\ Flags are passed, if provided. 1415\ 1416\ The kernel will be loaded from a directory computed from the 1417\ path given. Two directories will be tried in the following order: 1418\ 1419\ 1. /boot/path 1420\ 2. path 1421\ 1422\ Unless "path" is meant to be kernel name itself. In that case, it 1423\ will first be tried as a full path, and, next, search on the 1424\ directories pointed by module_path. 1425\ 1426\ The module_path variable is overridden if load is successful, by 1427\ prepending the successful path. 1428 1429: load_directory_or_file ( path len 1 | flags len' path len 2 -- flag ) 1430 local args 1431 2local path 1432 args 1 = if 0 0 then 1433 2local flags 1434 end-locals 1435 1436 \ First, assume path is an absolute path to a directory 1437 flags path args clip_args load_from_directory 1438 dup 0= if exit else drop then 1439 1440 \ Next, assume path points to the kernel 1441 flags path args try_multiple_kernels 1442; 1443 1444: initialize ( addr len -- ) 1445 strdup conf_files strset 1446; 1447 1448: kernel_options ( -- addr len 1 | 0 ) 1449 s" kernel_options" getenv 1450 dup -1 = if drop 0 else 1 then 1451; 1452 1453: standard_kernel_search ( flags 1 | 0 -- flag ) 1454 local args 1455 args 0= if 0 0 then 1456 2local flags 1457 s" kernel" getenv 1458 dup -1 = if 0 swap then 1459 2local path 1460 end-locals 1461 1462 path nip -1 = if ( there isn't a "kernel" environment variable ) 1463 flags args load_a_kernel 1464 else 1465 flags path args 1+ clip_args load_directory_or_file 1466 then 1467; 1468 1469: load_kernel ( -- ) ( throws: abort ) 1470 kernel_options standard_kernel_search 1471 abort" Unable to load a kernel!" 1472; 1473 1474: load_xen ( -- flag ) 1475 s" xen_kernel" getenv dup -1 <> if 1476 1 1 load ( c-addr/u flag N -- flag ) 1477 else 1478 drop 1479 0 ( -1 -- flag ) 1480 then 1481; 1482 1483: load_xen_throw ( -- ) ( throws: abort ) 1484 load_xen 1485 abort" Unable to load Xen!" 1486; 1487 1488: set_defaultoptions ( -- ) 1489 s" kernel_options" getenv dup -1 = if 1490 drop 1491 else 1492 s" temp_options" setenv 1493 then 1494; 1495 1496\ pick the i-th argument, i starts at 0 1497: argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 ) 1498 2dup = if 0 0 exit then \ out of range 1499 dup >r 1500 1+ 2* ( skip N and ui ) 1501 pick 1502 r> 1503 1+ 2* ( skip N and ai ) 1504 pick 1505; 1506 1507: drop_args ( aN uN ... a1 u1 N -- ) 1508 0 ?do 2drop loop 1509; 1510 1511: argc 1512 dup 1513; 1514 1515: queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 ) 1516 >r 1517 over 2* 1+ -roll 1518 r> 1519 over 2* 1+ -roll 1520 1+ 1521; 1522 1523: unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 ) 1524 1- -rot 1525; 1526 1527\ compute the length of the buffer including the spaces between words 1528: strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len ) 1529 dup 0= if 0 exit then 1530 0 >r \ Size 1531 0 >r \ Index 1532 begin 1533 argc r@ <> 1534 while 1535 r@ argv[] 1536 nip 1537 r> r> rot + 1+ 1538 >r 1+ >r 1539 repeat 1540 r> drop 1541 r> 1542; 1543 1544: concat_argv ( aN uN ... a1 u1 N -- a u ) 1545 strlen(argv) allocate if ENOMEM throw then 1546 0 2>r ( save addr 0 on return stack ) 1547 1548 begin 1549 dup 1550 while 1551 unqueue_argv ( ... N a1 u1 ) 1552 2r> 2swap ( old a1 u1 ) 1553 strcat 1554 s" " strcat ( append one space ) \ XXX this gives a trailing space 1555 2>r ( store string on the result stack ) 1556 repeat 1557 drop_args 1558 2r> 1559; 1560 1561: set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 ) 1562 \ Save the first argument, if it exists and is not a flag 1563 argc if 1564 0 argv[] drop c@ [char] - <> if 1565 unqueue_argv 2>r \ Filename 1566 1 >r \ Filename present 1567 else 1568 0 >r \ Filename not present 1569 then 1570 else 1571 0 >r \ Filename not present 1572 then 1573 1574 \ If there are other arguments, assume they are flags 1575 ?dup if 1576 concat_argv 1577 2dup s" temp_options" setenv 1578 drop free if EFREE throw then 1579 else 1580 set_defaultoptions 1581 then 1582 1583 \ Bring back the filename, if one was provided 1584 r> if 2r> 1 else 0 then 1585; 1586 1587: get_arguments ( -- addrN lenN ... addr1 len1 N ) 1588 0 1589 begin 1590 \ Get next word on the command line 1591 parse-word 1592 ?dup while 1593 queue_argv 1594 repeat 1595 drop ( empty string ) 1596; 1597 1598: load_kernel_and_modules ( args -- flag ) 1599 set_tempoptions 1600 argc >r 1601 s" temp_options" getenv dup -1 <> if 1602 queue_argv 1603 else 1604 drop 1605 then 1606 load_xen 1607 ?dup 0= if ( success ) 1608 r> if ( a path was passed ) 1609 load_directory_or_file 1610 else 1611 standard_kernel_search 1612 then 1613 ?dup 0= if ['] load_modules catch then 1614 then 1615; 1616 1617only forth definitions 1618