1 ;;;;------------------ -*- movitz-mode: t -*--------------------------
3 ;;;; Copyright (C) 2000-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway
6 ;;;; Filename: los0.lisp
7 ;;;; Description: Top-level initialization and testing.
8 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
9 ;;;; Created at: Fri Dec 1 18:08:32 2000
10 ;;;; Distribution: See the accompanying file COPYING.
12 ;;;; $Id: los0.lisp,v 1.51 2007/04/09 17:30:15 ffjeld Exp $
14 ;;;;------------------------------------------------------------------
16 (provide :los0
:load-priority
0)
18 (require :common-lisp
)
20 (require :x86-pc
/io-space
)
21 (require :x86-pc
/ne2k
)
22 (require :x86-pc
/floppy
)
23 (require :x86-pc
/serial
)
25 (require :lib
/readline
)
26 (require :lib
/toplevel
)
27 ;; (require :lib/net/ip6)
28 (require :lib
/net
/ip4
)
29 (require :lib
/net
/dhcp
)
32 (require :lib
/threading
)
33 (require :lib
/scheduler
)
35 (require :lib
/graphics
)
38 ;; (require :lice-0.1/all)
52 #:muerte.x86-pc.serial
55 (require :lib
/shallow-binding
)
56 (require :los0-gc
) ; Must come after defpackage.
57 ;; (require :asteroids)
62 ;; (defun load-ansi-tests ()
63 ;; (load "../ansi-tests.lisp"))
65 (defun assess-cpu-frequency ()
66 "Assess the CPU's frequency in units of 1024 Hz."
67 (assert (cpu-featurep :tsc
) ()
68 "This function requires a CPU with the time-stamp-counter feature.")
69 (let ((s0 (loop with x
= (rtc-register :second
)
70 for s0
= (rtc-register :second
)
72 finally
(return s0
))))
73 (multiple-value-bind (c0-lo c0-hi
)
74 (read-time-stamp-counter)
75 (loop while
(= s0
(rtc-register :second
)))
76 (multiple-value-bind (c1-lo c1-hi
)
77 (read-time-stamp-counter)
78 (+ (ash (- c1-hi c0-hi
) 19)
79 (ash (+ 512 (- c1-lo c0-lo
)) -
10))))))
81 (defun report-cpu-frequency ()
82 (multiple-value-bind (mhz khz
)
83 (truncate (assess-cpu-frequency) 976)
84 (format t
"~&CPU frequency: ~D.~2,'0D MHz.~%" mhz
(round khz
10)))
87 (defvar *cpu-frequency-mhz
*)
89 (defun init-nano-sleep ()
90 (setf *cpu-frequency-mhz
*
91 (truncate (assess-cpu-frequency) 976)))
93 (defun nano-sleep (nano-seconds)
94 (let* ((t0 (read-time-stamp-counter))
95 (t1 (+ t0
(truncate (* nano-seconds
(%symbol-global-value
'*cpu-frequency-mhz
*))
98 (loop until
(< (read-time-stamp-counter) t0
))) ; wait for wrap-around
99 (loop until
(>= (read-time-stamp-counter) t1
))))
101 (defun test-nano-sleep (x)
102 (time (nano-sleep x
)))
108 (defun install-internal-time (&optional
(minimum-frequency 100))
109 "Figure out this CPU's internal-time-unit. Warning: This process takes about 1.5 seconds."
110 (let ((s0 (loop with x
= (rtc-register :second
)
111 for s0
= (rtc-register :second
)
113 finally
(return s0
))))
114 (multiple-value-bind (c0-lo c0-hi
)
115 (read-time-stamp-counter)
116 (loop while
(= s0
(rtc-register :second
)))
117 (multiple-value-bind (c1-lo c1-hi
)
118 (read-time-stamp-counter)
119 (let ((res (+ (ash (ldb (byte 22 0) (- c1-hi c0-hi
)) 7)
120 (ash (- c1-lo c0-lo
) -
22))))
122 ((> res minimum-frequency
)
123 (setf (symbol-function 'get-internal-run-time
)
125 (multiple-value-bind (lo hi
)
126 (read-time-stamp-counter)
128 (ash (ldb (byte 22 0) hi
) 7)))))
129 (setf internal-time-units-per-second res
))
130 (t ;; This is for really slow machines, like bochs..
131 (let ((res (+ (ash (- c1-hi c0-hi
) 13)
132 (ash (- c1-lo c0-lo
) -
16))))
133 (setf (symbol-function 'get-internal-run-time
)
135 (multiple-value-bind (lo hi
)
136 (read-time-stamp-counter)
137 (+ (ash (ldb (byte 16 0) hi
) 13)
139 (setf internal-time-units-per-second res
))))))))
143 (defun y-or-n-p (&optional control
&rest arguments
)
144 "=> generalized-boolean"
145 (declare (dynamic-extent arguments
))
147 (fresh-line *query-io
*)
148 (apply #'format
*query-io
* control arguments
))
149 (write-string " (y/n) " *query-io
*)
150 (let ((response (contextual-readline *repl-readline-context
*)))
151 (and (> (length response
) 0)
152 (char-equal #\y
(char response
0)))))
155 ;;;;;;;;;;;;;; Top-level commands..
157 (define-toplevel-command :cls
()
158 (clear-console *terminal-io
*)
159 (setf (cursor-x *terminal-io
*) 0
160 (cursor-y *terminal-io
*) 0)
163 (define-toplevel-command :bt
(&rest args
)
164 (declare (dynamic-extent args
))
165 (apply #'backtrace
(mapcar #'eval args
)))
167 (define-toplevel-command :cpu-reset
()
168 (when (y-or-n-p "Really reset CPU?")
169 (muerte.x86-pc.keyboard
:cpu-reset
))
172 (define-toplevel-command :decimal
(&optional x-list
)
177 (16 (format t
"~&~W = ~D" x x
))
178 (10 (format t
"~&~W = #x~X" x x
))
179 (t (format t
"~&~W = ~D. = #x~X" x x x
)))
180 (when (typep x
'ratio
)
181 (format t
" ~~ ~,3F" x
)))
183 (format t
"~&~Z = ~W" x x
))
185 (write x
:radix nil
:base
(case *print-base
* (10 16) (t 10)))))
188 (do-print (eval x-list
))
189 (dolist (x cl
:/ (values-list cl
:/))
192 (define-toplevel-command :z
(&optional x-list
)
197 (do-print (eval x-list
))
198 (dolist (x cl
:/ (values-list cl
:/))
201 (defmacro with-paging
(options &body body
)
202 (declare (ignore options
))
204 (let ((paging-offset 2))
206 ((newline (lambda (condition)
207 (declare (ignore condition
))
208 (when (and paging-offset
209 (>= (incf paging-offset
)
210 muerte.x86-pc
::*screen-height
*))
211 (format t
"~&more? (y/n/a) ")
214 (case (muerte.x86-pc.keyboard
:poll-char
)
216 (break "Console pager"))
218 (return-from paging
(values)))
219 ((#\a #\A
) ; Quit paging
220 (setf paging-offset nil
))
223 (1- muerte.x86-pc
::*screen-height
*)))
224 ((#\y
#\Y
#\space
) ; One more page
225 (setf paging-offset
1))
227 (write-char #\return
)
228 (clear-line *standard-output
* 0 (cursor-y *standard-output
*))
232 (define-toplevel-command :more
(form)
234 (multiple-value-call #'format t
"~@{~&~W~}"
237 (define-toplevel-command :pop
()
238 (when *debugger-dynamic-context
*
239 (let ((r (find-restart-from-context 'abort
*debugger-dynamic-context
*)))
242 (warn "No abort restart found."))))
245 (define-toplevel-command :trace
(&rest args
)
246 (declare (dynamic-extent args
))
249 (mapcar #'car muerte
::*trace-map
*))
250 (t (apply #'do-trace args
)
253 (define-toplevel-command :untrace
(&rest function-names
)
254 (declare (dynamic-extent function-names
))
256 ((null function-names
)
257 (do () ((null muerte
::*trace-map
*))
258 (do-untrace (caar muerte
::*trace-map
*))))
259 (t (map nil
#'do-untrace function-names
)
262 (defvar *debugger-printing-restarts
* nil
)
264 (define-toplevel-command :error
()
265 (if (not (and (boundp '*debugger-condition
*)
266 *debugger-condition
*))
268 (let ((condition *debugger-condition
*)
273 (write-string (case (car condition
)
274 ((simple-error error
) "Error: ")
276 (t (write (car condition
)))))
277 (if (stringp (cadr condition
))
278 (apply 'format t
(cadr condition
) (cddr condition
))
279 (write (cdr condition
))))
280 (t (format t
"~&Error: ~A" condition
)))
281 (if *debugger-printing-restarts
*
282 (progn (format t
"~&[restarts suppressed]")
284 (let ((*debugger-printing-restarts
* t
))
285 (map-active-restarts (lambda (restart index
)
286 (format t
"~&~2D: ~A~%" index restart
))
287 (or *debugger-dynamic-context
*
288 (muerte::current-dynamic-context
)))))))
291 (define-toplevel-command :restart
(&optional
(r 0) &rest args
)
292 (declare (dynamic-extent args
))
293 (let* ((context (or *debugger-dynamic-context
*
294 (muerte::current-dynamic-context
)))
297 (find-restart-by-index r context
))
299 (find-restart-from-context r context
)))))
302 (format t
"~&There is no restart like that."))
304 (apply 'invoke-restart restart args
))
305 (t (invoke-restart-interactively restart
)))))
307 (define-toplevel-command :package
(package-name)
308 (let ((p (find-package (string package-name
))))
311 (format t
"~&No package named \"~A\"." package-name
)))
314 (define-toplevel-command :help
(&optional
(x (or (and (boundp '*debugger-condition
*)
315 *debugger-condition
*)
320 (format t
"Toplevel commands:")
321 (maphash (lambda (k v
)
324 *toplevel-commands
*))
325 ((and (keywordp x
) (gethash x
*toplevel-commands
*))
326 (describe (gethash x
*toplevel-commands
*)))
330 ;;;(muerte.toplevel:define-toplevel-command :bochs-trace (form)
331 ;;; (muerte::with-bochs-tracing ()
334 (muerte.toplevel
:define-toplevel-command
:mapkey
(code-char-form)
335 (let* ((code-char (eval code-char-form
))
336 (char (etypecase code-char
337 (character code-char
)
338 (integer (code-char code-char
)))))
339 (format t
"~&Hit the (single) key you want to map to ~S..." char
)
341 (loop until
(muerte.x86-pc.keyboard
::lowlevel-event-p
))
342 (multiple-value-bind (key-code release-p
)
343 (muerte.x86-pc.keyboard
::lowlevel-read
)
344 (when (and key-code
(not release-p
))
346 (#x1c
(format t
"~&Will not replace Enter key!"))
347 (t (format t
"~&Setting scan-code ~S to ~S...~%" key-code char
)
348 (setf (aref muerte.x86-pc.keyboard
::*scan-codes
* key-code
) char
)))
349 (return (values)))))))
351 (defun los0-debugger (condition)
352 (let ((*debugger-dynamic-context
* (muerte::current-dynamic-context
))
353 (*standard-output
* *debug-io
*)
354 (*standard-input
* *debug-io
*)
355 (*debugger-condition
* condition
)
356 (*package
* (or (and (packagep *package
*) *package
*)
357 (find-package "LOS0")
358 (find-package "USER")
359 (find-package "COMMON-LISP")
360 (error "Unable to find any package!")))
361 (*repl-prompt-context
* #\d
)
362 #+ignore
(*repl-readline-context
* (or *repl-readline-context
*
363 (make-readline-context :history-size
16))))
364 (let ((*print-safely
* t
))
365 (invoke-toplevel-command :error
))
367 (with-simple-restart (abort "Abort to command level ~D." (1+ *repl-level
*))
368 (read-eval-print)))))
371 (defun random (limit)
374 (mod (read-time-stamp-counter) limit
))
375 (muerte::positive-bignum
376 (let ((x (muerte::copy-bignum limit
)))
377 (dotimes (i (1- (muerte::%bignum-bigits x
)))
378 (setf (memref x
2 :index i
:type
:unsigned-byte32
)
379 (muerte::read-time-stamp-counter
)))
380 (setf x
(muerte::bignum-canonicalize x
))
381 (loop while
(>= x limit
)
382 do
(setf x
(truncate x
2)))
387 (defvar *segment-descriptor-table
*)
389 (defun format-segment-table (table &key
(start 0) (end (truncate (length table
) 2)))
390 (loop for i from start below end
391 as selector
= (* i
8)
392 do
(format t
"~&~3X: base: #x~8,'0X, limit: #x~5,'0X, type-s-dpl-p: ~8,'0b, avl-x-db-g: ~4,'0b~%"
394 (* 4 (segment-descriptor-base-location table selector
))
395 (segment-descriptor-limit table selector
)
396 (segment-descriptor-type-s-dpl-p table selector
)
397 (segment-descriptor-avl-x-db-g table selector
)))
401 (defun turn-on-irqs ()
402 ;; listen for timer and keyboard IRQ interrupts
403 (setf (pic8259-irq-mask) #xfffc
)
404 (with-inline-assembly (:returns
:nothing
) (:sti
)))
407 ;; (install-shallow-binding)
408 (setf *debugger-function
* #'los0-debugger
)
409 (let ((extended-memsize 0))
410 ;; Find out how much extended memory we have
411 (setf (io-port #x70
:unsigned-byte8
) #x18
)
412 (setf extended-memsize
(* 256 (io-port #x71
:unsigned-byte8
)))
413 (setf (io-port #x70
:unsigned-byte8
) #x17
)
414 (incf extended-memsize
(io-port #x71
:unsigned-byte8
))
415 ;; (format t "Extended memory: ~D KB~%" extended-memsize)
419 (setf *segment-descriptor-table
* ; Ensure we have a GDT with 16 entries, in static-space.
420 (setf (global-segment-descriptor-table)
421 (muerte::dump-global-segment-table
:entries
16)))
423 #+ignore
(install-los0-consing :kb-size
(* 2 1024))
424 (let* ((buf (check-the fixnum
(%run-time-context-slot nil
'muerte
::nursery-space
)))
425 (current (check-the fixnum
(memref buf
4)))
426 (end (check-the fixnum
(memref buf
0)))
427 (free-kb (1- (truncate (- end current
32) 256))))
430 (warn "Not enough memory to install GC (~D bytes)." (- end buf
16)))
431 (t (format t
"~&Installing los0-GC with ~D KB.~%" free-kb
)
432 (install-los0-consing :kb-size
(truncate free-kb
2))))))
436 (catch :top-level-repl
; If restarts don't work, you can throw this..
437 (with-simple-restart (abort "Abort to the top command level.")
440 ; (set-textmode +vga-state-90x30+)
441 (let ((muerte::*error-no-condition-for-debugger
* t
))
444 (setf *package
* (find-package "LOS0"))
446 ;; (install-shallow-binding)
447 (let ((*repl-readline-context
* (make-readline-context :history-size
16))
448 #+ignore
(*backtrace-stack-frame-barrier
* (stack-frame-uplink (current-stack-frame)))
449 #+ignore
(*error-no-condition-for-debugger
* t
)
450 #+ignore
(*debugger-function
* #'los0-debugger
)
451 #+ignore
(*package
* *package
*))
452 (with-simple-restart (abort "Skip Los0 boot-up initialization.")
455 (format t
"~&CPU features:~:[ none~;~{ ~A~#[~; and~:;,~]~}~].~%"
456 *cpu-features
* *cpu-features
*)
457 ;; (muerte:asm :int 49)
459 (when muerte
::*multiboot-data
*
460 (set-textmode +vga-state-90x30
+))
463 ((not (cpu-featurep :tsc
))
464 (warn "This CPU has no time-stamp-counter. Timer-related functions will not work."))
465 (t (install-internal-time)
466 (warn "Internal-time will wrap in ~D days."
467 (truncate most-positive-fixnum
468 (* internal-time-units-per-second
60 60 24)))))
469 ;; (muerte.toplevel:invoke-toplevel-command :mapkey #\newline)
470 #+ignore
(let ((s (make-instance 'muerte.x86-pc
:vga-text-console
)))
471 (setf *standard-output
* s
476 (setf threading
:*segment-descriptor-table-manager
*
477 (make-instance 'threading
:segment-descriptor-table-manager
))
479 (muerte.x86-pc.keyboard
:setup-kbd
)
480 (muerte.lib
::setup-scheduling
)
484 ;;; (setf (symbol-function 'write-char)
485 ;;; (muerte.x86-pc.serial::make-serial-write-char :baudrate 38400))
486 ;;; (format t "~&Installed serial-port write-char."))
487 (let ((* nil
) (** nil
) (*** nil
)
488 (/ nil
) (// nil
) (/// nil
)
489 (+ nil
) (++ nil
) (+++ nil
)
490 (*readline-signal-keypresses
* t
))
491 (format t
"~&Movitz image Los0 build ~D." *build-number
*)
495 (let ((key (readline-keypress-key c
)))
497 (fvf-textmode-screendump)
498 (format *query-io
* "~&Dumped console contents by TFTP."))))))
500 (catch :top-level-repl
; If restarts don't work, you can throw this..
501 (with-simple-restart (abort "Abort to the top command level.")
502 (read-eval-print)))))))
504 (error "What's up? [~S]" 'hey
))
506 (defun read (&optional input-stream eof-error-p eof-value recursive-p
)
507 (declare (ignore input-stream recursive-p
))
508 (let ((string (muerte.readline
:contextual-readline
*repl-readline-context
*)))
509 (simple-read-from-string string eof-error-p eof-value
)))