ooh, timer works fine in isolation
Acknowledging the interrupt is necessary.
This commit is contained in:
parent
f25b8e6e41
commit
5616691621
|
@ -0,0 +1,416 @@
|
|||
# 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
|
||||
b0/copy-to-al 0xfe/imm8 # disable mask for IRQ0
|
||||
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
|
||||
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
00 00 00 00 00 00 00 00
|
||||
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 = *Current-color
|
||||
8b/-> *Current-color 1/r32/ecx
|
||||
# increment *Current-color
|
||||
81 0/subop/add *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
|
||||
|
||||
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
|
||||
# }}}
|
||||
|
||||
Current-color:
|
||||
0/imm32
|
||||
|
||||
# vim:ft=subx
|
Loading…
Reference in New Issue