about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--boot.subx30
-rw-r--r--timer.subx464
2 files changed, 26 insertions, 468 deletions
diff --git a/boot.subx b/boot.subx
index 287c6877..2a896a97 100644
--- a/boot.subx
+++ b/boot.subx
@@ -302,11 +302,11 @@ idt_start:
 # https://wiki.osdev.org/index.php?title=Interrupts&oldid=25102#Default_PC_Interrupt_Vector_Assignment
 
 # entry 8: https://wiki.osdev.org/Programmable_Interval_Timer
-  null-interrupt-handler/imm16  # target[0:16]
+  timer-interrupt-handler/imm16  # target[0:16]
   8/imm16  # segment selector (gdt_code)
   00  # unused
   8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
-  0/imm16  # target[16:32] -- null-interrupt-handler must be within address 0x10000
+  0/imm16  # target[16:32] -- timer-interrupt-handler must be within address 0x10000
 
 # entry 9: keyboard
   keyboard-interrupt-handler/imm16  # target[0:16]
@@ -342,7 +342,7 @@ idt_start:
 
 == code
 
-null-interrupt-handler:
+timer-interrupt-handler:
   # prologue
   fa/disable-interrupts
   60/push-all-registers
@@ -351,13 +351,35 @@ null-interrupt-handler:
   b0/copy-to-al 0x20/imm8
   e6/write-al-into-port 0x20/imm8
   31/xor %eax 0/r32/eax
-$null-interrupt-handler:end:
+  # ecx = *Timer-current-color
+  8b/-> *Timer-current-color 1/r32/ecx
+  # update *Timer-current-color
+  81 0/subop/add *Timer-current-color 0x01010101/imm32
+  # eax = *Video-memory + 0x1200 (a few rows down from top, around middle of screen)
+  8b/-> *Video-memory-addr 0/r32/eax
+  05/add-to-eax 0x1200/imm32
+  89/copy *eax 1/r32/ecx
+  # eax += 0x400
+  05/add-to-eax 0x400/imm32
+  89/copy *eax 1/r32/ecx
+  # eax += 0x400
+  05/add-to-eax 0x400/imm32
+  89/copy *eax 1/r32/ecx
+  # eax += 0x400
+  05/add-to-eax 0x400/imm32
+  89/copy *eax 1/r32/ecx
+$timer-interrupt-handler:epilogue:
   # epilogue
   9d/pop-flags
   61/pop-all-registers
   fb/enable-interrupts
   cf/return-from-interrupt
 
+== data
+Timer-current-color:
+  0/imm32
+
+== code
 keyboard-interrupt-handler:
   # prologue
   fa/disable-interrupts
diff --git a/timer.subx b/timer.subx
deleted file mode 100644
index 89c5ef6d..00000000
--- a/timer.subx
+++ /dev/null
@@ -1,464 +0,0 @@
-# Example bootloader that handles just the timer interrupt.
-#
-# Code for the first few disk sectors that all programs in this directory need:
-#   - load sectors past the first (using BIOS primitives) since only the first is available by default
-#     - if this fails, print 'D' at top-left of screen and halt
-#   - initialize a minimal graphics mode
-#   - switch to 32-bit mode (giving up access to BIOS primitives)
-#   - set up a handler for keyboard events
-#   - jump to start of program
-
-# Code in this file needs to be more deliberate about the SubX facilities it
-# uses:
-#   - sigils only support 32-bit general-purpose registers, so don't work with segment registers or 16-bit or 8-bit registers
-#   - metadata like rm32 and r32 can sometimes misleadingly refer to only the bottom 16 bits of the register; pay attention to the register name
-#
-# While most of Mu is thoroughly tested, this file is not. I don't yet
-# understand hardware interfaces well enough to explain to others.
-
-# Memory map of a Mu computer:
-#   code: currently 4 tracks loaded from the primary disk to [0x00007c00, 0x00048600)
-#   stack: grows down from 0x02000000 to 0x01000000
-#   heap: [0x02000000, 0x08000000)
-#     see 120allocate.subx; Qemu initializes with 128MB RAM by default
-# Consult https://wiki.osdev.org/Memory_Map_(x86) before modifying any of
-# this. And don't forget to keep *stack-debug.subx in sync.
-
-== code
-
-## 16-bit entry point: 0x7c00
-
-# Upon reset, the IBM PC:
-#   - loads the first sector (512 bytes)
-#     from some bootable image (look for the boot-sector-marker further down this file)
-#     to the address range [0x7c00, 0x7e00)
-#   - starts executing code at address 0x7c00
-
-  fa/disable-interrupts
-
-  # initialize segment registers
-  b8/copy-to-ax 0/imm16
-  8e/->seg 3/mod/direct 0/rm32/ax 3/r32/ds
-  8e/->seg 3/mod/direct 0/rm32/ax 0/r32/es
-  8e/->seg 3/mod/direct 0/rm32/ax 4/r32/fs
-  8e/->seg 3/mod/direct 0/rm32/ax 5/r32/gs
-
-  # Temporarily initialize stack to 0x00070000 in real mode.
-  # We don't read or write the stack before we get to 32-bit mode, but BIOS
-  # calls do. We need to move the stack in case BIOS initializes it to some
-  # low address that we want to write code into.
-  b8/copy-to-ax 0x7000/imm16
-  8e/->seg 3/mod/direct 0/rm32/ax 2/r32/ss
-  bc/copy-to-esp 0/imm16
-
-  # undo the A20 hack: https://en.wikipedia.org/wiki/A20_line
-  # this is from https://github.com/mit-pdos/xv6-public/blob/master/bootasm.S
-  {
-    e4/read-port-into-al 0x64/imm8
-    a8/test-bits-in-al 0x02/imm8  # set zf if bit 1 (second-least significant) is not set
-    75/jump-if-!zero loop/disp8
-    b0/copy-to-al 0xd1/imm8
-    e6/write-al-into-port 0x64/imm8
-  }
-  {
-    e4/read-port-into-al 0x64/imm8
-    a8/test-bits-in-al 0x02/imm8  # set zf if bit 1 (second-least significant) is not set
-    75/jump-if-!zero loop/disp8
-    b0/copy-to-al 0xdf/imm8
-    e6/write-al-into-port 0x64/imm8
-  }
-
-  # load remaining sectors from first two tracks of disk into addresses [0x7e00, 0x17800)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 0/imm8/head                   # <====
-  b1/copy-to-cl 2/imm8/sector  # 1-based
-  b0/copy-to-al 0x7d/imm8/num-sectors  # 2*63 - 1 = 125
-  # address to write sectors to = es:bx = 0x7e00, contiguous with boot segment
-  bb/copy-to-bx 0/imm16
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0x7e00/imm16                  # <====
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # load two more tracks of disk into addresses [0x17800, 0x27400)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 2/imm8/head                   # <====
-  b1/copy-to-cl 1/imm8/sector  # 1-based
-  b0/copy-to-al 0x7e/imm8/num-sectors  # 2*63 = 126
-  # address to write sectors to = es:bx = 0x17800, contiguous with boot segment
-  bb/copy-to-bx 0x1780/imm16                  # <====
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0/imm16
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # load two more tracks of disk into addresses [0x27400, 0x37000)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 4/imm8/head                   # <====
-  b1/copy-to-cl 1/imm8/sector  # 1-based
-  b0/copy-to-al 0x7e/imm8/num-sectors  # 2*63 = 126
-  # address to write sectors to = es:bx = 0x27400, contiguous with boot segment
-  bb/copy-to-bx 0x2740/imm16                  # <====
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0/imm16
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # load two more tracks of disk into addresses [0x37000, 0x46c00)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 6/imm8/head                   # <====
-  b1/copy-to-cl 1/imm8/sector  # 1-based
-  b0/copy-to-al 0x7e/imm8/num-sectors  # 2*63 = 126
-  # address to write sectors to = es:bx = 0x37000, contiguous with boot segment
-  bb/copy-to-bx 0x3700/imm16                  # <====
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0/imm16
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # load two more tracks of disk into addresses [0x46c00, 0x56800)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 8/imm8/head                   # <====
-  b1/copy-to-cl 1/imm8/sector  # 1-based
-  b0/copy-to-al 0x7e/imm8/num-sectors  # 2*63 = 126
-  # address to write sectors to = es:bx = 0x46c00, contiguous with boot segment
-  bb/copy-to-bx 0x46c0/imm16                  # <====
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0/imm16
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # load two more tracks of disk into addresses [0x56800, 0x66400)
-  b4/copy-to-ah 2/imm8/read-drive
-  # dl comes conveniently initialized at boot time with the index of the device being booted
-  b5/copy-to-ch 0/imm8/cylinder
-  b6/copy-to-dh 0xa/imm8/head                 # <====
-  b1/copy-to-cl 1/imm8/sector  # 1-based
-  b0/copy-to-al 0x7e/imm8/num-sectors  # 2*63 = 126
-  # address to write sectors to = es:bx = 0x56800, contiguous with boot segment
-  bb/copy-to-bx 0x5680/imm16                  # <====
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-  bb/copy-to-bx 0/imm16
-  cd/syscall 0x13/imm8/bios-disk-services
-  0f 82/jump-if-carry disk_error/disp16
-
-  # reset es
-  bb/copy-to-bx 0/imm16
-  8e/->seg 3/mod/direct 3/rm32/bx 0/r32/es
-
-  # adjust video mode
-  b4/copy-to-ah 0x4f/imm8  # VBE commands
-  b0/copy-to-al 2/imm8  # set video mode
-  bb/copy-to-bx 0x4105/imm16  # 0x0105 | 0x4000
-                              # 0x0105 = graphics mode 1024x768x256
-                              #  (alternative candidate: 0x0101 for 640x480x256)
-                              # 0x4000 bit = configure linear frame buffer in Bochs emulator; hopefully this doesn't hurt anything when running natively
-  cd/syscall 0x10/imm8/bios-video-services
-
-  # load information for the (hopefully) current video mode
-  # mostly just for the address to the linear frame buffer
-  b4/copy-to-ah 0x4f/imm8  # VBE commands
-  b0/copy-to-al 1/imm8  # get video mode info
-  b9/copy-to-cx 0x0105/imm16  # mode we requested
-  bf/copy-to-di Video-mode-info/imm16
-  cd/syscall 0x10/imm8/bios-video-services
-
-  ## switch to 32-bit mode
-  # load global descriptor table
-  # We can't refer to the label directly because SubX doesn't do the right
-  # thing for lgdt, so rather than make errors worse in most places we instead
-  # pin gdt_descriptor below.
-  0f 01 2/subop/lgdt 0/mod/indirect 6/rm32/use-disp16 0x7de0/disp16/gdt_descriptor
-  # enable paging
-  0f 20/<-cr 3/mod/direct 0/rm32/eax 0/r32/cr0
-  66 83 1/subop/or 3/mod/direct 0/rm32/eax 1/imm8  # eax <- or 0x1
-  0f 22/->cr 3/mod/direct 0/rm32/eax 0/r32/cr0
-  # far jump to initialize_32bit_mode that sets cs to offset 8 in the gdt in the process
-  # We can't refer to the label directly because SubX doesn't have syntax for
-  # segment selectors. So we instead pin initialize_32bit_mode below.
-  ea/jump-far-absolute 0x00087e00/disp32  # address 0x7e00 in offset 8 of the gdt
-
-disk_error:
-  # print 'D' to top-left of screen to indicate disk error
-  # *0xb8000 <- 0x0f44
-  bb/copy-to-bx 0xb800/imm16
-  8e/->seg 3/mod/direct 3/rm32/bx 3/r32/ds
-  b0/copy-to-al 0x44/imm8/D
-  b4/copy-to-ah 0x0f/imm8/white-on-black
-  bb/copy-to-bx 0/imm16
-  89/<- 0/mod/indirect 7/rm32/bx 0/r32/ax  # *ds:bx <- ax
-  # loop forever
-  {
-    eb/jump loop/disp8
-  }
-
-## GDT: 3 records of 8 bytes each
-== data 0x7de0
-gdt_descriptor:
-  0x17/imm16  # final index of gdt = size of gdt - 1
-  gdt_start/imm32/start
-
-gdt_start:
-# offset 0: gdt_null:  mandatory null descriptor
-  00 00 00 00 00 00 00 00
-# offset 8: gdt_code
-  ff ff  # limit[0:16]
-  00 00 00  # base[0:24]
-  9a  # 1/present 00/privilege 1/descriptor type = 1001b
-      # 1/code 0/conforming 1/readable 0/accessed = 1010b
-  cf  # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b
-      # limit[16:20] = 1111b
-  00  # base[24:32]
-# offset 16: gdt_data
-  ff ff  # limit[0:16]
-  00 00 00  # base[0:24]
-  92  # 1/present 00/privilege 1/descriptor type = 1001b
-      # 0/data 0/conforming 1/readable 0/accessed = 0010b
-  cf  # same as gdt_code
-  00  # base[24:32]
-# gdt_end:
-
-== boot-sector-marker 0x7dfe
-# final 2 bytes of boot sector
-55 aa
-
-## sector 2 onwards loaded by load_disk, not automatically on boot
-
-## 32-bit code from this point
-
-== code 0x7e00
-initialize_32bit_mode:
-  66 b8/copy-to-ax 0x10/imm16  # offset 16 from gdt_start
-  8e/->seg 3/mod/direct 0/rm32/ax 3/r32/ds
-  8e/->seg 3/mod/direct 0/rm32/ax 2/r32/ss
-  8e/->seg 3/mod/direct 0/rm32/ax 0/r32/es
-  8e/->seg 3/mod/direct 0/rm32/ax 4/r32/fs
-  8e/->seg 3/mod/direct 0/rm32/ax 5/r32/gs
-
-  bc/copy-to-esp 0x02000000/imm32
-
-  ## load interrupt handlers
-  # We can't refer to the label directly because SubX doesn't do the right
-  # thing for lidt, so rather than make errors worse in most places we instead
-  # pin idt_descriptor below.
-  0f 01 3/subop/lidt 0/mod/indirect 5/rm32/use-disp32 0x7f00/disp32/idt_descriptor
-
-  # enable timer IRQ0 and keyboard IRQ1
-  b0/copy-to-al 0xfc/imm8  # disable mask for IRQ0 and IRQ1
-  e6/write-al-into-port 0x21/imm8
-
-  fb/enable-interrupts
-
-  {
-    eb/jump loop/disp8
-  }
-
-== data 0x7f00
-idt_descriptor:
-  ff 03  # final index of idt = size of idt - 1
-  idt_start/imm32/start
-
-# interrupt descriptor table {{{
-# 32 entries of 8 bytes each
-idt_start:
-
-# entry 0
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-
-# By default, BIOS maps IRQ0-7 to interrupt vectors 8-15.
-# https://wiki.osdev.org/index.php?title=Interrupts&oldid=25102#Default_PC_Interrupt_Vector_Assignment
-
-# entry 8: https://wiki.osdev.org/Programmable_Interval_Timer
-  timer-interrupt-handler/imm16  # target[0:16]
-  8/imm16  # segment selector (gdt_code)
-  00  # unused
-  8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
-  0/imm16  # target[16:32] -- timer-interrupt-handler must be within address 0x10000
-
-# entry 9: keyboard
-  keyboard-interrupt-handler/imm16  # target[0:16]
-  8/imm16  # segment selector (gdt_code)
-  00  # unused
-  8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
-  0/imm16  # target[16:32] -- keyboard-interrupt-handler must be within address 0x10000
-
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00
-# idt_end:
-# }}}
-
-== code
-
-timer-interrupt-handler:
-  # prologue
-  fa/disable-interrupts
-  60/push-all-registers
-  9c/push-flags
-  # acknowledge interrupt
-  b0/copy-to-al 0x20/imm8
-  e6/write-al-into-port 0x20/imm8
-  31/xor %eax 0/r32/eax
-  # ecx = *Timer-current-color
-  8b/-> *Timer-current-color 1/r32/ecx
-  # update *Timer-current-color
-  81 0/subop/add *Timer-current-color 0x01010101/imm32
-  # eax = *Video-memory + 0x1200 (a few rows down from top, around middle of screen)
-  8b/-> *Video-memory-addr 0/r32/eax
-  05/add-to-eax 0x1200/imm32
-  89/copy *eax 1/r32/ecx
-  # eax += 0x400
-  05/add-to-eax 0x400/imm32
-  89/copy *eax 1/r32/ecx
-  # eax += 0x400
-  05/add-to-eax 0x400/imm32
-  89/copy *eax 1/r32/ecx
-  # eax += 0x400
-  05/add-to-eax 0x400/imm32
-  89/copy *eax 1/r32/ecx
-$timer-interrupt-handler:epilogue:
-  # epilogue
-  9d/pop-flags
-  61/pop-all-registers
-  fb/enable-interrupts
-  cf/return-from-interrupt
-
-keyboard-interrupt-handler:
-  # prologue
-  fa/disable-interrupts
-  60/push-all-registers
-  9c/push-flags
-  # acknowledge interrupt
-  b0/copy-to-al 0x20/imm8
-  e6/write-al-into-port 0x20/imm8
-  31/xor %eax 0/r32/eax
-  # check output buffer of 8042 keyboard controller (https://web.archive.org/web/20040604041507/http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html)
-  e4/read-port-into-al 0x64/imm8
-  a8/test-bits-in-al 0x01/imm8  # set zf if bit 0 (least significant) is not set
-  0f 84/jump-if-not-set $keyboard-interrupt-handler:epilogue/disp32
-  # initialize current-pixel-location if necessary
-  81 7/subop/compare *Keyboard-current-pixel 0/imm32
-  {
-    75/jump-if-!= break/disp8
-    8b/-> *Video-memory-addr 1/r32/ecx
-    89/<- *Keyboard-current-pixel 1/r32/ecx
-  }
-  # - read keycode
-  e4/read-port-into-al 0x60/imm8
-  # if (al & 0x80) a key is being lifted; return
-  50/push-eax
-  24/and-al-with 0x80/imm8
-  3c/compare-al-and 0/imm8
-  58/pop-to-eax
-  75/jump-if-!= $keyboard-interrupt-handler:epilogue/disp8
-  # key pressed
-  8b/-> *Keyboard-current-pixel 1/r32/ecx
-  c6 0/subop/copy-byte *ecx 0x31/imm8/green
-  ff 0/subop/increment *Keyboard-current-pixel
-$keyboard-interrupt-handler:epilogue:
-  # epilogue
-  9d/pop-flags
-  61/pop-all-registers
-  fb/enable-interrupts
-  cf/return-from-interrupt
-
-== data
-
-Video-mode-info:
-# video mode info {{{
-  0/imm16  # attributes
-  00  # winA
-  00  # winB
-# 04
-  0/imm16  # granularity
-  0/imm16  # winsize
-# 08
-  0/imm16  # segmentA
-  0/imm16  # segmentB
-# 0c
-  0/imm32  # realFctPtr (who knows)
-# 10
-  0/imm16  # pitch
-  0/imm16  # Xres
-  0/imm16  # Yres
-  0/imm16  # Wchar Ychar
-# 18
-  00  # planes
-  00  # bpp
-  00  # banks
-  00  # memory_model
-# 1c
-  00  # bank_size
-  00  # image_pages
-  00  # reserved
-# 1f
-  0/imm16  # red_mask red_position
-  0/imm16  # green_mask green_position
-  0/imm16  # blue_mask blue_position
-  0/imm16  # rsv_mask rsv_position
-  00  # directcolor_attributes
-# 28
-Video-memory-addr:
-  0/imm32  # physbase
-
-# 2c
-# reserved for video mode info
-                                    00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-# }}}
-
-Timer-current-color:
-  0/imm32
-
-Keyboard-current-pixel:
-  0/imm32
-
-# vim:ft=subx