--- /dev/null
+/* proto.c
+ * GDB remote serial protocol implementation
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define GDB_BUF_SIZE 1024
+
+#include <minilib.h>
+#include <demap.h>
+#include <tables.h>
+
+#include <lwip/tcp.h>
+
+#include "stub.h"
+
+#define GDB_PORT 2159
+
+enum fsm_result { NEEDMORE, OK, FAIL };
+
+static struct tcp_pcb * last_conn = NULL;
+
+void enhexificate (void * ibuf, char * obuf, int len) {
+ unsigned char * cibuf = ibuf;
+ while (len > 0) {
+ btohex(obuf, *(cibuf++));
+ obuf += 2;
+ len--;
+ }
+
+ *obuf = '\0';
+}
+
+void rle (char * buf) {
+ char * inptr = buf;
+ char * outptr = buf;
+ int lastchar = buf[0];
+ int repcount = 0;
+
+ do {
+ if (*inptr == lastchar && repcount < 97) {
+ repcount += 1;
+ } else {
+ *(outptr++) = lastchar;
+
+ if (repcount == 2)
+ *(outptr++) = lastchar;
+
+ while (repcount == 6 || repcount == 7) {
+ *(outptr++) = lastchar;
+ repcount--;
+ }
+
+ if (repcount > 2) {
+ *(outptr++) = '*';
+ *(outptr++) = repcount + 29;
+ }
+
+ repcount = 1;
+ lastchar = *inptr;
+ }
+
+ inptr++;
+ } while (lastchar);
+
+ *(outptr) = 0;
+}
+
+
+struct gdb_state {
+ char data[128];
+ int writepos;
+ int readpos;
+};
+
+
+static void close_conn(struct tcp_pcb *pcb, struct gdb_state *state) {
+ outputf("close_conn: bailing");
+ set_run_mode(RM_UNENCUMBERED);
+ last_conn = NULL;
+ tcp_arg(pcb, NULL);
+ tcp_sent(pcb, NULL);
+ tcp_recv(pcb, NULL);
+ mem_free(state);
+ tcp_close(pcb);
+ outputf("close_conn: done");
+}
+
+static int dehexbyte (char * p) {
+ int v0, v1;
+ v0 = dehexit (p[0]);
+ v1 = dehexit (p[1]);
+ if (v0 < 0 || v1 < 0) return -1;
+ return v0 << 4 | v1;
+}
+
+static void finish_and_send(struct tcp_pcb *pcb, char * output_buf, int datalength) {
+ char * p;
+ unsigned char checksum = 0;
+
+ output_buf[0] = '+';
+ output_buf[1] = '$';
+
+ for (p = output_buf + 2; p < output_buf + datalength + 2; p++)
+ checksum += *(unsigned char *)p;
+
+ output_buf[datalength + 2] = '#';
+
+ btohex(output_buf + datalength + 3, checksum);
+ tcp_write(pcb, output_buf, datalength + 5, TCP_WRITE_FLAG_COPY);
+}
+
+void send_stop_packet() {
+ if (!last_conn) return;
+ tcp_write(last_conn, "$T05thread:01;#07", 17, 0);
+}
+
+static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct gdb_state *state) {
+ char * endp;
+ char * p;
+ unsigned char checksum = 0;
+ int i;
+ uint64_t addr;
+ uint64_t length;
+
+ char output_buf[256];
+
+ /* Make sure we have at least 4 bytes (the size of the smallest legal
+ packet), and that the packet does in fact start with $. */
+
+ if ((state->data[0] == '+') || (state->data[0] == '-')) {
+ outputf("GDB: chomp");
+ state->readpos++;
+ return OK;
+ }
+
+ if (state->writepos < 4) return NEEDMORE;
+
+ if (state->data[0] != '$') return FAIL;
+
+ /* Find the end; make sure there's room for the checksum after. */
+
+ endp = memchr(state->data, '#', state->writepos);
+
+ if ((!endp) || (endp - state->data > state->writepos - 3))
+ return NEEDMORE;
+
+ /* Checksum. */
+
+ for (p = state->data + 1; p < endp; p++)
+ checksum += *(unsigned char *)p;
+
+ if (checksum != dehexbyte(endp + 1))
+ {
+ outputf("GDB: bad checksum: %d vs %d", checksum , dehexbyte(endp + 1));
+ return FAIL;
+ }
+
+ /* Null-terminate, for processing convenience */
+ *endp = '\0';
+
+ outputf("GDB: Got \'%s\'", state->data + 1);
+
+ /* OK, process the packet */
+
+ switch (state->data[1]) {
+ case '?':
+ tcp_write(pcb, "+$T05thread:01;#07", 18, 0);
+ break;
+ case 'g':
+ read_registers_32(output_buf + 2);
+ finish_and_send(pcb, output_buf, 128);
+ break;
+
+ case 'm':
+ /* Parse the address */
+ p = memchr(state->data, ',', endp - state->data);
+ if (!p) return FAIL;
+ *p = '\0';
+ addr = 0;
+ length = 0;
+
+ if (!dehexstring(&addr, state->data + 2, -1)) return FAIL;
+ if (!dehexstring(&length, p + 1, -1)) return FAIL;
+
+ outputf("GDB: read %d from %d", (uint32_t)length, (uint32_t)addr);
+
+ if (length > 120) length = 120;
+
+ for (i = 0; i < length; i++) {
+ p = demap(addr++);
+ if (!p) break;
+ btohex(output_buf + 2 + (2*i), *(char *)p);
+ }
+
+ finish_and_send(pcb, output_buf, 2*i);
+ break;
+
+ case 's':
+ /* Step. */
+ set_run_mode(RM_STEPPING);
+ tcp_write(pcb, "+", 1, 0);
+ break;
+
+ default:
+ tcp_write(pcb, "+$#00", 5, 0);
+ break;
+ }
+
+ state->readpos += (endp - state->data) + 3;
+
+ return OK;
+}
+
+err_t
+gdb_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
+ struct gdb_state *state = arg;
+ uint16_t copylen;
+
+ if (err != ERR_OK) {
+ outputf("GDB: recv err %d", err);
+ /* FIXME do something better here? */
+ return ERR_OK;
+ }
+
+ if (p == NULL) {
+ outputf("GDB: Connection closed");
+ close_conn(pcb, state);
+ return ERR_OK;
+ }
+
+ if (p->tot_len > (GDB_BUF_SIZE - state->writepos)) {
+ /* Overflow! */
+ outputf("GDB: Overflow!");
+ close_conn(pcb, state);
+ return ERR_OK;
+ }
+
+ copylen = pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
+
+ outputf("GDB: Processing %d, wp %d, cp %d", p->tot_len, state->writepos, copylen);
+
+ state->writepos += p->tot_len;
+
+ tcp_recved(pcb, p->tot_len);
+ pbuf_free(p);
+
+ while (1) {
+ switch (recv_fsm(pcb, state)) {
+ case NEEDMORE:
+ outputf("GDB FSM: blocking");
+ goto doneprocessing;
+
+ case OK:
+ if (state->readpos == state->writepos) {
+ state->readpos = 0;
+ state->writepos = 0;
+ goto doneprocessing;
+ } else {
+ memmove(state->data,
+ state->data + state->readpos,
+ state->writepos - state->readpos);
+ state->writepos -= state->readpos;
+ state->readpos = 0;
+ }
+ break;
+ case FAIL:
+ /* Shit */
+ outputf("GDB: Protocol error");
+ close_conn(pcb, state);
+ return ERR_OK;
+ }
+ }
+
+doneprocessing:
+ return ERR_OK;
+}
+
+static err_t gdb_sent(void *arg, struct tcp_pcb *pcb, uint16_t len) {
+/*
+ struct gdb_state *state = arg;
+ send_fsm(pcb, state);
+*/
+ return ERR_OK;
+}
+
+static err_t gdb_poll(void *arg, struct tcp_pcb *pcb) {
+ /* Nothing? */
+ return ERR_OK;
+}
+
+
+static err_t gdb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
+ struct gdb_state *state;
+
+ LWIP_UNUSED_ARG(arg);
+ LWIP_UNUSED_ARG(err);
+
+ outputf("GDB: accept");
+
+ last_conn = pcb;
+
+ set_run_mode(RM_STOPPED);
+
+ state = (struct gdb_state *)mem_malloc(sizeof(struct gdb_state));
+
+ if (!state)
+ {
+ outputf("gdb_accept: out of memory\n");
+ return ERR_MEM;
+ }
+
+ memset(state, 0, sizeof(struct gdb_state));
+
+ tcp_arg(pcb, state);
+ tcp_recv(pcb, gdb_recv);
+ tcp_sent(pcb, gdb_sent);
+ tcp_poll(pcb, gdb_poll, 1);
+/*
+ tcp_err(pcb, gdb_err);
+*/
+ return ERR_OK;
+}
+
+
+void gdb_init() {
+ struct tcp_pcb *pcb;
+ pcb = tcp_new();
+ tcp_bind(pcb, IP_ADDR_ANY, GDB_PORT);
+ pcb = tcp_listen(pcb);
+ tcp_accept(pcb, gdb_accept);
+}
+
+PROTOCOL(gdb_init);
--- /dev/null
+/* gdb.h
+ * GDB server
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GDB_PROTO_H
+#define _GDB_PROTO_H
+
+void enhexificate (void * ibuf, char * obuf, int len);
+void gdb_init(void);
+
+#endif /* _GDB_PROTO_H */
--- /dev/null
+/* stub.c
+ * GDB stub system manipultion code.
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <msr.h>
+#include <output.h>
+#include <state.h>
+#include <demap.h>
+#include <paging.h>
+#include <reg-x86.h>
+#include "proto.h"
+#include "stub.h"
+
+void send_stop_packet();
+
+uint16_t saved_db_entry;
+uint64_t saved_db_entry_location;
+enum operating_mode step_start_mode;
+uint64_t saved_cs_base;
+uint64_t saved_eflags;
+uint64_t saved_cs_limit;
+uint64_t saved_cs_attrib;
+uint64_t saved_ss_base;
+uint64_t saved_ss_limit;
+uint64_t saved_ss_attrib;
+
+#define P64(x) (uint32_t)((x)>>32), (uint32_t)(x)
+
+static const enum state_reg_t regs32 [] = {
+ STATE_REG_EAX, STATE_REG_ECX, STATE_REG_EDX, STATE_REG_EBX,
+ STATE_REG_ESP, STATE_REG_EBP, STATE_REG_ESI, STATE_REG_EDI,
+ STATE_REG_EIP, STATE_REG_EFLAGS, STATE_REG_CS, STATE_REG_SS,
+ STATE_REG_DS, STATE_REG_ES, STATE_REG_FS, STATE_REG_GS
+};
+
+static enum run_mode run_mode;
+
+void set_run_mode(enum run_mode mode) {
+ run_mode = mode;
+}
+
+int gdb_post_smi_hook() {
+ uint64_t r, entry;
+ uint32_t * ptr;
+ uint16_t * entry_v;
+ enum operating_mode m = get_operating_mode();
+
+
+ switch (run_mode) {
+ case RM_STOPPED:
+ /* Until we have a better way of handling this - spin in
+ * a loop. */
+ return 1;
+
+ case RM_STEPPING:
+ /* First, set RFLAGS.TF */
+ r = state_get_reg(STATE_REG_EFLAGS);
+ saved_eflags = r;
+ r |= EFLAGS_TF;
+ /* We also don't want to deal with interrupts. */
+ r &= ~EFLAGS_IF;
+ state_set_reg(STATE_REG_EFLAGS, r);
+
+ /* Track down the handler for a debug exception */
+ r = state_get_reg(STATE_REG_IDT_LIMIT);
+ r = state_get_reg(STATE_REG_IDT_BASE);
+ if (m == LONG_64BIT || m == LONG_COMPAT) {
+ /* 64-bit. Index up 16 bytes to get to the
+ * debug trap descriptor. */
+ ptr = demap(r + 16);
+ entry = (*ptr) & 0xFFFF;
+ ptr = demap(r + 20);
+ entry |= (*ptr) & 0xFFFF0000;
+ ptr = demap(r + 24);
+ entry |= (uint64_t)(*ptr) << 32;
+ } else {
+ /* Assume 32-bit for now. */
+ ptr = demap(r + 8);
+ entry = (*ptr) & 0xFFFF;
+ ptr = demap(r + 12);
+ entry |= (*ptr) & 0xFFFF0000;
+ }
+
+ outputf("entry is at %08x %08x", (uint32_t)(entry>>32), (uint32_t)entry);
+ /* MAGIC_BREAK */
+ saved_db_entry_location = demap_phys(entry);
+ entry_v = p2v(saved_db_entry_location);
+ outputf("entry_v mapped to %08x", entry_v);
+ if (!entry_v) {
+ run_mode = RM_UNENCUMBERED; break;
+ }
+ saved_db_entry = *entry_v;
+ *entry_v = 0xB2E6; /* "out %al, $0xb2" */
+
+ step_start_mode = m;
+
+ /* Turn off the safety */
+ WRMSR(0xc0010054, 0x8002);
+ outputf("Have fun!");
+
+ saved_cs_base = state_get_reg(STATE_REG_CS_BASE);
+ saved_cs_limit = state_get_reg(STATE_REG_CS_LIMIT);
+ saved_cs_attrib = state_get_reg(STATE_REG_CS_ATTRIB);
+ saved_ss_base = state_get_reg(STATE_REG_SS_BASE);
+ saved_ss_limit = state_get_reg(STATE_REG_SS_LIMIT);
+ saved_ss_attrib = state_get_reg(STATE_REG_SS_ATTRIB);
+
+ break;
+
+ case RM_CONTINUING:
+ /* There may be breakpoints. Fall through to
+ * "unencumbered" for now. */
+
+ case RM_UNENCUMBERED:
+ /* Nada. */
+ return 0;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+#define READ_QWORD(pa) ({ uint64_t * p = demap(pa); if (!p) goto fail; outputf("pq %08x %08x", (uint32_t)((*p)>>32), (uint32_t)(*p)); *p; })
+#define READ_WORD(pa) ({ uint16_t * p = demap(pa); if (!p) goto fail; outputf("p %04x", (*p)); *p; })
+
+static void gdb_unmangle_stepped_system() {
+ uint64_t r;
+ uint16_t * entry_v;
+
+ /* The unexpected breakpoint has caused an interrupt stack to be
+ * built, which we must get rid of. */
+
+ if (step_start_mode == LONG_64BIT) {
+ r = state_get_reg(STATE_REG_RSP);
+ state_set_reg(STATE_REG_RIP, READ_QWORD(r));
+ state_set_reg(STATE_REG_CS, READ_WORD(r+8));
+ state_set_reg(STATE_REG_RFLAGS, READ_QWORD(r+16));
+ state_set_reg(STATE_REG_RSP, READ_QWORD(r+24));
+ state_set_reg(STATE_REG_SS, READ_WORD(r+32));
+ } else if (step_start_mode == LONG_COMPAT) {
+ r = state_get_reg(STATE_REG_RSP);
+ state_set_reg(STATE_REG_RIP, READ_QWORD(r) & 0xFFFFFFFF);
+ state_set_reg(STATE_REG_CS, READ_WORD(r+8));
+ state_set_reg(STATE_REG_RFLAGS, READ_QWORD(r+16) & 0xFFFFFFFF);
+ state_set_reg(STATE_REG_RSP, READ_QWORD(r+24) & 0xFFFFFFFF);
+ state_set_reg(STATE_REG_SS, READ_WORD(r+32));
+ }
+ entry_v = p2v(saved_db_entry_location);
+ *entry_v = saved_db_entry;
+
+ state_set_reg(STATE_REG_CS_BASE, saved_cs_base);
+ state_set_reg(STATE_REG_CS_LIMIT, saved_cs_limit);
+ state_set_reg(STATE_REG_CS_ATTRIB, saved_cs_attrib);
+ state_set_reg(STATE_REG_SS_BASE, saved_ss_base);
+ state_set_reg(STATE_REG_SS_LIMIT, saved_ss_limit);
+ state_set_reg(STATE_REG_SS_ATTRIB, saved_ss_attrib);
+ state_set_reg(STATE_REG_EFLAGS, saved_eflags);
+
+ /* Put us back in "stopped" mode, until the GDB server gets around
+ * to handling the step.
+ */
+
+ reset_operating_mode_memo();
+ run_mode = RM_STOPPED;
+
+ send_stop_packet();
+ return;
+
+fail:
+ outputf("ERROR: Failed to restore state!");
+ while(1);
+}
+
+void gdb_pre_smi_hook() {
+ enum operating_mode m = get_operating_mode();
+ uint64_t ip, break_phys;
+
+ if (run_mode == RM_STEPPING) {
+ /* Oh hey, we are probably stopped on a breakpoint.
+ * Let's check. */
+ ip = state_get_reg(
+ (m == LONG_64BIT)
+ ? STATE_REG_RIP : STATE_REG_EIP
+ );
+ break_phys = demap_phys(ip);
+
+ if ((break_phys != saved_db_entry_location)
+ && (break_phys != saved_db_entry_location + 2)) {
+ /* Some other event caused us to enter SMM. We'll deal
+ * with the single step when we *actually* get to
+ * the breakpoint. */
+ return;
+ }
+
+ /* Great. Now we have caused a debug exception.
+ *
+ * "Your problems just got worse. Think: what have you done?"
+ *
+ * We don't want the running system to know that anything
+ * ever happened, so we manually unwind the stack and undo
+ * everything that happened.
+ */
+
+ gdb_unmangle_stepped_system();
+ }
+}
+
+
+void read_registers_32 (char * buf) {
+ int i, r = 0, offset = 0, size = 0;
+
+ /* Dump registers to buffer. */
+
+ for (i = 0; i < (sizeof(regs32) / sizeof(enum state_reg_t)); i++) {
+ enum state_reg_t reg = regs32[i];
+ r = state_get_reg(reg);
+ //size = state_reg_size(reg);
+ size = 4;
+ enhexificate(&r, buf + offset, size);
+ offset += (size * 2);
+ }
+
+ /* XXX: The rest of the buffer "should be" filled with floating point
+ stuff. We'll worry about that later. */
+}
+
+void write_registers_32 (char * buf) {
+ //int size = 0, i;
+
+
+ uint32_t *ubuf = (uint32_t *)buf;
+
+ state_set_reg(STATE_REG_EAX, ubuf[0]);
+ state_set_reg(STATE_REG_ECX, ubuf[1]);
+ state_set_reg(STATE_REG_EDX, ubuf[2]);
+ state_set_reg(STATE_REG_EBX, ubuf[3]);
+ state_set_reg(STATE_REG_ESP, ubuf[4]);
+ state_set_reg(STATE_REG_EBP, ubuf[5]);
+ state_set_reg(STATE_REG_ESI, ubuf[6]);
+ state_set_reg(STATE_REG_EDI, ubuf[7]);
+
+ state_set_reg(STATE_REG_EIP, ubuf[8]);
+ state_set_reg(STATE_REG_EFLAGS, ubuf[9]);
+ state_set_reg(STATE_REG_CS, ubuf[10]);
+ state_set_reg(STATE_REG_SS, ubuf[11]);
+ state_set_reg(STATE_REG_DS, ubuf[12]);
+ state_set_reg(STATE_REG_ES, ubuf[13]);
+ state_set_reg(STATE_REG_FS, ubuf[14]);
+ state_set_reg(STATE_REG_GS, ubuf[15]);
+
+ /* XXX: Again, need to deal with floating point. */
+}
--- /dev/null
+/* stub.h
+ * Headers for GDB stub system manipulation.
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STUB_H
+#define __STUB_H
+
+void read_registers_32 (char * buf);
+void write_registers_32 (char * buf);
+
+enum run_mode {
+ RM_UNENCUMBERED,
+ RM_STOPPED,
+ RM_STEPPING,
+ RM_CONTINUING
+};
+
+void set_run_mode(enum run_mode mode);
+
+#endif
--- /dev/null
+/* demap.h
+ * Definitions for system page table de-mapping
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DEMAP_H
+#define __DEMAP_H
+
+#include <stdint.h>
+
+enum operating_mode {
+ UNKNOWN = 0,
+ LONG_64BIT,
+ LONG_COMPAT,
+ PROTECTED_PAGING,
+ PROTECTED_NOPAGING,
+ REAL,
+ V8086
+};
+
+enum operating_mode get_operating_mode(void);
+void reset_operating_mode_memo(void);
+
+uint64_t demap_phys (uint64_t vaddr);
+void * demap (uint64_t vaddr);
+
+#endif
#ifndef __PAGING_H
#define __PAGING_H
+#include <stdint.h>
+
extern unsigned long v2p(void *virt);
extern void *p2v(unsigned long phys);
+extern void *p2v64(uint64_t phys);
extern int addmap(unsigned long vaddr, unsigned long paddr);
extern int addmap_4m(unsigned long vaddr, unsigned long paddr);
-extern void *demap(unsigned long _pd, unsigned long vaddr);
#endif
--- /dev/null
+/* reg-k8-msr.h
+ * K8 / AMD64 architectural MSR macros.
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef REG_K8_MSR_H
+#define REG_K8_MSR_H
+
+#define SMM_ADDR_MSR 0xC0010112
+#define SMM_MASK_MSR 0xC0010113
+
+#define HWCR_MSR 0xC0010015
+
+#define HWCR_MSR_SMMLOCK (1 << 0)
+
+#define EFER_MSR 0xC0000080
+
+#define EFER_MSR_LMA (1 << 10)
+
+
+#endif
--- /dev/null
+/* reg-x86.h
+ * X86 standard registers
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __REG_X86_H
+#define __REG_X86_H
+
+#define CR0_PE (1<<0)
+#define CR0_MP (1<<1)
+#define CR0_EM (1<<2)
+#define CR0_TS (1<<3)
+#define CR0_ET (1<<4)
+#define CR0_NE (1<<5)
+#define CR0_WP (1<<16)
+#define CR0_AM (1<<18)
+#define CR0_NW (1<<29)
+#define CR0_CD (1<<30)
+#define CR0_PG (1<<31)
+
+#define CR3_PWT (1<<3)
+#define CR3_PCD (1<<4)
+
+#define CR4_VME (1<<0)
+#define CR4_PVI (1<<1)
+#define CR4_TSD (1<<2)
+#define CR4_DE (1<<3)
+#define CR4_PSE (1<<4)
+#define CR4_PAE (1<<5)
+#define CR4_MCE (1<<6)
+#define CR4_PGE (1<<7)
+#define CR4_PCE (1<<8)
+#define CR4_OSFXSR (1<<9)
+#define CR4_OSXMMEXCPT (1<<10)
+
+#define EFLAGS_CF (1<<0)
+#define EFLAGS_PF (1<<2)
+#define EFLAGS_AF (1<<4)
+#define EFLAGS_ZF (1<<6)
+#define EFLAGS_SF (1<<7)
+#define EFLAGS_TF (1<<8)
+#define EFLAGS_IF (1<<9)
+#define EFLAGS_DF (1<<10)
+#define EFLAGS_OF (1<<11)
+#define EFLAGS_IOPL (3<<12)
+#define EFLAGS_NT (1<<14)
+#define EFLAGS_RF (1<<16)
+#define EFLAGS_VM (1<<17)
+#define EFLAGS_AC (1<<18)
+#define EFLAGS_VIF (1<<19)
+#define EFLAGS_VIP (1<<20)
+#define EFLAGS_ID (1<<21)
+
+#endif /* __REG_X86_H */
+
STATE_REG_CR3,
STATE_REG_CS,
+ STATE_REG_CS_ATTRIB,
+ STATE_REG_CS_BASE,
+ STATE_REG_CS_LIMIT,
STATE_REG_SS,
+ STATE_REG_SS_ATTRIB,
+ STATE_REG_SS_BASE,
+ STATE_REG_SS_LIMIT,
STATE_REG_DS,
+ STATE_REG_DS_ATTRIB,
+ STATE_REG_DS_BASE,
+ STATE_REG_DS_LIMIT,
STATE_REG_ES,
+ STATE_REG_ES_ATTRIB,
+ STATE_REG_ES_BASE,
+ STATE_REG_ES_LIMIT,
STATE_REG_FS,
+ STATE_REG_FS_ATTRIB,
+ STATE_REG_FS_BASE,
+ STATE_REG_FS_LIMIT,
STATE_REG_GS,
+ STATE_REG_GS_ATTRIB,
+ STATE_REG_GS_BASE,
+ STATE_REG_GS_LIMIT,
+ STATE_REG_IDT_BASE,
+ STATE_REG_IDT_LIMIT,
/* 64-bit registers */
STATE_REG_RAX,
STATE_REG_R13,
STATE_REG_R14,
STATE_REG_R15,
- STATE_REG_RIP
+ STATE_REG_RIP,
+ STATE_REG_RFLAGS,
+
+ STATE_REG_EFER,
+
+ NUM_REGISTERS
};
+
enum smm_type {
SMM_TYPE_UNKNOWN,
SMM_TYPE_32,
SMM_TYPE_64
};
+enum smm_type state_get_type(void);
+
uint64_t state_get_reg (enum state_reg_t reg);
int state_reg_size (enum state_reg_t reg);
int state_set_reg (enum state_reg_t reg, uint64_t value);
+int state_dump_reg(char * dest, int max, enum state_reg_t reg);
+
#endif /* __STATE_H */
--- /dev/null
+/* tables.h
+ * Linker table helper macros.
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TABLES_H
+#define __TABLES_H
+
+/* Linker tables are a beautiful, evil piece of magic.
+ *
+ * The idea is this;
+ * - For each table, define start and end pointers as zero-length arrays.
+ * - Define however many data values as constants of the appropriate type
+ * - Put each in its own section. For example, 'start' is in section
+ * .table.foo; the data elemnts are in section .table.foo.1 (or other values
+ * for explicit ordering); and 'end' is in .table.foo.END.
+ * - Merge the sections together with the following linker script entry:
+ * *(SORT(.table.*))
+ *
+ * This has the effect that the start symbol points to the first value in the
+ * table, and the end symbol points to the last. The number of values is
+ * simply (table_foo_end - table_foo_start).
+ *
+ * And everything Just Works. Etherboot and the Linux kernel both use this
+ * for identifying linked-in modules; they have a somewhat more elaborate
+ * macro infastructure, but at the moment there are only two tables in
+ * NetWatch (network protocols and built-in drivers), so less is needed.
+ */
+
+#define PROTOCOL(x) void (* const x##_ptr)(void) \
+ __attribute__((section(".table.protocols.1"))) = x
+
+
+
+#define TABLE(typ, name) \
+ typ name##_table[0] __attribute__((section(".table." #name ))); \
+ typ name##_table_end[0] __attribute__((section(".table." #name ".END")));
+
+#define TABLE_LENGTH(name) (name##_table_end - name##_table)
+
+#endif /* __TABLES_H */
+
--- /dev/null
+/* demap.h
+ * Paging lookup functions.
+ * NetWatch system management mode administration console
+ *
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <state.h>
+#include <msr.h>
+#include <reg-k8-msr.h>
+#include <reg-x86.h>
+#include <paging.h>
+#include <output.h>
+#include <demap.h>
+
+#define REG_CS_ATTRIB_L (1<<9)
+#define PTE_PRESENT (1<<0)
+#define PTE_LARGE (1<<7)
+
+#define PTE_FOR(x) (((unsigned int)(x) >> 12) & 0x3FF)
+#define PDE_FOR(x) ((unsigned int)(x) >> 22)
+#define ADDR_12_MASK(x) ((unsigned int)(x) & ~((1 << 12) - 1))
+
+/* Keep a memoized copy of the operating mode the CPU was in when we
+ * entered SMM, so we don't have to look it up every time.
+ */
+
+static enum operating_mode mode;
+
+void reset_operating_mode_memo() {
+ mode = UNKNOWN;
+}
+
+/* Check the saved state map to determine what mode we were in. */
+
+void probe_operating_mode() {
+ unsigned long cr0;
+
+ if (state_get_type() == SMM_TYPE_64) {
+ /* This is a 64-bit processor, so we may be in 64-bit
+ * full or compatibility mode. Check if we are. */
+
+ uint64_t efer = state_get_reg(STATE_REG_EFER);
+
+ if (efer & EFER_MSR_LMA) {
+ /* We are in long mode. Is this full 64-bit, or
+ * comatibility mode? Check the "L" bit of the
+ * saved CS descriptor to be sure. */
+
+ if (state_get_reg(STATE_REG_CS_ATTRIB)
+ & REG_CS_ATTRIB_L) {
+ mode = LONG_64BIT;
+ } else {
+ mode = LONG_COMPAT;
+ }
+
+ return;
+ }
+ /* Otherwise, we are in legacy mode, so do the normal
+ * 32-bit probes. */
+ }
+
+ /* Either we are on a 32-bit processor, or we are on a 64-bit
+ * processor in legacy mode. */
+
+ if (state_get_reg(STATE_REG_EFLAGS) & EFLAGS_VM) {
+ mode = V8086;
+ return;
+ }
+
+ cr0 = state_get_reg(STATE_REG_CR0);
+
+ if (cr0 & CR0_PE)
+ if (cr0 & CR0_PG)
+ mode = PROTECTED_PAGING;
+ else
+ mode = PROTECTED_NOPAGING;
+ else
+ mode = REAL;
+}
+
+enum operating_mode get_operating_mode() {
+ if (mode == UNKNOWN)
+ probe_operating_mode();
+
+ return mode;
+}
+
+#define LONG_ADDR_MASK 0x000FFFFFFFFFF000
+#define PAGE_1G_MASK 0x000FFFFFC0000000
+#define PAGE_2M_MASK 0x000FFFFFFFE00000
+
+#define LONG_ADDR_SECTION(addr, offset) ((((addr) >> (offset)) & 0x1FF) * 8)
+
+#define READ_PHYS_QWORD(pa) ({ uint64_t * p = p2v(pa); if (!p) return 0; *p; })
+
+/* Given a virtual address from the current CPU context, determine what the
+ * actual corresponding physical address would be, then convert that back
+ * to a virtual address suitable for use within NetWatch.
+ *
+ * If the given address is not mapped in to RAM or is mapped to RAM which
+ * cannot be accessed, returns null.
+ *
+ * XXX: This currently handles both long and 32-bit modes, but only knows
+ * how to parse standard 4-kbyte pages. It assumes all segments span the full
+ * 32-bit address space. Thus, it will return correct results for most
+ * userspace environments in most sane OS kernels, but not necessarily kernel
+ * space (likely to be mapped with large pages) or anything that plays tricks
+ * with segmentation (like NaCl).
+ */
+
+uint64_t demap_phys (uint64_t vaddr) {
+
+ uint64_t pa = state_get_reg(STATE_REG_CR3) & LONG_ADDR_MASK;
+ uint64_t entry;
+
+ if (mode == UNKNOWN)
+ probe_operating_mode();
+
+outputf("demapping %08x %08x m %d", (uint32_t)(vaddr>>32), (uint32_t)vaddr, mode);
+ switch (mode) {
+ case LONG_64BIT:
+ case LONG_COMPAT: {
+ /* Get PML4 entry */
+ entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 39));
+ if (!(entry & PTE_PRESENT)) return 0;
+ pa = entry & LONG_ADDR_MASK;
+
+ /* Get PDP entry */
+ entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 30));
+ if (!(entry & PTE_PRESENT)) return 0;
+ pa = entry & LONG_ADDR_MASK;
+
+ if (entry & PTE_LARGE)
+ return (entry & PAGE_1G_MASK) + (vaddr & 0x3FFFFFFF);
+
+ /* Get PDE */
+ entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 21));
+ if (!(entry & PTE_PRESENT)) return 0;
+ pa = entry & LONG_ADDR_MASK;
+
+ if (entry & PTE_LARGE)
+ return (entry & PAGE_2M_MASK) + (vaddr & 0x1FFFFF);
+
+ /* Get PTE */
+ entry = READ_PHYS_QWORD(pa + LONG_ADDR_SECTION(vaddr, 12));
+ if (!(entry & PTE_PRESENT)) return 0;
+ pa = entry & LONG_ADDR_MASK;
+
+ return pa + (vaddr & 0xFFF);
+ }
+ case PROTECTED_NOPAGING:
+ case REAL:
+ return vaddr;
+
+ default: {
+ unsigned long pde = ((unsigned long *)p2v(pa))[PDE_FOR(vaddr)];
+ unsigned long pte;
+
+ if (!(pde & PTE_PRESENT)) return 0;
+ pte = ((unsigned long *)p2v(ADDR_12_MASK(pde)))[PTE_FOR(vaddr)];
+ if (!(pte & PTE_PRESENT)) return 0;
+
+ return (pte & ~0xFFF) + (vaddr & 0xFFF);
+ }
+ }
+}
+
+void *demap(uint64_t vaddr) {
+ uint64_t paddr = demap_phys(vaddr);
+ outputf("demap: paddr 0x%08x %08x", (uint32_t)(paddr>>32), (uint32_t)paddr);
+ if (!paddr) return 0;
+ return p2v(paddr);
+}
+
#include "state.h"
#include <cpuid.h>
+#include <output.h>
+#include <minilib.h>
/* Size flags. */
#define SZ_BYTE 0x10000000
[STATE_REG_DS] = 0xffb4 | SZ_DWORD,
[STATE_REG_ES] = 0xffa8 | SZ_DWORD,
[STATE_REG_FS] = 0xffb8 | SZ_DWORD,
- [STATE_REG_GS] = 0xffbc | SZ_DWORD
+ [STATE_REG_GS] = 0xffbc | SZ_DWORD,
+ [STATE_REG_IDT_BASE] = 0xff94 | SZ_DWORD
};
#define MAX_REG_LEGACY (sizeof(offset_table_legacy)/sizeof(uint32_t))
[STATE_REG_EBP] = 0xffd0 | SZ_DWORD,
[STATE_REG_EIP] = 0xff78 | SZ_DWORD,
[STATE_REG_EFLAGS] = 0xff70 | SZ_DWORD,
- [STATE_REG_CR0] = 0xff58 | SZ_DWORD,
- [STATE_REG_CR3] = 0xff50 | SZ_DWORD,
-
- [STATE_REG_CS] = 0xfe10 | SZ_DWORD,
- [STATE_REG_SS] = 0xfe20 | SZ_DWORD,
- [STATE_REG_DS] = 0xfe30 | SZ_DWORD,
- [STATE_REG_ES] = 0xfe00 | SZ_DWORD,
- [STATE_REG_FS] = 0xfe40 | SZ_DWORD,
- [STATE_REG_GS] = 0xfe50 | SZ_DWORD,
+ [STATE_REG_CR0] = 0xff58 | SZ_QWORD,
+ [STATE_REG_CR3] = 0xff50 | SZ_QWORD,
+
+ [STATE_REG_CS] = 0xfe10 | SZ_WORD,
+ [STATE_REG_CS_ATTRIB] = 0xfe12 | SZ_WORD,
+ [STATE_REG_CS_BASE] = 0xfe18 | SZ_QWORD,
+ [STATE_REG_CS_LIMIT] = 0xfe14 | SZ_DWORD,
+ [STATE_REG_SS] = 0xfe20 | SZ_WORD,
+ [STATE_REG_SS_ATTRIB] = 0xfe22 | SZ_WORD,
+ [STATE_REG_SS_BASE] = 0xfe28 | SZ_QWORD,
+ [STATE_REG_SS_LIMIT] = 0xfe24 | SZ_DWORD,
+ [STATE_REG_DS] = 0xfe30 | SZ_WORD,
+ [STATE_REG_DS_ATTRIB] = 0xfe32 | SZ_WORD,
+ [STATE_REG_DS_BASE] = 0xfe38 | SZ_QWORD,
+ [STATE_REG_DS_LIMIT] = 0xfe34 | SZ_DWORD,
+ [STATE_REG_ES] = 0xfe00 | SZ_WORD,
+ [STATE_REG_ES_ATTRIB] = 0xfe02 | SZ_WORD,
+ [STATE_REG_ES_BASE] = 0xfe08 | SZ_QWORD,
+ [STATE_REG_ES_LIMIT] = 0xfe04 | SZ_DWORD,
+ [STATE_REG_FS] = 0xfe40 | SZ_WORD,
+ [STATE_REG_FS_ATTRIB] = 0xfe42 | SZ_WORD,
+ [STATE_REG_FS_BASE] = 0xfe48 | SZ_QWORD,
+ [STATE_REG_FS_LIMIT] = 0xfe44 | SZ_DWORD,
+ [STATE_REG_GS] = 0xfe50 | SZ_WORD,
+ [STATE_REG_GS_ATTRIB] = 0xfe52 | SZ_WORD,
+ [STATE_REG_GS_BASE] = 0xfe58 | SZ_QWORD,
+ [STATE_REG_GS_LIMIT] = 0xfe54 | SZ_DWORD,
+ [STATE_REG_IDT_BASE] = 0xfe88 | SZ_QWORD,
+ [STATE_REG_IDT_LIMIT] = 0xfe84 | SZ_DWORD,
[STATE_REG_RAX] = 0xfff8 | SZ_QWORD,
[STATE_REG_RBX] = 0xffe0 | SZ_QWORD,
[STATE_REG_R13] = 0xff90 | SZ_QWORD,
[STATE_REG_R14] = 0xff88 | SZ_QWORD,
[STATE_REG_R15] = 0xff80 | SZ_QWORD,
- [STATE_REG_RIP] = 0xff78 | SZ_QWORD
+ [STATE_REG_RIP] = 0xff78 | SZ_QWORD,
+ [STATE_REG_RFLAGS] = 0xff70 | SZ_QWORD,
+
+ [STATE_REG_EFER] = 0xfed0 | SZ_QWORD
+};
+
+static const char register_names[][4] = {
+ [STATE_REV] = "sREV",
+ [STATE_REG_SMBASE] = "sBSE",
+ [STATE_REG_IORESTART] = "IOrs",
+ [STATE_REG_HALTRESTART] = "HLrs",
+
+ [STATE_REG_EAX] = "%eax",
+ [STATE_REG_EBX] = "%ebx",
+ [STATE_REG_ECX] = "%ecx",
+ [STATE_REG_EDX] = "%edx",
+ [STATE_REG_ESI] = "%esi",
+ [STATE_REG_EDI] = "%edi",
+ [STATE_REG_ESP] = "%esp",
+ [STATE_REG_EBP] = "%ebp",
+ [STATE_REG_EIP] = "%eip",
+ [STATE_REG_EFLAGS] = "%eFL",
+ [STATE_REG_CR0] = "%cr0",
+ [STATE_REG_CR3] = "%cr3",
+
+ [STATE_REG_CS] = "%cs ",
+ [STATE_REG_CS_ATTRIB] = "csAT",
+ [STATE_REG_CS_BASE] = "csBA",
+ [STATE_REG_CS_LIMIT] = "csLI",
+ [STATE_REG_SS] = "%ss ",
+ [STATE_REG_SS_ATTRIB] = "ssAT",
+ [STATE_REG_SS_BASE] = "ssBA",
+ [STATE_REG_SS_LIMIT] = "ssLI",
+ [STATE_REG_DS] = "%ds ",
+ [STATE_REG_DS_ATTRIB] = "dsAT",
+ [STATE_REG_DS_BASE] = "dsBA",
+ [STATE_REG_DS_LIMIT] = "dsLI",
+ [STATE_REG_ES] = "%es ",
+ [STATE_REG_ES_ATTRIB] = "esAT",
+ [STATE_REG_ES_BASE] = "esBA",
+ [STATE_REG_ES_LIMIT] = "esLI",
+ [STATE_REG_FS] = "%fs ",
+ [STATE_REG_FS_ATTRIB] = "fsAT",
+ [STATE_REG_FS_BASE] = "fsBA",
+ [STATE_REG_FS_LIMIT] = "fsLI",
+ [STATE_REG_GS] = "%gs ",
+ [STATE_REG_GS_ATTRIB] = "gsAT",
+ [STATE_REG_GS_BASE] = "gsBA",
+ [STATE_REG_GS_LIMIT] = "gsLI",
+
+ [STATE_REG_RAX] = "%rax",
+ [STATE_REG_RBX] = "%rbx",
+ [STATE_REG_RCX] = "%rcx",
+ [STATE_REG_RDX] = "%rdx",
+ [STATE_REG_RSI] = "%rsi",
+ [STATE_REG_RDI] = "%rdi",
+ [STATE_REG_RSP] = "%rsp",
+ [STATE_REG_RBP] = "%rbp",
+ [STATE_REG_R8] = "%r8 ",
+ [STATE_REG_R9] = "%r9 ",
+ [STATE_REG_R10] = "%r10",
+ [STATE_REG_R11] = "%r11",
+ [STATE_REG_R12] = "%r12",
+ [STATE_REG_R13] = "%r13",
+ [STATE_REG_R14] = "%r14",
+ [STATE_REG_R15] = "%r15",
+ [STATE_REG_RIP] = "%rip",
+
+ [STATE_REG_EFER] = "EFER"
};
#define MAX_REG_AMD64 (sizeof(offset_table_amd64)/sizeof(uint32_t))
return 0;
}
+
+/* Dump the name and contents of a register to a string.
+ *
+ * Returns: The number of bytes written.
+ */
+
+int state_dump_reg(char * dest, int max, enum state_reg_t reg) {
+ const char const * name = register_names[reg];
+ switch (state_reg_size(reg)) {
+ case 1:
+ return snprintf(dest, max, "%.4s: 0x%02x\n",
+ name, (unsigned int)state_get_reg(reg));
+ case 2:
+ return snprintf(dest, max, "%.4s: 0x%04x\n",
+ name, (unsigned int)state_get_reg(reg));
+ case 4:
+ return snprintf(dest, max, "%.4s: 0x%08x\n",
+ name, (unsigned int)state_get_reg(reg));
+ case 8: {
+ uint64_t v = state_get_reg(reg);
+ return snprintf(dest, max, "%.4s: 0x%08x%08x\n",
+ name, (unsigned int)(v>>32), (unsigned int)v);
+ }
+ default:
+ return 0;
+ }
+}
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
} else {
- LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
+ LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: OOM in pool %s\n", memp_desc[type]));
#if MEMP_STATS
++lwip_stats.memp[type].err;
#endif /* MEMP_STATS */
#include <io.h>
#include <minilib.h>
#include <paging.h>
+#include <demap.h>
#include <output.h>
+#include <state.h>
-static char http_output_buffer[1024];
+static char http_output_buffer[1280];
/*-----------------------------------------------------------------------------------*/
void handle_regs(struct fs_file *file)
{
- file->len = snprintf(http_output_buffer, sizeof(http_output_buffer),
- "<html><head><title>Registers</title></head><body>"
- "<p>At the time you requested this page, the system's registers were:</p>"
- "<tt><pre>"
- "%%eax: 0x%08x %%ebx: 0x%08x %%ecx: 0x%08x %%edx: 0x%08x\n"
- "%%ebp: 0x%08x %%esi: 0x%08x %%edi: 0x%08x %%esp: 0x%08x\n"
- "%%cr0: 0x%08x %%cr3: 0x%08x %%eip: 0x%08x %%eflags: 0x%08x\n"
- "</pre></tt></body></html>",
- *(unsigned long*)0xAFFD0,
- *(unsigned long*)0xAFFDC,
- *(unsigned long*)0xAFFD4,
- *(unsigned long*)0xAFFD8,
- *(unsigned long*)0xAFFE4,
- *(unsigned long*)0xAFFE8,
- *(unsigned long*)0xAFFEC,
- *(unsigned long*)0xAFFE0,
- *(unsigned long*)0xAFFFC,
- *(unsigned long*)0xAFFF8,
- *(unsigned long*)0xAFFF0,
- *(unsigned long*)0xAFFF4);
-
+ int i;
+ int len;
+
+ len = snprintf(http_output_buffer, sizeof(http_output_buffer), "<html><pre>");
+
+ for (i = 0; i < NUM_REGISTERS; i++) {
+ len += state_dump_reg(http_output_buffer + len, sizeof(http_output_buffer) - len, i);
+ }
+
+ file->len = len;
file->data = http_output_buffer;
}
{
int i = 10;
int len;
- unsigned long *pebp, *peip;
- unsigned long ebp;
- unsigned long cr3;
+ void *pebp, *peip;
+ uint64_t bp, next;
+
+ int longmode = (get_operating_mode() == LONG_64BIT);
char * buf = http_output_buffer;
strcpy(buf, "<html><head><title>Backtrace</title></head><body><tt><pre>");
len = strlen(buf);
- ebp = *(unsigned long *)0xAFFE4;
- cr3 = *(unsigned long *)0xAFFF8;
+
+ bp = state_get_reg(STATE_REG_RIP);
+
+ if (longmode)
+ len += snprintf(buf + len, LEFT, "0x%08x%08x, from\n", (uint32_t)(bp >> 32), (uint32_t)bp);
+ else
+ len += snprintf(buf + len, LEFT, "0x%08x, from\n", (uint32_t)bp);
- len += snprintf(buf + len, LEFT, "0x%08x, from\n", *(unsigned long*)0xAFFF0);
+ bp = state_get_reg(STATE_REG_RBP);
/* I never thought I'd do this again. */
- while ((peip = demap(cr3, ebp+4)) != 0x0 && i--)
+ while ((peip = demap(bp+(longmode?8:4))) != 0x0 && i--)
{
- len += snprintf(buf + len, LEFT, "0x%08x, from\n", *peip);
+ if (longmode) {
+ next = *(uint64_t *)peip;
+ len += snprintf(buf + len, LEFT, "0x%08x%08x, from\n", (uint32_t)(next >> 32), (uint32_t)next);
+ } else {
+ next = *(uint32_t *)peip;
+ len += snprintf(buf + len, LEFT, "0x%08x, from\n", (uint32_t)next);
+ }
+
+ pebp = demap(bp);
- pebp = demap(cr3, ebp);
if (!pebp)
{
- len += snprintf(buf + len, LEFT, "<unreadable %ebp>\n");
+ len += snprintf(buf + len, LEFT, "<unreadable frame>\n");
break;
}
- if (ebp >= *pebp && *pebp)
+
+ if (longmode)
+ next = *(uint64_t *)pebp;
+ else
+ next = *(uint32_t *)pebp;
+
+ if (bp >= next && next)
{
- len += snprintf(buf + len, LEFT, "<recursive %ebp>\n");
+ len += snprintf(buf + len, LEFT, "<recursive frame>\n");
break;
}
- ebp = *pebp;
+
+ bp = next;
}
if (i == -1)
static const char data_index_html[] =
"<html><head><title>NetWatch</title></head>"
- "<body><h1>NetWatch</h1>"
- "<iframe src=\"registers.html\" height=100 width=600></iframe><br>"
- "<iframe src=\"backtrace.html\" height=250 width=150></iframe>"
+ "<body><h1>NetWatch</h1><table cellpadding=0 cellspacing=0 border=0><tr valign=top><td>"
+ "<iframe src=\"registers.html\" height=500 width=300></iframe></td><td>"
+ "<iframe src=\"backtrace.html\" height=250 width=150></iframe></td></tr></table>"
"<form action=reboot type=post><input type=submit value=\"Reboot!\"></form>"
"</body></html>";
#include <minilib.h>
#include <output.h>
+#include <tables.h>
#include "lwip/debug.h"
#include "lwip/stats.h"
}
/*-----------------------------------------------------------------------------------*/
+PROTOCOL(httpd_init);
#include <pci-bother.h>
#include <output.h>
#include <minilib.h>
+#include <tables.h>
#include <lwip/init.h>
#include "net.h"
#include "netif/etharp.h"
#include "netif/ppp_oe.h"
-#include "rfb.h"
-
static struct nic *_nic = 0x0;
static struct netif _netif;
return 0;
}
+typedef void(*thunk_t)();
+
+TABLE(thunk_t, protocols);
+
void eth_init()
{
- extern void httpd_init();
+ int i;
/* Required for DMA to work. :( */
smram_tseg_set_state(SMRAM_TSEG_OPEN);
- lwip_init();
- httpd_init();
- rfb_init();
+ lwip_init();
+ for (i = 0; i < TABLE_LENGTH(protocols); i++)
+ protocols_table[i]();
}
#include <output.h>
#include <fb.h>
#include <keyboard.h>
+#include <tables.h>
#include "lwip/tcp.h"
#include "lwip/stats.h"
-#include "rfb.h"
+#define RFB_PORT 5900
#define SET_PIXEL_FORMAT 0
#define SET_ENCODINGS 2
return ERR_OK;
}
-void rfb_init() {
+static void rfb_init() {
struct tcp_pcb *pcb;
init_server_info();
pcb = tcp_listen(pcb);
tcp_accept(pcb, rfb_accept);
}
+
+PROTOCOL(rfb_init);
+++ /dev/null
-/* rfb.h
- * Remote framebuffer server
- * NetWatch system management mode administration console
- *
- * Copyright (c) 2008 Jacob Potter and Joshua Wise. All rights reserved.
- * This program is free software; you can redistribute and/or modify it under
- * the terms found in the file LICENSE in the root of this source tree.
- *
- */
-
-#ifndef _RFB_H
-#define _RFB_H
-
-void rfb_init(void);
-
-#define RFB_PORT 5900
-
-#endif /* _RFB_H */
. = 0x200000;
- .text : { *(.text); }
- .data : { *(.data); }
+ .text : {
+ *(.text);
+ *(SORT(.table.*));
+ }
+ .data : { *(.data); *(.data2); }
.rodata : { *(.rodata); }
.text : { *(.text); }
.stack : {
. = . + 0x10000;
. = ALIGN(0x10);
- _stacktop = .;
+ _primary_stack_top = .;
}
. = 0x10000;
ps_switch_stack:
mov 4(%esp), %eax
mov 8(%esp), %esp
+ # Put a sentinel value (FEEDFACE) at the top of the stack
+ mov $0xCEFAEDFE, %edx
+ push %edx
+ push %edx
+ push %edx
+ push %edx
call *%eax
rsm