Initial commit
This commit is contained in:
commit
92e9bda9bd
7
Tupfile
Normal file
7
Tupfile
Normal 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
6
Tuprules.tup
Normal 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
39
cards.68k
Normal 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
6
cards.i
Normal 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
237
elf.i
Normal 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
154
initrd.68k
Normal 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
17
initrd.i
Normal 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
35
kernel.ld
Normal 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
11
libstd_override.68k
Normal 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
146
main.68k
Normal 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
150
pmem.68k
Normal 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
11
pmem.i
Normal 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
86
start.68k
Normal 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
5
start.i
Normal file
@ -0,0 +1,5 @@
|
||||
ifnd START_I
|
||||
START_I equ 1
|
||||
xref __start
|
||||
xref kernel_map
|
||||
endif
|
6
syscall.i
Normal file
6
syscall.i
Normal 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
66
syscalls.68k
Normal 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
234
tasking.68k
Normal 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
13
tasking.i
Normal 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
35
term.68k
Normal 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
9
term.i
Normal 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
271
traps.68k
Normal 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
5
traps.i
Normal file
@ -0,0 +1,5 @@
|
||||
ifnd TRAPS_I
|
||||
TRAPS_I equ 1
|
||||
; Initialize trap handling
|
||||
xref traps_init
|
||||
endif
|
491
vmem.68k
Normal file
491
vmem.68k
Normal 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
51
vmem.i
Normal 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
|
Loading…
Reference in New Issue
Block a user