;;; -*- Lisp -*- ;;; ;;; Core image builder for Spice Lisp. ;;; Written by Skef Wholey. ;;; ;;; We gobble up SFASL files, building a virtual memory image in a collection ;;; of blocks in system table space. When we're done and wish to write out the ;;; file, we allocate a block large enough to hold the contents of the memory ;;; image, and twiddle the page map to map the parts of the image consecutively ;;; into this large block, which we then write out as a file. ;;; (defun get-valid-hunk (size) (let ((addr (%sp-make-misc (validate-memory 0 (ash size 1) -1)))) (values addr addr))) ;;; Memory accessing. ;;; The virtual address space is divided into 64 pieces. (defvar number-of-spaces 64 "Number of pointer-type spaces.") ;;; The initial size of spaces will be 512K words. If we need more than this, ;;; the following constant will have to be changed. (defvar space-size 524288 "Number of 16-bit words in each space.") ;;; Each space is represented as a structure containing the address of its ;;; data in system space and the number of words used so far in it. (defstruct (space (:print-function print-a-space)) address real-address free-pointer) (defun print-a-space (space stream depth) depth (write-string "# free 0) (incf nonempty-spaces) (incf data-pages (1+ (ash free -8)))))) (setq word-length (ash data-pages 8)) (multiple-value-bind (hunk addr) (get-valid-hunk word-length) ;; Write the CORE file password. (%primitive 16bit-system-set hunk 0 #x+5245) (%primitive 16bit-system-set hunk 1 #x+434F) ;; Write the directory header entry. (%primitive 16bit-system-set hunk 2 3841) (%primitive 16bit-system-set hunk 3 0) (%primitive 16bit-system-set hunk 4 (+ 2 (* 3 (+ nonempty-spaces 2)))) (%primitive 16bit-system-set hunk 5 0) ;; First, an entry for the alloc table. (%primitive 16bit-system-set hunk 6 0) ; Data page (%primitive 16bit-system-set hunk 7 0) (%primitive 16bit-system-set hunk 8 256) ; Process page (%primitive 16bit-system-set hunk 9 0) (%primitive 16bit-system-set hunk 10 1) ; Page count (%primitive 16bit-system-set hunk 11 0) ;; Next, an entry for the escape routine table. (%primitive 16bit-system-set hunk 12 1) ; Data page (%primitive 16bit-system-set hunk 13 0) (%primitive 16bit-system-set hunk 14 512); Process page (%primitive 16bit-system-set hunk 15 0) (%primitive 16bit-system-set hunk 16 1) ; Page count (%primitive 16bit-system-set hunk 17 0) ;; Construct the alloc table, with both free and clean pointers. (do ((space (ash %bit-vector-type 2) (1+ space))) ((> space (+ (ash %list-type 2) 3))) (let ((alloc-index (+ 256 (ash space 2)))) (cond ((svref memory space) (let ((free (handle-offset (space-free-pointer (svref memory space))))) (%primitive 16bit-system-set hunk alloc-index (logand free 65535)) (%primitive 16bit-system-set hunk (+ alloc-index 1) (logior (ash space 9) (ash free -16))) (%primitive 16bit-system-set hunk (+ alloc-index 2) 0) (%primitive 16bit-system-set hunk (+ alloc-index 3) (ash space 9)))) (t (%primitive 16bit-system-set hunk alloc-index 0) (%primitive 16bit-system-set hunk (+ alloc-index 1) (ash space 9)) (%primitive 16bit-system-set hunk (+ alloc-index 2) 0) (%primitive 16bit-system-set hunk (+ alloc-index 3) (ash space 9)))))) ;; Now construct the escape routine table. (dolist (routine escape-routines) (let ((name (get (car routine) 'handle)) (number (+ 512 (ash (cadr routine) 1)))) (cond (name (%primitive 16bit-system-set hunk number (cdr name)) (%primitive 16bit-system-set hunk (1+ number) (car name))) (t (format t "~&Warning: ~S is not defined in this core image." (car routine)))))) ;; Then, write entries for each space. (do ((spaces used-spaces (cdr spaces)) (data-page 2) (index 18)) ((null spaces) ;; Finally, the end of header code. (%primitive 16bit-system-set hunk index 3840) (%primitive 16bit-system-set hunk (+ index 1) 0) (%primitive 16bit-system-set hunk (+ index 2) 2) (%primitive 16bit-system-set hunk (+ index 3) 0)) (let* ((space (car spaces)) (free (handle-offset (space-free-pointer (svref memory space))))) (if (> free 0) (let ((process-page (ash space 1)) (page-count (1+ (ash free -8)))) ;; Make the directory entry. (%primitive 16bit-system-set hunk index data-page) (%primitive 16bit-system-set hunk (+ index 1) 0) (%primitive 16bit-system-set hunk (+ index 2) 0) (%primitive 16bit-system-set hunk (+ index 3) process-page) (%primitive 16bit-system-set hunk (+ index 4) page-count) (%primitive 16bit-system-set hunk (+ index 5) 0) (format t "~S pages from space ~S.~%" page-count space) ;; Move the words into the file. (move-words (%sp-make-fixnum (space-real-address (svref memory space))) (+ (%sp-make-fixnum addr) (ash (1+ data-page) 8)) (ash page-count 8) nil nil -1 ()) (incf data-page page-count) (incf index 6))))) (format t "Writing ~A.~%(Type a space when the paging has stopped)~%" name) (get-event 2) (sub-write-file name (%sp-make-fixnum addr) (ash word-length 1) 0) (write-line "Done!") t))) ;;; Cleanup. (defun clean-up-genesis () (dolist (symbol coldly-interned-symbols) (remprop symbol 'handle)) (setq coldly-interned-symbols nil)) ;;; Top level. (defun genesis (file-list core-name) "Builds a kernel Lisp image from the .SFASL files specified in the given File-List and writes it to a file named by Core-Name." (fresh-line) (clean-up-genesis) (initialize-memory) (initialize-spaces) (initialize-symbols) (dolist (file file-list) (write-line file) (cold-load file)) (finish-symbols) (write-initial-core-file core-name))