kernel/start.68k
2024-03-19 09:24:10 -05:00

87 lines
3.6 KiB
Plaintext

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