Initial commit

This commit is contained in:
pjht 2024-03-19 09:23:45 -05:00
commit 92e9bda9bd
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
24 changed files with 2091 additions and 0 deletions

7
Tupfile Normal file
View File

@ -0,0 +1,7 @@
include_rules
LDFLAGS = -z max-page-size=4096 --orphan-handling=error -T kernel.ld
ASFLAGS = -m68010 -spaces -Felf -ldots -align -quiet -x -nowarn=62
: foreach *.68k | ../<include> |> vasmm68k_mot $(ASFLAGS) -I../sysroot/usr/include -o %o %f |> %B.o
: *.o | kernel.ld ../<libstd> |> m68k-elf-ld $(LDFLAGS) -o %o %f '%<libstd>' |> kernel

6
Tuprules.tup Normal file
View File

@ -0,0 +1,6 @@
.gitignore
LDFLAGS = -z max-page-size=4096 --orphan-handling=error
ASFLAGS = -m68010 -spaces -Felf -ldots -align -quiet -x -nowarn=62
!as = |> vasmm68k_mot $(ASFLAGS) -o %o %f |> %B.o
!ld = |> m68k-elf-ld $(LDFLAGS) -o %o %f $(LDLIBS) |>

39
cards.68k Normal file
View File

@ -0,0 +1,39 @@
section .text,text
; Finds the first card with the type in d0.b, and returns it's IO base address in a0, or 0 if not found
; Clobbers d1
; Warning to developers: This function must only use PC-relative addressing as it is called from early boot before the kernel is properly mapped.
public find_first_card
find_first_card:
move.l #$ff0000, a0 ; a0 holds the address of the current card
ffc_loop:
lea ($100,a0), a0 ; Move to the next card
move.w ($fe,a0), d1 ; Load the type of the card into d1
beq.b ffc_done ; If the type is 0 (empty slot), we have scanned all cards, so exit the loop
cmp.b d0, d1 ; If the card is the type we want, return with the address in a0
beq.b ffc_done
bra.b ffc_loop ; Loop back and check the next card
ffc_done:
rts
get_all_cards:
; Gets the indexes of the cards with the specified type
; a0 is a pointer to the buffer to store the results in
; d0 is the length of the buffer in 4 byte units
; d1 is the type of card to find
move.l #$ff0000, a1 ; a0 holds the address of the current card
gac_loop:
lea ($100,a1), a1 ; Move to the next card
move.w ($fe,a1), d2 ; Load the type of the card into d1
cmp.b d1, d2 ; Check whether the type of the current card is the type we want
bne.b gac_next ; Skip the card if it is not
move.l a1, (a0) ; Put the card base into the buffer
lea ($4,a0), a0 ; Move to the next buffer location
subq.w #1, d0 ; Decement the count of available buffer locations
gac_next:
cmpa.l #$ffff00, a1 ; Check if we have gone through all the cards
beq.b gac_done ; If so, return
cmpi.b #0, d0 ; Check if we have filled the buffer
beq.b gac_done ; If so, returm
bra.b gac_loop
gac_done:
rts

6
cards.i Normal file
View File

@ -0,0 +1,6 @@
ifnd CARDS_I
CARDS_I equ 1
; Finds the first card with the type in d0.b, and returns it's IO base address in a0, or 0 if not found
; Clobbers d1
xref find_first_card
endif

237
elf.i Normal file
View File

@ -0,0 +1,237 @@
ifnd ELF_I
ELF_I equ 1
clrso
Elf_Ehdr.ei_mag: so.b 4
Elf_Ehdr.ei_class: so.b 1
Elf_Ehdr.ei_data: so.b 1
Elf_Ehdr.ei_version so.b 1
Elf_Ehdr.ei_osabi: so.b 1
Elf_Ehdr.ei_padd: so.b 8
Elf_Ehdr.e_type: so.w 1
Elf_Ehdr.e_machine: so.w 1
Elf_Ehdr.e_version: so.l 1
Elf_Ehdr.sizeof equ __SO
Elf32_Ehdr.e_entry: so.l 1
Elf32_Ehdr.e_phoff: so.l 1
Elf32_Ehdr.e_shoff: so.l 1
Elf32_Ehdr.e_flags: so.l 1
Elf32_Ehdr.e_ehsize: so.w 1
Elf32_Ehdr.e_phentsize: so.w 1
Elf32_Ehdr.e_phnum: so.w 1
Elf32_Ehdr.e_shentsize: so.w 1
Elf32_Ehdr.e_shnum: so.w 1
Elf32_Ehdr.e_shstrndx: so.w 1
Elf32_Ehdr.sizeof equ __SO
ELFMAG0 equ $7f ; EI_MAG
ELFMAG1 equ 'E'
ELFMAG2 equ 'L'
ELFMAG3 equ 'F'
ELFCLASSNONE equ 0 ; EI_CLASS
ELFCLASS32 equ 1
ELFCLASS64 equ 2
ELFCLASSNUM equ 3
ELFDATANONE equ 0 ; EI_DATA
ELFDATA2LSB equ 1
ELFDATA2MSB equ 2
ELFDATANUM equ 3
ET_NONE equ 0 ; e_type
ET_REL equ 1
ET_EXEC equ 2
ET_DYN equ 3
ET_CORE equ 4
ET_NUM equ 5
ET_LOOS equ $fe00 ; OS specific range
ET_LOSUNW equ $feff
ET_SUNWPSEUDO equ $feff
ET_HISUNW equ $feff
ET_HIOS equ $feff
ET_LOPROC equ $ff00 ; processor specific range
ET_HIPROC equ $ffff
EM_NONE equ 0 ; e_machine
EM_M32 equ 1 ; AT&T WE 32100
EM_SPARC equ 2 ; Sun SPARC
EM_386 equ 3 ; Intel 80386
EM_68K equ 4 ; Motorola 68000
EM_88K equ 5 ; Motorola 88000
EM_486 equ 6 ; Intel 80486
EM_860 equ 7 ; Intel i860
EM_MIPS equ 8 ; MIPS RS3000 Big-Endian
EM_S370 equ 9 ; IBM System/370 Processor
EM_MIPS_RS3_LE equ 10 ; MIPS RS3000 Little-Endian
EM_RS6000 equ 11 ; RS6000
EM_UNKNOWN12 equ 12
EM_UNKNOWN13 equ 13
EM_UNKNOWN14 equ 14
EM_PA_RISC equ 15 ; PA-RISC
EM_nCUBE equ 16 ; nCUBE
EM_VPP500 equ 17 ; Fujitsu VPP500
EM_SPARC32PLUS equ 18 ; Sun SPARC 32+
EM_960 equ 19 ; Intel 80960
EM_PPC equ 20 ; PowerPC
EM_PPC64 equ 21 ; 64-bit PowerPC
EM_UNKNOWN22 equ 22
EM_UNKNOWN23 equ 23
EM_UNKNOWN24 equ 24
EM_UNKNOWN25 equ 25
EM_UNKNOWN26 equ 26
EM_UNKNOWN27 equ 27
EM_UNKNOWN28 equ 28
EM_UNKNOWN29 equ 29
EM_UNKNOWN30 equ 30
EM_UNKNOWN31 equ 31
EM_UNKNOWN32 equ 32
EM_UNKNOWN33 equ 33
EM_UNKNOWN34 equ 34
EM_UNKNOWN35 equ 35
EM_V800 equ 36 ; NEX V800
EM_FR20 equ 37 ; Fujitsu FR20
EM_RH32 equ 38 ; TRW RH-32
EM_RCE equ 39 ; Motorola RCE
EM_ARM equ 40 ; Advanced RISC Marchines ARM
EM_ALPHA equ 41 ; Digital Alpha
EM_SH equ 42 ; Hitachi SH
EM_SPARCV9 equ 43 ; Sun SPARC V9 (64-bit)
EM_TRICORE equ 44 ; Siemens Tricore embedded processor
EM_ARC equ 45 ; Argonaut RISC Core,
; Argonaut Technologies Inc.
EM_H8_300 equ 46 ; Hitachi H8/300
EM_H8_300H equ 47 ; Hitachi H8/300H
EM_H8S equ 48 ; Hitachi H8S
EM_H8_500 equ 49 ; Hitachi H8/500
EM_IA_64 equ 50 ; Intel IA64
EM_MIPS_X equ 51 ; Stanford MIPS-X
EM_COLDFIRE equ 52 ; Motorola ColdFire
EM_68HC12 equ 53 ; Motorola M68HC12
EM_MMA equ 54 ; Fujitsu MMA Mulimedia Accelerator
EM_PCP equ 55 ; Siemens PCP
EM_NCPU equ 56 ; Sony nCPU embedded RISC processor
EM_NDR1 equ 57 ; Denso NDR1 microprocessor
EM_STARCORE equ 58 ; Motorola Star*Core processor
EM_ME16 equ 59 ; Toyota ME16 processor
EM_ST100 equ 60 ; STMicroelectronics ST100 processor
EM_TINYJ equ 61 ; Advanced Logic Corp. TinyJ
; embedded processor family
EM_AMD64 equ 62 ; AMDs x86-64 architecture
EM_X86_64 equ EM_AMD64 ; (compatibility)
EM_PDSP equ 63 ; Sony DSP Processor
EM_UNKNOWN64 equ 64
EM_UNKNOWN65 equ 65
EM_FX66 equ 66 ; Siemens FX66 microcontroller
EM_ST9PLUS equ 67 ; STMicroelectronics ST9+8/16 bit
; microcontroller
EM_ST7 equ 68 ; STMicroelectronics ST7 8-bit
; microcontroller
EM_68HC16 equ 69 ; Motorola MC68HC16 Microcontroller
EM_68HC11 equ 70 ; Motorola MC68HC11 Microcontroller
EM_68HC08 equ 71 ; Motorola MC68HC08 Microcontroller
EM_68HC05 equ 72 ; Motorola MC68HC05 Microcontroller
EM_SVX equ 73 ; Silicon Graphics SVx
EM_ST19 equ 74 ; STMicroelectronics ST19 8-bit
; microcontroller
EM_VAX equ 75 ; Digital VAX
EM_CRIS equ 76 ; Axis Communications 32-bit
; embedded processor
EM_JAVELIN equ 77 ; Infineon Technologies 32-bit
; embedded processor
EM_FIREPATH equ 78 ; Element 14 64-bit DSP Processor
EM_ZSP equ 79 ; LSI Logic 16-bit DSP Processor
EM_MMIX equ 80 ; Donald Knuth's educational
; 64-bit processor
EM_HUANY equ 81 ; Harvard University
; machine-independent
; object files
EM_PRISM equ 82 ; SiTera Prism
EM_AVR equ 83 ; Atmel AVR 8-bit microcontroller
EM_FR30 equ 84 ; Fujitsu FR30
EM_D10V equ 85 ; Mitsubishi D10V
EM_D30V equ 86 ; Mitsubishi D30V
EM_V850 equ 87 ; NEC v850
EM_M32R equ 88 ; Mitsubishi M32R
EM_MN10300 equ 89 ; Matsushita MN10300
EM_MN10200 equ 90 ; Matsushita MN10200
EM_PJ equ 91 ; picoJava
EM_OPENRISC equ 92 ; OpenRISC 32-bit embedded processor
EM_ARC_A5 equ 93 ; ARC Cores Tangent-A5
EM_XTENSA equ 94 ; Tensilica Xtensa architecture
EM_NUM equ 95
EV_NONE equ 0 ; e_version, EI_VERSION
EV_CURRENT equ 1
EV_NUM equ 2
ELFOSABI_NONE equ 0 ; No extensions or unspecified
ELFOSABI_HPUX equ 1 ; Hewlett-Packard HP-UX
ELFOSABI_NETBSD equ 2 ; NetBSD
ELFOSABI_LINUX equ 3 ; Linux
ELFOSABI_UNKNOWN4 equ 4
ELFOSABI_UNKNOWN5 equ 5
ELFOSABI_SOLARIS equ 6 ; Sun Solaris
ELFOSABI_AIX equ 7 ; AIX
ELFOSABI_IRIX equ 8 ; IRIX
ELFOSABI_FREEBSD equ 9 ; FreeBSD
ELFOSABI_TRU64 equ 10 ; Compaq TRU64 UNIX
ELFOSABI_MODESTO equ 11 ; Novell Modesto
ELFOSABI_OPENBSD equ 12 ; Open BSD
clrso
Elf32_Phdr.p_type: so.l 1
Elf32_Phdr.p_offset: so.l 1
Elf32_Phdr.p_vaddr: so.l 1
Elf32_Phdr.p_paddr: so.l 1
Elf32_Phdr.p_filesz: so.l 1
Elf32_Phdr.p_memsz: so.l 1
Elf32_Phdr.p_flags: so.l 1
Elf32_Phdr.p_align: so.l 1
Elf32_Phdr.sizeof equ __SO
PT_NULL equ 0 ; p_type
PT_LOAD equ 1
PT_DYNAMIC equ 2
PT_INTERP equ 3
PT_NOTE equ 4
PT_SHLIB equ 5
PT_PHDR equ 6
PT_TLS equ 7
PT_NUM equ 8
PT_LOOS equ $60000000 ; OS specific range
;
; Note: The amd64 psABI defines that the UNWIND program header
; should reside in the OS specific range of the program
; headers.
;
PT_SUNW_UNWIND equ $6464e550 ; amd64 UNWIND program header
PT_GNU_EH_FRAME equ PT_SUNW_UNWIND
PT_LOSUNW equ $6ffffffa
PT_SUNWBSS equ $6ffffffa ; Sun Specific segment
PT_SUNWSTACK equ $6ffffffb ; describes the stack segment
PT_SUNWDTRACE equ $6ffffffc ; private
PT_SUNWCAP equ $6ffffffd ; hard/soft capabilities segment
PT_HISUNW equ $6fffffff
PT_HIOS equ $6fffffff
PT_LOPROC equ $70000000 ; processor specific range
PT_HIPROC equ $7fffffff
PF_R equ $4 ; p_flags
PF_W equ $2
PF_X equ $1
PF_MASKOS equ $0ff00000 ; OS specific values
PF_MASKPROC equ $f0000000 ; processor specific values
PF_SUNW_FAILURE equ $00100000 ; mapping absent due to failure
PN_XNUM equ $ffff ; extended program header index
endif

154
initrd.68k Normal file
View File

@ -0,0 +1,154 @@
STORAGE_SEC equ $0
STORAGE_CNT equ $4
STORAGE_CMD equ $8
STORAGE_DMADR equ $C
include cards.i
include string.i
include memory.i
section .text,text
; Initialize the initrd reader
public initrd_init
initrd_init:
move.w #$4, d0 ; Get the pointer to the MMU card
jsr find_first_card
move.l a0, storage_card_base
rts
; Get the start byte for a specific file in the initrd
; Pointer to name in a0
; Number returned in d0, or 0 if not found
public initrd_find_file
initrd_find_file:
movem.l d2/a2, -(a7)
move.l a0, a2 ; Save the name pointer in a2
move.l #512, d0 ; Allocate a buffer to read sectors into
jsr malloc
move.l a0, a1 ; Save the buffer pointer in a1
move.l #1, d0 ; Set the first sector to read
iff_loop:
movem.l d0/a1, -(a7)
move.l storage_card_base, a0 ; Read a file header sector
move.l #1, d1
bsr.b read_sectors
movem.l (a7)+, d0/a1
move.l (a1), d2 ; Abort with a 0 return if we have reached the end of the initrd
bne.b .1
move.l #0, d0
bra.b iff_done
.1:
movem.l d0/a1, -(a7)
move.l a2, a0 ; Compare the passed in file name with the one in the header sector
adda.l #12, a1
jsr strcmp
movem.l (a7)+, d0/a1
bne.b .2 ; Continue to the next file if the name doesn't match
addi.l #1, d0 ; Add one to the current sector number to get the start sector of the file
lsl.l #8, d0 ; Shift the sector number left by 9 to get the start byte of the file
lsl.l #1, d0
movem.l (a7)+, d2/a2
rts
.2:
; Add the # of sectors of file data + 1 to the sector number to advance to the next header sector
addi.l #1, d0
move.l (4,a1), d2
add.l d2, d0
bra.b iff_loop
iff_done:
movem.l (a7)+, d2/a2
rts
; Reads bytes of a file from the initrd
; Start byte of file in d0
; Offset in d1
; Length in d2
; Buffer in a0
public initrd_read_bytes
initrd_read_bytes:
add.l d1, d0
move.l d2, d1
move.l a0, a1
move.l storage_card_base, a0
bra.b read_bytes
; Reads sectors from a storage card
; Card base in a0
; Destination in a1
; Start sector in d0.l
; Sector count in d1.l
read_sectors:
cmpi.l #0, d1 ; Do nothing if asked to read 0 sectors
beq.b read_sectors_done
move.l d0, (STORAGE_SEC,a0) ; Set the sector number
move.l d1, (STORAGE_CNT,a0) ; Set the sector count
move.l a1, (STORAGE_DMADR,a0) ; Set the destination address
move.w #$1, (STORAGE_CMD,a0) ; Issue a DMA read command
read_sectors_done:
rts
; Reads bytes off a storage card
; Card base in a0
; Destination in a1
; Start byte in d0.l
; Byte count in d1.l
read_bytes:
movem.l d2-d5/a2/a3,-(a7) ; Save callee preserved registers
move.l d0, d4 ; Save start byte in d4
move.l d1, d5 ; Save byte count in d5
move.l a1, a3 ; Save destination in a6
lsr.l #8, d0 ; Divide start byte by 512 to compute starting sector
lsr.l #1, d0
move.l d0, d3 ; Save the starting sector in d3
move.l #1, d1 ; Read the starting sector into the sector buffer
move.l #sec_buf, a1
bsr.b read_sectors
move.l a3, a2 ; Load the destination into a2
move.l d4, d0 ; Load the start byte into d0
andi.l #$1FF, d0 ; Modulus start byte by 512 to compute sector data offset
adda.l d0, a1 ; Add the offset to the start of the sector buffer
move.l #$200, d1 ; Compute the number of bytes to transfer by subtracting the offset from 512
sub.l d0, d1
cmp d5, d1 ; Compare the number of bytes to transfer with the byte count
ble.b count_ok ; If it was less than the byte count, do not adjust the bytes to transfer
move.l d5, d1 ; Otherwise, cap the transfer count to the total byte count
count_ok:
move.l d1, d4 ; Save the number of bytes in d4
subi.l #1, d1 ; Subtract 1 from the number of bytes to account for the extra loop done by dbra
start_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer
move.b (a1)+, (a2)+
dbra d1, start_sec_loop
move.l d3, d0 ; Load the starting sector into d0
addi #1, d0 ; Compute the start of the middle sectors by adding 1 to the starting sector
move.l d4, d2 ; Load the number of bytes transferred into d2
move.l d5, d1 ; Load the byte count into d1
sub.l d2, d1 ; Compute the number of remaining bytes by subtracting the number of transferred bytes from the byte count
cmpi.l #0, d1 ; If there are no more bytes to read, end early
beq.b read_bytes_done
move.l d1, d4 ; Save the number of remaining bytes in d4
lsr.l #8, d1 ; Divide remaining bytes by 512 to compute the number of middle sectors
lsr.l #1, d1
move.l a2, a1 ; Transfer the sector data to the end of the start sector bytes
bsr.b read_sectors ; Read the middle sectors
move.l d1, d3 ; Save the number of middle sectors in d3
lsl.l #8, d1 ; Multiply the number of middle sectors by 512 to compute the number of bytes transferred
lsl.l #1, d1
sub.l d1, d4 ; Subtract the number of transferred bytes from the number of remaining bytes
cmpi.l #0, d4 ; If there are no more bytes to read, end early
beq.b read_bytes_done
adda.l d1, a2 ; Add the number of bytes transferred to a2
add.l d3, d0 ; Compute the end sector number by adding the start and count of the middle sectors
move.l #1, d1 ; Set the number of sectors to read to 1
move.l #sec_buf, a1 ; Set the read address of the sector to the sector buffer
bsr.w read_sectors ; Read the end sector
move.l d4, d1 ; Load the number of remaining bytes into d1
end_sec_loop: ; Transfer the required bytes from the start sector to the destination buffer
move.b (a1)+, (a2)+
dbra d1, end_sec_loop
read_bytes_done:
movem.l (a7)+, d2-d5/a2/a3 ; Restore callee preserved registers
rts
section .bss,bss
storage_card_base: ds.b 4
sec_buf: ds.b 512

17
initrd.i Normal file
View File

@ -0,0 +1,17 @@
ifnd INITRD_I
INITRD_I equ 1
; Initialize the initrd reader
xref initrd_init
; Get the start byte for a specific file in the initrd
; Pointer to name in a0
; Number returned in d0, or 0 if not found
xref initrd_find_file
; Reads bytes of a file from the initrd
; Start byte of file in d0
; Offset in d1
; Length in d2
; Buffer in a0
xref initrd_read_bytes
endif

35
kernel.ld Normal file
View File

@ -0,0 +1,35 @@
ENTRY (_start)
SECTIONS
{
. = 0x1000;
.early.text ALIGN (4K) : {
*(.early.text)
}
.early.rodata ALIGN (4K) : {
*(.early.rodata)
}
.early.data ALIGN (4K) : {
*(.early.data)
}
.early.bss ALIGN (4K) : {
*(.early.bss)
}
. += 0xC00000;
.text ALIGN (4K) : AT (ADDR (.text) - 0xC00000) {
*(.text)
}
.rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC00000) {
*(.rodata)
}
.data ALIGN (4K) : AT (ADDR (.data) - 0xC00000) {
*(.data)
}
.bss ALIGN (4K) : AT (ADDR (.bss) - 0xC00000) {
*(COMMON)
*(.bss)
}
_kernel_end_page = ALIGN(4K);
}

11
libstd_override.68k Normal file
View File

@ -0,0 +1,11 @@
include vmem.i
section .text,text
public alloc_pages
alloc_pages:
move.l d2, -(a7)
move.l #0, d1
move.l #$2, d2
jsr vmem_map_free
alloc_pages_done:
move.l (a7)+, d2
rts

146
main.68k Normal file
View File

@ -0,0 +1,146 @@
include elf.i
include term.i
include traps.i
include vmem.i
include pmem.i
include initrd.i
include tasking.i
include start.i
include memory.i
section .text,text
public main
main:
move.l #inital_stack, a7 ; Load the initial stack pointer
jsr term_init
jsr traps_init
jsr vmem_init
jsr pmem_init
jsr initrd_init
jsr pmem_pop_frame
move.l #0, d2
move.l #$FEF000, a0
move.l #1, d1
move.l #$2, d3
move.l d0, -(a7)
jsr vmem_map_to
move.l (a7)+, d0
move.l #($FEF000+$1000), a7
clrfo
main.elf_header: fo.b Elf32_Ehdr.sizeof
link a6, #__FO ; Create a stack frame
move.l d0, a0
jsr tasking_init
; Activate the address space for init
move.l #init_addr_space, a0
jsr vmem_activate_addr_space
; Get the offset of init in the initrd
move.l #init_name, a0
jsr initrd_find_file
move.l d0, d5
; Read the ELF header
lea.l (main.elf_header,a6), a0
move.l #0, d1
move.l #Elf32_Ehdr.sizeof, d2
jsr initrd_read_bytes
; Allocate elf_header.e_phnum * 32 bytes to read the program headers into
clr.l d0
move.w (main.elf_header+Elf32_Ehdr.e_phnum,a6), d0
move.l d0, d4
lsl.l #5, d0
move.l d0, d2
jsr malloc
; Read the program headers
move.l (main.elf_header+Elf32_Ehdr.e_phoff,a6), d1
move.l a0, -(a7)
move.l d5, d0
jsr initrd_read_bytes
move.l (a7)+, a2
; Loop through the program headers
subi.l #1, d4
phead_loop:
; If the program header's type is not LOAD, skip it
move.l (Elf32_Phdr.p_type,a2), d0
cmpi.l #PT_LOAD, d0
bne.w skip_pheader
; Get the memory size of the pheader into d0 and round it to the next multiple of 4096
; round_size = p_memsz & 0xFFF > 0 ? p_memsz & ~(0xFFF) + 1 : p_memsz & ~(0xFF)
move.l (Elf32_Phdr.p_memsz,a2), d0
andi.l #$FFF, d0
beq.b .1
move.l #$1000, d1
bra.b .2
.1:
move.l #0, d1
.2:
move.l (Elf32_Phdr.p_memsz,a2), d0
andi.l #(~$FFF), d0
add.l d1, d0
; Shift the rounded size right by 12 to get the number of pages the pheader takes up
lsr.l #8, d0
lsr.l #4, d0
; Map the segment to free memory
move.l (Elf32_Phdr.p_vaddr,a2), a0
move.l #0, d1
move.l #6, d2
jsr vmem_map
; Zero the segment's memory
move.l (Elf32_Phdr.p_vaddr,a2), a0
move.l (Elf32_Phdr.p_memsz,a2), d0
subi.l #1, d0
.3:
move.b #0, (a0)+
dbra d0, .3
; Read the segment's data off disk
move.l d5, d0
move.l (Elf32_Phdr.p_offset,a2), d1
move.l (Elf32_Phdr.p_filesz,a2), d2
move.l (Elf32_Phdr.p_vaddr,a2), a0
jsr initrd_read_bytes
; Get the memory size of the pheader into d0 and round it to the next multiple of 4096
; Same as abobe
move.l (Elf32_Phdr.p_memsz,a2), d0
andi.l #$FFF, d0
beq.b .4
move.l #$1000, d1
bra.b .5
.4:
move.l #0, d1
.5:
move.l (Elf32_Phdr.p_memsz,a2), d0
andi.l #(~$FFF), d0
add.l d1, d0
; Shift the rounded size right by 12 to get the number of pages the pheader takes up
lsr.l #8, d0
lsr.l #4, d0
; Get the pheader's flags and make them into the page mapping flags, put the
; argumemts into the right registers, and set the flags for the pheader's memory
move.l d0, d1
move.l (Elf32_Phdr.p_vaddr,a2), a0
move.l (Elf32_Phdr.p_flags,a2), d0
andi.l #PF_W, d0
move.l (Elf32_Phdr.p_flags,a2), d2
andi.l #PF_X, d2
lsl.l #3, d2
or.l d2, d0
ori.l #$4, d0
move.l #$0, d2
jsr vmem_set_flags
skip_pheader:
; Advance to the next pheader and loop back if there are more
lea.l (Elf32_Phdr.sizeof,a2), a2
dbra d4, phead_loop
; Create the init process
move.l #init_addr_space, a0
move.l (main.elf_header+Elf32_Ehdr.e_entry,a6), a1
jsr tasking_new_process
unlk a6 ; Tear down the stack frame
jsr tasking_exit
section .bss,bss
ds.b 4096
inital_stack:
section .data,data
init_name: dc.b "init",0
align 1
init_addr_space: dc.l $0, $0, $0, kernel_map - $6000

150
pmem.68k Normal file
View File

@ -0,0 +1,150 @@
include vmem.i
include term.i
include cards.i
include string.i
xref _kernel_end_page
section .text, text
public pmem_init
; Initialize the physical memory manager
pmem_init:
movem.l d2/d3/d4, -(a7) ; Save old values of d2, d3, and d4 (callee preserved)
clrfo
pmem_init.buf: fo.b 12
link a6, #__FO ; Create a 12-byte stack frame to use as a buffer for hex_to_ascii
move.w #$1, d0 ; Get the pointer to the ROM card
jsr find_first_card
move.w #$C000, ($F0,a0) ; Enable the card at physical address $C0000000
move.b #$1, ($F3,a0)
move.l #0, d2 ; Map the beginning of the ROM card's RAM into virtual memory
move.l #$C0008000, d0
move.l #$1, d1
move.l #$2, d3
jsr vmem_map_free_to
move.l a0, -(a7) ; Save a0
move.l a0, a1
move.l #$1, d0
jsr vmem_get_free_kernel_pages ; Alocate the stack page
move.l a0, stack_page_addr
move.l a0, a1
move.l #kernel_address_space, a0
move.l (a7)+, a0 ; Restore a0
adda.l #($100-$4), a0
move.l #1, d0 ; d0 holds the physical base address of the RAM card (+ 1 for the enable flag)
move.l #_kernel_end_page, d4 ; Put the physical address of the last kernel page into d4
sub.l #$C01000, d4
ramcard_map_loop:
lea ($4,a0), a0 ; Move to the next RAM card
move.l (a0), a1 ; Load the IO base pointer into a1
cmpa.l #0, a1
beq.w ramcard_map_loop_done ; If the pointer is 0, we have reached the end of the list, so exit the loop
move.l d0, (a1) ; Map the card to the base address in d0
move.l d0, d3 ; Save the base address in d3 for later use
move.l ($4,a1), d1 ; Advance d0 by the size of the card
move.l d1, d2 ; Save the card size in d2 for later use
add.l d1, d0
movem.l d0/a0, -(a7) ; Save base address and RAM card pointer
move.l #pmem_log_name, a0 ; Log the mapped RAM card
jsr term_print
lea.l (pmem_init.buf,a6), a0 ; Print the card size in bytes
move.l d2, d0
jsr hex_to_ascii
lea.l (pmem_init.buf,a6), a0
jsr term_print
move.l #ramcard_log_msg, a0 ; Print " byte RAM card at "
jsr term_print
lea.l (pmem_init.buf,a6), a0 ; Print the card base address
move.l d3, d0
subi.l #1, d0
jsr hex_to_ascii
lea.l (-12,a6), a0
jsr term_println
subi.l #1, d3
rc_map_page_push_loop:
cmp.l d4, d3 ; If the current physical page is used by the kernel binary, skip it
bhi.b .1
add.l #$1000, d3
sub.l #$1000, d2
bra.b rc_map_page_push_loop
.1:
move.l d3, d0 ; Push the frame in d3 and move to the next one
jsr pmem_push_frame
add.l #$1000, d3
sub.l #$1000, d2
bne.b rc_map_page_push_loop ; Loop back if this card has more pages to push
rc_map_pages_pushed:
movem.l (a7)+, d0/a0 ; Restore base address and RAM card pointer
bra.w ramcard_map_loop ; Loop back and map the next card
ramcard_map_loop_done:
move.l a0, d0
andi.l #(~$FFF), d0
move.l d0, a0
move.l #0, d0
jsr vmem_unmap_page
unlk a6 ; Tear down the stack frame
movem.l (a7)+, d2/d3/d4 ; Restore d2, d3, and d4 (callee preserved)
rts
public pmem_push_frame
; Pushes a frame onto the stack
; Frame to push in d0
pmem_push_frame:
move.l d0, -(a7)
move.l #0, d0
move.l stack_page_addr, a0
jsr vmem_get_map_ptr
move.l (a7)+, d0
move.l (a0), d1 ; Read the mapping entry into d1
andi.l #(~$FFF), d1 ; Clear the entry's flags to get the pointer to its physical page
movem.l d1/d2/d3, -(a7)
; Map the stack page to the frame to push
move.l #0, d2
move.l stack_page_addr, a0
move.l #1, d1
move.l #$2, d3
jsr vmem_map_to
move.l stack_page_addr, a0 ; Clear the TLB entry for the mapping page
jsr vmem_clear_tlb_entry
movem.l (a7)+, d1/d2/d3
move.l stack_page_addr, a0 ; Load the address of the stack page into a0
move.l d1, (a0) ; Write the address of the old top frame to the next pointer of the new top
rts
public pmem_pop_frame
; Pops a frame off the stack
; Returns frame address in d0
pmem_pop_frame:
move.l #0, d0 ; Read the mapping entry into d0
move.l stack_page_addr, a0
jsr vmem_get_map_ptr
move.l (a0), d0
andi.l #(~$FFF), d0 ; Clear the entry's flags to get the pointer to its physical frame
move.l stack_page_addr, a1 ; Load the address of the stack page into a1
move.l (a1), d1 ; Get the address of the frame pointed to by the top of the stack
beq.b pop_no_page ; If the pointed-to frame is the null frame, OOM
movem.l d0/d2/d3, -(a7)
; Map the stack page to the pointed-to-frame
move.l d1, d0
move.l #0, d2
move.l stack_page_addr, a0
move.l #1, d1
move.l #$2, d3
jsr vmem_map_to
move.l stack_page_addr, a0 ; Clear the TLB entry for the mapping page
jsr vmem_clear_tlb_entry
movem.l (a7)+, d0/d2/d3
rts
pop_no_page:
move.l #oom_error_str, a0
jsr term_println
stop #$2700
section .data,data
pmem_log_name: dc.b "[PMEM] ",0
ramcard_log_msg: dc.b " byte RAM card at ",0
oom_error_str: dc.b "Out of physical memory",0
section .bss,bss
align 1
stack_page_addr:
ds.b 4

11
pmem.i Normal file
View File

@ -0,0 +1,11 @@
ifnd PMEM_I
PMEM_I equ 1
; Initialize the physical memory manager
xref pmem_init
; Pushes a frame onto the stack
; Frame to push in d0
xref pmem_push_frame
; Pops a frame off the stack
; Returns frame address in d0
xref pmem_pop_frame
endif

86
start.68k Normal file
View File

@ -0,0 +1,86 @@
include cards.i
xref main
section .early.text, text
public _start
; Receives pointer to program headers in a0 and number of program headers in d0
_start:
move.l d0, d2 ; Move the number of program headers to d2
move.l a0, a1 ; Move the program headaer pointer to a1
move.w #$5, d0 ; Get the pointer to the MMU card
jsr (find_first_card - $C00000)
cmpa.l #0, a0 ; Abort if there is no MMU card
beq.w no_mmu
subq.w #$1, d2 ; Adjust the number of program headers for dbra
phead_loop:
move.l (a1), d1 ; If the type of the program header isn't 1 (LOAD), skip the header
cmpi.l #$1, d1
bne.b next_phead
move.b (9,a1), d1 ; If the segment isn't for the high quarter, skip it
cmpi.b #$c0, d1
bgt.b next_phead
move.l (20,a1), d4 ; Put the memory size in d4
move.l d4, d3 ; Copy the size to d3
lsr #8, d3 ; Shift d3 right 12 bits to get the number of full pages the segment takes up
lsr #4, d3
andi.l #$FFF, d4 ; If the segment takes up a partial page, add 1 to the number of required pages in d3
cmp.l #$0, d4
beq.b even_page
addq.l #1, d3
even_page:
subq.b #1, d3 ; Adjust the number of pages to map for dbra
move.l (12,a1), d1 ; Get the starting physical page in d3
move.l (24,a1), d4 ; Get the permission flags in d4
andi.l #$2, d4 ; Isolate the writable flag
or.l d4, d1 ; Copy the writable flag to the page entry
move.l (24,a1), d4 ; Get the permission flags in d4
andi.l #$1, d4 ; Isolate the executable flag
lsl.l #3, d4 ; Copy the executable flag to the page entry
or.l d4, d1
ori.l #$1, d1 ; Set the present flag on the entry
move.l (8,a1), d0 ; Get the starting virtual page number in the quarter in d0
lsr.l #8, d0
lsr.l #4, d0
andi.l #$3ff, d0
lsl #2, d0 ; Get the pointer to the entry for the page in a2
move.l #(kernel_map - $C00000), a2
adda d0, a2
map_loop:
move.l d1, (a2)+ ; Write the entry to the mapping page and advance the entry pointer
addi.l #$1000, d1 ; Advance the entry to the next physical page
dbra d3, map_loop ; Loop back if there are more pages to map
next_phead:
lea ($20,a1), a1 ; Advance a1 to point to the next program header
dbra d2, phead_loop ; If there are more program headers, loop back
io_map:
move.l #15, d0 ; Put the number of IO pages in d0, minus one to adjust for dbra
move.l #(kernel_map - $C00000 + $3f0 * 4), a1 ; Put the poiner to the mapping for virtual page $FF0000 in a1
move.l #$ffff0003, d1 ; Put the initial map entry in d1
io_map_loop:
move.l d1, (a1)+ ; Write the entry to the mapping page and advance the entry pointer
addi.l #$1000, d1 ; Advance the entry to the next physical page
dbra d0, io_map_loop ; Loop back if there are more pages to map
map_done:
move.l #(kernel_map - $C00000), d0 ; Load the pointer to the mapping page into d0
ori.l #$1, d0 ; Set the map page present flag
move.l d0, ($0,a0) ; Write the mapping page to both the lower and upper quarter map registers
move.l d0, ($C,a0)
jmp (higher_bridge - $C00000) ; Jump to the lower-half equivalent of the bridging function
no_mmu:
stop #$2700 ; If there was no MMU card, halt the CPU
section .text,text
higher_bridge:
move.w #1, ($14,a0) ; Enable the MMU
jmp in_higher.l ; Jump to the higher half (THis function has been called with the PC in the
; lower half, so this seemingly no-op jump instruction actually switches to the higher half)
in_higher:
move.w #0, $ff0000 ; Disable the IO space at the top of the lower 16MB of memory
move.l #0, ($0,a0) ; Disable the mapping in the lower quarter
jmp main ; Jump to the kernel's main function
section .bss,bss
public kernel_map
kernel_map:
align 12
ds.b 4096

5
start.i Normal file
View File

@ -0,0 +1,5 @@
ifnd START_I
START_I equ 1
xref __start
xref kernel_map
endif

6
syscall.i Normal file
View File

@ -0,0 +1,6 @@
ifnd SYSCALL_I
SYSCALL_I equ 1
; Handle a syscall
; Syscall number in d0
xref handle_syscall
endif

66
syscalls.68k Normal file
View File

@ -0,0 +1,66 @@
include tasking.i
include vmem.i
include term.i
section .text,text
; Handle a syscall
; Syscall number in d0
public handle_syscall
handle_syscall:
; Get the d0th entry in the syscall table
move.l #syscall_table, a6
lsl.l #2, d0
adda.l d0, a6
move.l (a6), a6
; Call the entry
jsr (a6)
rts
syscall_exit:
jmp tasking_exit
syscall_yield:
jmp tasking_yield
syscall_print:
jmp term_print
syscall_println:
jmp term_println
; Maps the range of pages starting at address a0 with length d1 to free physical frames
; Permission flags in d2
syscall_vmem_map:
move.l d1, d0
move.l #0, d1
ori.l #$4, d2
jmp vmem_map
; Map a free range of pages with length d1 to free physical frames
; Returns the range start in a0
; Permission flags in d2
syscall_vmem_map_free:
move.l d1, d0
move.l #2, d1
ori.l #$4, d2
jmp vmem_map_free
; Maps a free range of virtual pages with length d2 to the range of physical frames starting at d1
; Returns the range start in a0
; Permission flags in d3
syscall_vmem_map_free_to:
move.l d1, d0
move.l d2, d1
move.l #2, d2
ori.l #$4, d3
jmp vmem_map_free_to
section .data,data
syscall_table:
align 1
dc.l syscall_exit
dc.l syscall_yield
dc.l syscall_print
dc.l syscall_println
dc.l syscall_vmem_map
dc.l syscall_vmem_map_free
dc.l syscall_vmem_map_free_to

234
tasking.68k Normal file
View File

@ -0,0 +1,234 @@
clrso
task.pid: so.w 2
task.stack_frame: so.l 1
task.stack_ptr: so.l 1
task.next_ptr: so.l 1
task.address_space: so.l 4
task.sizeof equ __SO
include term.i
include vmem.i
include pmem.i
include memory.i
section .text,text
; Initializes tasking, takes the kernel stack frame in a0
public tasking_init
tasking_init:
move.l a0, -(a7)
move.l #task.sizeof, d0 ; Allocate space for the task data
jsr malloc
ti_malloc_done:
move.l (a7)+, a1
move.w #0, (task.pid,a0)
move.l a1, (task.stack_frame,a0)
move.l #0, (task.stack_ptr,a0)
move.l #0, (task.next_ptr,a0)
move.l a0, current_process
move.l #15, d1 ; Put the address space size - 1 in d1
lea.l (task.address_space,a0), a1 ; Put the address of the task address space in a1
move.l #kernel_address_space, a0 ; Put the address of the kernel address space in a0
.1:
move.b (a0)+,(a1)+
dbra d1, .1 ; Loop back if there is more to copy
move.w #1, next_pid
rts
; Creates a new process
; Pointer to address space in a0
; Start address in a1
public tasking_new_process
tasking_new_process:
movem.l a2/a3, -(a7)
movem.l a0/a1, -(a7)
move.l #32, d0 ; Allocate space for the task data
jsr malloc
tnp_malloc_done:
movem.l (a7)+, a1/a2
move.w next_pid, d0 ; Get the next free PID
move.w d0, (task.pid,a0)
addi.w #1, d0 ; Increment the counter by 1
move.w d0, next_pid
movem.l a0/a1, -(a7)
jsr pmem_pop_frame ; Get a frame for the process' kernel stack
movem.l (a7)+, a0/a1
move.l d0, (task.stack_frame,a0)
; Map the new process' stack into memory
movem.l a0/a1/d2/d3, -(a7)
move.l #1, d1
move.l #0, d2
move.l #$2, d3
jsr vmem_map_free_to
move.l a0, a3
movem.l (a7)+, a0/a1/d2/d3
adda.l #$1000, a3
; Push start address onto new process stack
move.l a2, -(a3)
; Push address of user mode switch shim onto process stack
move.l #tasking_um_switch_shim, -(a3)
; Push dummy register values onto new process stack
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
move.l #0, -(a3)
; Set the page number of the new process's kernel stack address to $FEF
move.l a3, d0
andi.l #$FFF, d0
ori.l #$FEF000, d0
move.l d0, (task.stack_ptr,a0)
move.l #0, (task.next_ptr,a0)
; Unmap the temporary stack mapping
move.l a0, -(a7)
move.l a3, d0 ; Put the page number of the temporary page into a0
and.l #~($FFF), d0
move.l d0, a0
move.l #1, d0
move.l #0, d1
jsr vmem_unmap
move.l (a7)+, a0
move.l #15, d1 ; Put the address space size - 1 in d1
lea.l (task.address_space,a0), a2 ; Put the address of the task address space in a2
.1:
move.b (a1)+, (a2)+
dbra d1, .1 ; Loop back if there is more to copy
jsr rtr_push_head
movem.l (a7)+, a2/a3
rts
tasking_um_switch_shim:
move.w sr, d0 ; Push the SR with the supervisor bit cleared to make a "fake" exception frame
andi.w #(~$2000), d0
move.w d0, -(a7)
rte ; Switch the CPU into usermode and start executing the new process
; Yields to the next process
public tasking_yield
tasking_yield:
movem.l d2-d7/a2-a6, -(a7)
; Save the current kernel stack pointer
move.l current_process, a0
move.l a7, (task.stack_ptr,a0)
jsr rtr_pop ; Get the next ready process
; Return if there is none
cmp.l #0, a0
bne.b .1
movem.l (a7)+, d2-d7/a2-a6
rts
.1:
move.l a0, a2 ; Save the next process in a2
; Push the current process on the ready to run list
move.l current_process, a0
jsr rtr_push_tail
; Update the current process to be the next process to run
move.l a2, current_process
; Activate the next process' address space
lea.l (task.address_space,a2), a0
jsr vmem_activate_addr_space
; Set the kernel stack frame to the next process' stack frame
move.l #0, d0
move.l #$FEF000, a0
jsr vmem_get_map_ptr
move.l (task.stack_frame,a2), d0
ori.l #$3, d0
move.l d0, (a0)
move.l vmem_mmu_base_addr, a1
move.l #$FEF000, ($10,a1)
move.l (task.stack_ptr,a2), a7
movem.l (a7)+, d2-d7/a2-a6
rts
; Exits the current process
public tasking_exit
tasking_exit:
movem.l d2-d7/a2-a6, -(a7)
jsr rtr_pop ; Get the next ready process
; Return if there is none
cmp.l #0, a0
bne.b .1
move.l #last_proc_exited_str, a0
jsr term_println
stop #$2700
.1:
move.l a0, a2 ; Save the next process in a2
; Update the current process to be the next process to run
move.l a2, current_process
; Activate the next process' address space
lea.l (task.address_space,a2), a0
jsr vmem_activate_addr_space
; Set the kernel stack frame to the next process' stack frame
move.l #0, d0
move.l #$FEF000, a0
jsr vmem_get_map_ptr
move.l (task.stack_frame,a2), d0
ori.l #$3, d0
move.l d0, (a0)
move.l vmem_mmu_base_addr, a1
move.l #$FEF000, ($10,a1)
move.l (task.stack_ptr,a2), a7
movem.l (a7)+, d2-d7/a2-a6
rts
; Push the process pointed to by a0 onto the head of the ready to run list
rtr_push_head:
cmp.l #0, ready_to_run_head
bne.b .1
; Set the ready to run list to the passed-in process if it is empty
move.l a0, ready_to_run_head
move.l a0, ready_to_run_tail
rts
.1:
move.l ready_to_run_head, (task.next_ptr,a0) ; Set the next pointer of the passed-in process to the current head
move.l a0, ready_to_run_head ; Set the head to the passed-in process
rts
; Push the process pointed to by a0 onto the tail of the ready to run list
rtr_push_tail:
cmp.l #0, ready_to_run_head
bne.b .1
; Set the ready to run list to the passed-in process if it is empty
move.l a0, ready_to_run_head
move.l a0, ready_to_run_tail
rts
.1:
; Set the next pointer of the tail to the passed-in process
move.l ready_to_run_tail, a1
move.l a0, (task.next_ptr,a1)
move.l #0, (task.next_ptr,a0) ; Set the next pointer of the passed-in process to NULL
move.l a0, ready_to_run_tail ; Set the tail to the passed-in process
rts
; Pop a process of the head of the ready to run list
; Address returned in a0, or 0 if no process
rtr_pop:
; Return 0 if the list is empty
cmp.l #0, ready_to_run_head
bne.b .1
move.l #0, a0
rts
.1:
; Set the head to the current head's next pointer
move.l ready_to_run_head, a0
move.l (task.next_ptr,a0), ready_to_run_head
; If the new head is NULL, set the tail to NULL
cmp.l #0, ready_to_run_head
bne.b .2
move.l #0, ready_to_run_tail
.2:
rts
section .bss,bss
ready_to_run_head: ds.b 4
ready_to_run_tail: ds.b 4
current_process: ds.b 4
next_pid: ds.b 2
section .data,data
last_proc_exited_str: dc.b "Last process exited, halting",0

13
tasking.i Normal file
View File

@ -0,0 +1,13 @@
ifnd TASKING_I
TASKING_I equ 1
; Initializes tasking, takes the kernel stack frame in a0
xref tasking_init
; Creates a new process
; Pointer to address space in a0
; Start address in a1
xref tasking_new_process
; Yields to the next process
xref tasking_yield
; Exits the current process
xref tasking_exit
endif

35
term.68k Normal file
View File

@ -0,0 +1,35 @@
include cards.i
section .text,text
; Initializes the terminal card driver
public term_init
term_init:
move.b #$3, d0 ; Get the pointer to the terminal card
jsr find_first_card
move.l a0, term_io_base ; Save the pointer for later use
rts
; Prints the string pointed to by a0
public term_print
term_print:
move.l term_io_base, a1
term_print_loop:
move.b (a0)+, d0 ; Get the next character of the string
cmpi.b #0, d0 ; If NULL, end of string; return
beq.b term_print_done
move.b d0, (a1) ; Send the character to the terminal
bra.b term_print
term_print_done:
rts
; Prints the string pointed to by a0 followed by a newline
public term_println
term_println:
bsr.b term_print
; take advantage of the known register state after term_print and
; write the newline w/o loading the address from memory
move.b #$A, (a1)
rts
section .bss,bss
term_io_base:
ds.b 4

9
term.i Normal file
View File

@ -0,0 +1,9 @@
ifnd TERM_I
TERM_I equ 1
; Initializes the terminal card driver
xref term_init
; Prints the string pointed to by a0
xref term_print
; Prints the string pointed to by a0 followed by a newline
xref term_println
endif

271
traps.68k Normal file
View File

@ -0,0 +1,271 @@
include syscall.i
include term.i
include string.i
section .text,text
public traps_init
; Initialize trap handling
traps_init:
move.l #trap_table, a0
movec a0, VBR
rts
generic_handler:
; Read the format/vector word and isolate the interrupt vector
move.w ($6,a7), d0
andi.l #$FF, d0
cmpi.l #$20, d0
; Only the first 32 traps are named, print generic message for the rest
bge.b unk_trap
; Get the pointer to the trap name in a0
lsl.w #2, d0
move.l #trap_name_table, a0
move.l (a0,d0), a0
jsr term_print ; Print it
; Print " Trap"
move.l #trap_string, a0
jsr term_print
; Print where the PC was when the trap occured
move.l ($2,a7), a0
jsr print_pc
; Halt
stop #$2700
unk_trap:
; Print the unknown trap message
move.l #unk_trap_msg, a0
jsr term_print
; Convert the trap number to a hex string
move.w ($6,a7), d0
andi.l #$FF, d0
move.l #string_buffer, a0
jsr hex_to_ascii
; Print it
move.l #string_buffer, a0
jsr term_print
; Print where the PC was when the trap occured
move.l ($2,a7), a0
jsr print_pc
; Halt
stop #$2700
berr_handler:
; Select the correct prefix based on whether the error was in supervisor or user mode
move.w ($8,a7), d0
andi.w #$4, d0
cmpi.w #0, d0
beq.b .1
move.l #berr_supervisor_pfx, a0
bra.b .2
.1:
move.l #berr_user_pfx, a0
.2:
jsr term_print ; Print the prefi
; Print " bus error "
move.l #berr_msg, a0
jsr term_print
; Get the error kind out of the special status word (end up with ins flag, word flag, and write flg in that order, shifted left by 2 and put in d0)
move.l #0, d1
move.w ($8,a7), d0
andi.w #$100, d0
cmpi.w #0, d0
beq.b .3
move.l #$4, d1
.3:
move.w ($8,a7), d0
andi.w #$200, d0
cmpi.w #0, d0
beq.b .4
ori.l #$8, d1
.4:
move.w ($8,a7), d0
andi.w #$2000, d0
cmpi.w #0, d0
beq.b .5
ori.l #$10, d1
.5:
; Get the pointer to the correct message for this kind of bus error in a0
move.l #berr_table, a0
adda.l d1, a0
move.l (a0), a0
jsr term_print ; Print it
; Convert the triggering address to a hex string
move.l ($a,a7), d0
move.l #string_buffer, a0
jsr hex_to_ascii
; Print it
move.l #string_buffer, a0
jsr term_print
; Print where the PC was when the trap occured
move.l ($2,a7), a0
jsr print_pc
stop #$2700
int_vector_handler:
movem.l d0-d7/a0-a6,-(a7)
lea.l (60,a7), a6
; Print "Interrupt Vector "
move.l #int_vector_msg, a0
jsr term_print
; Get the interrupt vector offset
move.w ($6,a6), d0
andi.l #$FF, d0
subi.l #$40, d0
; Convert it to a hex string
move.l #string_buffer, a0
jsr hex_to_ascii
; Print it
move.l #string_buffer, a0
jsr term_println
movem.l (a7)+, d0-d7/a0-a6
rte
user_trap_handler:
movem.l d2-d7/a2-a6,-(a7)
jsr handle_syscall
movem.l (a7)+, d2-d7/a2-a6
rte
; Print " (PC: {a0})\n"
; Clobbers d0, a0, a1, a2
print_pc:
; Print the message up to the first variable
move.l a0, a2
move.l #pc_string_start, a0
jsr term_print
; Convert the PC value to a hex string
move.l a2, d0
move.l #string_buffer, a0
jsr hex_to_ascii
; Print it
move.l #string_buffer, a0
jsr term_print
; Print the rest of the message
move.l #pc_string_end, a0
jsr term_println
rts
section .bss,bss
string_buffer:
ds.b 11
section .data,data
unk_trap_msg: dc.b "Unknown trap ",0
trap_string: dc.b " Trap",0
berr_msg: dc.b "bus error ",0
pc_string_start: dc.b " (PC: ",0
pc_string_end: dc.b ")",0
int_vector_msg: dc.b "Interrupt Vector ",0
user_trap_msg: dc.b "User Trap ",0
berr_supervisor_pfx: dc.b "Supervsior ",0
berr_user_pfx: dc.b "User ",0
align 1
berr_table:
dc.l berr_rdw_msg
dc.l berr_wdw_msg
dc.l berr_rdb_msg
dc.l berr_wdb_msg
dc.l berr_riw_msg
dc.l berr_wiw_msg
dc.l berr_rib_msg
dc.l berr_wib_msg
berr_rdw_msg: dc.b "reading word from ",0
berr_wdw_msg: dc.b "writing word to ",0
berr_rdb_msg: dc.b "reading byte from ",0
berr_wdb_msg: dc.b "writing byte to ",0
berr_riw_msg: dc.b "reading instruction word from ",0
berr_wiw_msg: dc.b "writing instruction word to ",0
berr_rib_msg: dc.b "reading instruction byte from ",0
berr_wib_msg: dc.b "writing instruction byte to ",0
align 1
trap_name_table:
dc.l $0
dc.l $0
dc.l berr_msg
dc.l address_trap_name
dc.l ill_ins_trap_name
dc.l zero_div_trap_name
dc.l chk_ins_trap_name
dc.l trapv_trap_name
dc.l priv_viol_trap_name
dc.l trace_trap_name
dc.l line_1010_emu_trap_name
dc.l line_1111_emu_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l format_error_trap_name
dc.l uninit_int_vect_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l reserved_trap_name
dc.l spur_interrupt_trap_name
dc.l lev_1_autovec_trap_name
dc.l lev_2_autovec_trap_name
dc.l lev_3_autovec_trap_name
dc.l lev_4_autovec_trap_name
dc.l lev_5_autovec_trap_name
dc.l lev_6_autovec_trap_name
dc.l lev_7_autovec_trap_name
address_trap_name: dc.b "Address Error",0
ill_ins_trap_name: dc.b "Illegal Instruction",0
zero_div_trap_name: dc.b "Zero Divide",0
chk_ins_trap_name: dc.b "CHK Instruction",0
trapv_trap_name: dc.b "TRAPV Instruction",0
priv_viol_trap_name: dc.b "Privilege Violation",0
trace_trap_name: dc.b "Trace",0
line_1010_emu_trap_name: dc.b "Line 1010 Emulator",0
line_1111_emu_trap_name: dc.b "Line 1111 Emulator",0
reserved_trap_name: dc.b "Reserved",0
format_error_trap_name: dc.b "Format Error",0
uninit_int_vect_trap_name: dc.b "Uninitialized Interrupt Vector",0
spur_interrupt_trap_name: dc.b "Spurious Interrupt",0
lev_1_autovec_trap_name: dc.b "Level 1 Interrupt Autovector",0
lev_2_autovec_trap_name: dc.b "Level 2 Interrupt Autovector",0
lev_3_autovec_trap_name: dc.b "Level 3 Interrupt Autovector",0
lev_4_autovec_trap_name: dc.b "Level 4 Interrupt Autovector",0
lev_5_autovec_trap_name: dc.b "Level 5 Interrupt Autovector",0
lev_6_autovec_trap_name: dc.b "Level 6 Interrupt Autovector",0
lev_7_autovec_trap_name: dc.b "Level 7 Interrupt Autovector",0
align 10
trap_table:
dc.l generic_handler ; Reset initial SSP, should never be called
dc.l generic_handler ; Reset initial PC, should never be called
dc.l berr_handler ; Bus Error
dc.l generic_handler ; Address Error
dc.l generic_handler ; Illegal Instruction
dc.l generic_handler ; Zero Divide
dc.l generic_handler ; CHK Instruction
dc.l generic_handler ; TRAPV Instruction
dc.l generic_handler ; Privilege Violation
dc.l generic_handler ; Trace
dc.l generic_handler ; Line 1010 Emulator
dc.l generic_handler ; Line 1111 Emulator
dc.l generic_handler ; Reserved
dc.l generic_handler ; Reserved
dc.l generic_handler ; Format Error
dc.l generic_handler ; Uninitialized Interrupt Vector
rept 8
dc.l generic_handler ; Reserved
endr
dc.l generic_handler ; Spurious Interrupt
dc.l generic_handler ; Level 1 Interrupt Autovector
dc.l generic_handler ; Level 2 Interrupt Autovector
dc.l generic_handler ; Level 3 Interrupt Autovector
dc.l generic_handler ; Level 4 Interrupt Autovector
dc.l generic_handler ; Level 5 Interrupt Autovector
dc.l generic_handler ; Level 6 Interrupt Autovector
dc.l generic_handler ; Level 7 Interrupt Autovector
rept 16
dc.l user_trap_handler
endr
rept 16
dc.l generic_handler ; Reserved
endr
rept 192
dc.l int_vector_handler
endr

5
traps.i Normal file
View File

@ -0,0 +1,5 @@
ifnd TRAPS_I
TRAPS_I equ 1
; Initialize trap handling
xref traps_init
endif

491
vmem.68k Normal file
View File

@ -0,0 +1,491 @@
include pmem.i
include cards.i
include start.i
section .text,text
; Initialize the virtual memory manager
public vmem_init
vmem_init:
movem.l d2/d3, -(a7)
move.w #$5, d0 ; Get the pointer to the MMU card
jsr find_first_card
move.l a0, vmem_mmu_base_addr ; Save it for later use
; Map 3 pages to dummy physical frames for use in accessing user page mappings
move.l #$FFFFC000, d0
move.l #3, d1
move.l #0, d2
move.l #$2, d3
jsr vmem_map_free_to
move.l a0, vmem_active_space_mapping_ptr ; Save the pointer for later use
; Same as above for the secondary address space
move.l #$FFFFC000, d0
move.l #3, d1
move.l #0, d2
move.l #$2, d3
jsr vmem_map_free_to
move.l a0, vmem_secondary_space_mapping_ptr ; Save the pointer for later use
movem.l (a7)+, d2/d3
; Activate the kernel address space
move.l #kernel_address_space, a0
jsr vmem_activate_addr_space
rts
; Clears the TLB entry of the page pointed to by a0
public vmem_clear_tlb_entry
vmem_clear_tlb_entry:
; Write the address to the TLB clear register of the MMU card
move.l vmem_mmu_base_addr, a1
move.l a0, ($10,a1)
rts
; Activates the address space pointed to by a0
public vmem_activate_addr_space
vmem_activate_addr_space:
movem.l a2, -(a7)
move.l a0, vmem_active_space_ptr ; Set the pointer to the current address space
move.l vmem_mmu_base_addr, a1 ; Get the MMU card base into a1
move.l vmem_active_space_mapping_ptr, a2 ; Load the pointer to the active space mapping pages into a2
move.l #2, d0 ; Loop 3 times, count -1 due to dbra looping n+1 times
vaas_loop:
move.l (a0)+, d1 ; Read the next mapping frame into d1
movem.l d0/d1/d2/d3/a0/a1, -(a7)
; Map the mapping page pointed to by a2 to the mapping frame just read into d1
move.l a2, a0
move.l d1, d0
move.l #1, d1
move.l #0, d2
move.l #$2, d3
jsr vmem_map_to
movem.l (a7)+, d0/d1/d2/d3/a0/a1
cmp.l #0, d1 ; If the mapping frame isn't 0, mark it as active
beq.b .1
ori.l #3, d1
.1:
move.l d1, (a1)+ ; Write the frame to the next quarter mapping register in the MMU
adda.l #$1000, a2 ; Advance to the next mapping page
dbra d0, vaas_loop ; Loop back if there are more frames to read
movem.l (a7)+, a2
rts
; Sets the secondary address space
public vmem_set_secondary_addr_space
vmem_set_secondary_addr_space:
move.l a0, vmem_secondary_space_ptr ; Set the pointer to the secondary address space
move.l vmem_secondary_space_mapping_ptr, a1 ; Load the pointer to the secondary space mapping pages into a1
move.l #2, d0 ; Loop 3 times, count -1 due to dbra looping n+1 times
vssas_loop:
move.l (a0)+, d1 ; Read the next mapping frame into d1
movem.l d0/d1/d2/d3/a0, -(a7)
; Map the mapping page pointed to by a1 to the mapping frame just read into d1
move.l a1, a0
move.l d1, d0
move.l #1, d1
move.l #0, d2
move.l #$2, d3
jsr vmem_map_to
movem.l (a7)+, d0/d1/d2/d3/a0
adda.l #$1000, a1 ; Advance to the next mapping page
dbra d0, vssas_loop ; Loop back if there are more frames to read
rts
; Get the pointer to the mapping entry for the page in a0
; Pointer returned in a0
; Address space number in d0
public vmem_get_map_ptr
vmem_get_map_ptr:
move.l d2, -(a7)
; Save the space # in d2
move.l d0, d2
; Get the quarter number * 4096 in d0 (offset of mapping page), and the page number in the quarter * 4 in d1
; qnum_x4k = (addr >> 10 & 0x3000)
; q_pnum_x4 = (addr >> 10 & 0xFFC)
move.l a0, d0
lsr.l #8, d0
lsr.l #2, d0
move.l d0, d1
andi.l #$3000, d0
andi.l #$FFC, d1
; If the quarter is the kernel quarter, the mapping page is fixed
; and we can compute the pointer w/o using the user mapping pages
cmp.l #$3000, d0
bne.b .1
move.l #kernel_map, a0
bra.b .5
.1:
; Get the correct pointers for the space #. Active space for 0, secondary space for 1
cmp.l #0, d2
bne.b .2
move.l vmem_active_space_mapping_ptr, a0
move.l vmem_active_space_ptr, a1
bra.b .4
.2:
cmp.l #1, d2
bne.b .3
move.l vmem_secondary_space_mapping_ptr, a0
move.l vmem_secondary_space_ptr, a1
bra.b .4
.3:
; Halt if invalid space # passed
stop #2700
.4:
; Add the mapping page offset to the base of the mapping pages for the space
adda.l d0, a0
; Shift the mapping page offset to get the quarter # * 4 in d0
lsr.l #8, d0
lsr.l #2, d0
; Get the mapping frame for that quarter
move.l (a1,d0), d0
; Return 0 if the frame is not present
cmp.l #0, d0
bne.b .5
move.l #0, a0
move.l (a7)+, d2
rts
.5:
; Return the mapping page address + (page # * 4)
lea.l (a0,d1), a0
move.l (a7)+, d2
rts
; Unmaps the virtual page at address a0
; Address space number in d0
public vmem_unmap_page
vmem_unmap_page:
movem.l d0/a0, -(a7)
; Clear the page's TLB entry
bsr.w vmem_clear_tlb_entry
movem.l (a7)+, d0/a0
; Set the page entry to 0
bsr.w vmem_get_map_ptr
move.l #0, (a0)
rts
; Sets the mapping for the virtual page at address a0 to d0
; Address space number in d1
vmem_set_page_mapping:
movem.l d2/a2, -(a7)
movem.l d0/d1/a0, -(a7)
; Clear the page's TLB entry
bsr.w vmem_clear_tlb_entry
movem.l (a7)+, d0/d1/a0
movem.l d0/d1/a0, -(a7)
; Get the mapping pointer for the passed-in page
move.l d1, d0
bsr.w vmem_get_map_ptr
move.l a0, a2 ; Save it in a2
movem.l (a7)+, d0/d1/a0
; If there is no pointer, a mapping frame must be allocated, else write the mapping
cmpa.l #0, a2
bne.b .4
move.l d0, -(a7)
movem.l d1/a0, -(a7)
jsr pmem_pop_frame ; Get a physical frame to use
movem.l (a7)+, d1/a0
; Get the passed-in page's quarter # * 4 in d2
move.l a0, d2
lsr.l #8, d2
lsr.l #8, d2
lsr.l #4, d2
andi.l #%1100, d2
; Set the new physical frame as the mapping for the passed-in page's quarter and update the specified address space
cmp.l #0, d1
bne.b .1
movem.l d1/a0, -(a7)
move.l vmem_active_space_ptr, a0
move.l d0, (a0,d2)
bsr.w vmem_activate_addr_space
movem.l (a7)+, d1/a0
bra.b .3
.1:
cmp.l #1, d1
bne.b .2
movem.l d1/a0, -(a7)
move.l vmem_secondary_space_ptr, a0
move.l d0, (a0,d2)
bsr.w vmem_set_secondary_addr_space
movem.l (a7)+, d1/a0
bra.b .3
.2:
; Halt if invalid space # passed
stop #2700
.3:
; Get the new mapping pointer
move.l d1, d0
bsr.w vmem_get_map_ptr
move.l a0, a2
move.l (a7)+, d0
.4:
move.l d0, (a2) ; Write the mapping to the mapping page
movem.l (a7)+, d2/a2
rts
; Sets the permission flags for the virtual page at address a0 to d0
; Address space number in d1
vmem_set_page_flags:
movem.l d2/a2, -(a7)
movem.l d0/d1/a0, -(a7)
; Clear the page's TLB entry
bsr.w vmem_clear_tlb_entry
movem.l (a7)+, d0/d1/a0
movem.l d0/d1/a0, -(a7)
move.l d1, d0
; Get the mapping pointer for the passed-in page
bsr.w vmem_get_map_ptr
move.l a0, a2
movem.l (a7)+, d0/d1/a1
; If there is no pointer, return
cmpa.l #0, a2
beq.b .1
move.l (a2), d1 ; Read the old entry
andi.l #(~$FFE), d1 ; Clear the permission flags on the old entry
or.l d0, d1 ; Set the new permission flags
move.l d1, (a2) ; Write the entry
.1:
movem.l (a7)+, d2/a2
rts
; Maps the virtual page at address a0 to the physical frame at address d0
; d0 must have none of its lower 12 bits set
; Address space number in d1
; Permission flags in d2
vmem_map_page_to:
; Set the passed-in permission flags and the present flag on the passed-in page number
or.l d2, d0
or.l #1, d0
bra.w vmem_set_page_mapping
; Maps the virtual page at address a0 to a free physical frame
; Address space number in d0
; Permission flags in d1
vmem_map_page:
; Separate the register pushes to allow popping them directly
; into the right registers for vmem_map_page_to's arguments
move.l d2, -(a7)
move.l a0, -(a7)
move.l d0, -(a7)
move.l d1, -(a7)
jsr pmem_pop_frame
movem.l (a7)+, d2
movem.l (a7)+, d1
movem.l (a7)+, a0
bsr.w vmem_map_page_to
move.l (a7)+, d2
rts
; Unmaps the range of virtual pages at address a0 with length d0
; Address space number in d1
public vmem_unmap
vmem_unmap:
subi.l #1, d0 ; Subtract 1 to account for the extra loop done by dbra
vmem_um_loop:
movem.l d0/d1/a0, -(a7)
move.l d1, d0
bsr.w vmem_unmap_page
movem.l (a7)+, d0/d1/a0
adda.l #$1000, a0
dbra d0, vmem_um_loop
rts
; Sets the permission flags of the range of virtual pages starting at address a0 with length d1 to d0
; Address space number in d2
public vmem_set_flags
vmem_set_flags:
subi.l #1, d1 ; Subtract 1 to account for the extra loop done by dbra
vmem_sf_loop:
movem.l d0/d1/a0, -(a7)
move.l d2, d1
bsr.w vmem_set_page_flags
movem.l (a7)+, d0/d1/a0
adda.l #$1000, a0
dbra d1, vmem_sf_loop
rts
; Maps the range of virtual pages starting at address a0 with length d1 to the range of physical frames starting at d0
; d0 must have none of its lower 12 bits set
; Address space number in d2
; Permission flags in d3
public vmem_map_to
vmem_map_to:
subi.l #1, d1 ; Subtract 1 to account for the extra loop done by dbra
vmem_mt_loop:
movem.l d0/d1/d2/a0, -(a7)
move.l d2, d1
move.l d3, d2
bsr.w vmem_map_page_to
movem.l (a7)+, d0/d1/d2/a0
adda.l #$1000, a0
add.l #$1000, d0
dbra d1, vmem_mt_loop
rts
; Maps the range of virtual pages starting at address a0 with length d0 to free physical frames
; Address space number in d1
; Permission flags in d2
public vmem_map
vmem_map:
subi.l #1, d0 ; Subtract 1 to account for the extra loop done by dbra
vmem_m_loop:
movem.l d0/d1/a0, -(a7)
move.l d1, d0
move.l d2, d1
bsr.w vmem_map_page
movem.l (a7)+, d0/d1/a0
adda.l #$1000, a0
dbra d0, vmem_m_loop
rts
; Maps a free range of virtual pages with length d0 to free physical frames
; Returns the range start in a0
; Address space number in d1
; Permission flags in d2
public vmem_map_free
vmem_map_free:
movem.l d0/d1/d3, -(a7)
move.l d1, d3
; Use bit 2 of the address space # to choose between getting free user or kernel
; pages as only 0 and 1 are valid address space #s, requiring only bit 0.
andi.l #$2, d3
beq.b .1
bsr.w vmem_get_free_user_pages
bra.b .2
.1:
bsr.b vmem_get_free_kernel_pages
.2:
movem.l (a7)+, d0/d1/d3
; Clear bit 2 to make the passed-in address space # valid for the rest of the VMM code
andi.l #$1, d1
move.l a0, -(a7)
bsr.b vmem_map
move.l (a7)+, a0
rts
; Maps a free range of virtual pages with length d1 to the range of physical frames starting at d0
; Returns the range start in a0
; Address space number in d2
; Permission flags in d3
public vmem_map_free_to
vmem_map_free_to:
movem.l d0/d1/d3, -(a7)
move.l d1, d0
move.l d2, d3
; Use bit 2 of the address space # to choose between getting free user or kernel
; pages as only 0 and 1 are valid address space #s, requiring only bit 0.
andi.l #$2, d3
beq.b .1
bsr.w vmem_get_free_user_pages
bra.b .2
.1:
bsr.b vmem_get_free_kernel_pages
.2:
movem.l (a7)+, d0/d1/d3
; Clear bit 2 to make the passed-in address space # valid for the rest of the VMM code
andi.l #$1, d2
move.l a0, -(a7)
bsr.w vmem_map_to
move.l (a7)+, a0
rts
; Copies the range of page mappings at address a0 in the primary space with length d0 to the secondary space starting at address a1
public vmem_copy_to_secondary
vmem_copy_to_secondary:
move.l d0, -(a7)
; Get the mapping pointer for the start page in the primary address space
move.l #0, d0
bsr.w vmem_get_map_ptr
move.l (a7)+, d0
subi.l #1, d0 ; Subtract 1 to account for the extra loop done by dbra
vmem_cts_loop:
; Read the next page mapping and increment the pointer
move.l (a0)+, d1
movem.l d0/a0/a1, -(a7)
; Set the same mapping in the secondary address space at address a1
move.l d1, d0
move.l #1, d1
move.l a1, a0
bsr.w vmem_set_page_mapping
movem.l (a7)+, d0/a0/a1
adda.l #$1000, a1
dbra d0, vmem_cts_loop
rts
; Get a range of free kernel pages with length in d0 and return its start in a0
public vmem_get_free_kernel_pages
vmem_get_free_kernel_pages:
move.l d2, -(a7)
move.l d0, d1 ; Set the remaining page # count to the length of the requested range
move.l #$C00000, a0 ; Put the start page of the search in a0
vmem_gfkp_loop:
movem.l d0/d1/a0, -(a7)
move.l #0, d0 ; Get the pointer for the current page
bsr.w vmem_get_map_ptr
; If NULL, load dummy free mapping, otherwise read page mapping into d2
cmpa.l #0, a0
beq.b .1
move.l (a0), d2
bra.b .2
.1:
move.l #0, d2
.2:
movem.l (a7)+, d0/d1/a0
btst #0, d2 ; If the page is not free, skip it
beq.b .3
subi.l #1, d1
bne.b .4 ; If we have not found a run of pages of the right length, continue to check for free pages
adda.l #$1000, a0 ; Start address is (current_page + $1000 - (length * $1000)), compute this in d0 and return
lsl.l #8, d0
lsl.l #4, d0
suba.l d0, a0
move.l (a7)+, d2
rts
.3:
move.l d0, d1 ; Page not free, reset the page # count and try again
.4:
adda.l #$1000, a0 ; Move to the next page and continue the search
bra.b vmem_gfkp_loop
; Get a range of free user pages with length in d0 and return its start in a0
public vmem_get_free_user_pages
vmem_get_free_user_pages:
move.l d2, -(a7)
move.l d0, d1 ; Set the remaining page # count to the length of the requested range
move.l #$1000, a0 ; Put the start page of the search in a0
vmem_gfup_loop:
movem.l d0/d1/a0, -(a7)
move.l #0, d0 ; Get the pointer for the current page
bsr.w vmem_get_map_ptr
; If NULL, load dummy free mapping, otherwise read page mapping into d2
cmpa.l #0, a0
beq.b .1
move.l (a0), d2
bra.b .2
.1:
move.l #0, d2
.2:
movem.l (a7)+, d0/d1/a0
btst #0, d2 ; If the page is not free, skip it
beq.b .3
subi.l #1, d1
bne.b .4 ; If we have not found a run of pages of the right length, continue to check for free pages
adda.l #$1000, a0 ; Start address is (current_page + $1000 - (length * $1000)), compute this in d0 and return
lsl.l #8, d0
lsl.l #4, d0
suba.l d0, a0
move.l (a7)+, d2
rts
.3:
move.l d0, d1 ; Page not free, reset the page # count and try again
.4:
adda.l #$1000, a0 ; Move to the next page and continue the search
bra.b vmem_gfup_loop
section .data,data
public kernel_address_space
kernel_address_space:
dc.l $0, $0, $0, kernel_map - $C00000
vmem_active_space_ptr: dc.l kernel_address_space
section .bss,bss
public vmem_mmu_base_addr
vmem_mmu_base_addr: ds.l 1
vmem_secondary_space_ptr: ds.l 1
vmem_active_space_mapping_ptr: ds.l 1
vmem_secondary_space_mapping_ptr: ds.l 1

51
vmem.i Normal file
View File

@ -0,0 +1,51 @@
ifnd VMEM_I
VMEM_I equ 1
; Initialize the virtual memory manager
xref vmem_init
; Clears the TLB entry of the page pointed to by a0
xref vmem_clear_tlb_entry
; Activates the address space pointed to by a0
xref vmem_activate_addr_space
; Sets the secondary address space
xref vmem_set_secondary_addr_space
; Get the pointer to the mapping entry for the page in a0
; Pointer returned in a0
; Address space number in d0
xref vmem_get_map_ptr
; Unmaps the virtual page at address a0
; Address space number in d0
xref vmem_unmap_page
; Unmaps the range of virtual pages at address a0 with length d0
; Address space number in d1
xref vmem_unmap
; Sets the permission flags of the range of virtual pages starting at address a0 with length d1 to d0
; Address space number in d2
xref vmem_set_flags
; Maps the range of virtual pages starting at address a0 with length d1 to the range of physical frames starting at d0
; d0 must have none of its lower 12 bits set
; Address space number in d2
; Permission flags in d3
xref vmem_map_to
; Maps the range of virtual pages starting at address a0 with length d0 to free physical frames
; Address space number in d1
; Permission flags in d2
xref vmem_map
; Maps a free range of virtual pages with length d0 to free physical frames
; Returns the range start in a0
; Address space number in d1
; Permission flags in d2
xref vmem_map_free
; Maps a free range of virtual pages with length d1 to the range of physical frames starting at d0
; Returns the range start in a0
; Address space number in d2
; Permission flags in d3
xref vmem_map_free_to
; Copies the range of page mappings at address a0 in the primary space with length d0 to the secondary space starting at address a1
xref vmem_copy_to_secondary
; Get a range of free kernel pages with length in d0 and return its start in a0
xref vmem_get_free_kernel_pages
; Get a range of free user pages with length in d0 and return its start in a0
xref vmem_get_free_user_pages
xref kernel_address_space
xref vmem_mmu_base_addr
endif