Advertisement
Guest User

minimalexample

a guest
Aug 23rd, 2022
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.09 KB | None | 0 0
  1. --[kernel.c]---------------------
  2.  
  3. #define PIC1        0x20
  4. #define PIC2        0xA0
  5. #define PIC1_COMMAND    PIC1
  6. #define PIC1_DATA   (PIC1+1)
  7. #define PIC2_COMMAND    PIC2
  8. #define PIC2_DATA   (PIC2+1)
  9.  
  10. #define ICW1_ICW4   0x01
  11. #define ICW1_SINGLE 0x02
  12. #define ICW1_INTERVAL4  0x04
  13. #define ICW1_LEVEL  0x08
  14. #define ICW1_INIT   0x10
  15.  
  16. #define ICW4_8086   0x01
  17. #define ICW4_AUTO   0x02
  18. #define ICW4_BUF_SLAVE  0x08
  19. #define ICW4_BUF_MASTER 0x0C
  20. #define ICW4_SFNM   0x10
  21.  
  22. typedef unsigned char uint8_t;
  23. typedef unsigned short uint16_t;
  24. typedef unsigned int uint32_t;
  25. typedef unsigned long long uint64_t;
  26.  
  27. typedef char int8_t;
  28. typedef short int16_t;
  29. typedef int int32_t;
  30. typedef long long int64_t;
  31.  
  32. typedef enum {
  33.     /* Traps */
  34.     IV_DIV0     = 0x00, // Divide by 0
  35.     IV_RSV1     = 0x01, // Reserved
  36.     IV_NMI      = 0x02, // NMI Interrupt
  37.     IV_BRKP     = 0x03, // Breakpoint (INT3)
  38.     IV_OVRF     = 0x04, // Overflow (INTO)
  39.     IV_BOUNDS   = 0x05, // Bounds range exceeded (BOUND)
  40.     IV_INVALOP  = 0x06, // Invalid opcode (UD2)
  41.     IV_DEVAVAIL = 0x07, // Device not available (WAIT/FWAIT)
  42.     IV_DFAULT   = 0x08, // Double fault
  43.     IV_SEGOVRR  = 0x09, // Coprocessor segment overrun
  44.     IV_INVALTSS = 0x0A, // Invalid TSS
  45.     IV_SEGNPRES = 0x0B, // Segment not present
  46.     IV_STACKFLT = 0x0C, // Stack-segment fault
  47.     IV_GPFLT    = 0x0D, // General protection fault
  48.     IV_PAGEFLT  = 0x0E, // Page fault
  49.     IV_RSV2     = 0x0F, // Reserved
  50.     IV_FPUERR   = 0x10, // x87 FPU error
  51.     IV_ALIGNCHK = 0x11, // Alignment check
  52.     IV_MCHK     = 0x12, // Machine check
  53.     IV_SIMDFP   = 0x13, // SIMD Floating-Point Exception
  54.  
  55.     /* 0x14 - 0x1F Reserved */
  56.  
  57.     /* Interrupts */
  58.     IV_TIMER    = 0x20,
  59.     IV_KEYBOARD = 0x21,
  60.  
  61.     IV_PANIC    = 0x63,
  62.  
  63.     IV_COUNT = 0x100
  64. } interrupt_vector;
  65.  
  66. typedef union interrupt_descriptor interrupt_descriptor;
  67.  
  68. struct idtr {
  69.     uint16_t limit;
  70.     uint32_t base;
  71. } __attribute__((packed));
  72.  
  73. union interrupt_descriptor {
  74.     struct {
  75.         uint64_t offsetl   : 16,
  76.                  segsel    : 16,
  77.                  reserved  :  8,
  78.                  gate_type :  4,
  79.                  zero      :  1,
  80.                  dpl       :  2,
  81.                  present   :  1,
  82.                  offseth   : 16;
  83.     } __attribute__((packed));
  84.     uint64_t value;
  85. };
  86.  
  87. struct gdtr {
  88.     uint16_t limit;
  89.     uint32_t base;
  90. } __attribute__((packed));
  91.  
  92. typedef union {
  93.     struct {
  94.         uint64_t limitl : 16,
  95.                  basel  : 24,
  96.                  access :  8,
  97.                  limith :  4,
  98.                  flags  :  4,
  99.                  baseh  :  8;
  100.     } __attribute__((packed));
  101.     uint64_t value;
  102. } segment_descriptor;
  103.  
  104.  
  105. interrupt_descriptor idt[256];
  106. extern void* interrupt_entries;
  107. extern segment_descriptor gdt;
  108.  
  109. uint8_t ioport_read8(uint32_t port) {
  110.     uint8_t out;
  111.     asm("in %%dx, %%al"
  112.             : "=a"(out)
  113.             : "d"(port)
  114.             :
  115.     );
  116.     return out;
  117. }
  118.  
  119. void ioport_write8(uint32_t port, uint8_t b) {
  120.     asm("out %%al, %%dx"
  121.             :
  122.             : "a"(b), "d"(port)
  123.             :
  124.     );
  125. }
  126.  
  127. static interrupt_descriptor idte_create(uint32_t off, uint8_t gate_type, uint8_t dpl) {
  128.     interrupt_descriptor desc;
  129.  
  130.     desc.offsetl = off & 0xFFFF;
  131.     desc.offseth = (off >> 16) &0xFFFF;
  132.  
  133.     desc.segsel    = 8;
  134.     desc.gate_type = gate_type & 0xF;
  135.     desc.zero      = 0;
  136.     desc.dpl       = dpl & 0x3;
  137.     desc.present   = 1;
  138.     desc.reserved  = 0;
  139.     return desc;
  140. }
  141.  
  142. void eoi(unsigned char irq)
  143. {
  144.     uint32_t pic1_c = 0x20;
  145.     uint32_t pic2_c = 0xA0;
  146.  
  147.     if(irq >= 8) {
  148.         ioport_write8(pic2_c, 0x20);
  149.     }
  150.  
  151.     ioport_write8(pic1_c,0x20);
  152. }
  153.  
  154. void gdt_init() {
  155.     struct gdtr gdtreg;
  156.     gdtreg.limit = 18;
  157.     gdtreg.base  = (uint32_t)&gdt;
  158.     asm("lgdt %0" :: "m"(gdtreg));
  159. }
  160.  
  161. void idt_init() {
  162.  
  163.     struct idtr idtreg;
  164.     uint32_t**  int_entries = (uint32_t**) &interrupt_entries;
  165.  
  166.     for (int i = 0; i < IV_COUNT; ++i) {
  167.         interrupt_descriptor* idte = &idt[i];
  168.         interrupt_descriptor  desc = idte_create(int_entries[i], 0xE, 0b00);
  169.         *idte = desc;
  170.     }
  171.  
  172.     idtreg.limit = (uint16_t) (IV_COUNT*sizeof(interrupt_descriptor)) - 1;
  173.     idtreg.base  = (uint32_t) idt;
  174.  
  175.     asm("lidt %0" :: "m"(idtreg));
  176. }
  177.  
  178. void interrupt_handler(uint32_t vector) {
  179.     eoi(vector);
  180. }
  181.  
  182. void picremap(int offset_master, int offset_slave) {
  183.     uint8_t a1, a2;
  184.  
  185.     a1 = ioport_read8(PIC1_DATA);
  186.     a2 = ioport_read8(PIC2_DATA);
  187.  
  188.     ioport_write8(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
  189.     ioport_write8(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
  190.     ioport_write8(PIC1_DATA, offset_master);
  191.     ioport_write8(PIC2_DATA, offset_slave);
  192.     ioport_write8(PIC1_DATA, 4);
  193.     ioport_write8(PIC2_DATA, 2);
  194.  
  195.     ioport_write8(PIC1_DATA, ICW4_8086);
  196.     ioport_write8(PIC2_DATA, ICW4_8086);
  197.  
  198.     ioport_write8(PIC1_DATA, 0x00);
  199.     ioport_write8(PIC2_DATA, 0x00);
  200. }
  201.  
  202. void kernel_main() {
  203.  
  204.     gdt_init();
  205.     idt_init();
  206.  
  207.     picremap(0x20, 0x28);
  208.     asm("sti");
  209.  
  210.     while (1) {
  211.  
  212.     }
  213. }
  214. --[gdtable.s]---------------------
  215. .globl gdt
  216.  
  217. .section .data
  218. gdt:
  219.     .short 0,0,0,0 # NULL Deskriptor
  220.  
  221.     .short 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
  222.     .short 0x0000 # base address=0
  223.     .short 0x9A00 # code read/exec
  224.     .short 0x00CF # granularity=4096,
  225.  
  226.     .short 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
  227.     .short 0x0000 # base address=0
  228.     .short 0x9200 # data read/write
  229.     .short 0x00CF # granularity=4096,
  230. --[ientry.s]---------------------
  231. .globl interrupt_entries
  232. .extern interrupt_handler
  233. .section .text
  234.  
  235. .macro IRQ vector has_push has_error
  236. .align 8
  237. interrupt_entry_\vector:
  238.  
  239.     .if \has_push == 0
  240.         pushl $0
  241.     .endif
  242.  
  243.     pushl %edx
  244.     pushl %ecx
  245.     pushl %eax
  246.  
  247.     #pushl %esp
  248.     pushl $\vector
  249.     call interrupt_handler
  250.  
  251.     #addl $8, %esp
  252.     addl $4, %esp
  253.  
  254.     popl %eax
  255.     popl %ecx
  256.     popl %edx
  257.  
  258.     addl $4, %esp
  259.  
  260.     iret
  261. .endm
  262.  
  263. IRQ  0, 0, 0
  264. IRQ  1, 0, 0
  265. IRQ  2, 0, 0
  266. IRQ  3, 0, 0
  267. IRQ  4, 0, 0
  268. IRQ  5, 0, 0
  269. IRQ  6, 0, 0
  270. IRQ  7, 0, 0
  271. IRQ  8, 1, 1
  272. IRQ  9, 0, 0
  273. IRQ 10, 1, 1
  274. IRQ 11, 1, 1
  275. IRQ 12, 1, 1
  276. IRQ 13, 1, 1
  277. IRQ 14, 1, 1
  278. IRQ 15, 0, 0
  279. IRQ 16, 0, 0
  280. IRQ 17, 1, 1
  281. IRQ 18, 0, 0
  282. IRQ 19, 0, 0
  283. IRQ 20, 0, 0
  284. IRQ 21, 0, 1
  285. IRQ 22, 0, 0
  286. IRQ 23, 0, 0
  287. IRQ 24, 0, 0
  288. IRQ 25, 0, 0
  289. IRQ 26, 0, 0
  290. IRQ 27, 0, 0
  291. IRQ 28, 0, 0
  292. IRQ 29, 0, 1
  293. IRQ 30, 0, 1
  294.  
  295. .altmacro
  296.  
  297. .section .text
  298. .set i,31
  299. .rept 225
  300.     IRQ %i, 0, 0
  301.     .set i,i+1
  302. .endr
  303.  
  304. .section .data
  305.  
  306. interrupt_entries:
  307. .macro interrupt_vector vec
  308.     .long interrupt_entry_\vec
  309. .endm
  310.  
  311. .set i,0
  312. .rept 256
  313.     interrupt_vector %i
  314.     .set i, i+1
  315. .endr
  316. --[bootloader.s]---------------------
  317. /* Declare constants for the multiboot header. */
  318. .set ALIGN,    1<<0             /* align loaded modules on page boundaries */
  319. .set MEMINFO,  1<<1             /* provide memory map */
  320. .set FLAGS,    ALIGN | MEMINFO  /* this is the Multiboot 'flag' field */
  321. .set MAGIC,    0x1BADB002       /* 'magic number' lets bootloader find the header */
  322. .set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
  323.  
  324. /*
  325. Declare a multiboot header that marks the program as a kernel. These are magic
  326. values that are documented in the multiboot standard. The bootloader will
  327. search for this signature in the first 8 KiB of the kernel file, aligned at a
  328. 32-bit boundary. The signature is in its own section so the header can be
  329. forced to be within the first 8 KiB of the kernel file.
  330. */
  331. .section .multiboot
  332. .align 4
  333. .long MAGIC
  334. .long FLAGS
  335. .long CHECKSUM
  336.  
  337. /*
  338. The multiboot standard does not define the value of the stack pointer register
  339. (esp) and it is up to the kernel to provide a stack. This allocates room for a
  340. small stack by creating a symbol at the bottom of it, then allocating 16384
  341. bytes for it, and finally creating a symbol at the top. The stack grows
  342. downwards on x86. The stack is in its own section so it can be marked nobits,
  343. which means the kernel file is smaller because it does not contain an
  344. uninitialized stack. The stack on x86 must be 16-byte aligned according to the
  345. System V ABI standard and de-facto extensions. The compiler will assume the
  346. stack is properly aligned and failure to align the stack will result in
  347. undefined behavior.
  348. */
  349. .section .bss
  350. .align 16
  351. stack_bottom:
  352. .skip 16384 # 16 KiB
  353. stack_top:
  354.  
  355. /*
  356. The linker script specifies _start as the entry point to the kernel and the
  357. bootloader will jump to this position once the kernel has been loaded. It
  358. doesn't make sense to return from this function as the bootloader is gone.
  359. */
  360. .section .text
  361. .global _start
  362. .type _start, @function
  363. _start:
  364.     /*
  365.     The bootloader has loaded us into 32-bit protected mode on a x86
  366.     machine. Interrupts are disabled. Paging is disabled. The processor
  367.     state is as defined in the multiboot standard. The kernel has full
  368.     control of the CPU. The kernel can only make use of hardware features
  369.     and any code it provides as part of itself. There's no printf
  370.     function, unless the kernel provides its own <stdio.h> header and a
  371.     printf implementation. There are no security restrictions, no
  372.     safeguards, no debugging mechanisms, only what the kernel provides
  373.     itself. It has absolute and complete power over the
  374.     machine.
  375.     */
  376.  
  377.     /*
  378.     To set up a stack, we set the esp register to point to the top of the
  379.     stack (as it grows downwards on x86 systems). This is necessarily done
  380.     in assembly as languages such as C cannot function without a stack.
  381.     */
  382.     mov $stack_top, %esp
  383.  
  384.     /*
  385.     This is a good place to initialize crucial processor state before the
  386.     high-level kernel is entered. It's best to minimize the early
  387.     environment where crucial features are offline. Note that the
  388.     processor is not fully initialized yet: Features such as floating
  389.     point instructions and instruction set extensions are not initialized
  390.     yet. The GDT should be loaded here. Paging should be enabled here.
  391.     C++ features such as global constructors and exceptions will require
  392.     runtime support to work as well.
  393.     */
  394.  
  395.     /*
  396.     Enter the high-level kernel. The ABI requires the stack is 16-byte
  397.     aligned at the time of the call instruction (which afterwards pushes
  398.     the return pointer of size 4 bytes). The stack was originally 16-byte
  399.     aligned above and we've pushed a multiple of 16 bytes to the
  400.     stack since (pushed 0 bytes so far), so the alignment has thus been
  401.     preserved and the call is well defined.
  402.     */
  403.     call kernel_main
  404.  
  405.     /*
  406.     If the system has nothing more to do, put the computer into an
  407.     infinite loop. To do that:
  408.     1) Disable interrupts with cli (clear interrupt enable in eflags).
  409.        They are already disabled by the bootloader, so this is not needed.
  410.        Mind that you might later enable interrupts and return from
  411.        kernel_main (which is sort of nonsensical to do).
  412.     2) Wait for the next interrupt to arrive with hlt (halt instruction).
  413.        Since they are disabled, this will lock up the computer.
  414.     3) Jump to the hlt instruction if it ever wakes up due to a
  415.        non-maskable interrupt occurring or due to system management mode.
  416.     */
  417.     cli
  418. 1:  hlt
  419.     jmp 1b
  420.  
  421. /*
  422. Set the size of the _start symbol to the current location '.' minus its start.
  423. This is useful when debugging or when you implement call tracing.
  424. */
  425. .size _start, . - _start
  426.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement