From f1a8fd095e82249ec17894444283c81a9bd0d90d Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Tue, 20 Feb 2024 18:14:17 -0500 Subject: [PATCH 01/11] serial: Rename *debug-serial-at-line-start* --- supervisor/serial.lisp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index e02ef543f..4a2223415 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -108,7 +108,7 @@ (sys.int::defglobal *debug-serial-read-fn*) (sys.int::defglobal *debug-serial-write-fn*) (sys.int::defglobal *debug-serial-lock*) -(sys.int::defglobal *serial-at-line-start*) +(sys.int::defglobal *debug-serial-at-line-start*) ;; Low-level byte functions. @@ -142,11 +142,11 @@ ;; end of the port uses UTF-8 with CRLF newlines. (defun debug-serial-write-char (char) - (setf *serial-at-line-start* nil) + (setf *debug-serial-at-line-start* nil) ;; FIXME: Should write all the bytes to the buffer in one go. ;; Other processes may interfere. (cond ((eql char #\Newline) - (setf *serial-at-line-start* t) + (setf *debug-serial-at-line-start* t) ;; Turn #\Newline into CRLF (debug-serial-write-byte #x0D) (debug-serial-write-byte #x0A)) @@ -160,12 +160,12 @@ (dotimes (i (string-length string)) (let ((char (char string i))) (cond ((eql char #\Newline) - (setf *serial-at-line-start* t) + (setf *debug-serial-at-line-start* t) ;; Turn #\Newline into CRLF (debug-serial-write-byte-1 #x0D) (debug-serial-write-byte-1 #x0A)) (t - (setf *serial-at-line-start* nil) + (setf *debug-serial-at-line-start* nil) (with-utf-8-bytes (char byte) (debug-serial-write-byte-1 byte))))))))) @@ -179,12 +179,12 @@ (dotimes (i (cdr buf)) (let ((byte (aref buf-data (the fixnum i)))) (cond ((eql byte #.(char-code #\Newline)) - (setf *serial-at-line-start* t) + (setf *debug-serial-at-line-start* t) ;; Turn #\Newline into CRLF (debug-serial-write-byte-1 #x0D) (debug-serial-write-byte-1 #x0A)) (t - (setf *serial-at-line-start* nil) + (setf *debug-serial-at-line-start* nil) (debug-serial-write-byte-1 byte))))))))) (defun debug-serial-stream (op &optional arg) @@ -195,7 +195,7 @@ (:write-string (debug-serial-write-string arg)) (:flush-buffer (debug-serial-flush-buffer arg)) (:force-output) - (:start-line-p *serial-at-line-start*))) + (:start-line-p *debug-serial-at-line-start*))) (defun initialize-debug-serial (io-port io-shift io-read-fn io-write-fn irq baud &optional (reinit t)) (declare (ignore irq)) @@ -204,7 +204,7 @@ *debug-serial-read-fn* io-read-fn *debug-serial-write-fn* io-write-fn *debug-serial-lock* :unlocked - *serial-at-line-start* t) + *debug-serial-at-line-start* t) ;; Initialize port. (when reinit (let ((divisor (truncate 115200 baud))) From 3ae90cd613079775f238937b48e33b5a6af01ed9 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Thu, 20 Feb 2025 18:14:31 -0500 Subject: [PATCH 02/11] serial: Implement debug-serial-read-byte-1-blocking --- supervisor/serial.lisp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index 4a2223415..b8e026c74 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -231,3 +231,11 @@ ;; Enable RX interrupts. (uart-16550-reg +serial-IER+) +serial-ier-received-data-available+))) (debug-set-output-pseudostream 'debug-serial-stream)) + +(defun debug-serial-read-byte-1-blocking () + ;; Wait for the RX FIFO to have data available. + (loop + until (logbitp +serial-lsr-data-available+ + (uart-16550-reg +serial-LSR+))) + ;; Read byte. + (uart-16550-reg +serial-THR+)) From a6bae99b3f5b2fbf638e82c91c359dae8ad3b68e Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Tue, 20 Feb 2024 18:15:01 -0500 Subject: [PATCH 03/11] serial: Implement debug-serial-read-byte --- supervisor/serial.lisp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index b8e026c74..4b9e9bebb 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -109,6 +109,8 @@ (sys.int::defglobal *debug-serial-write-fn*) (sys.int::defglobal *debug-serial-lock*) (sys.int::defglobal *debug-serial-at-line-start*) +(sys.int::defglobal *debug-serial-irq*) +(sys.int::defglobal *debug-serial-irq-handler*) ;; Low-level byte functions. @@ -198,7 +200,6 @@ (:start-line-p *debug-serial-at-line-start*))) (defun initialize-debug-serial (io-port io-shift io-read-fn io-write-fn irq baud &optional (reinit t)) - (declare (ignore irq)) (setf *debug-serial-io-port* io-port *debug-serial-io-shift* io-shift *debug-serial-read-fn* io-read-fn @@ -209,6 +210,8 @@ (when reinit (let ((divisor (truncate 115200 baud))) (setf + *debug-serial-irq* irq + *debug-serial-irq-handler* nil ;; Turn interrupts off. (uart-16550-reg +serial-IER+) #x00 ;; DLAB on. @@ -239,3 +242,17 @@ (uart-16550-reg +serial-LSR+))) ;; Read byte. (uart-16550-reg +serial-THR+)) + +(defun debug-serial-read-byte () + ;; IRQ initialization cannot be done in initialize-debug-serial + ;; because it is called very early during boot, before interrupt + ;; objects exist. Calling make-simple-irq there causes the boot to + ;; hang just before "Hello, Debug World!" is printed. Initialize + ;; IRQ during the first debug-serial-read-byte call instead. + (unless *debug-serial-irq-handler* + (setf *debug-serial-irq-handler* (make-simple-irq *debug-serial-irq*)) + (simple-irq-attach *debug-serial-irq-handler*) + (simple-irq-unmask *debug-serial-irq-handler*)) + (mezzano.sync::wait-for-objects *debug-serial-irq-handler*) + (prog1 (debug-serial-read-byte-1-blocking) + (mezzano.supervisor:simple-irq-unmask *debug-serial-irq-handler*))) From 4142bb85dfac4ae8def8e339bbb67addd1bebfa0 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Mon, 19 Feb 2024 22:17:12 -0500 Subject: [PATCH 04/11] serial: Implement debug-serial-read-char --- supervisor/serial.lisp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index 4b9e9bebb..d752133be 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -191,7 +191,7 @@ (defun debug-serial-stream (op &optional arg) (ecase op - (:read-char (panic "Serial read char not implemented.")) + (:read-char (debug-serial-read-char)) (:clear-input) (:write-char (debug-serial-write-char arg)) (:write-string (debug-serial-write-string arg)) @@ -256,3 +256,26 @@ (mezzano.sync::wait-for-objects *debug-serial-irq-handler*) (prog1 (debug-serial-read-byte-1-blocking) (mezzano.supervisor:simple-irq-unmask *debug-serial-irq-handler*))) + +(defun utf8-sequence-length (byte) + (cond + ((eql (logand byte #x80) #x00) + (values 1 byte)) + ((eql (logand byte #xE0) #xC0) + (values 2 (logand byte #x1F))) + ((eql (logand byte #xF0) #xE0) + (values 3 (logand byte #x0F))) + ((eql (logand byte #xF8) #xF0) + (values 4 (logand byte #x07))) + (t (error "Invalid UTF-8 lead byte ~S." byte)))) + +(defun debug-serial-read-char () + (multiple-value-bind (length value) + (utf8-sequence-length (debug-serial-read-byte)) + ;; Read remaining bytes. They must all be continuation bytes. + (dotimes (i (1- length)) + (let ((byte (debug-serial-read-byte))) + (unless (eql (logand byte #xC0) #x80) + (error "Invalid UTF-8 continuation byte ~S." byte)) + (setf value (logior (ash value 6) (logand byte #x3F))))) + (code-char value))) From bf9843478b9e69a498f9c69db6ad154bcd5581c9 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Tue, 20 Feb 2024 18:15:25 -0500 Subject: [PATCH 05/11] system/debug: Fix a compiler warning --- system/debug.lisp | 1 + 1 file changed, 1 insertion(+) diff --git a/system/debug.lisp b/system/debug.lisp index 7f49fe615..79421ed26 100644 --- a/system/debug.lisp +++ b/system/debug.lisp @@ -596,6 +596,7 @@ executed, and the offset into it." (defgeneric function-source-location (function &key)) (defmethod function-source-location ((function compiled-function) &key (offset 0)) + (declare (ignore offset)) (let* ((info (function-debug-info function)) (pathname (mezzano.internals::debug-info-source-pathname info)) (tlf (mezzano.internals::debug-info-source-top-level-form-number info))) From 3252c112c32b6bd2d91b162a85bf00ce935da2cb Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Tue, 20 Feb 2024 18:15:44 -0500 Subject: [PATCH 06/11] system/debug: Implement debug-serial REPL --- system/debug.lisp | 39 +++++++++++++++++++++++ tools/cold-generator2/cold-generator.lisp | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/system/debug.lisp b/system/debug.lisp index 79421ed26..cdb7aca0f 100644 --- a/system/debug.lisp +++ b/system/debug.lisp @@ -910,3 +910,42 @@ executed, and the offset into it." (defmethod function-lambda-list ((function mezzano.clos:generic-function)) (mezzano.clos:generic-function-lambda-list function)) + +;;; A REPL for the debug serial port. + +(defclass debug-serial-repl (mezzano.gray:unread-char-mixin + mezzano.gray:fundamental-character-input-stream + mezzano.gray:fundamental-character-output-stream) + ((%thread :initarg :thread :reader thread))) + +(defmethod mezzano.gray:stream-read-char ((stream debug-serial-repl)) + (mezzano.supervisor::debug-serial-read-char)) + +(defmethod mezzano.gray:stream-terpri ((stream debug-serial-repl)) + (mezzano.supervisor::debug-serial-write-char #\Newline)) + +(defmethod mezzano.gray:stream-write-char ((stream debug-serial-repl) character) + (mezzano.supervisor::debug-serial-write-char character)) + +(defmethod mezzano.gray:stream-start-line-p ((stream debug-serial-repl)) + mezzano.supervisor::*debug-serial-at-line-start*) + +(defmethod mezzano.gray:stream-line-column ((stream debug-serial-repl)) + nil) + +(defun debug-serial-repl-main () + (let* ((terminal (make-instance 'debug-serial-repl + :thread (mezzano.supervisor:current-thread))) + (*terminal-io* terminal) + (*standard-input* (make-synonym-stream '*terminal-io*)) + (*standard-output* *standard-input*) + (*error-output* *standard-input*) + (*query-io* *standard-input*) + (*trace-output* *standard-input*) + (*debug-io* *standard-input*)) + (mezzano.internals::repl))) + +(defun debug-serial-repl-start (&rest args) + (mezzano.supervisor:make-thread + (lambda () (apply #'debug-serial-repl-main args)) + :name "Debug Serial Lisp Listener")) diff --git a/tools/cold-generator2/cold-generator.lisp b/tools/cold-generator2/cold-generator.lisp index eef87c214..d0e3422bf 100644 --- a/tools/cold-generator2/cold-generator.lisp +++ b/tools/cold-generator2/cold-generator.lisp @@ -148,12 +148,12 @@ "system/condition.lisp" "system/error.lisp" "system/coerce.lisp" + "system/gray-streams.lisp" ; before system/debug for debug-serial-repl "system/debug.lisp" "system/dispatch.lisp" "system/full-eval.lisp" "system/fast-eval.lisp" "system/eval.lisp" - "system/gray-streams.lisp" "system/external-format.lisp" "system/standard-streams.lisp" "system/stream.lisp" From 06500aa36ade299020aae161edb51fbff910bf7e Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Thu, 29 May 2025 19:41:44 -0400 Subject: [PATCH 07/11] serial: Factor out initialize-debug-serial-reads logic --- compiler/package.lisp | 2 ++ supervisor/serial.lisp | 6 ++++-- system/debug.lisp | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/package.lisp b/compiler/package.lisp index 783de3f3f..dde928f7d 100644 --- a/compiler/package.lisp +++ b/compiler/package.lisp @@ -685,6 +685,8 @@ #:dma-buffer-n-sg-entries #:dma-buffer-sg-entry #:dma-buffer-sg-entry-list + + #:initialize-debug-serial-reads )) ;;; Runtime contains a bunch of low-level and common functions required to diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index d752133be..0b1bcbd0c 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -243,7 +243,7 @@ ;; Read byte. (uart-16550-reg +serial-THR+)) -(defun debug-serial-read-byte () +(defun initialize-debug-serial-reads () ;; IRQ initialization cannot be done in initialize-debug-serial ;; because it is called very early during boot, before interrupt ;; objects exist. Calling make-simple-irq there causes the boot to @@ -252,7 +252,9 @@ (unless *debug-serial-irq-handler* (setf *debug-serial-irq-handler* (make-simple-irq *debug-serial-irq*)) (simple-irq-attach *debug-serial-irq-handler*) - (simple-irq-unmask *debug-serial-irq-handler*)) + (simple-irq-unmask *debug-serial-irq-handler*))) + +(defun debug-serial-read-byte () (mezzano.sync::wait-for-objects *debug-serial-irq-handler*) (prog1 (debug-serial-read-byte-1-blocking) (mezzano.supervisor:simple-irq-unmask *debug-serial-irq-handler*))) diff --git a/system/debug.lisp b/system/debug.lisp index cdb7aca0f..34e89b961 100644 --- a/system/debug.lisp +++ b/system/debug.lisp @@ -946,6 +946,7 @@ executed, and the offset into it." (mezzano.internals::repl))) (defun debug-serial-repl-start (&rest args) + (mezzano.supervisor:initialize-debug-serial-reads) (mezzano.supervisor:make-thread (lambda () (apply #'debug-serial-repl-main args)) :name "Debug Serial Lisp Listener")) From 93efe519ccdec66fc6debab39f0ca0779f09d6bc Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Thu, 29 May 2025 19:42:40 -0400 Subject: [PATCH 08/11] serial: Echo character received by debug-serial-read-char --- supervisor/serial.lisp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/supervisor/serial.lisp b/supervisor/serial.lisp index 0b1bcbd0c..deaa05abf 100644 --- a/supervisor/serial.lisp +++ b/supervisor/serial.lisp @@ -280,4 +280,6 @@ (unless (eql (logand byte #xC0) #x80) (error "Invalid UTF-8 continuation byte ~S." byte)) (setf value (logior (ash value 6) (logand byte #x3F))))) - (code-char value))) + (let ((result (code-char value))) + (debug-serial-write-char result) + result))) From 93bd61576dcff8889a1d5bf9e58b7d21c4bfd689 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Thu, 29 May 2025 19:58:43 -0400 Subject: [PATCH 09/11] system/debug: Add debug-serial-repl-stop --- system/debug.lisp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/debug.lisp b/system/debug.lisp index 34e89b961..934e8c28e 100644 --- a/system/debug.lisp +++ b/system/debug.lisp @@ -950,3 +950,8 @@ executed, and the offset into it." (mezzano.supervisor:make-thread (lambda () (apply #'debug-serial-repl-main args)) :name "Debug Serial Lisp Listener")) + +(defun debug-serial-repl-stop () + (dolist (thread (mezzano.supervisor:all-threads)) + (when (equal (mezzano.supervisor:thread-name thread) "Debug Serial Lisp Listener") + (mezzano.supervisor:terminate-thread thread)))) From 122d5f75ad954b2222c8b5f552eaa116de22c17e Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Thu, 29 May 2025 20:01:25 -0400 Subject: [PATCH 10/11] system/debug: Add reinitialization logic to debug-serial-repl-start --- compiler/package.lisp | 1 + system/debug.lisp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/compiler/package.lisp b/compiler/package.lisp index dde928f7d..1b7f60e82 100644 --- a/compiler/package.lisp +++ b/compiler/package.lisp @@ -686,6 +686,7 @@ #:dma-buffer-sg-entry #:dma-buffer-sg-entry-list + #:initialize-debug-serial #:initialize-debug-serial-reads )) diff --git a/system/debug.lisp b/system/debug.lisp index 934e8c28e..9e7322306 100644 --- a/system/debug.lisp +++ b/system/debug.lisp @@ -946,6 +946,15 @@ executed, and the offset into it." (mezzano.internals::repl))) (defun debug-serial-repl-start (&rest args) + #+(not x86-64) + (error "debug-serial-repl is not yet implemented on this architecture. Please file a feature request.") + (debug-serial-repl-stop) + (let ((interrupt 4)) + ;; Remove existing interrupt handlers. + (setf (mezzano.supervisor::irq-attachments (mezzano.supervisor::platform-irq interrupt)) nil) + ;; Make sure debug pseudostream is set to debug-serial-stream. + (mezzano.supervisor:initialize-debug-serial + #x3F8 0 #'sys.int::io-port/8 #'(setf sys.int::io-port/8) interrupt 115200)) (mezzano.supervisor:initialize-debug-serial-reads) (mezzano.supervisor:make-thread (lambda () (apply #'debug-serial-repl-main args)) From d8a3033fd1e40347bd80ded1ecef3e6b507ca370 Mon Sep 17 00:00:00 2001 From: Thomas Fitzsimmons Date: Sun, 1 Jun 2025 18:47:56 -0400 Subject: [PATCH 11/11] ipl: Start REPL on serial port when video-console is disabled --- ipl.lisp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ipl.lisp b/ipl.lisp index 7b64f05d1..1e71da385 100644 --- a/ipl.lisp +++ b/ipl.lisp @@ -282,6 +282,12 @@ Make sure there is a virtio-net NIC attached.~%") sys.int::*init-file-path* c))))) +(mezzano.supervisor:add-boot-hook + #'(lambda () + (unless (mezzano.supervisor:boot-option + mezzano.supervisor:+boot-option-video-console+) + ;; Start a REPL on the debug serial port. + (sys.int::debug-serial-repl-start)))) (mezzano.supervisor:add-boot-hook 'sys.int::load-init-file :late) (sys.int::load-init-file)