import util

#This is for parsing Multiboot _2_ data

type MBTagStub is
int type
int size
endtype

type RawMultibootInfo is packed
int total_size
int _reserved0

function(RawMultibootInfo i, int idx) RawMultibootInfo:get_tag -> MBTagStub does
int curr_tag=0
int curr_off=8 #Start after header
ptr base=i|ptr

while curr_off<i.total_size do
if curr_tag==idx do
return (base:offset(curr_off)|MBTagStub)
done
curr_off+=(base:offset(curr_off)|MBTagStub).size
if (curr_off%8)!=0 do
curr_off+=8-(curr_off%8)
done
curr_tag+=1
done
return 0|ptr|MBTagStub

function(RawMultibootInfo i, int reqtype) RawMultibootInfo:get_type -> MBTagStub does
int idx=0
MBTagStub curr=i:get_tag(0)
while curr.type!=0 do
if curr.type==reqtype do
return curr
done

idx+=1
curr=i:get_tag(idx)
done
return (0|ptr|MBTagStub)

function(RawMultibootInfo i, int reqtype) RawMultibootInfo:has_type -> bool does
int idx=0
MBTagStub curr=i:get_tag(0)
while curr.type!=0 do
if curr.type==reqtype do
return 1|bool
done
idx+=1
curr=i:get_tag(idx)
done
return (0|bool)

function(RawMultibootInfo i) RawMultibootInfo:print -> void does
kterm:print("Total Size: ")
kterm:printi(i.total_size)
kterm:print("\n")

int idx=0
MBTagStub curr=i:get_tag(0)
while curr.type!=0 do
kterm:printi(idx)
kterm:print(" - ")

if curr.type==1 do
kterm:print("Cmdline tag, cmdline=`")
kterm:print((curr|ptr):offset(8)|cstr)
kterm:print("'")
elif curr.type==2 do
kterm:print("Loader tag, name=`")
kterm:print((curr|ptr):offset(8)|cstr)
kterm:print("'")
elif curr.type==3 do
kterm:print("Module tag, args=")
kterm:print((curr|MBModuleTag):get_args())
elif curr.type==4 do
kterm:print("BasicMem tag, lower=")
kterm:printi((curr|MBBasicMemTag).mem_lower)
kterm:print(", upper=")
kterm:printi((curr|MBBasicMemTag).mem_upper)
elif curr.type==5 do
kterm:print("Boot Device tag, dev=")
kterm:dumphex((curr|MBDeviceTag).biosdev, 2)
kterm:print(", p=")
kterm:dumphex((curr|MBDeviceTag).part, 2)
kterm:print(":")
kterm:dumphex((curr|MBDeviceTag).spart, 2)
elif curr.type==6 do
kterm:print("MMAP Tag esz=")
kterm:printi((curr|MBMMAPMemTag).entry_size)
kterm:print(", ev=")
kterm:printi((curr|MBMMAPMemTag).entry_version)
kterm:print(", #=")
kterm:printi(curr.size/(curr|MBMMAPMemTag).entry_size)
(curr|MBMMAPMemTag):print()
elif curr.type==7 do
kterm:print("VBE Info Tag:. Controller info:\n")
((curr|ptr):offset(16)|RawVBEControllerInfo):print()
kterm:print("\nMode info:\n")
((curr|ptr):offset(16+512)|RawVBEModeInfo):print()
elif curr.type==8 do
MBFBMemTag tag = curr|MBFBMemTag
kterm:print("FB Tag addr=")
kterm:dumphexi(tag.address|int)
kterm:print(", pitch=")
kterm:printi(tag.pitch)
kterm:print(", width=")
kterm:printi(tag.width)
kterm:print(", height=")
kterm:printi(tag.height)
kterm:print(", bpp=")
kterm:printi(tag.bpp|int)
kterm:print(", fbtype=")
kterm:printi(tag.fbtype|int)
elif curr.type==10 do
kterm:print("APM Tag (unk.)")
elif curr.type==14 do
kterm:print("RSDP1 Tag, oem=")
(curr|MBRSDP1Tag):printOEM()
elif curr.type==15 do
kterm:print("RSDP2 Tag, oem=")
(curr|MBRSDP1Tag):printOEM()
elif curr.type==16 do
kterm:print("NIC Tag (unk.)")
else do
kterm:print("??? Tag")
done

kterm:print(", type=")
kterm:printi(curr.type)
kterm:print(", sz=")
kterm:printi(curr.size)
kterm:print(", pos=")
kterm:dumphexi(curr|ptr|int)
kterm:print("\n")

idx+=1
curr=i:get_tag(idx)
if curr|ptr|int==0 do
kterm:print("\nMalformed structure, no terminator tag!\n")
return
done

if curr.type==0 do
kterm:print("Reached End Tag\n")
done
done
return
endtype

type MBBasicMemTag is packed
int type
int size
int mem_lower
int mem_upper
endtype

type MBMMAPMemTagEntry is packed
long base_addr
long length
int type
int reserved
endtype

type MBMMAPMemTag is packed
int type
int size
int entry_size
int entry_version

function(MBMMAPMemTag t) MBMMAPMemTag:print -> void does
int count=(t.size-8)/t.entry_size
int idx=0
MBMMAPMemTagEntry entry
while idx<count do
entry=(t|ptr):offset(16+(t.entry_size*idx))|MBMMAPMemTagEntry
kterm:print("\n MMAP Tag ")
kterm:printi(idx)
kterm:print(" - type=")
kterm:printi(entry.type)
kterm:print(", start=")
kterm:dumphexi(entry.base_addr|int)
kterm:print(", len=")
kterm:dumphexi(entry.length|int)
idx+=1
done
return
endtype

type MBFBMemTag is packed
int type
int size
long address
int pitch
int width
int height
byte bpp
byte fbtype
byte reserved
endtype

type MBDeviceTag is packed
int type
int size
int biosdev
int part
int spart
endtype

type MBModuleTag is packed
int type
int size
int start
int end

function(MBModuleTag t) MBModuleTag:get_args -> cstr does
return (t|ptr):offset(@sizeof(MBModuleTag)@)|cstr

function(MBModuleTag t) MBModuleTag:get_addr -> ptr does
return (t.start+base_vma)|ptr
endtype

type MBRSDP1Tag is packed
int type
int size
long sig
byte checksum
byte oem0
byte oem1
byte oem2
byte oem3
byte oem4
byte oem5

function(MBRSDP1Tag t) MBRSDP1Tag:printOEM -> void does
kterm:putchar(t.oem0)
kterm:putchar(t.oem1)
kterm:putchar(t.oem2)
kterm:putchar(t.oem3)
kterm:putchar(t.oem4)
kterm:putchar(t.oem5)
return
endtype

type MultibootModuleInfo is
cstr params
ptr contents
int size
MultibootModuleInfo _next

function(MBModuleTag tag) MultibootModuleInfo::new -> MultibootModuleInfo does
MultibootModuleInfo new = malloc(@sizeof(MultibootModuleInfo)@)|MultibootModuleInfo
new.params=tag:get_args()
new.contents=tag:get_addr()
new.size=tag.end-tag.start
new._next=0|ptr|MultibootModuleInfo
return new
endtype

type MultibootInfo is
ptr mb_phys_addr
RawMultibootInfo mb_raw
bool valid
cstr bootloader
cstr cmdline
bool text_mode
int screen_w
int screen_h
int screen_pitch
int screen_depth #in bits
int fb_raw_addr
ptr fb_addr
int boot_device
int module_count
MultibootModuleInfo _firstmodule

function(ptr phys_addr) MultibootInfo::load -> MultibootInfo does
MultibootInfo new = malloc(@sizeof(MultibootInfo)@)|MultibootInfo
new.mb_phys_addr=phys_addr
new.mb_raw=phys_addr:offset(base_vma)|RawMultibootInfo
new.valid=0|bool

if phys_addr|int >= 0x400000 do
return new
done

if new.mb_raw:has_type(1) do
if new.mb_raw:has_type(2) do
if new.mb_raw:has_type(5) do
if new.mb_raw:has_type(8) do
new.valid=1|bool
new.cmdline=(new.mb_raw:get_type(1)|ptr):offset(8)|cstr
new.bootloader=((new.mb_raw:get_type(2)|ptr):offset(8))|cstr
new.boot_device=(new.mb_raw:get_type(5)|MBDeviceTag).biosdev

MBFBMemTag fb = new.mb_raw:get_type(8)|MBFBMemTag

new.text_mode=fb.fbtype==2|byte
new.screen_w=fb.width
new.screen_h=fb.height
new.screen_pitch=fb.pitch
new.screen_depth=fb.bpp|int
new.fb_raw_addr=fb.address|int
new.fb_addr=(fb.address|int|ptr):offset(base_vma)

new.module_count=0

int idx=0
MBTagStub tag=new.mb_raw:get_tag(0)
MultibootModuleInfo tail
while tag.type!=0 do
if tag.type==3 do
if new.module_count==0 do
new._firstmodule=MultibootModuleInfo::new(tag|MBModuleTag)
tail=new._firstmodule
else do
tail._next=MultibootModuleInfo::new(tag|MBModuleTag)
tail=tail._next
done
new.module_count+=1
done
idx+=1
tag=new.mb_raw:get_tag(idx)
done

return new
done
done
done
done
return new

function(MultibootInfo i, cstr args) MultibootInfo:get_mod_by_args -> MultibootModuleInfo does
if i.module_count==0 do
return 0|ptr|MultibootModuleInfo
done

MultibootModuleInfo cur = i._firstmodule
int idx=0
while idx<i.module_count do
if cur.params==args do
return cur
done

idx+=1
cur=cur._next
done
return 0|ptr|MultibootModuleInfo
endtype

type RawVBEControllerInfo is packed
byte sig_0
byte sig_1
byte sig_2
byte sig_3

short version

short oem_string_seg
short oem_string_addr

byte capabilities_0
byte capabilities_1
byte capabilities_2
byte capabilities_3

short vmode_seg
short vmode_addr

short avail_mem #number of 64kb blocks

function(RawVBEControllerInfo i) RawVBEControllerInfo:print -> void does
kterm:print(" Signature: ")
kterm:putchar(i.sig_0)
kterm:putchar(i.sig_1)
kterm:putchar(i.sig_2)
kterm:putchar(i.sig_3)
kterm:print("\n Version: ")
kterm:dumphex(i.version|int, 4)
kterm:print("\n OEM String FarPtr: ")
kterm:dumphex(i.oem_string_seg|int, 4)
kterm:print(":")
kterm:dumphex(i.oem_string_addr|int, 4)
kterm:print("\n Capabilities: ")
kterm:dumphex(i.capabilities_0|int, 2)
kterm:print(" ")
kterm:dumphex(i.capabilities_1|int, 2)
kterm:print(" ")
kterm:dumphex(i.capabilities_2|int, 2)
kterm:print(" ")
kterm:dumphex(i.capabilities_3|int, 2)
kterm:print("\n VMode FarPtr: ")
kterm:dumphex(i.vmode_seg|int, 4)
kterm:print(":")
kterm:dumphex(i.vmode_addr|int, 4)
kterm:print("\n Availible Memory (64KB units): ")
kterm:printi(i.avail_mem|int)
return
endtype

type RawVBEModeInfo is packed
short attributes
byte attrsA
byte attrsB
short granularity
short winsize
short segA
short segB

short unk_ptr_seg
short unk_ptr_addr

short pitch #bytes per line
short xres
short yres

byte wchar
byte ychar
byte planes
byte bpp
byte banks

byte memmodel
byte banksize
byte imgpage
byte res0

byte redmask
byte redpos
byte greenmask
byte greenpos
byte bluemask
byte bluepos
byte rsvmask
byte rsvpos

byte directcolor_attrs

int lfb_physaddr
int res1
short res2

function(RawVBEModeInfo i) RawVBEModeInfo:print -> void does
kterm:print(" Attributes:")
kterm:dumpbin(i.attributes|int)
kterm:print(" ")
kterm:dumphex(i.attrsA|int, 2)
kterm:print(":")
kterm:dumphex(i.attrsB|int, 2)

kterm:print("\n Res: ")
kterm:printi(i.xres|int)
kterm:print("x")
kterm:printi(i.yres|int)
kterm:print("x")
kterm:printi(i.bpp|int)

kterm:print("\n Pitch: ")
kterm:dumphex(i.pitch|int, 4)
kterm:print(" PysAddr: ")
kterm:dumphexi(i.lfb_physaddr)
kterm:print("\n")
return
endtype