|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: ! 53: #include <platforms.h> ! 54: #include <cpus.h> ! 55: #include <mach_kdb.h> ! 56: ! 57: #include <i386/asm.h> ! 58: #include <i386/proc_reg.h> ! 59: #include <assym.s> ! 60: ! 61: #if NCPUS > 1 ! 62: ! 63: #define CX(addr,reg) addr(,reg,4) ! 64: ! 65: #else ! 66: ! 67: #define CPU_NUMBER(reg) ! 68: #define CX(addr,reg) addr ! 69: ! 70: #endif /* NCPUS > 1 */ ! 71: ! 72: #include <i386/AT386/mp/mp.h> ! 73: ! 74: /* ! 75: * GAS won't handle an intersegment jump with a relocatable offset. ! 76: */ ! 77: #define LJMP(segment,address) \ ! 78: .byte 0xea ;\ ! 79: .long address ;\ ! 80: .word segment ! 81: ! 82: ! 83: ! 84: #define KVTOPHYS (-KERNELBASE) ! 85: #define KVTOLINEAR LINEAR_KERNELBASE ! 86: ! 87: ! 88: #define PA(addr) (addr)+KVTOPHYS ! 89: #define VA(addr) (addr)-KVTOPHYS ! 90: ! 91: .data ! 92: .align 2 ! 93: .globl EXT(_kick_buffer_) ! 94: EXT(_kick_buffer_): ! 95: .long 1 ! 96: .long 3 ! 97: .set .,.+16836 ! 98: /* ! 99: * Interrupt and bootup stack for initial processor. ! 100: */ ! 101: .align ALIGN ! 102: .globl EXT(intstack) ! 103: EXT(intstack): ! 104: .set ., .+INTSTACK_SIZE ! 105: .globl EXT(eintstack) ! 106: EXT(eintstack:) ! 107: ! 108: #if NCPUS == 1 ! 109: .globl EXT(int_stack_high) /* all interrupt stacks */ ! 110: EXT(int_stack_high): /* must lie below this */ ! 111: .long EXT(eintstack) /* address */ ! 112: ! 113: .globl EXT(int_stack_top) /* top of interrupt stack */ ! 114: EXT(int_stack_top): ! 115: .long EXT(eintstack) ! 116: #endif ! 117: ! 118: #if MACH_KDB ! 119: /* ! 120: * Kernel debugger stack for each processor. ! 121: */ ! 122: .align ALIGN ! 123: .globl EXT(db_stack_store) ! 124: EXT(db_stack_store): ! 125: .set ., .+(INTSTACK_SIZE*NCPUS) ! 126: ! 127: /* ! 128: * Stack for last-ditch debugger task for each processor. ! 129: */ ! 130: .align ALIGN ! 131: .globl EXT(db_task_stack_store) ! 132: EXT(db_task_stack_store): ! 133: .set ., .+(INTSTACK_SIZE*NCPUS) ! 134: #endif /* MACH_KDB */ ! 135: ! 136: /* ! 137: * per-processor kernel debugger stacks ! 138: */ ! 139: .align ALIGN ! 140: .globl EXT(kgdb_stack_store) ! 141: EXT(kgdb_stack_store): ! 142: .set ., .+(INTSTACK_SIZE*NCPUS) ! 143: ! 144: ! 145: /* ! 146: * Pointers to GDT and IDT. These contain linear addresses. ! 147: */ ! 148: .align ALIGN ! 149: .globl EXT(gdtptr) ! 150: LEXT(gdtptr) ! 151: .word Times(8,GDTSZ)-1 ! 152: .long EXT(gdt)+KVTOLINEAR ! 153: ! 154: .align ALIGN ! 155: .globl EXT(idtptr) ! 156: LEXT(idtptr) ! 157: .word Times(8,IDTSZ)-1 ! 158: .long EXT(idt)+KVTOLINEAR ! 159: ! 160: #if NCPUS > 1 ! 161: .data ! 162: /* ! 163: * start_lock is very special. We initialize the ! 164: * lock at allocation time rather than at run-time. ! 165: * Although start_lock should be an instance of a ! 166: * hw_lock, we hand-code all manipulation of the lock ! 167: * because the hw_lock code may require function calls; ! 168: * and we'd rather not introduce another dependency on ! 169: * a working stack at this point. ! 170: */ ! 171: .globl EXT(start_lock) ! 172: EXT(start_lock): ! 173: .long 0 /* synchronizes processor startup */ ! 174: ! 175: .globl EXT(master_is_up) ! 176: EXT(master_is_up): ! 177: .long 0 /* 1 when OK for other processors */ ! 178: /* to start */ ! 179: .globl EXT(mp_boot_pde) ! 180: EXT(mp_boot_pde): ! 181: .long 0 ! 182: #endif /* NCPUS > 1 */ ! 183: ! 184: /* ! 185: * All CPUs start here. ! 186: * ! 187: * Environment: ! 188: * protected mode, no paging, flat 32-bit address space. ! 189: * (Code/data/stack segments have base == 0, limit == 4G) ! 190: */ ! 191: .text ! 192: .align ALIGN ! 193: .globl EXT(pstart) ! 194: .globl EXT(_start) ! 195: LEXT(_start) ! 196: LEXT(pstart) ! 197: mov $0,%ax /* fs must be zeroed; */ ! 198: mov %ax,%fs /* some bootstrappers don`t do this */ ! 199: mov %ax,%gs ! 200: ! 201: #if NCPUS > 1 ! 202: jmp 1f ! 203: 0: cmpl $0,PA(EXT(start_lock)) ! 204: jne 0b ! 205: 1: movb $1,%eax ! 206: xchgl %eax,PA(EXT(start_lock)) /* locked */ ! 207: testl %eax,%eax ! 208: jnz 0b ! 209: ! 210: cmpl $0,PA(EXT(master_is_up)) /* are we first? */ ! 211: jne EXT(slave_start) /* no -- system already up. */ ! 212: movl $1,PA(EXT(master_is_up)) /* others become slaves */ ! 213: #endif /* NCPUS > 1 */ ! 214: ! 215: /* ! 216: * Get startup parameters. ! 217: */ ! 218: ! 219: #include <i386/AT386/asm_startup.h> ! 220: ! 221: /* ! 222: * Build initial page table directory and page tables. ! 223: * %ebx holds first available physical address. ! 224: */ ! 225: ! 226: addl $(NBPG-1),%ebx /* round first avail physical addr */ ! 227: andl $(-NBPG),%ebx /* to machine page size */ ! 228: leal -KVTOPHYS(%ebx),%eax /* convert to virtual address */ ! 229: movl %eax,PA(EXT(kpde)) /* save as kernel page table directory */ ! 230: movl %ebx,%cr3 /* set physical address in CR3 now */ ! 231: ! 232: movl %ebx,%edi /* clear page table directory */ ! 233: movl $(PTES_PER_PAGE),%ecx /* one page of ptes */ ! 234: xorl %eax,%eax ! 235: cld ! 236: rep ! 237: stosl /* edi now points to next page */ ! 238: ! 239: /* ! 240: * Use next few pages for page tables. ! 241: */ ! 242: addl $(KERNELBASEPDE),%ebx /* point to pde for kernel base */ ! 243: movl %edi,%esi /* point to end of current pte page */ ! 244: ! 245: /* ! 246: * Enter 1-1 mappings for kernel and for kernel page tables. ! 247: */ ! 248: movl $(INTEL_PTE_KERNEL),%eax /* set up pte prototype */ ! 249: 0: ! 250: cmpl %esi,%edi /* at end of pte page? */ ! 251: jb 1f /* if so: */ ! 252: movl %edi,%edx /* get pte address (physical) */ ! 253: andl $(-NBPG),%edx /* mask out offset in page */ ! 254: orl $(INTEL_PTE_KERNEL),%edx /* add pte bits */ ! 255: movl %edx,(%ebx) /* set pde */ ! 256: addl $4,%ebx /* point to next pde */ ! 257: movl %edi,%esi /* point to */ ! 258: addl $(NBPG),%esi /* end of new pte page */ ! 259: 1: ! 260: movl %eax,(%edi) /* set pte */ ! 261: addl $4,%edi /* advance to next pte */ ! 262: addl $(NBPG),%eax /* advance to next phys page */ ! 263: cmpl %edi,%eax /* have we mapped this pte page yet? */ ! 264: jb 0b /* loop if not */ ! 265: ! 266: /* ! 267: * Zero rest of last pte page. ! 268: */ ! 269: xor %eax,%eax /* don`t map yet */ ! 270: 2: cmpl %esi,%edi /* at end of pte page? */ ! 271: jae 3f ! 272: movl %eax,(%edi) /* zero mapping */ ! 273: addl $4,%edi ! 274: jmp 2b ! 275: 3: ! 276: ! 277: #if NCPUS > 1 ! 278: /* ! 279: * Grab (waste?) another page for a bootstrap page directory ! 280: * for the other CPUs. We don't want the running CPUs to see ! 281: * addresses 0..3fffff mapped 1-1. ! 282: */ ! 283: movl %edi,PA(EXT(mp_boot_pde)) /* save its physical address */ ! 284: movl $(PTES_PER_PAGE),%ecx /* and clear it */ ! 285: rep ! 286: stosl ! 287: #endif /* NCPUS > 1 */ ! 288: movl %edi,PA(EXT(first_avail)) /* save first available phys addr */ ! 289: ! 290: /* ! 291: * pmap_bootstrap will enter rest of mappings. ! 292: */ ! 293: ! 294: /* ! 295: * Fix initial descriptor tables. ! 296: */ ! 297: lea PA(EXT(idt)),%esi /* fix IDT */ ! 298: movl $(IDTSZ),%ecx ! 299: movl $(PA(fix_idt_ret)),%ebx ! 300: jmp fix_desc_common /* (cannot use stack) */ ! 301: fix_idt_ret: ! 302: ! 303: lea PA(EXT(gdt)),%esi /* fix GDT */ ! 304: movl $(GDTSZ),%ecx ! 305: movl $(PA(fix_gdt_ret)),%ebx ! 306: jmp fix_desc_common /* (cannot use stack) */ ! 307: fix_gdt_ret: ! 308: ! 309: lea PA(EXT(ldt)),%esi /* fix LDT */ ! 310: movl $(LDTSZ),%ecx ! 311: movl $(PA(fix_ldt_ret)),%ebx ! 312: jmp fix_desc_common /* (cannot use stack) */ ! 313: fix_ldt_ret: ! 314: ! 315: /* ! 316: * Turn on paging. ! 317: */ ! 318: movl %cr3,%eax /* retrieve kernel PDE phys address */ ! 319: movl KERNELBASEPDE(%eax),%ecx ! 320: movl %ecx,(%eax) /* set it also as pte for location */ ! 321: /* 0..3fffff, so that the code */ ! 322: /* that enters paged mode is mapped */ ! 323: /* to identical addresses after */ ! 324: /* paged mode is enabled */ ! 325: ! 326: movl $EXT(pag_start),%ebx /* first paged code address */ ! 327: ! 328: movl %cr0,%eax ! 329: orl $(CR0_PG),%eax /* set PG bit in CR0 */ ! 330: orl $(CR0_WP),%eax ! 331: movl %eax,%cr0 /* to enable paging */ ! 332: ! 333: jmp *%ebx /* flush prefetch queue */ ! 334: ! 335: /* ! 336: * We are now paging, and can run with correct addresses. ! 337: */ ! 338: LEXT(pag_start) ! 339: lgdt EXT(gdtptr) /* load GDT */ ! 340: lidt EXT(idtptr) /* load IDT */ ! 341: LJMP(KERNEL_CS,EXT(vstart)) /* switch to kernel code segment */ ! 342: ! 343: /* ! 344: * Master is now running with correct addresses. ! 345: */ ! 346: LEXT(vstart) ! 347: mov $(KERNEL_DS),%ax /* set kernel data segment */ ! 348: mov %ax,%ds ! 349: mov %ax,%es ! 350: mov %ax,%ss ! 351: mov %ax,EXT(ktss)+TSS_SS0 /* set kernel stack segment */ ! 352: /* for traps to kernel */ ! 353: #if MACH_KDB ! 354: mov %ax,EXT(dbtss)+TSS_SS0 /* likewise for debug task switch */ ! 355: mov %cr3,%eax /* get PDBR into debug TSS */ ! 356: mov %eax,EXT(dbtss)+TSS_PDBR ! 357: mov $0,%eax ! 358: #endif ! 359: ! 360: movw $(KERNEL_LDT),%ax /* get LDT segment */ ! 361: lldt %ax /* load LDT */ ! 362: #if MACH_KDB ! 363: mov %ax,EXT(ktss)+TSS_LDT /* store LDT in two TSS, as well... */ ! 364: mov %ax,EXT(dbtss)+TSS_LDT /* ...matters if we switch tasks */ ! 365: #endif ! 366: movw $(KERNEL_TSS),%ax ! 367: ltr %ax /* set up KTSS */ ! 368: ! 369: mov $CPU_DATA,%ax ! 370: mov %ax,%gs ! 371: ! 372: lea EXT(eintstack),%esp /* switch to the bootup stack */ ! 373: call EXT(machine_startup) /* run C code */ ! 374: /*NOTREACHED*/ ! 375: hlt ! 376: ! 377: #if NCPUS > 1 ! 378: /* ! 379: * master_up is used by the master cpu to signify that it is done ! 380: * with the interrupt stack, etc. See the code in pstart and svstart ! 381: * that this interlocks with. ! 382: */ ! 383: .align ALIGN ! 384: .globl EXT(master_up) ! 385: LEXT(master_up) ! 386: pushl %ebp /* set up */ ! 387: movl %esp,%ebp /* stack frame */ ! 388: movl $0,%ecx /* unlock start_lock */ ! 389: xchgl %ecx,EXT(start_lock) /* since we are no longer using */ ! 390: /* bootstrap stack */ ! 391: leave /* pop stack frame */ ! 392: ret ! 393: ! 394: /* ! 395: * We aren't the first. Call slave_main to initialize the processor ! 396: * and get Mach going on it. ! 397: */ ! 398: .align ALIGN ! 399: .globl EXT(slave_start) ! 400: LEXT(slave_start) ! 401: cli /* disable interrupts, so we don`t */ ! 402: /* need IDT for a while */ ! 403: movl EXT(kpde)+KVTOPHYS,%ebx /* get PDE virtual address */ ! 404: addl $(KVTOPHYS),%ebx /* convert to physical address */ ! 405: ! 406: movl PA(EXT(mp_boot_pde)),%edx /* point to the bootstrap PDE */ ! 407: movl KERNELBASEPDE(%ebx),%eax ! 408: /* point to pte for KERNELBASE */ ! 409: movl %eax,KERNELBASEPDE(%edx) ! 410: /* set in bootstrap PDE */ ! 411: movl %eax,(%edx) /* set it also as pte for location */ ! 412: /* 0..3fffff, so that the code */ ! 413: /* that enters paged mode is mapped */ ! 414: /* to identical addresses after */ ! 415: /* paged mode is enabled */ ! 416: movl %edx,%cr3 /* use bootstrap PDE to enable paging */ ! 417: ! 418: movl $EXT(spag_start),%edx /* first paged code address */ ! 419: ! 420: movl %cr0,%eax ! 421: orl $(CR0_PG),%eax /* set PG bit in CR0 */ ! 422: orl $(CR0_WP),%eax ! 423: movl %eax,%cr0 /* to enable paging */ ! 424: ! 425: jmp *%edx /* flush prefetch queue. */ ! 426: ! 427: /* ! 428: * We are now paging, and can run with correct addresses. ! 429: */ ! 430: LEXT(spag_start) ! 431: ! 432: lgdt EXT(gdtptr) /* load GDT */ ! 433: lidt EXT(idtptr) /* load IDT */ ! 434: LJMP(KERNEL_CS,EXT(svstart)) /* switch to kernel code segment */ ! 435: ! 436: /* ! 437: * Slave is now running with correct addresses. ! 438: */ ! 439: LEXT(svstart) ! 440: mov $(KERNEL_DS),%ax /* set kernel data segment */ ! 441: mov %ax,%ds ! 442: mov %ax,%es ! 443: mov %ax,%ss ! 444: ! 445: movl %ebx,%cr3 /* switch to the real kernel PDE */ ! 446: ! 447: CPU_NUMBER(%eax) ! 448: movl CX(EXT(interrupt_stack),%eax),%esp /* get stack */ ! 449: addl $(INTSTACK_SIZE),%esp /* point to top */ ! 450: xorl %ebp,%ebp /* for completeness */ ! 451: ! 452: movl $0,%ecx /* unlock start_lock */ ! 453: xchgl %ecx,EXT(start_lock) /* since we are no longer using */ ! 454: /* bootstrap stack */ ! 455: ! 456: /* ! 457: * switch to the per-cpu descriptor tables ! 458: */ ! 459: ! 460: pushl %eax /* pass CPU number */ ! 461: call EXT(mp_desc_init) /* set up local table */ ! 462: /* pointer returned in %eax */ ! 463: subl $4,%esp /* get space to build pseudo-descriptors */ ! 464: ! 465: CPU_NUMBER(%eax) ! 466: movw $(GDTSZ*8-1),0(%esp) /* set GDT size in GDT descriptor */ ! 467: movl CX(EXT(mp_gdt),%eax),%edx ! 468: addl $KVTOLINEAR,%edx ! 469: movl %edx,2(%esp) /* point to local GDT (linear address) */ ! 470: lgdt 0(%esp) /* load new GDT */ ! 471: ! 472: movw $(IDTSZ*8-1),0(%esp) /* set IDT size in IDT descriptor */ ! 473: movl CX(EXT(mp_idt),%eax),%edx ! 474: addl $KVTOLINEAR,%edx ! 475: movl %edx,2(%esp) /* point to local IDT (linear address) */ ! 476: lidt 0(%esp) /* load new IDT */ ! 477: ! 478: movw $(KERNEL_LDT),%ax ! 479: lldt %ax /* load new LDT */ ! 480: ! 481: movw $(KERNEL_TSS),%ax ! 482: ltr %ax /* load new KTSS */ ! 483: ! 484: mov $CPU_DATA,%ax ! 485: mov %ax,%gs ! 486: ! 487: call EXT(slave_main) /* start MACH */ ! 488: /*NOTREACHED*/ ! 489: hlt ! 490: #endif /* NCPUS > 1 */ ! 491: ! 492: /* ! 493: * Convert a descriptor from fake to real format. ! 494: * ! 495: * Calls from assembly code: ! 496: * %ebx = return address (physical) CANNOT USE STACK ! 497: * %esi = descriptor table address (physical) ! 498: * %ecx = number of descriptors ! 499: * ! 500: * Calls from C: ! 501: * 0(%esp) = return address ! 502: * 4(%esp) = descriptor table address (physical) ! 503: * 8(%esp) = number of descriptors ! 504: * ! 505: * Fake descriptor format: ! 506: * bytes 0..3 base 31..0 ! 507: * bytes 4..5 limit 15..0 ! 508: * byte 6 access byte 2 | limit 19..16 ! 509: * byte 7 access byte 1 ! 510: * ! 511: * Real descriptor format: ! 512: * bytes 0..1 limit 15..0 ! 513: * bytes 2..3 base 15..0 ! 514: * byte 4 base 23..16 ! 515: * byte 5 access byte 1 ! 516: * byte 6 access byte 2 | limit 19..16 ! 517: * byte 7 base 31..24 ! 518: * ! 519: * Fake gate format: ! 520: * bytes 0..3 offset ! 521: * bytes 4..5 selector ! 522: * byte 6 word count << 4 (to match fake descriptor) ! 523: * byte 7 access byte 1 ! 524: * ! 525: * Real gate format: ! 526: * bytes 0..1 offset 15..0 ! 527: * bytes 2..3 selector ! 528: * byte 4 word count ! 529: * byte 5 access byte 1 ! 530: * bytes 6..7 offset 31..16 ! 531: */ ! 532: .globl EXT(fix_desc) ! 533: LEXT(fix_desc) ! 534: pushl %ebp /* set up */ ! 535: movl %esp,%ebp /* stack frame */ ! 536: pushl %esi /* save registers */ ! 537: pushl %ebx ! 538: movl B_ARG0,%esi /* point to first descriptor */ ! 539: movl B_ARG1,%ecx /* get number of descriptors */ ! 540: lea 0f,%ebx /* get return address */ ! 541: jmp fix_desc_common /* call internal routine */ ! 542: 0: popl %ebx /* restore registers */ ! 543: popl %esi ! 544: leave /* pop stack frame */ ! 545: ret /* return */ ! 546: ! 547: fix_desc_common: ! 548: 0: ! 549: movw 6(%esi),%dx /* get access byte */ ! 550: movb %dh,%al ! 551: andb $0x14,%al ! 552: cmpb $0x04,%al /* gate or descriptor? */ ! 553: je 1f ! 554: ! 555: /* descriptor */ ! 556: movl 0(%esi),%eax /* get base in eax */ ! 557: rol $16,%eax /* swap 15..0 with 31..16 */ ! 558: /* (15..0 in correct place) */ ! 559: movb %al,%dl /* combine bits 23..16 with ACC1 */ ! 560: /* in dh/dl */ ! 561: movb %ah,7(%esi) /* store bits 31..24 in correct place */ ! 562: movw 4(%esi),%ax /* move limit bits 0..15 to word 0 */ ! 563: movl %eax,0(%esi) /* store (bytes 0..3 correct) */ ! 564: movw %dx,4(%esi) /* store bytes 4..5 */ ! 565: jmp 2f ! 566: ! 567: /* gate */ ! 568: 1: ! 569: movw 4(%esi),%ax /* get selector */ ! 570: shrb $4,%dl /* shift word count to proper place */ ! 571: movw %dx,4(%esi) /* store word count / ACC1 */ ! 572: movw 2(%esi),%dx /* get offset 16..31 */ ! 573: movw %dx,6(%esi) /* store in correct place */ ! 574: movw %ax,2(%esi) /* store selector in correct place */ ! 575: 2: ! 576: addl $8,%esi /* bump to next descriptor */ ! 577: loop 0b /* repeat */ ! 578: jmp *%ebx /* all done */ ! 579: ! 580: /* ! 581: * put arg in kbd leds and spin a while ! 582: * eats eax, ecx, edx ! 583: */ ! 584: #define K_RDWR 0x60 ! 585: #define K_CMD_LEDS 0xed ! 586: #define K_STATUS 0x64 ! 587: #define K_IBUF_FULL 0x02 /* input (to kbd) buffer full */ ! 588: #define K_OBUF_FULL 0x01 /* output (from kbd) buffer full */ ! 589: ! 590: ENTRY(set_kbd_leds) ! 591: mov S_ARG0,%cl /* save led value */ ! 592: ! 593: 0: inb $(K_STATUS),%al /* get kbd status */ ! 594: testb $(K_IBUF_FULL),%al /* input busy? */ ! 595: jne 0b /* loop until not */ ! 596: ! 597: mov $(K_CMD_LEDS),%al /* K_CMD_LEDS */ ! 598: outb %al,$(K_RDWR) /* to kbd */ ! 599: ! 600: 0: inb $(K_STATUS),%al /* get kbd status */ ! 601: testb $(K_OBUF_FULL),%al /* output present? */ ! 602: je 0b /* loop if not */ ! 603: ! 604: inb $(K_RDWR),%al /* read status (and discard) */ ! 605: ! 606: 0: inb $(K_STATUS),%al /* get kbd status */ ! 607: testb $(K_IBUF_FULL),%al /* input busy? */ ! 608: jne 0b /* loop until not */ ! 609: ! 610: mov %cl,%al /* move led value */ ! 611: outb %al,$(K_RDWR) /* to kbd */ ! 612: ! 613: movl $10000000,%ecx /* spin */ ! 614: 0: nop ! 615: nop ! 616: loop 0b /* a while */ ! 617: ! 618: ret
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.