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 get_nextboot_conf_file 1061 ['] peek_file catch if 2drop then 1062 nextboot? if 1063 get_nextboot_conf_file 1064 current_file_name_ref strref 1065 ['] load_conf catch 1066 process_conf_errors 1067 ['] rewrite_nextboot_file catch if 2drop then 1068 then 1069; 1070 1071\ Module loading functions 1072 1073: load_parameters { addr -- addr addrN lenN ... addr1 len1 N } 1074 addr 1075 addr module.args strget 1076 addr module.loadname .len @ if 1077 addr module.loadname strget 1078 else 1079 addr module.name strget 1080 then 1081 addr module.type .len @ if 1082 addr module.type strget 1083 s" -t " 1084 4 ( -t type name flags ) 1085 else 1086 2 ( name flags ) 1087 then 1088; 1089 1090: before_load ( addr -- addr ) 1091 dup module.beforeload .len @ if 1092 dup module.beforeload strget 1093 ['] evaluate catch if EBEFORELOAD throw then 1094 then 1095; 1096 1097: after_load ( addr -- addr ) 1098 dup module.afterload .len @ if 1099 dup module.afterload strget 1100 ['] evaluate catch if EAFTERLOAD throw then 1101 then 1102; 1103 1104: load_error ( addr -- addr ) 1105 dup module.loaderror .len @ if 1106 dup module.loaderror strget 1107 evaluate \ This we do not intercept so it can throw errors 1108 then 1109; 1110 1111: pre_load_message ( addr -- addr ) 1112 verbose? if 1113 dup module.name strtype 1114 ." ..." 1115 then 1116; 1117 1118: load_error_message verbose? if ." failed!" cr then ; 1119 1120: load_successful_message verbose? if ." ok" cr then ; 1121 1122: load_module 1123 load_parameters load 1124; 1125 1126: process_module ( addr -- addr ) 1127 pre_load_message 1128 before_load 1129 begin 1130 ['] load_module catch if 1131 dup module.loaderror .len @ if 1132 load_error \ Command should return a flag! 1133 else 1134 load_error_message true \ Do not retry 1135 then 1136 else 1137 after_load 1138 load_successful_message true \ Successful, do not retry 1139 then 1140 until 1141; 1142 1143: process_module_errors ( addr ior -- ) 1144 dup EBEFORELOAD = if 1145 drop 1146 ." Module " 1147 dup module.name strtype 1148 dup module.loadname .len @ if 1149 ." (" dup module.loadname strtype ." )" 1150 then 1151 cr 1152 ." Error executing " 1153 dup module.beforeload strtype cr \ XXX there was a typo here 1154 abort 1155 then 1156 1157 dup EAFTERLOAD = if 1158 drop 1159 ." Module " 1160 dup module.name .addr @ over module.name .len @ type 1161 dup module.loadname .len @ if 1162 ." (" dup module.loadname strtype ." )" 1163 then 1164 cr 1165 ." Error executing " 1166 dup module.afterload strtype cr 1167 abort 1168 then 1169 1170 throw \ Don't know what it is all about -- pass ahead 1171; 1172 1173\ Module loading interface 1174 1175\ scan the list of modules, load enabled ones. 1176: load_modules ( -- ) ( throws: abort & user-defined ) 1177 module_options @ ( list_head ) 1178 begin 1179 ?dup 1180 while 1181 dup module.flag @ if 1182 ['] process_module catch 1183 process_module_errors 1184 then 1185 module.next @ 1186 repeat 1187; 1188 1189\ h00h00 magic used to try loading either a kernel with a given name, 1190\ or a kernel with the default name in a directory of a given name 1191\ (the pain!) 1192 1193: bootpath s" /boot/" ; 1194: modulepath s" module_path" ; 1195 1196\ Functions used to save and restore module_path's value. 1197: saveenv ( addr len | -1 -- addr' len | 0 -1 ) 1198 dup -1 = if 0 swap exit then 1199 strdup 1200; 1201: freeenv ( addr len | 0 -1 ) 1202 -1 = if drop else free abort" Freeing error" then 1203; 1204: restoreenv ( addr len | 0 -1 -- ) 1205 dup -1 = if ( it wasn't set ) 1206 2drop 1207 modulepath unsetenv 1208 else 1209 over >r 1210 modulepath setenv 1211 r> free abort" Freeing error" 1212 then 1213; 1214 1215: clip_args \ Drop second string if only one argument is passed 1216 1 = if 1217 2swap 2drop 1218 1 1219 else 1220 2 1221 then 1222; 1223 1224also builtins 1225 1226\ Parse filename from a semicolon-separated list 1227 1228\ replacement, not working yet 1229: newparse-; { addr len | a1 -- a' len-x addr x } 1230 addr len [char] ; strchr dup if ( a1 len1 ) 1231 swap to a1 ( store address ) 1232 1 - a1 @ 1 + swap ( remove match ) 1233 addr a1 addr - 1234 else 1235 0 0 addr len 1236 then 1237; 1238 1239: parse-; ( addr len -- addr' len-x addr x ) 1240 over 0 2swap ( addr 0 addr len ) 1241 begin 1242 dup 0 <> ( addr 0 addr len ) 1243 while 1244 over c@ [char] ; <> ( addr 0 addr len flag ) 1245 while 1246 1- swap 1+ swap 1247 2swap 1+ 2swap 1248 repeat then 1249 dup 0 <> if 1250 1- swap 1+ swap 1251 then 1252 2swap 1253; 1254 1255\ Try loading one of multiple kernels specified 1256 1257: try_multiple_kernels ( addr len addr' len' args -- flag ) 1258 >r 1259 begin 1260 parse-; 2>r 1261 2over 2r> 1262 r@ clip_args 1263 s" DEBUG" getenv? if 1264 s" echo Module_path: ${module_path}" evaluate 1265 ." Kernel : " >r 2dup type r> cr 1266 dup 2 = if ." Flags : " >r 2over type r> cr then 1267 then 1268 1 load 1269 while 1270 dup 0= 1271 until 1272 1 >r \ Failure 1273 else 1274 0 >r \ Success 1275 then 1276 2drop 2drop 1277 r> 1278 r> drop 1279; 1280 1281\ Try to load a kernel; the kernel name is taken from one of 1282\ the following lists, as ordered: 1283\ 1284\ 1. The "bootfile" environment variable 1285\ 2. The "kernel" environment variable 1286\ 1287\ Flags are passed, if available. If not, dummy values must be given. 1288\ 1289\ The kernel gets loaded from the current module_path. 1290 1291: load_a_kernel ( flags len 1 | x x 0 -- flag ) 1292 local args 1293 2local flags 1294 0 0 2local kernel 1295 end-locals 1296 1297 \ Check if a default kernel name exists at all, exits if not 1298 s" bootfile" getenv dup -1 <> if 1299 to kernel 1300 flags kernel args 1+ try_multiple_kernels 1301 dup 0= if exit then 1302 then 1303 drop 1304 1305 s" kernel" getenv dup -1 <> if 1306 to kernel 1307 else 1308 drop 1309 1 exit \ Failure 1310 then 1311 1312 \ Try all default kernel names 1313 flags kernel args 1+ try_multiple_kernels 1314; 1315 1316\ Try to load a kernel; the kernel name is taken from one of 1317\ the following lists, as ordered: 1318\ 1319\ 1. The "bootfile" environment variable 1320\ 2. The "kernel" environment variable 1321\ 1322\ Flags are passed, if provided. 1323\ 1324\ The kernel will be loaded from a directory computed from the 1325\ path given. Two directories will be tried in the following order: 1326\ 1327\ 1. /boot/path 1328\ 2. path 1329\ 1330\ The module_path variable is overridden if load is successful, by 1331\ prepending the successful path. 1332 1333: load_from_directory ( path len 1 | flags len' path len 2 -- flag ) 1334 local args 1335 2local path 1336 args 1 = if 0 0 then 1337 2local flags 1338 0 0 2local oldmodulepath \ like a string 1339 0 0 2local newmodulepath \ like a string 1340 end-locals 1341 1342 \ Set the environment variable module_path, and try loading 1343 \ the kernel again. 1344 modulepath getenv saveenv to oldmodulepath 1345 1346 \ Try prepending /boot/ first 1347 bootpath nip path nip + \ total length 1348 oldmodulepath nip dup -1 = if 1349 drop 1350 else 1351 1+ + \ add oldpath -- XXX why the 1+ ? 1352 then 1353 allocate if ( out of memory ) 1 exit then \ XXX throw ? 1354 1355 0 1356 bootpath strcat 1357 path strcat 1358 2dup to newmodulepath 1359 modulepath setenv 1360 1361 \ Try all default kernel names 1362 flags args 1- load_a_kernel 1363 0= if ( success ) 1364 oldmodulepath nip -1 <> if 1365 newmodulepath s" ;" strcat 1366 oldmodulepath strcat 1367 modulepath setenv 1368 newmodulepath drop free-memory 1369 oldmodulepath drop free-memory 1370 then 1371 0 exit 1372 then 1373 1374 \ Well, try without the prepended /boot/ 1375 path newmodulepath drop swap move 1376 newmodulepath drop path nip 1377 2dup to newmodulepath 1378 modulepath setenv 1379 1380 \ Try all default kernel names 1381 flags args 1- load_a_kernel 1382 if ( failed once more ) 1383 oldmodulepath restoreenv 1384 newmodulepath drop free-memory 1385 1 1386 else 1387 oldmodulepath nip -1 <> if 1388 newmodulepath s" ;" strcat 1389 oldmodulepath strcat 1390 modulepath setenv 1391 newmodulepath drop free-memory 1392 oldmodulepath drop free-memory 1393 then 1394 0 1395 then 1396; 1397 1398\ Try to load a kernel; the kernel name is taken from one of 1399\ the following lists, as ordered: 1400\ 1401\ 1. The "bootfile" environment variable 1402\ 2. The "kernel" environment variable 1403\ 3. The "path" argument 1404\ 1405\ Flags are passed, if provided. 1406\ 1407\ The kernel will be loaded from a directory computed from the 1408\ path given. Two directories will be tried in the following order: 1409\ 1410\ 1. /boot/path 1411\ 2. path 1412\ 1413\ Unless "path" is meant to be kernel name itself. In that case, it 1414\ will first be tried as a full path, and, next, search on the 1415\ directories pointed by module_path. 1416\ 1417\ The module_path variable is overridden if load is successful, by 1418\ prepending the successful path. 1419 1420: load_directory_or_file ( path len 1 | flags len' path len 2 -- flag ) 1421 local args 1422 2local path 1423 args 1 = if 0 0 then 1424 2local flags 1425 end-locals 1426 1427 \ First, assume path is an absolute path to a directory 1428 flags path args clip_args load_from_directory 1429 dup 0= if exit else drop then 1430 1431 \ Next, assume path points to the kernel 1432 flags path args try_multiple_kernels 1433; 1434 1435: initialize ( addr len -- ) 1436 strdup conf_files strset 1437; 1438 1439: kernel_options ( -- addr len 1 | 0 ) 1440 s" kernel_options" getenv 1441 dup -1 = if drop 0 else 1 then 1442; 1443 1444: standard_kernel_search ( flags 1 | 0 -- flag ) 1445 local args 1446 args 0= if 0 0 then 1447 2local flags 1448 s" kernel" getenv 1449 dup -1 = if 0 swap then 1450 2local path 1451 end-locals 1452 1453 path nip -1 = if ( there isn't a "kernel" environment variable ) 1454 flags args load_a_kernel 1455 else 1456 flags path args 1+ clip_args load_directory_or_file 1457 then 1458; 1459 1460: load_kernel ( -- ) ( throws: abort ) 1461 kernel_options standard_kernel_search 1462 abort" Unable to load a kernel!" 1463; 1464 1465: load_xen ( -- flag ) 1466 s" xen_kernel" getenv dup -1 <> if 1467 1 1 load ( c-addr/u flag N -- flag ) 1468 else 1469 drop 1470 0 ( -1 -- flag ) 1471 then 1472; 1473 1474: load_xen_throw ( -- ) ( throws: abort ) 1475 load_xen 1476 abort" Unable to load Xen!" 1477; 1478 1479: set_defaultoptions ( -- ) 1480 s" kernel_options" getenv dup -1 = if 1481 drop 1482 else 1483 s" temp_options" setenv 1484 then 1485; 1486 1487\ pick the i-th argument, i starts at 0 1488: argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 ) 1489 2dup = if 0 0 exit then \ out of range 1490 dup >r 1491 1+ 2* ( skip N and ui ) 1492 pick 1493 r> 1494 1+ 2* ( skip N and ai ) 1495 pick 1496; 1497 1498: drop_args ( aN uN ... a1 u1 N -- ) 1499 0 ?do 2drop loop 1500; 1501 1502: argc 1503 dup 1504; 1505 1506: queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 ) 1507 >r 1508 over 2* 1+ -roll 1509 r> 1510 over 2* 1+ -roll 1511 1+ 1512; 1513 1514: unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 ) 1515 1- -rot 1516; 1517 1518\ compute the length of the buffer including the spaces between words 1519: strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len ) 1520 dup 0= if 0 exit then 1521 0 >r \ Size 1522 0 >r \ Index 1523 begin 1524 argc r@ <> 1525 while 1526 r@ argv[] 1527 nip 1528 r> r> rot + 1+ 1529 >r 1+ >r 1530 repeat 1531 r> drop 1532 r> 1533; 1534 1535: concat_argv ( aN uN ... a1 u1 N -- a u ) 1536 strlen(argv) allocate if ENOMEM throw then 1537 0 2>r ( save addr 0 on return stack ) 1538 1539 begin 1540 dup 1541 while 1542 unqueue_argv ( ... N a1 u1 ) 1543 2r> 2swap ( old a1 u1 ) 1544 strcat 1545 s" " strcat ( append one space ) \ XXX this gives a trailing space 1546 2>r ( store string on the result stack ) 1547 repeat 1548 drop_args 1549 2r> 1550; 1551 1552: set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 ) 1553 \ Save the first argument, if it exists and is not a flag 1554 argc if 1555 0 argv[] drop c@ [char] - <> if 1556 unqueue_argv 2>r \ Filename 1557 1 >r \ Filename present 1558 else 1559 0 >r \ Filename not present 1560 then 1561 else 1562 0 >r \ Filename not present 1563 then 1564 1565 \ If there are other arguments, assume they are flags 1566 ?dup if 1567 concat_argv 1568 2dup s" temp_options" setenv 1569 drop free if EFREE throw then 1570 else 1571 set_defaultoptions 1572 then 1573 1574 \ Bring back the filename, if one was provided 1575 r> if 2r> 1 else 0 then 1576; 1577 1578: get_arguments ( -- addrN lenN ... addr1 len1 N ) 1579 0 1580 begin 1581 \ Get next word on the command line 1582 parse-word 1583 ?dup while 1584 queue_argv 1585 repeat 1586 drop ( empty string ) 1587; 1588 1589: load_kernel_and_modules ( args -- flag ) 1590 set_tempoptions 1591 argc >r 1592 s" temp_options" getenv dup -1 <> if 1593 queue_argv 1594 else 1595 drop 1596 then 1597 load_xen 1598 ?dup 0= if ( success ) 1599 r> if ( a path was passed ) 1600 load_directory_or_file 1601 else 1602 standard_kernel_search 1603 then 1604 ?dup 0= if ['] load_modules catch then 1605 then 1606; 1607 1608only forth definitions 1609