The biggest issues that jump out at me are the horrible overuse of magic numbers (#define is your friend, especially when working with the GDT and IDT) and the disabling of interrupts and paging when copying an address space (the latter of which is slow and the former of which prevents concurrency -- imagine how well Linux would work if every fork() were terribly slow and stopped the world -- doing this in even a halfway reasonable way is not hard). Inline assembly is also a really bad idea for portability and maintainability, the latter of which you at least care about for a toy kernel. I'm also not sure why they are disabling interrupts so much in general... and on and on.
Again, a very interesting read for kernel-development-n00bs, I'm sure, but a lot of their code is very, very, terrifyingly wrong even for a toy kernel. Our OS class has students write a kernel somewhat like this one; the class provides a list of things which you are not to ever do, ever, oh god, or you will fail. This article does a staggering number of those things.