| jmp llshell_out |
| |
| // (c) 2004 Bryan Chafy, This program is released under the GPL |
| |
| // LLShell, A low level interactive debug shell |
| // Designed to be an interactive shell that operates with zero |
| // system resources. For example at initial boot. |
| |
| // to use, jump to label "low_level_shell" |
| // set %esp to the return address for exiting |
| |
| |
| #define UART_BASEADDR $0x3f8 |
| #define resultreg %esi |
| #define subroutinereg %edi |
| #define freqtime $2193 // 1.93 * freq |
| #define timertime $6000 |
| .equ sys_IOPL, 110 |
| |
| // .data |
| // .text |
| |
| welcome: |
| .string "\r\n! Low Level Shell (LLShell) (c)2004 Bryan Chafy \r\n\r\n" |
| prompt: |
| .string "\r\n!> " |
| badcmd: |
| .string "bad command\r\n" |
| sorry: |
| .string "sorry, not yet implemented\r\n" |
| cmds: |
| .string "\r\nList of commands:\r\n \ |
| \r\nbeep -- pc speaker beep \ |
| \r\nrst (or RST) -- reset \ |
| \r\nout(b,w,l) <val> <port> -- raw out val at port \ |
| \r\nin(b,w,l) <port> -- show raw port value \ |
| \r\njmp <address> -- jmp to address (llshell addr is in eax) \ |
| \r\ncall <address> -- funcion call (assumes a working stack) \ |
| \r\ncli -- clear interrupts \ |
| \r\nsti -- enable interrupts \ |
| \r\npush <value> -- push value onto stack \ |
| \r\npop -- pop from stack and display \ |
| \r\nwm(b,w,l) <addr> <val> -- write mem \ |
| \r\ndm <addr> <lines> -- dump mem \ |
| \r\nmcp <src> <dst> <size> -- mem copy \ |
| \r\nmpat <pat> <dst> <size> -- mem pattern \ |
| \r\nmemt <begin> <end> -- memory test \ |
| \r\npcir(b,w,l) <loc> -- pci read config \ |
| \r\npciw(b,w,l) <loc> <val> -- pci write config \ |
| \r\ndl <addr> <size> -- memory download (display xor cheksum at completion) \ |
| \r\ncram <addr> <size> -- enable cache to be ram (experimental) \ |
| \r\nbaud <val> -- change baudrate (not yet implemented) \ |
| \r\nexit -- exit shell \ |
| \r\nAll values in hex (0x prefixing ok) \ |
| \r\n" |
| |
| cr: |
| .string "\r\n" |
| spaces: |
| .string " " |
| |
| // .globl _start |
| //ASSUME CS:@CODE, DS:@DATA |
| |
| // _start: |
| |
| // call ioperms |
| |
| low_level_shell: |
| |
| mov $preamble,subroutinereg |
| jmp beep |
| preamble: |
| mov $welcome,resultreg |
| mov $readcommand,subroutinereg |
| jmp displaystring |
| |
| readcommand: |
| mov $prompt,resultreg |
| mov $rcmd,subroutinereg |
| jmp displaystring |
| |
| rcmd: |
| mov $readcommand,subroutinereg |
| movl $0x0, resultreg |
| |
| readchar: |
| mov UART_BASEADDR+5,%dx |
| in %dx, %al |
| and $0x9f,%al |
| test $0x01,%al |
| jz readchar |
| mov UART_BASEADDR,%dx |
| in %dx,%al //char in al |
| xchg %al,%ah |
| |
| send_char: |
| mov UART_BASEADDR+5,%dx |
| us_wait: |
| in %dx,%al |
| test $0x20,%al |
| jz us_wait |
| mov UART_BASEADDR,%dx |
| xchg %al,%ah |
| out %al,%dx // output char |
| |
| cmp $0x0D,%al //CR |
| jnz eval_char |
| mov $0x0A,%ah |
| jmp send_char |
| |
| eval_char: |
| cmp $0x20,%al //space |
| jz cmdtable |
| cmp $0x0A,%al //CR |
| jz cmdtable |
| cmp $0x08,%al //BS |
| jnz additup |
| //subit: |
| shr $0x8,resultreg |
| jmp readchar |
| additup: |
| shl $0x8,resultreg |
| and $0xff,%eax |
| add %eax,resultreg |
| jmp readchar |
| |
| cmdtable: |
| mov resultreg,%eax |
| cmp $0,%eax |
| jz readcommand |
| cmp $0x74657374,%eax |
| jz dotest |
| cmp $0x68656c70,%eax |
| jz dohelp |
| cmp $0x0000003f,%eax |
| jz dohelp |
| cmp $0x6f757462,%eax |
| jz dooutb |
| cmp $0x6f757477,%eax |
| jz dooutw |
| cmp $0x6f75746c,%eax |
| jz dooutd |
| cmp $0x00696e62,%eax |
| jz doinb |
| cmp $0x00696e77,%eax |
| jz doinw |
| cmp $0x00696e6c,%eax |
| jz doind |
| cmp $0x63697262,%eax |
| jz pcirb |
| cmp $0x63697277,%eax |
| jz pcirw |
| cmp $0x6369726c,%eax |
| jz pcirl |
| cmp $0x63697762,%eax |
| jz pciwb |
| cmp $0x63697777,%eax |
| jz pciww |
| cmp $0x6369776c,%eax |
| jz pciwl |
| cmp $0x00776d62,%eax |
| jz wmemb |
| cmp $0x00776d77,%eax |
| jz wmemw |
| cmp $0x00776d6c,%eax |
| jz wmeml |
| cmp $0x0000646d,%eax |
| jz dodmem |
| cmp $0x6d656d74,%eax |
| jz memt // mem test |
| cmp $0x00727374,%eax |
| jz rst // reset |
| cmp $0x00525354,%eax |
| jz RST |
| cmp $0x62656570,%eax |
| jz beep |
| cmp $0x0000646c,%eax |
| jz dodl // download to mem <loc> <size> |
| cmp $0x006a6d70,%eax |
| jz jmpto // jump to location (eax holds return addr) |
| cmp $0x62617564,%eax |
| jz baud // change baudrate |
| cmp $0x00696e74,%eax |
| jz doint // trigger an interrupt |
| cmp $0x63616c6c,%eax |
| jz callto // call assumes memory |
| cmp $0x70757368,%eax |
| jz dopush // assumes mem |
| cmp $0x00706f70,%eax |
| jz dopop // assumes mem |
| cmp $0x6372616d,%eax |
| jz cram // cache ram trick <location> <size> |
| cmp $0x006d6370,%eax |
| jz mcp // mem copy <src> <dst> <size> |
| cmp $0x6d706174,%eax |
| jz dopattern |
| cmp $0x00636c69,%eax |
| jz docli |
| cmp $0x00737469,%eax |
| jz dosti |
| cmp $0x65786974,%eax |
| jz doexit |
| mov $badcmd,resultreg |
| mov $readcommand,subroutinereg |
| jmp displaystring |
| |
| |
| readnibbles: |
| movl $0x0, resultreg |
| readit: |
| mov UART_BASEADDR+5,%dx |
| in %dx, %al |
| and $0x9f,%al |
| test $0x1,%al |
| jz readit |
| mov UART_BASEADDR,%dx |
| in %dx,%al |
| xchg %al,%ah |
| |
| sendchar: |
| mov UART_BASEADDR+5,%dx |
| us_waitit: |
| in %dx,%al |
| test $0x20,%al |
| jz us_waitit |
| mov UART_BASEADDR,%dx |
| xchg %al,%ah |
| out %al,%dx // output char |
| |
| cmp $0x78,%al |
| jz readit |
| cmp $0x0D,%al //CR |
| jnz evalchar |
| mov $0x0A,%ah |
| jmp sendchar |
| |
| evalchar: |
| cmp $0x20,%al //space |
| jz gosub |
| cmp $0x0A,%al //CR |
| jz gosub |
| cmp $0x08,%al //BS |
| jnz processchar |
| //subit: |
| shr $0x04,resultreg |
| jmp readit |
| processchar: |
| cmp $0x3A,%al |
| jl subnum |
| cmp $0x47,%al |
| jl subcaps |
| //sublc: |
| sub $0x57,%al |
| jmp additupn |
| subcaps: |
| sub $0x37,%al |
| jmp additupn |
| subnum: |
| sub $0x30,%al |
| additupn: |
| shl $0x04,resultreg |
| and $0xf,%eax |
| add %eax,resultreg |
| jmp readit |
| |
| gosub: |
| jmp *subroutinereg |
| |
| //intersubcall |
| // eax,edx,esi,edi |
| |
| // ebx,ecx,ebp,esp(?) |
| // ds,es,fs,gs |
| |
| dotest: |
| mov $ramtest,resultreg |
| mov $test1a,subroutinereg |
| jmp displayhex |
| test1a: |
| mov $welcome,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| dodmem: |
| |
| movl $dmem1a, subroutinereg |
| jmp readnibbles |
| dmem1a: |
| mov resultreg,%ebx // address |
| movl $dmem1b, subroutinereg |
| jmp readnibbles |
| dmem1b: |
| mov resultreg,%ecx // length |
| |
| dmemloop: |
| mov %ebx,resultreg |
| mov $daddr1,subroutinereg |
| jmp displayhex |
| daddr1: |
| mov $spaces,resultreg |
| mov $startshowm,subroutinereg |
| jmp displaystring |
| |
| startshowm: |
| mov (%ebx),resultreg |
| mov $showm1,subroutinereg |
| jmp displayhexlinear |
| showm1: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $showm2,subroutinereg |
| jmp displayhexlinear |
| showm2: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $showm3,subroutinereg |
| jmp displayhexlinear |
| showm3: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $showa0,subroutinereg |
| jmp displayhexlinear |
| |
| showa0: |
| sub $0xC,%ebx |
| mov (%ebx),resultreg |
| mov $showa1,subroutinereg |
| jmp displayasciilinear |
| showa1: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $showa2,subroutinereg |
| jmp displayasciilinear |
| showa2: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $showa3,subroutinereg |
| jmp displayasciilinear |
| showa3: |
| add $0x04,%ebx |
| mov (%ebx),resultreg |
| mov $doneshow,subroutinereg |
| jmp displayasciilinear |
| doneshow: |
| mov $cr,resultreg |
| mov $doneshow1,subroutinereg |
| jmp displaystring |
| doneshow1: |
| dec %cx |
| cmp $0x0,%cx |
| jz exitdmem |
| add $0x04,%ebx |
| jmp dmemloop |
| exitdmem: |
| jmp readcommand |
| |
| dooutb: |
| // out val,port |
| movl $outb1a, subroutinereg |
| jmp readnibbles |
| outb1a: |
| mov resultreg,%ebx |
| movl $outb1b, subroutinereg |
| jmp readnibbles |
| outb1b: |
| mov resultreg,%edx |
| mov %ebx,%eax |
| out %al,%dx |
| jmp readcommand |
| |
| dooutw: |
| // out val,port |
| movl $outw1a, subroutinereg |
| jmp readnibbles |
| outw1a: |
| mov resultreg,%ebx |
| movl $outw1b, subroutinereg |
| jmp readnibbles |
| outw1b: |
| mov resultreg,%edx |
| mov %ebx,%eax |
| out %ax,%dx |
| jmp readcommand |
| |
| dooutd: |
| // out val,port |
| movl $outd1a, subroutinereg |
| jmp readnibbles |
| outd1a: |
| mov resultreg,%ebx |
| movl $outd1b, subroutinereg |
| jmp readnibbles |
| outd1b: |
| mov resultreg,%edx |
| mov %ebx,%eax |
| out %eax,%dx |
| jmp readcommand |
| |
| wmemb: |
| movl $wmemba, subroutinereg |
| jmp readnibbles |
| wmemba: |
| mov resultreg,%ebx |
| movl $wmembb, subroutinereg |
| jmp readnibbles |
| wmembb: |
| mov resultreg,%eax |
| mov %al,(%ebx) |
| jmp readcommand |
| |
| wmemw: |
| movl $wmemwa, subroutinereg |
| jmp readnibbles |
| wmemwa: |
| mov resultreg,%ebx |
| movl $wmemwb, subroutinereg |
| jmp readnibbles |
| wmemwb: |
| mov resultreg,%eax |
| mov %ax,(%ebx) |
| jmp readcommand |
| |
| wmeml: |
| movl $wmemla, subroutinereg |
| jmp readnibbles |
| wmemla: |
| mov resultreg,%ebx |
| movl $wmemlb, subroutinereg |
| jmp readnibbles |
| wmemlb: |
| mov resultreg,%eax |
| mov %eax,(%ebx) |
| jmp readcommand |
| |
| doinb: |
| // in port |
| movl $inb1a, subroutinereg |
| jmp readnibbles |
| inb1a: |
| mov resultreg,%edx |
| mov $0x0,%eax |
| in %dx,%al |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| doinw: |
| // in port |
| movl $inw1a, subroutinereg |
| jmp readnibbles |
| inw1a: |
| mov resultreg,%edx |
| mov $0x0,%eax |
| in %dx,%ax |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| doind: |
| // in port |
| movl $ind1a, subroutinereg |
| jmp readnibbles |
| ind1a: |
| mov resultreg,%edx |
| in %dx,%eax |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| jmpto: |
| movl $jmp1a, subroutinereg |
| jmp readnibbles |
| jmp1a: |
| mov $readcommand,%eax |
| jmp *resultreg |
| |
| callto: |
| movl $call1a, subroutinereg |
| jmp readnibbles |
| call1a: |
| mov $readcommand,%eax |
| call *resultreg |
| jmp readcommand |
| |
| dopush: |
| movl $push1a, subroutinereg |
| jmp readnibbles |
| push1a: |
| mov resultreg,%eax |
| push %eax |
| jmp readcommand |
| |
| doint: |
| movl $int1a, subroutinereg |
| jmp readnibbles |
| int1a: |
| mov resultreg,%eax |
| // need to lookup int table? |
| // int %eax |
| jmp readcommand |
| |
| doenter: |
| //setup stack frame |
| |
| |
| dopop: |
| movl $readcommand, subroutinereg |
| pop resultreg |
| jmp displayhex |
| |
| docli: |
| cli |
| jmp readcommand |
| |
| dosti: |
| sti |
| jmp readcommand |
| |
| |
| displaystring: |
| // resultreg= pointer to string terminated by \0 |
| dsloop: |
| movb (resultreg),%ah |
| cmp $0x0, %ah |
| jz displaystringexit |
| mov UART_BASEADDR+5,%dx |
| us_waits: |
| in %dx,%al |
| test $0x20,%al |
| jz us_waits |
| mov UART_BASEADDR,%dx |
| xchg %al,%ah |
| out %al,%dx // output char |
| inc resultreg |
| jmp dsloop |
| displaystringexit: |
| jmp *subroutinereg |
| |
| displayhexlinear: |
| mov resultreg,%eax |
| xchg %al,%ah |
| rol $0x10,%eax |
| xchg %al,%ah |
| mov %eax,resultreg |
| displayhex: |
| rol $0x10,%ecx |
| mov $0x8,%cx |
| dhloop: |
| cmp $0xf,%cl |
| je exitdisplayhex |
| rol $0x04,resultreg |
| movl resultreg,%eax |
| and $0xf,%al |
| cmp $0xa,%al |
| jl addnum |
| //addcaps |
| add $0x37,%al |
| jmp outcharhex |
| addnum: |
| add $0x30,%al |
| outcharhex: |
| xchg %al,%ah |
| mov UART_BASEADDR+5,%dx |
| us_waith: |
| in %dx,%al |
| test $0x20,%al |
| jz us_waith |
| mov UART_BASEADDR,%dx |
| xchg %al,%ah |
| out %al,%dx // output char |
| dec %cx |
| cmp $0x0,%cx |
| jne dhloop |
| mov $0x20,%al |
| mov $0x10,%cl |
| jmp outcharhex |
| exitdisplayhex: |
| rol $0x10,%ecx |
| jmp *subroutinereg |
| |
| displayasciilinear: |
| mov resultreg,%eax |
| xchg %al,%ah |
| rol $0x10,%eax |
| xchg %al,%ah |
| mov %eax,resultreg |
| displayascii: |
| rol $0x10,%ecx |
| mov $0x4,%cx |
| daloop: |
| rol $0x08,resultreg |
| movl resultreg,%eax |
| cmp $0x7e,%al |
| jg unprintable |
| cmp $0x20,%al |
| jl unprintable |
| jmp outcharascii |
| unprintable: |
| mov $0x2e,%al // dot |
| outcharascii: |
| xchg %al,%ah |
| mov UART_BASEADDR+5,%dx |
| us_waita: |
| in %dx,%al |
| test $0x20,%al |
| jz us_waita |
| mov UART_BASEADDR,%dx |
| xchg %al,%ah |
| out %al,%dx // output char |
| dec %cx |
| cmp $0x0,%cx |
| jne daloop |
| rol $0x10,%ecx |
| jmp *subroutinereg |
| |
| rst: |
| cli |
| movb $0x0fe,%al |
| out %al,$0x64 |
| hlt |
| |
| RST: |
| cli |
| lidt %cs:0x03fff |
| int $0x3 |
| hlt |
| |
| |
| beep: |
| mov timertime,%eax |
| rol $0x10,%eax |
| mov $0xb6,%al |
| out %al,$0x43 |
| mov freqtime,%ax |
| out %al,$0x42 |
| xchg %al,%ah |
| out %al,$0x42 |
| |
| in $0x61,%al |
| or $0x03,%al |
| out %al,$0x61 |
| |
| //timer here |
| timer: |
| in $0x42,%al |
| // xchg %al,%ah |
| in $0x42,%al |
| // xchg %al,%ah |
| cmp $0x0,%al |
| jnz timer |
| rol $0x10,%eax |
| dec %ax |
| cmp $0x0,%ax; |
| rol $0x10,%eax |
| jnz timer |
| // timer |
| |
| in $0x61,%al |
| and $0xfc,%al |
| out %al,$0x61 |
| jmp *subroutinereg |
| |
| dohelp: |
| mov $cmds,resultreg |
| mov $readcommand,subroutinereg |
| jmp displaystring |
| |
| memt: |
| movl $memt1, subroutinereg |
| jmp readnibbles |
| memt1: |
| mov resultreg,%ecx |
| movl $memt2, subroutinereg |
| jmp readnibbles |
| memt2: |
| mov resultreg,%ebx |
| xchg %ecx,%eax |
| mov $readcommand,%esp // internal to linux bios |
| jmp ramtest |
| |
| pcirb: |
| movl $pcirb1, subroutinereg |
| jmp readnibbles |
| pcirb1: |
| mov resultreg,%eax |
| PCI_READ_CONFIG_BYTE |
| and $0xff,%eax |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| pcirw: |
| movl $pcirw1, subroutinereg |
| jmp readnibbles |
| pcirw1: |
| mov resultreg,%eax |
| PCI_READ_CONFIG_WORD |
| and $0xffff,%eax |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| pcirl: |
| movl $pcirl1, subroutinereg |
| jmp readnibbles |
| pcirl1: |
| mov resultreg,%eax |
| PCI_READ_CONFIG_DWORD |
| mov %eax,resultreg |
| mov $readcommand,subroutinereg |
| jmp displayhex |
| |
| |
| |
| |
| pciwb: |
| movl $pciwb1, subroutinereg |
| jmp readnibbles |
| pciwb1: |
| mov resultreg,%ebx |
| movl $pciwb2, subroutinereg |
| jmp readnibbles |
| pciwb2: |
| mov resultreg,%edx |
| mov %ebx,%eax |
| PCI_WRITE_CONFIG_BYTE |
| jmp readcommand |
| |
| pciww: |
| movl $pciww1, subroutinereg |
| jmp readnibbles |
| pciww1: |
| mov resultreg,%ebx |
| movl $pciww2, subroutinereg |
| jmp readnibbles |
| pciww2: |
| mov resultreg,%ecx |
| mov %ebx,%eax |
| PCI_WRITE_CONFIG_WORD |
| jmp readcommand |
| |
| pciwl: |
| movl $pciwl1, subroutinereg |
| jmp readnibbles |
| pciwl1: |
| mov resultreg,%ebx |
| movl $pciwl2, subroutinereg |
| jmp readnibbles |
| pciwl2: |
| mov resultreg,%ecx |
| mov %ebx,%eax |
| PCI_WRITE_CONFIG_DWORD |
| jmp readcommand |
| |
| cram: |
| //likely not working. Just testing for now |
| movl $cram1, subroutinereg |
| jmp readnibbles |
| cram1: |
| mov resultreg,%ebx |
| movl $cram1, subroutinereg |
| jmp readnibbles |
| cram2: |
| mov resultreg,%ecx |
| // enable it |
| mov %cr0,%eax |
| and $0x9fffffff,%eax // also try 0x0fff, 0x2ff(write back)... |
| mov %eax,%cr0 |
| //wbinvd ?? |
| cacheloop: |
| mov (%ebx),%eax |
| inc %ebx |
| loop cacheloop |
| // disable it |
| mov %cr0,%eax |
| or $0x60000000,%eax |
| mov %eax,%cr0 |
| //wbinvd ?? |
| |
| dodl: |
| movl $dl1, subroutinereg |
| jmp readnibbles |
| dl1: |
| mov resultreg,%ebx |
| movl $dl2, subroutinereg |
| jmp readnibbles |
| dl2: |
| mov resultreg,%ecx |
| mov resultreg,subroutinereg |
| mov %ebx,resultreg |
| dlloop: |
| mov UART_BASEADDR+5,%dx |
| in %dx, %al |
| and $0x9f,%al |
| test $0x01,%al |
| jz dlloop |
| mov UART_BASEADDR,%dx |
| in %dx,%al |
| mov %al,(%ebx) |
| inc %ebx |
| loop dlloop |
| csum: |
| mov subroutinereg,%ecx |
| shr $0x02,%ecx |
| mov resultreg,%ebx |
| mov $0x0,%eax |
| csumloop: |
| rol $0x03,%eax |
| mov (%ebx),%dl |
| xor %dl,%al |
| inc %ebx |
| loop csumloop |
| mov $readcommand,subroutinereg |
| mov %eax,resultreg |
| jmp displayhex |
| |
| baud: |
| mov $sorry,resultreg |
| mov $readcommand,subroutinereg |
| jmp displaystring |
| |
| mcp: |
| movl $mcp1, subroutinereg |
| jmp readnibbles |
| mcp1: |
| mov resultreg,%ebx |
| movl $mcp2, subroutinereg |
| jmp readnibbles |
| mcp2: |
| mov resultreg,%ecx |
| movl $mcp3, subroutinereg |
| jmp readnibbles |
| mcp3: |
| mov resultreg,%eax |
| xchg %ecx,%eax |
| mcploop: |
| mov (%ebx),%dl |
| mov %dl,(%eax) |
| inc %ebx |
| inc %eax |
| loop mcploop |
| jmp readcommand |
| |
| dopattern: |
| movl $pat1, subroutinereg |
| jmp readnibbles |
| pat1: |
| mov resultreg,%ebx |
| movl $pat2, subroutinereg |
| jmp readnibbles |
| pat2: |
| mov resultreg,%ecx |
| movl $pat3, subroutinereg |
| jmp readnibbles |
| pat3: |
| mov resultreg,%eax |
| xchg %ecx,%eax |
| patloop: |
| rol $0x08,%ebx |
| mov %bl,(%eax) |
| inc %eax |
| loop patloop |
| jmp readcommand |
| |
| |
| doexit: |
| // LB specific: |
| RETSP // if there's no stack yet, caller must set %esp manually |
| // RET_LABEL(low_level_shell) |
| |
| |
| //Linux OS Specific |
| ioperms: |
| movl $sys_IOPL, %eax # system-call ID-number |
| movl $3, %ebx # new value for IO0PL |
| int $0x80 # enter the kernel |
| ret |
| |
| llshell_out: |