Port kernel to Jmk2
diff --git a/include/kernel/dri/fs/ext2/ext2.h b/include/kernel/dri/fs/ext2/ext2.h
index 9b6d5ba..8f5b0b9 100644
--- a/include/kernel/dri/fs/ext2/ext2.h
+++ b/include/kernel/dri/fs/ext2/ext2.h
@@ -237,7 +237,7 @@
 /// File type flag (used on inode->mode)
 #define EXT2_F_TYPE 0xf000
 
-const extern uchar ext2_s_to_ft[];
+extern const uchar ext2_s_to_ft[];
 
 /// Converts the file "mode" (inode->mode, EXT2_S_*) to a file type
 /// (EXT2_FT_*).
diff --git a/share/jmk/jmk.tcl b/share/jmk/jmk.tcl
index d1de805..b3b860c 100644
--- a/share/jmk/jmk.tcl
+++ b/share/jmk/jmk.tcl
@@ -2,11 +2,20 @@
 
 variable jmk_name {}
 variable jmk_target {}
+variable jmk_clean_libs {}
+variable jmk_phony_libs {}
+variable jmk_lib_paths
+variable jmk_lib_targets
+
 variable cflags {}
 variable asmflags {}
+variable ldflags {}
 
 variable asm as
-variable cc cc
+variable cc gcc
+variable ld ld
+
+variable objs {}
 
 # variable options
 
@@ -28,6 +37,11 @@
 	puts {MAKEFILE_DEPTH ?= 1}
 
 	rule all $target {}
+
+	rule Makefile Jmk2 {
+		log JMK2 ""
+		shell "cd $::jmk_build_dir && $::jmk_build_cmd"
+	}
 }
 
 proc preset {p} {
@@ -62,6 +76,17 @@
 	}
 }
 
+proc ldflag {arg} {
+	global ldflags
+	set ldflags "$ldflags $arg"
+}
+
+proc ldflags {args} {
+	foreach arg $args {
+		ldflag $arg
+	}
+}
+
 proc option {name val} {
 	global options
 	if {![info exists options($name)]} {
@@ -70,7 +95,7 @@
 }
 
 proc log {category message} {
-	puts "\t@printf '\\e\[1;34m%8s\\e\[m  %s\\n' '$category' '$message' > /dev/stderr"
+	puts "\t@printf ' \\e\[1;34m%8s\\e\[m  %s\\n' '$category' '$message' > /dev/stderr"
 }
 
 proc cc {command} {
@@ -85,33 +110,62 @@
 	puts "\t@$command"
 }
 
+proc make {command} {
+	shell "\$(MAKE) --no-print-directory MAKEFILE_DEPTH=\$\$((\$(MAKEFILE_DEPTH)+1)) $command"
+}
+
 proc rule {target deps does} {
 	puts ""
 	puts "$target: $deps"
-	eval $does
+	uplevel 1 $does
 }
 
 proc type {type} {
 	::type::$type
 }
 
+proc objs {args} {
+	foreach obj $args {
+		set ::objs "$::objs $obj"
+	}
+}
+
 proc srcs {args} {
 	puts ""
 	variable objs ""
 
 	foreach src $args {
 		variable obj [regsub -- {(.+)\.\w+} $src {\1.o}]
-		variable objs "$objs $obj"
+		set ::objs "$::objs $obj"
+	}
+}
+
+proc depends {name path {target DEFAULT_TARGET}} {
+	if {$target eq {DEFAULT_TARGET}} {
+		variable target "lib${name}.a"
 	}
 
-	puts "OBJECTS += $objs"
+	set ::jmk_clean_libs "$::jmk_clean_libs $path"
+	set ::jmk_lib_paths($name) $path
+	set ::jmk_lib_target($name) $target
+	set ::jmk_phony_libs "$::jmk_phony_libs $path"
+
+	rule "$path/$target" {} {
+		log "MAKE\[\$(MAKEFILE_DEPTH)\]" "Entering $name"
+		make "-C $path $target"
+		log "MAKE\[\$(MAKEFILE_DEPTH)\]" "Leaving $name"
+	}
+}
+
+proc lib {name} {
+	return "$::jmk_lib_paths($name)/$::jmk_lib_target($name)"
 }
 
 namespace eval type {
 	proc executable {} {
 		global jmk_target
 
-		rule $jmk_target "\$(OBJECTS)" {
+		rule $jmk_target $::objs {
 			log LD $::target
 			cc "-o $::target $::src"
 		}
@@ -119,6 +173,17 @@
 		helpers
 	}
 
+proc custom_link {} {
+	global jmk_target
+
+	rule $jmk_target $::objs {
+		log LD $::target
+		shell "$::ld $::ldflags -o $::target $::src"
+	}
+
+	helpers
+}
+
 proc helpers {} {
 	rule .c.o {} {
 		log CC $::first_src
@@ -131,9 +196,13 @@
 	}
 
 	rule clean {} {
-		shell "rm -f **/*.o **/*.a *.so $::target \$(OBJECTS)"
+		shell "rm -f **/*.o **/*.a *.so $::jmk_target $::objs"
+
+		foreach lib $::jmk_clean_libs {
+			make "-C $lib clean"
+		}
 	}
-}	
+}
 }
 
 namespace eval preset {
@@ -156,7 +225,7 @@
 	}
 
 	proc warn {} {
-		cflags -Wall -Wextra -Wno-unused-function -Wno-unused-variable -Wno-incompatible-pointer-types -Werror
+		cflags -Wall -Wno-unused-function -Wno-unused-variable -Wno-incompatible-pointer-types -Wno-sign-compare
 	}
 
 	proc nasm {} {
diff --git a/src/kernel/Jmk2 b/src/kernel/Jmk2
new file mode 100644
index 0000000..21b7ebe
--- /dev/null
+++ b/src/kernel/Jmk2
@@ -0,0 +1,72 @@
+# -*- tcl -*-
+
+init kernel kernel.elf
+
+presets freestanding debug 32 warn nasm
+
+cflags -I$root/include/kernel -I$root/include -O0 -Wno-ignored-qualifiers -Wno-sign-compare
+
+ldflags -Tlink.ld -melf_i386
+asmflags -felf -Fdwarf
+set qemuflags "-drive file=hd0_ext2.img,format=raw"
+
+depends sys $root/src/libsys libsys.a
+depends initrd $root/boot/initrd initrd.img
+depends ata_pio dri/ata_pio ata_pio.a
+depends pci dri/pci pci.a
+depends ide dri/ide ide.a
+depends ext2 dri/fs/ext2 ext2.a
+
+option FS ext2
+
+srcs boot.s \
+	main.c \
+	descriptor_tables.c \
+	io.c \
+	vga.c \
+	gdt_flush.s \
+	tss_flush.s \
+	idt.s \
+	log.c \
+	irq.c \
+	pic.c \
+	timer.c \
+	paging.c \
+	switch_table.s \
+	scan_codes.c \
+	kheap.c \
+	alloc.c \
+	vfs.c \
+	multiboot.c \
+	vfs_initrd.c \
+	syscall.c \
+	task.c \
+	task_api.s \
+	faults.c \
+	sync.c
+
+objs [lib ext2] \
+	[lib ide] \
+	[lib ata_pio] \
+	[lib pci] \
+	[lib sys]
+
+type custom_link
+
+rule debug-wait kernel.elf {
+	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.efl"
+}
+rule debug kernel.elf {
+	shell "qemu-system-i386 -s -S $::qemuflags -kernel kernel.efl"
+	shell "echo run target remote localhost:1234 to connect to qemu"
+	shell "gdb $::first_src"
+	shell "pkill qemu-system-i386"
+}
+
+rule qemu "kernel.elf hd0_$::options(FS).img" {
+	shell "qemu-system-i386 $::qemuflags -d cpu_reset -monitor stdio -kernel kernel.elf -no-reboot"
+}
+
+rule scan_codes.c "gen_scan_codes.py scan_codes.tsv" {
+	shell "python3 $::first_src > $::target"
+}